@fitlab-ai/agent-infra 0.9.12 → 0.9.14

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 (402) hide show
  1. package/README.md +11 -11
  2. package/README.zh-CN.md +11 -11
  3. package/bin/cli.ts +26 -9
  4. package/dist/bin/cli.js +173 -157
  5. package/dist/bin/internal-cli.js +66 -40
  6. package/dist/lib/agent-client.js +5 -0
  7. package/dist/lib/agent-clients/next-steps.js +6 -1
  8. package/dist/lib/decide.js +3 -3
  9. package/dist/lib/internal/agent-client.js +5 -2
  10. package/dist/lib/internal/cli-route-inventory.js +152 -0
  11. package/dist/lib/internal/codex-lifecycle.js +9 -6
  12. package/dist/lib/internal/codex-sandbox-controller.js +8 -2
  13. package/dist/lib/internal/git-workflow.js +10 -6
  14. package/dist/lib/internal/platform-checks.js +19 -7
  15. package/dist/lib/internal/platform-comment.js +25 -13
  16. package/dist/lib/internal/platform-context.js +6 -3
  17. package/dist/lib/internal/platform-issue.js +20 -13
  18. package/dist/lib/internal/platform-metadata.js +88 -0
  19. package/dist/lib/internal/platform-pr-review.js +26 -13
  20. package/dist/lib/internal/platform-pr.js +84 -31
  21. package/dist/lib/internal/platform-release-notes.js +9 -6
  22. package/dist/lib/internal/platform-security.js +93 -0
  23. package/dist/lib/internal/pr-review-grade.js +25 -12
  24. package/dist/lib/internal/release-workflow.js +23 -9
  25. package/dist/lib/internal/sandbox-control.js +50 -7
  26. package/dist/lib/internal/task-activity.js +16 -7
  27. package/dist/lib/internal/task-artifact.js +235 -24
  28. package/dist/lib/internal/task-context.js +4 -1
  29. package/dist/lib/internal/task-create.js +50 -17
  30. package/dist/lib/internal/task-delivery.js +4 -1
  31. package/dist/lib/internal/task-event.js +10 -4
  32. package/dist/lib/internal/task-finalization.js +6 -3
  33. package/dist/lib/internal/task-invalidation.js +63 -0
  34. package/dist/lib/internal/task-ledger.js +20 -6
  35. package/dist/lib/internal/task-lifecycle.js +6 -3
  36. package/dist/lib/internal/task-operation-registry.js +421 -0
  37. package/dist/lib/internal/task-orchestration.js +12 -0
  38. package/dist/lib/internal/task-override.js +14 -7
  39. package/dist/lib/internal/task-qualification.js +90 -0
  40. package/dist/lib/internal/task-review.js +7 -4
  41. package/dist/lib/internal/task-short-id.js +11 -1
  42. package/dist/lib/internal/task-snapshot.js +4 -1
  43. package/dist/lib/internal/task-validate.js +7 -2
  44. package/dist/lib/internal/task-verify.js +11 -7
  45. package/dist/lib/internal/task-warning.js +11 -4
  46. package/dist/lib/platform/adapters.js +1 -3
  47. package/dist/lib/platform/change-request-git-evidence.js +27 -7
  48. package/dist/lib/platform/comment-safety.js +226 -0
  49. package/dist/lib/platform/completion-backfill.js +6 -5
  50. package/dist/lib/platform/context.js +70 -130
  51. package/dist/lib/platform/github-client.js +1 -1
  52. package/dist/lib/platform/github-provider.js +1130 -0
  53. package/dist/lib/platform/in-label-sync.js +143 -0
  54. package/dist/lib/platform/issue-comments.js +237 -72
  55. package/dist/lib/platform/issues.js +335 -189
  56. package/dist/lib/platform/metadata-labels.js +6 -2
  57. package/dist/lib/platform/none-provider.js +28 -0
  58. package/dist/lib/platform/pr-change-report.js +545 -0
  59. package/dist/lib/platform/pr-checks.js +119 -104
  60. package/dist/lib/platform/pr-review.js +88 -72
  61. package/dist/lib/platform/pr-summary.js +541 -50
  62. package/dist/lib/platform/provider-bridge.js +45 -0
  63. package/dist/lib/platform/provider-contract.d.ts +553 -0
  64. package/dist/lib/platform/provider-contract.js +99 -0
  65. package/dist/lib/platform/provider-loader.js +251 -0
  66. package/dist/lib/platform/provider-validation.js +577 -0
  67. package/dist/lib/platform/pull-request-metadata.js +8 -6
  68. package/dist/lib/platform/pull-requests.js +734 -543
  69. package/dist/lib/platform/release-notes.js +78 -55
  70. package/dist/lib/platform/releases.js +79 -50
  71. package/dist/lib/platform/repository-metadata.js +377 -0
  72. package/dist/lib/platform/resource-identity.d.ts +26 -0
  73. package/dist/lib/platform/resource-identity.js +92 -0
  74. package/dist/lib/platform/security-alerts.js +155 -0
  75. package/dist/lib/platform/task-identities.js +31 -0
  76. package/dist/lib/platform/verification-required.js +11 -12
  77. package/dist/lib/platform/verification-sync.js +129 -248
  78. package/dist/lib/pr-review/evidence-grading.js +19 -6
  79. package/dist/lib/process-data/index.js +7 -0
  80. package/dist/lib/run/index.js +68 -23
  81. package/dist/lib/sandbox/commands/control-status.js +22 -0
  82. package/dist/lib/sandbox/commands/create.js +32 -6
  83. package/dist/lib/sandbox/commands/ls.js +5 -0
  84. package/dist/lib/sandbox/commands/rm.js +827 -120
  85. package/dist/lib/sandbox/commands/show.js +16 -0
  86. package/dist/lib/sandbox/control/client.js +174 -19
  87. package/dist/lib/sandbox/control/completed-reentry.js +85 -0
  88. package/dist/lib/sandbox/control/container-identity.js +28 -31
  89. package/dist/lib/sandbox/control/executor.js +151 -16
  90. package/dist/lib/sandbox/control/lifecycle.js +621 -127
  91. package/dist/lib/sandbox/control/native-file-lock.js +177 -0
  92. package/dist/lib/sandbox/control/protocol.js +77 -0
  93. package/dist/lib/sandbox/control/server.js +677 -34
  94. package/dist/lib/sandbox/control/state.js +209 -4
  95. package/dist/lib/sandbox/control/task-view.js +183 -0
  96. package/dist/lib/sandbox/engines/authority.js +289 -0
  97. package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
  98. package/dist/lib/sandbox/index.js +5 -0
  99. package/dist/lib/sandbox/recovery.js +21 -1
  100. package/dist/lib/sandbox/workspace-view.js +2 -1
  101. package/dist/lib/sandbox/worktree-safety.js +4 -1
  102. package/dist/lib/server/index.js +8 -0
  103. package/dist/lib/server/protocol.js +38 -1
  104. package/dist/lib/task/activity-log.js +8 -1
  105. package/dist/lib/task/artifact-lifecycle.js +75 -18
  106. package/dist/lib/task/artifact-operations.js +520 -0
  107. package/dist/lib/task/artifact-repair-intent.js +59 -0
  108. package/dist/lib/task/artifact-schema.js +135 -0
  109. package/dist/lib/task/capabilities.js +310 -0
  110. package/dist/lib/task/commands/status.js +32 -0
  111. package/dist/lib/task/commit-operation.js +12 -1
  112. package/dist/lib/task/control-authority.js +12 -5
  113. package/dist/lib/task/create-service.js +111 -12
  114. package/dist/lib/task/create.js +25 -0
  115. package/dist/lib/task/current-contract.js +5 -1
  116. package/dist/lib/task/decision-details.js +1 -1
  117. package/dist/lib/task/events.js +416 -17
  118. package/dist/lib/task/finalization.js +37 -13
  119. package/dist/lib/task/human-override.js +58 -36
  120. package/dist/lib/task/index.js +11 -3
  121. package/dist/lib/task/invalidation-command.js +86 -0
  122. package/dist/lib/task/invalidation.js +260 -0
  123. package/dist/lib/task/ledger-intents.js +37 -0
  124. package/dist/lib/task/local-artifact-finalization.js +299 -0
  125. package/dist/lib/task/orchestration.js +240 -144
  126. package/dist/lib/task/pr-delivery-fact.js +102 -101
  127. package/dist/lib/task/qualification-audit.js +490 -0
  128. package/dist/lib/task/qualification-confirmation.js +109 -0
  129. package/dist/lib/task/qualification-intents.js +148 -0
  130. package/dist/lib/task/review-artifacts.js +22 -23
  131. package/dist/lib/task/review-finalization.js +121 -4
  132. package/dist/lib/task/review-fingerprint.js +24 -2
  133. package/dist/lib/task/rework-intent.js +138 -0
  134. package/dist/lib/task/sections.js +6 -4
  135. package/dist/lib/task/skill-scope.js +23 -0
  136. package/dist/lib/task/task-execution-lock.js +27 -17
  137. package/dist/lib/task/verification-config.js +11 -0
  138. package/dist/lib/task/verification-engine.js +93 -16
  139. package/dist/lib/task/verification.js +3 -3
  140. package/dist/lib/task/workflow-warning-intents.js +1 -1
  141. package/dist/lib/task/write.js +11 -0
  142. package/dist/lib/version.js +11 -1
  143. package/dist/lifecycle-build-manifest.json +3 -3
  144. package/lib/agent-client.ts +9 -0
  145. package/lib/agent-clients/next-steps.ts +6 -1
  146. package/lib/decide.ts +3 -3
  147. package/lib/init.ts +1 -1
  148. package/lib/internal/agent-client.ts +4 -2
  149. package/lib/internal/cli-route-inventory.ts +140 -0
  150. package/lib/internal/codex-lifecycle.ts +8 -6
  151. package/lib/internal/codex-sandbox-controller.ts +7 -2
  152. package/lib/internal/git-workflow.ts +9 -6
  153. package/lib/internal/platform-checks.ts +14 -6
  154. package/lib/internal/platform-comment.ts +20 -12
  155. package/lib/internal/platform-context.ts +5 -3
  156. package/lib/internal/platform-issue.ts +17 -11
  157. package/lib/internal/platform-metadata.ts +70 -0
  158. package/lib/internal/platform-pr-review.ts +23 -12
  159. package/lib/internal/platform-pr.ts +65 -27
  160. package/lib/internal/platform-release-notes.ts +8 -6
  161. package/lib/internal/platform-security.ts +83 -0
  162. package/lib/internal/pr-review-grade.ts +20 -11
  163. package/lib/internal/release-workflow.ts +21 -9
  164. package/lib/internal/sandbox-control.ts +44 -6
  165. package/lib/internal/task-activity.ts +15 -7
  166. package/lib/internal/task-artifact.ts +204 -22
  167. package/lib/internal/task-context.ts +3 -1
  168. package/lib/internal/task-create.ts +78 -17
  169. package/lib/internal/task-delivery.ts +3 -1
  170. package/lib/internal/task-event.ts +9 -4
  171. package/lib/internal/task-finalization.ts +6 -4
  172. package/lib/internal/task-invalidation.ts +41 -0
  173. package/lib/internal/task-ledger.ts +21 -8
  174. package/lib/internal/task-lifecycle.ts +5 -3
  175. package/lib/internal/task-operation-registry.ts +482 -0
  176. package/lib/internal/task-orchestration.ts +12 -0
  177. package/lib/internal/task-override.ts +15 -9
  178. package/lib/internal/task-qualification.ts +61 -0
  179. package/lib/internal/task-review.ts +6 -4
  180. package/lib/internal/task-short-id.ts +10 -1
  181. package/lib/internal/task-snapshot.ts +3 -1
  182. package/lib/internal/task-validate.ts +6 -2
  183. package/lib/internal/task-verify.ts +10 -7
  184. package/lib/internal/task-warning.ts +10 -4
  185. package/lib/platform/adapters.ts +3 -2
  186. package/lib/platform/change-request-git-evidence.ts +36 -9
  187. package/lib/platform/comment-safety.ts +250 -0
  188. package/lib/platform/completion-backfill.ts +9 -8
  189. package/lib/platform/context.ts +97 -134
  190. package/lib/platform/github-client.ts +2 -2
  191. package/lib/platform/github-provider.ts +1132 -0
  192. package/lib/platform/in-label-sync.ts +208 -0
  193. package/lib/platform/issue-comments.ts +255 -80
  194. package/lib/platform/issues.ts +344 -174
  195. package/lib/platform/metadata-labels.ts +5 -2
  196. package/lib/platform/none-provider.ts +35 -0
  197. package/lib/platform/pr-change-report.ts +639 -0
  198. package/lib/platform/pr-checks.ts +126 -106
  199. package/lib/platform/pr-review.ts +88 -85
  200. package/lib/platform/pr-summary.ts +581 -53
  201. package/lib/platform/provider-bridge.ts +82 -0
  202. package/lib/platform/provider-contract.ts +611 -0
  203. package/lib/platform/provider-loader.ts +307 -0
  204. package/lib/platform/provider-validation.ts +611 -0
  205. package/lib/platform/pull-request-metadata.ts +10 -7
  206. package/lib/platform/pull-requests.ts +781 -550
  207. package/lib/platform/release-notes.ts +76 -59
  208. package/lib/platform/releases.ts +77 -43
  209. package/lib/platform/repository-metadata.ts +453 -0
  210. package/lib/platform/resource-identity.ts +121 -0
  211. package/lib/platform/security-alerts.ts +191 -0
  212. package/lib/platform/task-identities.ts +40 -0
  213. package/lib/platform/types.ts +4 -2
  214. package/lib/platform/verification-required.ts +11 -13
  215. package/lib/platform/verification-sync.ts +128 -304
  216. package/lib/pr-review/evidence-grading.ts +25 -8
  217. package/lib/process-data/index.ts +7 -0
  218. package/lib/run/index.ts +62 -22
  219. package/lib/sandbox/commands/control-status.ts +26 -0
  220. package/lib/sandbox/commands/create.ts +46 -6
  221. package/lib/sandbox/commands/ls.ts +7 -0
  222. package/lib/sandbox/commands/rm.ts +1000 -87
  223. package/lib/sandbox/commands/show.ts +16 -0
  224. package/lib/sandbox/control/client.ts +203 -19
  225. package/lib/sandbox/control/completed-reentry.ts +98 -0
  226. package/lib/sandbox/control/container-identity.ts +27 -43
  227. package/lib/sandbox/control/executor.ts +180 -15
  228. package/lib/sandbox/control/lifecycle.ts +629 -17
  229. package/lib/sandbox/control/native-file-lock.ts +209 -0
  230. package/lib/sandbox/control/protocol.ts +118 -2
  231. package/lib/sandbox/control/server.ts +724 -34
  232. package/lib/sandbox/control/state.ts +257 -4
  233. package/lib/sandbox/control/task-view.ts +240 -0
  234. package/lib/sandbox/engines/authority.ts +365 -0
  235. package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
  236. package/lib/sandbox/index.ts +7 -0
  237. package/lib/sandbox/recovery.ts +21 -1
  238. package/lib/sandbox/workspace-view.ts +9 -3
  239. package/lib/sandbox/worktree-safety.ts +4 -1
  240. package/lib/server/index.ts +10 -0
  241. package/lib/server/protocol.ts +36 -1
  242. package/lib/task/activity-log.ts +8 -0
  243. package/lib/task/artifact-lifecycle.ts +70 -22
  244. package/lib/task/artifact-operations.ts +626 -0
  245. package/lib/task/artifact-repair-intent.ts +71 -0
  246. package/lib/task/artifact-schema.ts +192 -0
  247. package/lib/task/capabilities.ts +331 -0
  248. package/lib/task/commands/status.ts +38 -0
  249. package/lib/task/commit-operation.ts +12 -1
  250. package/lib/task/control-authority.ts +22 -9
  251. package/lib/task/create-service.ts +139 -14
  252. package/lib/task/create.ts +27 -0
  253. package/lib/task/current-contract.ts +6 -1
  254. package/lib/task/decision-details.ts +6 -2
  255. package/lib/task/events.ts +392 -16
  256. package/lib/task/finalization.ts +50 -14
  257. package/lib/task/human-override.ts +70 -46
  258. package/lib/task/index.ts +16 -3
  259. package/lib/task/invalidation-command.ts +86 -0
  260. package/lib/task/invalidation.ts +332 -0
  261. package/lib/task/ledger-intents.ts +35 -1
  262. package/lib/task/local-artifact-finalization.ts +432 -0
  263. package/lib/task/orchestration.ts +223 -133
  264. package/lib/task/pr-delivery-fact.ts +131 -148
  265. package/lib/task/qualification-audit.ts +599 -0
  266. package/lib/task/qualification-confirmation.ts +117 -0
  267. package/lib/task/qualification-intents.ts +150 -0
  268. package/lib/task/review-artifacts.ts +21 -22
  269. package/lib/task/review-finalization.ts +133 -4
  270. package/lib/task/review-fingerprint.ts +23 -2
  271. package/lib/task/rework-intent.ts +165 -0
  272. package/lib/task/sections.ts +6 -4
  273. package/lib/task/skill-scope.ts +24 -0
  274. package/lib/task/task-execution-lock.ts +23 -14
  275. package/lib/task/verification-config.ts +12 -0
  276. package/lib/task/verification-engine.ts +103 -17
  277. package/lib/task/verification.ts +4 -4
  278. package/lib/task/workflow-warning-intents.ts +1 -1
  279. package/lib/task/write.ts +19 -0
  280. package/lib/update.ts +1 -1
  281. package/lib/version.ts +15 -1
  282. package/package.json +12 -1
  283. package/templates/.agents/rules/README.en.md +3 -1
  284. package/templates/.agents/rules/README.zh-CN.md +3 -1
  285. package/templates/.agents/rules/decision-qualification.en.md +22 -0
  286. package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
  287. package/templates/.agents/rules/evidence-reporting.en.md +28 -0
  288. package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
  289. package/templates/.agents/rules/issue-pr-commands.en.md +1 -1
  290. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
  291. package/templates/.agents/rules/issue-sync.en.md +2 -0
  292. package/templates/.agents/rules/issue-sync.zh-CN.md +2 -0
  293. package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
  294. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
  295. package/templates/.agents/rules/local-artifact-repair.en.md +13 -2
  296. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +13 -2
  297. package/templates/.agents/rules/pr-sync.en.md +10 -4
  298. package/templates/.agents/rules/pr-sync.zh-CN.md +17 -4
  299. package/templates/.agents/rules/security-alerts.en.md +8 -8
  300. package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
  301. package/templates/.agents/rules/task-short-id.en.md +1 -4
  302. package/templates/.agents/rules/task-short-id.zh-CN.md +1 -3
  303. package/templates/.agents/skills/analyze-task/SKILL.en.md +28 -5
  304. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +29 -5
  305. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
  306. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
  307. package/templates/.agents/skills/check-task/SKILL.en.md +16 -37
  308. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -37
  309. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  310. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  311. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  312. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  313. package/templates/.agents/skills/code-task/SKILL.en.md +41 -9
  314. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +43 -11
  315. package/templates/.agents/skills/code-task/config/verify.en.json +6 -14
  316. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +6 -14
  317. package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
  318. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
  319. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
  320. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
  321. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
  322. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
  323. package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
  324. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
  325. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +2 -0
  326. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +2 -0
  327. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +3 -3
  328. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +3 -3
  329. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +10 -4
  330. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +10 -4
  331. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
  332. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
  333. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +4 -3
  334. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +4 -3
  335. package/templates/.agents/skills/complete-task/SKILL.en.md +26 -21
  336. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +25 -21
  337. package/templates/.agents/skills/create-pr/SKILL.en.md +7 -6
  338. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +7 -7
  339. package/templates/.agents/skills/create-pr/config/verify.json +1 -0
  340. package/templates/.agents/skills/create-pr/reference/change-report.en.md +16 -4
  341. package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +16 -4
  342. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +5 -3
  343. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +5 -3
  344. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
  345. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
  346. package/templates/.agents/skills/create-pr/scripts/change-report.mjs +3 -0
  347. package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
  348. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
  349. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  350. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  351. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  352. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  353. package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
  354. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
  355. package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
  356. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
  357. package/templates/.agents/skills/plan-task/SKILL.en.md +27 -4
  358. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +26 -4
  359. package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
  360. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
  361. package/templates/.agents/skills/review-analysis/SKILL.en.md +17 -4
  362. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +17 -4
  363. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
  364. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
  365. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
  366. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
  367. package/templates/.agents/skills/review-code/SKILL.en.md +18 -5
  368. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +18 -5
  369. package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
  370. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
  371. package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
  372. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
  373. package/templates/.agents/skills/review-plan/SKILL.en.md +17 -4
  374. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +17 -4
  375. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
  376. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
  377. package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
  378. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
  379. package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
  380. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
  381. package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
  382. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
  383. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +9 -3
  384. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +9 -3
  385. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +3 -1
  386. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +3 -1
  387. package/templates/.agents/skills/test/SKILL.en.md +13 -2
  388. package/templates/.agents/skills/test/SKILL.zh-CN.md +13 -2
  389. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
  390. package/templates/.agents/skills/watch-pr/SKILL.en.md +2 -2
  391. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +2 -2
  392. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +6 -0
  393. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +6 -0
  394. package/templates/.agents/templates/task.en.md +24 -1
  395. package/templates/.agents/templates/task.zh-CN.md +24 -1
  396. package/templates/.github/workflows/pr-label.yml +7 -26
  397. package/templates/.agents/scripts/security-alerts.github.sh +0 -151
  398. package/templates/.agents/scripts/security-alerts.sh +0 -31
  399. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
  400. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
  401. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
  402. package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
