@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,117 @@
1
+ import { createHash } from 'node:crypto';
2
+ import fs from 'node:fs';
3
+
4
+ import { appendActivityEntry, locateActivityLog } from './activity-log.ts';
5
+ import { CONFIRMATION_COLUMNS, CONFIRMATION_HEADINGS, constraintDigest, parseQualificationConfirmations, parseTaskQualification } from './qualification-audit.ts';
6
+ import type { QualificationConfirmation } from './qualification-audit.ts';
7
+ import { findSectionHeading } from './sections.ts';
8
+ import { resolveTaskRef } from './resolve-ref.ts';
9
+ import { captureTaskWriteMetadata, writeTask } from './write.ts';
10
+ import type { TaskOperationSummary, TaskWriteOptions } from './write.ts';
11
+
12
+ type QualificationConfirmationRequest = {
13
+ taskRef: string;
14
+ constraintId: string;
15
+ expectedDigest: string;
16
+ rationale: string;
17
+ operation?: 'confirm' | 'supersede' | 'revoke';
18
+ dryRun?: boolean;
19
+ };
20
+ type QualificationConfirmationResult = {
21
+ status: 'planned' | 'applied' | 'no-op' | 'failed';
22
+ changed: boolean;
23
+ taskId: string | null;
24
+ qcrId: string | null;
25
+ requestId: string | null;
26
+ operations: readonly TaskOperationSummary[];
27
+ error: { code: string; message: string } | null;
28
+ };
29
+
30
+ function failed(code: string, message: string, taskId: string | null = null): QualificationConfirmationResult {
31
+ return { status: 'failed', changed: false, taskId, qcrId: null, requestId: null, operations: [], error: { code, message } };
32
+ }
33
+
34
+ function nextQcrId(content: string): string {
35
+ let max = 0;
36
+ for (const match of content.matchAll(/^\|\s*(QCR-(\d+))\s*\|/gm)) max = Math.max(max, Number(match[2]));
37
+ return `QCR-${max + 1}`;
38
+ }
39
+
40
+ function requestIdFor(taskId: string, constraintId: string, expectedDigest: string, rationale: string, timestamp: string): string {
41
+ const hash = createHash('sha256').update(JSON.stringify([taskId, constraintId, expectedDigest, rationale, timestamp])).digest('hex');
42
+ return `QCR-REQUEST-${hash.slice(0, 20)}`;
43
+ }
44
+
45
+ function renderConfirmations(rows: readonly QualificationConfirmation[]): string {
46
+ return [
47
+ `| ${CONFIRMATION_COLUMNS.join(' | ')} |`,
48
+ `| ${CONFIRMATION_COLUMNS.map(() => '---').join(' | ')} |`,
49
+ ...rows.map((row) => [row.qcrId, row.constraintId, row.actor, row.entrypoint, row.requestId, row.approvedDigest, row.confirmedAt, row.rationale]
50
+ .map((value) => value.replace(/\\/g, '\\\\').replace(/\|/g, '\\|').replace(/[\r\n]/g, ' '))
51
+ .join(' | ')).map((line) => `| ${line} |`)
52
+ ].join('\n');
53
+ }
54
+
55
+ function applyQualificationConfirmation(request: QualificationConfirmationRequest, options: TaskWriteOptions = {}): QualificationConfirmationResult {
56
+ if (!request || typeof request !== 'object' || !request.taskRef || !/^C-[1-9]\d*$/.test(request.constraintId) || !/^[a-f0-9]{64}$/i.test(request.expectedDigest) || !request.rationale?.trim() || /[\r\n]/.test(request.rationale)) {
57
+ return failed('QUALIFICATION_CONFIRMATION_INVALID', 'taskRef, constraintId, expectedDigest, and a single-line rationale are required');
58
+ }
59
+ const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
60
+ if (!resolved.ok) return failed(resolved.code, resolved.message, resolved.taskId);
61
+ if (resolved.state !== 'active') return failed('TASK_STATE_MISMATCH', `task ${resolved.taskId} is ${resolved.state}, expected active`, resolved.taskId);
62
+ let content: string;
63
+ try { content = fs.readFileSync(resolved.taskMdPath, 'utf8'); }
64
+ catch (error) { return failed('TASK_READ_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId); }
65
+ const parsed = parseTaskQualification(content);
66
+ if (!parsed.ok) return failed(parsed.code, parsed.message, resolved.taskId);
67
+ if (!parsed.qualification.present) return failed('QUALIFICATION_TASK_CONTRACT_MISSING', 'task qualification contract is missing', resolved.taskId);
68
+ const constraint = parsed.qualification.constraints.find((row) => row.constraintId === request.constraintId);
69
+ if (!constraint) return failed('QUALIFICATION_CONSTRAINT_UNKNOWN', `unknown constraint '${request.constraintId}'`, resolved.taskId);
70
+ const operation = request.operation ?? 'confirm';
71
+ const existing = parseQualificationConfirmations(content);
72
+ if (!existing.ok) return failed(existing.code, existing.message, resolved.taskId);
73
+ const previous = existing.confirmations.find((row) => row.qcrId === constraint.approvalEvidence);
74
+ if (operation === 'confirm' && constraint.status === 'confirmed') {
75
+ if (previous?.constraintId === constraint.constraintId && previous.approvedDigest === constraint.digest && previous.rationale === request.rationale.trim()) {
76
+ return { status: 'no-op', changed: false, taskId: resolved.taskId, qcrId: previous.qcrId, requestId: previous.requestId, operations: [], error: null };
77
+ }
78
+ return failed('QUALIFICATION_CONFIRMATION_CONFLICT', `constraint '${request.constraintId}' is already confirmed with different evidence`, resolved.taskId);
79
+ }
80
+ const transitionStatus = operation === 'supersede' ? 'superseded' : 'open';
81
+ if (operation !== 'confirm' && constraint.status === transitionStatus && !constraint.approvalEvidence) {
82
+ return { status: 'no-op', changed: false, taskId: resolved.taskId, qcrId: null, requestId: null, operations: [], error: null };
83
+ }
84
+ if (operation !== 'confirm' && constraint.status !== 'confirmed') return failed('QUALIFICATION_CONFIRMATION_REQUIRED', `constraint '${request.constraintId}' is not confirmed`, resolved.taskId);
85
+ if (parsed.qualification.constraintDigest !== request.expectedDigest) return failed('QUALIFICATION_DIGEST_CONFLICT', 'constraint digest changed before human confirmation', resolved.taskId);
86
+ let metadata;
87
+ try { metadata = (options.metadataProvider ?? captureTaskWriteMetadata)(); }
88
+ catch (error) { return failed('METADATA_CAPTURE_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId); }
89
+ const qcrId = operation === 'confirm' ? nextQcrId(content) : null;
90
+ const requestId = operation === 'confirm' ? requestIdFor(resolved.taskId, request.constraintId, request.expectedDigest, request.rationale.trim(), metadata.timestamp) : null;
91
+ const confirmedConstraint = qcrId ? {
92
+ constraintId: constraint.constraintId, statement: constraint.statement, status: 'confirmed' as const,
93
+ authority: 'human-declared', source: constraint.source, evidence: constraint.evidence,
94
+ derivedFrom: constraint.derivedFrom, approvalEvidence: qcrId
95
+ } : null;
96
+ const confirmation = confirmedConstraint && qcrId && requestId ? {
97
+ qcrId, constraintId: request.constraintId, actor: 'human-declared' as const, entrypoint: 'task-qualification' as const,
98
+ requestId, approvedDigest: constraintDigest(confirmedConstraint), confirmedAt: metadata.timestamp, rationale: request.rationale.trim()
99
+ } : null;
100
+ const confirmations = confirmation ? [...existing.confirmations, confirmation] : existing.confirmations;
101
+ const activity = locateActivityLog(content);
102
+ if (!activity) return failed('QUALIFICATION_ACTIVITY_MISSING', 'task has no unique Activity Log section', resolved.taskId);
103
+ const mutations: Parameters<typeof writeTask>[0]['mutations'][number][] = [
104
+ {
105
+ kind: 'table-row', action: 'upsert', sectionAliases: ['约束', 'Constraints'], columns: ['constraint_id', 'statement', 'status', 'authority', 'source', 'evidence', 'derived_from', 'approval_evidence'], keyColumn: 'constraint_id', key: constraint.constraintId,
106
+ values: { statement: constraint.statement, status: operation === 'confirm' ? 'confirmed' : transitionStatus, authority: operation === 'confirm' ? 'human-declared' : constraint.authority, source: constraint.source, evidence: constraint.evidence, derived_from: constraint.derivedFrom.join(','), approval_evidence: qcrId ?? '' }
107
+ },
108
+ ...(operation === 'confirm' ? [{ kind: 'section' as const, aliases: CONFIRMATION_HEADINGS, heading: findSectionHeading(content, [...CONFIRMATION_HEADINGS]), body: renderConfirmations(confirmations) }] : []),
109
+ { kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: activity.heading, body: appendActivityEntry(activity, { time: metadata.timestamp, step: 'Qualification Confirmation', agent: 'human', note: operation === 'confirm' ? `${request.constraintId} confirmed → ${qcrId}` : `${request.constraintId} ${operation}d` }) }
110
+ ];
111
+ const result = writeTask({ taskRef: resolved.taskId, expectedState: 'active', mutations, dryRun: request.dryRun }, { ...options, taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: resolved.state }, metadataProvider: () => metadata });
112
+ if (result.status === 'failed') return failed(result.error.code, result.error.message, result.taskId);
113
+ return { status: result.status, changed: result.changed, taskId: result.taskId, qcrId, requestId, operations: result.operations, error: null };
114
+ }
115
+
116
+ export { applyQualificationConfirmation };
117
+ export type { QualificationConfirmationRequest, QualificationConfirmationResult };
@@ -0,0 +1,150 @@
1
+ import fs from 'node:fs';
2
+
3
+ import { CONSTRAINT_COLUMNS, CANDIDATE_COLUMNS, parseTaskQualification } from './qualification-audit.ts';
4
+ import type { CandidateStatus, ConstraintStatus } from './qualification-audit.ts';
5
+ import { resolveTaskRef } from './resolve-ref.ts';
6
+ import { captureTaskWriteMetadata, writeTask } from './write.ts';
7
+ import type { TaskOperationSummary, TaskWriteOptions } from './write.ts';
8
+
9
+ type QualificationConstraintProposal = {
10
+ constraintId: string;
11
+ statement: string;
12
+ status: Exclude<ConstraintStatus, 'confirmed'>;
13
+ authority: string;
14
+ source: string;
15
+ evidence: string;
16
+ derivedFrom: readonly string[];
17
+ approvalEvidence: string;
18
+ };
19
+ type QualificationCandidateProposal = {
20
+ candidateId: string;
21
+ statement: string;
22
+ status: Extract<CandidateStatus, 'pending'>;
23
+ constraintIds: readonly string[];
24
+ impact: string;
25
+ evidence: string;
26
+ };
27
+ type QualificationProposalRequest = {
28
+ taskRef: string;
29
+ expectedTaskInputDigest: string;
30
+ constraints?: readonly QualificationConstraintProposal[];
31
+ candidates?: readonly QualificationCandidateProposal[];
32
+ dryRun?: boolean;
33
+ };
34
+ type QualificationProposalResult = {
35
+ status: 'planned' | 'applied' | 'no-op' | 'failed';
36
+ changed: boolean;
37
+ taskId: string | null;
38
+ operations: readonly TaskOperationSummary[];
39
+ error: { code: string; message: string } | null;
40
+ };
41
+
42
+ function failed(code: string, message: string, taskId: string | null = null): QualificationProposalResult {
43
+ return { status: 'failed', changed: false, taskId, operations: [], error: { code, message } };
44
+ }
45
+
46
+ function validSingleLine(value: unknown): value is string {
47
+ return typeof value === 'string' && Boolean(value.trim()) && !/[\r\n]/.test(value);
48
+ }
49
+
50
+ function assertProposalKeys(value: unknown, keys: readonly string[], label: string): Record<string, unknown> {
51
+ if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error(`${label} must be an object`);
52
+ const record = value as Record<string, unknown>;
53
+ const unexpected = Object.keys(record).find((key) => !keys.includes(key));
54
+ if (unexpected) throw new Error(`${label} does not accept '${unexpected}'`);
55
+ return record;
56
+ }
57
+
58
+ function parseConstraintProposal(value: unknown): QualificationConstraintProposal {
59
+ const row = assertProposalKeys(value, ['constraintId', 'statement', 'status', 'authority', 'source', 'evidence', 'derivedFrom', 'approvalEvidence'], 'constraint proposal');
60
+ for (const key of ['constraintId', 'statement', 'status', 'authority', 'source', 'evidence', 'approvalEvidence']) {
61
+ if (typeof row[key] !== 'string' || /[\r\n]/.test(row[key] as string)) throw new Error(`constraint proposal '${key}' must be a single-line string`);
62
+ }
63
+ if (!/^C-[1-9]\d*$/.test(row.constraintId as string)) throw new Error(`constraint proposal id '${row.constraintId as string}' is invalid`);
64
+ if (row.status === 'confirmed' || !['derived', 'assumption', 'open', 'conflicted', 'superseded'].includes(row.status as string)) throw new Error('proposal cannot write confirmed constraint status');
65
+ if ((row.approvalEvidence as string) !== '') throw new Error('proposal cannot write approval_evidence');
66
+ if (!Array.isArray(row.derivedFrom) || row.derivedFrom.some((item) => typeof item !== 'string' || !/^C-[1-9]\d*$/.test(item))) throw new Error('constraint proposal derivedFrom is invalid');
67
+ return {
68
+ constraintId: row.constraintId as string, statement: row.statement as string, status: row.status as Exclude<ConstraintStatus, 'confirmed'>,
69
+ authority: row.authority as string, source: row.source as string, evidence: row.evidence as string,
70
+ derivedFrom: [...row.derivedFrom as string[]], approvalEvidence: ''
71
+ };
72
+ }
73
+
74
+ function parseCandidateProposal(value: unknown): QualificationCandidateProposal {
75
+ const row = assertProposalKeys(value, ['candidateId', 'statement', 'status', 'constraintIds', 'impact', 'evidence'], 'candidate proposal');
76
+ for (const key of ['candidateId', 'statement', 'status', 'impact', 'evidence']) if (!validSingleLine(row[key])) throw new Error(`candidate proposal '${key}' must be a non-empty single-line string`);
77
+ if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(row.candidateId as string)) throw new Error(`candidate proposal id '${row.candidateId as string}' is invalid`);
78
+ if (row.status !== 'pending') throw new Error('proposal can only write pending candidate status');
79
+ if (!Array.isArray(row.constraintIds) || row.constraintIds.some((item) => typeof item !== 'string' || !/^C-[1-9]\d*$/.test(item))) throw new Error('candidate proposal constraintIds is invalid');
80
+ return row as unknown as QualificationCandidateProposal;
81
+ }
82
+
83
+ function proposalValues(request: QualificationProposalRequest): { constraints: QualificationConstraintProposal[]; candidates: QualificationCandidateProposal[] } {
84
+ if (!/^[a-f0-9]{64}$/i.test(request.expectedTaskInputDigest)) throw new Error('expectedTaskInputDigest must be a sha256 digest');
85
+ if (Object.keys(request).some((key) => !['taskRef', 'expectedTaskInputDigest', 'constraints', 'candidates', 'dryRun'].includes(key))) throw new Error('proposal contains an unsupported field');
86
+ if (!Array.isArray(request.constraints) && request.constraints !== undefined) throw new Error('constraints must be an array');
87
+ if (!Array.isArray(request.candidates) && request.candidates !== undefined) throw new Error('candidates must be an array');
88
+ return {
89
+ constraints: (request.constraints ?? []).map(parseConstraintProposal),
90
+ candidates: (request.candidates ?? []).map(parseCandidateProposal)
91
+ };
92
+ }
93
+
94
+ function applyQualificationProposal(request: QualificationProposalRequest, options: TaskWriteOptions = {}): QualificationProposalResult {
95
+ if (!request || typeof request !== 'object' || !validSingleLine(request.taskRef)) return failed('QUALIFICATION_PROPOSAL_INVALID', 'taskRef is required');
96
+ let values: ReturnType<typeof proposalValues>;
97
+ try { values = proposalValues(request); }
98
+ catch (error) { return failed('QUALIFICATION_PROPOSAL_INVALID', error instanceof Error ? error.message : String(error)); }
99
+ if (values.constraints.length === 0 && values.candidates.length === 0) return failed('QUALIFICATION_PROPOSAL_INVALID', 'proposal must contain a constraint or candidate');
100
+ const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
101
+ if (!resolved.ok) return failed(resolved.code, resolved.message, resolved.taskId);
102
+ if (resolved.state !== 'active') return failed('TASK_STATE_MISMATCH', `task ${resolved.taskId} is ${resolved.state}, expected active`, resolved.taskId);
103
+ let content: string;
104
+ try { content = fs.readFileSync(resolved.taskMdPath, 'utf8'); }
105
+ catch (error) { return failed('TASK_READ_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId); }
106
+ const parsed = parseTaskQualification(content);
107
+ if (!parsed.ok) return failed(parsed.code, parsed.message, resolved.taskId);
108
+ if (!parsed.qualification.present) return failed('QUALIFICATION_TASK_CONTRACT_MISSING', 'task qualification contract is missing', resolved.taskId);
109
+ const currentConstraintMap = new Map(parsed.qualification.constraints.map((row) => [row.constraintId, row]));
110
+ const currentCandidateMap = new Map(parsed.qualification.candidates.map((row) => [row.candidateId, row]));
111
+ const proposalAlreadyApplied = values.constraints.every((row) => {
112
+ const current = currentConstraintMap.get(row.constraintId);
113
+ return current && current.statement === row.statement && current.status === row.status && current.authority === row.authority
114
+ && current.source === row.source && current.evidence === row.evidence && current.derivedFrom.join(',') === row.derivedFrom.join(',') && current.approvalEvidence === '';
115
+ }) && values.candidates.every((row) => {
116
+ const current = currentCandidateMap.get(row.candidateId);
117
+ return current && current.statement === row.statement && current.status === row.status && current.constraintIds.join(',') === row.constraintIds.join(',')
118
+ && current.impact === row.impact && current.evidence === row.evidence;
119
+ });
120
+ if (parsed.qualification.taskInputDigest !== request.expectedTaskInputDigest) {
121
+ return proposalAlreadyApplied
122
+ ? { status: 'no-op', changed: false, taskId: resolved.taskId, operations: [], error: null }
123
+ : failed('QUALIFICATION_DIGEST_CONFLICT', 'task qualification input changed before proposal was applied', resolved.taskId);
124
+ }
125
+ for (const row of values.constraints) {
126
+ const current = currentConstraintMap.get(row.constraintId);
127
+ if (current?.status === 'confirmed') return failed('QUALIFICATION_CONFIRMATION_REQUIRED', `confirmed constraint '${row.constraintId}' must be superseded or revoked through task-qualification`, resolved.taskId);
128
+ }
129
+ const knownConstraintIds = new Set([...parsed.qualification.constraints.map((row) => row.constraintId), ...values.constraints.map((row) => row.constraintId)]);
130
+ for (const row of values.constraints) for (const parent of row.derivedFrom) if (!knownConstraintIds.has(parent)) return failed('QUALIFICATION_CONSTRAINT_UNKNOWN', `constraint proposal '${row.constraintId}' references unknown '${parent}'`, resolved.taskId);
131
+ for (const row of values.candidates) for (const id of row.constraintIds) if (!knownConstraintIds.has(id)) return failed('QUALIFICATION_CONSTRAINT_UNKNOWN', `candidate proposal '${row.candidateId}' references unknown '${id}'`, resolved.taskId);
132
+ const mutations: Parameters<typeof writeTask>[0]['mutations'][number][] = [];
133
+ for (const row of values.constraints) {
134
+ mutations.push({ kind: 'table-row', action: 'upsert', sectionAliases: ['约束', 'Constraints'], columns: CONSTRAINT_COLUMNS, keyColumn: 'constraint_id', key: row.constraintId, values: { statement: row.statement, status: row.status, authority: row.authority, source: row.source, evidence: row.evidence, derived_from: row.derivedFrom.join(','), approval_evidence: '' } });
135
+ }
136
+ for (const row of values.candidates) {
137
+ mutations.push({ kind: 'table-row', action: 'upsert', sectionAliases: ['候选与否决方案', 'Candidate and Rejected Options', 'Candidates and Rejected Options', 'Candidates and Rejected Alternatives'], columns: CANDIDATE_COLUMNS, keyColumn: 'candidate_id', key: row.candidateId, values: { statement: row.statement, status: row.status, constraint_ids: row.constraintIds.join(','), impact: row.impact, evidence: row.evidence } });
138
+ }
139
+ // Only the submitted rows are mutated; no actor, confirmation, or QCR fields
140
+ // can be smuggled into this internal proposal operation.
141
+ let metadata;
142
+ try { metadata = (options.metadataProvider ?? captureTaskWriteMetadata)(); }
143
+ catch (error) { return failed('METADATA_CAPTURE_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId); }
144
+ const result = writeTask({ taskRef: resolved.taskId, expectedState: 'active', mutations, dryRun: request.dryRun }, { ...options, taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: resolved.state }, metadataProvider: () => metadata });
145
+ if (result.status === 'failed') return failed(result.error.code, result.error.message, result.taskId);
146
+ return { status: result.status, changed: result.changed, taskId: result.taskId, operations: result.operations, error: null };
147
+ }
148
+
149
+ export { applyQualificationProposal };
150
+ export type { QualificationCandidateProposal, QualificationConstraintProposal, QualificationProposalRequest, QualificationProposalResult };
@@ -1,6 +1,8 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
 
4
+ import { scanVisibleMarkdown } from './markdown.ts';
5
+
4
6
  type ReviewFindingCounts = {
5
7
  blocker: number;
6
8
  major: number;
@@ -51,23 +53,6 @@ function escapeRegExp(value: string): string {
51
53
  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
52
54
  }
53
55
 
54
- function maxRound(entries: string[], stem: string): number {
55
- let max = 0;
56
- for (const entry of entries) {
57
- if (entry === `${stem}.md`) {
58
- max = Math.max(max, 1);
59
- continue;
60
- }
61
- const match = entry.match(new RegExp(`^${escapeRegExp(stem)}-r(\\d+)\\.md$`));
62
- if (match) max = Math.max(max, Number(match[1]));
63
- }
64
- return max;
65
- }
66
-
67
- function artifactName(stem: string, round: number): string {
68
- return round === 1 ? `${stem}.md` : `${stem}-r${round}.md`;
69
- }
70
-
71
56
  function normalizeVerdict(raw: unknown): ReviewVerdict | '' {
72
57
  const value = String(raw).trim().toLowerCase();
73
58
  if (value === '通过' || value === 'approved') return 'Approved';
@@ -77,29 +62,21 @@ function normalizeVerdict(raw: unknown): ReviewVerdict | '' {
77
62
  }
78
63
 
79
64
  function extractSection(content: string, names: string[]): string {
80
- const lines = content.split(/\r?\n/);
81
65
  const nameSet = new Set(names);
82
- const start = lines.findIndex((line) => {
83
- const match = line.trim().match(/^##\s+(.+?)\s*$/);
84
- return match ? nameSet.has(match[1]!) : false;
85
- });
86
- if (start === -1) return '';
87
- const sectionLines = [];
88
- for (let index = start + 1; index < lines.length; index += 1) {
89
- if (/^##\s+/.test(lines[index]!)) break;
90
- sectionLines.push(lines[index]);
91
- }
92
- return sectionLines.join('\n');
66
+ const scanned = scanVisibleMarkdown(content);
67
+ const heading = scanned.headings.find((item) => item.level === 2 && nameSet.has(item.text));
68
+ if (!heading) return '';
69
+ const next = scanned.headings.find((item) => item.start > heading.start && item.level <= 2);
70
+ return content.slice(heading.end, next?.start ?? content.length);
93
71
  }
94
72
 
95
73
  function summaryBounds(content: string): { start: number; end: number } | null {
96
- const headings = [...content.matchAll(/^##\s+(.+?)\s*$/gm)]
97
- .map((match) => ({ index: match.index, end: match.index + match[0].length, name: match[1]! }));
98
- const summaries = headings.filter((heading) => SUMMARY_HEADINGS.has(heading.name));
74
+ const scanned = scanVisibleMarkdown(content);
75
+ const summaries = scanned.headings.filter((heading) => heading.level === 2 && SUMMARY_HEADINGS.has(heading.text));
99
76
  if (summaries.length !== 1) return null;
100
77
  const summary = summaries[0]!;
101
- const next = headings.find((heading) => heading.index > summary.index);
102
- return { start: summary.end, end: next?.index ?? content.length };
78
+ const next = scanned.headings.find((heading) => heading.start > summary.start && heading.level <= 2);
79
+ return { start: summary.end, end: next?.start ?? content.length };
103
80
  }
104
81
 
105
82
  function uniqueLine(
@@ -107,14 +84,19 @@ function uniqueLine(
107
84
  bounds: { start: number; end: number },
108
85
  pattern: RegExp
109
86
  ): { value: string; start: number; end: number } | null {
110
- const section = content.slice(bounds.start, bounds.end);
111
- const matches = [...section.matchAll(pattern)];
87
+ const matches: Array<{ value: string; index: number; length: number }> = [];
88
+ for (const line of scanVisibleMarkdown(content).lines) {
89
+ if (line.start < bounds.start || line.start >= bounds.end) continue;
90
+ pattern.lastIndex = 0;
91
+ const match = pattern.exec(line.text);
92
+ if (match) matches.push({ value: match[1]!, index: line.start + match.index, length: match[0].length });
93
+ }
112
94
  if (matches.length !== 1) return null;
113
95
  const match = matches[0]!;
114
96
  return {
115
- value: match[1]!,
116
- start: bounds.start + match.index,
117
- end: bounds.start + match.index + match[0].length
97
+ value: match.value,
98
+ start: match.index,
99
+ end: match.index + match.length
118
100
  };
119
101
  }
120
102
 
@@ -261,12 +243,10 @@ function parseVerdict(reviewPath: string): PathVerdictResult {
261
243
  }
262
244
 
263
245
  export {
264
- artifactName,
265
246
  equalCounts,
266
247
  escapeRegExp,
267
248
  extractSection,
268
249
  finalizeReviewSummaryContent,
269
- maxRound,
270
250
  normalizeVerdict,
271
251
  parseReviewSummary,
272
252
  parseVerdict,
@@ -0,0 +1,23 @@
1
+ import type { ReviewFinalizationRequest } from './review-finalization.ts';
2
+
3
+ export function parseReviewCommand(args: readonly string[]): ReviewFinalizationRequest & {
4
+ overrideTicket?: string; overrideTarget?: string; overrideScope?: string;
5
+ } {
6
+ if (!args[0] || args[1] !== 'finalize-summary') throw new Error('task ref and finalize-summary are required');
7
+ const values: Record<string, string | boolean> = {};
8
+ const flags = {
9
+ '--stage': 'stage', '--artifact': 'artifact', '--orchestrated': 'orchestrated', '--dry-run': 'dryRun',
10
+ '--override-ticket': 'overrideTicket', '--override-target': 'overrideTarget', '--override-scope': 'overrideScope'
11
+ } as const;
12
+ for (let index = 2; index < args.length; index += 1) {
13
+ const flag = args[index]!;
14
+ if (!Object.hasOwn(flags, flag)) throw new Error(`unknown option '${flag}'`);
15
+ const key = flags[flag as keyof typeof flags];
16
+ if (Object.hasOwn(values, key)) throw new Error(`duplicate option '${flag}'`);
17
+ const value = flag === '--orchestrated' || flag === '--dry-run' ? true : args[++index];
18
+ if (!value || typeof value === 'string' && value.startsWith('--')) throw new Error(`option '${flag}' requires a value`);
19
+ values[key] = value;
20
+ }
21
+ if (!values.stage || !values.artifact) throw new Error("options '--stage' and '--artifact' are required");
22
+ return { taskRef: args[0], ...values } as ReturnType<typeof parseReviewCommand>;
23
+ }