背景
Agent Tracking Phase 4。Phase 3 (#18) 已就位 wrapper 二进制。本 issue 实现 Claude Code 的具体 adapter,是首个端到端跑通的 agent。
范围
ClaudeCodeAdapter (`src/Worker/CortexTerminal.Worker/Agent/Adapters/ClaudeCodeAdapter.cs`):
- `Kind = AgentKind.ClaudeCode`
- `ResolveBinary()`:`CORTERM_ORIGINAL_PATH` 里 `which claude`,或读 `CLAUDE_BINARY_PATH` 覆盖
- `GenerateHookConfig(ctx)`:返回 Claude Code 的 settings.json 内容,配置 5 个 hook:
- SessionStart / UserPromptSubmit / PreToolUse / PostToolUse / Stop
- 每个 hook command: `curl -sX POST $CORTERM_AGENT_HOOK_URL -d @-`(stdin 收 JSON,POST 出去)
- `BuildEnvironment()`:设置 `CLAUDE_SETTINGS_FILE` 指向临时配置
- `ParseEvent(payload)`:
- SessionStart → `AgentStartedFrame(AgentSessionId=payload.session_id, WorkDir=payload.cwd)`
- UserPromptSubmit → `AgentPromptSubmittedFrame(PromptText=payload.prompt)`
- PreToolUse / PostToolUse → `AgentToolCallFrame(ToolName, Input, Output, DurationMs, IsError)`
- Stop → `AgentStoppedFrame(TotalCostUsd, TotalTokensIn, TotalTokensOut)`
Transcript 兜底观察者 (`src/Worker/.../Transcripts/ClaudeCodeTranscriptWatcher.cs`):
- `FileSystemWatcher` 监听 `~/.claude/projects/` 目录树
- 找到当前 sessionId 对应的 jsonl 文件(按 cwd / mtime 关联)→ 增量解析
- hook 漏发或被禁用时仍能补全事件流
Gateway 自动命名:
- 收到首条 `AgentPromptSubmittedFrame` → 取前 50 字符 → 写 `SessionRecordEntity.InferredTitle`
- Console 优先显示 `InferredTitle`,fallback `Name`,最后 `sess_id`
验收
- 在 Corterm session 里跑 `claude`,1 秒内 Console session 标题变成首条 prompt 摘要
- 在 Claude Code 里调一个 tool,Console 立刻出现 tool call 记录
- 退出 Claude Code,Stop 帧带 cost / token 统计
- 禁用 hook(`CLAUDE_SETTINGS_FILE` 指空)后,transcript watcher 仍能补全事件
依赖
不做的事
背景
Agent Tracking Phase 4。Phase 3 (#18) 已就位 wrapper 二进制。本 issue 实现 Claude Code 的具体 adapter,是首个端到端跑通的 agent。
范围
ClaudeCodeAdapter (`src/Worker/CortexTerminal.Worker/Agent/Adapters/ClaudeCodeAdapter.cs`):
Transcript 兜底观察者 (`src/Worker/.../Transcripts/ClaudeCodeTranscriptWatcher.cs`):
Gateway 自动命名:
验收
依赖
不做的事