@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,209 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { inspectOwnedPath } from '../owned-path.ts';
4
+ import { parseTaskFrontmatter } from '../task/frontmatter.ts';
5
+ import { readTaskFinalizationReceipt, type TaskFinalizationReceipt } from '../task/finalization.ts';
6
+ import { taskFinalizationReceiptState, type TaskControlBindingEvidence, type TaskControlBinding as SandboxControlBinding } from '../task/finalization-state.ts';
7
+ import { enumerateAllTaskDirs } from '../task/resolve-ref.ts';
8
+ import { resolveSandboxCleanupTarget } from './workspace-identity.ts';
9
+ import { readSandboxControlManifest } from './control/lifecycle.ts';
10
+ import { readJsonFile, readSandboxControlStatus } from './control/state.ts';
11
+ import { finalizationTerminalResponse } from './control/finalization-response.ts';
12
+
13
+ const TASK_ID_RE = /^TASK-\d{8}-\d{6}$/;
14
+
15
+ function matchingControlManifest(repoRoot: string, controlRoot: string, taskId: string, binding: SandboxControlBinding) {
16
+ if (!controlRootIdentity(controlRoot)) return null;
17
+ const manifestPath = path.join(controlRoot, 'manifest.json');
18
+ let manifest;
19
+ try { manifest = readSandboxControlManifest(manifestPath); }
20
+ catch { return null; }
21
+ if (manifest.mode !== 'task-bound' || manifest.taskId !== taskId
22
+ || canonicalPath(manifest.repoRoot) !== repoRoot || manifest.generation !== binding.generation
23
+ || path.resolve(manifest.channelDir) !== path.join(controlRoot, 'channel')
24
+ || path.resolve(manifest.publicStatusDir) !== path.join(controlRoot, 'public')
25
+ || path.resolve(manifest.processingDir) !== path.join(controlRoot, 'processing')
26
+ || path.resolve(manifest.runtimeDir) !== path.join(controlRoot, 'runtime')) return null;
27
+ return manifest;
28
+ }
29
+
30
+ type DirectoryIdentity = Readonly<{ dev: string; ino: string }>;
31
+ type SandboxRemovalJournalEvidence = Readonly<{
32
+ phase: string;
33
+ generation: string;
34
+ target: Readonly<{
35
+ branch: string;
36
+ controlRoot: string;
37
+ }>;
38
+ }>;
39
+
40
+ function errorCode(error: unknown): string | null {
41
+ const code = (error as NodeJS.ErrnoException | null)?.code;
42
+ return typeof code === 'string' ? code : null;
43
+ }
44
+
45
+ function controlBindingKey(taskId: string, binding: SandboxControlBinding): string {
46
+ return `${taskId}\0${binding.generation}\0${binding.requestId}`;
47
+ }
48
+
49
+ function controlRootIdentity(root: string): DirectoryIdentity | null {
50
+ try {
51
+ const stat = fs.lstatSync(root);
52
+ if (!stat.isDirectory() || stat.isSymbolicLink()) return null;
53
+ return { dev: String(stat.dev), ino: String(stat.ino) };
54
+ } catch {
55
+ return null;
56
+ }
57
+ }
58
+
59
+ function controlRootState(
60
+ root: string,
61
+ expected: DirectoryIdentity
62
+ ): 'missing' | 'same' | 'replaced' {
63
+ let stat: fs.Stats;
64
+ try { stat = fs.lstatSync(root); }
65
+ catch (error) { return errorCode(error) === 'ENOENT' ? 'missing' : 'replaced'; }
66
+ if (stat.isSymbolicLink() || !stat.isDirectory()) return 'replaced';
67
+ return String(stat.dev) === expected.dev && String(stat.ino) === expected.ino ? 'same' : 'replaced';
68
+ }
69
+
70
+ function controlRootIsAbsent(root: string): boolean {
71
+ try {
72
+ fs.lstatSync(root);
73
+ return false;
74
+ } catch (error) {
75
+ return errorCode(error) === 'ENOENT';
76
+ }
77
+ }
78
+
79
+ function canonicalPath(input: string): string {
80
+ try { return fs.realpathSync.native(input); }
81
+ catch { return path.resolve(input); }
82
+ }
83
+
84
+ function taskFinalizationReceiptComplete(
85
+ receipt: TaskFinalizationReceipt,
86
+ taskId: string,
87
+ binding: SandboxControlBinding
88
+ ): boolean {
89
+ return receipt.taskId === taskId
90
+ && taskFinalizationReceiptState(receipt) === 'complete'
91
+ && receipt.controlBinding?.generation === binding.generation
92
+ && receipt.controlBinding.requestId === binding.requestId;
93
+ }
94
+
95
+ function terminalControlBindingEvidence(
96
+ repoRootInput: string,
97
+ controlRootInput: string,
98
+ taskId: string,
99
+ binding: SandboxControlBinding
100
+ ): boolean {
101
+ const repoRoot = canonicalPath(repoRootInput);
102
+ const controlRoot = path.resolve(controlRootInput);
103
+ if (!TASK_ID_RE.test(taskId) || !controlRootIdentity(controlRoot)) return false;
104
+ const manifestPath = path.join(controlRoot, 'manifest.json');
105
+ if (!inspectOwnedPath(controlRoot, manifestPath, 'file')) return false;
106
+ const manifest = matchingControlManifest(repoRoot, controlRoot, taskId, binding);
107
+ if (!manifest) return false;
108
+ try {
109
+ const leasePath = path.join(controlRoot, 'lease.json');
110
+ try {
111
+ fs.lstatSync(leasePath);
112
+ return false;
113
+ } catch (error) {
114
+ if (errorCode(error) !== 'ENOENT') return false;
115
+ }
116
+ const receipt = readTaskFinalizationReceipt(repoRoot, taskId);
117
+ if (!receipt || !taskFinalizationReceiptComplete(receipt, taskId, binding)) {
118
+ return false;
119
+ }
120
+ const status = readSandboxControlStatus(manifest.publicStatusDir);
121
+ const viewReceipt = status.taskView.receipt;
122
+ const terminalTaskView = (status.taskView.state === 'current' && status.taskView.observedSource === 'completed')
123
+ || (status.taskView.state === 'finalized-stale' && status.taskView.observedSource === 'active');
124
+ if (status.generation !== binding.generation || status.state !== 'healthy'
125
+ || status.activeRequestId !== null || !terminalTaskView || status.taskView.taskId !== taskId
126
+ || !viewReceipt || viewReceipt.generation !== binding.generation
127
+ || viewReceipt.requestId !== binding.requestId
128
+ || viewReceipt.receiptId !== receipt.receiptId
129
+ || viewReceipt.revision !== receipt.revision) return false;
130
+ const responsePath = path.join(manifest.channelDir, 'responses', `${binding.requestId}.json`);
131
+ if (!inspectOwnedPath(path.join(controlRoot, 'channel'), responsePath, 'file')) return false;
132
+ const actual = readJsonFile(responsePath);
133
+ const expected = finalizationTerminalResponse(taskId, binding.requestId, receipt);
134
+ return JSON.stringify(actual) === JSON.stringify(expected);
135
+ } catch {
136
+ return false;
137
+ }
138
+ }
139
+
140
+ function removedControlBindingEvidence(
141
+ repoRootInput: string,
142
+ journal: SandboxRemovalJournalEvidence,
143
+ taskId: string,
144
+ binding: SandboxControlBinding
145
+ ): boolean {
146
+ const repoRoot = canonicalPath(repoRootInput);
147
+ if (journal.phase !== 'completed'
148
+ || journal.generation !== binding.generation
149
+ || !path.isAbsolute(journal.target.controlRoot)) return false;
150
+ const controlRoot = path.resolve(journal.target.controlRoot);
151
+ if (!controlRootIsAbsent(controlRoot)) return false;
152
+ const task = enumerateAllTaskDirs(repoRoot).find((entry) => entry.taskId === taskId);
153
+ if (!task || (task.state !== 'completed' && task.state !== 'archive')) return false;
154
+ let frontmatter: Record<string, string>;
155
+ try { frontmatter = parseTaskFrontmatter(fs.readFileSync(path.join(task.taskDir, 'task.md'), 'utf8')); }
156
+ catch { return false; }
157
+ if (frontmatter.id !== taskId || frontmatter.branch !== journal.target.branch) return false;
158
+ try {
159
+ const receipt = readTaskFinalizationReceipt(repoRoot, taskId);
160
+ return receipt !== null && taskFinalizationReceiptComplete(receipt, taskId, binding);
161
+ } catch {
162
+ return false;
163
+ }
164
+ }
165
+
166
+ export function createSandboxControlBindingEvidence(
167
+ repoRoot: string,
168
+ controlRoots: readonly string[],
169
+ removalJournals: readonly SandboxRemovalJournalEvidence[] = []
170
+ ): TaskControlBindingEvidence {
171
+ const canonicalRepoRoot = canonicalPath(repoRoot);
172
+ const roots = [...new Set(controlRoots.map((candidate) => path.resolve(candidate)))];
173
+ const captured = roots.flatMap((controlRoot) => {
174
+ let manifest;
175
+ try { manifest = readSandboxControlManifest(path.join(controlRoot, 'manifest.json')); }
176
+ catch { return []; }
177
+ const rootIdentity = controlRootIdentity(controlRoot);
178
+ if (!rootIdentity) return [];
179
+ const receipt = (() => {
180
+ try { return readSandboxControlStatus(manifest.publicStatusDir).taskView.receipt; }
181
+ catch { return null; }
182
+ })();
183
+ if (!receipt || !terminalControlBindingEvidence(canonicalRepoRoot, controlRoot, manifest.taskId ?? '', receipt)) return [];
184
+ return [{
185
+ controlRoot,
186
+ taskId: manifest.taskId!,
187
+ key: controlBindingKey(manifest.taskId!, receipt),
188
+ rootIdentity
189
+ }];
190
+ });
191
+ return (taskId, binding) => {
192
+ const terminal = captured.some((candidate) => {
193
+ if (candidate.taskId !== taskId || candidate.key !== controlBindingKey(taskId, binding)) return false;
194
+ const state = controlRootState(candidate.controlRoot, candidate.rootIdentity);
195
+ return state === 'missing'
196
+ || state === 'same' && terminalControlBindingEvidence(canonicalRepoRoot, candidate.controlRoot, taskId, binding);
197
+ }) || removalJournals.some((journal) => removedControlBindingEvidence(canonicalRepoRoot, journal, taskId, binding));
198
+ if (terminal) return 'terminal';
199
+ if (roots.some((root) => matchingControlManifest(canonicalRepoRoot, root, taskId, binding))) return 'pending';
200
+ try {
201
+ const branch = resolveSandboxCleanupTarget(taskId, canonicalRepoRoot, { allowProtected: true }).branch;
202
+ if (removalJournals.some((journal) => journal.phase !== 'completed'
203
+ && journal.generation === binding.generation && journal.target.branch === branch)) return 'pending';
204
+ } catch {
205
+ // Missing or conflicting task identity cannot authorize removal.
206
+ }
207
+ return 'mismatch';
208
+ };
209
+ }
@@ -3,10 +3,13 @@ import fs from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import type { SandboxWorkspaceIdentity, SandboxWorkspaceKey } from './workspace-identity.ts';
5
5
  import type { SandboxControlManifest } from './control/protocol.ts';
