yao/tai/volume/volume.go
Max df420978f0 feat(workspace): implement JSAPI with archive support and full test coverage
- tai/volume: add WithRemotePath sync option, 8 archive/compression methods
  (Zip/Unzip/Gzip/Gunzip/Tar/Untar/Tgz/Untgz) with local+remote impls
- workspace/jsapi: implement 24-method WorkspaceFS (file I/O, Copy with
  local:///tmp:// URI dispatch, archive ops) and 4 static methods
- workspace/manager: add Rename, MkdirAll, Volume() accessors via singleton
- Tests: comprehensive Go tests for tai/volume, workspace, workspace/jsapi
  covering both local and remote modes via SANDBOX_TEST_REMOTE_ADDR
- CI: update tai Docker image to latest in pr-test.yml
- sandbox/v2: add JSAPI docs and host/node module stubs

Made-with: Cursor
2026-03-08 14:17:39 +08:00

88 lines
2.9 KiB
Go

package volume
import (
"context"
"io/fs"
"os"
"time"
)
// Volume provides filesystem IO, directory synchronization, and archive operations.
// Remote connects to Tai gRPC :19100; Local operates directly on disk.
type Volume interface {
ReadFile(ctx context.Context, sessionID, path string) ([]byte, os.FileMode, error)
WriteFile(ctx context.Context, sessionID, path string, data []byte, perm os.FileMode) error
Stat(ctx context.Context, sessionID, path string) (*FileInfo, error)
ListDir(ctx context.Context, sessionID, path string) ([]FileInfo, error)
Remove(ctx context.Context, sessionID, path string, recursive bool) error
Rename(ctx context.Context, sessionID, oldPath, newPath string) error
MkdirAll(ctx context.Context, sessionID, path string) error
SyncPush(ctx context.Context, sessionID, localDir string, opts ...SyncOption) (*SyncResult, error)
SyncPull(ctx context.Context, sessionID, localDir string, opts ...SyncOption) (*SyncResult, error)
Zip(ctx context.Context, sessionID, src, dst string, excludes []string) (*ArchiveResult, error)
Unzip(ctx context.Context, sessionID, src, dst string) (*ArchiveResult, error)
Gzip(ctx context.Context, sessionID, src, dst string) (*ArchiveResult, error)
Gunzip(ctx context.Context, sessionID, src, dst string) (*ArchiveResult, error)
Tar(ctx context.Context, sessionID, src, dst string, excludes []string) (*ArchiveResult, error)
Untar(ctx context.Context, sessionID, src, dst string) (*ArchiveResult, error)
Tgz(ctx context.Context, sessionID, src, dst string, excludes []string) (*ArchiveResult, error)
Untgz(ctx context.Context, sessionID, src, dst string) (*ArchiveResult, error)
Close() error
}
// FileInfo describes a single file or directory.
type FileInfo struct {
Path string
Size int64
Mtime time.Time
Mode fs.FileMode
IsDir bool
}
// SyncResult summarizes a SyncPush or SyncPull operation.
type SyncResult struct {
FilesSynced int
BytesTransferred int64
Duration time.Duration
}
// ArchiveResult summarizes an archive/compression operation.
type ArchiveResult struct {
SizeBytes int64
FilesCount int
}
// SyncOption configures sync behavior.
type SyncOption func(*syncConfig)
type syncConfig struct {
forceFull bool
excludes []string
remotePath string
}
// WithForceFull skips snapshot caches and diffs against actual disk.
func WithForceFull() SyncOption {
return func(c *syncConfig) { c.forceFull = true }
}
// WithExcludes adds glob patterns to exclude from sync.
func WithExcludes(patterns ...string) SyncOption {
return func(c *syncConfig) { c.excludes = append(c.excludes, patterns...) }
}
// WithRemotePath sets a sub-path within the workspace root for sync operations.
func WithRemotePath(path string) SyncOption {
return func(c *syncConfig) { c.remotePath = path }
}
func applySyncOpts(opts []SyncOption) syncConfig {
var cfg syncConfig
for _, o := range opts {
o(&cfg)
}
return cfg
}