@fitlab-ai/agent-infra 0.9.14 → 0.10.0

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 (354) hide show
  1. package/README.md +10 -0
  2. package/README.zh-CN.md +10 -0
  3. package/bin/internal-cli.sh +45 -0
  4. package/dist/bin/internal-cli.js +93 -30
  5. package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +165 -27
  6. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +9 -4
  7. package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +43 -3
  8. package/dist/lib/defaults.json +103 -103
  9. package/dist/lib/fs/durable-write.js +39 -0
  10. package/dist/lib/fs/file-lock.js +111 -0
  11. package/dist/lib/host-control/audit.js +19 -0
  12. package/dist/lib/host-control/client.js +142 -0
  13. package/dist/lib/host-control/command.js +49 -0
  14. package/dist/lib/host-control/path.js +160 -0
  15. package/dist/lib/host-control/secure-fs.js +140 -0
  16. package/dist/lib/host-control/server.js +159 -0
  17. package/dist/lib/host-control/service.js +112 -0
  18. package/dist/lib/init.js +11 -2
  19. package/dist/lib/internal/cli-route-inventory.js +4 -2
  20. package/dist/lib/internal/codex-lifecycle.js +6 -6
  21. package/dist/lib/internal/demo-promotion.js +322 -0
  22. package/dist/lib/internal/demo-transcript.js +454 -0
  23. package/dist/lib/internal/host-control.js +28 -0
  24. package/dist/lib/internal/manual-validation.js +331 -0
  25. package/dist/lib/internal/platform-pr.js +18 -4
  26. package/dist/lib/internal/release-workflow.js +63 -84
  27. package/dist/lib/internal/sandbox-control.js +149 -2
  28. package/dist/lib/internal/task-artifact.js +16 -263
  29. package/dist/lib/internal/task-create.js +6 -5
  30. package/dist/lib/internal/task-event.js +37 -37
  31. package/dist/lib/internal/task-lifecycle.js +2 -2
  32. package/dist/lib/internal/task-operation-registry.js +101 -4
  33. package/dist/lib/internal/task-review.js +11 -56
  34. package/dist/lib/internal/task-validate.js +30 -10
  35. package/dist/lib/owned-path.js +33 -0
  36. package/dist/lib/platform/check-status.js +11 -0
  37. package/dist/lib/platform/comment-safety.js +4 -1
  38. package/dist/lib/platform/completion-backfill.js +1 -1
  39. package/dist/lib/platform/github-data.js +241 -0
  40. package/dist/lib/platform/github-provider.js +15 -20
  41. package/dist/lib/platform/issue-comments.js +18 -12
  42. package/dist/lib/platform/issues.js +2 -180
  43. package/dist/lib/platform/pr-change-report.js +5 -4
  44. package/dist/lib/platform/pr-checks.js +12 -65
  45. package/dist/lib/platform/pr-summary.js +117 -33
  46. package/dist/lib/platform/pull-requests.js +5 -108
  47. package/dist/lib/platform/snapshots.js +2 -0
  48. package/dist/lib/platform/task-identities.js +2 -9
  49. package/dist/lib/platform/verification-sync.js +132 -143
  50. package/dist/lib/pr-review/evidence-grading.js +4 -8
  51. package/dist/lib/release/workflow.js +1 -1
  52. package/dist/lib/sandbox/commands/create.js +7 -2
  53. package/dist/lib/sandbox/commands/rm.js +19 -1511
  54. package/dist/lib/sandbox/control/audit.js +203 -0
  55. package/dist/lib/sandbox/control/client.js +93 -54
  56. package/dist/lib/sandbox/control/executor.js +129 -65
  57. package/dist/lib/sandbox/control/finalization-response.js +27 -0
  58. package/dist/lib/sandbox/control/identity-sentinel.js +107 -0
  59. package/dist/lib/sandbox/control/lifecycle.js +36 -2
  60. package/dist/lib/sandbox/control/native-file-lock.js +6 -98
  61. package/dist/lib/sandbox/control/protocol.js +55 -4
  62. package/dist/lib/sandbox/control/server.js +518 -127
  63. package/dist/lib/sandbox/control/state.js +64 -0
  64. package/dist/lib/sandbox/control/task-workflow.js +74 -0
  65. package/dist/lib/sandbox/control/workflow-executor.js +89 -0
  66. package/dist/lib/sandbox/index.js +1 -2
  67. package/dist/lib/sandbox/recovery.js +28 -4
  68. package/dist/lib/sandbox/removal.js +822 -0
  69. package/dist/lib/sandbox/task-cleanup.js +217 -0
  70. package/dist/lib/sandbox/workspace-identity.js +17 -1
  71. package/dist/lib/sandbox/workspace-view.js +13 -14
  72. package/dist/lib/task/activity-intent.js +2 -1
  73. package/dist/lib/task/activity-log.js +30 -24
  74. package/dist/lib/task/artifact-command.js +79 -0
  75. package/dist/lib/task/artifact-lifecycle.js +30 -28
  76. package/dist/lib/task/artifact-name.js +36 -0
  77. package/dist/lib/task/artifact-operations.js +29 -289
  78. package/dist/lib/task/artifact-receipts.js +3 -15
  79. package/dist/lib/task/artifact-recovery.js +430 -0
  80. package/dist/lib/task/artifact-repair-intent.js +134 -29
  81. package/dist/lib/task/artifact-schema.js +6 -14
  82. package/dist/lib/task/capabilities.js +12 -19
  83. package/dist/lib/task/codex-orchestration.js +71 -25
  84. package/dist/lib/task/commit-identity.js +28 -0
  85. package/dist/lib/task/commit-operation.js +33 -20
  86. package/dist/lib/task/control-authority.js +403 -6
  87. package/dist/lib/task/control-recovery.js +140 -0
  88. package/dist/lib/task/create-service.js +1 -8
  89. package/dist/lib/task/create.js +62 -9
  90. package/dist/lib/task/decision-details.js +2 -46
  91. package/dist/lib/task/delegation-receipts.js +64 -3
  92. package/dist/lib/task/events.js +275 -22
  93. package/dist/lib/task/finalization-state.js +9 -0
  94. package/dist/lib/task/human-override.js +8 -14
  95. package/dist/lib/task/implementation-inputs.js +3 -3
  96. package/dist/lib/task/intermediate-cleanup.js +441 -0
  97. package/dist/lib/task/invalidation.js +18 -65
  98. package/dist/lib/task/ledger-intents.js +7 -22
  99. package/dist/lib/task/ledger.js +1 -3
  100. package/dist/lib/task/lifecycle-recovery.js +549 -0
  101. package/dist/lib/task/lifecycle.js +31 -4
  102. package/dist/lib/task/local-artifact-finalization.js +197 -197
  103. package/dist/lib/task/manual-validation-completion.js +26 -0
  104. package/dist/lib/task/manual-validation-evidence.js +130 -0
  105. package/dist/lib/task/manual-validation-receipt.js +105 -0
  106. package/dist/lib/task/manual-validation-shared.js +40 -0
  107. package/dist/lib/task/manual-validation-transaction.js +243 -0
  108. package/dist/lib/task/markdown.js +47 -0
  109. package/dist/lib/task/orchestration.js +66 -19
  110. package/dist/lib/task/pr-delivery-fact.js +12 -56
  111. package/dist/lib/task/qualification-audit.js +20 -34
  112. package/dist/lib/task/recovery-warning.js +19 -0
  113. package/dist/lib/task/review-artifacts.js +2 -18
  114. package/dist/lib/task/review-command.js +26 -0
  115. package/dist/lib/task/review-finalization.js +175 -216
  116. package/dist/lib/task/review-fingerprint.js +2 -2
  117. package/dist/lib/task/sections.js +34 -56
  118. package/dist/lib/task/short-id.js +15 -7
  119. package/dist/lib/task/task-execution-lock.js +1 -1
  120. package/dist/lib/task/verification-engine.js +119 -337
  121. package/dist/lib/task/verification.js +1 -1
  122. package/dist/lib/task/workflow-command.js +16 -0
  123. package/dist/lib/task/workflow-warning-intents.js +0 -16
  124. package/dist/lib/task/workflow-warnings.js +28 -2
  125. package/dist/lib/update.js +2 -0
  126. package/dist/lib/version.js +1 -11
  127. package/dist/lifecycle-build-manifest.json +3 -3
  128. package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +223 -33
  129. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +10 -4
  130. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +55 -3
  131. package/lib/fs/durable-write.ts +30 -0
  132. package/lib/fs/file-lock.ts +113 -0
  133. package/lib/host-control/audit.ts +22 -0
  134. package/lib/host-control/client.ts +172 -0
  135. package/lib/host-control/command.ts +60 -0
  136. package/lib/host-control/path.ts +167 -0
  137. package/lib/host-control/secure-fs.ts +135 -0
  138. package/lib/host-control/server.ts +180 -0
  139. package/lib/host-control/service.ts +133 -0
  140. package/lib/init.ts +15 -2
  141. package/lib/internal/cli-route-inventory.ts +4 -2
  142. package/lib/internal/codex-lifecycle.ts +6 -6
  143. package/lib/internal/demo-promotion.ts +354 -0
  144. package/lib/internal/demo-transcript.ts +419 -0
  145. package/lib/internal/host-control.ts +28 -0
  146. package/lib/internal/manual-validation.ts +315 -0
  147. package/lib/internal/platform-pr.ts +15 -4
  148. package/lib/internal/release-workflow.ts +74 -82
  149. package/lib/internal/sandbox-control.ts +162 -1
  150. package/lib/internal/task-artifact.ts +14 -217
  151. package/lib/internal/task-create.ts +5 -5
  152. package/lib/internal/task-event.ts +20 -11
  153. package/lib/internal/task-lifecycle.ts +4 -3
  154. package/lib/internal/task-operation-registry.ts +111 -4
  155. package/lib/internal/task-review.ts +9 -54
  156. package/lib/internal/task-validate.ts +26 -10
  157. package/lib/owned-path.ts +26 -0
  158. package/lib/platform/check-status.ts +9 -0
  159. package/lib/platform/comment-safety.ts +5 -0
  160. package/lib/platform/completion-backfill.ts +1 -1
  161. package/lib/platform/github-data.ts +322 -0
  162. package/lib/platform/github-provider.ts +15 -20
  163. package/lib/platform/issue-comments.ts +21 -14
  164. package/lib/platform/issues.ts +5 -246
  165. package/lib/platform/pr-change-report.ts +7 -5
  166. package/lib/platform/pr-checks.ts +13 -77
  167. package/lib/platform/pr-summary.ts +123 -35
  168. package/lib/platform/pull-requests.ts +6 -173
  169. package/lib/platform/snapshots.ts +53 -0
  170. package/lib/platform/task-identities.ts +3 -14
  171. package/lib/platform/verification-sync.ts +150 -156
  172. package/lib/pr-review/evidence-grading.ts +4 -9
  173. package/lib/release/workflow.ts +3 -3
  174. package/lib/sandbox/commands/create.ts +7 -6
  175. package/lib/sandbox/commands/rm.ts +21 -1895
  176. package/lib/sandbox/control/audit.ts +253 -0
  177. package/lib/sandbox/control/client.ts +109 -66
  178. package/lib/sandbox/control/executor.ts +134 -74
  179. package/lib/sandbox/control/finalization-response.ts +29 -0
  180. package/lib/sandbox/control/identity-sentinel.ts +137 -0
  181. package/lib/sandbox/control/lifecycle.ts +45 -3
  182. package/lib/sandbox/control/native-file-lock.ts +6 -107
  183. package/lib/sandbox/control/protocol.ts +80 -6
  184. package/lib/sandbox/control/server.ts +567 -132
  185. package/lib/sandbox/control/state.ts +86 -0
  186. package/lib/sandbox/control/task-workflow.ts +95 -0
  187. package/lib/sandbox/control/workflow-executor.ts +92 -0
  188. package/lib/sandbox/index.ts +1 -2
  189. package/lib/sandbox/recovery.ts +28 -5
  190. package/lib/sandbox/removal.ts +1142 -0
  191. package/lib/sandbox/task-cleanup.ts +209 -0
  192. package/lib/sandbox/workspace-identity.ts +19 -3
  193. package/lib/sandbox/workspace-view.ts +17 -15
  194. package/lib/task/activity-intent.ts +2 -2
  195. package/lib/task/activity-log.ts +27 -19
  196. package/lib/task/artifact-command.ts +85 -0
  197. package/lib/task/artifact-lifecycle.ts +31 -26
  198. package/lib/task/artifact-name.ts +55 -0
  199. package/lib/task/artifact-operations.ts +34 -310
  200. package/lib/task/artifact-receipts.ts +3 -14
  201. package/lib/task/artifact-recovery.ts +519 -0
  202. package/lib/task/artifact-repair-intent.ts +162 -33
  203. package/lib/task/artifact-schema.ts +5 -34
  204. package/lib/task/capabilities.ts +13 -22
  205. package/lib/task/codex-orchestration.ts +85 -24
  206. package/lib/task/commit-identity.ts +31 -0
  207. package/lib/task/commit-operation.ts +37 -20
  208. package/lib/task/control-authority.ts +540 -10
  209. package/lib/task/control-recovery.ts +186 -0
  210. package/lib/task/create-service.ts +1 -10
  211. package/lib/task/create.ts +63 -8
  212. package/lib/task/decision-details.ts +3 -71
  213. package/lib/task/delegation-receipts.ts +73 -2
  214. package/lib/task/events.ts +309 -24
  215. package/lib/task/finalization-state.ts +11 -0
  216. package/lib/task/human-override.ts +8 -16
  217. package/lib/task/implementation-inputs.ts +3 -3
  218. package/lib/task/intermediate-cleanup.ts +493 -0
  219. package/lib/task/invalidation.ts +18 -62
  220. package/lib/task/ledger-intents.ts +7 -24
  221. package/lib/task/ledger.ts +1 -3
  222. package/lib/task/lifecycle-recovery.ts +691 -0
  223. package/lib/task/lifecycle.ts +30 -5
  224. package/lib/task/local-artifact-finalization.ts +244 -234
  225. package/lib/task/manual-validation-completion.ts +40 -0
  226. package/lib/task/manual-validation-evidence.ts +209 -0
  227. package/lib/task/manual-validation-receipt.ts +156 -0
  228. package/lib/task/manual-validation-shared.ts +50 -0
  229. package/lib/task/manual-validation-transaction.ts +304 -0
  230. package/lib/task/markdown.ts +70 -0
  231. package/lib/task/orchestration.ts +84 -19
  232. package/lib/task/pr-delivery-fact.ts +15 -62
  233. package/lib/task/qualification-audit.ts +22 -33
  234. package/lib/task/recovery-warning.ts +21 -0
  235. package/lib/task/review-artifacts.ts +1 -20
  236. package/lib/task/review-command.ts +24 -0
  237. package/lib/task/review-finalization.ts +183 -292
  238. package/lib/task/review-fingerprint.ts +2 -2
  239. package/lib/task/sections.ts +33 -54
  240. package/lib/task/short-id.ts +27 -5
  241. package/lib/task/task-execution-lock.ts +1 -1
  242. package/lib/task/verification-engine.ts +113 -383
  243. package/lib/task/verification-types.ts +15 -0
  244. package/lib/task/verification.ts +1 -1
  245. package/lib/task/workflow-command.ts +17 -0
  246. package/lib/task/workflow-warning-intents.ts +0 -13
  247. package/lib/task/workflow-warnings.ts +21 -2
  248. package/lib/update.ts +6 -0
  249. package/lib/version.ts +1 -15
  250. package/package.json +6 -6
  251. package/templates/.agents/hooks/lifecycle-delegation.js +6 -6
  252. package/templates/.agents/rules/create-issue.en.md +1 -1
  253. package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
  254. package/templates/.agents/rules/issue-sync.en.md +4 -2
  255. package/templates/.agents/rules/issue-sync.zh-CN.md +4 -3
  256. package/templates/.agents/rules/local-artifact-repair.en.md +46 -39
  257. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +43 -36
  258. package/templates/.agents/rules/testing-discipline.en.md +2 -0
  259. package/templates/.agents/rules/testing-discipline.zh-CN.md +2 -0
  260. package/templates/.agents/scripts/package.json +3 -0
  261. package/templates/.agents/skills/analyze-task/SKILL.en.md +6 -6
  262. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +6 -6
  263. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -1
  264. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -1
  265. package/templates/.agents/skills/block-task/SKILL.en.md +2 -2
  266. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +2 -2
  267. package/templates/.agents/skills/block-task/config/verify.json +1 -1
  268. package/templates/.agents/skills/cancel-task/SKILL.en.md +3 -3
  269. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +3 -3
  270. package/templates/.agents/skills/cancel-task/config/verify.json +1 -1
  271. package/templates/.agents/skills/code-task/SKILL.en.md +7 -7
  272. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +7 -7
  273. package/templates/.agents/skills/code-task/config/verify.en.json +1 -1
  274. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +1 -1
  275. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +1 -1
  276. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +1 -1
  277. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +33 -21
  278. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +33 -21
  279. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
  280. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
  281. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
  282. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
  283. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +16 -7
  284. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +16 -7
  285. package/templates/.agents/skills/complete-task/SKILL.en.md +3 -3
  286. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +3 -3
  287. package/templates/.agents/skills/complete-task/config/verify.en.json +2 -2
  288. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +2 -2
  289. package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +1 -1
  290. package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +1 -1
  291. package/templates/.agents/skills/create-pr/SKILL.en.md +2 -2
  292. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +2 -2
  293. package/templates/.agents/skills/create-pr/config/verify.json +1 -1
  294. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +2 -2
  295. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +2 -2
  296. package/templates/.agents/skills/create-task/SKILL.en.md +5 -5
  297. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +5 -5
  298. package/templates/.agents/skills/create-task/config/verify.json +1 -1
  299. package/templates/.agents/skills/import-issue/SKILL.en.md +8 -8
  300. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +8 -8
  301. package/templates/.agents/skills/import-issue/config/verify.json +2 -2
  302. package/templates/.agents/skills/plan-task/SKILL.en.md +4 -4
  303. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +4 -4
  304. package/templates/.agents/skills/plan-task/config/verify.en.json +1 -1
  305. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -1
  306. package/templates/.agents/skills/release/SKILL.en.md +7 -3
  307. package/templates/.agents/skills/release/SKILL.zh-CN.md +7 -3
  308. package/templates/.agents/skills/restore-task/SKILL.en.md +2 -2
  309. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +2 -2
  310. package/templates/.agents/skills/restore-task/config/verify.json +1 -1
  311. package/templates/.agents/skills/review-analysis/SKILL.en.md +2 -2
  312. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +2 -2
  313. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -1
  314. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -1
  315. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +7 -7
  316. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +6 -6
  317. package/templates/.agents/skills/review-code/SKILL.en.md +2 -2
  318. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +2 -2
  319. package/templates/.agents/skills/review-code/config/verify.en.json +1 -1
  320. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -1
  321. package/templates/.agents/skills/review-code/reference/report-template.en.md +12 -12
  322. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +12 -12
  323. package/templates/.agents/skills/review-plan/SKILL.en.md +2 -2
  324. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +2 -2
  325. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -1
  326. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -1
  327. package/templates/.agents/skills/review-plan/reference/report-template.en.md +7 -7
  328. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +7 -7
  329. package/templates/.agents/skills/review-pr/config/verify.en.json +1 -1
  330. package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +1 -1
  331. package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +3 -3
  332. package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +3 -3
  333. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +20 -3
  334. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +20 -3
  335. package/templates/.agents/skills/run-manual-validation/config/verify.en.json +1 -1
  336. package/templates/.agents/skills/run-manual-validation/config/verify.zh-CN.json +1 -1
  337. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +4 -1
  338. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +4 -1
  339. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +2 -0
  340. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +2 -0
  341. package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
  342. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
  343. package/templates/.agents/skills/test/SKILL.en.md +17 -6
  344. package/templates/.agents/skills/test/SKILL.zh-CN.md +17 -6
  345. package/templates/.agents/templates/task.en.md +1 -1
  346. package/templates/.agents/templates/task.zh-CN.md +1 -1
  347. package/templates/.claude/commands/import-issue.en.md +1 -1
  348. package/templates/.claude/commands/import-issue.zh-CN.md +1 -1
  349. package/templates/.claude/commands/restore-task.en.md +1 -1
  350. package/templates/.claude/commands/restore-task.zh-CN.md +1 -1
  351. package/templates/.claude/commands/run-manual-validation.en.md +1 -1
  352. package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
  353. package/dist/lib/platform/adapters.js +0 -56
  354. package/lib/platform/adapters.ts +0 -197