6
+ import {
7
+ createSandboxControlIdentitySentinel,
8
+ writeSandboxControlIdentitySentinel
9
+ } from './control/identity-sentinel.ts';
6
10
 
7
11
  export type SandboxWorkspaceView = Readonly<{
8
12
  root: string;
9
- taskMountPath: string | null;
10
13
  }>;
11
14
 
12
15
  export const SANDBOX_WORKSPACE_VIEW_STATES = Object.freeze([
@@ -38,12 +41,7 @@ export function sandboxWorkspaceViewPaths(params: Readonly<{
38
41
  const digest = createHash('sha256').update(identityKey).digest('hex').slice(0, 16);
39
42
  const projectRoot = path.resolve(params.base, params.project);
40
43
  const root = path.resolve(projectRoot, params.container, digest);
41
- return {
42
- root,
43
- taskMountPath: params.identity.mode === 'task-bound'
44
- ? path.join(root, 'active', params.identity.taskId)
45
- : null
46
- };
44
+ return { root };
47
45
  }
48
46
 
49
47
  export type SandboxControlSetup = Readonly<{
@@ -55,9 +53,10 @@ export type SandboxControlSetup = Readonly<{
55
53
  manifestDraft: SandboxControlManifestDraft;
56
54
  token: string;
57
55
  generation: string;
56
+ controlRootId: string;
58
57
  }>;
59
58
 
60
- export type SandboxControlManifestDraft = Readonly<Omit<SandboxControlManifest, 'containerIdentity' | 'engine'> & {
59
+ export type SandboxControlManifestDraft = Readonly<Omit<SandboxControlManifest, 'containerIdentity' | 'engine' | 'authorityEvidence'> & {
61
60
  engine: string;
62
61
  }>;
63
62
 
@@ -158,7 +157,7 @@ export function materializeSandboxWorkspaceView(params: Readonly<{
158
157
  identity: SandboxWorkspaceIdentity;
159
158
  }>): SandboxWorkspaceView {
160
159
  const projectRoot = path.resolve(params.base, params.project);
161
- const { root, taskMountPath } = sandboxWorkspaceViewPaths(params);
160
+ const { root } = sandboxWorkspaceViewPaths(params);
162
161
  assertSafeDirectory(projectRoot, path.resolve(params.base));
163
162
  assertSafeDirectory(root, projectRoot);
164
163
  fs.mkdirSync(root, { recursive: true, mode: 0o700 });
@@ -179,11 +178,7 @@ export function materializeSandboxWorkspaceView(params: Readonly<{
179
178
  encoding: 'utf8',
180
179
  mode: 0o600
181
180
  });
182
- if (taskMountPath) {
183
- assertSafeDirectory(taskMountPath, active);
184
- fs.mkdirSync(taskMountPath, { recursive: true, mode: 0o700 });
185
- }
186
- return { root, taskMountPath };
181
+ return { root };
187
182
  }
188
183
 
189
184
  export function materializeSandboxControl(params: Readonly<{
@@ -234,6 +229,12 @@ export function materializeSandboxControl(params: Readonly<{
234
229
  }
235
230
  const token = randomBytes(32).toString('hex');
236
231
  const generation = randomBytes(16).toString('hex');
232
+ const identitySentinel = createSandboxControlIdentitySentinel({
233
+ mode: params.identity.mode,
234
+ taskId: params.identity.mode === 'task-bound' ? params.identity.taskId : null,
235
+ generation
236
+ });
237
+ writeSandboxControlIdentitySentinel(statusDir, identitySentinel);
237
238
  const repoRoot = fs.realpathSync.native(params.repoRoot);
238
239
  const manifestDraft: SandboxControlManifestDraft = {
239
240
  engine: params.engine ?? 'docker',
@@ -246,23 +247,30 @@ export function materializeSandboxControl(params: Readonly<{
246
247
  taskId: params.identity.mode === 'task-bound' ? params.identity.taskId : null,
247
248
  token,
248
249
  generation,
250
+ controlRootId: identitySentinel.controlRootId,
249
251
  channelDir,
250
252
  publicStatusDir: statusDir,
251
253
  processingDir,
252
- runtimeDir
254
+ runtimeDir,
253
255
  };
254
- return { root, channelDir, statusDir, runtimeDir, manifestPath, manifestDraft, token, generation };
256
+ return { root, channelDir, statusDir, runtimeDir, manifestPath, manifestDraft, token, generation, controlRootId: identitySentinel.controlRootId };
255
257
  }
256
258
 
257
259
  export function finalizeSandboxControlManifest(
258
260
  setup: SandboxControlSetup,
259
- identity: Readonly<{ engine: string; id: string; labels: Readonly<Record<string, string>> }>
261
+ identity: Readonly<{
262
+ engine: string;
263
+ id: string;
264
+ labels: Readonly<Record<string, string>>;
265
+ authorityEvidence: SandboxControlManifest['authorityEvidence'];
266
+ }>
260
267
  ): SandboxControlManifest {
261
268
  if (!identity.engine || !identity.id) throw new Error('SANDBOX_CONTROL_CONTAINER_ID_INVALID');
262
269
  const manifest: SandboxControlManifest = {
263
270
  ...setup.manifestDraft,
264
271
  engine: identity.engine,
265
- containerIdentity: { id: identity.id, labels: { ...identity.labels } }
272
+ containerIdentity: { id: identity.id, labels: { ...identity.labels } },
273
+ authorityEvidence: identity.authorityEvidence
266
274
  };
267
275
  const temporary = `${setup.manifestPath}.${process.pid}.${randomBytes(8).toString('hex')}.tmp`;
268
276
  try {
@@ -436,7 +436,10 @@ function verifyWorktreePermit(
436
436
  ? inspectRecoveredWorktree(permit.snapshot.worktree, permit.snapshot.recovery, options)
437
437
  : inspectWorktree(permit.snapshot.worktree, options);
438
438
  if (current.status === 'failed') throw new Error(`Unable to verify worktree permit: ${current.message}`);
439
- if (current.snapshot.identity !== permit.snapshot.identity || (permit.mode === 'clean' && current.status !== 'clean')) {
439
+ const sameTarget = current.snapshot.worktree === permit.snapshot.worktree
440
+ && current.snapshot.branch === permit.snapshot.branch;
441
+ if (!sameTarget || (permit.mode === 'clean'
442
+ && (current.snapshot.identity !== permit.snapshot.identity || current.status !== 'clean'))) {
440
443
  throw new Error(`Worktree changed after authorization: ${permit.snapshot.worktree}`);
441
444
  }
442
445
  return current.snapshot;
@@ -1,5 +1,8 @@
1
1
  import { runDaemon } from './daemon.ts';
2
2
  import { start, stop, status, logs } from './process-control.ts';
3
+ import { PUBLIC_CLI_ROUTE_SELECTORS } from '../internal/cli-route-inventory.ts';
4
+
5
+ const SERVER_OPERATIONS = PUBLIC_CLI_ROUTE_SELECTORS.server;
3
6
 
4
7
  const USAGE = `Usage: ai server <command> [options]
5
8
 
@@ -25,6 +28,13 @@ export async function runServer(args: string[]): Promise<void> {
25
28
  return;
26
29
  }
27
30
 
31
+ if (!SERVER_OPERATIONS.includes(subcommand as typeof SERVER_OPERATIONS[number])) {
32
+ process.stderr.write(`Unknown server command: ${subcommand}\n`);
33
+ process.stdout.write(`${USAGE}\n`);
34
+ process.exitCode = 1;
35
+ return;
36
+ }
37
+
28
38
  switch (subcommand) {
29
39
  case 'start':
30
40
  await start({ foreground: rest.includes('--foreground') });
@@ -6,9 +6,9 @@ import { locateActivityLog, appendActivityEntry } from './activity-log.ts';
6
6
  import {
7
7
  assertWritableInventory,
8
8
  buildArtifactLinkSection,
9
- inspectTaskArtifacts,
10
- parseArtifactName
9
+ inspectTaskArtifacts
11
10
  } from './artifact-lifecycle.ts';
11
+ import { parseArtifactName } from './artifact-name.ts';
12
12
  import type { ArtifactIdentity } from './artifact-lifecycle.ts';
13
13
  import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.ts';
14
14
  import type { TaskExecutionLockOptions } from './task-execution-lock.ts';
@@ -1,5 +1,4 @@
1
- const HEADING_RE = /^##\s+(活动日志|Activity Log)\s*$/;
2
- const NEXT_H2_RE = /^##\s/;
1
+ import { scanVisibleMarkdown } from './markdown.ts';
3
2
  const ENTRY_RE = /^- (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}) — \*\*(.+?)\*\* by (.+?) — (.*)$/;
4
3
  const STARTED_SUFFIX_RE = /\s*\[started\]\s*$/;
5
4
  const ABORTED_SUFFIX_RE = /\s*\[aborted\]\s*$/;
@@ -17,24 +16,32 @@ function parseActivityLog(content: string): { sectionFound: boolean; entries: Lo
17
16
  return section ? { sectionFound: true, entries: section.entries } : { sectionFound: false, entries: [] };
18
17
  }
19
18
 
20
- function locateActivityLog(content: string): ActivityLogSection | null {
21
- const lines = content.split('\n');
22
- const headings = lines.map((line, index) => HEADING_RE.test(line) ? index : -1).filter((index) => index >= 0);
23
- if (headings.length !== 1) return null;
24
- const i = headings[0]!;
25
- let end = lines.length;
26
- for (let j = i + 1; j < lines.length; j += 1) {
27
- if (NEXT_H2_RE.test(lines[j]!)) { end = j; break; }
28
- }
29
- const bodyLines = lines.slice(i + 1, end);
30
- const parsed: { entry: LogEntry; epoch: number; order: number }[] = [];
31
- for (const line of bodyLines) {
32
- const m = ENTRY_RE.exec(line);
33
- if (!m) continue;
34
- parsed.push({ entry: { time: m[1]!, step: m[2]!, agent: m[3]!, note: m[4]! }, epoch: Date.parse(m[1]!.replace(' ', 'T')), order: parsed.length });
19
+ /** Returns source-order entries and malformed bullets without applying display or gate policy. */
20
+ function inspectActivityLog(content: string): { section: ActivityLogSection | null; invalidEntries: string[] } {
21
+ const scanned = scanVisibleMarkdown(content);
22
+ const headings = scanned.headings.filter((heading) => heading.level === 2);
23
+ const matches = headings.filter((heading) => heading.text === '活动日志' || heading.text === 'Activity Log');
24
+ if (matches.length !== 1) return { section: null, invalidEntries: [] };
25
+ const heading = matches[0]!;
26
+ const end = headings.find((candidate) => candidate.start > heading.start)?.start ?? content.length;
27
+ const entries: LogEntry[] = [];
28
+ const invalidEntries: string[] = [];
29
+ for (const line of scanned.lines) {
30
+ if (line.start <= heading.end || line.start >= end) continue;
31
+ const text = line.text.trimStart();
32
+ const match = ENTRY_RE.exec(text);
33
+ if (match) entries.push({ time: match[1]!, step: match[2]!, agent: match[3]!, note: match[4]! });
34
+ else if (text.startsWith('- ')) invalidEntries.push(text);
35
35
  }
36
- parsed.sort((a, b) => a.epoch - b.epoch || a.order - b.order);
37
- return { heading: HEADING_RE.exec(lines[i]!)![1]!, body: bodyLines.join('\n').replace(/^\n+|\n+$/g, ''), entries: parsed.map((item) => item.entry) };
36
+ const body = content.slice(heading.end + 1, end).replace(/\r\n/g, '\n').replace(/^\n+|\n+$/g, '');
37
+ return { section: { heading: heading.text, body, entries }, invalidEntries };
38
+ }
39
+
40
+ function locateActivityLog(content: string): ActivityLogSection | null {
41
+ const { section } = inspectActivityLog(content);
42
+ if (!section) return null;
43
+ section.entries.sort((left, right) => Date.parse(left.time.replace(' ', 'T')) - Date.parse(right.time.replace(' ', 'T')));
44
+ return section;
38
45
  }
39
46
 
40
47
  function appendActivityEntry(section: ActivityLogSection, entry: LogEntry): string {
@@ -105,6 +112,7 @@ export {
105
112
  appendActivityEntry,
106
113
  hasOpenLifecycleExecution,
107
114
  commitAttemptStartedNote,
115
+ inspectActivityLog,
108
116
  locateActivityLog,
109
117
  pairEntries,
110
118
  parseActivityLog,
@@ -0,0 +1,104 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { readStableFileSync } from '../host-control/secure-fs.ts';
4
+
5
+ import { resolveArtifactContext, hasOpenArtifactRound } from './artifact-lifecycle.ts';
6
+ import { parseArtifactName } from './artifact-name.ts';
7
+ import { resolveTaskRef } from './resolve-ref.ts';
8
+ import { getArtifactSchema } from './artifact-schema.ts';
9
+ import { finalizeLocalArtifact } from './local-artifact-finalization.ts';
10
+ import { applyArtifactRepair, initializeArtifactSkeleton, inspectArtifactStructure } from './artifact-operations.ts';
11
+
12
+ export type ArtifactCommand = Readonly<{
13
+ taskRef: string;
14
+ operation: 'inspect' | 'init' | 'repair' | 'finalize-local';
15
+ family: string;
16
+ artifact: string;
17
+ locale?: 'zh-CN' | 'en';
18
+ expectedSha256: string;
19
+ expectedSemanticDigest: string;
20
+ }>;
21
+
22
+ /** One option contract for the CLI and trusted projection executor. */
23
+ export function parseArtifactCommand(args: readonly string[]): ArtifactCommand {
24
+ const [taskRef, operation] = args;
25
+ if (!taskRef || !['inspect', 'init', 'repair', 'finalize-local'].includes(operation ?? '')) {
26
+ throw new Error('task ref and a supported artifact operation are required');
27
+ }
28
+ const fields: Record<string, string> = {};
29
+ const allowed = {
30
+ inspect: ['--family'],
31
+ init: ['--family', '--artifact', '--locale'],
32
+ repair: ['--family', '--artifact', '--expected-sha256', '--expected-semantic-digest'],
33
+ 'finalize-local': ['--family', '--artifact']
34
+ }[operation as ArtifactCommand['operation']];
35
+ for (let index = 2; index < args.length; index += 1) {
36
+ const flag = args[index]!;
37
+ if (!allowed.includes(flag)) throw new Error(`unknown option '${flag}'`);
38
+ if (Object.hasOwn(fields, flag)) throw new Error(`duplicate option '${flag}'`);
39
+ const value = args[++index];
40
+ if (!value || value.startsWith('--')) throw new Error(`option '${flag}' requires a value`);
41
+ fields[flag] = value;
42
+ }
43
+ if (!fields['--family']) throw new Error("option '--family' is required");
44
+ if (operation !== 'inspect' && !fields['--artifact']) throw new Error("option '--artifact' is required");
45
+ const locale = fields['--locale'];
46
+ if (locale !== undefined && locale !== 'zh-CN' && locale !== 'en') throw new Error("option '--locale' must be 'zh-CN' or 'en'");
47
+ if (operation === 'repair' && !['--expected-sha256', '--expected-semantic-digest'].every((flag) => /^[a-f0-9]{64}$/u.test(fields[flag] ?? ''))) {
48
+ throw new Error('repair requires lowercase 64-character digests');
49
+ }
50
+ return {
51
+ taskRef, operation: operation as ArtifactCommand['operation'], family: fields['--family'],
52
+ artifact: fields['--artifact'] ?? '', locale,
53
+ expectedSha256: fields['--expected-sha256'] ?? '', expectedSemanticDigest: fields['--expected-semantic-digest'] ?? ''
54
+ };
55
+ }
56
+ /** Resolve authoritative task metadata separately from a trusted candidate directory. */
57
+ export function executeArtifactCommand(
58
+ command: ArtifactCommand,
59
+ options: Readonly<{ repoRoot?: string; artifactDir?: string }> = {}
60
+ ): Record<string, unknown> {
61
+ const { taskRef, operation, family, artifact, locale, expectedSha256, expectedSemanticDigest } = command;
62
+ const fail = (code: string, message: string) => ({ status: 'failed', changed: false, error: { code, message } });
63
+ if (operation === 'inspect') {
64
+ const result = resolveArtifactContext(taskRef, family, { repoRoot: options.repoRoot });
65
+ return family === 'code' && result.codeMode ? {
66
+ ...result, mode: result.codeMode.mode, code_max: result.codeMode.codeMax, rev_max: result.codeMode.reviewMax,
67
+ verdict: result.codeMode.verdict, next_round: result.next?.round ?? null, next_artifact: result.next?.name ?? null,
68
+ review_artifact: result.codeMode.reviewArtifact, implementation_input: result.codeMode.implementationInput,
69
+ decision_id: result.codeMode.decisionId, decision_evidence: result.codeMode.decisionEvidence, message: result.codeMode.message
70
+ } : { ...result };
71
+ }
72
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
73
+ if (!resolved.ok) return fail(resolved.code, resolved.message);
74
+ const schema = getArtifactSchema(family);
75
+ const parsed = parseArtifactName(artifact);
76
+ if (!schema || !parsed || parsed.family !== family) {
77
+ return fail('ARTIFACT_IDENTITY_INVALID', `artifact '${artifact}' does not match ${family}`);
78
+ }
79
+ const taskDir = options.artifactDir ?? resolved.taskDir;
80
+ const identity = { taskId: resolved.taskId, taskDir, family, artifact };
81
+ const input = { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskDir, family: schema.family, artifact };
82
+ if (operation === 'init') {
83
+ const context = resolveArtifactContext(taskRef, family, { repoRoot: resolved.repoRoot });
84
+ if (context.status !== 'ready' || (context.next?.name !== artifact && !hasOpenArtifactRound(fs.readFileSync(resolved.taskMdPath, 'utf8'), family, parsed.round))) {
85
+ return fail('ARTIFACT_INIT_CONTEXT_INVALID', context.error?.message ?? `artifact '${artifact}' is not the next ${family} artifact`);
86
+ }
87
+ return { ...initializeArtifactSkeleton({ ...input, ...(locale ? { locale } : {}) }), ...identity };
88
+ }
89
+ if (operation === 'repair') {
90
+ let content: string;
91
+ try { content = readStableFileSync(path.join(taskDir, artifact), { maxBytes: 1024 * 1024 }).bytes.toString('utf8'); }
92
+ catch (error) { return fail('ARTIFACT_REPAIR_TARGET_INVALID', String(error)); }
93
+ const inspection = inspectArtifactStructure(content, schema);
94
+ if (!inspection.repair) {
95
+ return { ...fail('ARTIFACT_REPAIR_UNSAFE', inspection.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ') || 'no deterministic structural repair is available'),
96
+ artifact, family, diagnostics: inspection.diagnostics };
97
+ }
98
+ return { ...applyArtifactRepair({ ...input, expectedSha256, expectedSemanticDigest, operation: inspection.repair }), ...identity };
99
+ }
100
+ if (family !== 'analysis' && family !== 'plan' && family !== 'code') {
101
+ return fail('ARTIFACT_PAYLOAD_INVALID', "finalize-local only supports 'analysis', 'plan', and 'code'");
102
+ }
103
+ return { ...finalizeLocalArtifact({ taskRef, family, artifact, repoRoot: resolved.repoRoot }) };
104
+ }