@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,474 @@
1
+ import fs from 'node:fs';
2
+ import { parseArtifactName } from './artifact-name.js';
3
+ import path from 'node:path';
4
+ import { createHash } from 'node:crypto';
5
+ import { readStableFileSync } from '../host-control/secure-fs.js';
6
+ import { scanVisibleMarkdown } from './markdown.js';
7
+ import { hasOpenArtifactRound } from './artifact-lifecycle.js';
8
+ import { readArtifactRepairIntent } from './artifact-repair-intent.js';
9
+ import { resolveTaskRef } from './resolve-ref.js';
10
+ import { getArtifactSchema, renderArtifactSkeleton } from './artifact-schema.js';
11
+ import { withTaskExecutionLock } from './task-execution-lock.js';
12
+ function sha256Content(content) {
13
+ return createHash('sha256').update(content, 'utf8').digest('hex');
14
+ }
15
+ function lineNumber(content, offset) {
16
+ return content.slice(0, offset).split('\n').length;
17
+ }
18
+ function markerPattern(marker) {
19
+ return new RegExp(`<!--\\s*${escapeRegExp(marker)}\\s*-->`);
20
+ }
21
+ function escapeRegExp(value) {
22
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
23
+ }
24
+ function markerEntries(content, scanned) {
25
+ const entries = [];
26
+ for (const line of scanned.lines) {
27
+ const match = line.text.match(/<!--\s*(artifact-section:[^\s>]+)\s*-->/g);
28
+ if (!match)
29
+ continue;
30
+ for (const raw of match) {
31
+ const marker = raw.match(/artifact-section:[^\s>]+/)[0];
32
+ const offset = line.text.indexOf(raw);
33
+ entries.push({
34
+ marker,
35
+ start: line.start + offset,
36
+ end: line.start + offset + raw.length,
37
+ line: lineNumber(content, line.start),
38
+ standalone: line.text.trim() === raw
39
+ });
40
+ }
41
+ }
42
+ return entries;
43
+ }
44
+ function sectionBodyBounds(content, heading, scanned) {
45
+ const next = scanned.headings.find((candidate) => candidate.start > heading.start && candidate.level <= 2);
46
+ return { start: heading.end, end: next?.start ?? content.length };
47
+ }
48
+ function stripHtmlComments(content) {
49
+ let result = '';
50
+ let cursor = 0;
51
+ while (cursor < content.length) {
52
+ const start = content.indexOf('<!--', cursor);
53
+ if (start < 0)
54
+ return result + content.slice(cursor);
55
+ result += content.slice(cursor, start);
56
+ const end = content.indexOf('-->', start + 4);
57
+ if (end < 0)
58
+ return result;
59
+ cursor = end + 3;
60
+ }
61
+ return result;
62
+ }
63
+ function diagnostic(code, message, sectionId, line, repairable = false, operation) {
64
+ return {
65
+ code, message, sectionId, line, repairable,
66
+ ...(operation ? { operation } : {})
67
+ };
68
+ }
69
+ function sectionHeadings(schema, section) {
70
+ return [section.headings.zh, section.headings.en];
71
+ }
72
+ function createHeadingRepair(content, section, heading) {
73
+ const to = heading.text.slice(0, -1);
74
+ return {
75
+ kind: 'replace-line',
76
+ sectionId: section.id,
77
+ line: lineNumber(content, heading.start),
78
+ from: heading.text,
79
+ to,
80
+ start: heading.start,
81
+ end: heading.end
82
+ };
83
+ }
84
+ function createSectionInsertionRepair(content, section, marker, locale) {
85
+ return {
86
+ kind: 'insert-section',
87
+ sectionId: section.id,
88
+ line: marker.line,
89
+ from: '',
90
+ to: `## ${section.headings[locale === 'en' ? 'en' : 'zh']}\n`,
91
+ start: marker.start,
92
+ end: marker.start
93
+ };
94
+ }
95
+ function applyRepairOperation(content, operation) {
96
+ if (operation.start < 0 || operation.end < operation.start || operation.end > content.length)
97
+ return null;
98
+ if (operation.kind === 'insert-section') {
99
+ if (operation.from !== '' || operation.start !== operation.end || !operation.to)
100
+ return null;
101
+ return `${content.slice(0, operation.start)}${operation.to}${content.slice(operation.end)}`;
102
+ }
103
+ const raw = content.slice(operation.start, operation.end);
104
+ const offset = raw.indexOf(operation.from);
105
+ if (!operation.from || offset < 0 || raw.indexOf(operation.from, offset + operation.from.length) >= 0)
106
+ return null;
107
+ return `${content.slice(0, operation.start)}${raw.slice(0, offset)}${operation.to}${raw.slice(offset + operation.from.length)}${content.slice(operation.end)}`;
108
+ }
109
+ function canonicalContent(content, operation = null) {
110
+ let normalized = content;
111
+ if (operation) {
112
+ normalized = applyRepairOperation(normalized, operation) ?? normalized;
113
+ }
114
+ normalized = normalized.replace(/\r\n/g, '\n');
115
+ normalized = normalized.replace(/^<!--\s*artifact-context:[^\n]+-->\s*\n?/gm, '');
116
+ normalized = normalized.replace(/^\s*<!--\s*artifact-section:[^\n]+-->\s*\n?/gm, '');
117
+ normalized = normalized.replace(/^\s*<!--\s*artifact-slot:empty\s*-->\s*\n?/gm, '');
118
+ return normalized;
119
+ }
120
+ function canonicalSemanticDigest(content, operation = null) {
121
+ return sha256Content(canonicalContent(content, operation));
122
+ }
123
+ function inspectArtifactStructure(content, schema) {
124
+ const diagnostics = [];
125
+ const scanned = scanVisibleMarkdown(content);
126
+ const repairCandidates = [];
127
+ if (!content.trim())
128
+ diagnostics.push(diagnostic('ARTIFACT_EMPTY', 'artifact is empty', null, null));
129
+ if (scanned.hasUnclosedFence)
130
+ diagnostics.push(diagnostic('ARTIFACT_UNCLOSED_FENCE', 'artifact contains an unclosed Markdown fence', null, null));
131
+ const headingsBySection = new Map();
132
+ for (const section of schema.sections) {
133
+ const aliases = sectionHeadings(schema, section);
134
+ const exact = scanned.headings.filter((heading) => heading.level === 2 && aliases.includes(heading.text));
135
+ const punctuated = scanned.headings.filter((heading) => heading.level === 2 && aliases.some((alias) => heading.text === `${alias}:` || heading.text === `${alias}:`));
136
+ headingsBySection.set(section.id, exact.length === 0 && punctuated.length === 1 ? punctuated : exact);
137
+ if (exact.length > 1 || punctuated.length > 0 && exact.length > 0 || punctuated.length > 1) {
138
+ const first = exact[1] ?? punctuated[0] ?? exact[0];
139
+ diagnostics.push(diagnostic('ARTIFACT_DUPLICATE_SECTION', `required section '${aliases[0]}' is duplicated or has an ambiguous punctuation variant`, section.id, first ? lineNumber(content, first.start) : null));
140
+ }
141
+ else if (exact.length === 0 && punctuated.length === 1) {
142
+ repairCandidates.push(createHeadingRepair(content, section, punctuated[0]));
143
+ }
144
+ else if (exact.length === 0) {
145
+ diagnostics.push(diagnostic('ARTIFACT_MISSING_SECTION', `required section '${aliases[0]}' is missing`, section.id, null));
146
+ }
147
+ }
148
+ const markers = markerEntries(content, scanned);
149
+ const englishHeadings = scanned.headings.filter((heading) => heading.level === 2 && schema.sections.some((section) => section.headings.en === heading.text)).length;
150
+ const chineseHeadings = scanned.headings.filter((heading) => heading.level === 2 && schema.sections.some((section) => section.headings.zh === heading.text)).length;
151
+ const locale = englishHeadings > chineseHeadings ? 'en' : 'zh-CN';
152
+ for (const section of schema.sections) {
153
+ const matches = markers.filter((entry) => entry.marker === section.marker);
154
+ if (matches.length === 0) {
155
+ diagnostics.push(diagnostic('ARTIFACT_MARKER_MISSING', `section marker '${section.marker}' is missing`, section.id, null));
156
+ }
157
+ else if (matches.length > 1) {
158
+ diagnostics.push(diagnostic('ARTIFACT_MARKER_DUPLICATE', `section marker '${section.marker}' is duplicated`, section.id, matches[1].line));
159
+ }
160
+ const marker = matches[0];
161
+ const heading = headingsBySection.get(section.id)?.[0];
162
+ if (marker && !marker.standalone) {
163
+ diagnostics.push(diagnostic('ARTIFACT_MARKER_MISMATCH', `section marker '${section.marker}' must occupy its own visible line`, section.id, marker.line));
164
+ }
165
+ if (marker && heading) {
166
+ const bounds = sectionBodyBounds(content, heading, scanned);
167
+ if (marker.start < bounds.start || marker.start >= bounds.end) {
168
+ diagnostics.push(diagnostic('ARTIFACT_MARKER_MISMATCH', `section marker '${section.marker}' is outside its section`, section.id, marker.line));
169
+ }
170
+ const body = stripHtmlComments(content.slice(bounds.start, bounds.end)).trim();
171
+ if (!body)
172
+ diagnostics.push(diagnostic('ARTIFACT_EMPTY_SECTION', `section '${section.headings.zh}' has no semantic body`, section.id, lineNumber(content, heading.start)));
173
+ }
174
+ if (marker && !heading && marker.standalone) {
175
+ const nextHeading = scanned.headings.find((candidate) => candidate.start > marker.start && candidate.level <= 2);
176
+ const body = stripHtmlComments(content.slice(marker.end, nextHeading?.start ?? content.length)).trim();
177
+ if (body && repairCandidates.length === 0) {
178
+ repairCandidates.push(createSectionInsertionRepair(content, section, marker, locale));
179
+ }
180
+ else if (!body) {
181
+ diagnostics.push(diagnostic('ARTIFACT_EMPTY_SECTION', `section '${section.headings.zh}' has no semantic body`, section.id, marker.line));
182
+ }
183
+ }
184
+ }
185
+ for (const marker of markers) {
186
+ if (!schema.sections.some((section) => markerPattern(section.marker).test(`<!-- ${marker.marker} -->`))) {
187
+ diagnostics.push(diagnostic('ARTIFACT_MARKER_MISMATCH', `unknown section marker '${marker.marker}'`, null, marker.line));
188
+ }
189
+ }
190
+ for (const candidate of repairCandidates) {
191
+ if (candidate.kind === 'replace-line') {
192
+ diagnostics.push(diagnostic('ARTIFACT_HEADING_TRAILING_PUNCTUATION', `visible required H2 '${candidate.from}' may be normalized to '${candidate.to}'`, candidate.sectionId, candidate.line, true, candidate));
193
+ continue;
194
+ }
195
+ const missing = diagnostics.findIndex((item) => item.code === 'ARTIFACT_MISSING_SECTION' && item.sectionId === candidate.sectionId);
196
+ if (missing >= 0) {
197
+ const section = schema.sections.find((item) => item.id === candidate.sectionId);
198
+ diagnostics.splice(missing, 1, diagnostic('ARTIFACT_MISSING_SECTION', `required section '${section.headings.zh}' is missing and can be inserted at its unique marker`, candidate.sectionId, candidate.line, true, candidate));
199
+ }
200
+ }
201
+ const orderedHeadings = schema.sections.flatMap((section) => {
202
+ const heading = headingsBySection.get(section.id)?.[0];
203
+ return heading ? [{ section, start: heading.start }] : [];
204
+ });
205
+ if (orderedHeadings.some((item, index) => index > 0 && item.start <= orderedHeadings[index - 1].start)) {
206
+ diagnostics.push(diagnostic('ARTIFACT_SECTION_ORDER_INVALID', 'required sections are not in schema order', null, null));
207
+ }
208
+ const orderedMarkers = schema.sections.flatMap((section) => {
209
+ const marker = markers.find((entry) => entry.marker === section.marker);
210
+ return marker ? [{ section, start: marker.start }] : [];
211
+ });
212
+ if (orderedMarkers.some((item, index) => index > 0 && item.start <= orderedMarkers[index - 1].start)) {
213
+ diagnostics.push(diagnostic('ARTIFACT_SECTION_ORDER_INVALID', 'section markers are not in schema order', null, null));
214
+ }
215
+ const repair = repairCandidates.length === 1 && (diagnostics.length === 0 ||
216
+ (diagnostics.length === 1 && diagnostics[0]?.operation?.kind === repairCandidates[0]?.kind)) ? repairCandidates[0] : null;
217
+ return {
218
+ ok: diagnostics.length === 0,
219
+ family: schema.family,
220
+ semanticDigest: canonicalSemanticDigest(content, repair),
221
+ diagnostics,
222
+ repair
223
+ };
224
+ }
225
+ function inspectArtifactPatterns(content, schema) {
226
+ const diagnostics = schema.requiredPatterns
227
+ .filter((pattern) => !new RegExp(pattern, 'm').test(content))
228
+ .map((pattern) => diagnostic('ARTIFACT_REQUIRED_PATTERN_MISSING', `artifact is missing required pattern '${pattern}'`, null, null));
229
+ return {
230
+ ok: diagnostics.length === 0,
231
+ family: schema.family,
232
+ semanticDigest: canonicalSemanticDigest(content),
233
+ diagnostics,
234
+ repair: null
235
+ };
236
+ }
237
+ function inspectArtifactContract(content, schema) {
238
+ const structure = inspectArtifactStructure(content, schema);
239
+ const patterns = inspectArtifactPatterns(content, schema);
240
+ const diagnostics = [...structure.diagnostics, ...patterns.diagnostics];
241
+ const repair = patterns.diagnostics.length === 0 ? structure.repair : null;
242
+ return {
243
+ ok: diagnostics.length === 0,
244
+ family: schema.family,
245
+ semanticDigest: canonicalSemanticDigest(content, repair),
246
+ diagnostics,
247
+ repair
248
+ };
249
+ }
250
+ function resultFailure(code, message) {
251
+ return { status: 'failed', changed: false, artifactSha256: null, semanticDigest: null, operation: null, error: { code, message } };
252
+ }
253
+ function resultNoOp(content) {
254
+ return {
255
+ status: 'no-op',
256
+ changed: false,
257
+ artifactSha256: sha256Content(content),
258
+ semanticDigest: canonicalSemanticDigest(content),
259
+ operation: null,
260
+ error: null
261
+ };
262
+ }
263
+ function validateRepairContext(request, content) {
264
+ const round = artifactRound(request.family, request.artifact);
265
+ if (round === null)
266
+ return { ok: false, code: 'ARTIFACT_REPAIR_CONTEXT_INVALID', message: 'artifact round is not canonical' };
267
+ const contextPattern = /^<!--\s*artifact-context:([^:\s]+):([^:\s]+):(\d+)\s*-->\s*$/;
268
+ const contexts = scanVisibleMarkdown(content).lines
269
+ .map((line) => line.text.trim().match(contextPattern))
270
+ .filter((match) => match !== null);
271
+ if (contexts.length !== 1
272
+ || contexts[0][1] !== request.taskId
273
+ || contexts[0][2] !== request.family
274
+ || Number(contexts[0][3]) !== round) {
275
+ return { ok: false, code: 'ARTIFACT_REPAIR_CONTEXT_INVALID', message: 'artifact context marker does not match the requested task, family, and round' };
276
+ }
277
+ let taskContent;
278
+ const resolved = resolveTaskRef(request.taskId, { repoRoot: request.repoRoot });
279
+ if (!resolved.ok)
280
+ return { ok: false, code: 'ARTIFACT_REPAIR_CONTEXT_INVALID', message: resolved.message };
281
+ try {
282
+ taskContent = fs.readFileSync(resolved.taskMdPath, 'utf8');
283
+ }
284
+ catch (error) {
285
+ return { ok: false, code: 'ARTIFACT_REPAIR_CONTEXT_INVALID', message: `cannot read task lifecycle context: ${String(error)}` };
286
+ }
287
+ if (!hasOpenArtifactRound(taskContent, request.family, round)) {
288
+ return { ok: false, code: 'ARTIFACT_REPAIR_CONTEXT_INVALID', message: `artifact '${request.artifact}' does not have exactly one matching open started lifecycle event` };
289
+ }
290
+ let intent;
291
+ try {
292
+ intent = readArtifactRepairIntent(request.repoRoot, request.taskId, request.family, request.artifact);
293
+ }
294
+ catch (error) {
295
+ return { ok: false, code: 'ARTIFACT_REPAIR_PROVENANCE_INVALID', message: String(error) };
296
+ }
297
+ if (!intent || intent.state !== 'awaiting-repair') {
298
+ return { ok: false, code: 'ARTIFACT_REPAIR_PROVENANCE_INVALID', message: 'artifact has no awaiting-repair finalization provenance' };
299
+ }
300
+ if (intent.artifactSha256 !== request.expectedSha256 || intent.semanticDigest !== request.expectedSemanticDigest) {
301
+ return { ok: false, code: 'ARTIFACT_REPAIR_PROVENANCE_INVALID', message: 'repair request does not match the current finalization provenance' };
302
+ }
303
+ return { ok: true };
304
+ }
305
+ function artifactRound(family, artifact) {
306
+ const identity = parseArtifactName(artifact);
307
+ return identity?.family === family ? identity.round : null;
308
+ }
309
+ function validateTarget(taskDir, family, artifact) {
310
+ if (path.basename(artifact) !== artifact || artifactRound(family, artifact) === null || !artifact.endsWith('.md'))
311
+ return resultFailure('ARTIFACT_REPAIR_TARGET_INVALID', 'artifact must be a canonical top-level Markdown file');
312
+ if (!/^TASK-\d{8}-\d{6}$/.test(path.basename(path.resolve(taskDir))))
313
+ return resultFailure('ARTIFACT_REPAIR_TARGET_INVALID', 'target directory is not a task directory');
314
+ const target = path.join(taskDir, artifact);
315
+ if (path.dirname(path.resolve(target)) !== path.resolve(taskDir))
316
+ return resultFailure('ARTIFACT_REPAIR_TARGET_INVALID', 'artifact must be inside the current task directory');
317
+ let stat;
318
+ try {
319
+ stat = fs.lstatSync(target);
320
+ }
321
+ catch (error) {
322
+ return resultFailure('ARTIFACT_REPAIR_TARGET_INVALID', `artifact cannot be read: ${String(error)}`);
323
+ }
324
+ if (stat.isSymbolicLink() || !stat.isFile())
325
+ return resultFailure('ARTIFACT_REPAIR_TARGET_INVALID', 'artifact is not a regular file');
326
+ try {
327
+ fs.accessSync(target, fs.constants.R_OK | fs.constants.W_OK);
328
+ }
329
+ catch (error) {
330
+ return resultFailure('ARTIFACT_REPAIR_TARGET_INVALID', `artifact is not readable and writable: ${String(error)}`);
331
+ }
332
+ return { path: target };
333
+ }
334
+ function applyRepairUnlocked(request) {
335
+ const schema = getArtifactSchema(request.family);
336
+ if (!schema)
337
+ return resultFailure('ARTIFACT_FAMILY_UNKNOWN', `unknown artifact family '${request.family}'`);
338
+ const target = validateTarget(request.taskDir, request.family, request.artifact);
339
+ if ('status' in target)
340
+ return target;
341
+ let content;
342
+ try {
343
+ content = readStableFileSync(target.path, { maxBytes: 1024 * 1024 }).bytes.toString('utf8');
344
+ }
345
+ catch (error) {
346
+ return resultFailure('ARTIFACT_REPAIR_TARGET_INVALID', String(error));
347
+ }
348
+ const actualSha256 = sha256Content(content);
349
+ if (actualSha256 !== request.expectedSha256)
350
+ return resultFailure('ARTIFACT_REPAIR_BASELINE_MISMATCH', 'artifact SHA-256 does not match the expected repair baseline');
351
+ const context = validateRepairContext(request, content);
352
+ if (!context.ok)
353
+ return resultFailure(context.code, context.message);
354
+ const inspection = inspectArtifactStructure(content, schema);
355
+ if (!inspection.repair || inspection.diagnostics.length !== 1) {
356
+ return resultFailure('ARTIFACT_REPAIR_UNSAFE', inspection.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ') || 'no deterministic structural repair is available');
357
+ }
358
+ if (inspection.repair.kind !== request.operation.kind
359
+ || inspection.repair.sectionId !== request.operation.sectionId
360
+ || inspection.repair.from !== request.operation.from
361
+ || inspection.repair.to !== request.operation.to
362
+ || inspection.repair.start !== request.operation.start
363
+ || inspection.repair.end !== request.operation.end) {
364
+ return resultFailure('ARTIFACT_REPAIR_OPERATION_MISMATCH', 'repair operation does not match the current artifact structure');
365
+ }
366
+ if (inspection.semanticDigest !== request.expectedSemanticDigest)
367
+ return resultFailure('ARTIFACT_REPAIR_BASELINE_MISMATCH', 'artifact semantic digest does not match the expected repair baseline');
368
+ const transformed = applyRepairOperation(content, inspection.repair);
369
+ if (transformed === null)
370
+ return resultFailure('ARTIFACT_REPAIR_OPERATION_MISMATCH', 'repair operation does not match the current artifact bytes');
371
+ if (transformed === content)
372
+ return resultFailure('ARTIFACT_REPAIR_NO_PROGRESS', 'repair operation produced no byte change');
373
+ const tempPath = path.join(request.taskDir, `.${request.artifact}.repair-${process.pid}-${Date.now()}.tmp`);
374
+ let mode = 0o600;
375
+ try {
376
+ mode = fs.statSync(target.path).mode & 0o777;
377
+ fs.writeFileSync(tempPath, transformed, { encoding: 'utf8', mode, flag: 'wx' });
378
+ const currentStat = fs.lstatSync(target.path);
379
+ if (currentStat.isSymbolicLink() || !currentStat.isFile() || readStableFileSync(target.path, { maxBytes: 1024 * 1024 }).sha256 !== actualSha256) {
380
+ fs.unlinkSync(tempPath);
381
+ return resultFailure('ARTIFACT_REPAIR_CONFLICT', 'artifact changed or was replaced during repair');
382
+ }
383
+ fs.renameSync(tempPath, target.path);
384
+ }
385
+ catch (error) {
386
+ try {
387
+ fs.unlinkSync(tempPath);
388
+ }
389
+ catch { /* preserve primary error */ }
390
+ return resultFailure('ARTIFACT_REPAIR_WRITE_FAILED', String(error));
391
+ }
392
+ return {
393
+ status: 'applied',
394
+ changed: true,
395
+ artifactSha256: sha256Content(transformed),
396
+ semanticDigest: canonicalSemanticDigest(transformed),
397
+ operation: inspection.repair,
398
+ error: null
399
+ };
400
+ }
401
+ function applyArtifactRepair(request) {
402
+ try {
403
+ return withTaskExecutionLock(request.repoRoot, request.taskId, 'task-artifact.repair', () => applyRepairUnlocked(request));
404
+ }
405
+ catch (error) {
406
+ return resultFailure('ARTIFACT_REPAIR_LOCK_FAILED', String(error));
407
+ }
408
+ }
409
+ function initializeArtifactSkeleton(request) {
410
+ const schema = getArtifactSchema(request.family);
411
+ if (!schema)
412
+ return resultFailure('ARTIFACT_FAMILY_UNKNOWN', `unknown artifact family '${request.family}'`);
413
+ if (artifactRound(request.family, request.artifact) === null)
414
+ return resultFailure('ARTIFACT_INIT_TARGET_INVALID', 'artifact must be a canonical top-level Markdown file');
415
+ if (!/^TASK-\d{8}-\d{6}$/.test(path.basename(path.resolve(request.taskDir))) || path.basename(path.resolve(request.taskDir)) !== request.taskId)
416
+ return resultFailure('ARTIFACT_INIT_TARGET_INVALID', 'target directory is not the requested task directory');
417
+ const target = path.join(request.taskDir, request.artifact);
418
+ if (path.dirname(path.resolve(target)) !== path.resolve(request.taskDir))
419
+ return resultFailure('ARTIFACT_INIT_TARGET_INVALID', 'artifact must be inside the current task directory');
420
+ try {
421
+ return withTaskExecutionLock(request.repoRoot, request.taskId, 'task-artifact.init', () => {
422
+ try {
423
+ const existing = fs.lstatSync(target);
424
+ if (existing.isSymbolicLink() || !existing.isFile())
425
+ return resultFailure('ARTIFACT_INIT_TARGET_INVALID', 'artifact target is not a regular file');
426
+ return resultNoOp(readStableFileSync(target, { maxBytes: 1024 * 1024 }).bytes.toString('utf8'));
427
+ }
428
+ catch (error) {
429
+ if (error.code !== 'ENOENT')
430
+ return resultFailure('ARTIFACT_INIT_TARGET_INVALID', String(error));
431
+ }
432
+ const content = renderArtifactSkeleton({
433
+ taskId: request.taskId,
434
+ family: request.family,
435
+ artifact: request.artifact,
436
+ ...(request.locale ? { locale: request.locale } : {})
437
+ });
438
+ const tempPath = path.join(request.taskDir, `.${request.artifact}.init-${process.pid}-${Date.now()}.tmp`);
439
+ try {
440
+ fs.writeFileSync(tempPath, content, { encoding: 'utf8', mode: 0o600, flag: 'wx' });
441
+ try {
442
+ fs.lstatSync(target);
443
+ fs.unlinkSync(tempPath);
444
+ return resultFailure('ARTIFACT_INIT_TARGET_EXISTS', 'artifact was created concurrently');
445
+ }
446
+ catch (error) {
447
+ if (error.code !== 'ENOENT')
448
+ throw error;
449
+ }
450
+ fs.renameSync(tempPath, target);
451
+ }
452
+ catch (error) {
453
+ try {
454
+ fs.unlinkSync(tempPath);
455
+ }
456
+ catch { /* preserve primary error */ }
457
+ return resultFailure('ARTIFACT_INIT_WRITE_FAILED', String(error));
458
+ }
459
+ return {
460
+ status: 'applied',
461
+ changed: true,
462
+ artifactSha256: sha256Content(content),
463
+ semanticDigest: canonicalSemanticDigest(content),
464
+ operation: null,
465
+ error: null
466
+ };
467
+ });
468
+ }
469
+ catch (error) {
470
+ return resultFailure('ARTIFACT_INIT_LOCK_FAILED', String(error));
471
+ }
472
+ }
473
+ export { applyArtifactRepair, canonicalSemanticDigest, initializeArtifactSkeleton, inspectArtifactContract, inspectArtifactPatterns, inspectArtifactStructure, sha256Content };
474
+ //# sourceMappingURL=artifact-operations.js.map
@@ -1,5 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import { createHash } from 'node:crypto';
3
+ import { parseArtifactName } from './artifact-name.js';
3
4
  import { extractSection, findSectionHeading, parseTable } from './sections.js';
4
5
  const RECEIPT_SECTION_ALIASES = ['产物生命周期收据', 'Artifact Lifecycle Receipts'];
5
6
  const RECEIPT_COLUMNS = ['event', 'output', 'input', 'input_sha256', 'completed_at'];
@@ -10,7 +11,6 @@ const RECEIPT_EVENTS = new Set([
10
11
  'code.completed'
11
12
  ]);
12
13
  const SHA256_RE = /^[a-f0-9]{64}$/;
13
- const ARTIFACT_NAME_RE = /^(analysis|review-analysis|plan|review-plan|code|review-code|manual-validation|validation-run|pr-review)(?:-r([2-9]|[1-9]\d+))?\.md$/;
14
14
  const RECEIPT_SHAPES = {
15
15
  'review-analysis.completed': { output: 'review-analysis', input: 'analysis' },
16
16
  'review-plan.completed': { output: 'review-plan', input: 'plan' },
@@ -30,21 +30,9 @@ function sha256Bytes(value) {
30
30
  function sha256File(filePath) {
31
31
  return sha256Bytes(fs.readFileSync(filePath));
32
32
  }
33
- function parseReceiptArtifactName(name) {
34
- const match = ARTIFACT_NAME_RE.exec(name);
35
- if (!match)
36
- return null;
37
- const roundText = match[2];
38
- if (roundText !== undefined) {
39
- const round = Number(roundText);
40
- if (!Number.isSafeInteger(round) || String(round) !== roundText)
41
- return null;
42
- }
43
- return { family: match[1] };
44
- }
45
33
  function validateReceiptShape(event, output, input) {
46
- const outputIdentity = parseReceiptArtifactName(output);
47
- const inputIdentity = parseReceiptArtifactName(input);
34
+ const outputIdentity = parseArtifactName(output);
35
+ const inputIdentity = parseArtifactName(input);
48
36
  if (!outputIdentity || !inputIdentity)
49
37
  throw new ArtifactReceiptError(`receipt artifact identity is invalid: ${output} -> ${input}`);
50
38
  const shape = RECEIPT_SHAPES[event];
@@ -0,0 +1,130 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { isDeepStrictEqual } from 'node:util';
4
+ function intentRoot(repoRoot) {
5
+ return path.join(repoRoot, '.agents', 'workspace', '.local-artifact-finalization-intents');
6
+ }
7
+ function intentPath(repoRoot, taskId, family, artifact) {
8
+ return path.join(intentRoot(repoRoot), `${taskId}-${family}-${artifact}.json`);
9
+ }
10
+ function validDigest(value) {
11
+ return typeof value === 'string' && /^[a-f0-9]{64}$/u.test(value);
12
+ }
13
+ function validTaskId(value) {
14
+ return typeof value === 'string' && /^TASK-\d{8}-\d{6}$/u.test(value);
15
+ }
16
+ function exactKeys(value, keys) {
17
+ return Object.keys(value).sort().join(',') === [...keys].sort().join(',');
18
+ }
19
+ export function isArtifactRepairIntent(value) {
20
+ if (!value || typeof value !== 'object' || Array.isArray(value))
21
+ return false;
22
+ const intent = value;
23
+ return exactKeys(intent, [
24
+ 'artifact', 'artifactSha256', 'authorityDigest', 'baselineSemanticDigest', 'createdAt',
25
+ 'family', 'phase', 'recoveryOperationId', 'requestId', 'semanticDigest', 'state',
26
+ 'taskId', 'updatedAt', 'version'
27
+ ])
28
+ && intent.version === 2
29
+ && validTaskId(intent.taskId)
30
+ && typeof intent.family === 'string'
31
+ && ['analysis', 'review-analysis', 'plan', 'review-plan', 'code', 'review-code'].includes(intent.family)
32
+ && typeof intent.artifact === 'string' && intent.artifact.length > 0
33
+ && ['awaiting-repair', 'finalize-ready', 'commit-started', 'passed', 'consumed'].includes(String(intent.state))
34
+ && (intent.baselineSemanticDigest === null || validDigest(intent.baselineSemanticDigest))
35
+ && validDigest(intent.artifactSha256)
36
+ && validDigest(intent.semanticDigest)
37
+ && (intent.recoveryOperationId === null || (typeof intent.recoveryOperationId === 'string' && /^[a-f0-9-]{16,64}$/u.test(intent.recoveryOperationId)))
38
+ && (intent.phase === null || ['orchestration.prepare', 'artifact.finalize-local', 'task-event.completed'].includes(String(intent.phase)))
39
+ && (intent.authorityDigest === null || validDigest(intent.authorityDigest))
40
+ && typeof intent.requestId === 'string' && intent.requestId.length > 0 && !/[\r\n]/u.test(intent.requestId)
41
+ && Number.isSafeInteger(intent.createdAt) && Number.isSafeInteger(intent.updatedAt)
42
+ && (intent.state === 'awaiting-repair' ? intent.baselineSemanticDigest === intent.semanticDigest : true);
43
+ }
44
+ function readArtifactRepairIntent(repoRoot, taskId, family, artifact) {
45
+ const target = intentPath(repoRoot, taskId, family, artifact);
46
+ if (!fs.existsSync(target))
47
+ return null;
48
+ let value;
49
+ try {
50
+ value = JSON.parse(fs.readFileSync(target, 'utf8'));
51
+ }
52
+ catch (error) {
53
+ throw new Error(`ARTIFACT_REPAIR_INTENT_INVALID: ${String(error)}`);
54
+ }
55
+ if (!isArtifactRepairIntent(value) || value.taskId !== taskId || value.family !== family || value.artifact !== artifact) {
56
+ throw new Error('ARTIFACT_REPAIR_INTENT_INVALID: repair provenance schema is invalid');
57
+ }
58
+ return value;
59
+ }
60
+ export function writeArtifactRepairIntent(repoRoot, value, options = {}) {
61
+ if (!isArtifactRepairIntent(value))
62
+ throw new Error('ARTIFACT_REPAIR_INTENT_INVALID: repair provenance schema is invalid');
63
+ const directory = intentRoot(repoRoot);
64
+ fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
65
+ const target = intentPath(repoRoot, value.taskId, value.family, value.artifact);
66
+ const lock = `${target}.lock`;
67
+ let descriptor;
68
+ try {
69
+ descriptor = fs.openSync(lock, 'wx', 0o600);
70
+ }
71
+ catch (error) {
72
+ if (error.code === 'EEXIST') {
73
+ throw new Error('ARTIFACT_REPAIR_INTENT_CONFLICT: another provenance writer owns the intent');
74
+ }
75
+ throw error;
76
+ }
77
+ try {
78
+ const current = fs.existsSync(target)
79
+ ? readArtifactRepairIntent(repoRoot, value.taskId, value.family, value.artifact)
80
+ : null;
81
+ if (!isDeepStrictEqual(current, options.expected ?? null)) {
82
+ throw new Error('ARTIFACT_REPAIR_INTENT_CONFLICT: repair provenance changed during finalization');
83
+ }
84
+ const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
85
+ fs.writeFileSync(temporary, `${JSON.stringify(value)}\n`, { encoding: 'utf8', mode: 0o600, flag: 'wx' });
86
+ try {
87
+ fs.renameSync(temporary, target);
88
+ }
89
+ catch (error) {
90
+ try {
91
+ fs.unlinkSync(temporary);
92
+ }
93
+ catch { /* preserve primary error */ }
94
+ throw error;
95
+ }
96
+ }
97
+ finally {
98
+ fs.closeSync(descriptor);
99
+ try {
100
+ fs.unlinkSync(lock);
101
+ }
102
+ catch { /* preserve the primary result */ }
103
+ }
104
+ }
105
+ export function findArtifactRepairIntentsByOperation(repoRoot, operationId) {
106
+ if (!operationId || /[\r\n]/u.test(operationId)) {
107
+ throw new Error('ARTIFACT_REPAIR_OPERATION_INVALID: recovery operation id is invalid');
108
+ }
109
+ const directory = intentRoot(repoRoot);
110
+ if (!fs.existsSync(directory))
111
+ return Object.freeze([]);
112
+ return Object.freeze(fs.readdirSync(directory)
113
+ .filter((name) => name.endsWith('.json'))
114
+ .map((name) => {
115
+ const target = path.join(directory, name);
116
+ let value;
117
+ try {
118
+ value = JSON.parse(fs.readFileSync(target, 'utf8'));
119
+ }
120
+ catch (error) {
121
+ throw new Error(`ARTIFACT_REPAIR_INTENT_INVALID: ${String(error)}`);
122
+ }
123
+ if (!isArtifactRepairIntent(value))
124
+ throw new Error('ARTIFACT_REPAIR_INTENT_INVALID: repair provenance schema is invalid');
125
+ return value;
126
+ })
127
+ .filter((value) => value.recoveryOperationId === operationId));
128
+ }
129
+ export { readArtifactRepairIntent };
130
+ //# sourceMappingURL=artifact-repair-intent.js.map