@fitlab-ai/agent-infra 0.9.3 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/README.md +2 -0
  2. package/README.zh-CN.md +2 -0
  3. package/bin/cli.ts +12 -0
  4. package/dist/bin/cli.js +14 -0
  5. package/dist/bin/internal-cli.js +134 -123
  6. package/dist/lib/agent-clients/adapter.js +92 -2
  7. package/dist/lib/{sandbox/credentials.js → agent-clients/adapters/claude-code-credentials.js} +4 -14
  8. package/dist/lib/agent-clients/adapters/claude-code-refresh.js +85 -0
  9. package/dist/lib/agent-clients/adapters/claude-code-sandbox.js +247 -0
  10. package/dist/lib/agent-clients/adapters/claude-code.js +17 -3
  11. package/dist/lib/agent-clients/adapters/opencode-sandbox.js +108 -0
  12. package/dist/lib/agent-clients/adapters/opencode.js +15 -3
  13. package/dist/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
  14. package/dist/lib/agent-clients/registry.js +9 -1
  15. package/dist/lib/internal/sandbox-control.js +24 -0
  16. package/dist/lib/internal/task-activity.js +45 -13
  17. package/dist/lib/internal/task-ledger.js +12 -3
  18. package/dist/lib/internal/task-lifecycle.js +19 -1
  19. package/dist/lib/internal/task-orchestration.js +122 -18
  20. package/dist/lib/platform/github-client.js +19 -2
  21. package/dist/lib/platform/pr-checks.js +1 -1
  22. package/dist/lib/platform/pull-requests.js +47 -1
  23. package/dist/lib/platform/releases.js +13 -5
  24. package/dist/lib/process-data/index.js +239 -0
  25. package/dist/lib/process-data/normalize.js +198 -0
  26. package/dist/lib/process-data/privacy.js +33 -0
  27. package/dist/lib/process-data/reconcile.js +95 -0
  28. package/dist/lib/process-data/repair.js +58 -0
  29. package/dist/lib/process-data/sources.js +345 -0
  30. package/dist/lib/process-data/store.js +282 -0
  31. package/dist/lib/process-data/types.js +2 -0
  32. package/dist/lib/run/index.js +4 -3
  33. package/dist/lib/run/tui.js +7 -8
  34. package/dist/lib/sandbox/agent-client-reconciler.js +26 -2
  35. package/dist/lib/sandbox/capture.js +7 -2
  36. package/dist/lib/sandbox/commands/create.js +109 -228
  37. package/dist/lib/sandbox/commands/enter.js +15 -47
  38. package/dist/lib/sandbox/commands/list-running.js +16 -6
  39. package/dist/lib/sandbox/commands/ls.js +10 -6
  40. package/dist/lib/sandbox/commands/rebuild.js +4 -3
  41. package/dist/lib/sandbox/commands/refresh.js +4 -84
  42. package/dist/lib/sandbox/commands/rm.js +24 -3
  43. package/dist/lib/sandbox/commands/show.js +12 -3
  44. package/dist/lib/sandbox/commands/start.js +7 -4
  45. package/dist/lib/sandbox/config.js +2 -0
  46. package/dist/lib/sandbox/constants.js +6 -0
  47. package/dist/lib/sandbox/control/client.js +44 -0
  48. package/dist/lib/sandbox/control/protocol.js +35 -0
  49. package/dist/lib/sandbox/control/server.js +109 -0
  50. package/dist/lib/sandbox/dockerfile.js +36 -13
  51. package/dist/lib/sandbox/mounts.js +17 -4
  52. package/dist/lib/sandbox/recovery.js +128 -5
  53. package/dist/lib/sandbox/redaction.js +12 -0
  54. package/dist/lib/sandbox/runtimes/base.dockerfile +24 -74
  55. package/dist/lib/sandbox/workspace-identity.js +95 -0
  56. package/dist/lib/sandbox/workspace-view.js +103 -0
  57. package/dist/lib/task/activity-intent.js +257 -51
  58. package/dist/lib/task/commit-finalization.js +267 -0
  59. package/dist/lib/task/commit-intent.js +165 -0
  60. package/dist/lib/task/decision-intents.js +31 -17
  61. package/dist/lib/task/delegation-receipts.js +2 -2
  62. package/dist/lib/task/implementation-inputs.js +54 -7
  63. package/dist/lib/task/ledger-intents.js +35 -1
  64. package/dist/lib/task/orchestration.js +363 -28
  65. package/dist/lib/task/resolve-ref.js +41 -1
  66. package/lib/agent-clients/adapter.ts +126 -2
  67. package/lib/{sandbox/credentials.ts → agent-clients/adapters/claude-code-credentials.ts} +3 -18
  68. package/lib/agent-clients/adapters/claude-code-refresh.ts +128 -0
  69. package/lib/agent-clients/adapters/claude-code-sandbox.ts +295 -0
  70. package/lib/agent-clients/adapters/claude-code.ts +21 -3
  71. package/lib/agent-clients/adapters/opencode-sandbox.ts +136 -0
  72. package/lib/agent-clients/adapters/opencode.ts +18 -3
  73. package/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
  74. package/lib/agent-clients/registry.ts +9 -1
  75. package/lib/internal/sandbox-control.ts +24 -0
  76. package/lib/internal/task-activity.ts +50 -14
  77. package/lib/internal/task-ledger.ts +12 -3
  78. package/lib/internal/task-lifecycle.ts +22 -1
  79. package/lib/internal/task-orchestration.ts +81 -11
  80. package/lib/platform/github-client.ts +20 -2
  81. package/lib/platform/pr-checks.ts +1 -1
  82. package/lib/platform/pull-requests.ts +49 -1
  83. package/lib/platform/releases.ts +16 -4
  84. package/lib/process-data/index.ts +224 -0
  85. package/lib/process-data/normalize.ts +202 -0
  86. package/lib/process-data/privacy.ts +41 -0
  87. package/lib/process-data/reconcile.ts +110 -0
  88. package/lib/process-data/repair.ts +64 -0
  89. package/lib/process-data/sources.ts +354 -0
  90. package/lib/process-data/store.ts +315 -0
  91. package/lib/process-data/types.ts +135 -0
  92. package/lib/run/index.ts +5 -3
  93. package/lib/run/tui.ts +11 -8
  94. package/lib/sandbox/agent-client-reconciler.ts +44 -2
  95. package/lib/sandbox/capture.ts +9 -2
  96. package/lib/sandbox/commands/create.ts +126 -260
  97. package/lib/sandbox/commands/enter.ts +13 -59
  98. package/lib/sandbox/commands/list-running.ts +23 -6
  99. package/lib/sandbox/commands/ls.ts +22 -6
  100. package/lib/sandbox/commands/rebuild.ts +4 -3
  101. package/lib/sandbox/commands/refresh.ts +4 -126
  102. package/lib/sandbox/commands/rm.ts +24 -3
  103. package/lib/sandbox/commands/show.ts +29 -3
  104. package/lib/sandbox/commands/start.ts +6 -4
  105. package/lib/sandbox/config.ts +4 -0
  106. package/lib/sandbox/constants.ts +8 -0
  107. package/lib/sandbox/control/client.ts +55 -0
  108. package/lib/sandbox/control/protocol.ts +75 -0
  109. package/lib/sandbox/control/server.ts +117 -0
  110. package/lib/sandbox/dockerfile.ts +66 -13
  111. package/lib/sandbox/mounts.ts +24 -4
  112. package/lib/sandbox/recovery.ts +163 -6
  113. package/lib/sandbox/redaction.ts +14 -0
  114. package/lib/sandbox/runtimes/base.dockerfile +24 -74
  115. package/lib/sandbox/tool-types.ts +16 -0
  116. package/lib/sandbox/workspace-identity.ts +123 -0
  117. package/lib/sandbox/workspace-view.ts +143 -0
  118. package/lib/task/activity-intent.ts +350 -61
  119. package/lib/task/commit-finalization.ts +356 -0
  120. package/lib/task/commit-intent.ts +230 -0
  121. package/lib/task/decision-intents.ts +32 -12
  122. package/lib/task/delegation-receipts.ts +2 -2
  123. package/lib/task/implementation-inputs.ts +62 -8
  124. package/lib/task/ledger-intents.ts +43 -3
  125. package/lib/task/orchestration.ts +501 -33
  126. package/lib/task/resolve-ref.ts +46 -1
  127. package/package.json +1 -1
  128. package/templates/.agents/rules/README.en.md +1 -1
  129. package/templates/.agents/rules/README.zh-CN.md +1 -1
  130. package/templates/.agents/rules/human-decision-context.en.md +11 -2
  131. package/templates/.agents/rules/human-decision-context.zh-CN.md +11 -2
  132. package/templates/.agents/rules/pr-checks-commands.en.md +1 -1
  133. package/templates/.agents/rules/pr-checks-commands.github.en.md +1 -1
  134. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +2 -2
  135. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +1 -1
  136. package/templates/.agents/rules/review-handshake.zh-CN.md +1 -1
  137. package/templates/.agents/rules/task-management.en.md +2 -0
  138. package/templates/.agents/rules/task-management.zh-CN.md +2 -0
  139. package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
  140. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +1 -1
  141. package/templates/.agents/skills/commit/SKILL.en.md +21 -11
  142. package/templates/.agents/skills/commit/SKILL.zh-CN.md +27 -11
  143. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +49 -0
  144. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +55 -0
  145. package/templates/.agents/skills/commit/reference/task-status-update.en.md +4 -4
  146. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +4 -4
  147. package/templates/.agents/skills/complete-task/SKILL.en.md +1 -1
  148. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +1 -1
  149. package/templates/.agents/skills/create-pr/SKILL.en.md +4 -4
  150. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +4 -4
  151. package/templates/.agents/skills/create-task/reference/context-capture.en.md +34 -0
  152. package/templates/.agents/skills/create-task/reference/context-capture.zh-CN.md +34 -0
  153. package/templates/.agents/skills/review-code/SKILL.en.md +2 -2
  154. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +2 -2
  155. package/templates/.agents/skills/review-code/reference/output-templates.en.md +1 -1
  156. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +1 -1
  157. package/templates/.agents/skills/review-pr/SKILL.en.md +36 -8
  158. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +36 -8
  159. package/templates/.agents/skills/review-pr/reference/report-template.en.md +1 -1
  160. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +1 -1
  161. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +67 -50
  162. package/templates/.agents/skills/watch-pr/SKILL.en.md +4 -4
  163. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +4 -4
  164. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +2 -2
  165. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +2 -2
  166. package/templates/.agents/templates/task.en.md +1 -1
  167. package/templates/.agents/templates/task.zh-CN.md +1 -1
  168. package/templates/.claude/commands/watch-pr.en.md +1 -1
  169. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  170. package/templates/.claude/rules/tool-preferences.en.md +20 -0
  171. package/templates/.claude/rules/tool-preferences.zh-CN.md +20 -0
  172. package/templates/.opencode/commands/watch-pr.en.md +1 -1
  173. package/templates/.opencode/commands/watch-pr.zh-CN.md +1 -1
  174. package/templates/.gemini/commands/_project_/review-pr.en.toml +0 -10
  175. package/templates/.gemini/commands/_project_/review-pr.zh-CN.toml +0 -10
