@fitlab-ai/agent-infra 0.9.13 → 0.9.15

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 +10 -0
  2. package/README.zh-CN.md +10 -0
  3. package/bin/cli.ts +26 -9
  4. package/bin/internal-cli.sh +45 -0
  5. package/dist/bin/cli.js +173 -157
  6. package/dist/bin/internal-cli.js +126 -42
  7. package/dist/lib/agent-client.js +5 -0
  8. package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +165 -27
  9. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +3 -2
  10. package/dist/lib/defaults.json +103 -103
  11. package/dist/lib/fs/durable-write.js +37 -0
  12. package/dist/lib/fs/file-lock.js +111 -0
  13. package/dist/lib/host-control/audit.js +19 -0
  14. package/dist/lib/host-control/client.js +142 -0
  15. package/dist/lib/host-control/command.js +49 -0
  16. package/dist/lib/host-control/path.js +160 -0
  17. package/dist/lib/host-control/secure-fs.js +140 -0
  18. package/dist/lib/host-control/server.js +159 -0
  19. package/dist/lib/host-control/service.js +112 -0
  20. package/dist/lib/init.js +11 -2
  21. package/dist/lib/internal/agent-client.js +5 -2
  22. package/dist/lib/internal/cli-route-inventory.js +154 -0
  23. package/dist/lib/internal/codex-lifecycle.js +15 -12
  24. package/dist/lib/internal/codex-sandbox-controller.js +8 -2
  25. package/dist/lib/internal/demo-promotion.js +322 -0
  26. package/dist/lib/internal/demo-transcript.js +454 -0
  27. package/dist/lib/internal/git-workflow.js +10 -6
  28. package/dist/lib/internal/host-control.js +28 -0
  29. package/dist/lib/internal/manual-validation.js +322 -0
  30. package/dist/lib/internal/platform-checks.js +16 -4
  31. package/dist/lib/internal/platform-comment.js +16 -4
  32. package/dist/lib/internal/platform-context.js +4 -1
  33. package/dist/lib/internal/platform-issue.js +12 -4
  34. package/dist/lib/internal/platform-metadata.js +88 -0
  35. package/dist/lib/internal/platform-pr-review.js +16 -3
  36. package/dist/lib/internal/platform-pr.js +42 -14
  37. package/dist/lib/internal/platform-release-notes.js +6 -3
  38. package/dist/lib/internal/platform-security.js +93 -0
  39. package/dist/lib/internal/pr-review-grade.js +14 -3
  40. package/dist/lib/internal/release-workflow.js +82 -89
  41. package/dist/lib/internal/sandbox-control.js +171 -7
  42. package/dist/lib/internal/task-activity.js +13 -4
  43. package/dist/lib/internal/task-artifact.js +19 -107
  44. package/dist/lib/internal/task-context.js +4 -1
  45. package/dist/lib/internal/task-create.js +48 -14
  46. package/dist/lib/internal/task-delivery.js +4 -1
  47. package/dist/lib/internal/task-event.js +38 -35
  48. package/dist/lib/internal/task-finalization.js +4 -1
  49. package/dist/lib/internal/task-invalidation.js +4 -1
  50. package/dist/lib/internal/task-ledger.js +12 -1
  51. package/dist/lib/internal/task-lifecycle.js +4 -1
  52. package/dist/lib/internal/task-operation-registry.js +519 -0
  53. package/dist/lib/internal/task-orchestration.js +12 -0
  54. package/dist/lib/internal/task-override.js +10 -3
  55. package/dist/lib/internal/task-qualification.js +90 -0
  56. package/dist/lib/internal/task-review.js +10 -52
  57. package/dist/lib/internal/task-short-id.js +11 -1
  58. package/dist/lib/internal/task-snapshot.js +4 -1
  59. package/dist/lib/internal/task-validate.js +37 -12
  60. package/dist/lib/internal/task-verify.js +5 -1
  61. package/dist/lib/internal/task-warning.js +8 -1
  62. package/dist/lib/owned-path.js +33 -0
  63. package/dist/lib/platform/check-status.js +11 -0
  64. package/dist/lib/platform/comment-safety.js +229 -0
  65. package/dist/lib/platform/completion-backfill.js +1 -1
  66. package/dist/lib/platform/github-data.js +241 -0
  67. package/dist/lib/platform/github-provider.js +248 -26
  68. package/dist/lib/platform/issue-comments.js +146 -34
  69. package/dist/lib/platform/issues.js +1 -179
  70. package/dist/lib/platform/pr-change-report.js +6 -12
  71. package/dist/lib/platform/pr-checks.js +12 -65
  72. package/dist/lib/platform/pr-summary.js +83 -10
  73. package/dist/lib/platform/provider-contract.d.ts +67 -1
  74. package/dist/lib/platform/provider-contract.js +6 -2
  75. package/dist/lib/platform/provider-validation.js +76 -3
  76. package/dist/lib/platform/pull-requests.js +117 -275
  77. package/dist/lib/platform/repository-metadata.js +377 -0
  78. package/dist/lib/platform/security-alerts.js +155 -0
  79. package/dist/lib/platform/snapshots.js +2 -0
  80. package/dist/lib/platform/verification-sync.js +154 -162
  81. package/dist/lib/process-data/index.js +7 -0
  82. package/dist/lib/release/workflow.js +1 -1
  83. package/dist/lib/run/index.js +5 -0
  84. package/dist/lib/sandbox/commands/control-status.js +22 -0
  85. package/dist/lib/sandbox/commands/create.js +39 -8
  86. package/dist/lib/sandbox/commands/ls.js +5 -0
  87. package/dist/lib/sandbox/commands/rm.js +3 -807
  88. package/dist/lib/sandbox/commands/show.js +16 -0
  89. package/dist/lib/sandbox/control/audit.js +203 -0
  90. package/dist/lib/sandbox/control/client.js +125 -12
  91. package/dist/lib/sandbox/control/completed-reentry.js +85 -0
  92. package/dist/lib/sandbox/control/container-identity.js +28 -31
  93. package/dist/lib/sandbox/control/executor.js +233 -34
  94. package/dist/lib/sandbox/control/finalization-response.js +27 -0
  95. package/dist/lib/sandbox/control/identity-sentinel.js +107 -0
  96. package/dist/lib/sandbox/control/lifecycle.js +656 -128
  97. package/dist/lib/sandbox/control/native-file-lock.js +85 -0
  98. package/dist/lib/sandbox/control/protocol.js +55 -4
  99. package/dist/lib/sandbox/control/server.js +720 -79
  100. package/dist/lib/sandbox/control/state.js +63 -3
  101. package/dist/lib/sandbox/control/task-view.js +183 -0
  102. package/dist/lib/sandbox/control/task-workflow.js +74 -0
  103. package/dist/lib/sandbox/control/workflow-executor.js +99 -0
  104. package/dist/lib/sandbox/engines/authority.js +289 -0
  105. package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
  106. package/dist/lib/sandbox/index.js +7 -2
  107. package/dist/lib/sandbox/recovery.js +49 -5
  108. package/dist/lib/sandbox/removal.js +1717 -0
  109. package/dist/lib/sandbox/task-cleanup.js +217 -0
  110. package/dist/lib/sandbox/workspace-view.js +15 -15
  111. package/dist/lib/sandbox/worktree-safety.js +4 -1
  112. package/dist/lib/server/index.js +8 -0
  113. package/dist/lib/task/activity-intent.js +2 -1
  114. package/dist/lib/task/activity-log.js +30 -24
  115. package/dist/lib/task/artifact-command.js +101 -0
  116. package/dist/lib/task/artifact-lifecycle.js +71 -40
  117. package/dist/lib/task/artifact-name.js +36 -0
  118. package/dist/lib/task/artifact-operations.js +474 -0
  119. package/dist/lib/task/artifact-receipts.js +3 -15
  120. package/dist/lib/task/artifact-repair-intent.js +130 -0
  121. package/dist/lib/task/artifact-schema.js +127 -0
  122. package/dist/lib/task/capabilities.js +83 -19
  123. package/dist/lib/task/codex-orchestration.js +71 -25
  124. package/dist/lib/task/commit-identity.js +28 -0
  125. package/dist/lib/task/commit-operation.js +2 -16
  126. package/dist/lib/task/control-authority.js +375 -5
  127. package/dist/lib/task/control-recovery.js +128 -0
  128. package/dist/lib/task/create-service.js +103 -4
  129. package/dist/lib/task/create.js +80 -2
  130. package/dist/lib/task/decision-details.js +2 -46
  131. package/dist/lib/task/events.js +306 -76
  132. package/dist/lib/task/finalization-state.js +9 -0
  133. package/dist/lib/task/human-override.js +3 -6
  134. package/dist/lib/task/implementation-inputs.js +3 -3
  135. package/dist/lib/task/index.js +11 -3
  136. package/dist/lib/task/intermediate-cleanup.js +383 -0
  137. package/dist/lib/task/invalidation.js +18 -65
  138. package/dist/lib/task/ledger-intents.js +7 -22
  139. package/dist/lib/task/ledger.js +1 -3
  140. package/dist/lib/task/lifecycle.js +19 -1
  141. package/dist/lib/task/local-artifact-finalization.js +190 -290
  142. package/dist/lib/task/manual-validation-completion.js +26 -0
  143. package/dist/lib/task/manual-validation-evidence.js +130 -0
  144. package/dist/lib/task/manual-validation-receipt.js +101 -0
  145. package/dist/lib/task/manual-validation-shared.js +40 -0
  146. package/dist/lib/task/manual-validation-transaction.js +243 -0
  147. package/dist/lib/task/markdown.js +47 -0
  148. package/dist/lib/task/orchestration.js +206 -69
  149. package/dist/lib/task/qualification-audit.js +476 -0
  150. package/dist/lib/task/qualification-confirmation.js +109 -0
  151. package/dist/lib/task/qualification-intents.js +148 -0
  152. package/dist/lib/task/review-artifacts.js +23 -40
  153. package/dist/lib/task/review-command.js +25 -0
  154. package/dist/lib/task/review-finalization.js +146 -97
  155. package/dist/lib/task/review-fingerprint.js +2 -2
  156. package/dist/lib/task/sections.js +34 -54
  157. package/dist/lib/task/verification-config.js +11 -0
  158. package/dist/lib/task/verification-engine.js +170 -327
  159. package/dist/lib/task/verification.js +1 -1
  160. package/dist/lib/task/workflow-command.js +17 -0
  161. package/dist/lib/task/workflow-warning-intents.js +0 -16
  162. package/dist/lib/task/workflow-warnings.js +28 -2
  163. package/dist/lib/update.js +2 -0
  164. package/dist/lifecycle-build-manifest.json +3 -3
  165. package/lib/agent-client.ts +9 -0
  166. package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +223 -33
  167. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +3 -2
  168. package/lib/fs/durable-write.ts +29 -0
  169. package/lib/fs/file-lock.ts +113 -0
  170. package/lib/host-control/audit.ts +22 -0
  171. package/lib/host-control/client.ts +172 -0
  172. package/lib/host-control/command.ts +60 -0
  173. package/lib/host-control/path.ts +167 -0
  174. package/lib/host-control/secure-fs.ts +135 -0
  175. package/lib/host-control/server.ts +180 -0
  176. package/lib/host-control/service.ts +133 -0
  177. package/lib/init.ts +15 -2
  178. package/lib/internal/agent-client.ts +4 -2
  179. package/lib/internal/cli-route-inventory.ts +142 -0
  180. package/lib/internal/codex-lifecycle.ts +14 -12
  181. package/lib/internal/codex-sandbox-controller.ts +7 -2
  182. package/lib/internal/demo-promotion.ts +354 -0
  183. package/lib/internal/demo-transcript.ts +419 -0
  184. package/lib/internal/git-workflow.ts +9 -6
  185. package/lib/internal/host-control.ts +28 -0
  186. package/lib/internal/manual-validation.ts +306 -0
  187. package/lib/internal/platform-checks.ts +12 -4
  188. package/lib/internal/platform-comment.ts +12 -4
  189. package/lib/internal/platform-context.ts +3 -1
  190. package/lib/internal/platform-issue.ts +11 -4
  191. package/lib/internal/platform-metadata.ts +70 -0
  192. package/lib/internal/platform-pr-review.ts +14 -3
  193. package/lib/internal/platform-pr.ts +38 -14
  194. package/lib/internal/platform-release-notes.ts +5 -3
  195. package/lib/internal/platform-security.ts +83 -0
  196. package/lib/internal/pr-review-grade.ts +10 -3
  197. package/lib/internal/release-workflow.ts +91 -87
  198. package/lib/internal/sandbox-control.ts +181 -6
  199. package/lib/internal/task-activity.ts +12 -4
  200. package/lib/internal/task-artifact.ts +15 -79
  201. package/lib/internal/task-context.ts +3 -1
  202. package/lib/internal/task-create.ts +76 -15
  203. package/lib/internal/task-delivery.ts +3 -1
  204. package/lib/internal/task-event.ts +21 -10
  205. package/lib/internal/task-finalization.ts +3 -1
  206. package/lib/internal/task-invalidation.ts +3 -1
  207. package/lib/internal/task-ledger.ts +11 -1
  208. package/lib/internal/task-lifecycle.ts +3 -1
  209. package/lib/internal/task-operation-registry.ts +590 -0
  210. package/lib/internal/task-orchestration.ts +12 -0
  211. package/lib/internal/task-override.ts +9 -3
  212. package/lib/internal/task-qualification.ts +61 -0
  213. package/lib/internal/task-review.ts +7 -50
  214. package/lib/internal/task-short-id.ts +10 -1
  215. package/lib/internal/task-snapshot.ts +3 -1
  216. package/lib/internal/task-validate.ts +32 -12
  217. package/lib/internal/task-verify.ts +4 -1
  218. package/lib/internal/task-warning.ts +7 -1
  219. package/lib/owned-path.ts +26 -0
  220. package/lib/platform/check-status.ts +9 -0
  221. package/lib/platform/comment-safety.ts +255 -0
  222. package/lib/platform/completion-backfill.ts +1 -1
  223. package/lib/platform/github-data.ts +322 -0
  224. package/lib/platform/github-provider.ts +244 -27
  225. package/lib/platform/issue-comments.ts +159 -35
  226. package/lib/platform/issues.ts +4 -245
  227. package/lib/platform/pr-change-report.ts +6 -12
  228. package/lib/platform/pr-checks.ts +13 -77
  229. package/lib/platform/pr-summary.ts +88 -11
  230. package/lib/platform/provider-contract.ts +78 -3
  231. package/lib/platform/provider-validation.ts +85 -3
  232. package/lib/platform/pull-requests.ts +129 -348
  233. package/lib/platform/repository-metadata.ts +453 -0
  234. package/lib/platform/security-alerts.ts +191 -0
  235. package/lib/platform/snapshots.ts +53 -0
  236. package/lib/platform/verification-sync.ts +171 -177
  237. package/lib/process-data/index.ts +7 -0
  238. package/lib/release/workflow.ts +3 -3
  239. package/lib/run/index.ts +5 -0
  240. package/lib/sandbox/commands/control-status.ts +26 -0
  241. package/lib/sandbox/commands/create.ts +53 -12
  242. package/lib/sandbox/commands/ls.ts +7 -0
  243. package/lib/sandbox/commands/rm.ts +3 -996
  244. package/lib/sandbox/commands/show.ts +16 -0
  245. package/lib/sandbox/control/audit.ts +253 -0
  246. package/lib/sandbox/control/client.ts +150 -13
  247. package/lib/sandbox/control/completed-reentry.ts +98 -0
  248. package/lib/sandbox/control/container-identity.ts +27 -43
  249. package/lib/sandbox/control/executor.ts +262 -37
  250. package/lib/sandbox/control/finalization-response.ts +29 -0
  251. package/lib/sandbox/control/identity-sentinel.ts +137 -0
  252. package/lib/sandbox/control/lifecycle.ts +672 -18
  253. package/lib/sandbox/control/native-file-lock.ts +108 -0
  254. package/lib/sandbox/control/protocol.ts +80 -8
  255. package/lib/sandbox/control/server.ts +779 -82
  256. package/lib/sandbox/control/state.ts +84 -3
  257. package/lib/sandbox/control/task-view.ts +240 -0
  258. package/lib/sandbox/control/task-workflow.ts +95 -0
  259. package/lib/sandbox/control/workflow-executor.ts +102 -0
  260. package/lib/sandbox/engines/authority.ts +365 -0
  261. package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
  262. package/lib/sandbox/index.ts +9 -2
  263. package/lib/sandbox/recovery.ts +49 -6
  264. package/lib/sandbox/removal.ts +2144 -0
  265. package/lib/sandbox/task-cleanup.ts +209 -0
  266. package/lib/sandbox/workspace-view.ts +26 -18
  267. package/lib/sandbox/worktree-safety.ts +4 -1
  268. package/lib/server/index.ts +10 -0
  269. package/lib/task/activity-intent.ts +2 -2
  270. package/lib/task/activity-log.ts +27 -19
  271. package/lib/task/artifact-command.ts +104 -0
  272. package/lib/task/artifact-lifecycle.ts +66 -39
  273. package/lib/task/artifact-name.ts +55 -0
  274. package/lib/task/artifact-operations.ts +580 -0
  275. package/lib/task/artifact-receipts.ts +3 -14
  276. package/lib/task/artifact-repair-intent.ts +152 -0
  277. package/lib/task/artifact-schema.ts +163 -0
  278. package/lib/task/capabilities.ts +82 -22
  279. package/lib/task/codex-orchestration.ts +85 -24
  280. package/lib/task/commit-identity.ts +31 -0
  281. package/lib/task/commit-operation.ts +2 -16
  282. package/lib/task/control-authority.ts +513 -6
  283. package/lib/task/control-recovery.ts +174 -0
  284. package/lib/task/create-service.ts +131 -6
  285. package/lib/task/create.ts +83 -1
  286. package/lib/task/decision-details.ts +3 -71
  287. package/lib/task/events.ts +292 -75
  288. package/lib/task/finalization-state.ts +11 -0
  289. package/lib/task/human-override.ts +3 -8
  290. package/lib/task/implementation-inputs.ts +3 -3
  291. package/lib/task/index.ts +16 -3
  292. package/lib/task/intermediate-cleanup.ts +455 -0
  293. package/lib/task/invalidation.ts +18 -62
  294. package/lib/task/ledger-intents.ts +7 -24
  295. package/lib/task/ledger.ts +1 -3
  296. package/lib/task/lifecycle.ts +17 -1
  297. package/lib/task/local-artifact-finalization.ts +223 -388
  298. package/lib/task/manual-validation-completion.ts +40 -0
  299. package/lib/task/manual-validation-evidence.ts +209 -0
  300. package/lib/task/manual-validation-receipt.ts +152 -0
  301. package/lib/task/manual-validation-shared.ts +50 -0
  302. package/lib/task/manual-validation-transaction.ts +304 -0
  303. package/lib/task/markdown.ts +70 -0
  304. package/lib/task/orchestration.ts +191 -68
  305. package/lib/task/qualification-audit.ts +588 -0
  306. package/lib/task/qualification-confirmation.ts +117 -0
  307. package/lib/task/qualification-intents.ts +150 -0
  308. package/lib/task/review-artifacts.ts +21 -41
  309. package/lib/task/review-command.ts +23 -0
  310. package/lib/task/review-finalization.ts +154 -153
  311. package/lib/task/review-fingerprint.ts +2 -2
  312. package/lib/task/sections.ts +33 -52
  313. package/lib/task/verification-config.ts +12 -0
  314. package/lib/task/verification-engine.ts +165 -370
  315. package/lib/task/verification-types.ts +17 -0
  316. package/lib/task/verification.ts +1 -1
  317. package/lib/task/workflow-command.ts +18 -0
  318. package/lib/task/workflow-warning-intents.ts +0 -13
  319. package/lib/task/workflow-warnings.ts +21 -2
  320. package/lib/update.ts +6 -0
  321. package/package.json +7 -2
  322. package/templates/.agents/hooks/lifecycle-delegation.js +6 -6
  323. package/templates/.agents/rules/README.en.md +2 -0
  324. package/templates/.agents/rules/README.zh-CN.md +2 -0
  325. package/templates/.agents/rules/decision-qualification.en.md +22 -0
  326. package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
  327. package/templates/.agents/rules/evidence-reporting.en.md +28 -0
  328. package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
  329. package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
  330. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
  331. package/templates/.agents/rules/local-artifact-repair.en.md +5 -1
  332. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +5 -1
  333. package/templates/.agents/rules/security-alerts.en.md +8 -8
  334. package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
  335. package/templates/.agents/rules/testing-discipline.en.md +2 -0
  336. package/templates/.agents/rules/testing-discipline.zh-CN.md +2 -0
  337. package/templates/.agents/scripts/package.json +3 -0
  338. package/templates/.agents/skills/analyze-task/SKILL.en.md +15 -2
  339. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +19 -2
  340. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
  341. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
  342. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  343. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  344. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  345. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  346. package/templates/.agents/skills/code-task/SKILL.en.md +14 -1
  347. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +14 -1
  348. package/templates/.agents/skills/code-task/config/verify.en.json +5 -14
  349. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +5 -14
  350. package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
  351. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
  352. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
  353. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
  354. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
  355. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
  356. package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
  357. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
  358. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +37 -21
  359. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +37 -21
  360. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
  361. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
  362. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +4 -0
  363. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +4 -0
  364. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +16 -7
  365. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +16 -7
  366. package/templates/.agents/skills/complete-task/SKILL.en.md +10 -23
  367. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +10 -23
  368. package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
  369. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
  370. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  371. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  372. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  373. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  374. package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
  375. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
  376. package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
  377. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
  378. package/templates/.agents/skills/plan-task/SKILL.en.md +14 -1
  379. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +16 -1
  380. package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
  381. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
  382. package/templates/.agents/skills/release/SKILL.en.md +7 -3
  383. package/templates/.agents/skills/release/SKILL.zh-CN.md +7 -3
  384. package/templates/.agents/skills/review-analysis/SKILL.en.md +14 -1
  385. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -1
  386. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
  387. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
  388. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
  389. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
  390. package/templates/.agents/skills/review-code/SKILL.en.md +14 -1
  391. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +14 -1
  392. package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
  393. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
  394. package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
  395. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
  396. package/templates/.agents/skills/review-plan/SKILL.en.md +14 -1
  397. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -1
  398. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
  399. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
  400. package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
  401. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
  402. package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
  403. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
  404. package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
  405. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
  406. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +25 -4
  407. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +25 -4
  408. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +4 -1
  409. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +4 -1
  410. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +5 -1
  411. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +5 -1
  412. package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
  413. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
  414. package/templates/.agents/skills/test/SKILL.en.md +29 -7
  415. package/templates/.agents/skills/test/SKILL.zh-CN.md +29 -7
  416. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
  417. package/templates/.agents/templates/task.en.md +6 -0
  418. package/templates/.agents/templates/task.zh-CN.md +6 -0
  419. package/templates/.claude/commands/run-manual-validation.en.md +1 -1
  420. package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
  421. package/dist/lib/platform/adapters.js +0 -56
  422. package/lib/platform/adapters.ts +0 -197
  423. package/templates/.agents/scripts/security-alerts.github.sh +0 -151
  424. package/templates/.agents/scripts/security-alerts.sh +0 -31
  425. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
  426. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
  427. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
  428. package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
