@fitlab-ai/agent-infra 0.9.2 → 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 (428) hide show
  1. package/README.md +12 -9
  2. package/README.zh-CN.md +12 -9
  3. package/bin/cli.ts +12 -0
  4. package/dist/bin/cli.js +14 -0
  5. package/dist/bin/internal-cli.js +134 -108
  6. package/dist/lib/agent-clients/adapter.js +137 -4
  7. package/dist/lib/agent-clients/adapters/antigravity-cli.js +64 -0
  8. package/dist/lib/{sandbox/credentials.js → agent-clients/adapters/claude-code-credentials.js} +4 -14
  9. package/dist/lib/agent-clients/adapters/claude-code-refresh.js +85 -0
  10. package/dist/lib/agent-clients/adapters/claude-code-sandbox.js +247 -0
  11. package/dist/lib/agent-clients/adapters/claude-code.js +27 -4
  12. package/dist/lib/agent-clients/adapters/codex.js +9 -0
  13. package/dist/lib/agent-clients/adapters/index.js +2 -2
  14. package/dist/lib/agent-clients/adapters/opencode-sandbox.js +108 -0
  15. package/dist/lib/agent-clients/adapters/opencode.js +24 -3
  16. package/dist/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
  17. package/dist/lib/agent-clients/config.js +42 -4
  18. package/dist/lib/agent-clients/next-steps.js +11 -2
  19. package/dist/lib/agent-clients/reconcile.js +2 -1
  20. package/dist/lib/agent-clients/registry.js +16 -2
  21. package/dist/lib/agent-clients/schema.js +18 -0
  22. package/dist/lib/agent-clients/tokens.js +49 -0
  23. package/dist/lib/agent-clients/types.js +1 -1
  24. package/dist/lib/defaults.json +1 -1
  25. package/dist/lib/git/workflow.js +54 -1
  26. package/dist/lib/internal/agent-client.js +61 -4
  27. package/dist/lib/internal/git-workflow.js +6 -1
  28. package/dist/lib/internal/platform-checks.js +3 -3
  29. package/dist/lib/internal/platform-comment.js +29 -2
  30. package/dist/lib/internal/platform-issue.js +7 -0
  31. package/dist/lib/internal/platform-pr-review.js +132 -0
  32. package/dist/lib/internal/platform-pr.js +20 -2
  33. package/dist/lib/internal/platform-release-notes.js +52 -16
  34. package/dist/lib/internal/pr-review-grade.js +140 -0
  35. package/dist/lib/internal/release-workflow.js +13 -6
  36. package/dist/lib/internal/sandbox-control.js +24 -0
  37. package/dist/lib/internal/task-activity.js +105 -0
  38. package/dist/lib/internal/task-event.js +17 -1
  39. package/dist/lib/internal/task-ledger.js +12 -3
  40. package/dist/lib/internal/task-lifecycle.js +26 -1
  41. package/dist/lib/internal/task-orchestration.js +167 -18
  42. package/dist/lib/internal/task-review.js +8 -3
  43. package/dist/lib/platform/adapters.js +8 -1
  44. package/dist/lib/platform/completion-backfill.js +122 -0
  45. package/dist/lib/platform/github-client.js +19 -2
  46. package/dist/lib/platform/issue-comments.js +3 -2
  47. package/dist/lib/platform/merged-pr-equivalence.js +115 -5
  48. package/dist/lib/platform/pr-checks.js +65 -42
  49. package/dist/lib/platform/pr-review.js +166 -0
  50. package/dist/lib/platform/pull-requests.js +371 -4
  51. package/dist/lib/platform/release-notes.js +85 -3
  52. package/dist/lib/platform/releases.js +13 -5
  53. package/dist/lib/pr-review/evidence-grading.js +229 -0
  54. package/dist/lib/process-data/index.js +239 -0
  55. package/dist/lib/process-data/normalize.js +198 -0
  56. package/dist/lib/process-data/privacy.js +33 -0
  57. package/dist/lib/process-data/reconcile.js +95 -0
  58. package/dist/lib/process-data/repair.js +58 -0
  59. package/dist/lib/process-data/sources.js +345 -0
  60. package/dist/lib/process-data/store.js +282 -0
  61. package/dist/lib/process-data/types.js +2 -0
  62. package/dist/lib/run/index.js +4 -3
  63. package/dist/lib/run/tui.js +10 -13
  64. package/dist/lib/sandbox/agent-client-reconciler.js +26 -2
  65. package/dist/lib/sandbox/capture.js +7 -2
  66. package/dist/lib/sandbox/commands/create.js +109 -248
  67. package/dist/lib/sandbox/commands/enter.js +15 -47
  68. package/dist/lib/sandbox/commands/list-running.js +16 -6
  69. package/dist/lib/sandbox/commands/ls.js +10 -6
  70. package/dist/lib/sandbox/commands/rebuild.js +4 -3
  71. package/dist/lib/sandbox/commands/refresh.js +4 -84
  72. package/dist/lib/sandbox/commands/rm.js +24 -3
  73. package/dist/lib/sandbox/commands/show.js +13 -4
  74. package/dist/lib/sandbox/commands/start.js +7 -4
  75. package/dist/lib/sandbox/config.js +2 -0
  76. package/dist/lib/sandbox/constants.js +6 -0
  77. package/dist/lib/sandbox/control/client.js +44 -0
  78. package/dist/lib/sandbox/control/protocol.js +35 -0
  79. package/dist/lib/sandbox/control/server.js +109 -0
  80. package/dist/lib/sandbox/dockerfile.js +36 -13
  81. package/dist/lib/sandbox/mounts.js +17 -4
  82. package/dist/lib/sandbox/recovery.js +128 -5
  83. package/dist/lib/sandbox/redaction.js +12 -0
  84. package/dist/lib/sandbox/runtimes/base.dockerfile +24 -74
  85. package/dist/lib/sandbox/workspace-identity.js +95 -0
  86. package/dist/lib/sandbox/workspace-view.js +103 -0
  87. package/dist/lib/task/activity-intent.js +307 -0
  88. package/dist/lib/task/artifact-lifecycle.js +2 -1
  89. package/dist/lib/task/commands/log.js +15 -14
  90. package/dist/lib/task/commit-finalization.js +267 -0
  91. package/dist/lib/task/commit-intent.js +165 -0
  92. package/dist/lib/task/decision-intents.js +31 -17
  93. package/dist/lib/task/delegation-receipts.js +25 -4
  94. package/dist/lib/task/events.js +67 -28
  95. package/dist/lib/task/finalization-artifacts.js +35 -0
  96. package/dist/lib/task/implementation-inputs.js +54 -7
  97. package/dist/lib/task/ledger-intents.js +35 -1
  98. package/dist/lib/task/lifecycle-execution.js +46 -0
  99. package/dist/lib/task/orchestration.js +753 -54
  100. package/dist/lib/task/resolve-ref.js +41 -1
  101. package/dist/lib/task/review-finalization.js +29 -9
  102. package/dist/lib/task/task-execution-lock.js +231 -0
  103. package/dist/lib/task/verification-checks.js +1 -1
  104. package/dist/lib/task/verification-engine.js +218 -2
  105. package/dist/lib/task/verification.js +4 -3
  106. package/dist/lib/task/workspace-snapshot.js +17 -5
  107. package/lib/agent-clients/adapter.ts +201 -4
  108. package/lib/agent-clients/adapters/antigravity-cli.ts +65 -0
  109. package/lib/{sandbox/credentials.ts → agent-clients/adapters/claude-code-credentials.ts} +3 -18
  110. package/lib/agent-clients/adapters/claude-code-refresh.ts +128 -0
  111. package/lib/agent-clients/adapters/claude-code-sandbox.ts +295 -0
  112. package/lib/agent-clients/adapters/claude-code.ts +31 -4
  113. package/lib/agent-clients/adapters/codex.ts +9 -0
  114. package/lib/agent-clients/adapters/index.ts +2 -2
  115. package/lib/agent-clients/adapters/opencode-sandbox.ts +136 -0
  116. package/lib/agent-clients/adapters/opencode.ts +27 -3
  117. package/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
  118. package/lib/agent-clients/config.ts +49 -4
  119. package/lib/agent-clients/next-steps.ts +15 -2
  120. package/lib/agent-clients/reconcile.ts +2 -1
  121. package/lib/agent-clients/registry.ts +19 -1
  122. package/lib/agent-clients/schema.ts +18 -0
  123. package/lib/agent-clients/tokens.ts +53 -0
  124. package/lib/agent-clients/types.ts +15 -1
  125. package/lib/defaults.json +1 -1
  126. package/lib/git/workflow.ts +66 -2
  127. package/lib/internal/agent-client.ts +59 -4
  128. package/lib/internal/git-workflow.ts +5 -1
  129. package/lib/internal/platform-checks.ts +4 -4
  130. package/lib/internal/platform-comment.ts +17 -2
  131. package/lib/internal/platform-issue.ts +4 -0
  132. package/lib/internal/platform-pr-review.ts +104 -0
  133. package/lib/internal/platform-pr.ts +14 -1
  134. package/lib/internal/platform-release-notes.ts +59 -16
  135. package/lib/internal/pr-review-grade.ts +130 -0
  136. package/lib/internal/release-workflow.ts +13 -6
  137. package/lib/internal/sandbox-control.ts +24 -0
  138. package/lib/internal/task-activity.ts +91 -0
  139. package/lib/internal/task-event.ts +9 -1
  140. package/lib/internal/task-ledger.ts +12 -3
  141. package/lib/internal/task-lifecycle.ts +26 -1
  142. package/lib/internal/task-orchestration.ts +123 -14
  143. package/lib/internal/task-review.ts +8 -3
  144. package/lib/platform/adapters.ts +29 -2
  145. package/lib/platform/completion-backfill.ts +134 -0
  146. package/lib/platform/github-client.ts +20 -2
  147. package/lib/platform/issue-comments.ts +3 -2
  148. package/lib/platform/merged-pr-equivalence.ts +127 -5
  149. package/lib/platform/pr-checks.ts +73 -46
  150. package/lib/platform/pr-review.ts +201 -0
  151. package/lib/platform/pull-requests.ts +444 -3
  152. package/lib/platform/release-notes.ts +100 -4
  153. package/lib/platform/releases.ts +16 -4
  154. package/lib/pr-review/evidence-grading.ts +318 -0
  155. package/lib/process-data/index.ts +224 -0
  156. package/lib/process-data/normalize.ts +202 -0
  157. package/lib/process-data/privacy.ts +41 -0
  158. package/lib/process-data/reconcile.ts +110 -0
  159. package/lib/process-data/repair.ts +64 -0
  160. package/lib/process-data/sources.ts +354 -0
  161. package/lib/process-data/store.ts +315 -0
  162. package/lib/process-data/types.ts +135 -0
  163. package/lib/run/index.ts +5 -3
  164. package/lib/run/tui.ts +14 -12
  165. package/lib/sandbox/agent-client-reconciler.ts +44 -2
  166. package/lib/sandbox/capture.ts +9 -2
  167. package/lib/sandbox/commands/create.ts +126 -280
  168. package/lib/sandbox/commands/enter.ts +13 -59
  169. package/lib/sandbox/commands/list-running.ts +23 -6
  170. package/lib/sandbox/commands/ls.ts +22 -6
  171. package/lib/sandbox/commands/rebuild.ts +4 -3
  172. package/lib/sandbox/commands/refresh.ts +4 -126
  173. package/lib/sandbox/commands/rm.ts +24 -3
  174. package/lib/sandbox/commands/show.ts +30 -4
  175. package/lib/sandbox/commands/start.ts +6 -4
  176. package/lib/sandbox/config.ts +4 -0
  177. package/lib/sandbox/constants.ts +8 -0
  178. package/lib/sandbox/control/client.ts +55 -0
  179. package/lib/sandbox/control/protocol.ts +75 -0
  180. package/lib/sandbox/control/server.ts +117 -0
  181. package/lib/sandbox/dockerfile.ts +66 -13
  182. package/lib/sandbox/mounts.ts +24 -4
  183. package/lib/sandbox/recovery.ts +163 -6
  184. package/lib/sandbox/redaction.ts +14 -0
  185. package/lib/sandbox/runtimes/base.dockerfile +24 -74
  186. package/lib/sandbox/tool-types.ts +16 -0
  187. package/lib/sandbox/workspace-identity.ts +123 -0
  188. package/lib/sandbox/workspace-view.ts +143 -0
  189. package/lib/server/server.schema.json +2 -2
  190. package/lib/task/activity-intent.ts +417 -0
  191. package/lib/task/artifact-lifecycle.ts +2 -1
  192. package/lib/task/commands/log.ts +15 -14
  193. package/lib/task/commit-finalization.ts +356 -0
  194. package/lib/task/commit-intent.ts +230 -0
  195. package/lib/task/decision-intents.ts +32 -12
  196. package/lib/task/delegation-receipts.ts +34 -5
  197. package/lib/task/events.ts +75 -30
  198. package/lib/task/finalization-artifacts.ts +58 -0
  199. package/lib/task/implementation-inputs.ts +62 -8
  200. package/lib/task/ledger-intents.ts +43 -3
  201. package/lib/task/lifecycle-execution.ts +106 -0
  202. package/lib/task/orchestration.ts +1019 -72
  203. package/lib/task/resolve-ref.ts +46 -1
  204. package/lib/task/review-finalization.ts +40 -9
  205. package/lib/task/task-execution-lock.ts +296 -0
  206. package/lib/task/verification-checks.ts +1 -1
  207. package/lib/task/verification-engine.ts +249 -2
  208. package/lib/task/verification.ts +5 -3
  209. package/lib/task/workspace-snapshot.ts +26 -5
  210. package/package.json +3 -3
  211. package/templates/.agents/QUICKSTART.en.md +25 -8
  212. package/templates/.agents/QUICKSTART.zh-CN.md +25 -8
  213. package/templates/.agents/README.en.md +10 -7
  214. package/templates/.agents/README.zh-CN.md +10 -7
  215. package/templates/.agents/hooks/lifecycle-delegation.js +15 -4
  216. package/templates/.agents/rules/README.en.md +1 -1
  217. package/templates/.agents/rules/README.zh-CN.md +1 -1
  218. package/templates/.agents/rules/create-issue.github.en.md +4 -2
  219. package/templates/.agents/rules/create-issue.github.zh-CN.md +4 -2
  220. package/templates/.agents/rules/human-decision-context.en.md +11 -2
  221. package/templates/.agents/rules/human-decision-context.zh-CN.md +11 -2
  222. package/templates/.agents/rules/issue-fields.github.en.md +3 -1
  223. package/templates/.agents/rules/issue-fields.github.zh-CN.md +3 -1
  224. package/templates/.agents/rules/issue-pr-commands.en.md +5 -3
  225. package/templates/.agents/rules/issue-pr-commands.github.en.md +5 -3
  226. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +5 -3
  227. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +5 -3
  228. package/templates/.agents/rules/issue-sync.github.en.md +7 -3
  229. package/templates/.agents/rules/issue-sync.github.zh-CN.md +8 -4
  230. package/templates/.agents/rules/lifecycle-orchestration.en.md +5 -2
  231. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +5 -2
  232. package/templates/.agents/rules/milestone-inference.github.en.md +4 -2
  233. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +4 -2
  234. package/templates/.agents/rules/next-step-output.en.md +3 -1
  235. package/templates/.agents/rules/next-step-output.zh-CN.md +3 -1
  236. package/templates/.agents/rules/no-mid-flow-questions.en.md +17 -0
  237. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +17 -0
  238. package/templates/.agents/rules/pr-checks-commands.en.md +3 -3
  239. package/templates/.agents/rules/pr-checks-commands.github.en.md +2 -2
  240. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +3 -3
  241. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +3 -3
  242. package/templates/.agents/rules/pr-sync.en.md +3 -1
  243. package/templates/.agents/rules/pr-sync.github.en.md +11 -1
  244. package/templates/.agents/rules/pr-sync.github.zh-CN.md +11 -1
  245. package/templates/.agents/rules/pr-sync.zh-CN.md +3 -1
  246. package/templates/.agents/rules/release-commands.en.md +1 -1
  247. package/templates/.agents/rules/release-commands.github.en.md +12 -2
  248. package/templates/.agents/rules/release-commands.github.zh-CN.md +12 -2
  249. package/templates/.agents/rules/release-commands.zh-CN.md +1 -1
  250. package/templates/.agents/rules/review-handshake.zh-CN.md +1 -1
  251. package/templates/.agents/rules/task-management.en.md +13 -0
  252. package/templates/.agents/rules/task-management.zh-CN.md +13 -0
  253. package/templates/.agents/skills/analyze-task/SKILL.en.md +10 -7
  254. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +10 -7
  255. package/templates/.agents/skills/block-task/SKILL.en.md +7 -5
  256. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +7 -5
  257. package/templates/.agents/skills/cancel-task/SKILL.en.md +6 -4
  258. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +6 -4
  259. package/templates/.agents/skills/close-codescan/SKILL.en.md +3 -1
  260. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +3 -1
  261. package/templates/.agents/skills/close-dependabot/SKILL.en.md +3 -1
  262. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +3 -1
  263. package/templates/.agents/skills/code-task/SKILL.en.md +10 -7
  264. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +12 -9
  265. package/templates/.agents/skills/commit/SKILL.en.md +23 -11
  266. package/templates/.agents/skills/commit/SKILL.zh-CN.md +29 -11
  267. package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -1
  268. package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -1
  269. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +49 -0
  270. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +55 -0
  271. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +1 -1
  272. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +1 -1
  273. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
  274. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
  275. package/templates/.agents/skills/commit/reference/task-status-update.en.md +4 -4
  276. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +4 -4
  277. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +6 -4
  278. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +6 -4
  279. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +1 -1
  280. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +1 -1
  281. package/templates/.agents/skills/complete-task/SKILL.en.md +22 -7
  282. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +22 -7
  283. package/templates/.agents/skills/complete-task/config/verify.en.json +1 -0
  284. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +1 -0
  285. package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +17 -0
  286. package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +17 -0
  287. package/templates/.agents/skills/create-pr/SKILL.en.md +7 -5
  288. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +7 -5
  289. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +1 -1
  290. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +1 -1
  291. package/templates/.agents/skills/create-release-note/SKILL.en.md +17 -16
  292. package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +17 -16
  293. package/templates/.agents/skills/create-task/SKILL.en.md +5 -3
  294. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +5 -3
  295. package/templates/.agents/skills/create-task/reference/context-capture.en.md +34 -0
  296. package/templates/.agents/skills/create-task/reference/context-capture.zh-CN.md +34 -0
  297. package/templates/.agents/skills/import-issue/SKILL.en.md +5 -3
  298. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -3
  299. package/templates/.agents/skills/plan-task/SKILL.en.md +8 -5
  300. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +8 -5
  301. package/templates/.agents/skills/post-release/SKILL.en.md +2 -0
  302. package/templates/.agents/skills/post-release/SKILL.zh-CN.md +2 -0
  303. package/templates/.agents/skills/release/SKILL.en.md +16 -10
  304. package/templates/.agents/skills/release/SKILL.zh-CN.md +16 -10
  305. package/templates/.agents/skills/restore-task/SKILL.en.md +4 -1
  306. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +4 -1
  307. package/templates/.agents/skills/review-analysis/SKILL.en.md +7 -4
  308. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +7 -4
  309. package/templates/.agents/skills/review-code/SKILL.en.md +11 -8
  310. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +11 -8
  311. package/templates/.agents/skills/review-code/reference/output-templates.en.md +1 -1
  312. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +1 -1
  313. package/templates/.agents/skills/review-plan/SKILL.en.md +7 -4
  314. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +7 -4
  315. package/templates/.agents/skills/review-pr/SKILL.en.md +186 -0
  316. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +186 -0
  317. package/templates/.agents/skills/review-pr/config/verify.en.json +37 -0
  318. package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +37 -0
  319. package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +65 -0
  320. package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +65 -0
  321. package/templates/.agents/skills/review-pr/reference/output-guidance.en.md +18 -0
  322. package/templates/.agents/skills/review-pr/reference/output-guidance.zh-CN.md +18 -0
  323. package/templates/.agents/skills/review-pr/reference/report-template.en.md +85 -0
  324. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +85 -0
  325. package/templates/.agents/skills/run-task/SKILL.en.md +8 -8
  326. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +8 -8
  327. package/templates/.agents/skills/run-task/config/verify.en.json +2 -1
  328. package/templates/.agents/skills/run-task/config/verify.zh-CN.json +2 -1
  329. package/templates/.agents/skills/run-task/reference/host-validation.en.md +20 -0
  330. package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +20 -0
  331. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +98 -107
  332. package/templates/.agents/skills/watch-pr/SKILL.en.md +13 -13
  333. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +13 -13
  334. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +27 -6
  335. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +26 -5
  336. package/templates/.agents/templates/task.en.md +2 -2
  337. package/templates/.agents/templates/task.zh-CN.md +2 -2
  338. package/templates/.agents/workflows/bug-fix.en.yaml +3 -3
  339. package/templates/.agents/workflows/bug-fix.zh-CN.yaml +3 -3
  340. package/templates/.agents/workflows/code-review.en.yaml +1 -1
  341. package/templates/.agents/workflows/code-review.zh-CN.yaml +1 -1
  342. package/templates/.agents/workflows/feature-development.en.yaml +4 -4
  343. package/templates/.agents/workflows/feature-development.zh-CN.yaml +4 -4
  344. package/templates/.agents/workflows/refactoring.en.yaml +3 -3
  345. package/templates/.agents/workflows/refactoring.zh-CN.yaml +3 -3
  346. package/templates/.claude/commands/post-release.en.md +1 -0
  347. package/templates/.claude/commands/post-release.zh-CN.md +1 -0
  348. package/templates/.claude/commands/review-pr.en.md +8 -0
  349. package/templates/.claude/commands/review-pr.zh-CN.md +8 -0
  350. package/templates/.claude/commands/watch-pr.en.md +1 -1
  351. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  352. package/templates/.claude/rules/tool-preferences.en.md +20 -0
  353. package/templates/.claude/rules/tool-preferences.zh-CN.md +20 -0
  354. package/templates/.opencode/commands/post-release.en.md +2 -0
  355. package/templates/.opencode/commands/post-release.zh-CN.md +2 -0
  356. package/templates/.opencode/commands/review-pr.en.md +11 -0
  357. package/templates/.opencode/commands/review-pr.zh-CN.md +11 -0
  358. package/templates/.opencode/commands/watch-pr.en.md +1 -1
  359. package/templates/.opencode/commands/watch-pr.zh-CN.md +1 -1
  360. package/dist/lib/agent-clients/adapters/gemini-cli.js +0 -64
  361. package/lib/agent-clients/adapters/gemini-cli.ts +0 -65
  362. package/templates/.gemini/commands/_project_/analyze-task.en.toml +0 -10
  363. package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +0 -10
  364. package/templates/.gemini/commands/_project_/archive-tasks.en.toml +0 -10
  365. package/templates/.gemini/commands/_project_/archive-tasks.zh-CN.toml +0 -10
  366. package/templates/.gemini/commands/_project_/block-task.en.toml +0 -10
  367. package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +0 -10
  368. package/templates/.gemini/commands/_project_/cancel-task.en.toml +0 -10
  369. package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +0 -10
  370. package/templates/.gemini/commands/_project_/check-task.en.toml +0 -10
  371. package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +0 -10
  372. package/templates/.gemini/commands/_project_/close-codescan.en.toml +0 -8
  373. package/templates/.gemini/commands/_project_/close-codescan.zh-CN.toml +0 -8
  374. package/templates/.gemini/commands/_project_/close-dependabot.en.toml +0 -8
  375. package/templates/.gemini/commands/_project_/close-dependabot.zh-CN.toml +0 -8
  376. package/templates/.gemini/commands/_project_/code-task.en.toml +0 -10
  377. package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +0 -10
  378. package/templates/.gemini/commands/_project_/commit.en.toml +0 -10
  379. package/templates/.gemini/commands/_project_/commit.zh-CN.toml +0 -10
  380. package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +0 -10
  381. package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +0 -10
  382. package/templates/.gemini/commands/_project_/complete-task.en.toml +0 -10
  383. package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +0 -10
  384. package/templates/.gemini/commands/_project_/create-pr.en.toml +0 -10
  385. package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +0 -10
  386. package/templates/.gemini/commands/_project_/create-release-note.en.toml +0 -8
  387. package/templates/.gemini/commands/_project_/create-release-note.zh-CN.toml +0 -8
  388. package/templates/.gemini/commands/_project_/create-task.en.toml +0 -8
  389. package/templates/.gemini/commands/_project_/create-task.zh-CN.toml +0 -8
  390. package/templates/.gemini/commands/_project_/import-codescan.en.toml +0 -8
  391. package/templates/.gemini/commands/_project_/import-codescan.zh-CN.toml +0 -8
  392. package/templates/.gemini/commands/_project_/import-dependabot.en.toml +0 -8
  393. package/templates/.gemini/commands/_project_/import-dependabot.zh-CN.toml +0 -8
  394. package/templates/.gemini/commands/_project_/import-issue.en.toml +0 -8
  395. package/templates/.gemini/commands/_project_/import-issue.zh-CN.toml +0 -8
  396. package/templates/.gemini/commands/_project_/init-labels.en.toml +0 -8
  397. package/templates/.gemini/commands/_project_/init-labels.zh-CN.toml +0 -8
  398. package/templates/.gemini/commands/_project_/init-milestones.en.toml +0 -10
  399. package/templates/.gemini/commands/_project_/init-milestones.zh-CN.toml +0 -10
  400. package/templates/.gemini/commands/_project_/plan-task.en.toml +0 -10
  401. package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +0 -10
  402. package/templates/.gemini/commands/_project_/post-release.en.toml +0 -6
  403. package/templates/.gemini/commands/_project_/post-release.zh-CN.toml +0 -6
  404. package/templates/.gemini/commands/_project_/refine-title.en.toml +0 -8
  405. package/templates/.gemini/commands/_project_/refine-title.zh-CN.toml +0 -8
  406. package/templates/.gemini/commands/_project_/release.en.toml +0 -8
  407. package/templates/.gemini/commands/_project_/release.zh-CN.toml +0 -8
  408. package/templates/.gemini/commands/_project_/restore-task.en.toml +0 -8
  409. package/templates/.gemini/commands/_project_/restore-task.zh-CN.toml +0 -8
  410. package/templates/.gemini/commands/_project_/review-analysis.en.toml +0 -10
  411. package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +0 -10
  412. package/templates/.gemini/commands/_project_/review-code.en.toml +0 -10
  413. package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +0 -10
  414. package/templates/.gemini/commands/_project_/review-plan.en.toml +0 -10
  415. package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +0 -10
  416. package/templates/.gemini/commands/_project_/run-task.en.toml +0 -8
  417. package/templates/.gemini/commands/_project_/run-task.zh-CN.toml +0 -8
  418. package/templates/.gemini/commands/_project_/test-integration.en.toml +0 -6
  419. package/templates/.gemini/commands/_project_/test-integration.zh-CN.toml +0 -6
  420. package/templates/.gemini/commands/_project_/test.en.toml +0 -6
  421. package/templates/.gemini/commands/_project_/test.zh-CN.toml +0 -6
  422. package/templates/.gemini/commands/_project_/update-agent-infra.en.toml +0 -6
  423. package/templates/.gemini/commands/_project_/update-agent-infra.zh-CN.toml +0 -6
  424. package/templates/.gemini/commands/_project_/upgrade-dependency.en.toml +0 -8
  425. package/templates/.gemini/commands/_project_/upgrade-dependency.zh-CN.toml +0 -8
  426. package/templates/.gemini/commands/_project_/watch-pr.en.toml +0 -10
  427. package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +0 -10
  428. package/templates/.gemini/settings.json +0 -3