@@ -162,7 +162,7 @@ agent-infra-internal task-verify {task-id} complete-task.preflight --format text
162
162
 
163
163
  This event runs `review-ledger`, `manual-validation`, `post-review-commit`, then `platform-sync-preflight`. On any non-zero exit (fail/blocked), keep the task active, derive the stable code/target from the gate result, record it through `task-warning ... add --step complete-task ...`, and stop. For a review/head mismatch, rerun `commit` or `review-code`; never fall back to the review baseline.
164
164
 
165
- `--force` does not lift this hard gate: close ledger disagreements; re-review or exempt post-review commits, use the platform adapter's authoritative snapshot and remote refs for the bound change request (PR/MR) to prove a content-equivalent single-parent squash merge in an isolated temporary repository, or, without a valid change request, prove from local Git objects that the only protected commit is a content-equivalent single-parent rewrite with no later protected commits; then pass platform preflight. An unsupported adapter capability, missing required platform facts, Git objects, topology, or content evidence, or current Git credentials that cannot read the remote evidence refs fails closed. The platform adapter supplies normalized required-checks state, which remains enforced before merge by branch protection / rulesets and the `review-code` / `watch-pr` routes.
165
+ `--force` does not lift this hard gate: close ledger disagreements; re-review or exempt post-review commits, use the platform adapter's authoritative snapshot and remote refs for the bound change request (PR/MR) to prove a content-equivalent single-parent squash merge in an isolated temporary repository, or, without a valid change request, prove from local Git objects that the only protected commit is a content-equivalent single-parent rewrite with no later protected commits; then pass platform preflight. An unsupported adapter capability, missing required platform facts, Git objects, topology, or content evidence, or current Git credentials that cannot read the remote evidence refs fails closed. The platform adapter supplies normalized state for all checks, enforced before merge by the `review-code` / `watch-pr` routes; required checks remain additionally enforced by branch protection / rulesets.
166
166
 
167
167
  ### 6. Apply the Local Lifecycle Intent and Verify the Move
168
168
 
@@ -161,7 +161,7 @@ agent-infra-internal task-verify {task-id} complete-task.preflight --format text
161
161
 
162
162
  该事件依次执行 `review-ledger`、`manual-validation`、`post-review-commit`、`platform-sync-preflight`。任一退出码非 0(fail/blocked)时,任务必须继续留在 active;从 gate 结果取稳定 code/target,通过 `task-warning ... add --step complete-task ...` 落账后停止。若审查基线或 head 不一致,必须先重新 `commit` / `review-code`;不得回退审查基线。
163
163
 
164
- `--force` 不解除本硬门禁:未关闭分歧必须先在账本闭合,未复审提交必须重新审查、具备有效豁免,或由平台适配器为绑定的变更请求(PR/MR)提供权威合并快照与远端 refs,并在隔离临时仓库中证明单父 squash merge 等价,或在无有效变更请求时由本地 Git 对象证明唯一受保护提交是内容等价的单父重写且之后无受保护提交;平台 preflight 必须通过。适配器不支持所需能力,平台事实、Git 对象、拓扑、内容证据缺失,或当前 Git 凭据不能读取远端证据 refs 时 fail closed。required checks 由平台适配器提供规范化状态,并在合并前通过分支保护 / ruleset 以及 `review-code` / `watch-pr` 路由承担。
164
+ `--force` 不解除本硬门禁:未关闭分歧必须先在账本闭合,未复审提交必须重新审查、具备有效豁免,或由平台适配器为绑定的变更请求(PR/MR)提供权威合并快照与远端 refs,并在隔离临时仓库中证明单父 squash merge 等价,或在无有效变更请求时由本地 Git 对象证明唯一受保护提交是内容等价的单父重写且之后无受保护提交;平台 preflight 必须通过。适配器不支持所需能力,平台事实、Git 对象、拓扑、内容证据缺失,或当前 Git 凭据不能读取远端证据 refs 时 fail closed。全部 checks 由平台适配器提供规范化状态,并在合并前通过 `review-code` / `watch-pr` 路由承担;其中 required checks 仍受分支保护 / ruleset 强制。
165
165
 