@@ -0,0 +1,174 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { isCompletionEvidence } from './orchestration.ts';
3
+ import { TASK_WORKFLOW_OPERATIONS } from './workflow-command.ts';
4
+
5
+ export type ControlRecoveryOutcome = 'not-executed' | 'in-progress' | 'success' | 'failure' | 'unknown' | 'rejected';
6
+
7
+ /** Normalize the command result once at the control transport boundary. */
8
+ export function parseControlOutput(output: string | null): Record<string, unknown> | null {
9
+ if (output === null) return null;
10
+ try {
11
+ const value = JSON.parse(output);
12
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
13
+ return value.result && typeof value.result === 'object' && !Array.isArray(value.result) ? value.result : value;
14
+ } catch { return null; }
15
+ }
16
+
17
+ export type ControlRecoveryOperation = Readonly<{
18
+ family: 'task-lifecycle' | 'task-finalization' | 'task-orchestration' | 'task-create' | 'codex-controller' | 'task-workflow';
19
+ intent: string;
20
+ class: string;
21
+ }>;
22
+
23
+ export type ControlRecoveryBinding = Readonly<{
24
+ requestId: string;
25
+ generation: string;
26
+ taskId: string | null;
27
+ intentDigest: string;
28
+ }>;
29
+
30
+ export type ControlRecoveryInput = Readonly<{
31
+ operation: ControlRecoveryOperation;
32
+ binding: ControlRecoveryBinding;
33
+ startedCommitted: boolean;
34
+ terminalResult?: Readonly<Record<string, unknown>> | null;
35
+ criticalPhases?: readonly string[];
36
+ domain?: Readonly<Record<string, unknown>> | null;
37
+ journal?: Readonly<{
38
+ exists: boolean;
39
+ completedSteps?: readonly string[];
40
+ failure?: string | null;
41
+ }> | null;
42
+ explicitRejection?: boolean;
43
+ evidenceConflict?: boolean;
44
+ }>;
45
+
46
+ export const SANDBOX_CONTROL_REQUIRED_COMPLETION_PHASES = Object.freeze([
47
+ 'completed', 'evidence-written', 'publish-authorized'
48
+ ] as const);
49
+
50
+ export type ControlRecoveryDecision = Readonly<{
51
+ outcome: ControlRecoveryOutcome;
52
+ responseReconstructable: boolean;
53
+ reasonCode: string;
54
+ }>;
55
+
56
+ const LIFECYCLE_INTENTS = ['block', 'activate', 'cancel', 'complete', 'close-codescan', 'close-dependabot', 'restore'] as const;
57
+ const ORCHESTRATION_INTENTS = [
58
+ 'begin-or-resume', 'route.read', 'route.clean-completion', 'status', 'prepare', 'dispatch',
59
+ 'await-activation', 'recover-prepared', 'hook-start', 'hook-stop', 'advance', 'pause'
60
+ ] as const;
61
+
62
+ export const SANDBOX_CONTROL_RECOVERY_OPERATIONS: readonly ControlRecoveryOperation[] = Object.freeze([
63
+ ...LIFECYCLE_INTENTS.map((intent) => ({ family: 'task-lifecycle' as const, intent, class: 'lifecycle-mutation' })),
64
+ { family: 'task-finalization', intent: 'complete', class: 'finalization' },
65
+ ...ORCHESTRATION_INTENTS.map((intent) => ({
66
+ family: 'task-orchestration' as const,
67
+ intent,
68
+ class: intent === 'route.clean-completion' ? 'route.clean-completion' : intent === 'route.read' || intent === 'status' ? 'read-only' : 'orchestration'
69
+ })),
70
+ { family: 'task-create', intent: 'create', class: 'task-create' },
71
+ ...TASK_WORKFLOW_OPERATIONS.map((intent) => ({ family: 'task-workflow' as const, intent, class: intent === 'artifact-inspect' || intent === 'decision-next-id' ? 'read-only' : 'workflow' })),
72
+ ...(['open', 'close', 'verify'] as const).map((intent) => ({ family: 'codex-controller' as const, intent, class: 'codex-controller' }))
73
+ ]);
74
+
75
+ export function digestControlRecoveryIntent(family: string, intent: string): string {
76
+ return createHash('sha256').update(`${family}\0${intent}`, 'utf8').digest('hex');
77
+ }
78
+
79
+ export function findSandboxControlRecoveryOperation(family: ControlRecoveryOperation['family'], intent: string): ControlRecoveryOperation | null {
80
+ return SANDBOX_CONTROL_RECOVERY_OPERATIONS.find((operation) => operation.family === family && operation.intent === intent) ?? null;
81
+ }
82
+
83
+ function bindingMatchesResult(binding: ControlRecoveryBinding, result: Readonly<Record<string, unknown>>): boolean {
84
+ return result.requestId === binding.requestId
85
+ && result.generation === binding.generation
86
+ && (result.taskId === undefined || result.taskId === binding.taskId)
87
+ && (result.intentDigest === undefined || result.intentDigest === binding.intentDigest);
88
+ }
89
+
90
+ function domainEvidenceMatches(
91
+ operation: ControlRecoveryOperation,
92
+ result: Readonly<Record<string, unknown>>,
93
+ domain: Readonly<Record<string, unknown>> | null | undefined
94
+ ): boolean {
95
+ if (!domain) return false;
96
+ if (domain.consistent !== true) return false;
97
+ if (operation.class === 'route.clean-completion') {
98
+ const completion = domain.completionEvidence as Record<string, unknown> | undefined;
99
+ const snapshot = domain.snapshot as Record<string, unknown> | undefined;
100
+ const lastReviewedCommit = domain.lastReviewedCommit;
101
+ return result.status === 'completed'
102
+ && domain.status === 'completed'
103
+ && domain.pendingDelegation === null
104
+ && isCompletionEvidence(completion)
105
+ && snapshot?.head === completion.head
106
+ && snapshot.headTree === completion.headTree
107
+ && snapshot.worktreeTree === completion.worktreeTree
108
+ && lastReviewedCommit === completion.lastReviewedCommit;
109
+ }
110
+ if (operation.class === 'read-only') return result.changed === false && domain.snapshotValid === true;
111
+ return true;
112
+ }
113
+
114
+ export function classifySandboxControlRecovery(input: ControlRecoveryInput): ControlRecoveryDecision {
115
+ const result = input.terminalResult ?? null;
116
+ if (input.evidenceConflict) return { outcome: 'unknown', responseReconstructable: false, reasonCode: 'RECOVERY_EVIDENCE_CONFLICT' };
117
+ if (input.explicitRejection && !input.startedCommitted) {
118
+ return { outcome: 'not-executed', responseReconstructable: true, reasonCode: 'RECOVERY_EXPLICIT_REJECTION' };
119
+ }
120
+ if (!input.startedCommitted) {
121
+ return { outcome: 'not-executed', responseReconstructable: false, reasonCode: 'RECOVERY_NOT_STARTED' };
122
+ }
123
+ if (!result) return { outcome: 'unknown', responseReconstructable: false, reasonCode: 'RECOVERY_TERMINAL_RESULT_MISSING' };
124
+ if (!bindingMatchesResult(input.binding, result)) {
125
+ return { outcome: 'unknown', responseReconstructable: false, reasonCode: 'RECOVERY_RESULT_BINDING_MISMATCH' };
126
+ }
127
+ if (!SANDBOX_CONTROL_REQUIRED_COMPLETION_PHASES.every((phase) => input.criticalPhases?.includes(phase))) {
128
+ return { outcome: 'unknown', responseReconstructable: false, reasonCode: 'RECOVERY_CRITICAL_AUDIT_INCOMPLETE' };
129
+ }
130
+ const status = result.status;
131
+ const failed = status === 'failed' || result.error !== null && result.error !== undefined;
132
+ if (failed) {
133
+ if (input.domain && input.domain.consistent === false) {
134
+ return { outcome: 'failure', responseReconstructable: true, reasonCode: 'RECOVERY_TERMINAL_FAILURE' };
135
+ }
136
+ return { outcome: 'unknown', responseReconstructable: false, reasonCode: 'RECOVERY_FAILURE_EVIDENCE_INCOMPLETE' };
137
+ }
138
+ if (result.changed === null) {
139
+ return { outcome: 'unknown', responseReconstructable: false, reasonCode: 'RECOVERY_RESULT_CHANGE_FLAG_MISSING' };
140
+ }
141
+ if (!domainEvidenceMatches(input.operation, result, input.domain)) {
142
+ if (input.journal?.exists && (input.journal.completedSteps?.length ?? 0) > 0) {
143
+ return { outcome: 'in-progress', responseReconstructable: false, reasonCode: 'RECOVERY_DOMAIN_EVIDENCE_INCOMPLETE' };
144
+ }
145
+ return { outcome: 'unknown', responseReconstructable: false, reasonCode: 'RECOVERY_DOMAIN_EVIDENCE_MISSING' };
146
+ }
147
+ if (input.operation.family === 'task-lifecycle' && input.journal?.exists) {
148
+ if (input.journal.failure) {
149
+ return { outcome: 'failure', responseReconstructable: true, reasonCode: 'RECOVERY_LIFECYCLE_JOURNAL_FAILURE' };
150
+ }
151
+ return {
152
+ outcome: input.journal.completedSteps && input.journal.completedSteps.length > 0 ? 'in-progress' : 'unknown',
153
+ responseReconstructable: false,
154
+ reasonCode: 'RECOVERY_LIFECYCLE_JOURNAL_PRESENT'
155
+ };
156
+ }
157
+ return {
158
+ outcome: 'success',
159
+ responseReconstructable: true,
160
+ reasonCode: input.operation.class === 'route.clean-completion' && result.changed === false
161
+ ? 'RECOVERY_ROUTE_COMPLETION_NOOP'
162
+ : 'RECOVERY_TERMINAL_AND_DOMAIN_MATCH'
163
+ };
164
+ }
165
+
166
+ export function operationRecoveryBinding(
167
+ requestId: string,
168
+ generation: string,
169
+ taskId: string | null,
170
+ family: string,
171
+ intent: string
172
+ ): ControlRecoveryBinding {
173
+ return { requestId, generation, taskId, intentDigest: digestControlRecoveryIntent(family, intent) };
174
+ }
@@ -12,6 +12,13 @@ import { verifyTaskEvent } from './verification.ts';
12
12
  type TaskCreateStatus = 'applied' | 'no-op' | 'degraded' | 'failed' | 'blocked';