@@ -1,6 +1,7 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
 
3
3
  import type { AgentClientId } from '../agent-clients/types.ts';
4
+ import { normalizeAgentToken } from '../agent-clients/tokens.ts';
4
5
 
5
6
  type DelegationRole = 'executor' | 'reviewer';
6
7
  type DelegationStage = 'analysis' | 'review-analysis' | 'plan' | 'review-plan' | 'code' | 'review-code' | 'commit';
@@ -16,13 +17,17 @@ type DelegationReceipt = Readonly<{
16
17
  artifact: string;
17
18
  client: AgentClientId;
18
19
  requestedModel: string | null;
20
+ requestedReasoningEffort: string | null;
19
21
  actualModel: string | null;
22
+ actualReasoningEffort: string | null;
20
23
  modelFallbackReason: string | null;
24
+ reasoningEffortFallbackReason: string | null;
21
25
  parentId: string | null;
22
26
  childId: string | null;
23
27
  spawnMode: string | null;
24
28
  agent: string | null;
25
29
  status: DelegationStatus;
30
+ workspaceSnapshotScope?: 'task';
26
31
  beforeFingerprint: string;
27
32
  afterFingerprint: string | null;
28
33
  changedPaths: readonly string[];
@@ -50,14 +55,16 @@ function fail(code: string, message: string): ReceiptFailure {
50
55
  }
51
56
 
52
57
  function prepareDelegation(
53
- input: Omit<DelegationReceipt, 'id' | 'actualModel' | 'modelFallbackReason' | 'parentId' | 'childId' | 'spawnMode' | 'agent' | 'status' | 'afterFingerprint' | 'changedPaths' | 'createdAt' | 'activatedAt' | 'sealedAt' | 'consumedAt'>,
58
+ input: Omit<DelegationReceipt, 'id' | 'requestedModel' | 'requestedReasoningEffort' | 'actualModel' | 'actualReasoningEffort' | 'modelFallbackReason' | 'reasoningEffortFallbackReason' | 'parentId' | 'childId' | 'spawnMode' | 'agent' | 'status' | 'afterFingerprint' | 'changedPaths' | 'createdAt' | 'activatedAt' | 'sealedAt' | 'consumedAt'> & Readonly<{ requestedModel: string; requestedReasoningEffort: string }>,
54
59
  options: { id?: () => string; now?: () => string } = {}
55
60
  ): DelegationReceipt {
56
61
  return Object.freeze({
57
62
  ...input,
58
63
  id: (options.id ?? randomUUID)(),
59
64
  actualModel: null,
65
+ actualReasoningEffort: null,
60
66
  modelFallbackReason: null,
67
+ reasoningEffortFallbackReason: null,
61
68
  parentId: null,
62
69
  childId: null,
63
70
  spawnMode: null,
@@ -80,7 +87,9 @@ function activateDelegation(
80
87
  parentId: string;
81
88
  spawnMode: string;
82
89
  actualModel?: string;
90
+ actualReasoningEffort?: string;
83
91
  modelFallbackReason?: string;
92
+ reasoningEffortFallbackReason?: string;
84
93
  }>,
85
94
  options: { now?: () => string } = {}
86
95
  ): ReceiptResult {
@@ -92,10 +101,29 @@ function activateDelegation(
92
101
  return fail('DELEGATION_IDENTITY_INVALID', 'native parent/child identity does not match the prepared delegation');
93
102
  }
94
103
  if (event.spawnMode !== 'fresh') return fail('DELEGATION_FORK_FORBIDDEN', `spawn mode '${event.spawnMode}' is not fresh`);
95
- const actualModel = event.actualModel ?? null;
96
- if (actualModel && receipt.requestedModel && actualModel !== receipt.requestedModel && !event.modelFallbackReason) {
104
+ const actualModel = event.actualModel;
105
+ if (!actualModel || actualModel.trim() !== actualModel) {
106
+ return fail('DELEGATION_MODEL_IDENTITY_MISSING', 'native start event must provide a non-empty actual model identity');
107
+ }
108
+ if (actualModel !== receipt.requestedModel && (!event.modelFallbackReason || event.modelFallbackReason.trim() === '')) {
97
109
  return fail('DELEGATION_MODEL_FALLBACK_UNRECORDED', 'actual model differs from requested model without a fallback reason');
98
110
  }
111
+ const actualReasoningEffort = event.actualReasoningEffort;
112
+ if (!actualReasoningEffort || actualReasoningEffort.trim() !== actualReasoningEffort) {
113
+ return fail('DELEGATION_REASONING_EFFORT_MISSING', 'native start event must provide a non-empty actual reasoning effort');
114
+ }
115
+ if (
116
+ actualReasoningEffort !== receipt.requestedReasoningEffort
117
+ && (!event.reasoningEffortFallbackReason || event.reasoningEffortFallbackReason.trim() === '')
118
+ ) {
119
+ return fail('DELEGATION_REASONING_EFFORT_FALLBACK_UNRECORDED', 'actual reasoning effort differs from requested effort without a fallback reason');
120
+ }
121
+ if (actualModel === receipt.requestedModel && event.modelFallbackReason) {
122
+ return fail('DELEGATION_MODEL_FALLBACK_INVALID', 'model fallback reason is only valid when actual model differs');
123
+ }
124
+ if (actualReasoningEffort === receipt.requestedReasoningEffort && event.reasoningEffortFallbackReason) {
125
+ return fail('DELEGATION_REASONING_EFFORT_FALLBACK_INVALID', 'reasoning-effort fallback reason is only valid when actual effort differs');
126
+ }
99
127
  return { ok: true, receipt: Object.freeze({
100
128
  ...receipt,
101
129
  status: 'activated',
@@ -103,7 +131,9 @@ function activateDelegation(
103
131
  childId: event.childId,
104
132
  spawnMode: event.spawnMode,
105
133
  actualModel,
134
+ actualReasoningEffort,
106
135
  modelFallbackReason: event.modelFallbackReason ?? null,
136
+ reasoningEffortFallbackReason: event.reasoningEffortFallbackReason ?? null,
107
137
  activatedAt: (options.now ?? (() => new Date().toISOString()))()
108
138
  }) };
109
139
  }
@@ -116,8 +146,7 @@ function completeDelegationStage(
116
146
  if (event.stage !== receipt.stage || event.round !== receipt.round || event.artifact !== receipt.artifact) {
117
147
  return fail('DELEGATION_STAGE_MISMATCH', 'stage completion identity does not match the active delegation');
118
148
  }
119
- const acceptedAgents = receipt.client === 'claude-code' ? ['claude', 'claude-code'] : [receipt.client];
120
- if (!acceptedAgents.includes(event.agent)) {
149
+ if (normalizeAgentToken(event.agent) !== normalizeAgentToken(receipt.client)) {
121
150
  return fail('DELEGATION_AGENT_MISMATCH', `stage agent '${event.agent}' does not match client '${receipt.client}'`);
122
151
  }
123
152
  return { ok: true, receipt: Object.freeze({ ...receipt, status: 'stage-completed', agent: event.agent }) };
@@ -21,7 +21,10 @@ import type { ReviewStage } from './ledger.ts';
21
21
  import { parseReviewSummary } from './review-artifacts.ts';
22
22
  import { resolveTaskRef } from './resolve-ref.ts';
23
23
  import { findSectionHeading } from './sections.ts';
24
- import { completeOrchestrationStage, validateOrchestrationStage } from './orchestration.ts';
24
+ import { validateLifecycleExecution } from './lifecycle-execution.ts';
25
+ import { commitOrchestrationStageCompletion } from './orchestration.ts';
26
+ import type { OrchestrationStageCompletion } from './orchestration.ts';
27
+ import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.ts';
25
28
  import { captureTaskWriteMetadata, writeTask } from './write.ts';
26
29
  import type { TaskOperationSummary, TaskWriteErrorCode, TaskWriteOptions } from './write.ts';
27
30
 
@@ -40,15 +43,19 @@ type TaskEventErrorCode =
40
43
  | 'EVENT_UNKNOWN' | 'EVENT_PAYLOAD_INVALID' | 'EVENT_TRANSITION_INVALID'
41
44
  | 'EVENT_LOG_MISSING' | 'EVENT_START_MISSING' | 'EVENT_ALREADY_COMPLETED'
42
45
  | 'EVENT_LOG_CONFLICT' | 'EVENT_ARTIFACT_CONFLICT' | 'EVENT_FINDING_COUNT_MISMATCH'
46
+ | 'EVENT_ORCHESTRATION_COMMIT_FAILED'
43
47
  | ArtifactErrorCode | TaskWriteErrorCode;
44
48
  type TaskEventRequest = {
45
- taskRef: string; event: TaskEventName | string; agent: string; dryRun?: boolean;
49
+ taskRef: string; event: TaskEventName | string; agent: string; dryRun?: boolean; orchestrated?: boolean;
46
50
  round?: number; question?: number; artifact?: string; fixFor?: string; implementationInput?: string;
47
51
  verdict?: Verdict; blockers?: number; major?: number; minor?: number;
48
52
  manualValidation?: number; filesModified?: number; testsPassed?: number;
49
53
  summaryResult?: string;
50
54
  };
51
55
  type TaskEventError = { code: TaskEventErrorCode; message: string };
56
+ type TaskEventOptions = TaskWriteOptions & {
57
+ commitOrchestrationCompletion?: (plan: OrchestrationStageCompletion) => void;
58
+ };
52
59
  type TaskEventResult = {
53
60
  status: 'planned' | 'applied' | 'no-op' | 'failed'; changed: boolean;
54
61
  event: string; requestRef: string; taskId: string | null; taskMdPath: string | null;
@@ -64,17 +71,17 @@ const BASE_FIELDS = new Set(['taskRef', 'event', 'agent', 'dryRun']);
64
71
  const SCHEMAS: Record<TaskEventName, { required?: string[]; optional?: string[] }> = {
65
72
  'analyze.started': { optional: ['round'] },
66
73
  'analyze.awaiting-input': { required: ['question'] },
67
- 'analyze.completed': { required: ['artifact'], optional: ['round'] },
74
+ 'analyze.completed': { required: ['artifact'], optional: ['round', 'orchestrated'] },
68
75
  'review-analysis.started': { optional: ['round'] },
69
- 'review-analysis.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
76
+ 'review-analysis.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round', 'orchestrated'] },
70
77
  'plan.started': { optional: ['round'] },
71
- 'plan.completed': { required: ['artifact'], optional: ['round'] },
78
+ 'plan.completed': { required: ['artifact'], optional: ['round', 'orchestrated'] },
72
79
  'review-plan.started': { optional: ['round'] },
73
- 'review-plan.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
80
+ 'review-plan.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round', 'orchestrated'] },
74
81
  'code.started': { optional: ['round', 'fixFor', 'implementationInput'] },
75
- 'code.completed': { required: ['artifact'], optional: ['round', 'fixFor', 'implementationInput', 'filesModified', 'testsPassed', 'blockers', 'major', 'minor', 'manualValidation'] },
82
+ 'code.completed': { required: ['artifact'], optional: ['round', 'fixFor', 'implementationInput', 'filesModified', 'testsPassed', 'blockers', 'major', 'minor', 'manualValidation', 'orchestrated'] },
76
83
  'review-code.started': { optional: ['round'] },
77
- 'review-code.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
84
+ 'review-code.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round', 'orchestrated'] },
78
85
  'manual-validation.started': { optional: ['round'] },
79
86
  'manual-validation.completed': { required: ['artifact', 'summaryResult'], optional: ['round'] }
80
87
  };
@@ -261,7 +268,7 @@ function openStartedIdentity(rows: ReturnType<typeof pairEntries>, family: Event
261
268
  return matches.length === 1 ? matches[0] : matches.length > 1 ? { conflict: true as const } : null;
262
269
  }
263
270
 
264
- function applyTaskEvent(request: TaskEventRequest, options: TaskWriteOptions = {}): TaskEventResult {
271
+ function applyTaskEventUnlocked(request: TaskEventRequest, options: TaskEventOptions = {}): TaskEventResult {
265
272
  const invalid = validateTaskEventRequest(request);
266
273
  if (invalid) return failed(request, invalid);
267
274
  const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
@@ -334,20 +341,27 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskWriteOptions = {
334
341
  completedArtifact?.path ?? null
335
342
  );
336
343
  if (findingCountError) return failed(normalized, findingCountError, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
337
- if (eventIdentity.phase === 'completed' && !normalized.dryRun && eventIdentity.family !== 'manual-validation') {
344
+ let orchestrationCompletion: OrchestrationStageCompletion | null = null;
345
+ if (eventIdentity.phase === 'completed' && eventIdentity.family !== 'manual-validation') {
338
346
  const orchestrationStage = eventIdentity.family === 'analyze' ? 'analysis' : eventIdentity.family;
339
- const provenance = validateOrchestrationStage(normalized.taskRef, {
340
- stage: orchestrationStage,
341
- round: normalized.round!,
342
- artifact: normalized.artifact!,
343
- role: eventIdentity.family.startsWith('review-') ? 'reviewer' : 'executor'
347
+ const execution = validateLifecycleExecution(normalized.taskRef, {
348
+ mode: normalized.orchestrated ? 'orchestrated' : 'standalone',
349
+ identity: {
350
+ stage: orchestrationStage,
351
+ round: normalized.round!,
352
+ artifact: normalized.artifact!,
353
+ role: eventIdentity.family.startsWith('review-') ? 'reviewer' : 'executor'
354
+ },
355
+ agent: normalized.agent,
356
+ dryRun: normalized.dryRun
344
357
  }, { repoRoot: options.repoRoot });
345
- if (provenance.status === 'failed' || provenance.status === 'paused') {
358
+ if (!execution.ok) {
346
359
  return failed(normalized, {
347
360
  code: 'EVENT_TRANSITION_INVALID',
348
- message: provenance.error?.message ?? provenance.run?.pause?.message ?? 'orchestration provenance validation failed'
361
+ message: `${execution.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH'}: ${execution.error?.message ?? 'orchestration provenance validation failed'}`
349
362
  }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase, artifactContext });
350
363
  }
364
+ orchestrationCompletion = execution.completionPlan;
351
365
  }
352
366
  let metadata;
353
367
  try { metadata = (options.metadataProvider ?? captureTaskWriteMetadata)(); }
@@ -384,19 +398,25 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskWriteOptions = {
384
398
  mutations.push({ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: section.heading, body });
385
399
  const result = writeTask({ taskRef: normalized.taskRef, expectedState: 'active', dryRun: normalized.dryRun, mutations }, { ...options, metadataProvider: () => metadata });
386
400
  if (result.status === 'failed') return failed(normalized, result.error, { taskId: result.taskId, taskMdPath: result.taskMdPath, fromStep: currentStep, toStep: step, action: eventIdentity.action, phase: eventIdentity.phase, timestamp: result.timestamp, agentInfraVersion: result.agentInfraVersion, operations: result.operations, artifactContext });
387
- if (eventIdentity.phase === 'completed' && !normalized.dryRun && eventIdentity.family !== 'manual-validation') {
388
- const orchestrationStage = eventIdentity.family === 'analyze' ? 'analysis' : eventIdentity.family;
389
- const orchestration = completeOrchestrationStage(normalized.taskRef, {
390
- stage: orchestrationStage,
391
- round: normalized.round!,
392
- artifact: normalized.artifact!,
393
- agent: normalized.agent
394
- }, { repoRoot: options.repoRoot });
395
- if (orchestration.status === 'failed' || orchestration.status === 'paused') {
401
+ if (!normalized.dryRun && orchestrationCompletion) {
402
+ try {
403
+ (options.commitOrchestrationCompletion ?? commitOrchestrationStageCompletion)(orchestrationCompletion);
404
+ } catch (error) {
396
405
  return failed(normalized, {
397
- code: 'EVENT_TRANSITION_INVALID',
398
- message: orchestration.error?.message ?? orchestration.run?.pause?.message ?? 'orchestration provenance validation failed'
399
- }, { taskId: result.taskId, taskMdPath: result.taskMdPath, fromStep: currentStep, toStep: step, action: eventIdentity.action, phase: eventIdentity.phase, timestamp: result.timestamp, agentInfraVersion: result.agentInfraVersion, operations: result.operations, artifactContext });
406
+ code: 'EVENT_ORCHESTRATION_COMMIT_FAILED',
407
+ message: `task.md was written but orchestration completion could not be persisted; manual recovery is required: ${error instanceof Error ? error.message : String(error)}`
408
+ }, {
409
+ taskId: result.taskId,
410
+ taskMdPath: result.taskMdPath,
411
+ fromStep: currentStep,
412
+ toStep: step,
413
+ action: eventIdentity.action,
414
+ phase: eventIdentity.phase,
415
+ timestamp: result.timestamp,
416
+ agentInfraVersion: result.agentInfraVersion,
417
+ operations: result.operations,
418
+ artifactContext
419
+ });
400
420
  }
401
421
  }
402
422
  return {
@@ -410,6 +430,31 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskWriteOptions = {
410
430
  };
411
431
  }
412
432
 
433
+ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {}): TaskEventResult {
434
+ const invalid = validateTaskEventRequest(request);
435
+ if (invalid) return failed(request, invalid);
436
+ const parts = eventParts(request.event);
437
+ if (request.dryRun || parts.phase !== 'completed' || parts.family === 'manual-validation') {
438
+ return applyTaskEventUnlocked(request, options);
439
+ }
440
+ const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
441
+ if (!resolved.ok) return applyTaskEventUnlocked(request, options);
442
+ try {
443
+ return withTaskExecutionLock(
444
+ resolved.repoRoot,
445
+ resolved.taskId,
446
+ `task-event.${request.event}`,
447
+ () => applyTaskEventUnlocked(request, options)
448
+ );
449
+ } catch (error) {
450
+ if (!(error instanceof TaskExecutionLockError)) throw error;
451
+ return failed(request, {
452
+ code: 'EVENT_TRANSITION_INVALID',
453
+ message: `${error.code}: ${error.message}`
454
+ }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
455
+ }
456
+ }
457
+
413
458
  function successNoOp(
414
459
  request: TaskEventRequest, taskId: string, taskMdPath: string, currentStep: string,
415
460
  eventIdentity: ReturnType<typeof identity>, timestamp: string,
@@ -425,4 +470,4 @@ function successNoOp(
425
470
  }
426
471
 
427
472
  export { eventCatalog, validateTaskEventRequest, applyTaskEvent };
428
- export type { TaskEventName, TaskEventRequest, TaskEventResult, TaskEventError, TaskEventErrorCode, Verdict };
473
+ export type { TaskEventName, TaskEventRequest, TaskEventResult, TaskEventError, TaskEventErrorCode, TaskEventOptions, Verdict };
@@ -0,0 +1,58 @@
1
+ import {
2
+ assertWritableInventory,
3
+ inspectTaskArtifacts
4
+ } from './artifact-lifecycle.ts';
5
+ import type {
6
+ ArtifactError,
7
+ ArtifactFamily,
8
+ ArtifactIdentity,
9
+ InspectOptions
10
+ } from './artifact-lifecycle.ts';
11
+
12
+ const COMPLETION_BACKFILL_FAMILIES = [
13
+ 'analysis',
14
+ 'review-analysis',
15
+ 'plan',
16
+ 'review-plan',
17
+ 'code',
18
+ 'review-code',
19
+ 'manual-validation'
20
+ ] as const satisfies readonly ArtifactFamily[];
21
+
22
+ type CompletionArtifactResult = {
23
+ status: 'ready' | 'failed';
24
+ changed: false;
25
+ taskId: string | null;
26
+ taskDir: string | null;
27
+ artifacts: readonly ArtifactIdentity[];
28
+ error: ArtifactError | null;
29
+ };
30
+
31
+ function inspectCompletionArtifacts(
32
+ taskRef: string,
33
+ options: InspectOptions = {}
34
+ ): CompletionArtifactResult {
35
+ const artifacts: ArtifactIdentity[] = [];
36
+ let taskId: string | null = null;
37
+ let taskDir: string | null = null;
38
+ for (const family of COMPLETION_BACKFILL_FAMILIES) {
39
+ const inventory = inspectTaskArtifacts(taskRef, family, options);
40
+ taskId = inventory.taskId ?? taskId;
41
+ taskDir = inventory.taskDir ?? taskDir;
42
+ if (inventory.status === 'failed') {
43
+ return { status: 'failed', changed: false, taskId, taskDir, artifacts: [], error: inventory.error };
44
+ }
45
+ const writableError = assertWritableInventory(inventory);
46
+ const brokenReference = inventory.diagnostics.find((item) => item.code === 'BROKEN_REFERENCE');
47
+ const error = writableError ?? (brokenReference ? {
48
+ code: 'ARTIFACT_REFERENCE_INVALID' as const,
49
+ message: brokenReference.message
50
+ } : null);
51
+ if (error) return { status: 'failed', changed: false, taskId, taskDir, artifacts: [], error };
52
+ artifacts.push(...inventory.artifacts);
53
+ }
54
+ return { status: 'ready', changed: false, taskId, taskDir, artifacts, error: null };
55
+ }
56
+
57
+ export { COMPLETION_BACKFILL_FAMILIES, inspectCompletionArtifacts };
58
+ export type { CompletionArtifactResult };
@@ -8,7 +8,7 @@ const COLUMNS = [
8
8
  const TIMESTAMP_RE = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}$/;
9
9
  const ARTIFACT_RE = /^code(?:-r(?:[2-9]|[1-9]\d+))?\.md$/;
10
10
 
11
- type ImplementationInputStatus = 'pending' | 'not-required' | 'consumed';
11
+ type ImplementationInputStatus = 'declared' | 'pending' | 'not-required' | 'consumed';
12
12
  type ImplementationInput = {
13
13
  id: string;
14
14
  ledgerId: string;
@@ -25,18 +25,18 @@ type ImplementationInputDraft = {
25
25
  needsImplementation: boolean;
26
26
  decidedAt: string;
27
27
  };
28
+ type ImplementationInputDeclaration = Omit<ImplementationInputDraft, 'decidedAt'>;
28
29
 
29
30
  function validateInput(row: ImplementationInput): void {
30
31
  if (!/^II-[1-9]\d*$/.test(row.id)) throw new Error(`implementation input id '${row.id}' is invalid`);
31
32
  if (!row.ledgerId || !row.decisionEvidence || /[\r\n]/.test(row.ledgerId) || /[\r\n]/.test(row.decisionEvidence)) throw new Error(`implementation input ${row.id} has incomplete decision identity`);
32
33
  if (row.stage !== 'code') throw new Error(`implementation input ${row.id} has invalid stage`);
33
- if (!TIMESTAMP_RE.test(row.decidedAt) || !Number.isFinite(Date.parse(row.decidedAt.replace(' ', 'T')))) {
34
- throw new Error(`implementation input ${row.id} has invalid decided_at`);
35
- }
34
+ const hasValidTimestamp = TIMESTAMP_RE.test(row.decidedAt) && Number.isFinite(Date.parse(row.decidedAt.replace(' ', 'T')));
36
35
  const valid =
37
- (row.needsImplementation && row.status === 'pending' && row.consumedBy === '') ||
38
- (!row.needsImplementation && row.status === 'not-required' && row.consumedBy === '') ||
39
- (row.needsImplementation && row.status === 'consumed' && ARTIFACT_RE.test(row.consumedBy));
36
+ (row.status === 'declared' && row.decidedAt === '' && row.consumedBy === '') ||
37
+ (hasValidTimestamp && row.needsImplementation && row.status === 'pending' && row.consumedBy === '') ||
38
+ (hasValidTimestamp && !row.needsImplementation && row.status === 'not-required' && row.consumedBy === '') ||
39
+ (hasValidTimestamp && row.needsImplementation && row.status === 'consumed' && ARTIFACT_RE.test(row.consumedBy));
40
40
  if (!valid) throw new Error(`implementation input ${row.id} has an invalid state combination`);
41
41
  }
42
42
 
@@ -79,6 +79,57 @@ function createImplementationInput(rows: readonly ImplementationInput[], draft:
79
79
  return row;
80
80
  }
81
81
 
82
+ function declareImplementationInput(
83
+ rows: readonly ImplementationInput[], draft: ImplementationInputDeclaration
84
+ ): ImplementationInput {
85
+ const existing = rows.filter((row) => row.ledgerId === draft.ledgerId && row.status === 'declared');
86
+ if (existing.length > 1) throw new Error(`implementation input declaration for '${draft.ledgerId}' conflicts with existing rows`);
87
+ if (existing.length === 1) {
88
+ const row = existing[0]!;
89
+ if (row.decisionEvidence !== draft.decisionEvidence || row.needsImplementation !== draft.needsImplementation) {
90
+ throw new Error(`implementation input declaration for '${draft.ledgerId}' conflicts with the existing row`);
91
+ }
92
+ return row;
93
+ }
94
+ const row: ImplementationInput = {
95
+ id: nextId(rows), ledgerId: draft.ledgerId, decisionEvidence: draft.decisionEvidence,
96
+ stage: 'code', needsImplementation: draft.needsImplementation, decidedAt: '',
97
+ status: 'declared', consumedBy: ''
98
+ };
99
+ validateInput(row);
100
+ return row;
101
+ }
102
+
103
+ function selectDeclaredImplementationInput(
104
+ rows: readonly ImplementationInput[], ledgerId: string, decisionEvidence: string
105
+ ): ImplementationInput | null {
106
+ const forLedger = rows.filter((row) => row.ledgerId === ledgerId && row.status === 'declared');
107
+ if (forLedger.length > 1) throw new Error(`implementation input declaration for '${ledgerId}' is ambiguous`);
108
+ if (forLedger.length === 0) return null;
109
+ if (forLedger[0]!.decisionEvidence !== decisionEvidence) {
110
+ throw new Error(`implementation input declaration for '${ledgerId}' has conflicting evidence`);
111
+ }
112
+ return forLedger[0]!;
113
+ }
114
+
115
+ function finalizeImplementationInput(
116
+ rows: readonly ImplementationInput[], id: string, decisionEvidence: string, decidedAt: string
117
+ ): ImplementationInput[] {
118
+ let found = false;
119
+ const next = rows.map((row) => {
120
+ if (row.id !== id) return row;
121
+ found = true;
122
+ if (row.status !== 'declared') throw new Error(`implementation input ${id} is not declared`);
123
+ return {
124
+ ...row, decisionEvidence, decidedAt,
125
+ status: row.needsImplementation ? 'pending' as const : 'not-required' as const
126
+ };
127
+ });
128
+ if (!found) throw new Error(`implementation input ${id} was not found`);
129
+ next.forEach(validateInput);
130
+ return next;
131
+ }
132
+
82
133
  function selectPendingImplementationInput(
83
134
  rows: readonly ImplementationInput[], reviewCompletedAt: string
84
135
  ): ImplementationInput | null {
@@ -130,8 +181,11 @@ export {
130
181
  SECTION_ALIASES as IMPLEMENTATION_INPUT_ALIASES,
131
182
  createImplementationInput,
132
183
  consumeImplementationInput,
184
+ declareImplementationInput,
185
+ finalizeImplementationInput,
133
186
  parseImplementationInputs,
134
187
  renderImplementationInputs,
188
+ selectDeclaredImplementationInput,
135
189
  selectPendingImplementationInput
136
190
  };
137
- export type { ImplementationInput, ImplementationInputDraft, ImplementationInputStatus };
191
+ export type { ImplementationInput, ImplementationInputDeclaration, ImplementationInputDraft, ImplementationInputStatus };
@@ -1,6 +1,12 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
 
4
+ import {
5
+ declareImplementationInput,
6
+ IMPLEMENTATION_INPUT_ALIASES,
7
+ parseImplementationInputs,
8
+ renderImplementationInputs
9
+ } from './implementation-inputs.ts';
4
10
  import { LEDGER_COLUMNS, LEDGER_HEADINGS, nextHdId, parseLedger, validateLedgerRows } from './ledger.ts';
5
11
  import type { LedgerRow, ReviewStage } from './ledger.ts';
6
12
  import { resolveTaskRef } from './resolve-ref.ts';
@@ -13,9 +19,9 @@ type ReviewDisposition = 'confirmed' | 'closed' | 'open' | 'needs-human-decision
13
19
  type LedgerIntent =
14
20
  | { kind: 'finding-upsert'; taskRef: string; stage: ReviewStage; reviewArtifact: string; ordinal: number; severity: ReviewSeverity; evidence: string; dryRun?: boolean }
15
21
  | { kind: 'finding-respond'; taskRef: string; id: string; round: number; status: ExecutorResponse; evidence: string; dryRun?: boolean }
16
- | { kind: 'finding-review'; taskRef: string; id: string; status: ReviewDisposition; evidence: string; dryRun?: boolean }
22
+ | { kind: 'finding-review'; taskRef: string; id: string; status: ReviewDisposition; evidence: string; needsImplementation?: boolean; dryRun?: boolean }
17
23
  | { kind: 'decision-next-id'; taskRef: string }
18
- | { kind: 'decision-upsert'; taskRef: string; id: string; stage: ReviewStage; artifact: string; dryRun?: boolean };
24
+ | { kind: 'decision-upsert'; taskRef: string; id: string; stage: ReviewStage; artifact: string; needsImplementation?: boolean; dryRun?: boolean };
19
25
 
20
26
  type LedgerIntentError = { code: string; message: string };
21
27
  type LedgerIntentResult = {
@@ -97,6 +103,15 @@ function ledgerSectionMutation(content: string): TaskMutation[] {
97
103
  }];
98
104
  }
99
105
 
106
+ function implementationInputMutation(content: string, rows: Parameters<typeof renderImplementationInputs>[0]): TaskMutation {
107
+ const english = /^##\s+Activity Log\s*$/m.test(content);
108
+ return {
109
+ kind: 'section', aliases: IMPLEMENTATION_INPUT_ALIASES,
110
+ heading: english ? 'Implementation Inputs' : '实现输入',
111
+ body: renderImplementationInputs(rows)
112
+ };
113
+ }
114
+
100
115
  function mapWrite(intent: LedgerIntent, entityId: string, before: LedgerRow | null, after: LedgerRow, result: ReturnType<typeof writeTask>): LedgerIntentResult {
101
116
  if (result.status === 'failed') return failed(intent, result.error.code, result.error.message, result.taskId, entityId);
102
117
  return { status: result.status, changed: result.changed, intent: intent.kind, taskId: result.taskId, entityId, before, after, operations: result.operations, error: null };
@@ -189,9 +204,34 @@ function applyLedgerIntent(intent: LedgerIntent, options: TaskWriteOptions = {})
189
204
  }
190
205
  }
191
206
 
207
+ let implementationMutation: TaskMutation | null = null;
208
+ if (intent.kind === 'decision-upsert' || intent.kind === 'finding-review') {
209
+ const stage = intent.kind === 'decision-upsert' ? intent.stage : after.stage;
210
+ const escalates = intent.kind === 'decision-upsert' || intent.status === 'needs-human-decision';
211
+ if (stage === 'code' && escalates && intent.needsImplementation === undefined) {
212
+ return failed(intent, 'LEDGER_PAYLOAD_INVALID', 'code-stage decisions require --needs-implementation true|false', resolved.taskId, after.id);
213
+ }
214
+ if ((stage !== 'code' || !escalates) && intent.needsImplementation !== undefined) {
215
+ return failed(intent, 'LEDGER_PAYLOAD_INVALID', '--needs-implementation is only valid for code-stage escalation', resolved.taskId, after.id);
216
+ }
217
+ if (stage === 'code' && escalates) {
218
+ try {
219
+ const parsed = parseImplementationInputs(content);
220
+ const declaration = declareImplementationInput(parsed.rows, {
221
+ ledgerId: after.id, decisionEvidence: after.evidence,
222
+ needsImplementation: intent.needsImplementation!
223
+ });
224
+ const nextRows = parsed.rows.includes(declaration) ? parsed.rows : [...parsed.rows, declaration];
225
+ implementationMutation = implementationInputMutation(content, nextRows);
226
+ } catch (error) {
227
+ return failed(intent, 'LEDGER_DOCUMENT_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId, after.id);
228
+ }
229
+ }
230
+ }
231
+
192
232
  const result = writeTask({
193
233
  taskRef: intent.taskRef, expectedState: 'active',
194
- mutations: [...ledgerSectionMutation(content), rowMutation(after)],
234
+ mutations: [...ledgerSectionMutation(content), rowMutation(after), ...(implementationMutation ? [implementationMutation] : [])],
195
235
  dryRun: 'dryRun' in intent ? intent.dryRun : false
196
236
  }, { ...options, taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: resolved.state } });
197
237
  return mapWrite(intent, after.id, before, after, result);
@@ -0,0 +1,106 @@
1
+ import {
2
+ inspectOrchestrationStage,
3
+ pauseOrchestration,
4
+ planOrchestrationStageCompletion,
5
+ readRun
6
+ } from './orchestration.ts';
7
+ import type {
8
+ OrchestrationStageCompletion,
9
+ OrchestrationStageIdentity
10
+ } from './orchestration.ts';
11
+ import { resolveTaskRef } from './resolve-ref.ts';
12
+
13
+ type LifecycleExecutionMode = 'standalone' | 'orchestrated';
14
+ type LifecycleExecutionRequest = Readonly<{
15
+ mode: LifecycleExecutionMode;
16
+ identity: OrchestrationStageIdentity;
17
+ agent?: string;
18
+ dryRun?: boolean;
19
+ }>;
20
+ type LifecycleExecutionResult = Readonly<{
21
+ ok: boolean;
22
+ mode: LifecycleExecutionMode;
23
+ completionPlan: OrchestrationStageCompletion | null;
24
+ error: Readonly<{ code: string; message: string }> | null;
25
+ }>;
26
+
27
+ function failure(mode: LifecycleExecutionMode, code: string, message: string): LifecycleExecutionResult {
28
+ return { ok: false, mode, completionPlan: null, error: { code, message } };
29
+ }
30
+
31
+ function inspectLifecycleExecution(
32
+ taskRef: string,
33
+ request: LifecycleExecutionRequest,
34
+ options: Readonly<{ repoRoot?: string }> = {}
35
+ ): LifecycleExecutionResult {
36
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
37
+ if (!resolved.ok) return failure(request.mode, resolved.code, resolved.message);
38
+ if (request.mode === 'standalone') {
39
+ try {
40
+ const run = readRun(resolved.taskDir);
41
+ if (run?.pendingDelegation) {
42
+ return failure(
43
+ request.mode,
44
+ 'ORCHESTRATION_STANDALONE_BUSY',
45
+ 'standalone lifecycle execution is blocked by a pending orchestration delegation'
46
+ );
47
+ }
48
+ return { ok: true, mode: request.mode, completionPlan: null, error: null };
49
+ } catch (error) {
50
+ return failure(
51
+ request.mode,
52
+ 'ORCHESTRATION_STATE_INVALID',
53
+ error instanceof Error ? error.message : String(error)
54
+ );
55
+ }
56
+ }
57
+
58
+ if (request.agent) {
59
+ const planned = planOrchestrationStageCompletion(taskRef, {
60
+ ...request.identity,
61
+ agent: request.agent
62
+ }, options);
63
+ if (planned.plan) {
64
+ return { ok: true, mode: request.mode, completionPlan: planned.plan, error: null };
65
+ }
66
+ return failure(
67
+ request.mode,
68
+ planned.result.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH',
69
+ planned.result.error?.message ?? 'orchestration provenance validation failed'
70
+ );
71
+ }
72
+
73
+ const inspected = inspectOrchestrationStage(taskRef, request.identity, options);
74
+ if (inspected.status !== 'failed') {
75
+ return { ok: true, mode: request.mode, completionPlan: null, error: null };
76
+ }
77
+ return failure(
78
+ request.mode,
79
+ inspected.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH',
80
+ inspected.error?.message ?? 'orchestration provenance validation failed'
81
+ );
82
+ }
83
+
84
+ function validateLifecycleExecution(
85
+ taskRef: string,
86
+ request: LifecycleExecutionRequest,
87
+ options: Readonly<{ repoRoot?: string }> = {}
88
+ ): LifecycleExecutionResult {
89
+ const inspected = inspectLifecycleExecution(taskRef, request, options);
90
+ if (inspected.ok || request.mode === 'standalone' || request.dryRun) return inspected;
91
+ const paused = pauseOrchestration(
92
+ taskRef,
93
+ inspected.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH',
94
+ inspected.error?.message ?? 'orchestration provenance validation failed',
95
+ true,
96
+ options
97
+ );
98
+ return failure(
99
+ request.mode,
100
+ paused.run?.pause?.code ?? inspected.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH',
101
+ paused.run?.pause?.message ?? inspected.error?.message ?? 'orchestration provenance validation failed'
102
+ );
103
+ }
104
+
105
+ export { inspectLifecycleExecution, validateLifecycleExecution };
106
+ export type { LifecycleExecutionMode, LifecycleExecutionRequest, LifecycleExecutionResult };