// Package acp 实现 ACP(Agent Client Protocol)Client 模块。 // 模块结构(spec §13 决策 #12):单 package + 多文件,与现有 chat/jobs/workspace 一致。 // // 三个聚合根: // - AgentKind:admin 注册的 agent 类型(claude_code/gemini/...),含加密 env // - Session:用户启动的一个 ACP 会话,绑定 workspace + agent kind + (issue/req?) // - Event:JSON-RPC 双向消息流,每条入库 package acp import ( "context" "time" "github.com/google/uuid" ) // SessionStatus 是 acp_sessions.status 枚举。 type SessionStatus string const ( SessionStarting SessionStatus = "starting" SessionRunning SessionStatus = "running" SessionCrashed SessionStatus = "crashed" SessionExited SessionStatus = "exited" ) // IsActive 判定 session 是否仍占资源(worktree、subprocess、限流计数)。 func (s SessionStatus) IsActive() bool { return s == SessionStarting || s == SessionRunning } // EventDirection 标识事件流向。in = client→agent,out = agent→client。 type EventDirection string const ( DirectionIn EventDirection = "in" DirectionOut EventDirection = "out" ) // RPCKind 标识 JSON-RPC 消息类型。 type RPCKind string const ( RPCRequest RPCKind = "request" RPCResponse RPCKind = "response" RPCNotification RPCKind = "notification" RPCError RPCKind = "error" ) // AgentKind 是 admin 注册的 agent 类型记录。EncryptedEnv 是 AES-GCM 密文, // 仅 supervisor spawn 时解密为 map 注入子进程。其他场景不解密、不出 API。 type AgentKind struct { ID uuid.UUID Name string DisplayName string Description string BinaryPath string Args []string EncryptedEnv []byte Enabled bool CreatedBy uuid.UUID CreatedAt time.Time UpdatedAt time.Time } // Session 是一次 ACP 会话。AgentSessionID 是 agent 侧的 session 标识(来自 // session/new response),与本表 ID 不同,仅用于 ACP 协议 method 内填充。 type Session struct { ID uuid.UUID WorkspaceID uuid.UUID ProjectID uuid.UUID AgentKindID uuid.UUID UserID uuid.UUID IssueID *uuid.UUID RequirementID *uuid.UUID AgentSessionID *string Branch string CwdPath string IsMainWorktree bool Status SessionStatus PID *int32 ExitCode *int32 LastError *string StartedAt time.Time EndedAt *time.Time } // Event 是一条入库的 JSON-RPC 消息。Payload 是 JSON-RPC envelope 完整 JSON // 字节(不解析为结构体,便于无损 replay);超过 64KB 的会按 §3.5 规则裁剪。 type Event struct { ID int64 SessionID uuid.UUID Direction EventDirection RPCKind RPCKind Method *string Payload []byte PayloadSize int32 Truncated bool CreatedAt time.Time } // Caller 表示发起请求的用户上下文,与 PM 模块的 Caller 同语义。 type Caller struct { UserID uuid.UUID IsAdmin bool } // AgentKindService 暴露 AgentKind 的应用服务方法。env 走"完整 map 替换" // 语义:每次 PATCH 传完整 env,nil 表示不修改;非 nil 整体加密重写。 type AgentKindService interface { Create(ctx context.Context, c Caller, in CreateAgentKindInput) (*AgentKind, error) List(ctx context.Context, c Caller) ([]*AgentKind, error) Get(ctx context.Context, c Caller, id uuid.UUID) (*AgentKind, error) Update(ctx context.Context, c Caller, id uuid.UUID, in UpdateAgentKindInput) (*AgentKind, error) Delete(ctx context.Context, c Caller, id uuid.UUID) error } // SessionService 在 Part 2 实施。占位以便 handler.go 编译通过。 type SessionService interface { // methods filled in Part 2 } // CreateAgentKindInput 携带创建必需字段。Args / Env 可为 nil。 type CreateAgentKindInput struct { Name string DisplayName string Description string BinaryPath string Args []string Env map[string]string Enabled bool } // UpdateAgentKindInput 是 patch 输入。Name 不可改(创建后稳定,引用约束)。 // Env 三态:nil = 不修改;空 map = 清空全部 env;非空 = 整体替换。 type UpdateAgentKindInput struct { DisplayName *string Description *string BinaryPath *string Args []string // nil = 不改;非 nil = 替换 Env map[string]string // nil = 不改;非 nil(含空)= 替换 Enabled *bool }