13
13
  type TaskCreateOperation = { name: string; status: string; reasonCode: string | null };
14
14
  type TaskCreateWarning = { code: string; severity: string; action: string };
15
+ type TaskCreateRecovery = 'none' | 'same-request-id' | 'new-request-id' | 'inspect-domain-state';
16
+ type TaskCreateControl = Readonly<{
17
+ requestId: string | null;
18
+ accepted: boolean;
19
+ recovery: TaskCreateRecovery;
20
+ }>;
21
+ type TaskCreateError = { code: string; message: string; retryable: boolean };
15
22
  type TaskCreateResult = Readonly<{
16
23
  status: TaskCreateStatus;
17
24
  changed: boolean;
@@ -19,7 +26,8 @@ type TaskCreateResult = Readonly<{
19
26
  issue: { number: number; url: string } | null;
20
27
  operations: readonly TaskCreateOperation[];
21
28
  warnings: readonly TaskCreateWarning[];
22
- error: { code: string; message: string; retryable: boolean } | null;
29
+ error: TaskCreateError | null;
30
+ control?: TaskCreateControl;
23
31
  }>;
24
32
 
25
33
  type CreateTaskOptions = Readonly<{
@@ -42,6 +50,116 @@ const DEFAULT_DEPENDENCIES: TaskCreateDependencies = {
42
50
  addWarning: applyWorkflowWarningIntent
43
51
  };
44
52
 
53
+ function invalidTaskCreateResult(): never {
54
+ throw new Error('TASK_CREATE_RESULT_INVALID');
55
+ }
56
+
57
+ function exactKeys(value: Record<string, unknown>, expected: readonly string[]): boolean {
58
+ return Object.keys(value).sort().join(',') === [...expected].sort().join(',');
59
+ }
60
+
61
+ function validTaskReference(value: unknown): boolean {
62
+ return value === null || (typeof value === 'string' && value.length > 0);
63
+ }
64
+
65
+ function validTaskCreateError(value: unknown): value is TaskCreateError {
66
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
67
+ const error = value as Record<string, unknown>;
68
+ return exactKeys(error, ['code', 'message', 'retryable'])
69
+ && typeof error.code === 'string' && /^[A-Z][A-Z0-9_]+$/u.test(error.code)
70
+ && typeof error.message === 'string'
71
+ && typeof error.retryable === 'boolean';
72
+ }
73
+
74
+ function validTaskCreateControl(value: unknown): value is TaskCreateControl {
75
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
76
+ const control = value as Record<string, unknown>;
77
+ return exactKeys(control, ['accepted', 'recovery', 'requestId'])
78
+ && validTaskReference(control.requestId)
79
+ && typeof control.accepted === 'boolean'
80
+ && ['none', 'same-request-id', 'new-request-id', 'inspect-domain-state'].includes(control.recovery as string);
81
+ }
82
+
83
+ export function parseTaskCreateResult(value: unknown): TaskCreateResult {
84
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return invalidTaskCreateResult();
85
+ const result = value as Record<string, unknown>;
86
+ if (!exactKeys(result, ['changed', 'control', 'error', 'issue', 'operations', 'status', 'task', 'warnings'])
87
+ && !exactKeys(result, ['changed', 'error', 'issue', 'operations', 'status', 'task', 'warnings'])) {
88
+ return invalidTaskCreateResult();
89
+ }
90
+ if (!['applied', 'no-op', 'degraded', 'failed', 'blocked'].includes(result.status as string)
91
+ || typeof result.changed !== 'boolean'
92
+ || !result.task || typeof result.task !== 'object' || Array.isArray(result.task)
93
+ || !exactKeys(result.task as Record<string, unknown>, ['id', 'shortId'])
94
+ || !validTaskReference((result.task as { id?: unknown }).id)
95
+ || !validTaskReference((result.task as { shortId?: unknown }).shortId)
96
+ || !Array.isArray(result.operations)
97
+ || !result.operations.every((operation) => {
98
+ if (!operation || typeof operation !== 'object' || Array.isArray(operation)) return false;
99
+ const value = operation as Record<string, unknown>;
100
+ return exactKeys(value, ['name', 'reasonCode', 'status'])
101
+ && typeof value.name === 'string' && typeof value.status === 'string'
102
+ && (value.reasonCode === null || typeof value.reasonCode === 'string');
103
+ })
104
+ || !Array.isArray(result.warnings)
105
+ || !result.warnings.every((warning) => {
106
+ if (!warning || typeof warning !== 'object' || Array.isArray(warning)) return false;
107
+ const value = warning as Record<string, unknown>;
108
+ return exactKeys(value, ['action', 'code', 'severity'])
109
+ && typeof value.action === 'string' && typeof value.code === 'string' && typeof value.severity === 'string';
110
+ })
111
+ || (result.issue !== null && (
112
+ !result.issue || typeof result.issue !== 'object' || Array.isArray(result.issue)
113
+ || !exactKeys(result.issue as Record<string, unknown>, ['number', 'url'])
114
+ || !Number.isSafeInteger((result.issue as { number?: unknown }).number)
115
+ || ((result.issue as { number: number }).number) <= 0
116
+ || typeof (result.issue as { url?: unknown }).url !== 'string'
117
+ ))
118
+ || (result.error !== null && !validTaskCreateError(result.error))
119
+ || ('control' in result && !validTaskCreateControl(result.control))) {
120
+ return invalidTaskCreateResult();
121
+ }
122
+ if (result.status === 'blocked' && !(result.error as TaskCreateError | null)?.retryable) return invalidTaskCreateResult();
123
+ if (result.status === 'failed' && !(result.error as TaskCreateError | null)) return invalidTaskCreateResult();
124
+ return result as unknown as TaskCreateResult;
125
+ }
126
+
127
+ export function projectTaskCreateResult(result: TaskCreateResult, control: TaskCreateControl): TaskCreateResult {
128
+ return { ...result, control };
129
+ }
130
+
131
+ export function taskCreateExitCode(result: Pick<TaskCreateResult, 'status'>): number {
132
+ return result.status === 'blocked' ? 2 : result.status === 'failed' ? 1 : 0;
133
+ }
134
+
135
+ export function taskCreateFailure(
136
+ error: TaskCreateError,
137
+ control?: TaskCreateControl
138
+ ): TaskCreateResult {
139
+ return {
140
+ status: error.retryable ? 'blocked' : 'failed',
141
+ changed: false,
142
+ task: { id: null, shortId: null },
143
+ issue: null,
144
+ operations: [],
145
+ warnings: [],
146
+ error,
147
+ ...(control ? { control } : {})
148
+ };
149
+ }
150
+
151
+ export function taskCreateOutputUnavailableResult(requestId: string): TaskCreateResult {
152
+ return taskCreateFailure({
153
+ code: 'SANDBOX_CONTROL_OUTPUT_UNAVAILABLE',
154
+ message: 'SANDBOX_CONTROL_OUTPUT_UNAVAILABLE: task-create result output was not retained; inspect domain state before retrying',
155
+ retryable: false
156
+ }, {
157
+ requestId,
158
+ accepted: true,
159
+ recovery: 'inspect-domain-state'
160
+ });
161
+ }
162
+
45
163
  async function verifyCreatedTask(repoRoot: string, taskId: string): Promise<{ operation: TaskCreateOperation; error: TaskCreateResult['error'] }> {
46
164
  const verification = await verifyTaskEvent(
47
165
  { taskRef: taskId, event: 'create-task.completed' },
@@ -91,10 +209,7 @@ async function createTask(value: unknown, options: CreateTaskOptions): Promise<T
91
209
  } catch (error) {
92
210
  const message = error instanceof Error ? error.message : String(error);
93
211
  const code = /^([A-Z][A-Z0-9_]+)/.exec(message)?.[1] ?? 'TASK_CREATE_FAILED';
94
- return {
95
- status: 'failed', changed: false, task: { id: null, shortId: null }, issue: null,
96
- operations: [], warnings: [], error: { code, message, retryable: code === 'TASK_CREATE_LOCK_TIMEOUT' }
97
- };
212
+ return taskCreateFailure({ code, message, retryable: code === 'TASK_CREATE_LOCK_TIMEOUT' });
98
213
  }
99
214
 
100
215
  const operations: TaskCreateOperation[] = [{
@@ -168,4 +283,14 @@ async function createTask(value: unknown, options: CreateTaskOptions): Promise<T
168
283
  }
169
284
 
170
285
  export { createTask };
171
- export type { CreateTaskOptions, TaskCreateDependencies, TaskCreateOperation, TaskCreateResult, TaskCreateStatus, TaskCreateWarning };
286
+ export type {
287
+ CreateTaskOptions,
288
+ TaskCreateControl,
289
+ TaskCreateDependencies,
290
+ TaskCreateError,
291
+ TaskCreateOperation,
292
+ TaskCreateRecovery,
293
+ TaskCreateResult,
294
+ TaskCreateStatus,
295
+ TaskCreateWarning
296
+ };
@@ -7,6 +7,7 @@ import { loadShortIdByTaskId, mutateShortIdRegistry } from './short-id.ts';
7
7
  import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.ts';
8
8
  import { readDeliveryDefaults, validateBaseRef, validateRemote } from './delivery-target.ts';
9
9
  import { buildUnboundFact, encodePrDeliveryFact } from './pr-delivery-fact.ts';
10
+ import { CANDIDATE_COLUMNS, CONSTRAINT_COLUMNS, parseTaskQualification } from './qualification-audit.ts';
10
11
 
11
12
  const AGENTS = ['claude', 'codex', 'antigravity', 'opencode', 'cursor'] as const;
12
13
  const TYPES = ['feature', 'bugfix', 'refactor', 'docs', 'chore'] as const;
@@ -178,6 +179,78 @@ function renderList(items: readonly string[]): string {
178
179
  return items.map((item) => `- ${item}`).join('\n');
179
180
  }
180
181
 
182
+ function tableCell(value: string): string {
183
+ return value.replace(/\\/g, '\\\\').replace(/\|/g, '\\|').replace(/[\r\n]/g, ' ');
184
+ }
185
+
186
+ function renderTable(columns: readonly string[], rows: readonly (readonly string[])[]): string {
187
+ return [
188
+ `| ${columns.join(' | ')} |`,
189
+ `| ${columns.map(() => '---').join(' | ')} |`,
190
+ ...rows.map((row) => `| ${row.map(tableCell).join(' | ')} |`)
191
+ ].join('\n');
192
+ }
193
+
194
+ function escapeRegExp(value: string): string {
195
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
196
+ }
197
+
198
+ function candidateIdFor(index: number): string {
199
+ let value = index + 1;
200
+ let id = '';
201
+ while (value > 0) {
202
+ const remainder = (value - 1) % 26;
203
+ id = `${String.fromCharCode(65 + remainder)}${id}`;
204
+ value = Math.floor((value - 1) / 26);
205
+ }
206
+ return id;
207
+ }
208
+
209
+ function appendCanonicalRows(content: string, heading: string, columns: readonly string[], rows: readonly (readonly string[])[]): string {
210
+ if (rows.length === 0) return content;
211
+ const table = renderTable(columns, rows);
212
+ const [header, separator, ...rowLines] = table.split('\n');
213
+ const eol = content.includes('\r\n') ? '\r\n' : '\n';
214
+ const lines = content.split(/\r?\n/);
215
+ const headingPattern = new RegExp(`^###\\s+${escapeRegExp(heading)}\\s*$`);
216
+ const sectionStart = lines.findIndex((line) => headingPattern.test(line));
217
+ if (sectionStart < 0) throw new Error(`TASK_CREATE_QUALIFICATION_INVALID: section '${heading}' is missing`);
218
+ let sectionEnd = lines.length;
219
+ for (let index = sectionStart + 1; index < lines.length; index += 1) {
220
+ if (/^#{2,3}\s+/.test(lines[index]!)) {
221
+ sectionEnd = index;
222
+ break;
223
+ }
224
+ }
225
+ const matches: number[] = [];
226
+ for (let index = sectionStart + 1; index + 1 < sectionEnd; index += 1) {
227
+ if (lines[index]!.trim() === header && lines[index + 1]!.trim() === separator) matches.push(index);
228
+ }
229
+ if (matches.length !== 1) {
230
+ throw new Error(`TASK_CREATE_QUALIFICATION_INVALID: section '${heading}' must contain exactly one canonical qualification table`);
231
+ }
232
+ lines.splice(matches[0]! + 2, 0, ...rowLines);
233
+ return lines.join(eol);
234
+ }
235
+
236
+ function validateRenderedQualification(content: string, candidate: TaskCreateCandidateV1): void {
237
+ const parsed = parseTaskQualification(content);
238
+ if (!parsed.ok) {
239
+ throw new Error(`TASK_CREATE_QUALIFICATION_INVALID: ${parsed.code}: ${parsed.message}`);
240
+ }
241
+ if (!parsed.qualification.present) {
242
+ throw new Error('TASK_CREATE_QUALIFICATION_INVALID: rendered task qualification contract is missing');
243
+ }
244
+ const expectedConstraintIds = candidate.taskInput.constraints.map((_, index) => `C-${index + 1}`);
245
+ const expectedCandidateIds = candidate.taskInput.alternatives.map((_, index) => candidateIdFor(index));
246
+ const actualConstraintIds = parsed.qualification.constraints.map((row) => row.constraintId);
247
+ const actualCandidateIds = parsed.qualification.candidates.map((row) => row.candidateId);
248
+ if (JSON.stringify(actualConstraintIds) !== JSON.stringify(expectedConstraintIds)
249
+ || JSON.stringify(actualCandidateIds) !== JSON.stringify(expectedCandidateIds)) {
250
+ throw new Error('TASK_CREATE_QUALIFICATION_INVALID: rendered task qualification rows do not match task input');
251
+ }
252
+ }
253
+
181
254
  function replaceEmptySubsection(content: string, heading: string, items: readonly string[]): string {
182
255
  if (items.length === 0) return content;
183
256
  return content.replace(`${heading}\n`, `${heading}\n\n${renderList(items)}\n`);
@@ -231,6 +304,13 @@ function renderTask(params: Readonly<{
231
304
  ['### 验收标准', 'acceptanceCriteria'], ['### 未决事项', 'openQuestions']
232
305
  ];
233
306
  for (const [heading, key] of sections) content = replaceEmptySubsection(content, heading, candidate.taskInput[key]);
307
+ const constraintIds = candidate.taskInput.constraints.map((_, index) => `C-${index + 1}`);
308
+ content = appendCanonicalRows(content, '约束', CONSTRAINT_COLUMNS, candidate.taskInput.constraints.map((statement, index) => [
309
+ constraintIds[index]!, statement, 'assumption', 'create-task', 'taskInput', 'create-task input', '', ''
310
+ ]));
311
+ content = appendCanonicalRows(content, '候选与否决方案', CANDIDATE_COLUMNS, candidate.taskInput.alternatives.map((statement, index) => [
312
+ candidateIdFor(index), statement, 'pending', constraintIds.join(','), 'requires qualification', 'create-task input'
313
+ ]));
234
314
  content = content.replace('- **关联 Issue**:#XXX', '- **关联 Issue**:N/A');
235
315
  content = content.replace('- **关联 PR**:#XXX', '- **关联 PR**:N/A');
236
316
  content = content.replace('- **分支**:`feature/xxx`', `- **分支**:\`${branch}\``);
@@ -338,7 +418,6 @@ function createLocalTask(value: unknown, options: LocalTaskCreateOptions): Local
338
418
 
339
419
  return withCreateLock(repoRoot, workspaceRoot, () => {
340
420
  if (fs.existsSync(receipts)) assertRealDirectory(receipts, 'TASK_CREATE_RECEIPT_INVALID');
341
- else fs.mkdirSync(receipts, { mode: 0o700 });
342
421
  const receiptPath = path.join(receipts, `${keyDigest}.json`);
343
422
  if (fs.existsSync(receiptPath)) {
344
423
  const stat = fs.lstatSync(receiptPath);
@@ -353,6 +432,7 @@ function createLocalTask(value: unknown, options: LocalTaskCreateOptions): Local
353
432
 
354
433
  const recovered = recoverPublishedTask(activeRoot, repoRoot, keyDigest, candidateDigest);
355
434
  if (recovered) {
435
+ ensureRealDirectory(receipts, 'TASK_CREATE_RECEIPT_INVALID');
356
436
  writeReceipt(receiptPath, {
357
437
  version: 1, candidateDigest, taskId: recovered.taskId, shortId: recovered.shortId, status: 'recovered'
358
438
  });
@@ -374,6 +454,8 @@ function createLocalTask(value: unknown, options: LocalTaskCreateOptions): Local
374
454
  template: fs.readFileSync(templatePath, 'utf8'), candidate, taskId, project: projectConfig.project, delivery: projectConfig.delivery, timestamp,
375
455
  agentInfraVersion, keyDigest, candidateDigest
376
456
  });
457
+ validateRenderedQualification(rendered, candidate);
458
+ ensureRealDirectory(receipts, 'TASK_CREATE_RECEIPT_INVALID');
377
459
  const temporary = path.join(workspaceRoot, `.task-create.tmp.${process.pid}.${randomUUID()}`);
378
460
  fs.mkdirSync(temporary, { mode: 0o700 });
379
461
  fs.writeFileSync(path.join(temporary, 'task.md'), rendered, { flag: 'wx', mode: 0o600 });
@@ -1,23 +1,4 @@
1
- type SourceLine = {
2
- start: number;
3
- end: number;
4
- text: string;
5
- };
6
-
7
- type VisibleHeading = SourceLine & {
8
- level: number;
9
- text: string;
10
- };
11
-
12
- type VisibleAnchor = SourceLine & {
13
- id: string;
14
- };
15
-
16
- type VisibleMarkdown = {
17
- lines: SourceLine[];
18
- headings: VisibleHeading[];
19
- anchors: VisibleAnchor[];
20
- };
1
+ import { scanVisibleMarkdown, type SourceLine } from './markdown.ts';
21
2
 
22
3
  type DecisionDetailBlock = {
23
4
  id: string;
@@ -49,54 +30,9 @@ type DecisionDetailInspection =
49
30
  };
50
31
 
51
32
  const DECISION_ID = /^(AN|PL|CD|HD)-[1-9]\d*(?=$|[\s::])/i;
52
- const HEADING = /^ {0,3}(#{1,6})[ \t]+(.+?)\s*$/;
53
- const FENCE_OPEN = /^ {0,3}(`{3,}|~{3,})(.*)$/;
54
- const FENCE_CLOSE = /^ {0,3}(`{3,}|~{3,})\s*$/;
55
- const ANCHOR = /^\s*<a\s+id=(['"])([^'"]+)\1\s*><\/a>\s*$/;
56
33
  const FIELD = /^\s*[-*]\s+\*\*([^*]+)\*\*\s*[::]\s*/;
57
34
  const OPTION_HEADING = /^(?:方案|Option)\s+[A-Z](?:\b|\s*[::])/i;
58
35
 
59
- function sourceLines(content: string): SourceLine[] {
60
- const lines: SourceLine[] = [];
61
- let start = 0;
62
- while (start < content.length) {
63
- const newline = content.indexOf('\n', start);
64
- const end = newline === -1 ? content.length : newline;
65
- lines.push({ start, end, text: content.slice(start, end).replace(/\r$/, '') });
66
- start = newline === -1 ? content.length : newline + 1;
67
- }
68
- return lines;
69
- }
70
-
71
- function scanVisibleMarkdown(content: string): VisibleMarkdown {
72
- const lines = sourceLines(content);
73
- const visible: SourceLine[] = [];
74
- const headings: VisibleHeading[] = [];
75
- const anchors: VisibleAnchor[] = [];
76
- let fence: { character: '`' | '~'; length: number } | null = null;
77
-
78
- for (const line of lines) {
79
- if (fence) {
80
- const close = line.text.match(FENCE_CLOSE);
81
- if (close && close[1]![0] === fence.character && close[1]!.length >= fence.length) fence = null;
82
- continue;
83
- }
84
- const open = line.text.match(FENCE_OPEN);
85
- const marker = open?.[1];
86
- const info = open?.[2] ?? '';
87
- if (marker && !(marker[0] === '`' && info.includes('`'))) {
88
- fence = { character: marker[0] as '`' | '~', length: marker.length };
89
- continue;
90
- }
91
- visible.push(line);
92
- const heading = line.text.match(HEADING);
93
- if (heading) headings.push({ ...line, level: heading[1]!.length, text: heading[2]!.trim() });
94
- const anchor = line.text.match(ANCHOR);
95
- if (anchor) anchors.push({ ...line, id: anchor[2]! });
96
- }
97
- return { lines: visible, headings, anchors };
98
- }
99
-
100
36
  function parseDecisionDetailBlocks(content: string): DecisionDetailBlock[] {
101
37
  const scanned = scanVisibleMarkdown(content);
102
38
  const details = scanned.headings.filter((heading) => heading.level === 3 && DECISION_ID.test(heading.text));
@@ -270,15 +206,11 @@ export {
270
206
  normalizeDecisionDetailForDisplay,
271
207
  parseDecisionDetailBlocks,
272
208
  parseDecisionEvidence,
273
- resolveDecisionDetail,
274
- scanVisibleMarkdown
209
+ resolveDecisionDetail
275
210
  };
276
211
  export type {
277
212
  DecisionDetailBlock,
278
213
  DecisionDetailDuplicate,
279
214
  DecisionDetailInspection,
280
- DecisionDetailResolution,
281
- SourceLine,
282
- VisibleHeading,
283
- VisibleMarkdown
215
+ DecisionDetailResolution
284
216
  };