// Package workspace 承载 Workspace / Worktree / GitOps 三个 service 的领域类型与 // 接口契约。沿 PM 模块(internal/project)的"单包多 service"风格:聚合在 schema // 上紧耦合,分包反而要互相 import。 package workspace import ( "context" "time" "github.com/google/uuid" "github.com/yan1h/agent-coding-workflow/internal/infra/git" ) // SyncStatus 与 DB CHECK 约束完全一致。 type SyncStatus string // SyncStatus 枚举值,与 migrations/0003 的 CHECK 约束完全一致。 const ( SyncStatusCloning SyncStatus = "cloning" SyncStatusIdle SyncStatus = "idle" SyncStatusSyncing SyncStatus = "syncing" SyncStatusError SyncStatus = "error" ) // IsValid 报告 s 是否在枚举集合内。 func (s SyncStatus) IsValid() bool { switch s { case SyncStatusCloning, SyncStatusIdle, SyncStatusSyncing, SyncStatusError: return true } return false } // WorktreeStatus 与 DB CHECK 约束完全一致。 type WorktreeStatus string // WorktreeStatus 枚举值,与 migrations/0003 的 CHECK 约束完全一致。 const ( WorktreeStatusIdle WorktreeStatus = "idle" WorktreeStatusActive WorktreeStatus = "active" WorktreeStatusPruning WorktreeStatus = "pruning" ) // CredentialKind 与 DB CHECK 约束完全一致;与 git.CredentialKind 同值,但分开 // 定义避免业务包对 infra/git 类型的强依赖。 type CredentialKind string // CredentialKind 枚举值,与 migrations/0003 的 CHECK 约束完全一致。 const ( CredKindPAT CredentialKind = "pat" CredKindSSHKey CredentialKind = "ssh_key" CredKindNone CredentialKind = "none" ) // IsValid 报告 k 是否在枚举集合内。 func (k CredentialKind) IsValid() bool { return k == CredKindPAT || k == CredKindSSHKey || k == CredKindNone } // Workspace 是顶层聚合根。 type Workspace struct { ID uuid.UUID ProjectID uuid.UUID Slug string Name string Description string GitRemoteURL string DefaultBranch string MainPath string SyncStatus SyncStatus LastSyncedAt *time.Time LastSyncError string CreatedAt time.Time UpdatedAt time.Time } // Worktree 表示一个支线 worktree(不含 main_path)。 type Worktree struct { ID uuid.UUID WorkspaceID uuid.UUID Branch string Path string Status WorktreeStatus ActiveHolder string // "user:" / "session:" / 空 AcquiredAt *time.Time LastUsedAt time.Time PruneWarningAt *time.Time CreatedAt time.Time } // Credential 是 git_credentials 表的领域投影。Secret 仅在创建/更新时有值, // 读取路径上 Service 永远不返回明文 secret。Fingerprint 是给前端展示的脱敏串。 type Credential struct { ID uuid.UUID WorkspaceID uuid.UUID Kind CredentialKind Username string Secret []byte // 写路径填明文;读路径恒为 nil Fingerprint string CreatedAt time.Time UpdatedAt time.Time } // FetchTarget 是 workspace 包暴露给 jobs 模块的"周期 fetch 目标"投影。 // owner_id 通过 JOIN projects 取,避免 workspaces 表加冗余列。 type FetchTarget struct { ID uuid.UUID OwnerID uuid.UUID Name string MainPath string } // Caller 表示发起请求的用户上下文。Service 据此判定鉴权与 holder 字符串。 type Caller struct { UserID uuid.UUID IsAdmin bool } // Holder 把 Caller 折成 acquire_holder 字符串。Plan #4 的 ACP supervisor 会用 // "session:" 形式调相同接口。 func (c Caller) Holder() string { return "user:" + c.UserID.String() } // ===== Service 接口 ===== // WorkspaceService 暴露 Workspace 聚合根的应用服务方法。 // //nolint:revive // 名字带聚合前缀比 "Service" 更准确:包内有 3 个并列服务接口 type WorkspaceService interface { Create(ctx context.Context, c Caller, projectSlug string, in CreateWorkspaceInput) (*Workspace, error) Get(ctx context.Context, c Caller, wsID uuid.UUID) (*Workspace, error) List(ctx context.Context, c Caller, projectSlug string) ([]*Workspace, error) Update(ctx context.Context, c Caller, wsID uuid.UUID, in UpdateWorkspaceInput) (*Workspace, error) Delete(ctx context.Context, c Caller, wsID uuid.UUID) error Sync(ctx context.Context, c Caller, wsID uuid.UUID) (*Workspace, error) UpsertCredential(ctx context.Context, c Caller, wsID uuid.UUID, in UpsertCredentialInput) (*Credential, error) GetCredentialMeta(ctx context.Context, c Caller, wsID uuid.UUID) (*Credential, error) } // WorktreeService 暴露支线 worktree 的应用服务方法。 type WorktreeService interface { Create(ctx context.Context, c Caller, wsID uuid.UUID, in CreateWorktreeInput) (*Worktree, error) List(ctx context.Context, c Caller, wsID uuid.UUID) ([]*Worktree, error) Delete(ctx context.Context, c Caller, wtID uuid.UUID) error Acquire(ctx context.Context, c Caller, wtID uuid.UUID) (*Worktree, error) Release(ctx context.Context, c Caller, wtID uuid.UUID) (*Worktree, error) } // GitOpsService 暴露 status/commit/push 操作。target 既可以是 Workspace(main_path) // 也可以是 Worktree。 type GitOpsService interface { StatusOnMain(ctx context.Context, c Caller, wsID uuid.UUID) ([]git.FileStatus, error) CommitOnMain(ctx context.Context, c Caller, wsID uuid.UUID, in CommitInput) (string, error) PushOnMain(ctx context.Context, c Caller, wsID uuid.UUID) error StatusOnWorktree(ctx context.Context, c Caller, wtID uuid.UUID) ([]git.FileStatus, error) CommitOnWorktree(ctx context.Context, c Caller, wtID uuid.UUID, in CommitInput) (string, error) PushOnWorktree(ctx context.Context, c Caller, wtID uuid.UUID) error } // ===== Input DTO ===== // CreateWorkspaceInput 携带创建 Workspace 与其凭据的字段。 type CreateWorkspaceInput struct { Slug string Name string Description string GitRemoteURL string DefaultBranch string Credential UpsertCredentialInput } // UpdateWorkspaceInput 是 patch 输入:nil = 保持原值。 type UpdateWorkspaceInput struct { Name *string Description *string DefaultBranch *string } // UpsertCredentialInput 创建或替换 git 凭据。Secret 是明文(PAT token / SSH 私钥 PEM)。 type UpsertCredentialInput struct { Kind CredentialKind Username string // PAT 时填 Secret []byte // PAT/SSH 时填;None 时为空 } // CreateWorktreeInput 创建支线 worktree。BaseBranch 留空时用 workspace.DefaultBranch。 type CreateWorktreeInput struct { Branch string BaseBranch string } // CommitInput 提交描述。AddAll 留 false 等价于"已经手动 git add",默认 service // 调用方传 true(与 4.4 端点 default 对齐)。 type CommitInput struct { Message string Push bool AddAll bool }