166
166
  ### 6. 执行本地生命周期意图并验证转移
167
167
 
@@ -68,7 +68,7 @@ Use `agent-infra-internal git-workflow inspect` for upstream/remote facts and `g
68
68
 
69
69
  ### 5. Create or Recover the PR
70
70
 
71
- Read `.agents/rules/issue-pr-commands.md`, write the title and body to temporary files, then invoke its `platform-pr create` intent. The core first performs exact head/base lookup: one existing PR is reused and bound, zero creates, and multiple matches fail deterministically. Replays must not create duplicate PRs.
71
+ Read `.agents/rules/issue-pr-commands.md`, write the title and body to temporary files, then invoke its `platform-pr create` intent. Under the task lock and before any Create PR started entry, POST, or reuse-bind, core checks commit finalization. An active intent, open Commit, missing review anchor, or tree drift returns a stable code and directs the caller to rerun commit/review-code; create-pr never repairs Commit state. Only after the gate passes does core perform exact head/base lookup: one existing PR is reused and bound, zero creates, and multiple matches fail deterministically. Replays must not create duplicate PRs.
72
72
 
73
73
  If `{task-id}` is available and the related task provides `issue_number`, keep `Closes #{issue-number}` in the PR body.
74
74
 
@@ -114,11 +114,11 @@ Explain the created PR URL, summarize metadata sync and summary-comment results,
114
114
  Populate `{next-step-commands}` for this scenario by running `agent-infra-internal agent-client next-steps --skill watch-pr --task-ref {task-ref}`.
115
115
 
116
116
  ```
117
- Next step - Watch PR checks (auto self-heal until required checks are green):
117
+ Next step - Watch PR checks (auto self-heal until all checks are green):
118
118
  {next-step-commands}
119
119
  ```
120
120
 
121
- Alternatively, to skip active monitoring and attempt completion immediately, use `complete-task`; its required-checks hard gate still fails closed for pending/failed checks or head mismatch:
121
+ Alternatively, to skip active monitoring and attempt completion immediately, use `complete-task`; its all-checks hard gate still fails closed for pending/failed checks or head mismatch:
122
122
 
123
123
  Populate `{next-step-commands}` for this scenario by running `agent-infra-internal agent-client next-steps --skill complete-task --task-ref {task-ref}`.
124
124
 
@@ -127,7 +127,7 @@ Next step (alternative) - Skip active monitoring and attempt completion:
127
127
  {next-step-commands}
128
128
  ```
129
129
 
130
- `watch-pr` is the primary path. The alternative `complete-task` block skips active polling only; it never skips required checks and does not guarantee immediate archival.
130
+ `watch-pr` is the primary path. The alternative `complete-task` block skips active polling only; it never skips the full check set and does not guarantee immediate archival.
131
131
 
132
132
  ## Notes
133
133
 
@@ -68,7 +68,7 @@ description: >
68
68
 
69
69
  ### 5. 创建或恢复 PR
70
70
 
71
- 执行前先读取 `.agents/rules/issue-pr-commands.md`,把标题和正文写入临时文件,并调用其中的 `platform-pr create` intent。core 先按 head/base 精确定位:唯一既有 PR 会复用并绑定,零个才创建,多个稳定失败;重放不得产生重复 PR。
71
+ 执行前先读取 `.agents/rules/issue-pr-commands.md`,把标题和正文写入临时文件,并调用其中的 `platform-pr create` intent。core 在任务锁内、任何 Create PR started / POST / reuse-bind 之前检查 commit finalization;active intent、open Commit、审查锚点缺失或 tree 漂移时返回稳定 code 并指向重跑 commit/review-code,不自动恢复。门禁通过后才按 head/base 精确定位:唯一既有 PR 会复用并绑定,零个才创建,多个稳定失败;重放不得产生重复 PR。
72
72
 
73
73
  如果获取到 `{task-id}` 且对应任务提供了 `issue_number`,必须在 PR 正文中保留 `Closes #{issue-number}`。
74
74
 
@@ -114,11 +114,11 @@ agent-infra-internal task-verify {task-id} create-pr.completed --format text
114
114
  使用 `agent-infra-internal agent-client next-steps --skill watch-pr --task-ref {task-ref}` 生成本场景的 `{next-step-commands}`。
115
115
 
116
116
  ```
117
- 下一步 - 监控 PR 检查(required checks 全绿前自动自愈):
117
+ 下一步 - 监控 PR 检查(全部 checks 全绿前自动自愈):
118
118
  {next-step-commands}
119
119
  ```
120
120
 
121
- 或者,若想跳过主动监控并立即尝试完成,改用 `complete-task`;其 required-checks 硬门禁仍会对 pending/failed/head mismatch fail-closed:
121
+ 或者,若想跳过主动监控并立即尝试完成,改用 `complete-task`;其全部 checks 硬门禁仍会对 pending/failed/head mismatch fail-closed:
122
122
 
123
123
  使用 `agent-infra-internal agent-client next-steps --skill complete-task --task-ref {task-ref}` 生成本场景的 `{next-step-commands}`。
124
124
 
@@ -127,7 +127,7 @@ agent-infra-internal task-verify {task-id} create-pr.completed --format text
127
127
  {next-step-commands}
128
128
  ```
129
129
 
130
- `watch-pr` 为主路径;上面的 `complete-task` 备选块只跳过主动轮询,不跳过 required checks,也不保证立即归档。
130
+ `watch-pr` 为主路径;上面的 `complete-task` 备选块只跳过主动轮询,不跳过全部 checks,也不保证立即归档。
131
131
 
132
132
  ## 注意事项
133
133
 
@@ -18,6 +18,40 @@ Faithfully condense existing information into task.md under `## Task Input`:
18
18
 
19
19
  Leave missing categories empty rather than inferring content. Deduplicate repeated information without losing its source or state.
20
20
 
