@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
@@ -0,0 +1,165 @@
1
+ import { createHash, randomBytes, randomUUID, timingSafeEqual } from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ class CommitIntentError extends Error {
5
+ code;
6
+ constructor(code, message) {
7
+ super(message);
8
+ this.name = 'CommitIntentError';
9
+ this.code = code;
10
+ }
11
+ }
12
+ function commitIntentPath(taskDir) {
13
+ return path.join(taskDir, 'commit-intent.json');
14
+ }
15
+ function digest(value) {
16
+ return createHash('sha256').update(value).digest('hex');
17
+ }
18
+ function serialize(value) {
19
+ return `${JSON.stringify(value, null, 2)}\n`;
20
+ }
21
+ function atomicWrite(file, value) {
22
+ const temp = `${file}.${process.pid}.${randomUUID()}.tmp`;
23
+ try {
24
+ fs.writeFileSync(temp, serialize(value), { encoding: 'utf8', flag: 'wx', mode: 0o600 });
25
+ const handle = fs.openSync(temp, 'r+');
26
+ try {
27
+ fs.fsyncSync(handle);
28
+ }
29
+ finally {
30
+ fs.closeSync(handle);
31
+ }
32
+ fs.renameSync(temp, file);
33
+ fs.chmodSync(file, 0o600);
34
+ try {
35
+ const directory = fs.openSync(path.dirname(file), 'r');
36
+ try {
37
+ fs.fsyncSync(directory);
38
+ }
39
+ finally {
40
+ fs.closeSync(directory);
41
+ }
42
+ }
43
+ catch (error) {
44
+ const code = error.code;
45
+ if (!['EACCES', 'EISDIR', 'EINVAL', 'EPERM'].includes(code ?? ''))
46
+ throw error;
47
+ }
48
+ }
49
+ finally {
50
+ if (fs.existsSync(temp))
51
+ fs.unlinkSync(temp);
52
+ }
53
+ }
54
+ function isRecord(value) {
55
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
56
+ }
57
+ function keysEqual(value, expected) {
58
+ return Object.keys(value).sort().join('\0') === [...expected].sort().join('\0');
59
+ }
60
+ function validPushEvidence(value) {
61
+ return value === null || (isRecord(value)
62
+ && keysEqual(value, ['remote', 'ref', 'head'])
63
+ && ['remote', 'ref', 'head'].every((key) => typeof value[key] === 'string' && value[key] !== ''));
64
+ }
65
+ function validOrchestration(value) {
66
+ if (value === null)
67
+ return true;
68
+ if (!isRecord(value) || !keysEqual(value, [
69
+ 'runId', 'receiptId', 'authorizationIssuedAt', 'sourceRunDigest', 'plannedRunDigest',
70
+ 'completionUpdatedAt', 'plannedReceipt'
71
+ ]))
72
+ return false;
73
+ return [
74
+ 'runId', 'receiptId', 'authorizationIssuedAt', 'sourceRunDigest', 'plannedRunDigest', 'completionUpdatedAt'
75
+ ].every((key) => typeof value[key] === 'string' && value[key] !== '') && isRecord(value.plannedReceipt);
76
+ }
77
+ function parseIntent(raw, taskId) {
78
+ let value;
79
+ try {
80
+ value = JSON.parse(raw);
81
+ }
82
+ catch {
83
+ throw new CommitIntentError('ORCHESTRATION_COMMIT_INTENT_INVALID', 'commit intent is not valid JSON');
84
+ }
85
+ if (!isRecord(value) || !keysEqual(value, [
86
+ 'schemaVersion', 'taskId', 'mode', 'phase', 'tokenDigest', 'baselineHead', 'committedHead',
87
+ 'pushEvidence', 'orchestration', 'createdAt', 'updatedAt'
88
+ ])) {
89
+ throw new CommitIntentError('ORCHESTRATION_COMMIT_INTENT_INVALID', 'commit intent has an invalid schema');
90
+ }
91
+ if (value.schemaVersion !== 1
92
+ || value.taskId !== taskId
93
+ || !['standalone', 'orchestrated'].includes(String(value.mode))
94
+ || !['prepared', 'committed', 'pushed'].includes(String(value.phase))
95
+ || typeof value.tokenDigest !== 'string'
96
+ || !/^[a-f0-9]{64}$/.test(value.tokenDigest)
97
+ || typeof value.baselineHead !== 'string'
98
+ || (value.committedHead !== null && typeof value.committedHead !== 'string')
99
+ || !validPushEvidence(value.pushEvidence)
100
+ || !validOrchestration(value.orchestration)
101
+ || typeof value.createdAt !== 'string'
102
+ || typeof value.updatedAt !== 'string'
103
+ || (value.mode === 'standalone') !== (value.orchestration === null)) {
104
+ throw new CommitIntentError('ORCHESTRATION_COMMIT_INTENT_INVALID', 'commit intent has invalid field values');
105
+ }
106
+ return value;
107
+ }
108
+ function tokenMatches(actualDigest, token) {
109
+ const actual = Buffer.from(actualDigest, 'hex');
110
+ const supplied = Buffer.from(digest(token), 'hex');
111
+ return actual.length === supplied.length && timingSafeEqual(actual, supplied);
112
+ }
113
+ function readCommitIntent(taskDir, taskId, token) {
114
+ const file = commitIntentPath(taskDir);
115
+ const intent = parseIntent(fs.readFileSync(file, 'utf8'), taskId);
116
+ if (token !== undefined && !tokenMatches(intent.tokenDigest, token)) {
117
+ throw new CommitIntentError('ORCHESTRATION_COMMIT_INTENT_TOKEN_MISMATCH', 'commit intent token does not match');
118
+ }
119
+ return intent;
120
+ }
121
+ function createCommitIntent(taskDir, input, options = {}) {
122
+ const file = commitIntentPath(taskDir);
123
+ if (fs.existsSync(file)) {
124
+ throw new CommitIntentError('ORCHESTRATION_COMMIT_INTENT_BUSY', 'an active commit intent already exists');
125
+ }
126
+ const token = (options.token ?? (() => randomBytes(32).toString('base64url')))();
127
+ const intent = Object.freeze({ schemaVersion: 1, ...input, tokenDigest: digest(token) });
128
+ atomicWrite(file, intent);
129
+ return { intent, token };
130
+ }
131
+ function updateCommitIntent(taskDir, taskId, token, updates) {
132
+ const current = readCommitIntent(taskDir, taskId, token);
133
+ const nextPhase = updates.phase ?? current.phase;
134
+ const transitions = {
135
+ prepared: ['prepared', 'committed', 'pushed'],
136
+ committed: ['committed', 'pushed'],
137
+ pushed: ['pushed']
138
+ };
139
+ if (!transitions[current.phase].includes(nextPhase)) {
140
+ throw new CommitIntentError('ORCHESTRATION_COMMIT_INTENT_STATE_INVALID', `cannot move commit intent from ${current.phase} to ${nextPhase}`);
141
+ }
142
+ const updated = Object.freeze({ ...current, ...updates, phase: nextPhase });
143
+ atomicWrite(commitIntentPath(taskDir), updated);
144
+ return updated;
145
+ }
146
+ function removeCommitIntent(taskDir, taskId, token) {
147
+ readCommitIntent(taskDir, taskId, token);
148
+ fs.unlinkSync(commitIntentPath(taskDir));
149
+ }
150
+ function removeCommitIntentByDigest(taskDir, taskId, expectedDigest) {
151
+ const file = commitIntentPath(taskDir);
152
+ const raw = fs.readFileSync(file);
153
+ parseIntent(raw.toString('utf8'), taskId);
154
+ const actual = digest(raw);
155
+ const expected = Buffer.from(expectedDigest, 'hex');
156
+ const observed = Buffer.from(actual, 'hex');
157
+ if (!/^[a-f0-9]{64}$/.test(expectedDigest)
158
+ || expected.length !== observed.length
159
+ || !timingSafeEqual(expected, observed)) {
160
+ throw new CommitIntentError('ORCHESTRATION_COMMIT_RECOVERY_REQUIRED', 'commit intent changed after recovery inspection');
161
+ }
162
+ fs.unlinkSync(file);
163
+ }
164
+ export { CommitIntentError, commitIntentPath, createCommitIntent, digest, readCommitIntent, removeCommitIntent, removeCommitIntentByDigest, serialize, updateCommitIntent };
165
+ //# sourceMappingURL=commit-intent.js.map
@@ -1,7 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import { appendActivityEntry, locateActivityLog } from './activity-log.js';
3
3
  import { isDecisionItem, listDecisionItems, selectDecisionItem } from './decision-items.js';