@@ -1,4 +1,5 @@
1
1
  import fs from 'node:fs';
2
+ import path from 'node:path';
2
3
 
3
4
  import {
4
5
  accessSandboxTaskView,
@@ -13,12 +14,18 @@ import {
13
14
  PUBLIC_CLI_SELECTOR_ALIASES,
14
15
  internalRouteSelector
15
16
  } from './cli-route-inventory.ts';
17
+ import { readSandboxControlIdentitySentinel } from '../sandbox/control/identity-sentinel.ts';
16
18
 
17
19
  export type TaskOperationDispatcher = 'public' | 'internal';
18
20
  export type TaskOperationScope = 'task-bound' | 'non-task' | 'conditional';
19
21
  export type TaskOperationEffect = TaskViewAccessEffect;
20
22
  export type TaskRefSource = 'argv' | 'environment' | 'none' | 'delegated' | 'input';
21
23
 
24
+ export type SandboxControlTransportDecision = Readonly<{
25
+ kind: 'direct-host' | 'broker-client' | 'fail-closed';
26
+ reasonCode: string | null;
27
+ }>;
28
+
22
29
  export type TaskOperationDescriptor = Readonly<{
23
30
  dispatcher: TaskOperationDispatcher;
24
31
  command: string;
@@ -49,6 +56,10 @@ function internalTaskRoutes(): TaskOperationDescriptor[] {
49
56
  descriptor('internal', 'sandbox-control', 'execute', 'non-task', 'progress', 'none'),
50
57
  descriptor('internal', 'sandbox-control', 'recover', 'conditional', 'recovery', 'delegated'),
51
58
  descriptor('internal', 'sandbox-control', 'client', 'conditional', 'progress', 'delegated'),
59
+ descriptor('internal', 'host-control', 'serve', 'non-task', 'progress', 'none'),
60
+ descriptor('internal', 'host-control', 'status', 'non-task', 'diagnostic', 'none'),
61
+ descriptor('internal', 'host-control', 'install', 'non-task', 'progress', 'none'),
62
+ descriptor('internal', 'host-control', 'uninstall', 'non-task', 'progress', 'none'),
52
63
  descriptor('internal', 'agent-client', 'next-steps', 'non-task', 'diagnostic', 'none'),
53
64
  descriptor('internal', 'agent-client', 'model-selection', 'non-task', 'diagnostic', 'none'),
54
65
  descriptor('internal', 'codex-lifecycle', 'preflight', 'non-task', 'diagnostic', 'none'),
@@ -125,7 +136,6 @@ function internalTaskRoutes(): TaskOperationDescriptor[] {
125
136
  descriptor('internal', 'task-activity', 'pr-review-terminate', 'task-bound', 'progress'),
126
137
  descriptor('internal', 'task-artifact', 'inspect', 'task-bound', 'diagnostic'),
127
138
  descriptor('internal', 'task-artifact', 'init', 'task-bound', 'artifact-write'),
128
- descriptor('internal', 'task-artifact', 'repair', 'task-bound', 'artifact-write'),
129
139
  descriptor('internal', 'task-artifact', 'finalize-local', 'task-bound', 'artifact-write'),
130
140
  descriptor('internal', 'task-orchestration', 'status', 'task-bound', 'diagnostic'),
131
141
  descriptor('internal', 'task-orchestration', 'progress', 'task-bound', 'progress'),
@@ -145,7 +155,8 @@ function internalTaskRoutes(): TaskOperationDescriptor[] {
145
155
  descriptor('internal', 'task-snapshot', 'snapshot', 'conditional', 'diagnostic'),
146
156
  descriptor('internal', 'task-verify', 'event', 'task-bound', 'terminal-verdict'),
147
157
  descriptor('internal', 'task-validate', 'snapshot', 'conditional', 'diagnostic'),
148
- descriptor('internal', 'task-validate', 'inplace', 'task-bound', 'progress')
158
+ descriptor('internal', 'task-validate', 'inplace', 'task-bound', 'progress'),
159
+ descriptor('internal', 'manual-validation', 'transaction', 'task-bound', 'remote-write')
149
160
  ];
150
161
  }
151
162
 
@@ -207,12 +218,12 @@ export const TASK_OPERATION_DESCRIPTORS = Object.freeze([
207
218
  ]);
208
219
 
209
220
  export const INTERNAL_DISPATCHER_ROUTES = Object.freeze([
210
- 'task-create', 'task-qualification', 'sandbox-control', 'agent-client', 'codex-lifecycle', 'codex-sandbox-controller',
221
+ 'task-create', 'task-qualification', 'sandbox-control', 'host-control', 'agent-client', 'codex-lifecycle', 'codex-sandbox-controller',
211
222
  'git-workflow', 'task-delivery', 'release-workflow', 'platform-release-notes', 'platform-security', 'platform-metadata', 'platform-context',
212
223
  'platform-comment', 'platform-issue', 'platform-pr', 'platform-pr-review', 'pr-review-grade',
213
224
  'platform-checks', 'task-context', 'task-ledger', 'task-warning', 'task-activity', 'task-artifact',
214
225
  'task-orchestration', 'task-review', 'task-event', 'task-invalidation', 'task-lifecycle',
215
- 'task-finalization', 'task-override', 'task-short-id', 'task-snapshot', 'task-verify', 'task-validate'
226
+ 'task-finalization', 'task-override', 'task-short-id', 'task-snapshot', 'task-verify', 'task-validate', 'manual-validation'
216
227
  ]);
217
228
  export const PUBLIC_DISPATCHER_ROUTES = Object.freeze([
218
229
  'agent-client', 'cp', 'data', 'decide', 'help', 'init', 'merge', 'run', 'sandbox', 'server', 'task', 'sync', 'update', 'version'
@@ -284,6 +295,35 @@ const TASK_CONTROL_MARKER_KEYS = [
284
295
  'AGENT_INFRA_CONTROL_STATUS_DIR'
285
296
  ] as const;
286
297
 
298
+ const TASK_CONTROL_CONFIG_KEYS = [
299
+ 'AGENT_INFRA_CONTROL_TOKEN',
300
+ 'AGENT_INFRA_CONTROL_GENERATION',
301
+ 'AGENT_INFRA_CONTROL_ROOT_ID',
302
+ 'AGENT_INFRA_CONTROL_DIR',
303
+ 'AGENT_INFRA_CONTROL_STATUS_DIR'
304
+ ] as const;
305
+ export const SANDBOX_CONTROL_STATUS_MOUNT = '/run/agent-infra/control-status';
306
+
307
+ type NativeDirectoryProbe = 'present' | 'absent' | 'unknown';
308
+
309
+ function nativeDirectoryProbe(candidate: string): NativeDirectoryProbe {
310
+ try {
311
+ // The fixed mount is a trust anchor. Do not use a mutable node:fs export:
312
+ // a preload must not turn a mounted sandbox into the direct-host path by
313
+ // replacing the ordinary filesystem probe.
314
+ const binding = (process as unknown as {
315
+ binding(name: string): { internalModuleStat(filePath: string): number }
316
+ }).binding('fs');
317
+ if (!Function.prototype.toString.call(binding.internalModuleStat).includes('[native code]')) return 'unknown';
318
+ const result = binding.internalModuleStat(candidate);
319
+ if (result === 1) return 'present';
320
+ if (result === -2) return 'absent';
321
+ return 'unknown';
322
+ } catch {
323
+ return 'unknown';
324
+ }
325
+ }
326
+
287
327
  type TaskMarkerState = 'none' | 'branch-only' | 'task-bound' | 'incomplete';
288
328
 
289
329
  function taskMarkerState(env: NodeJS.ProcessEnv): TaskMarkerState {
@@ -298,6 +338,73 @@ function taskMarkerState(env: NodeJS.ProcessEnv): TaskMarkerState {
298
338
  return 'incomplete';
299
339
  }
300
340
 
341
+ export function resolveSandboxControlTransport(
342
+ env: NodeJS.ProcessEnv = process.env,
343
+ options: Readonly<{ statusMountPath?: string }> = {}
344
+ ): SandboxControlTransportDecision {
345
+ const configuredStatusDir = env.AGENT_INFRA_CONTROL_STATUS_DIR;
346
+ const fixedStatusDir = options.statusMountPath
347
+ ?? SANDBOX_CONTROL_STATUS_MOUNT;
348
+ const hasAnyMarker = TASK_MARKER_KEYS.some((key) => Boolean(env[key]))
349
+ || Boolean(env.AGENT_INFRA_CONTROL_CONTROLLER_BINDING)
350
+ || Boolean(env.AGENT_INFRA_EXECUTOR_MANIFEST);
351
+ const fixedStatusProbe = !env.AGENT_INFRA_TEST_HOST_CONTROL_ENDPOINT && path.isAbsolute(fixedStatusDir)
352
+ ? nativeDirectoryProbe(fixedStatusDir) : 'absent';
353
+ if (fixedStatusProbe === 'unknown') {
354
+ return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_IDENTITY_UNAVAILABLE' };
355
+ }
356
+ const fixedStatusMounted = fixedStatusProbe === 'present';
357
+ const configuredStatusProbe = configuredStatusDir && path.isAbsolute(configuredStatusDir)
358
+ ? nativeDirectoryProbe(configuredStatusDir) : 'absent';
359
+ if (configuredStatusProbe === 'unknown') {
360
+ return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_IDENTITY_UNAVAILABLE' };
361
+ }
362
+ const statusDir = configuredStatusDir && path.isAbsolute(configuredStatusDir) && configuredStatusProbe === 'present'
363
+ ? configuredStatusDir
364
+ : fixedStatusMounted ? fixedStatusDir : null;
365
+ const statusMounted = statusDir !== null;
366
+ const hasCompleteConfig = TASK_CONTROL_CONFIG_KEYS.every((key) => Boolean(env[key]));
367
+ if (env.AGENT_INFRA_EXECUTOR_MANIFEST || env.AGENT_INFRA_CONTROL_CONTROLLER_BINDING) {
368
+ return { kind: 'fail-closed', reasonCode: 'TASK_CONTROL_TRANSPORT_INVALID' };
369
+ }
370
+ const taskBound = Boolean(env.AGENT_INFRA_TASK_ID);
371
+ const runtime = Boolean(env.AGENT_INFRA_RUNTIME_DIR);
372
+
373
+ if (statusMounted) {
374
+ let sentinel;
375
+ try {
376
+ sentinel = readSandboxControlIdentitySentinel(statusDir);
377
+ } catch (error) {
378
+ const message = error instanceof Error ? error.message : '';
379
+ return { kind: 'fail-closed', reasonCode: message.endsWith('MISSING')
380
+ ? 'SANDBOX_CONTROL_IDENTITY_MISSING'
381
+ : 'SANDBOX_CONTROL_IDENTITY_MALFORMED' };
382
+ }
383
+ if (sentinel.generation !== env.AGENT_INFRA_CONTROL_GENERATION) {
384
+ return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_IDENTITY_GENERATION_MISMATCH' };
385
+ }
386
+ if (env.AGENT_INFRA_CONTROL_ROOT_ID && sentinel.controlRootId !== env.AGENT_INFRA_CONTROL_ROOT_ID) {
387
+ return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_IDENTITY_ROOT_ID_MISMATCH' };
388
+ }
389
+ if (sentinel.mode === 'task-bound'
390
+ && (sentinel.taskId !== env.AGENT_INFRA_TASK_ID || !runtime)) {
391
+ return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_IDENTITY_TOPOLOGY_MISMATCH' };
392
+ }
393
+ if (sentinel.mode === 'branch-only' && (taskBound || runtime)) {
394
+ return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_IDENTITY_TOPOLOGY_MISMATCH' };
395
+ }
396
+ if (!hasCompleteConfig) {
397
+ return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_CONFIGURATION_INCOMPLETE' };
398
+ }
399
+ return { kind: 'broker-client', reasonCode: null };
400
+ }
401
+ if (!hasAnyMarker) return { kind: 'direct-host', reasonCode: null };
402
+ if (!hasCompleteConfig || (taskBound && !runtime) || (!taskBound && runtime)) {
403
+ return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_CONFIGURATION_INCOMPLETE' };
404
+ }
405
+ return { kind: 'broker-client', reasonCode: null };
406
+ }
407
+
301
408
  export function hasTaskBoundMarker(env: NodeJS.ProcessEnv = process.env): boolean {
302
409
  return taskMarkerState(env) === 'task-bound';
303
410
  }
@@ -1,10 +1,11 @@
1
+ import { parseReviewCommand } from '../task/review-command.ts';
1
2
  import { finalizeReviewSummary } from '../task/review-finalization.ts';
2
3
  import { consumeHumanOverride, failureId, overrideDryRunConflict } from '../task/human-override.ts';
3
4
  import { resolveTaskRef } from '../task/resolve-ref.ts';
4
5
  import { TaskExecutionLockError, withTaskExecutionLock } from '../task/task-execution-lock.ts';
5
- import { ensureInternalHandlerRoute, internalHandlerRoute } from './cli-route-inventory.ts';
6
+ import { ensureInternalHandlerRoute } from './cli-route-inventory.ts';
6
7
 
7
- const USAGE = 'Usage: agent-infra-internal task-review <task-ref> finalize-summary --stage <analysis|plan|code> --artifact <review-*.md> [--orchestrated] [--dry-run] [--override-ticket <ticket> --override-target <target> --override-scope <scope>]\n';
8
+ const USAGE = 'Usage: agent-infra-internal task-review <task-ref> finalize-summary --stage <analysis|plan|code> --artifact <review-*.md> [--recovery-id <id>] [--orchestrated] [--dry-run] [--override-ticket <ticket> --override-target <target> --override-scope <scope>]\n';
8
9
 
9
10
  function failUsage(message: string): void {
10
11
  process.stdout.write(`${JSON.stringify({
@@ -23,56 +24,10 @@ async function taskReview(args: string[] = []): Promise<void> {
23
24
  process.stdout.write(USAGE);
24
25
  return;
25
26
  }
26
- if (args.length < 2) {
27
- failUsage('task ref and intent are required');
28
- return;
29
- }
30
- if (!internalHandlerRoute('task-review', 'finalize-summary', args[1] ?? '')) {
31
- failUsage(`unknown intent '${args[1]}'`);
32
- return;
33
- }
34
- let stage = '';
35
- let artifact = '';
36
- let dryRun = false;
37
- let orchestrated = false;
38
- let overrideTicket = '';
39
- let overrideTarget = '';
40
- let overrideScope = '';
41
- const seen = new Set<string>();
42
- for (let index = 2; index < args.length; index += 1) {
43
- const flag = args[index]!;
44
- if (!['--stage', '--artifact', '--orchestrated', '--dry-run', '--override-ticket', '--override-target', '--override-scope'].includes(flag)) {
45
- failUsage(`unknown option '${flag}'`);
46
- return;
47
- }
48
- if (seen.has(flag)) {
49
- failUsage(`duplicate option '${flag}'`);
50
- return;
51
- }
52
- seen.add(flag);
53
- if (flag === '--dry-run') {
54
- dryRun = true;
55
- continue;
56
- }
57
- if (flag === '--orchestrated') {
58
- orchestrated = true;
59
- continue;
60
- }
61
- const value = args[++index];
62
- if (!value || value.startsWith('--')) {
63
- failUsage(`option '${flag}' requires a value`);
64
- return;
65
- }
66
- if (flag === '--stage') stage = value;
67
- else if (flag === '--artifact') artifact = value;
68
- else if (flag === '--override-ticket') overrideTicket = value;
69
- else if (flag === '--override-target') overrideTarget = value;
70
- else if (flag === '--override-scope') overrideScope = value;
71
- }
72
- if (!stage || !artifact) {
73
- failUsage("options '--stage' and '--artifact' are required");
74
- return;
75
- }
27
+ let request;
28
+ try { request = parseReviewCommand(args); }
29
+ catch (error) { failUsage(error instanceof Error ? error.message : String(error)); return; }
30
+ const { stage, artifact, recoveryId, dryRun, orchestrated, overrideTicket, overrideTarget, overrideScope } = request;
76
31
  const dryRunConflict = overrideDryRunConflict({ dryRun, overrideTicket, overrideTarget, overrideScope });
77
32
  if (dryRunConflict) { failUsage(dryRunConflict.message); return; }
78
33
  const resolved = resolveTaskRef(args[0]!);
@@ -81,7 +36,7 @@ async function taskReview(args: string[] = []): Promise<void> {
81
36
  let humanOverride: unknown = null;
82
37
  try {
83
38
  result = await withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-review.finalize-summary', async () => {
84
- let current = finalizeReviewSummary({ taskRef: args[0]!, stage, artifact, orchestrated, dryRun }, { lockAlreadyHeld: true });
39
+ let current = finalizeReviewSummary({ taskRef: args[0]!, stage, artifact, recoveryId, orchestrated, dryRun }, { lockAlreadyHeld: true });
85
40
  if (current.status !== 'failed' || !overrideTicket) return current;
86
41
  if (!overrideTarget || !overrideScope) { failUsage('override ticket requires target and scope'); return current; }
87
42
  const consumed = await consumeHumanOverride({
@@ -90,7 +45,7 @@ async function taskReview(args: string[] = []): Promise<void> {
90
45
  target: overrideTarget, scope: overrideScope
91
46
  }, {
92
47
  effectExecutor: (capability) => {
93
- const retried = finalizeReviewSummary({ taskRef: args[0]!, stage, artifact, orchestrated, dryRun }, { lockAlreadyHeld: true, manualOverride: capability });
48
+ const retried = finalizeReviewSummary({ taskRef: args[0]!, stage, artifact, recoveryId, orchestrated, dryRun }, { lockAlreadyHeld: true, manualOverride: capability });
94
49
  current = retried;
95
50
  return retried.status === 'failed' || retried.status === 'planned'
96
51
  ? { code: 'OVERRIDE_EFFECT_FAILED', message: retried.status === 'planned' ? 'producer returned planned; no review effect was committed' : `${retried.error?.code ?? 'REVIEW_FAILED'}: ${retried.error?.message ?? 'manual review effect failed'}` }
@@ -24,9 +24,12 @@ import {
24
24
  } from '../sandbox/control/protocol.ts';
25
25
  import { getProcessStartTime } from '../server/process-state.ts';
26
26
  import { assertGitWorktreeBinding } from '../git/worktree-identity.ts';
27
+ import { createManualValidationEvidence, manualValidationEvidenceSummary } from '../task/manual-validation-evidence.ts';
28
+ import type { ManualValidationCleanup } from '../task/manual-validation-evidence.ts';
29
+ import { writeJsonAtomic } from '../task/manual-validation-shared.ts';
27
30
  import { ensureInternalHandlerRoute, internalHandlerRoute } from './cli-route-inventory.ts';
28
31
 
29
- const USAGE = `Usage: agent-infra-internal task-validate <branch | TASK-id | N> [--scope snapshot|inplace] [--timeout <ms>] [--format text|json] -- <command> [args...]`;
32
+ const USAGE = `Usage: agent-infra-internal task-validate <branch | TASK-id | N> [--scope snapshot|inplace] [--timeout <ms>] [--format text|json] [--evidence-file <path>] -- <command> [args...]`;
30
33
  const MAX_TIMEOUT_MS = 60 * 60 * 1000;
31
34
  const RECOVERY_GRACE_MS = 30_000;
32
35
 
@@ -35,13 +38,14 @@ type ValidateOptions = {
35
38
  scope: 'snapshot' | 'inplace';
36
39
  timeoutMs: number;
37
40
  format: 'text' | 'json';
41
+ evidenceFile: string | null;
38
42
  command: string[];
39
43
  help: boolean;
40
44
  };
41
45
 
42
46
  export function parseValidateArgs(args: string[]): ValidateOptions {
43
47
  if (args.includes('--help') || args.includes('-h')) {
44
- return { target: '', scope: 'snapshot', timeoutMs: 300_000, format: 'text', command: [], help: true };
48
+ return { target: '', scope: 'snapshot', timeoutMs: 300_000, format: 'text', evidenceFile: null, command: [], help: true };
45
49
  }
46
50
  const separator = args.indexOf('--');
47
51
  if (separator < 0) throw new Error(`${USAGE}\nA literal -- must separate validation options from the command.`);
@@ -50,6 +54,7 @@ export function parseValidateArgs(args: string[]): ValidateOptions {
50
54
  let scope: ValidateOptions['scope'] = 'snapshot';
51
55
  let timeoutMs = 300_000;
52
56
  let format: ValidateOptions['format'] = 'text';
57
+ let evidenceFile: string | null = null;
53
58
  const positionals: string[] = [];
54
59
  for (let index = 0; index < optionArgs.length; index += 1) {
55
60
  const arg = optionArgs[index]!;
@@ -65,6 +70,10 @@ export function parseValidateArgs(args: string[]): ValidateOptions {
65
70
  const value = optionArgs[++index];
66
71
  if (value !== 'text' && value !== 'json') throw new Error('validate --format must be text or json');
67
72
  format = value;
73
+ } else if (arg === '--evidence-file') {
74
+ const value = optionArgs[++index];
75
+ if (!value || value.startsWith('-')) throw new Error('validate --evidence-file requires a path');
76
+ evidenceFile = value;
68
77
  } else if (arg.startsWith('-')) {
69
78
  throw new Error(`Unknown option: ${arg}`);
70
79
  } else {
@@ -72,7 +81,7 @@ export function parseValidateArgs(args: string[]): ValidateOptions {
72
81
  }
73
82
  }
74
83
  if (positionals.length !== 1 || command.length === 0) throw new Error(USAGE);
75
- return { target: positionals[0]!, scope, timeoutMs, format, command, help: false };
84
+ return { target: positionals[0]!, scope, timeoutMs, format, evidenceFile, command, help: false };
76
85
  }
77
86
 
78
87
  function runValidationCommand(command: string[], cwd: string, scope: string, timeoutMs: number, json: boolean) {
@@ -294,23 +303,30 @@ function taskValidate(args: string[]): void {
294
303
  : internalHandlerRoute('task-validate', 'inplace', options.scope)
295
304
  ? inplaceValidation(config, target, options)
296
305
  : (() => { throw new Error('TASK_VALIDATE_SCOPE_UNREGISTERED'); })();
297
- const evidence = {
298
- version: 1,
306
+ const cleanup = result.cleanup() as ManualValidationCleanup;
307
+ const evidence = createManualValidationEvidence({
308
+ mode: target.workspace.mode,
299
309
  taskId: target.workspace.mode === 'task-bound' ? target.workspace.taskId : null,
300
310
  branch: target.branch,
301
- scope: options.scope,
302
311
  commit,
312
+ recoverable: target.workspace.mode === 'task-bound',
313
+ scope: options.scope,
303
314
  command: path.basename(options.command[0]!),
304
315
  startedAt,
305
316
  completedAt: new Date().toISOString(),
306
317
  exitCode: result.exitCode,
307
318
  signal: result.signal,
308
- cleanup: result.cleanup()
309
- };
319
+ cleanup
320
+ });
321
+ if (options.evidenceFile) {
322
+ try { writeJsonAtomic(path.resolve(options.evidenceFile), evidence); }
323
+ catch (error) { throw new Error(`MANUAL_VALIDATION_EVIDENCE_WRITE_FAILED: ${error instanceof Error ? error.message : String(error)}`); }
324
+ }
325
+ const evidenceSummary = manualValidationEvidenceSummary(evidence);
310
326
  if (options.format === 'json') {
311
- process.stdout.write(`${JSON.stringify({ status: 'applied', changed: false, evidence, error: null })}\n`);
327
+ process.stdout.write(`${JSON.stringify({ status: 'applied', changed: false, evidence: evidenceSummary, evidenceFile: options.evidenceFile, error: null })}\n`);
312
328
  } else {
313
- process.stdout.write(`Validation ${result.exitCode === 0 ? 'passed' : 'failed'} (${options.scope}, ${evidence.command}, cleanup=${evidence.cleanup}).\n`);
329
+ process.stdout.write(`Validation ${result.exitCode === 0 ? 'passed' : 'failed'} (${options.scope}, ${evidenceSummary.command}, cleanup=${evidenceSummary.cleanup}).\n`);
314
330
  }
315
331
  process.exitCode = result.exitCode;
316
332
  } catch (error) {
@@ -0,0 +1,26 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ // Inspect descendants without following symlinks. The caller supplies the trusted root.
5
+ export function inspectOwnedPath(rootInput: string, targetInput: string, expect: 'file' | 'directory'): fs.Stats | null {
6
+ const root = path.resolve(rootInput);
7
+ const target = path.resolve(targetInput);
8
+ const relative = path.relative(root, target);
9
+ if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) return null;
10
+ try {
11
+ const rootStat = fs.lstatSync(root);
12
+ if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) return null;
13
+ let current = root;
14
+ for (const segment of relative.split(path.sep)) {
15
+ current = path.join(current, segment);
16
+ const stat = fs.lstatSync(current);
17
+ if (stat.isSymbolicLink()) return null;
18
+ if (process.platform !== 'win32' && typeof process.getuid === 'function' && stat.uid !== process.getuid()) return null;
19
+ if (current === target) return (expect === 'file' ? stat.isFile() : stat.isDirectory()) ? stat : null;
20
+ if (!stat.isDirectory()) return null;
21
+ }
22
+ } catch {
23
+ return null;
24
+ }
25
+ return null;
26
+ }
@@ -0,0 +1,9 @@
1
+ import type { PlatformCheckSnapshot } from './snapshots.ts';
2
+
3
+ export function checkStatusBucket(status: string): PlatformCheckSnapshot['bucket'] {
4
+ const value = status.toLowerCase();
5
+ if (['pass', 'success', 'successful', 'neutral'].includes(value)) return 'pass';
6
+ if (['fail', 'failure', 'failed', 'error', 'timed_out', 'action_required'].includes(value)) return 'fail';
7
+ if (['cancel', 'cancelled', 'canceled', 'skipped', 'stale'].includes(value)) return 'cancel';
8
+ return 'pending';
9
+ }
@@ -185,6 +185,10 @@ function sanitizeMarkdownDocument(value: string, options: SanitizationOptions =
185
185
  return ok(result + tail.value);
186
186
  }
187
187
 
188
+ function canonicalizeCommentBody(value: string): SanitizationResult<string> {
189
+ return sanitizeMarkdownDocument(value, { reservedMarkers: [CONTROL_MARKER_PATTERN] });
190
+ }
191
+
188
192
  function renderSafeCodeFence(value: string, language = '', reservedMarkers: readonly RegExp[] = [CONTROL_MARKER_PATTERN]): string {
189
193
  const content = markerSafe(normalized(value), reservedMarkers);
190
194
  const longestRun = Math.max(0, ...(content.match(/`+/g) || []).map((run) => run.length));
@@ -244,6 +248,7 @@ export {
244
248
  escapeMarkdownLiteral,
245
249
  fenceRanges,
246
250
  renderSafeCodeFence,
251
+ canonicalizeCommentBody,
247
252
  sanitizeMarkdownDocument,
248
253
  splitDocumentPlaceholder
249
254
  };
@@ -2,7 +2,7 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
 
4
4
  import { COMPLETION_BACKFILL_FAMILIES, inspectCompletionArtifacts } from '../task/finalization-artifacts.ts';
5
- import { parseArtifactName } from '../task/artifact-lifecycle.ts';
5
+ import { parseArtifactName } from '../task/artifact-name.ts';
6
6
  import { parseTaskFrontmatter } from '../task/frontmatter.ts';
7
7
  import { resolveTaskRef } from '../task/resolve-ref.ts';
8
8
  import { getOpenWorkflowWarnings } from '../task/workflow-warnings.ts';