21
+ ## Observable Acceptance Extraction
22
+
23
+ The following language-neutral contract is the stable boundary for capturing observable acceptance information:
24
+
25
+ ```text
26
+ # observable-acceptance-contract
27
+ sources: current-request,necessary-prior-discussion
28
+ scan-entire-visible-context: true
29
+ recognize-without-acceptance-label: true
30
+ components: observable-input,action,expected-result
31
+ combine-distributed-evidence: true
32
+ preserve-source-state: true
33
+ missing-components: preserve-as-gaps
34
+ agent-inference-as-confirmed: false
35
+ destination: task-input.acceptance-criteria
36
+ scenario-explicit: capture-supported-components
37
+ scenario-distributed: combine-supported-components
38
+ scenario-insufficient: preserve-supported-components-and-gaps
39
+ ```
40
+
41
+ Execution order:
42
+
43
+ 1. Scan the complete visible context of the current request and necessary prior discussion. Recognize observable information even when the user did not label it as acceptance criteria.
44
+ 2. Identify observable inputs, user or system actions, and expected results. These components may be distributed across turns.
45
+ 3. Combine supported components that describe the same behavior into a self-contained item, preserving the source and confirmation state of each piece of information.
46
+ 4. Preserve unexpressed components as gaps. Do not invent thresholds, scenarios, actions, or results, and do not mark agent inference as user-confirmed information.
47
+ 5. Write the items under `## Task Input / ### Acceptance Criteria`. If the context provides no observable criterion, leave that category empty and retain genuine unknowns in the existing categories.
48
+
49
+ Boundary examples:
50
+
51
+ - **Single-turn explicit information**: when the current request provides an input, action, and result, capture every supported component and identify the current request as its source.
52
+ - **Distributed information**: when the current request describes an action and necessary prior discussion provides an input or result, combine only components for the same behavior and preserve their source states separately.
53
+ - **Insufficient information**: when the user only says that something "should be faster" without an observable condition or threshold, do not invent a performance target; preserve the stated concern and gaps, leaving the acceptance category empty when no criterion can be formed.
54
+
21
55
  ## Safety and Compression
22
56
 
23
57
  - Exclude secrets, tokens, credentials, and unrelated personal information.
@@ -18,6 +18,40 @@
18
18
 
19
19
  缺失类别保持为空,不推导补齐。相同信息去重,但不得丢失来源或状态语义。
20
20
 
21
+ ## 可观察验收提取
22
+
23
+ 以下语言无关契约是可观察验收信息的稳定捕获边界:
24
+
25
+ ```text
26
+ # observable-acceptance-contract
27
+ sources: current-request,necessary-prior-discussion
28
+ scan-entire-visible-context: true
29
+ recognize-without-acceptance-label: true
30
+ components: observable-input,action,expected-result
31
+ combine-distributed-evidence: true
32
+ preserve-source-state: true
33
+ missing-components: preserve-as-gaps
34
+ agent-inference-as-confirmed: false
35
+ destination: task-input.acceptance-criteria
36
+ scenario-explicit: capture-supported-components
37
+ scenario-distributed: combine-supported-components
38
+ scenario-insufficient: preserve-supported-components-and-gaps
39
+ ```
40
+
41
+ 执行顺序:
42
+
43
+ 1. 扫描当前请求及必要前序讨论的完整可见上下文;即使用户没有使用“验收标准”标签,也要识别其中的可观察信息。
44
+ 2. 找出可观察输入、用户或系统执行的动作以及预期结果。这些组成可以分散在不同轮次。
45
+ 3. 将描述同一行为且有上下文证据的组成合并为自足条目,并保留每项信息的来源和确认状态。
46
+ 4. 未表达的组成保持为缺口;不得补造阈值、场景、动作或结果,也不得把 Agent 推导标记为用户已确认。
47
+ 5. 将条目写入 `## 任务输入 / ### 验收标准`。如果上下文没有提供可观察标准,该分类保持为空,真实的待确认信息继续保留在既有分类中。
48
+
49
+ 边界样例:
50
+
51
+ - **单轮显式信息**:当前请求同时给出输入、动作和结果时,捕获全部有证据的组成并注明来自当前请求。
52
+ - **跨轮分散信息**:当前请求描述动作、必要前序讨论提供输入或结果时,只合并属于同一行为的组成,并分别保留来源状态。
53
+ - **信息不足**:用户只说“应该更快”但没有可观察条件或阈值时,不得编造性能目标;保留已表达的关注点和缺口,无法形成标准则让验收分类为空。
54
+
21
55
  ## 安全与压缩
22
56
 
23
57
  - 排除密钥、Token、凭据和与任务无关的个人信息。
@@ -97,7 +97,7 @@ Create `.agents/workspace/active/{task-id}/{review-artifact}`.
97
97
  ### 6. Update Task Status
98
98
 
99
99
  Update task.md:
100
- - After the report, submit each new finding with `agent-infra-internal task-ledger {task-id} finding-upsert --stage code --review-artifact {review-artifact} --ordinal {n} --severity {blocker|major|minor} --evidence {review-artifact}#{anchor}`; submit prior-response dispositions with `finding-review --id {ledger-id} --status {confirmed|closed|open|needs-human-decision} --evidence {evidence}`. Do not scan ids or edit ledger rows
100
+ - After the report, submit each new finding with `agent-infra-internal task-ledger {task-id} finding-upsert --stage code --review-artifact {review-artifact} --ordinal {n} --severity {blocker|major|minor} --evidence {review-artifact}#{anchor}`; submit prior-response dispositions with `finding-review --id {ledger-id} --status {confirmed|closed|open|needs-human-decision} --evidence {evidence}`. When escalating to `needs-human-decision`, append `--needs-implementation true|false` using the judgment recorded in the detail block. Do not scan ids or edit ledger rows
101
101
  - After all ledger writes, call `agent-infra-internal task-review {task-id} finalize-summary --stage code --artifact {review-artifact} {execution-flag}` exactly once
102
102
 
103
103
  Bind and reuse this structured mapping from that one response:
@@ -110,7 +110,7 @@ Update task.md:
110
110
 
111
111
  The intent atomically finalizes the report summary and returns the same ledger snapshot. Do not call `stage-status`, replace placeholders manually, or rescan the finding list. If finalization fails or a response field is missing, stop before the completion event. Derive the verdict and next-step branch from the same response's `stageStatus.canAdvance`; only `canAdvance=true` permits Approved
112
112
  - Only when `canAdvance=true`, the verdict is Approved, and `T == R^{tree}`, write `last_reviewed_commit: {R}`. Clear an old value for an Approved snapshot with uncommitted differences; otherwise preserve the existing value and do not advance it
113
- - For an Approved exit, collect PR and required-checks facts as defined in `reference/output-templates.md`: route uncommitted/unpushed code to `commit`, no PR to `create-pr` (except no-PR flow), non-terminal checks to `watch-pr`, and route to `complete-task` only when `HEAD == last_reviewed_commit == PR head` with checks `passed|no-required`; never route by review round alone
113
+ - For an Approved exit, collect PR and all-check facts as defined in `reference/output-templates.md`: route uncommitted/unpushed code to `commit`, no PR to `create-pr` (except no-PR flow), non-terminal checks to `watch-pr`, and route to `complete-task` only when `HEAD == last_reviewed_commit == PR head` with checks `passed|no-required`; never route by review round alone
114
114
  - After handling `last_reviewed_commit`, run `agent-infra-internal task-event {task-id} review-code.completed --agent {standard-agent-token} --artifact {review-artifact} --verdict {approved|changes-requested|rejected} --blockers {unresolved-blockers} --major {unresolved-major} --minor {unresolved-minor} --manual-validation {n} {execution-flag}`
115
115
 
116
116
  Always include the `Manual-validation: {n}` field in the done log, including when it is 0.
@@ -95,7 +95,7 @@ agent-infra-internal task-snapshot {task-id} --format text
95
95
 
96
96
  ### 6. 更新任务状态
97
97
 