@@ -2,6 +2,7 @@ import { finalizeReviewSummary } from '../task/review-finalization.ts';
2
2
  import { consumeHumanOverride, failureId, overrideDryRunConflict } from '../task/human-override.ts';
3
3
  import { resolveTaskRef } from '../task/resolve-ref.ts';
4
4
  import { TaskExecutionLockError, withTaskExecutionLock } from '../task/task-execution-lock.ts';
5
+ import { ensureInternalHandlerRoute, internalHandlerRoute } from './cli-route-inventory.ts';
5
6
 
6
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';
7
8
 
@@ -16,7 +17,8 @@ function failUsage(message: string): void {
16
17
  process.exitCode = 2;
17
18
  }
18
19
 
19
- function taskReview(args: string[] = []): void {
20
+ async function taskReview(args: string[] = []): Promise<void> {
21
+ if (!ensureInternalHandlerRoute('task-review', args)) return;
20
22
  if (args[0] === '--help' || args[0] === '-h') {
21
23
  process.stdout.write(USAGE);
22
24
  return;
@@ -25,7 +27,7 @@ function taskReview(args: string[] = []): void {
25
27
  failUsage('task ref and intent are required');
26
28
  return;
27
29
  }
28
- if (args[1] !== 'finalize-summary') {
30
+ if (!internalHandlerRoute('task-review', 'finalize-summary', args[1] ?? '')) {
29
31
  failUsage(`unknown intent '${args[1]}'`);
30
32
  return;
31
33
  }
@@ -78,11 +80,11 @@ function taskReview(args: string[] = []): void {
78
80
  let result;
79
81
  let humanOverride: unknown = null;
80
82
  try {
81
- result = withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-review.finalize-summary', () => {
83
+ result = await withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-review.finalize-summary', async () => {
82
84
  let current = finalizeReviewSummary({ taskRef: args[0]!, stage, artifact, orchestrated, dryRun }, { lockAlreadyHeld: true });
83
85
  if (current.status !== 'failed' || !overrideTicket) return current;
84
86
  if (!overrideTarget || !overrideScope) { failUsage('override ticket requires target and scope'); return current; }
85
- const consumed = consumeHumanOverride({
87
+ const consumed = await consumeHumanOverride({
86
88
  taskRef: args[0]!, ticketId: overrideTicket,
87
89
  failureId: failureId('review-finalization', current.error?.code ?? 'TASK_STATE_MISMATCH'),
88
90
  target: overrideTarget, scope: overrideScope
@@ -2,6 +2,7 @@ import path from 'node:path';
2
2
 
3
3
  import { detectRepoRoot } from '../task/resolve-ref.ts';
4
4
  import { configuredShortIdLength, executeShortIdCommand } from '../task/short-id.ts';
5
+ import { ensureInternalHandlerRoute, internalHandlerRoute } from './cli-route-inventory.ts';
5
6
 
6
7
  const USAGE = `Usage: agent-infra-internal task-short-id <alloc|release|resolve|list> [argument] [--active-dir <path>] [--short-id-length <N>] [--verify]\n`;
7
8
 
@@ -12,9 +13,17 @@ function failure(message: string): void {
12
13
  }
13
14
 
14
15
  function taskShortId(args: string[] = []): void {
16
+ if (!ensureInternalHandlerRoute('task-short-id', args)) return;
15
17
  if (args[0] === '--help' || args[0] === '-h') { process.stdout.write(USAGE); return; }
16
18
  const operation = args[0];
17
- if (!operation || !['alloc', 'release', 'resolve', 'list'].includes(operation)) { failure('a valid short-id operation is required'); return; }
19
+ const route = operation === 'list' && args.includes('--verify') ? 'list-verify' : operation ?? '';
20
+ if (!operation || ![
21
+ internalHandlerRoute('task-short-id', 'alloc', route),
22
+ internalHandlerRoute('task-short-id', 'release', route),
23
+ internalHandlerRoute('task-short-id', 'resolve', route),
24
+ internalHandlerRoute('task-short-id', 'list', route),
25
+ internalHandlerRoute('task-short-id', 'list-verify', route)
26
+ ].some(Boolean)) { failure('a valid short-id operation is required'); return; }
18
27
  const positional: string[] = [];
19
28
  let activeDir: string | null = null;
20
29
  let shortIdLength: number | null = null;
@@ -1,4 +1,5 @@
1
1
  import { collectTaskSnapshot } from '../task/snapshot.ts';
2
+ import { ensureInternalHandlerRoute, internalHandlerRoute } from './cli-route-inventory.ts';
2
3
 
3
4
  const USAGE = 'Usage: agent-infra-internal task-snapshot <N | TASK-id> [--format json|text]\n';
4
5
 
@@ -9,8 +10,9 @@ function fail(message: string): void {
9
10
  }
10
11
 
11
12
  function taskSnapshot(args: string[] = []): void {
13
+ if (!ensureInternalHandlerRoute('task-snapshot', args)) return;
12
14
  if (args[0] === '--help' || args[0] === '-h') { process.stdout.write(USAGE); return; }
13
- if (!args[0] || args[0].startsWith('--')) { fail('task ref is required'); return; }
15
+ if (!args[0] || args[0].startsWith('--') || !internalHandlerRoute('task-snapshot', 'snapshot', 'snapshot')) { fail('task ref is required'); return; }
14
16
  let format: 'json' | 'text' = 'json';
15
17
  let seenFormat = false;
16
18
  for (let index = 1; index < args.length; index += 1) {
@@ -24,6 +24,7 @@ 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 { ensureInternalHandlerRoute, internalHandlerRoute } from './cli-route-inventory.ts';
27
28
 
28
29
  const USAGE = `Usage: agent-infra-internal task-validate <branch | TASK-id | N> [--scope snapshot|inplace] [--timeout <ms>] [--format text|json] -- <command> [args...]`;
29
30
  const MAX_TIMEOUT_MS = 60 * 60 * 1000;
@@ -271,6 +272,7 @@ function sniffFormat(args: string[]): 'text' | 'json' {
271
272
  }
272
273
 
273
274
  function taskValidate(args: string[]): void {
275
+ if (!ensureInternalHandlerRoute('task-validate', args)) return;
274
276
  let options: ValidateOptions;
275
277
  try {
276
278
  options = parseValidateArgs(args);
@@ -287,9 +289,11 @@ function taskValidate(args: string[]): void {
287
289
  const target = resolveSandboxTarget(options.target, config.repoRoot);
288
290
  const commit = git(config.repoRoot, ['rev-parse', target.branch]);
289
291
  const startedAt = new Date().toISOString();
290
- const result = options.scope === 'snapshot'
292
+ const result = internalHandlerRoute('task-validate', 'snapshot', options.scope)
291
293
  ? snapshotValidation(config.repoRoot, commit, options)
292
- : inplaceValidation(config, target, options);
294
+ : internalHandlerRoute('task-validate', 'inplace', options.scope)
295
+ ? inplaceValidation(config, target, options)
296
+ : (() => { throw new Error('TASK_VALIDATE_SCOPE_UNREGISTERED'); })();
293
297
  const evidence = {
294
298
  version: 1,
295
299
  taskId: target.workspace.mode === 'task-bound' ? target.workspace.taskId : null,
@@ -2,6 +2,7 @@ import { renderTaskVerification, verifyTaskEvent } from '../task/verification.ts
2
2
  import { consumeHumanOverride, failureId } from '../task/human-override.ts';
3
3
  import { resolveTaskRef } from '../task/resolve-ref.ts';
4
4
  import { TaskExecutionLockError, withTaskExecutionLock } from '../task/task-execution-lock.ts';
5
+ import { ensureInternalHandlerRoute, internalHandlerRoute } from './cli-route-inventory.ts';
5
6
 
6
7
  const USAGE = 'Usage: agent-infra-internal task-verify <N | TASK-id> <verification-event> [--artifact <canonical.md>] [--format json|text] [--override-ticket <ticket> --override-target <target> --override-scope <scope>]\n';
7
8
 
@@ -11,9 +12,11 @@ function fail(message: string): void {
11
12
  process.exitCode = 1;
12
13
  }
13
14
 
14
- function taskVerify(args: string[] = []): void {
15
+ async function taskVerify(args: string[] = []): Promise<void> {
16
+ if (!ensureInternalHandlerRoute('task-verify', args)) return;
15
17
  if (args[0] === '--help' || args[0] === '-h') { process.stdout.write(USAGE); return; }
16
- if (!args[0] || !args[1] || args[0].startsWith('--') || args[1].startsWith('--')) { fail('task ref and verification event are required'); return; }
18
+ if (!args[0] || !args[1] || args[0].startsWith('--') || args[1].startsWith('--')
19
+ || !internalHandlerRoute('task-verify', 'event', args[1] ? 'event' : '')) { fail('task ref and verification event are required'); return; }
17
20
  const taskRef = args[0];
18
21
  const event = args[1];
19
22
  let artifact: string | undefined;
@@ -41,8 +44,8 @@ function taskVerify(args: string[] = []): void {
41
44
  let result;
42
45
  let humanOverride: unknown = null;
43
46
  try {
44
- result = withTaskExecutionLock(resolved.repoRoot, resolved.taskId, `task-verify.${event}`, () => {
45
- let current = verifyTaskEvent({ taskRef, event, ...(artifact ? { artifact } : {}) });
47
+ result = await withTaskExecutionLock(resolved.repoRoot, resolved.taskId, `task-verify.${event}`, async () => {
48
+ let current = await verifyTaskEvent({ taskRef, event, ...(artifact ? { artifact } : {}) });
46
49
  if (current.status === 'pass' || !overrideTicket) return current;
47
50
  if (!overrideTarget || !overrideScope) { fail('override ticket requires target and scope'); return current; }
48
51
  const failureProducer = current.status === 'blocked' || current.status === 'fail'
@@ -53,13 +56,13 @@ function taskVerify(args: string[] = []): void {
53
56
  : current.status === 'fail'
54
57
  ? 'CHECK_FAILED'
55
58
  : current.error?.code ?? 'VERIFY_TASK_STATE_MISMATCH';
56
- const consumed = consumeHumanOverride({
59
+ const consumed = await consumeHumanOverride({
57
60
  taskRef, ticketId: overrideTicket,
58
61
  failureId: failureId(failureProducer, failureCode),
59
62
  target: overrideTarget, scope: overrideScope
60
63
  }, {
61
- effectExecutor: (capability) => {
62
- const retried = verifyTaskEvent({ taskRef, event, ...(artifact ? { artifact } : {}) }, { manualOverride: capability });
64
+ effectExecutor: async (capability) => {
65
+ const retried = await verifyTaskEvent({ taskRef, event, ...(artifact ? { artifact } : {}) }, { manualOverride: capability });
63
66
  current = retried;
64
67
  return retried.status !== 'pass'
65
68
  ? { code: 'OVERRIDE_EFFECT_FAILED', message: `${retried.error?.code ?? 'VERIFY_FAILED'}: ${retried.error?.message ?? 'manual verification effect failed'}` }
@@ -3,6 +3,7 @@ import type { WorkflowWarningIntent } from '../task/workflow-warning-intents.ts'
3
3
  import { consumeHumanOverride, failureId, overrideDryRunConflict } from '../task/human-override.ts';
4
4
  import { resolveTaskRef } from '../task/resolve-ref.ts';
5
5
  import { TaskExecutionLockError, withTaskExecutionLock } from '../task/task-execution-lock.ts';
6
+ import { ensureInternalHandlerRoute, internalHandlerRoute } from './cli-route-inventory.ts';
6
7
 
7
8
  const USAGE = `Usage: agent-infra-internal task-warning <task-ref> <add|set-status|list> [intent flags] [--dry-run]\n`;
8
9
  const FLAGS: Record<string, string> = {
@@ -17,10 +18,15 @@ function usageFailure(message: string): void {
17
18
  process.exitCode = 1;
18
19
  }
19
20
 
20
- function taskWarning(args: string[] = []): void {
21
+ async function taskWarning(args: string[] = []): Promise<void> {
22
+ if (!ensureInternalHandlerRoute('task-warning', args)) return;
21
23
  if (args[0] === '--help' || args[0] === '-h') { process.stdout.write(USAGE); return; }
22
24
  const [taskRef, kind] = args;
23
- if (!taskRef || !kind || !['add', 'set-status', 'list'].includes(kind)) { usageFailure('task ref and a valid intent are required'); return; }
25
+ if (!taskRef || !kind || ![
26
+ internalHandlerRoute('task-warning', 'add', kind ?? ''),
27
+ internalHandlerRoute('task-warning', 'set-status', kind ?? ''),
28
+ internalHandlerRoute('task-warning', 'list', kind ?? '')
29
+ ].some(Boolean)) { usageFailure('task ref and a valid intent are required'); return; }
24
30
  const values: Record<string, unknown> = { kind, taskRef };
25
31
  const seen = new Set<string>();
26
32
  for (let index = 2; index < args.length; index += 1) {
@@ -54,11 +60,11 @@ function taskWarning(args: string[] = []): void {
54
60
  let result;
55
61
  let humanOverride: unknown = null;
56
62
  try {
57
- result = withTaskExecutionLock(resolved.repoRoot, resolved.taskId, `task-warning.${kind}`, () => {
63
+ result = await withTaskExecutionLock(resolved.repoRoot, resolved.taskId, `task-warning.${kind}`, async () => {
58
64
  let current = applyWorkflowWarningIntent(values as WorkflowWarningIntent);
59
65
  if (current.status !== 'failed' || !values.overrideTicket) return current;
60
66
  if (!values.overrideTarget || !values.overrideScope) { usageFailure('override ticket requires target and scope'); return current; }
61
- const consumed = consumeHumanOverride({
67
+ const consumed = await consumeHumanOverride({
62
68
  taskRef, ticketId: String(values.overrideTicket),
63
69
  failureId: failureId('workflow-warning', current.error?.code ?? 'TASK_STATE_MISMATCH'),
64
70
  target: String(values.overrideTarget), scope: String(values.overrideScope)
@@ -1,4 +1,5 @@
1
1
  import type { PlatformError, PlatformResult } from './types.ts';
2
+ import type { ResourceIdentity } from './resource-identity.ts';
2
3
 
3
4
  type PlatformAdapterContext = {
4
5
  cwd: string;
@@ -28,6 +29,7 @@ type PlatformChangeRequestSnapshot = {
28
29
  assignees: string[];
29
30
  milestone: string | null;
30
31
  mergeability?: PlatformMergeability;
32
+ identity?: ResourceIdentity;
31
33
  };
32
34
 
33
35
  type PlatformCheckSnapshot = {
@@ -105,8 +107,7 @@ function registerPlatformCapabilities(
105
107
  'inspectChangeRequest' | 'inspectIssueClosingChangeRequests' | 'inspectRequiredChecks' | 'resolveChangeRequestGitEvidence'
106
108
  >
107
109
  ): void {
108
- const adapter = adapters.get(type);
109
- if (!adapter) throw new Error(`Platform adapter '${type}' must be registered before its capabilities`);
110
+ const adapter = adapters.get(type) ?? { type } as PlatformAdapter;
110
111
  adapters.set(type, { ...adapter, ...capabilities });
111
112
  }
112
113
 
@@ -3,7 +3,13 @@ import os from "node:os";
3
3
  import path from "node:path";
4
4
  import { execFileSync, spawnSync } from "node:child_process";
5
5
 
6
- import { resolvePlatformChangeRequestGitEvidence } from "./adapters.ts";
6
+ import { resolvePlatformProviderContext } from './context.ts';
7
+ import {
8
+ providerError,
9
+ providerOperationContext,
10
+ unsupportedProviderOperation
11
+ } from './provider-bridge.ts';
12
+ import { isResourceIdentity } from './resource-identity.ts';
7
13
  import { resolveReviewedHeadRelation } from "./merged-pr-equivalence.ts";
8
14
  import type { ReviewedHeadRelation } from "./merged-pr-equivalence.ts";
9
15
  import type { PullRequestSnapshot } from "./pull-requests.ts";
@@ -53,25 +59,46 @@ function validMergeIdentity(lastReviewedCommit: string, pullRequest: PullRequest
53
59
  return null;
54
60
  }
55
61
 
56
- function resolveMaterializedReviewedHeadRelation(input: {
62
+ async function resolveMaterializedReviewedHeadRelation(input: {
57
63
  cwd: string;
58
64
  platformType: string | null;
59
65
  lastReviewedCommit: string;
60
66
  pullRequest: PullRequestSnapshot;
61
- }): ReviewedHeadRelation {
67
+ }): Promise<ReviewedHeadRelation> {
62
68
  const identityFailure = validMergeIdentity(input.lastReviewedCommit, input.pullRequest);
63
69
  if (identityFailure) return identityFailure;
64
70
 
65
- const source = resolvePlatformChangeRequestGitEvidence(input.platformType, {
71
+ const loaded = await resolvePlatformProviderContext({
66
72
  cwd: input.cwd,
67
- repository: input.pullRequest.repository,
68
- number: input.pullRequest.number,
69
- pullRequest: input.pullRequest
73
+ platformType: input.platformType || undefined
70
74
  });
75
+ if (!loaded.ok) {
76
+ return blocked(
77
+ loaded.context.error?.code || 'PR_MERGE_EVIDENCE_SOURCE_UNAVAILABLE',
78
+ loaded.context.error?.message || 'Unable to resolve the configured platform provider'
79
+ );
80
+ }
81
+ const target = isResourceIdentity(input.pullRequest.identity)
82
+ ? input.pullRequest.identity
83
+ : { kind: 'number' as const, value: input.pullRequest.number };
84
+ const operation = loaded.value.provider.changeRequests?.resolveGitEvidence
85
+ ? await loaded.value.provider.changeRequests.resolveGitEvidence({
86
+ context: providerOperationContext(loaded.value),
87
+ target,
88
+ expected: {
89
+ baseSha: input.pullRequest.base.sha,
90
+ headSha: input.pullRequest.head.sha,
91
+ targetBranch: input.pullRequest.base.ref
92
+ }
93
+ })
94
+ : unsupportedProviderOperation(loaded.value.provider, 'changeRequests.resolveGitEvidence');
95
+ const source = operation.ok
96
+ ? operation
97
+ : { ok: false as const, error: providerError(operation.error, 'PR_MERGE_EVIDENCE_SOURCE_UNAVAILABLE') };
71
98
  if (!source.ok || !source.value) {
72
99
  return blocked(
73
- source.error?.code || "PR_MERGE_EVIDENCE_SOURCE_UNAVAILABLE",
74
- source.error?.message || "Unable to resolve authoritative PR Git evidence"
100
+ ('error' in source && source.error?.code) || "PR_MERGE_EVIDENCE_SOURCE_UNAVAILABLE",
101
+ ('error' in source && source.error?.message) || "Unable to resolve authoritative PR Git evidence"
75
102
  );
76
103
  }
77
104
  if (
@@ -0,0 +1,250 @@
1
+ type SanitizationError = { code: 'COMMENT_DOCUMENT_INVALID'; message: string; offset: number };
2
+ type SanitizationResult<T> = { ok: true; value: T } | { ok: false; error: SanitizationError };
3
+ type SanitizationOptions = { reservedMarkers?: readonly RegExp[] };
4
+ type PlaceholderSplit = { prefix: string; suffix: string };
5
+ type FenceRange = {
6
+ start: number;
7
+ end: number;
8
+ openingEnd: number;
9
+ closingStart: number;
10
+ character: '`' | '~';
11
+ opening: string;
12
+ closing: string;
13
+ };
14
+ type Line = { start: number; end: number; text: string };
15
+
16
+ const CONTROL_MARKER_PATTERN = /<!--\s*(?:sync-issue|sync-pr|last-commit)\b[\s\S]*?-->|<!--\s*canonical-pr-change-report\s*-->/gi;
17
+
18
+ function ok<T>(value: T): SanitizationResult<T> {
19
+ return { ok: true, value };
20
+ }
21
+
22
+ function invalid(message: string, offset: number): SanitizationResult<never> {
23
+ return { ok: false, error: { code: 'COMMENT_DOCUMENT_INVALID', message, offset } };
24
+ }
25
+
26
+ function normalized(value: string): string {
27
+ return value.replace(/\r\n?/g, '\n');
28
+ }
29
+
30
+ function linesOf(value: string): Line[] {
31
+ const lines: Line[] = [];
32
+ let start = 0;
33
+ while (start < value.length) {
34
+ const newline = value.indexOf('\n', start);
35
+ const end = newline === -1 ? value.length : newline;
36
+ lines.push({ start, end: newline === -1 ? end : newline + 1, text: value.slice(start, end) });
37
+ start = newline === -1 ? value.length : newline + 1;
38
+ }
39
+ if (value.length === 0) lines.push({ start: 0, end: 0, text: '' });
40
+ return lines;
41
+ }
42
+
43
+ function openingFence(line: string): { character: '`' | '~'; length: number } | null | 'invalid' {
44
+ const match = line.match(/^ {0,3}(`{3,}|~{3,})(.*)$/);
45
+ if (!match) return null;
46
+ const character = match[1]![0] as '`' | '~';
47
+ const info = match[2]!;
48
+ if (character === '`' && info.includes('`')) return 'invalid';
49
+ return { character, length: match[1]!.length };
50
+ }
51
+
52
+ function closesFence(line: string, fence: { character: '`' | '~'; length: number }): boolean {
53
+ const escaped = fence.character === '`' ? '`' : '~';
54
+ return new RegExp(`^ {0,3}${escaped}{${fence.length},}[ \\t]*$`).test(line);
55
+ }
56
+
57
+ function fenceRanges(value: string): SanitizationResult<FenceRange[]> {
58
+ const ranges: FenceRange[] = [];
59
+ let fence: { character: '`' | '~'; length: number; start: number; openingEnd: number } | null = null;
60
+ for (const line of linesOf(value)) {
61
+ if (!fence) {
62
+ const opening = openingFence(line.text);
63
+ if (opening === 'invalid') return invalid('fenced code info string is invalid', line.start);
64
+ if (opening) fence = { ...opening, start: line.start, openingEnd: line.end };
65
+ continue;
66
+ }
67
+ if (closesFence(line.text, fence)) {
68
+ ranges.push({
69
+ start: fence.start,
70
+ end: line.end,
71
+ openingEnd: fence.openingEnd,
72
+ closingStart: line.start,
73
+ character: fence.character,
74
+ opening: value.slice(fence.start, fence.openingEnd),
75
+ closing: value.slice(line.start, line.end)
76
+ });
77
+ fence = null;
78
+ }
79
+ }
80
+ if (fence) return invalid('fenced code block is not closed', fence.start);
81
+ return ok(ranges);
82
+ }
83
+
84
+ function escapeHtml(value: string): string {
85
+ return value
86
+ .replace(/&/g, '&amp;')
87
+ .replace(/</g, '&lt;')
88
+ .replace(/>/g, '&gt;')
89
+ .replace(/"/g, '&quot;')
90
+ .replace(/'/g, '&#39;');
91
+ }
92
+
93
+ function escapeHtmlText(value: string): string {
94
+ return escapeHtml(value);
95
+ }
96
+
97
+ function escapeHtmlAttribute(value: string): string {
98
+ return escapeHtml(value);
99
+ }
100
+
101
+ function escapeMarkdownLiteral(value: string): string {
102
+ return value.replace(/[\\`*_{}\[\]()#+.!|<>-]/g, '\\$&');
103
+ }
104
+
105
+ function markerSafe(value: string, markers: readonly RegExp[]): string {
106
+ let result = value;
107
+ for (const marker of markers) {
108
+ const flags = marker.flags.includes('g') ? marker.flags : `${marker.flags}g`;
109
+ const pattern = new RegExp(marker.source, flags);
110
+ result = result.replace(pattern, (match) => escapeHtmlText(match));
111
+ }
112
+ return result;
113
+ }
114
+
115
+ function tagEnd(value: string, start: number): number {
116
+ let quote: '"' | "'" | null = null;
117
+ for (let index = start + 1; index < value.length; index += 1) {
118
+ const character = value[index]!;
119
+ if (quote) {
120
+ if (character === quote) quote = null;
121
+ } else if (character === '"' || character === "'") {
122
+ quote = character;
123
+ } else if (character === '>') {
124
+ return index;
125
+ }
126
+ }
127
+ return -1;
128
+ }
129
+
130
+ function isMarkdownAutolink(value: string, start: number): boolean {
131
+ const end = value.indexOf('>', start + 1);
132
+ if (end === -1) return false;
133
+ const target = value.slice(start + 1, end);
134
+ return /^(?:https?:\/\/|mailto:)[^<>\s]+$/i.test(target)
135
+ || /^[^<>\s@]+@[^<>\s@]+\.[^<>\s@]+$/.test(target);
136
+ }
137
+
138
+ function sanitizeOutside(value: string, baseOffset: number): SanitizationResult<string> {
139
+ let result = '';
140
+ let index = 0;
141
+ while (index < value.length) {
142
+ if (value.startsWith('<!--', index)) {
143
+ const end = value.indexOf('-->', index + 4);
144
+ if (end === -1) return invalid('HTML comment is not closed', baseOffset + index);
145
+ const token = value.slice(index, end + 3);
146
+ result += escapeHtmlText(token);
147
+ index = end + 3;
148
+ continue;
149
+ }
150
+ if (value[index] === '<' && isMarkdownAutolink(value, index)) {
151
+ const end = value.indexOf('>', index + 1);
152
+ result += value.slice(index, end + 1);
153
+ index = end + 1;
154
+ continue;
155
+ }
156
+ if (value[index] === '<' && /[\\/!?A-Za-z]/.test(value[index + 1] || '')) {
157
+ const end = tagEnd(value, index);
158
+ if (end === -1) return invalid('HTML-like tag is not closed', baseOffset + index);
159
+ result += escapeHtmlText(value.slice(index, end + 1));
160
+ index = end + 1;
161
+ continue;
162
+ }
163
+ result += value[index]!;
164
+ index += 1;
165
+ }
166
+ return ok(result);
167
+ }
168
+
169
+ function sanitizeMarkdownDocument(value: string, options: SanitizationOptions = {}): SanitizationResult<string> {
170
+ const source = normalized(value);
171
+ const ranges = fenceRanges(source);
172
+ if (!ranges.ok) return ranges;
173
+ const markers = options.reservedMarkers || [];
174
+ let result = '';
175
+ let cursor = 0;
176
+ for (const range of ranges.value) {
177
+ const outside = sanitizeOutside(source.slice(cursor, range.start), cursor);
178
+ if (!outside.ok) return outside;
179
+ result += outside.value;
180
+ result += markerSafe(source.slice(range.start, range.end), markers);
181
+ cursor = range.end;
182
+ }
183
+ const tail = sanitizeOutside(source.slice(cursor), cursor);
184
+ if (!tail.ok) return tail;
185
+ return ok(result + tail.value);
186
+ }
187
+
188
+ function renderSafeCodeFence(value: string, language = '', reservedMarkers: readonly RegExp[] = [CONTROL_MARKER_PATTERN]): string {
189
+ const content = markerSafe(normalized(value), reservedMarkers);
190
+ const longestRun = Math.max(0, ...(content.match(/`+/g) || []).map((run) => run.length));
191
+ const delimiter = '`'.repeat(Math.max(3, longestRun + 1));
192
+ const suffix = content.endsWith('\n') ? '' : '\n';
193
+ return `${delimiter}${language}\n${content}${suffix}${delimiter}`;
194
+ }
195
+
196
+ function commentRangesOutsideFences(source: string, ranges: readonly FenceRange[]): SanitizationResult<Array<{ start: number; end: number }>> {
197
+ const comments: Array<{ start: number; end: number }> = [];
198
+ let cursor = 0;
199
+ for (const fence of [...ranges, { start: source.length, end: source.length }]) {
200
+ const segment = source.slice(cursor, fence.start);
201
+ let index = 0;
202
+ while (index < segment.length) {
203
+ const opening = segment.indexOf('<!--', index);
204
+ if (opening === -1) break;
205
+ const absoluteStart = cursor + opening;
206
+ const closing = segment.indexOf('-->', opening + 4);
207
+ if (closing === -1) return invalid('HTML comment is not closed', absoluteStart);
208
+ comments.push({ start: absoluteStart, end: cursor + closing + 3 });
209
+ index = closing + 3;
210
+ }
211
+ cursor = fence.end;
212
+ }
213
+ return ok(comments);
214
+ }
215
+
216
+ function splitDocumentPlaceholder(value: string, placeholder: string): SanitizationResult<PlaceholderSplit> {
217
+ const source = normalized(value);
218
+ const ranges = fenceRanges(source);
219
+ if (!ranges.ok) return ranges;
220
+ const positions: number[] = [];
221
+ let cursor = source.indexOf(placeholder);
222
+ while (cursor !== -1) {
223
+ positions.push(cursor);
224
+ cursor = source.indexOf(placeholder, cursor + placeholder.length);
225
+ }
226
+ if (positions.length !== 1) return invalid('document must contain exactly one placeholder', positions[1] ?? positions[0] ?? source.length);
227
+ const position = positions[0]!;
228
+ if (ranges.value.some((range) => position >= range.start && position < range.end)) {
229
+ return invalid('placeholder must be outside fenced code', position);
230
+ }
231
+ const comments = commentRangesOutsideFences(source, ranges.value);
232
+ if (!comments.ok) return comments;
233
+ const containing = comments.value.find((comment) => position >= comment.start && position < comment.end);
234
+ if (containing && (containing.start !== position || containing.end !== position + placeholder.length)) {
235
+ return invalid('placeholder must not be nested in another HTML comment', position);
236
+ }
237
+ return ok({ prefix: source.slice(0, position), suffix: source.slice(position + placeholder.length) });
238
+ }
239
+
240
+ export {
241
+ CONTROL_MARKER_PATTERN,
242
+ escapeHtmlAttribute,
243
+ escapeHtmlText,
244
+ escapeMarkdownLiteral,
245
+ fenceRanges,
246
+ renderSafeCodeFence,
247
+ sanitizeMarkdownDocument,
248
+ splitDocumentPlaceholder
249
+ };
250
+ export type { FenceRange, SanitizationError, SanitizationOptions, SanitizationResult };
@@ -9,11 +9,12 @@ import { getOpenWorkflowWarnings } from '../task/workflow-warnings.ts';
9
9
  import { applyWorkflowWarningIntent } from '../task/workflow-warning-intents.ts';
10
10
  import { captureTaskWriteMetadata } from '../task/write.ts';
11
11
  import { syncPlatformComment } from './issue-comments.ts';
12
- import type { GitHubClient } from './github-client.ts';
12
+ import type { PlatformClient } from './context.ts';
13
13
  import { platformResult } from './types.ts';
14
14
  import type { PlatformOperation, PlatformResult } from './types.ts';
15
+ import { taskIssueIdentity } from './task-identities.ts';
15
16
 
16
- type CompletionBackfillOptions = { agent: string; cwd?: string; client?: GitHubClient };
17
+ type CompletionBackfillOptions = { agent: string; cwd?: string; client?: PlatformClient };
17
18
  type CompletionBackfillResult = PlatformResult & {
18
19
  artifacts: Array<{ artifact: string; status: PlatformResult['status'] }>;
19
20
  warnings: Array<{ id: string; status: string }>;
@@ -42,10 +43,10 @@ function excludedPrReview(taskDir: string, message: string): string | null {
42
43
  }
43
44
  }
44
45
 
45
- function backfillCompletionComments(
46
+ async function backfillCompletionComments(
46
47
  taskRef: string,
47
48
  options: CompletionBackfillOptions
48
- ): CompletionBackfillResult {
49
+ ): Promise<CompletionBackfillResult> {
49
50
  const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
50
51
  if (!resolved.ok) return result(platformResult('failed', {
51
52
  error: { code: resolved.code, message: resolved.message, retryable: false }
@@ -59,16 +60,16 @@ function backfillCompletionComments(
59
60
  }
60
61
  }), [], []);
61
62
  const initialContent = fs.readFileSync(resolved.taskMdPath, 'utf8');
62
- const issueNumber = Number(parseTaskFrontmatter(initialContent).issue_number);
63
- if (!Number.isInteger(issueNumber) || issueNumber <= 0) return result(platformResult('no-op', {
64
- error: { code: 'ISSUE_NOT_LINKED', message: 'Task has no valid issue_number', retryable: false }
63
+ const issueIdentity = taskIssueIdentity(parseTaskFrontmatter(initialContent));
64
+ if (!issueIdentity) return result(platformResult('no-op', {
65
+ error: { code: 'ISSUE_NOT_LINKED', message: 'Task has no valid platform issue identity', retryable: false }
65
66
  }), [], []);
66
67
 
67
68
  const artifacts: CompletionBackfillResult['artifacts'] = [];
68
69
  const operations: PlatformOperation[] = [];
69
70
  let latest = platformResult('no-op', { error: null });
70
71
  for (const artifact of inventory.artifacts) {
71
- latest = syncPlatformComment(resolved.taskId, {
72
+ latest = await syncPlatformComment(resolved.taskId, {
72
73
  kind: 'artifact',
73
74
  artifact: artifact.name,
74
75
  agent: options.agent,