update-claude-agent-acp
更新内置 ACP agent fork(vendor/claude-agent-acp,自维护 git submodule),合并上游 agentclientprotocol/claude-agent-acp 新提交并重建发布产物。当用户说更新 claude-agent-acp / 合并上游修改 / 同步 acp agent / 升级内置 agent / 升级 claude-agent-sdk 时
SKILL.md.claude/skills/update-claude-agent-acp/SKILL.md
GitHub维护 claude-agent-acp(评估并选择性吸收上游变化)
vendor/claude-agent-acp 是我们独立维护的 fork:git submodule,不在 pnpm workspace 内,用自带 npm 工具链独立构建(见根 CLAUDE.md)。上游是 agentclientprotocol/claude-agent-acp(npm @agentclientprotocol/claude-agent-acp,Apache-2.0,作者 Zed Industries)。
核心套路:固定比较范围 → 逐条读变更实现/测试/前提 → 影响分类 → 采纳(移植或等价实现)/ 不适用 / 延后 → 完整验证 → 更新评估台账。不再以 rebase / 保 diff 最小为目标:Git 历史与 submodule 结构保持不变,上游变更按需选择吸收。
本 skill 只手动调用:frontmatter
disable-model-invocation: true+agents/openai.yaml的allow_implicit_invocation: false,不被模型隐式触发。
⚠️ 第一原则:产品行为契约不能被上游同名实现静默覆盖。主仓库 renderer 依赖 fork 的既有行为(尤其 AskUserQuestion 的 extMethod 兜底、ext-method /
_meta形状);评估上游变更时逐条核对,优先「两条路并存」而非二选一。
流程
0. 摸清现状(只读)
全部用 git / gh api 探查,不要在调查阶段改动 submodule:
cd vendor/claude-agent-acp
git remote -v # 通常只有 origin = 我们的 fork,无 upstream
git log --oneline -8 # 顶部若干条是我们的自定义提交,其下是上游基线
git rev-parse main HEAD origin/main # ⚠️ submodule 常是 detached HEAD;本地 main 可能过时,别用它做基线
注:package.json 内部
version(如 0.85.1)与上游 git tag 不是一回事,版本号对不上正常,不影响评估。
1. 固定比较范围
git -C vendor/claude-agent-acp fetch upstream
git -C vendor/claude-agent-acp log --oneline HEAD..upstream/main # 待评估清单
gh api 'repos/agentclientprotocol/claude-agent-acp/compare/<起点>...<上游HEAD>' --jq '.ahead_by,.behind_by,.total_commits'
git -C vendor/claude-agent-acp diff --stat <基线>..HEAD # 我们改了哪些文件,预判影响面
记录起止 SHA 与提交数;已审阅到的上游 SHA ≠ 已吸收。
2. 逐条评估与分类
读每条变更的实现、测试、前提,按下表处置并记入台账(docs/development/claude-agent-maintenance.md「上游评估记录」):
| 分类 | 处置 |
|---|---|
| 安全 / 权限 / 数据损坏 / SDK·CLI 兼容修复 | 优先采纳,不等月度巡检 |
| 产品需要的新功能 | 按本地契约实现 |
| 通用且自包含的修复 | 可直接移植,保留来源 |
| 上游专属功能 / 内部重构 | 通常不跟,记录不适用理由 |
| 与本地行为重叠 | 先确认 wire 形状与 editor 侧兼容,再决定切上游还是保持本地 |
依赖(SDK / CLI / ACP SDK / transcript 格式)分别跟踪,升级单独成批,不夹在结构重构或功能改动里。
3. 实现
- 采纳:移植上游补丁,或按本地结构等价实现(不要求与上游代码形状一致)。
- 分块、单一职责:一次只解决一个行为问题;不夹带无关格式化(本仓库风格 = 分号 + 双引号 +
printWidth:100)。 - 每个行为变更配走生产入口(真实
session/load、unstable_forkSession等)的测试,且测试能抓错。 - 同步更新
vendor/claude-agent-acp/CLAUDE.md的「本地行为清单」。
4. 验证
npm --prefix vendor/claude-agent-acp run typecheck
env -u ANTHROPIC_BASE_URL -u ANTHROPIC_AUTH_TOKEN npm --prefix vendor/claude-agent-acp run test:run
pnpm agent:build
UNIVERSE_FORK_CONTRACT=1 pnpm --filter @universe-editor/editor test:integration acpForkContract
pnpm check
- 契约测试默认 10s 内必须跑完——超时不是「加超时」的理由,先查谁占住 SDK 控制通道(案例 12)。
- codex 腿的
CODEX_HOME已由共享 fixture 自动隔离:apps/editor/integration/fixtures/realForkConnection.ts给每个 codex 连接在建临时 cwd 里mkdtemp一个干净 home(写cli_auth_credentials_store = "file",不复制父环境任何东西),故跑契约测试不再需要手工CODEX_HOME=$(mktemp -d),也不会读写开发者真实~/.codex。但独立跑 codex CLI(不经该 fixture,如codex exec)仍须显式CODEX_HOME=$(mktemp -d);任何情况下都绝不改动真实用户 auth 文件。 pnpm check的FileWatcherMainServicedebounce /DiffEditor getPosition偶发失败是主仓库既有 flake,重跑即绿。
5. 提交(推送前有阻断项)
git diff --submodule=log vendor/claude-agent-acp # 核对变更范围
- 提交/推送只在用户要求时做;开分支提交 submodule 指针,不 force push、不重写历史。
- ⚠️ 推送 fork
main前必须核实并决定自动发布:继承自上游的.github/workflows/publish.yml会在 main push 时以@agentclientprotocol/claude-agent-acp名发布 preview 并 tag;未处理前不得推送。详见docs/development/claude-agent-maintenance.md「发布入口阻断项」。
6. 更新台账
在 docs/development/claude-agent-maintenance.md 追加本批「上游评估记录」行(范围 / 目的 / 判断 / 处置 / 原因 / 本地测试),并回填基线字段(SHA / 版本 / 测试结果)。
适配套路(按文件)
package.json:编辑时当心重复 key(公共行别在 new_string 重写);version/依赖取上游,build(esbuild)取我方。package-lock.json:在vendor/*内重新生成锁一律带--registry=https://registry.npmjs.org,否则本机镜像 URL 写进resolved污染 CI(案例 10)。esbuild.config.mjs/src/interactive.ts等我方新增文件:上游无,直接保留。src/acp-agent.ts/src/tools.ts:双方都大改,需语义合并(案例 2、3、11)。
案例索引(按症状查,详情在 references/cases.md)
| 症状 | 案例 |
|---|---|
fork npm test 报 src\x vs src/x 路径失败 |
1(扩展见 9) |
| AskUserQuestion 被上游「无 form 就禁用」掐断 / extMethod 丢失 | 2、5 |
npm test 报 idle-without-result / no_result |
6 |
| SDK 升级后成批类型 / mock 适配报错 | 7、11 |
| session/load 或 resume 变慢、契约测试超时 | 8、9、12 |
| 升级后子 Agent 卡片降级成普通 tool | 13 |
| 已压缩会话恢复后丢压缩前历史 / steering | 14 |
npm ci 报 Missing ... from lock file / EUSAGE |
10 |
| 测试成片失败、疑似环境变量污染 | 9(坑 1) |
| 拼接 append 型冲突后丢括号 / 对齐吞噬 | 9(坑 2)、11 |
| 挂在某分支上的副作用在上游新路径丢失 | 11 |
要点速记
- 调查阶段全程只读(
git/gh api),别在 plan mode 改 submodule。 - submodule 是 detached HEAD;本地
main常过时,基线用HEAD/origin/main的真实 sha。 - 环境隔离:fork 单测带
env -u ANTHROPIC_BASE_URL -u ANTHROPIC_AUTH_TOKEN;实测问题起独立node探针 +CLAUDE_AGENT_LOGS=<dir>。 - AskUserQuestion:editor 主路径走标准
elicitation.form/url,fork 的 extMethod 仅兜底;两路并存(案例 2)。 package.json解冲突当心重复 key;version/依赖取上游,build/esbuild 取我方。- 锁:在
vendor/*重生成带--registry(案例 10);npm ci --dry-run能过才算噪音可丢。 - fork 测试已知 6 个 Windows 路径分隔符失败是上游缺陷(案例 1 家族),非回归。
- 契约测试默认 10s 内跑完;codex 腿用干净
CODEX_HOME。 - 验证旧行为用
git clone -q --no-hardlinks . /tmp/xxx,不在工作区做破坏性 reset(案例 9 坑 5)。 - 零冲突 ≠ 语义正确:上游重构接口 / 新增校验 / 给已有函数加入参都可能静默遮蔽本地行为;typecheck + test + 契约测试都要跑(案例 5、6、14)。
- 合并方式已改为选择性吸收,不再 rebase;提交/推送仅在用户要求时做,推送
main前先处理自动发布阻断项。
关键参考路径
- 根
CLAUDE.md「内置 ACP agent」节 +scripts/release/vendor-install.mjs、package.json的agent:build - fork
CLAUDE.md(本地行为清单 / 维护原则)+cases-session.md/cases-subagent.md/cases-permissions.md vendor/claude-agent-acp/src/{acp-agent.ts,tools.ts,interactive.ts,extra-models.ts}、vendor/claude-agent-acp/src/tests/{helpers.ts,session-doubles.ts,acp-scenarios/}- 主仓库
apps/editor/src/renderer/services/acp/(acpClientService.ts的DEFAULT_INIT_PARAMS能力声明、session/acpExtMethods.ts、session/acpSessionUpdateMeta.ts) - 跨仓契约测试
apps/editor/integration/scenarios/acpForkContract.integration.test.ts+apps/editor/integration/fixtures/realForkConnection.ts - 台账与验证入口
docs/development/claude-agent-maintenance.md
其它
- 后续用本 skill,发现新经验,需同步更新本文件与
references/cases.md(新案例先在案例索引补一行)。