98
- - 报告完成后,新 finding 逐条调用 `agent-infra-internal task-ledger {task-id} finding-upsert --stage code --review-artifact {review-artifact} --ordinal {n} --severity {blocker|major|minor} --evidence {review-artifact}#{anchor}`;复核上一轮响应时调用 `finding-review --id {ledger-id} --status {confirmed|closed|open|needs-human-decision} --evidence {相称证据}`。不得扫描编号或手写账本行
98
+ - 报告完成后,新 finding 逐条调用 `agent-infra-internal task-ledger {task-id} finding-upsert --stage code --review-artifact {review-artifact} --ordinal {n} --severity {blocker|major|minor} --evidence {review-artifact}#{anchor}`;复核上一轮响应时调用 `finding-review --id {ledger-id} --status {confirmed|closed|open|needs-human-decision} --evidence {相称证据}`。升级为 `needs-human-decision` 时,按详情块中的判断追加 `--needs-implementation true|false`。不得扫描编号或手写账本行
99
99
  - 全部账本写入完成后只调用一次 `agent-infra-internal task-review {task-id} finalize-summary --stage code --artifact {review-artifact} {execution-flag}`
100
100
 
101
101
  从该次返回值绑定并复用以下结构化映射:
@@ -108,7 +108,7 @@ agent-infra-internal task-snapshot {task-id} --format text
108
108
 
109
109
  该 intent 原子最终化报告摘要并返回同一次账本快照;不得再调用 `stage-status`、手工替换占位符或扫描问题清单。最终化失败或返回字段缺失时,停止在完成事件之前。以同一次返回的 `stageStatus.canAdvance` 决定 verdict 和下一步;仅 `canAdvance=true` 可用 Approved
110
110
  - 仅当 `canAdvance=true`、本轮结论为 Approved 且 `T == R^{tree}` 时写入 `last_reviewed_commit: {R}`;Approved 快照包含未提交差异时清除旧值。否则保留既有值,不得推进或清空
111
- - Approved 出口继续按 `reference/output-templates.md` 采集 PR 与 required-checks 事实:未提交/未推送走 `commit`,无 PR 走 `create-pr`(无 PR 流程除外),checks 未终态走 `watch-pr`,仅 `HEAD == last_reviewed_commit == PR head` 且 checks 为 `passed|no-required` 时走 `complete-task`;不得仅按审查轮次分流
111
+ - Approved 出口继续按 `reference/output-templates.md` 采集 PR 与全部 checks 事实:未提交/未推送走 `commit`,无 PR 走 `create-pr`(无 PR 流程除外),checks 未终态走 `watch-pr`,仅 `HEAD == last_reviewed_commit == PR head` 且 checks 为 `passed|no-required` 时走 `complete-task`;不得仅按审查轮次分流
112
112
  - 完成 `last_reviewed_commit` 处理后执行 `agent-infra-internal task-event {task-id} review-code.completed --agent {standard-agent-token} --artifact {review-artifact} --verdict {approved|changes-requested|rejected} --blockers {unresolved-blockers} --major {unresolved-major} --minor {unresolved-minor} --manual-validation {n} {execution-flag}`
113
113
 
114
114
  完成日志必须始终写入 `Manual-validation: {n}` 字段,0 也保留。
@@ -59,7 +59,7 @@ Next step - create a Pull Request:
59
59
  {next-step-commands}
60
60
  ```
61
61
 
62
- #### Branch A3: Watch Required Checks
62
+ #### Branch A3: Watch All Checks
63
63
 
64
64
  Populate `{next-step-commands}` for this scenario by running `agent-infra-internal agent-client next-steps --skill watch-pr --task-ref {task-ref}`.
65
65
 
@@ -59,7 +59,7 @@
59
59
  {next-step-commands}
60
60
  ```
61
61
 
62
- #### 场景 A3:监控 required checks
62
+ #### 场景 A3:监控全部 checks
63
63
 
64
64
  使用 `agent-infra-internal agent-client next-steps --skill watch-pr --task-ref {task-ref}` 生成本场景的 `{next-step-commands}`。
65
65
 