4
- import { createImplementationInput, IMPLEMENTATION_INPUT_ALIASES, parseImplementationInputs, renderImplementationInputs } from './implementation-inputs.js';
4
+ import { createImplementationInput, finalizeImplementationInput, IMPLEMENTATION_INPUT_ALIASES, parseImplementationInputs, renderImplementationInputs, selectDeclaredImplementationInput } from './implementation-inputs.js';
5
5
  import { LEDGER_COLUMNS, LEDGER_HEADINGS, parseLedger } from './ledger.js';
6
6
  import { resolveTaskContext } from './resolve-ref.js';
7
7
  import { extractSection, extractSubSection, findSectionHeading } from './sections.js';
@@ -45,7 +45,7 @@ function existingDecision(content, row, decision, needsImplementation) {
45
45
  ? { recordId, implementationInputId: null }
46
46
  : { conflict: '--needs-implementation is only valid for code-stage decisions' };
47
47
  const inputs = parseImplementationInputs(content).rows.filter((input) => input.ledgerId === row.id && input.decisionEvidence === row.evidence);
48
- if (inputs.length !== 1 || inputs[0].needsImplementation !== needsImplementation) {
48
+ if (inputs.length !== 1 || (needsImplementation !== undefined && inputs[0].needsImplementation !== needsImplementation)) {
49
49
  return { conflict: `implementation intent for '${row.id}' conflicts with the existing decision` };
50
50
  }
51
51
  return { recordId, implementationInputId: inputs[0].id };
@@ -87,10 +87,29 @@ function applyHumanDecision(request, options = {}) {
87
87
  return failed('DECISION_TARGET_INVALID', message, resolved.taskId);
88
88
  }
89
89
  const row = selected.row;
90
- if (row.stage === 'code' && request.needsImplementation === undefined)
91
- return failed('DECISION_PAYLOAD_INVALID', 'code-stage decisions require --needs-implementation true|false', resolved.taskId, row.id);
92
90
  if (row.stage !== 'code' && request.needsImplementation !== undefined)
93
91
  return failed('DECISION_PAYLOAD_INVALID', '--needs-implementation is only valid for code-stage decisions', resolved.taskId, row.id);
92
+ let parsedInputs = null;
93
+ let declaredInput = null;
94
+ let effectiveNeedsImplementation = request.needsImplementation;
95
+ if (row.stage === 'code') {
96
+ try {
97
+ parsedInputs = parseImplementationInputs(content);
98
+ declaredInput = selectDeclaredImplementationInput(parsedInputs.rows, row.id, row.evidence);
99
+ }
100
+ catch (error) {
101
+ return failed('DECISION_DOCUMENT_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId, row.id);
102
+ }
103
+ if (declaredInput) {
104
+ if (request.needsImplementation !== undefined && request.needsImplementation !== declaredInput.needsImplementation) {
105
+ return failed('DECISION_CONFLICT', `implementation intent for '${row.id}' conflicts with its declaration`, resolved.taskId, row.id);
106
+ }
107
+ effectiveNeedsImplementation = declaredInput.needsImplementation;
108
+ }
109
+ else if (effectiveNeedsImplementation === undefined) {
110
+ return failed('DECISION_PAYLOAD_INVALID', 'code-stage decisions require --needs-implementation true|false when no implementation intent was declared', resolved.taskId, row.id);
111
+ }
112
+ }
94
113
  let metadata;
95
114
  try {
96
115
  metadata = (options.metadataProvider ?? captureTaskWriteMetadata)();
@@ -119,22 +138,17 @@ function applyHumanDecision(request, options = {}) {
119
138
  ];
120
139
  let implementationInputId = null;
121
140
  if (row.stage === 'code') {
122
- let parsed;
123
- try {
124
- parsed = parseImplementationInputs(content);
125
- }
126
- catch (error) {
127
- return failed('DECISION_DOCUMENT_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId, row.id);
128
- }
129
- const input = createImplementationInput(parsed.rows, {
130
- ledgerId: row.id, decisionEvidence: evidence,
131
- needsImplementation: request.needsImplementation, decidedAt: metadata.timestamp
132
- });
133
- implementationInputId = input.id;
141
+ const nextInputs = declaredInput
142
+ ? finalizeImplementationInput(parsedInputs.rows, declaredInput.id, evidence, metadata.timestamp)
143
+ : [...parsedInputs.rows, createImplementationInput(parsedInputs.rows, {
144
+ ledgerId: row.id, decisionEvidence: evidence,
145
+ needsImplementation: effectiveNeedsImplementation, decidedAt: metadata.timestamp
146
+ })];
147
+ implementationInputId = declaredInput?.id ?? nextInputs[nextInputs.length - 1].id;
134
148
  mutations.push({
135
149
  kind: 'section', aliases: IMPLEMENTATION_INPUT_ALIASES,
136
150
  heading: findSectionHeading(content, [...IMPLEMENTATION_INPUT_ALIASES]),
137
- body: renderImplementationInputs([...parsed.rows, input])
151
+ body: renderImplementationInputs(nextInputs)
138
152
  });
139
153
  }
140
154
  mutations.push({
@@ -1,4 +1,5 @@
1
1
  import { randomUUID } from 'node:crypto';
2
+ import { normalizeAgentToken } from '../agent-clients/tokens.js';
2
3
  const MANAGED_AGENTS = {
3
4
  'agent-infra-lifecycle-executor': 'executor',
4
5
  'agent-infra-lifecycle-reviewer': 'reviewer'
@@ -14,7 +15,9 @@ function prepareDelegation(input, options = {}) {
14
15
  ...input,
15
16
  id: (options.id ?? randomUUID)(),
16
17
  actualModel: null,
18
+ actualReasoningEffort: null,
17
19
  modelFallbackReason: null,
20
+ reasoningEffortFallbackReason: null,
18
21
  parentId: null,
19
22
  childId: null,
20
23
  spawnMode: null,
@@ -41,10 +44,27 @@ function activateDelegation(receipt, event, options = {}) {
41
44
  }
42
45
  if (event.spawnMode !== 'fresh')
43
46
  return fail('DELEGATION_FORK_FORBIDDEN', `spawn mode '${event.spawnMode}' is not fresh`);
44
- const actualModel = event.actualModel ?? null;
45
- if (actualModel && receipt.requestedModel && actualModel !== receipt.requestedModel && !event.modelFallbackReason) {
47
+ const actualModel = event.actualModel;
48
+ if (!actualModel || actualModel.trim() !== actualModel) {
49
+ return fail('DELEGATION_MODEL_IDENTITY_MISSING', 'native start event must provide a non-empty actual model identity');
50
+ }
51
+ if (actualModel !== receipt.requestedModel && (!event.modelFallbackReason || event.modelFallbackReason.trim() === '')) {
46
52
  return fail('DELEGATION_MODEL_FALLBACK_UNRECORDED', 'actual model differs from requested model without a fallback reason');
47
53
  }
54
+ const actualReasoningEffort = event.actualReasoningEffort;
55
+ if (!actualReasoningEffort || actualReasoningEffort.trim() !== actualReasoningEffort) {
56
+ return fail('DELEGATION_REASONING_EFFORT_MISSING', 'native start event must provide a non-empty actual reasoning effort');
57
+ }
58
+ if (actualReasoningEffort !== receipt.requestedReasoningEffort
59
+ && (!event.reasoningEffortFallbackReason || event.reasoningEffortFallbackReason.trim() === '')) {
60
+ return fail('DELEGATION_REASONING_EFFORT_FALLBACK_UNRECORDED', 'actual reasoning effort differs from requested effort without a fallback reason');
61
+ }
62
+ if (actualModel === receipt.requestedModel && event.modelFallbackReason) {
63
+ return fail('DELEGATION_MODEL_FALLBACK_INVALID', 'model fallback reason is only valid when actual model differs');
64
+ }
65
+ if (actualReasoningEffort === receipt.requestedReasoningEffort && event.reasoningEffortFallbackReason) {
66
+ return fail('DELEGATION_REASONING_EFFORT_FALLBACK_INVALID', 'reasoning-effort fallback reason is only valid when actual effort differs');
67
+ }
48
68
  return { ok: true, receipt: Object.freeze({
49
69
  ...receipt,
50
70
  status: 'activated',
@@ -52,7 +72,9 @@ function activateDelegation(receipt, event, options = {}) {
52
72
  childId: event.childId,
53
73
  spawnMode: event.spawnMode,
54
74
  actualModel,
75
+ actualReasoningEffort,
55
76
  modelFallbackReason: event.modelFallbackReason ?? null,
77
+ reasoningEffortFallbackReason: event.reasoningEffortFallbackReason ?? null,
56
78
  activatedAt: (options.now ?? (() => new Date().toISOString()))()
57
79
  }) };
58
80
  }
@@ -62,8 +84,7 @@ function completeDelegationStage(receipt, event) {
62
84
  if (event.stage !== receipt.stage || event.round !== receipt.round || event.artifact !== receipt.artifact) {
63
85
  return fail('DELEGATION_STAGE_MISMATCH', 'stage completion identity does not match the active delegation');
64
86
  }
65
- const acceptedAgents = receipt.client === 'claude-code' ? ['claude', 'claude-code'] : [receipt.client];
66
- if (!acceptedAgents.includes(event.agent)) {
87
+ if (normalizeAgentToken(event.agent) !== normalizeAgentToken(receipt.client)) {
67
88
  return fail('DELEGATION_AGENT_MISMATCH', `stage agent '${event.agent}' does not match client '${receipt.client}'`);
68
89
  }
69
90
  return { ok: true, receipt: Object.freeze({ ...receipt, status: 'stage-completed', agent: event.agent }) };
@@ -7,7 +7,9 @@ import { parseLedger, summarizeLedgerStage, validateLedgerRows } from './ledger.
7
7
  import { parseReviewSummary } from './review-artifacts.js';
8
8
  import { resolveTaskRef } from './resolve-ref.js';
9
9
  import { findSectionHeading } from './sections.js';
10
- import { completeOrchestrationStage, validateOrchestrationStage } from './orchestration.js';
10
+ import { validateLifecycleExecution } from './lifecycle-execution.js';
11
+ import { commitOrchestrationStageCompletion } from './orchestration.js';
12
+ import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
11
13
  import { captureTaskWriteMetadata, writeTask } from './write.js';
12
14
  const eventCatalog = [
13
15
  'analyze.started', 'analyze.awaiting-input', 'analyze.completed',
@@ -22,17 +24,17 @@ const BASE_FIELDS = new Set(['taskRef', 'event', 'agent', 'dryRun']);
22
24
  const SCHEMAS = {
23
25
  'analyze.started': { optional: ['round'] },
24
26
  'analyze.awaiting-input': { required: ['question'] },
25
- 'analyze.completed': { required: ['artifact'], optional: ['round'] },
27
+ 'analyze.completed': { required: ['artifact'], optional: ['round', 'orchestrated'] },
26
28
  'review-analysis.started': { optional: ['round'] },
27
- 'review-analysis.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
29
+ 'review-analysis.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round', 'orchestrated'] },
28
30
  'plan.started': { optional: ['round'] },
29
- 'plan.completed': { required: ['artifact'], optional: ['round'] },
31
+ 'plan.completed': { required: ['artifact'], optional: ['round', 'orchestrated'] },
30
32
  'review-plan.started': { optional: ['round'] },
31
- 'review-plan.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
33
+ 'review-plan.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round', 'orchestrated'] },
32
34
  'code.started': { optional: ['round', 'fixFor', 'implementationInput'] },
33
- 'code.completed': { required: ['artifact'], optional: ['round', 'fixFor', 'implementationInput', 'filesModified', 'testsPassed', 'blockers', 'major', 'minor', 'manualValidation'] },
35
+ 'code.completed': { required: ['artifact'], optional: ['round', 'fixFor', 'implementationInput', 'filesModified', 'testsPassed', 'blockers', 'major', 'minor', 'manualValidation', 'orchestrated'] },
34
36
  'review-code.started': { optional: ['round'] },
35
- 'review-code.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
37
+ 'review-code.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round', 'orchestrated'] },
36
38
  'manual-validation.started': { optional: ['round'] },
37
39
  'manual-validation.completed': { required: ['artifact', 'summaryResult'], optional: ['round'] }
38
40
  };
@@ -229,7 +231,7 @@ function openStartedIdentity(rows, family) {
229
231
  });
230
232
  return matches.length === 1 ? matches[0] : matches.length > 1 ? { conflict: true } : null;
231
233
  }
232
- function applyTaskEvent(request, options = {}) {
234
+ function applyTaskEventUnlocked(request, options = {}) {
233
235
  const invalid = validateTaskEventRequest(request);
234
236
  if (invalid)
235
237
  return failed(request, invalid);
@@ -326,20 +328,27 @@ function applyTaskEvent(request, options = {}) {
326
328
  const findingCountError = validateReviewFindingCounts(normalized, content, eventIdentity.family, completedArtifact?.path ?? null);
327
329
  if (findingCountError)
328
330
  return failed(normalized, findingCountError, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
329
- if (eventIdentity.phase === 'completed' && !normalized.dryRun && eventIdentity.family !== 'manual-validation') {
331
+ let orchestrationCompletion = null;
332
+ if (eventIdentity.phase === 'completed' && eventIdentity.family !== 'manual-validation') {
330
333
  const orchestrationStage = eventIdentity.family === 'analyze' ? 'analysis' : eventIdentity.family;
331
- const provenance = validateOrchestrationStage(normalized.taskRef, {
332
- stage: orchestrationStage,
333
- round: normalized.round,
334
- artifact: normalized.artifact,
335
- role: eventIdentity.family.startsWith('review-') ? 'reviewer' : 'executor'
334
+ const execution = validateLifecycleExecution(normalized.taskRef, {
335
+ mode: normalized.orchestrated ? 'orchestrated' : 'standalone',
336
+ identity: {
337
+ stage: orchestrationStage,
338
+ round: normalized.round,
339
+ artifact: normalized.artifact,
340
+ role: eventIdentity.family.startsWith('review-') ? 'reviewer' : 'executor'
341
+ },
342
+ agent: normalized.agent,
343
+ dryRun: normalized.dryRun
336
344
  }, { repoRoot: options.repoRoot });
337
- if (provenance.status === 'failed' || provenance.status === 'paused') {
345
+ if (!execution.ok) {
338
346
  return failed(normalized, {
339
347
  code: 'EVENT_TRANSITION_INVALID',
340
- message: provenance.error?.message ?? provenance.run?.pause?.message ?? 'orchestration provenance validation failed'
348
+ message: `${execution.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH'}: ${execution.error?.message ?? 'orchestration provenance validation failed'}`
341
349
  }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase, artifactContext });
342
350
  }
351
+ orchestrationCompletion = execution.completionPlan;
343
352
  }
344
353
  let metadata;
345
354
  try {
@@ -379,19 +388,26 @@ function applyTaskEvent(request, options = {}) {
379
388
  const result = writeTask({ taskRef: normalized.taskRef, expectedState: 'active', dryRun: normalized.dryRun, mutations }, { ...options, metadataProvider: () => metadata });
380
389
  if (result.status === 'failed')
381
390
  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 });
382
- if (eventIdentity.phase === 'completed' && !normalized.dryRun && eventIdentity.family !== 'manual-validation') {
383
- const orchestrationStage = eventIdentity.family === 'analyze' ? 'analysis' : eventIdentity.family;
384
- const orchestration = completeOrchestrationStage(normalized.taskRef, {
385
- stage: orchestrationStage,
386
- round: normalized.round,
387
- artifact: normalized.artifact,
388
- agent: normalized.agent
389
- }, { repoRoot: options.repoRoot });
390
- if (orchestration.status === 'failed' || orchestration.status === 'paused') {
391
+ if (!normalized.dryRun && orchestrationCompletion) {
392
+ try {
393
+ (options.commitOrchestrationCompletion ?? commitOrchestrationStageCompletion)(orchestrationCompletion);
394
+ }
395
+ catch (error) {
391
396
  return failed(normalized, {
392
- code: 'EVENT_TRANSITION_INVALID',
393
- message: orchestration.error?.message ?? orchestration.run?.pause?.message ?? 'orchestration provenance validation failed'
394
- }, { 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 });
397
+ code: 'EVENT_ORCHESTRATION_COMMIT_FAILED',
398
+ message: `task.md was written but orchestration completion could not be persisted; manual recovery is required: ${error instanceof Error ? error.message : String(error)}`
399
+ }, {
400
+ taskId: result.taskId,
401
+ taskMdPath: result.taskMdPath,
402
+ fromStep: currentStep,
403
+ toStep: step,
404
+ action: eventIdentity.action,
405
+ phase: eventIdentity.phase,
406
+ timestamp: result.timestamp,
407
+ agentInfraVersion: result.agentInfraVersion,
408
+ operations: result.operations,
409
+ artifactContext
410
+ });
395
411
  }
396
412
  }
397
413
  return {
@@ -404,6 +420,29 @@ function applyTaskEvent(request, options = {}) {
404
420
  agentInfraVersion: result.agentInfraVersion, operations: result.operations, error: null
405
421
  };
406
422
  }
423
+ function applyTaskEvent(request, options = {}) {
424
+ const invalid = validateTaskEventRequest(request);
425
+ if (invalid)
426
+ return failed(request, invalid);
427
+ const parts = eventParts(request.event);
428
+ if (request.dryRun || parts.phase !== 'completed' || parts.family === 'manual-validation') {
429
+ return applyTaskEventUnlocked(request, options);
430
+ }
431
+ const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
432
+ if (!resolved.ok)
433
+ return applyTaskEventUnlocked(request, options);
434
+ try {
435
+ return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, `task-event.${request.event}`, () => applyTaskEventUnlocked(request, options));
436
+ }
437
+ catch (error) {
438
+ if (!(error instanceof TaskExecutionLockError))
439
+ throw error;
440
+ return failed(request, {
441
+ code: 'EVENT_TRANSITION_INVALID',
442
+ message: `${error.code}: ${error.message}`
443
+ }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
444
+ }
445
+ }
407
446
  function successNoOp(request, taskId, taskMdPath, currentStep, eventIdentity, timestamp, frontmatter, artifactContext) {
408
447
  return {
409
448
  ...failed(request, { code: 'EVENT_LOG_CONFLICT', message: '' }), status: 'no-op', error: null,
@@ -0,0 +1,35 @@
1
+ import { assertWritableInventory, inspectTaskArtifacts } from './artifact-lifecycle.js';
2
+ const COMPLETION_BACKFILL_FAMILIES = [
3
+ 'analysis',
4
+ 'review-analysis',
5
+ 'plan',
6
+ 'review-plan',
7
+ 'code',
8
+ 'review-code',
9
+ 'manual-validation'
10
+ ];
11
+ function inspectCompletionArtifacts(taskRef, options = {}) {
12
+ const artifacts = [];
13
+ let taskId = null;
14
+ let taskDir = null;
15
+ for (const family of COMPLETION_BACKFILL_FAMILIES) {
16
+ const inventory = inspectTaskArtifacts(taskRef, family, options);
17
+ taskId = inventory.taskId ?? taskId;
18
+ taskDir = inventory.taskDir ?? taskDir;
19
+ if (inventory.status === 'failed') {
20
+ return { status: 'failed', changed: false, taskId, taskDir, artifacts: [], error: inventory.error };
21
+ }
22
+ const writableError = assertWritableInventory(inventory);
23
+ const brokenReference = inventory.diagnostics.find((item) => item.code === 'BROKEN_REFERENCE');
24
+ const error = writableError ?? (brokenReference ? {
25
+ code: 'ARTIFACT_REFERENCE_INVALID',
26
+ message: brokenReference.message
27
+ } : null);
28
+ if (error)
29
+ return { status: 'failed', changed: false, taskId, taskDir, artifacts: [], error };
30
+ artifacts.push(...inventory.artifacts);
31
+ }
32
+ return { status: 'ready', changed: false, taskId, taskDir, artifacts, error: null };
33
+ }
34
+ export { COMPLETION_BACKFILL_FAMILIES, inspectCompletionArtifacts };
35
+ //# sourceMappingURL=finalization-artifacts.js.map
@@ -13,12 +13,11 @@ function validateInput(row) {
13
13
  throw new Error(`implementation input ${row.id} has incomplete decision identity`);
14
14
  if (row.stage !== 'code')
15
15
  throw new Error(`implementation input ${row.id} has invalid stage`);
16
- if (!TIMESTAMP_RE.test(row.decidedAt) || !Number.isFinite(Date.parse(row.decidedAt.replace(' ', 'T')))) {
17
- throw new Error(`implementation input ${row.id} has invalid decided_at`);
18
- }
19
- const valid = (row.needsImplementation && row.status === 'pending' && row.consumedBy === '') ||
20
- (!row.needsImplementation && row.status === 'not-required' && row.consumedBy === '') ||
21
- (row.needsImplementation && row.status === 'consumed' && ARTIFACT_RE.test(row.consumedBy));
16
+ const hasValidTimestamp = TIMESTAMP_RE.test(row.decidedAt) && Number.isFinite(Date.parse(row.decidedAt.replace(' ', 'T')));
17
+ const valid = (row.status === 'declared' && row.decidedAt === '' && row.consumedBy === '') ||
18
+ (hasValidTimestamp && row.needsImplementation && row.status === 'pending' && row.consumedBy === '') ||
19
+ (hasValidTimestamp && !row.needsImplementation && row.status === 'not-required' && row.consumedBy === '') ||
20
+ (hasValidTimestamp && row.needsImplementation && row.status === 'consumed' && ARTIFACT_RE.test(row.consumedBy));
22
21
  if (!valid)
23
22
  throw new Error(`implementation input ${row.id} has an invalid state combination`);
24
23
  }
@@ -67,6 +66,54 @@ function createImplementationInput(rows, draft) {
67
66
  validateInput(row);
68
67
  return row;
69
68
  }
69
+ function declareImplementationInput(rows, draft) {
70
+ const existing = rows.filter((row) => row.ledgerId === draft.ledgerId && row.status === 'declared');
71
+ if (existing.length > 1)
72
+ throw new Error(`implementation input declaration for '${draft.ledgerId}' conflicts with existing rows`);
73
+ if (existing.length === 1) {
74
+ const row = existing[0];
75
+ if (row.decisionEvidence !== draft.decisionEvidence || row.needsImplementation !== draft.needsImplementation) {
76
+ throw new Error(`implementation input declaration for '${draft.ledgerId}' conflicts with the existing row`);
77
+ }
78
+ return row;
79
+ }
80
+ const row = {
81
+ id: nextId(rows), ledgerId: draft.ledgerId, decisionEvidence: draft.decisionEvidence,
82
+ stage: 'code', needsImplementation: draft.needsImplementation, decidedAt: '',
83
+ status: 'declared', consumedBy: ''
84
+ };
85
+ validateInput(row);
86
+ return row;
87
+ }
88
+ function selectDeclaredImplementationInput(rows, ledgerId, decisionEvidence) {
89
+ const forLedger = rows.filter((row) => row.ledgerId === ledgerId && row.status === 'declared');
90
+ if (forLedger.length > 1)
91
+ throw new Error(`implementation input declaration for '${ledgerId}' is ambiguous`);
92
+ if (forLedger.length === 0)
93
+ return null;
94
+ if (forLedger[0].decisionEvidence !== decisionEvidence) {
95
+ throw new Error(`implementation input declaration for '${ledgerId}' has conflicting evidence`);
96
+ }
97
+ return forLedger[0];
98
+ }
99
+ function finalizeImplementationInput(rows, id, decisionEvidence, decidedAt) {
100
+ let found = false;
101
+ const next = rows.map((row) => {
102
+ if (row.id !== id)
103
+ return row;
104
+ found = true;
105
+ if (row.status !== 'declared')
106
+ throw new Error(`implementation input ${id} is not declared`);
107
+ return {
108
+ ...row, decisionEvidence, decidedAt,
109
+ status: row.needsImplementation ? 'pending' : 'not-required'
110
+ };
111
+ });
112
+ if (!found)
113
+ throw new Error(`implementation input ${id} was not found`);
114
+ next.forEach(validateInput);
115
+ return next;
116
+ }
70
117
  function selectPendingImplementationInput(rows, reviewCompletedAt) {
71
118
  const reviewEpoch = Date.parse(reviewCompletedAt.replace(' ', 'T'));
72
119
  if (!Number.isFinite(reviewEpoch))
@@ -113,5 +160,5 @@ function renderImplementationInputs(rows) {
113
160
  })
114
161
  ].join('\n');
115
162
  }
116
- export { SECTION_ALIASES as IMPLEMENTATION_INPUT_ALIASES, createImplementationInput, consumeImplementationInput, parseImplementationInputs, renderImplementationInputs, selectPendingImplementationInput };
163
+ export { SECTION_ALIASES as IMPLEMENTATION_INPUT_ALIASES, createImplementationInput, consumeImplementationInput, declareImplementationInput, finalizeImplementationInput, parseImplementationInputs, renderImplementationInputs, selectDeclaredImplementationInput, selectPendingImplementationInput };
117
164
  //# sourceMappingURL=implementation-inputs.js.map
@@ -1,5 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
+ import { declareImplementationInput, IMPLEMENTATION_INPUT_ALIASES, parseImplementationInputs, renderImplementationInputs } from './implementation-inputs.js';
3
4
  import { LEDGER_COLUMNS, LEDGER_HEADINGS, nextHdId, parseLedger, validateLedgerRows } from './ledger.js';
4
5
  import { resolveTaskRef } from './resolve-ref.js';
5
6
  import { writeTask } from './write.js';
@@ -66,6 +67,14 @@ function ledgerSectionMutation(content) {
66
67
  body: `| ${LEDGER_COLUMNS.join(' | ')} |\n|----|-------|-------|----------|--------|----------|`
67
68
  }];
68
69
  }
70
+ function implementationInputMutation(content, rows) {
71
+ const english = /^##\s+Activity Log\s*$/m.test(content);
72
+ return {
73
+ kind: 'section', aliases: IMPLEMENTATION_INPUT_ALIASES,
74
+ heading: english ? 'Implementation Inputs' : '实现输入',
75
+ body: renderImplementationInputs(rows)
76
+ };
77
+ }
69
78
  function mapWrite(intent, entityId, before, after, result) {
70
79
  if (result.status === 'failed')
71
80
  return failed(intent, result.error.code, result.error.message, result.taskId, entityId);
@@ -174,9 +183,34 @@ function applyLedgerIntent(intent, options = {}) {
174
183
  }
175
184
  }
176
185
  }
186
+ let implementationMutation = null;
187
+ if (intent.kind === 'decision-upsert' || intent.kind === 'finding-review') {
188
+ const stage = intent.kind === 'decision-upsert' ? intent.stage : after.stage;
189
+ const escalates = intent.kind === 'decision-upsert' || intent.status === 'needs-human-decision';
190
+ if (stage === 'code' && escalates && intent.needsImplementation === undefined) {
191
+ return failed(intent, 'LEDGER_PAYLOAD_INVALID', 'code-stage decisions require --needs-implementation true|false', resolved.taskId, after.id);
192
+ }
193
+ if ((stage !== 'code' || !escalates) && intent.needsImplementation !== undefined) {
194
+ return failed(intent, 'LEDGER_PAYLOAD_INVALID', '--needs-implementation is only valid for code-stage escalation', resolved.taskId, after.id);
195
+ }
196
+ if (stage === 'code' && escalates) {
197
+ try {
198
+ const parsed = parseImplementationInputs(content);
199
+ const declaration = declareImplementationInput(parsed.rows, {
200
+ ledgerId: after.id, decisionEvidence: after.evidence,
201
+ needsImplementation: intent.needsImplementation
202
+ });
203
+ const nextRows = parsed.rows.includes(declaration) ? parsed.rows : [...parsed.rows, declaration];
204
+ implementationMutation = implementationInputMutation(content, nextRows);
205
+ }
206
+ catch (error) {
207
+ return failed(intent, 'LEDGER_DOCUMENT_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId, after.id);
208
+ }
209
+ }
210
+ }
177
211
  const result = writeTask({
178
212
  taskRef: intent.taskRef, expectedState: 'active',
179
- mutations: [...ledgerSectionMutation(content), rowMutation(after)],
213
+ mutations: [...ledgerSectionMutation(content), rowMutation(after), ...(implementationMutation ? [implementationMutation] : [])],
180
214
  dryRun: 'dryRun' in intent ? intent.dryRun : false
181
215
  }, { ...options, taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: resolved.state } });
182
216
  return mapWrite(intent, after.id, before, after, result);