@@ -55,13 +55,32 @@ agent-infra-internal pr-review-grade resolve-host --pr {pr-number} [--cwd <path>
55
55
 
56
56
  `resolve-host` returns a typed `HostResolution` (`unique` / `ambiguous` / `none`). Branch as follows:
57
57
 
58
- - **Unique host**: bind `{task-id}` and enumerate `analysis*`/`plan*`/`code*`/`review-*`/`pr-review*` presence (go to step 2).
58
+ - **Unique host**: bind `{task-id}`, call `task-activity pr-review-inspect` to obtain the canonical round, prepared/open state, and latest successful review identity, then start this round using the recovery rules below (go to step 2).
59
59
  - **Ambiguous hosts**: `resolve-host` returns `ambiguous` and `decide` refuses to classify (fail closed). Stop and ask a human to pin the unique host; do not enter evidence classification.
60
60
  - **No host**: block by default and require linking an Issue/task first (show linking guidance); never auto-create/import an Issue. Only when the user explicitly chooses a "one-shot review" do process files land in `.agents/workspace/reviews/{pr-number}/` (`recoverable: false`).
61
61
 
62
+ After the task-anchored path resolves the host and remote head, run:
63
+
64
+ ```bash
65
+ agent-infra-internal task-activity {task-id} pr-review-inspect
66
+ ```
67
+
68
+ - `prepared`: reuse that artifact; `open` with an unchanged head: replay start for the same artifact/head (a no-op) and resume the round.
69
+ - `open` with a changed head: first set the old artifact Formal Review Status to `superseded`, then terminate it using the old artifact/head; continue with the next round returned by inspect.
70
+ - No prepared/open round: create the next artifact skeleton from `reference/report-template.md`, initially recording the state check, identity, reviewed head, and `Formal Review Status: pending`.
71
+
72
+ After this branch and before step 2 evidence grading, write started:
73
+
74
+ ```bash
75
+ agent-infra-internal task-activity {task-id} pr-review-start --agent {agent} \
76
+ --artifact {pr-review-artifact} --head {head-sha}
77
+ ```
78
+
79
+ The one-shot path never calls `task-activity`. For a controlled failure after started where the formal Review is known not to have been published, first set the artifact status to `aborted`, then call `pr-review-terminate --outcome aborted --reason <single-line>` with the same artifact/head. If publication outcome is uncertain, leave the round open rather than guessing aborted.
80
+
62
81
  ### 2. Single decide: evidence enumeration + classification + risk + mode
63
82
 
64
- Write the host, artifact presence, head state, and the six pure-evidence risk factors to an input JSON, then call once:
83
+ Write the host, artifact presence, head state, and the six pure-evidence risk factors to an input JSON. Use only the highest `applied` / `no-op` artifact returned by inspect as the prior review; pending/aborted/superseded/failed artifacts count only toward round continuity. Then call once:
65
84
 
66
85
  ```bash
67
86
  agent-infra-internal pr-review-grade decide --input-file {decide-input.json} [--cwd <path>]
@@ -71,7 +90,7 @@ Returns the full `DecisionRecord` (`scenario` / `freshness` / `alignment` / `ris
71
90
 
72
91
  ### 3. Generate `pr-review-rN.md`
73
92
 
74
- Generate this round's artifact per `reference/report-template.md`. In `reconstruct` mode (or `audit` with insufficient evidence), write a "Reconstruction Context" section (requirement boundary / architecture choices / impact surface / validation coverage, see `reference/evidence-grading.md`) before the line-level findings. Record `recoverable: true|false` in the frontmatter or header (the one-shot path sets `false`).
93
+ Complete this round's artifact per `reference/report-template.md`; the task-anchored path preserves the identity/head/pending status written in step 1 and does not reallocate the round. In `reconstruct` mode (or `audit` with insufficient evidence), write a "Reconstruction Context" section (requirement boundary / architecture choices / impact surface / validation coverage, see `reference/evidence-grading.md`) before the line-level findings. Record `recoverable: true|false` in the frontmatter or header (the one-shot path sets `false`). After finalizing the findings list, freeze `{verdict, blockers, major, minor}` once; the formal Review body and step 6 complete payload must consume that same object directly, never recounting report prose.
75
94
 
76
95
  ### 4. Sync the Issue artifact comments (task-anchored path)
77
96
 
@@ -99,18 +118,27 @@ agent-infra-internal platform-pr-review publish --pr {pr-number} --scope {taskId
99
118
  --commit {head-sha} --event {COMMENT|APPROVE|REQUEST_CHANGES} --body-file {review-body.md} [--dry-run] [--cwd <path>]
100
119
  ```
101
120
 
102
- `publish` generates and validates the marker (first line) in core and is idempotent per marker + commit (replay is a no-op; marker hit on a different commit fails stably). On head drift, stop and start a new round (re-run step 1 with round `{round}+1`).
121
+ `publish` generates and validates the marker (first line) in core and is idempotent per marker + commit (replay is a no-op; marker hit on a different commit fails stably). On head drift, first set the old artifact status to `superseded`, then close the old round:
122
+
123
+ ```bash
124
+ agent-infra-internal task-activity {task-id} pr-review-terminate --agent {agent} \
125
+ --artifact {pr-review-artifact} --head {head-sha} \
126
+ --outcome superseded --reason "head changed before publish"
127
+ ```
128
+
129
+ After closure, re-run step 1 for the next canonical round; never start the new round first. If the remote outcome of `publish` is uncertain, keep the round open and recover through marker + commit idempotency on retry.
103
130
 
104
131
  ### 6. Write back the publication result and task state
105
132
 
106
- - **Task-anchored path**: write the Review ID/URL into the `pr-review-rN.md` "Publication Result" section and append the Activity Log entry:
133
+ - **Task-anchored path**: after publish returns `applied` / `no-op`, write the Review ID/URL and matching Formal Review Status into the `pr-review-rN.md` "Publication Result" section, then close the Activity Log with the exact verdict/counts frozen in step 3:
107
134
 
108
135
  ```bash
109
- agent-infra-internal task-activity {task-id} append --step "Review PR (Round {round})" --agent {agent} \
110
- --note "receipt {receipt} · Review URL {review-url}" --artifact {pr-review-artifact}
136
+ agent-infra-internal task-activity {task-id} pr-review-complete --agent {agent} \
137
+ --artifact {pr-review-artifact} --head {head-sha} --verdict {approved|changes-requested|commented} \
138
+ --blockers {blockers} --major {major} --minor {minor}
111
139
  ```
112
140
 
113
- `task-activity` atomically completes the Activity Log append, the `## Review Feedback` link, and the version-stamp refresh via `writeTask`; it never changes `current_step`.
141
+ `task-activity` generates `Verdict: <result>, blockers: N, major: N, minor: N → {pr-review-artifact}` from the typed payload and atomically writes the Activity Log, `## Review Feedback` link, and version stamp through `writeTask`. It never changes `current_step` or puts receipt/head/Review URL into the NOTE.
114
142
 
115
143
  - **One-shot path (no task)**: write the Review ID/URL only into the `pr-review-rN.md` "Publication Result" section; do not call `task-activity`.
116
144
 
@@ -55,13 +55,32 @@ agent-infra-internal pr-review-grade resolve-host --pr {pr-number} [--cwd <path>
55
55
 
56
56
  `resolve-host` 输出 `HostResolution`(`unique` / `ambiguous` / `none`),按以下策略分流:
57
57
 
58
- - **唯一宿主**:绑定 `{task-id}`,用 artifact 枚举确定 `analysis*`/`plan*`/`code*`/`review-*`/`pr-review*` 的存在性(进入步骤 2)。
58
+ - **唯一宿主**:绑定 `{task-id}`,调用 `task-activity pr-review-inspect` 取得 canonical round、prepared/open 状态和最近成功审查身份,再按下述恢复规则开始本轮(进入步骤 2)。
59
59
  - **多宿主歧义**:`resolve-host` 返回 `ambiguous`,`decide` 会拒绝分类(fail closed)。立即停止并提示人工指定唯一宿主;不进入证据分类。
60
60
  - **无宿主**:默认阻塞,要求先建立 Issue/task 关联(给出关联指引),不自动创建/导入 Issue。仅当用户显式选择「仅一次性检视」时,过程文件写入 `.agents/workspace/reviews/{pr-number}/`(`recoverable: false`)。
61
61
 
62
+ 任务锚定路径在宿主与远端 head 确定后执行:
63
+
64
+ ```bash
65
+ agent-infra-internal task-activity {task-id} pr-review-inspect
66
+ ```
67
+
68
+ - `prepared`:复用该 artifact;`open` 且 head 未变:对同一 artifact/head 重放 start(no-op)并恢复该轮。
69
+ - `open` 且 head 已变:先把旧 artifact 的正式 Review 状态写为 `superseded`,再用旧 artifact/head 执行 terminate;随后使用 inspect 返回的 next round。
70
+ - 无 prepared/open:按 `reference/report-template.md` 创建 next artifact 骨架,先写状态核对、身份信息、被审 head 与 `正式 Review 状态: pending`。
71
+
72
+ 在上述分流完成后、步骤 2 证据分级开始前写 started:
73
+
74
+ ```bash
75
+ agent-infra-internal task-activity {task-id} pr-review-start --agent {agent} \
76
+ --artifact {pr-review-artifact} --head {head-sha}
77
+ ```
78
+
79
+ 一次性路径不调用 `task-activity`。任意 started 后、正式 Review 明确尚未发布的受控失败,都先把 artifact 状态写为 `aborted`,再以同一 artifact/head 调用 `pr-review-terminate --outcome aborted --reason <single-line>`;发布结果不确定时保持 open,不臆断 aborted。
80
+
62
81
  ### 2. 单次 decide:证据枚举 + 场景分类 + 风险分级 + 模式选择
63
82
 
64
- 把宿主、artifact 存在性、head 状态与六个纯证据风险因素写入输入 JSON,调用一次:
83
+ 把宿主、artifact 存在性、head 状态与六个纯证据风险因素写入输入 JSON。prior review 只使用 inspect 返回的最高 `applied` / `no-op` artifact;pending/aborted/superseded/failed 只参与 round 连续性,不作为既有结论。调用一次:
65
84
 
66
85
  ```bash
67
86
  agent-infra-internal pr-review-grade decide --input-file {decide-input.json} [--cwd <path>]
@@ -71,7 +90,7 @@ agent-infra-internal pr-review-grade decide --input-file {decide-input.json} [--
71
90
 
72
91
  ### 3. 生成 `pr-review-rN.md`
73
92
 
74
- 按 `reference/report-template.md` 生成本轮产物。`reconstruct`(或 `audit` 证据不足)时,在行级 finding 之前先写「重建上下文」段(需求边界 / 架构选择 / 影响面 / 验证覆盖,见 `reference/evidence-grading.md`)。frontmatter 或首部记录 `recoverable: true|false`(一次性路径为 `false`)。
93
+ 按 `reference/report-template.md` 完成本轮产物;任务锚定路径保留步骤 1 已写入的身份/head/pending 状态,不重新分配 round。`reconstruct`(或 `audit` 证据不足)时,在行级 finding 之前先写「重建上下文」段(需求边界 / 架构选择 / 影响面 / 验证覆盖,见 `reference/evidence-grading.md`)。frontmatter 或首部记录 `recoverable: true|false`(一次性路径为 `false`)。完成最终问题清单后,一次性冻结 `{verdict, blockers, major, minor}`;正式 Review 正文与步骤 6 的 complete payload 必须直接复用该对象,不从报告文案反向统计。
75
94
 
76
95
  ### 4. 同步 Issue artifact 评论(任务锚定路径)
77
96
 
@@ -99,18 +118,27 @@ agent-infra-internal platform-pr-review publish --pr {pr-number} --scope {taskId
99
118
  --commit {head-sha} --event {COMMENT|APPROVE|REQUEST_CHANGES} --body-file {review-body.md} [--dry-run] [--cwd <path>]
100
119
  ```
101
120
 
102
- `publish` 由 core 生成并校验 marker(首行),按 marker + commit 幂等(重放 no-op;marker 命中但 commit 不一致稳定失败)。head 漂移则停止并转入新轮次(重新执行步骤 1,轮次 `{round}+1`)。
121
+ `publish` 由 core 生成并校验 marker(首行),按 marker + commit 幂等(重放 no-op;marker 命中但 commit 不一致稳定失败)。head 漂移时,先把旧 artifact 状态写为 `superseded`,再闭合旧轮:
122
+
123
+ ```bash
124
+ agent-infra-internal task-activity {task-id} pr-review-terminate --agent {agent} \
125
+ --artifact {pr-review-artifact} --head {head-sha} \
126
+ --outcome superseded --reason "head changed before publish"
127
+ ```
128
+
129
+ 闭合成功后重新执行步骤 1,进入下一 canonical round;不得先写新轮 started。若 publish 调用的远端结果不确定,保留 open 并在重试时依赖 marker + commit 恢复。
103
130
 
104
131
  ### 6. 回写发布结果与任务状态
105
132
 
106
- - **任务锚定路径**:把 Review ID/URL 写入 `pr-review-rN.md`「发布结果」段,并追加活动日志:
133
+ - **任务锚定路径**:publish 返回 `applied` / `no-op` 后,把 Review ID/URL 与同名正式 Review 状态写入 `pr-review-rN.md`「发布结果」段,再以步骤 3 冻结的同一组 verdict/counts 闭合活动日志:
107
134
 
108
135
  ```bash
109
- agent-infra-internal task-activity {task-id} append --step "Review PR (Round {round})" --agent {agent} \
110
- --note "receipt {receipt} · Review URL {review-url}" --artifact {pr-review-artifact}
136
+ agent-infra-internal task-activity {task-id} pr-review-complete --agent {agent} \
137
+ --artifact {pr-review-artifact} --head {head-sha} --verdict {approved|changes-requested|commented} \
138
+ --blockers {blockers} --major {major} --minor {minor}
111
139
  ```
112
140
 
113
- `task-activity` 经 `writeTask` 原子完成 Activity Log 追加、`## 审查反馈` 链接与版本戳刷新;不改 `current_step`。
141
+ `task-activity` 由 typed payload 生成 `Verdict: <结论>, blockers: N, major: N, minor: N → {pr-review-artifact}`,并经 `writeTask` 原子完成 Activity Log、`## 审查反馈` 链接与版本戳刷新;不改 `current_step`,也不把 receipt/head/Review URL 写入 NOTE。
114
142
 
115
143
  - **一次性路径(无任务)**:Review ID/URL 只写 `pr-review-rN.md`「发布结果」段,不调用 `task-activity`。
116
144
 
@@ -69,7 +69,7 @@ Land the following in order before the line-level findings, without impersonatin
69
69
 
70
70
  ## Publication Result
71
71
 
72
- - **Formal Review Status**: {applied / no-op / blocked / failed}
72
+ - **Formal Review Status**: {pending / applied / no-op / aborted / superseded / blocked / failed}
73
73
  - **Review ID**: {review-id or N/A}
74
74
  - **Review URL**: {review-url or N/A}
75
75
  - **Issue Artifact Comment URL**: {comment-url or N/A}
@@ -69,7 +69,7 @@
69
69
 
70
70
  ## 发布结果
71
71
 
72
- - **正式 Review 状态**:{applied / no-op / blocked / failed}
72
+ - **正式 Review 状态**:{pending / applied / no-op / aborted / superseded / blocked / failed}
73
73
  - **Review ID**:{review-id 或 N/A}
74
74
  - **Review URL**:{review-url 或 N/A}
75
75
  - **Issue artifact 评论 URL**:{comment-url 或 N/A}
@@ -124,12 +124,19 @@ const AGENT_CLIENT_MANIFEST = [
124
124
  ],
125
125
  "managed": [
126
126
  ".claude/commands/",
127
- ".claude/agents/"
127
+ ".claude/agents/",
128
+ ".claude/rules/"
128
129
  ],
129
130
  "merged": [
130
131
  ".claude/settings.json"
131
132
  ],
132
- "ejected": []
133
+ "ejected": [],
134
+ "customCommand": {
135
+ "target": ".claude/commands/${skillName}.md",
136
+ "frontmatter": {},
137
+ "includeUsage": true,
138
+ "inheritDisableModelInvocation": true
139
+ }
133
140
  },
134
141
  {
135
142
  "id": "codex",
@@ -165,7 +172,15 @@ const AGENT_CLIENT_MANIFEST = [
165
172
  ".opencode/commands/"
166
173
  ],
167
174
  "merged": [],
168
- "ejected": []
175
+ "ejected": [],
176
+ "customCommand": {
177
+ "target": ".opencode/commands/${skillName}.md",
178
+ "frontmatter": {
179
+ "agent": "general",
180
+ "subtask": false
181
+ },
182
+ "argumentsToken": "$ARGUMENTS"
183
+ }
169
184
  }
170
185
  ];
171
186
  const CUSTOM_TUI_CONTRACT = {
@@ -565,15 +580,12 @@ function detectCustomSkills(projectRoot, templateSkillNames) {
565
580
  .sort((left, right) => left.dirName.localeCompare(right.dirName));
566
581
  }
567
582
 
568
- function isCustomProtected(targetPath, customSkills, customTUICommandTargets) {
583
+ function isCustomProtected(targetPath, customSkills, customCommandTargets) {
569
584
  const normalized = norm(targetPath);
570
585
 
571
586
  return customSkills.some(({ dirName }) => (
572
- normalized.startsWith(`.agents/skills/${dirName}/`) ||
573
- normalized === `.claude/commands/${dirName}.md` ||
574
- normalized === `.opencode/commands/${dirName}.md` ||
575
- customTUICommandTargets.has(normalized)
576
- ));
587
+ normalized.startsWith(`.agents/skills/${dirName}/`)
588
+ )) || customCommandTargets.has(normalized);
577
589
  }
578
590
 
579
591
  function recordCustomTUISkipped(report, entry) {
@@ -780,43 +792,37 @@ function formatYamlMetadata(key, value) {
780
792
  return [`${key}: |-`, ...value.split('\n').map((line) => ` ${line}`)];
781
793
  }
782
794
 
783
- function generateClaudeCommand(skill, lang) {
784
- const isZhCN = lang === 'zh-CN';
785
- const lines = ['---', ...formatYamlMetadata('description', skill.description)];
786
-
787
- if (skill.args) {
788
- lines.push(`usage: ${JSON.stringify(`/${skill.dirName} ${skill.args}`)}`);
789
- }
790
-
791
- if (skill.disableModelInvocation) {
792
- lines.push('disable-model-invocation: true');
793
- }
794
-
795
- lines.push('---', '');
796
- lines.push(
797
- isZhCN
798
- ? `读取并执行 \`.agents/skills/${skill.dirName}/SKILL.md\` 中的 ${skill.dirName} 技能。`
799
- : `Read and execute the ${skill.dirName} skill from \`.agents/skills/${skill.dirName}/SKILL.md\`.`
800
- );
801
- lines.push('');
802
- lines.push(isZhCN ? '严格按照技能中定义的所有步骤执行。' : 'Follow all steps defined in the skill exactly.');
803
-
804
- return `${lines.join('\n')}\n`;
795
+ function formatYamlScalarMetadata(key, value) {
796
+ if (typeof value === 'boolean') return [`${key}: ${String(value)}`];
797
+ if (/^[A-Za-z0-9_-]+$/.test(value)) return [`${key}: ${value}`];
798
+ return formatYamlMetadata(key, value);
805
799
  }
806
800
 
807
- function generateOpenCodeCommand(skill, lang) {
801
+ function generateAgentClientCommand(skill, lang, descriptor) {
808
802
  const isZhCN = lang === 'zh-CN';
809
803
  const lines = [
810
804
  '---',
811
805
  ...formatYamlMetadata('description', skill.description),
812
- 'agent: general',
813
- 'subtask: false',
814
- '---',
815
- ''
806
+ ...Object.entries(descriptor.frontmatter).flatMap(([key, value]) =>
807
+ formatYamlScalarMetadata(key, value)
808
+ )
816
809
  ];
817
810
 
818
- if (skill.args) {
819
- lines.push(isZhCN ? '参数:$ARGUMENTS' : 'Arguments: $ARGUMENTS');
811
+ if (descriptor.includeUsage && skill.args) {
812
+ lines.push(`usage: ${JSON.stringify(`${descriptor.invocation} ${skill.args}`)}`);
813
+ }
814
+ if (descriptor.inheritDisableModelInvocation && skill.disableModelInvocation) {
815
+ lines.push('disable-model-invocation: true');
816
+ }
817
+
818
+ lines.push('---', '');
819
+
820
+ if (skill.args && descriptor.argumentsToken) {
821
+ lines.push(
822
+ isZhCN
823
+ ? `参数:${descriptor.argumentsToken}`
824
+ : `Arguments: ${descriptor.argumentsToken}`
825
+ );
820
826
  lines.push('');
821
827
  }
822
828
 
@@ -1029,6 +1035,15 @@ function buildCustomTUICommandTargets(projectRoot, customSkills, customTUIs, tem
1029
1035
  return targets;
1030
1036
  }
1031
1037
 
1038
+ function buildBuiltinCustomCommandTargets(customSkills, enabledTUIs) {
1039
+ return new Set(AGENT_CLIENT_MANIFEST.flatMap((adapter) => {
1040
+ if (!enabledTUIs.has(adapter.id) || !adapter.customCommand) return [];
1041
+ return customSkills.map((skill) =>
1042
+ adapter.customCommand.target.replaceAll('${skillName}', skill.dirName)
1043
+ );
1044
+ }));
1045
+ }
1046
+
1032
1047
  function learnAndGenerateCommands(projectRoot, customSkills, tool, templateSkillNames, report) {
1033
1048
  const ref = findCustomTUIReference(projectRoot, tool, templateSkillNames, report, true);
1034
1049
  if (!ref) return;
@@ -1060,17 +1075,15 @@ function generateCustomCommands(
1060
1075
  managedWriter
1061
1076
  ) {
1062
1077
  for (const skill of customSkills) {
1063
- if (enabledTUIs.has('claude-code')) {
1064
- managedWriter(
1065
- `.claude/commands/${skill.dirName}.md`,
1066
- generateClaudeCommand(skill, lang),
1067
- report.custom.commands
1068
- );
1069
- }
1070
- if (enabledTUIs.has('opencode')) {
1078
+ for (const adapter of AGENT_CLIENT_MANIFEST) {
1079
+ if (!enabledTUIs.has(adapter.id) || !adapter.customCommand) continue;
1080
+ const descriptor = {
1081
+ ...adapter.customCommand,
1082
+ invocation: adapter.invocation.replaceAll('${skillName}', skill.dirName)
1083
+ };
1071
1084
  managedWriter(
1072
- `.opencode/commands/${skill.dirName}.md`,
1073
- generateOpenCodeCommand(skill, lang),
1085
+ adapter.customCommand.target.replaceAll('${skillName}', skill.dirName),
1086
+ generateAgentClientCommand(skill, lang, descriptor),
1074
1087
  report.custom.commands
1075
1088
  );
1076
1089
  }
@@ -1333,6 +1346,10 @@ function syncTemplates(projectRoot, templateRootOverride) {
1333
1346
  customTUIs,
1334
1347
  templateSkillNames
1335
1348
  );
1349
+ const customCommandTargets = new Set([
1350
+ ...buildBuiltinCustomCommandTargets(protectedCustomSkills, enabledTUIs),
1351
+ ...customTUICommandTargets
1352
+ ]);
1336
1353
 
1337
1354
  for (const category of ['managed', 'merged', 'ejected']) {
1338
1355
  const before = currentRegistry[category];
@@ -1545,7 +1562,7 @@ function syncTemplates(projectRoot, templateRootOverride) {
1545
1562
  const protectedByEjection = ejected.some((pattern) =>
1546
1563
  assetMatches(pattern, target) || globMatch(pattern, target)
1547
1564
  );
1548
- const protectedByCustom = customTUICommandTargets.has(target);
1565
+ const protectedByCustom = customCommandTargets.has(target);
1549
1566
 
1550
1567
  if (protectedByEjection || protectedByCustom || (sourceRoot && sourceRoot !== templateRoot)) {
1551
1568
  report.managed.protected.push({
@@ -1674,7 +1691,7 @@ function syncTemplates(projectRoot, templateRootOverride) {
1674
1691
  for (const projFile of projFiles) {
1675
1692
  if (expectedTargets.has(projFile)) continue;
1676
1693
  if (projFile === configPathRel) continue;
1677
- if (isCustomProtected(projFile, protectedCustomSkills, customTUICommandTargets)) continue;
1694
+ if (isCustomProtected(projFile, protectedCustomSkills, customCommandTargets)) continue;
1678
1695
  if (matchesAny(projFile, merged) || matchesAny(projFile, ejected)) continue;
1679
1696
  if (assetPlan.enabledManaged.includes(entry)) {
1680
1697
  const baseline = trustedBaseline(managedBaselines[projFile]);