@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
@@ -0,0 +1,322 @@
1
+ import type { PlatformClient as GitHubClient } from './context.ts';
2
+ import type { PlatformIssueSnapshot as IssueSnapshot, PlatformChangeRequestSnapshot as PullRequestSnapshot } from './snapshots.ts';
3
+ import type { RequiredCheckSnapshot } from './provider-contract.ts';
4
+ import { checkStatusBucket } from './check-status.ts';
5
+
6
+ type RemoteIssue = {
7
+ number?: number;
8
+ id?: number;
9
+ node_id?: string;
10
+ html_url?: string;
11
+ state?: string;
12
+ title?: string;
13
+ body?: string | null;
14
+ labels?: Array<string | { name?: string }>;
15
+ assignees?: Array<{ login?: string }>;
16
+ milestone?: { title?: string } | null;
17
+ type?: { name?: string } | null;
18
+ pull_request?: unknown;
19
+ };
20
+
21
+ type IssueFieldSchema = {
22
+ id: string;
23
+ name: string;
24
+ kind: 'single-select' | 'date' | 'text' | 'number';
25
+ options: Array<{ id: string; name: string }>;
26
+ };
27
+
28
+ type IssueTypeSchema = { id: string; name: string; fields: IssueFieldSchema[] };
29
+
30
+ type CurrentField = { id: string; name: string; kind: IssueFieldSchema['kind']; value: string | number | null };
31
+
32
+ const ISSUE_FIELDS_QUERY = `query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){issue(number:$number){id issueType{id name pinnedFields{__typename ... on IssueFieldSingleSelect{id name options{id name}} ... on IssueFieldDate{id name} ... on IssueFieldText{id name} ... on IssueFieldNumber{id name}}} issueFieldValues(first:50){nodes{__typename ... on IssueFieldSingleSelectValue{name optionId field{... on IssueFieldSingleSelect{id name}}} ... on IssueFieldDateValue{value field{... on IssueFieldDate{id name}}} ... on IssueFieldTextValue{value field{... on IssueFieldText{id name}}} ... on IssueFieldNumberValue{value field{... on IssueFieldNumber{id name}}}}}}}}`;
33
+
34
+ function normalizeIssue(remote: RemoteIssue, repository: string, fallbackNumber?: number): IssueSnapshot | null {
35
+ const number = Number.isInteger(remote.number) && Number(remote.number) > 0
36
+ ? Number(remote.number)
37
+ : fallbackNumber;
38
+ if (!number || !Number.isSafeInteger(number) || remote.pull_request) return null;
39
+ return {
40
+ repository,
41
+ number,
42
+ databaseId: Number.isInteger(remote.id) ? Number(remote.id) : null,
43
+ nodeId: remote.node_id || `issue-${number}`,
44
+ url: remote.html_url || `https://github.com/${repository}/issues/${number}`,
45
+ state: String(remote.state || '').toLowerCase() === 'closed' ? 'closed' : 'open',
46
+ title: remote.title || '',
47
+ body: remote.body || '',
48
+ labels: (remote.labels || []).map((label) => typeof label === 'string' ? label : label.name || '').filter(Boolean).sort(),
49
+ assignees: (remote.assignees || []).map((assignee) => assignee.login || '').filter(Boolean).sort(),
50
+ milestone: remote.milestone?.title || null,
51
+ issueType: remote.type?.name || null,
52
+ fields: {}
53
+ };
54
+ }
55
+
56
+ function fieldKind(value: { __typename?: string }): IssueFieldSchema['kind'] | null {
57
+ if (value.__typename === 'IssueFieldSingleSelect' || value.__typename === 'IssueFieldSingleSelectValue') return 'single-select';
58
+ if (value.__typename === 'IssueFieldDate' || value.__typename === 'IssueFieldDateValue') return 'date';
59
+ if (value.__typename === 'IssueFieldText' || value.__typename === 'IssueFieldTextValue') return 'text';
60
+ if (value.__typename === 'IssueFieldNumber' || value.__typename === 'IssueFieldNumberValue') return 'number';
61
+ return null;
62
+ }
63
+
64
+ function normalizeFieldSchemas(value: unknown): IssueFieldSchema[] {
65
+ if (!Array.isArray(value)) return [];
66
+ return value.flatMap((raw) => {
67
+ const item = raw as { id?: string; name?: string; __typename?: string; options?: Array<{ id?: string; name?: string }> };
68
+ const kind = fieldKind(item);
69
+ return item.id && item.name && kind ? [{
70
+ id: item.id,
71
+ name: item.name,
72
+ kind,
73
+ options: (item.options || []).flatMap((option) => option.id && option.name ? [{ id: option.id, name: option.name }] : [])
74
+ }] : [];
75
+ });
76
+ }
77
+
78
+ function normalizeCurrentFields(value: unknown): { issueId: string | null; type: IssueTypeSchema | null; values: CurrentField[] } {
79
+ const issue = (value as { data?: { repository?: { issue?: {
80
+ id?: string;
81
+ issueType?: { id?: string; name?: string; pinnedFields?: unknown[] } | null;
82
+ issueFieldValues?: { nodes?: unknown[] };
83
+ } } } })?.data?.repository?.issue;
84
+ const type = issue?.issueType?.name ? {
85
+ id: issue.issueType.id || issue.issueType.name,
86
+ name: issue.issueType.name,
87
+ fields: normalizeFieldSchemas(issue.issueType.pinnedFields)
88
+ } : null;
89
+ const values = (issue?.issueFieldValues?.nodes || []).flatMap((raw) => {
90
+ const item = raw as { __typename?: string; name?: string; value?: string | number; field?: { id?: string; name?: string } };
91
+ const kind = fieldKind(item);
92
+ const value = kind === 'single-select' ? item.name : item.value;
93
+ return item.field?.name && kind && value !== undefined
94
+ ? [{ id: item.field.id || item.field.name, name: item.field.name, kind, value: value ?? null }]
95
+ : [];
96
+ });
97
+ return { issueId: issue?.id || null, type, values };
98
+ }
99
+
100
+ function graphState(client: GitHubClient, repository: string, issue: number, cwd: string) {
101
+ const [owner, name] = repository.split('/');
102
+ if (!owner || !name) return null;
103
+ const current = client.json<unknown>([
104
+ 'api', 'graphql', '-f', `query=${ISSUE_FIELDS_QUERY}`, '-F', `owner=${owner}`, '-F', `name=${name}`, '-F', `number=${issue}`
105
+ ], { cwd });
106
+ if (!current.ok) return null;
107
+ return normalizeCurrentFields(current.value);
108
+ }
109
+
110
+ function fetchIssue(client: GitHubClient, repository: string, issue: number, cwd: string) {
111
+ return client.json<RemoteIssue>(['api', `repos/${repository}/issues/${issue}`], { cwd });
112
+ }
113
+
114
+ function inspectGitHubIssue(client: GitHubClient, repository: string, issue: number, cwd: string) {
115
+ const fetched = fetchIssue(client, repository, issue, cwd);
116
+ if (!fetched.ok) return fetched;
117
+ const snapshot = normalizeIssue(fetched.value, repository, issue);
118
+ return snapshot
119
+ ? { ok: true as const, value: snapshot }
120
+ : { ok: false as const, error: { code: 'ISSUE_IDENTITY_INVALID', message: 'Remote resource is not a valid Issue', retryable: false } };
121
+ }
122
+
123
+ type RemotePullRequest = {
124
+ number?: number;
125
+ node_id?: string;
126
+ html_url?: string;
127
+ state?: string;
128
+ title?: string;
129
+ body?: string | null;
130
+ draft?: boolean;
131
+ pull_request?: unknown;
132
+ head?: { ref?: string; sha?: string; repo?: { full_name?: string } | null };
133
+ base?: { ref?: string; sha?: string; repo?: { full_name?: string } | null };
134
+ merged_at?: string | null;
135
+ merge_commit_sha?: string | null;
136
+ labels?: Array<string | { name?: string }>;
137
+ assignees?: Array<{ login?: string }>;
138
+ milestone?: { title?: string } | null;
139
+ mergeable?: boolean | null;
140
+ mergeable_state?: string | null;
141
+ };
142
+
143
+ type ClosingPullRequestNode = {
144
+ number?: number;
145
+ id?: string;
146
+ url?: string;
147
+ state?: string;
148
+ title?: string;
149
+ body?: string | null;
150
+ isDraft?: boolean;
151
+ headRefName?: string;
152
+ headRefOid?: string;
153
+ headRepository?: { nameWithOwner?: string } | null;
154
+ baseRefName?: string;
155
+ baseRefOid?: string;
156
+ baseRepository?: { nameWithOwner?: string } | null;
157
+ mergedAt?: string | null;
158
+ mergeCommit?: { oid?: string } | null;
159
+ labels?: { nodes?: Array<{ name?: string }> };
160
+ assignees?: { nodes?: Array<{ login?: string }> };
161
+ milestone?: { title?: string } | null;
162
+ };
163
+
164
+ type ClosingPullRequestPage = {
165
+ data?: { repository?: { issue?: { closedByPullRequestsReferences?: {
166
+ nodes?: ClosingPullRequestNode[];
167
+ pageInfo?: { hasNextPage?: boolean; endCursor?: string | null };
168
+ } } } };
169
+ };
170
+
171
+ const CLOSING_PULL_REQUESTS_QUERY = `query($owner:String!,$name:String!,$issue:Int!,$cursor:String){repository(owner:$owner,name:$name){issue(number:$issue){closedByPullRequestsReferences(first:100,after:$cursor){nodes{number id url state title body isDraft headRefName headRefOid headRepository{nameWithOwner} baseRefName baseRefOid baseRepository{nameWithOwner} mergedAt mergeCommit{oid} labels(first:100){nodes{name}} assignees(first:100){nodes{login}} milestone{title}} pageInfo{hasNextPage endCursor}}}}}`;
172
+
173
+ function normalizePullRequest(remote: RemotePullRequest, repository: string): PullRequestSnapshot | null {
174
+ const number = Number(remote.number);
175
+ const headRepository = remote.head?.repo?.full_name;
176
+ const baseRepository = remote.base?.repo?.full_name;
177
+ if (!Number.isInteger(number) || number <= 0 || !remote.node_id || !remote.html_url ||
178
+ !remote.head?.ref || !remote.head.sha || !headRepository || !remote.base?.ref || !baseRepository) return null;
179
+ const mergeabilityDetail = remote.mergeable_state?.trim().toLowerCase() || null;
180
+ const mergeability = remote.mergeable === false
181
+ ? { state: 'conflicting' as const, detail: mergeabilityDetail }
182
+ : remote.mergeable === true && mergeabilityDetail !== 'dirty'
183
+ ? { state: 'mergeable' as const, detail: mergeabilityDetail }
184
+ : { state: 'unknown' as const, detail: mergeabilityDetail };
185
+ return {
186
+ repository,
187
+ number,
188
+ nodeId: remote.node_id,
189
+ url: remote.html_url,
190
+ state: remote.state === 'closed' ? 'closed' : 'open',
191
+ title: remote.title || '',
192
+ body: remote.body || '',
193
+ draft: Boolean(remote.draft),
194
+ head: { repository: headRepository, ref: remote.head.ref, sha: remote.head.sha },
195
+ base: { repository: baseRepository, ref: remote.base.ref, sha: remote.base.sha || '' },
196
+ mergedAt: remote.merged_at || null,
197
+ mergeCommitSha: remote.merge_commit_sha || null,
198
+ labels: (remote.labels || []).map((label) => typeof label === 'string' ? label : label.name || '').filter(Boolean).sort(),
199
+ assignees: (remote.assignees || []).map((assignee) => assignee.login || '').filter(Boolean).sort(),
200
+ milestone: remote.milestone?.title || null,
201
+ mergeability
202
+ };
203
+ }
204
+
205
+ function normalizeClosingPullRequest(node: ClosingPullRequestNode, repository: string): PullRequestSnapshot | null {
206
+ return normalizePullRequest({
207
+ number: node.number,
208
+ node_id: node.id,
209
+ html_url: node.url,
210
+ state: node.state === 'OPEN' ? 'open' : 'closed',
211
+ title: node.title,
212
+ body: node.body,
213
+ draft: node.isDraft,
214
+ head: { ref: node.headRefName, sha: node.headRefOid, repo: node.headRepository ? { full_name: node.headRepository.nameWithOwner } : null },
215
+ base: { ref: node.baseRefName, sha: node.baseRefOid, repo: node.baseRepository ? { full_name: node.baseRepository.nameWithOwner } : null },
216
+ merged_at: node.mergedAt,
217
+ merge_commit_sha: node.mergeCommit?.oid,
218
+ labels: node.labels?.nodes,
219
+ assignees: node.assignees?.nodes,
220
+ milestone: node.milestone
221
+ }, repository);
222
+ }
223
+
224
+ function inspectGitHubIssueClosingChangeRequests(
225
+ client: GitHubClient,
226
+ repository: string,
227
+ issueNumber: number,
228
+ cwd: string
229
+ ) {
230
+ const [owner, name] = repository.split('/');
231
+ if (!owner || !name || !Number.isInteger(issueNumber) || issueNumber <= 0) return {
232
+ ok: false as const,
233
+ error: { code: 'PR_IDENTITY_INVALID', message: 'Repository or Issue identity is invalid', retryable: false }
234
+ };
235
+ const candidates: PullRequestSnapshot[] = [];
236
+ let cursor: string | null = null;
237
+ for (;;) {
238
+ const args = [
239
+ 'api', 'graphql', '-f', `query=${CLOSING_PULL_REQUESTS_QUERY}`,
240
+ '-F', `owner=${owner}`, '-F', `name=${name}`, '-F', `issue=${issueNumber}`
241
+ ];
242
+ if (cursor) args.push('-F', `cursor=${cursor}`);
243
+ const response = client.json<ClosingPullRequestPage>(args, { cwd });
244
+ if (!response.ok) return response;
245
+ const connection = response.value?.data?.repository?.issue?.closedByPullRequestsReferences;
246
+ if (!connection || !Array.isArray(connection.nodes) || !connection.pageInfo) return {
247
+ ok: false as const,
248
+ error: { code: 'PR_IDENTITY_INVALID', message: 'Closing pull request response is incomplete', retryable: false }
249
+ };
250
+ for (const node of connection.nodes) {
251
+ const normalized = normalizeClosingPullRequest(node, repository);
252
+ if (!normalized) return {
253
+ ok: false as const,
254
+ error: { code: 'PR_IDENTITY_INVALID', message: 'Closing pull request identity is incomplete', retryable: false }
255
+ };
256
+ candidates.push(normalized);
257
+ }
258
+ if (!connection.pageInfo.hasNextPage) return { ok: true as const, value: candidates };
259
+ if (!connection.pageInfo.endCursor || connection.pageInfo.endCursor === cursor) return {
260
+ ok: false as const,
261
+ error: { code: 'PR_IDENTITY_INVALID', message: 'Closing pull request pagination cursor is invalid', retryable: false }
262
+ };
263
+ cursor = connection.pageInfo.endCursor;
264
+ }
265
+ }
266
+
267
+ function inspectGitHubPullRequest(client: GitHubClient, repository: string, number: number, cwd: string) {
268
+ const fetched = client.json<RemotePullRequest>(['api', `repos/${repository}/pulls/${number}`], { cwd });
269
+ if (!fetched.ok) return fetched;
270
+ const pullRequest = normalizePullRequest(fetched.value, repository);
271
+ return pullRequest
272
+ ? { ok: true as const, value: pullRequest }
273
+ : { ok: false as const, error: { code: 'PR_IDENTITY_INVALID', message: 'Remote resource is not a valid pull request', retryable: false } };
274
+ }
275
+
276
+ function normalizeGitHubChecks(value: unknown): RequiredCheckSnapshot[] {
277
+ if (!Array.isArray(value)) return [];
278
+ return value.flatMap((raw) => {
279
+ const item = raw as Record<string, unknown>;
280
+ const name = String(item.name || item.context || '');
281
+ return name ? [{
282
+ name,
283
+ status: checkStatusBucket(String(item.bucket || item.status || item.conclusion || item.state || '')),
284
+ conclusion: item.conclusion ? String(item.conclusion) : item.state ? String(item.state) : null,
285
+ detailsUrl: item.link ? String(item.link) : item.detailsUrl ? String(item.detailsUrl) : null
286
+ }] : [];
287
+ });
288
+ }
289
+
290
+ function inspectGitHubRequiredChecks(client: GitHubClient, repository: string, number: number, cwd: string) {
291
+ const inspected = client.json<unknown>([
292
+ 'pr', 'checks', String(number), '--repo', repository,
293
+ '--json', 'name,state,bucket,link,workflow,startedAt,completedAt'
294
+ ], { cwd });
295
+ return inspected.ok
296
+ ? { ok: true as const, value: normalizeGitHubChecks(inspected.value) }
297
+ : { ok: false as const, error: inspected.error };
298
+ }
299
+
300
+ function parseRunJobIdentity(detailsUrl: string): { runId: number; jobId: number | null } | null {
301
+ try {
302
+ const url = new URL(detailsUrl);
303
+ if (url.hostname !== 'github.com') return null;
304
+ const match = url.pathname.match(/\/actions\/runs\/(\d+)(?:\/job\/(\d+))?/);
305
+ if (!match) return null;
306
+ return { runId: Number(match[1]), jobId: match[2] ? Number(match[2]) : null };
307
+ } catch {
308
+ return null;
309
+ }
310
+ }
311
+
312
+ function fetchCheckLogText(client: GitHubClient, args: string[], cwd: string) {
313
+ if (!client.text) return { ok: false as const, error: { code: 'PLATFORM_CLIENT_TEXT_UNAVAILABLE', message: 'Platform client does not support text responses', retryable: false } };
314
+ const fetched = client.text(args, { cwd });
315
+ if (fetched.ok || args[0] !== 'api' || !/response contains terminal escape sequences/i.test(fetched.error.message)) {
316
+ return fetched;
317
+ }
318
+ return client.text([...args, '--allow-escape-sequences'], { cwd });
319
+ }
320
+
321
+ export { ISSUE_FIELDS_QUERY, graphState, inspectGitHubIssue, normalizePullRequest, inspectGitHubIssueClosingChangeRequests, inspectGitHubPullRequest, inspectGitHubRequiredChecks, parseRunJobIdentity, fetchCheckLogText };
322
+ export type { IssueFieldSchema, RemotePullRequest };
@@ -1,3 +1,4 @@
1
+ import { ISSUE_FIELDS_QUERY, graphState, inspectGitHubIssue, inspectGitHubPullRequest, inspectGitHubIssueClosingChangeRequests, inspectGitHubRequiredChecks, parseRunJobIdentity, fetchCheckLogText } from './github-data.ts';
1
2
  import { execFileSync } from 'node:child_process';
2
3
  import fs from 'node:fs';
3
4
  import os from 'node:os';
@@ -30,7 +31,6 @@ import type {
30
31
  RepositoryMetadataSnapshot,
31
32
  ReleaseSnapshot,
32
33
  RemoteCommentSnapshot,
33
- RequiredCheckSnapshot,
34
34
  ReviewSnapshot,
35
35
  SecurityAlertKind,
36
36
  SecurityAlertSnapshot,
@@ -41,7 +41,6 @@ import { extractPullRequestFileNames, syncLabelDelta } from './in-label-sync.ts'
41
41
 
42
42
  const CURRENT_USER_QUERY = 'query { viewer { login } }';
43
43
  const ISSUE_TYPES_QUERY = `query($owner:String!){organization(login:$owner){issueTypes(first:20){nodes{id name pinnedFields{__typename ... on IssueFieldSingleSelect{id name options{id name}} ... on IssueFieldDate{id name} ... on IssueFieldText{id name} ... on IssueFieldNumber{id name}}}}}}`;
44
- const ISSUE_FIELDS_QUERY = `query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){issue(number:$number){id issueType{id name pinnedFields{__typename ... on IssueFieldSingleSelect{id name options{id name}} ... on IssueFieldDate{id name} ... on IssueFieldText{id name} ... on IssueFieldNumber{id name}}} issueFieldValues(first:50){nodes{__typename ... on IssueFieldSingleSelectValue{name optionId field{... on IssueFieldSingleSelect{id name}}} ... on IssueFieldDateValue{value field{... on IssueFieldDate{id name}}} ... on IssueFieldTextValue{value field{... on IssueFieldText{id name}}} ... on IssueFieldNumberValue{value field{... on IssueFieldNumber{id name}}}}}}}}`;
45
44
  const CLOSING_ISSUES_QUERY = 'query($owner:String!,$name:String!,$number:Int!,$cursor:String){repository(owner:$owner,name:$name){pullRequest(number:$number){closingIssuesReferences(first:100,after:$cursor){nodes{number} pageInfo{hasNextPage endCursor}}}}}';
46
45
 
47
46
  function parseGitHubRemote(remote: string): string | null {
@@ -465,10 +464,9 @@ function createGitHubOperations(client: GitHubClient): Pick<PlatformProvider, 'i
465
464
  async inspect({ context, target }) {
466
465
  const number = resourceIdentityNumber(target);
467
466
  if (!number) return invalid('ISSUE_NUMBER_INVALID', 'Issue number must be positive');
468
- const module = await import('./issues.ts');
469
- const fetched = module.inspectGitHubIssue(client, repository(context), number, context.workingDirectory);
467
+ const fetched = inspectGitHubIssue(client, repository(context), number, context.workingDirectory);
470
468
  if (!fetched.ok) return fetched;
471
- const graph = module.graphState(client, repository(context), number, context.workingDirectory);
469
+ const graph = graphState(client, repository(context), number, context.workingDirectory);
472
470
  return { ok: true, value: issueSnapshot(fetched.value, graph || undefined) };
473
471
  },
474
472
  async create({ context, desired }) {
@@ -648,8 +646,7 @@ function createGitHubOperations(client: GitHubClient): Pick<PlatformProvider, 'i
648
646
  async inspect({ context, target }) {
649
647
  const number = resourceIdentityNumber(target);
650
648
  if (!number) return invalid('PR_NUMBER_INVALID', 'Pull request number must be positive');
651
- const module = await import('./pull-requests.ts');
652
- const fetched = module.inspectGitHubPullRequest(client, repository(context), number, context.workingDirectory);
649
+ const fetched = inspectGitHubPullRequest(client, repository(context), number, context.workingDirectory);
653
650
  if (!fetched.ok) return fetched;
654
651
  return { ok: true, value: changeRequestSnapshot(fetched.value) };
655
652
  },
@@ -708,8 +705,7 @@ function createGitHubOperations(client: GitHubClient): Pick<PlatformProvider, 'i
708
705
  async listClosing({ context, issue }) {
709
706
  const number = resourceIdentityNumber(issue);
710
707
  if (!number) return invalid('ISSUE_NUMBER_INVALID', 'Issue number must be positive');
711
- const module = await import('./pull-requests.ts');
712
- const fetched = module.inspectGitHubIssueClosingChangeRequests(client, repository(context), number, context.workingDirectory);
708
+ const fetched = inspectGitHubIssueClosingChangeRequests(client, repository(context), number, context.workingDirectory);
713
709
  if (!fetched.ok) return fetched;
714
710
  return { ok: true, value: fetched.value.map(changeRequestSnapshot) };
715
711
  },
@@ -780,8 +776,7 @@ function createGitHubOperations(client: GitHubClient): Pick<PlatformProvider, 'i
780
776
  async resolveGitEvidence({ context, target, expected }) {
781
777
  const number = resourceIdentityNumber(target);
782
778
  if (!number) return invalid('PR_NUMBER_INVALID', 'Pull request number must be positive');
783
- const module = await import('./github-provider.ts');
784
- return module.resolveGitHubChangeRequestGitEvidence({
779
+ return resolveGitHubChangeRequestGitEvidence({
785
780
  cwd: context.workingDirectory,
786
781
  repository: repository(context),
787
782
  number,
@@ -795,16 +790,12 @@ function createGitHubOperations(client: GitHubClient): Pick<PlatformProvider, 'i
795
790
  async inspectRequired({ context, changeRequest }) {
796
791
  const number = resourceIdentityNumber(changeRequest);
797
792
  if (!number) return invalid('PR_NUMBER_INVALID', 'Pull request number must be positive');
798
- const module = await import('./pr-checks.ts');
799
- const fetched = module.inspectGitHubRequiredChecks(client, repository(context), number, context.workingDirectory);
800
- if (!fetched.ok) return fetched;
801
- return { ok: true, value: fetched.value.map((check: any): RequiredCheckSnapshot => ({ name: check.name, status: check.bucket, conclusion: check.conclusion, detailsUrl: check.detailsUrl })) };
793
+ return inspectGitHubRequiredChecks(client, repository(context), number, context.workingDirectory);
802
794
  },
803
795
  async resolveRun({ context, changeRequest, checkName, detailsUrl }) {
804
796
  const number = resourceIdentityNumber(changeRequest);
805
797
  if (!number) return invalid('PR_NUMBER_INVALID', 'Pull request number must be positive');
806
- const module = await import('./pr-checks.ts');
807
- const direct = detailsUrl ? module.parseRunJobIdentity(detailsUrl) : null;
798
+ const direct = detailsUrl ? parseRunJobIdentity(detailsUrl) : null;
808
799
  if (direct) {
809
800
  const run = client.json<any>(['api', `repos/${repository(context)}/actions/runs/${direct.runId}`], { cwd: context.workingDirectory });
810
801
  if (!run.ok) return run;
@@ -818,11 +809,10 @@ function createGitHubOperations(client: GitHubClient): Pick<PlatformProvider, 'i
818
809
  : invalid('CHECK_RUN_NOT_FOUND', 'Check run was not found');
819
810
  },
820
811
  async fetchLogs({ context, runId, jobId }) {
821
- const module = await import('./pr-checks.ts');
822
812
  const args = jobId
823
813
  ? ['api', `repos/${repository(context)}/actions/jobs/${jobId}/logs`]
824
814
  : ['run', 'view', runId, '--repo', repository(context), '--log-failed'];
825
- const fetched = module.fetchCheckLogText(client, args, context.workingDirectory);
815
+ const fetched = fetchCheckLogText(client, args, context.workingDirectory);
826
816
  if (!fetched.ok) return fetched;
827
817
  return { ok: true, value: { runId, jobId, text: fetched.value || '' } } as ProviderResult<CheckLogSnapshot>;
828
818
  }
@@ -891,7 +881,12 @@ function createGitHubOperations(client: GitHubClient): Pick<PlatformProvider, 'i
891
881
  }
892
882
  continue;
893
883
  }
894
- const response = client.json(['api', '--method', 'POST', `repos/${repository(context)}/milestones`, '-f', `title=${item.title}`, '-f', `description=${item.description}`], { cwd: context.workingDirectory });
884
+ const response = client.json([
885
+ 'api', '--method', 'POST', `repos/${repository(context)}/milestones`,
886
+ '-f', `title=${item.title}`,
887
+ '-f', `description=${item.description}`,
888
+ '-f', `state=${item.state}`
889
+ ], { cwd: context.workingDirectory });
895
890
  if (!response.ok) return response;
896
891
  created.push(item.title);
897
892
  }
@@ -17,11 +17,10 @@ import {
17
17
  import { resourceIdentityNumber } from './resource-identity.ts';
18
18
  import { taskIssueIdentity, taskIssueIdentityError } from './task-identities.ts';
19
19
  import {
20
- CONTROL_MARKER_PATTERN,
20
+ canonicalizeCommentBody,
21
21
  escapeHtmlText,
22
22
  fenceRanges,
23
- renderSafeCodeFence,
24
- sanitizeMarkdownDocument
23
+ renderSafeCodeFence
25
24
  } from './comment-safety.ts';
26
25
  import type { FenceRange } from './comment-safety.ts';
27
26
 
@@ -51,6 +50,7 @@ const MARKERS = {
51
50
  summary: (taskId: string) => `<!-- sync-issue:${taskId}:summary -->`,
52
51
  cancel: (taskId: string) => `<!-- sync-issue:${taskId}:cancel -->`
53
52
  };
53
+ const COMMENT_BYTE_LIMIT = 60_000;
54
54
 
55
55
  const ARTIFACT_TITLES: Record<string, string> = {
56
56
  analysis: '需求分析',
@@ -68,6 +68,10 @@ function normalizeCommentContent(content: string): string {
68
68
  return content.replace(/\r\n/g, '\n').replace(/\n+$/, '\n');
69
69
  }
70
70
 
71
+ function isTaskCommentTooLarge(content: string): boolean {
72
+ return Buffer.byteLength(content, 'utf8') > COMMENT_BYTE_LIMIT;
73
+ }
74
+
71
75
  function splitFrontmatter(content: string): { frontmatter: string | null; body: string } {
72
76
  const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
73
77
  if (!match) return { frontmatter: null, body: content };
@@ -75,7 +79,7 @@ function splitFrontmatter(content: string): { frontmatter: string | null; body:
75
79
  }
76
80
 
77
81
  function sanitizeCommentBody(value: string, label: string): string {
78
- const result = sanitizeMarkdownDocument(value, { reservedMarkers: [CONTROL_MARKER_PATTERN] });
82
+ const result = canonicalizeCommentBody(value);
79
83
  if (!result.ok) throw new Error(`${result.error.code}: ${label}: ${result.error.message} at offset ${result.error.offset}`);
80
84
  return result.value;
81
85
  }
@@ -270,7 +274,7 @@ function chunkArtifactComment(input: {
270
274
  byteLimit?: number;
271
275
  backfill?: boolean;
272
276
  }): RenderedChunk[] {
273
- const byteLimit = input.byteLimit || 60_000;
277
+ const byteLimit = input.byteLimit || COMMENT_BYTE_LIMIT;
274
278
  const identity = artifactIdentity(input.artifact);
275
279
  const safeBody = sanitizeCommentBody(input.body, 'artifact body');
276
280
  const single = buildArtifactChunk(
@@ -324,12 +328,6 @@ function flattenComments(value: unknown): RemoteComment[] {
324
328
  );
325
329
  }
326
330
 
327
- function issueNumberFromTask(content: string): number | null {
328
- const value = parseTaskFrontmatter(content).issue_number;
329
- const number = Number(value);
330
- return Number.isInteger(number) && number > 0 ? number : null;
331
- }
332
-
333
331
  function listRemoteComments(client: PlatformClient, repo: string, issue: number, cwd: string) {
334
332
  const result = client.json<unknown>([
335
333
  'api', '--paginate', '--slurp', `repos/${repo}/issues/${issue}/comments?per_page=100`
@@ -453,11 +451,18 @@ async function syncPlatformComment(taskRef: string, options: SyncOptions): Promi
453
451
  }
454
452
  const taskContent = fs.readFileSync(resolved.taskMdPath, 'utf8');
455
453
  let issueIdentityFromTask: ReturnType<typeof taskIssueIdentity>;
456
- try { issueIdentityFromTask = taskIssueIdentity(parseTaskFrontmatter(taskContent), undefined, options.runtimeVersion); }
454
+ try { issueIdentityFromTask = taskIssueIdentity(parseTaskFrontmatter(taskContent)); }
457
455
  catch (error) { return platformResult('failed', { error: { ...taskIssueIdentityError(error), retryable: false } }); }
458
456
  if (!issueIdentityFromTask) {
459
457
  return platformResult('no-op', {
460
- error: { code: 'ISSUE_NOT_LINKED', message: 'Task has no valid issue_number', retryable: false }
458
+ error: { code: 'ISSUE_NOT_LINKED', message: 'Task has no valid platform issue identity', retryable: false }
459
+ });
460
+ }
461
+ if (options.kind === 'task' && isTaskCommentTooLarge(taskContent)) {
462
+ return platformResult('no-op', {
463
+ resource: { kind: 'issue', number: resourceIdentityNumber(issueIdentityFromTask), identity: issueIdentityFromTask },
464
+ operations: [{ name: `comment:${MARKERS.task(resolved.taskId)}`, status: 'skipped', reasonCode: 'COMMENT_PAYLOAD_TOO_LARGE' }],
465
+ error: null
461
466
  });
462
467
  }
463
468
  let desired: RenderedChunk[];
@@ -615,7 +620,7 @@ async function checkPlatformCommentOwner(taskRef: string, options: { cwd?: strin
615
620
  if (!resolved.ok) return platformResult('failed', { error: { code: resolved.code, message: resolved.message, retryable: false } });
616
621
  const content = fs.readFileSync(resolved.taskMdPath, 'utf8');
617
622
  let issueIdentity: ReturnType<typeof taskIssueIdentity>;
618
- try { issueIdentity = taskIssueIdentity(parseTaskFrontmatter(content), undefined, options.runtimeVersion); }
623
+ try { issueIdentity = taskIssueIdentity(parseTaskFrontmatter(content)); }
619
624
  catch (error) { return platformResult('failed', { error: { ...taskIssueIdentityError(error), retryable: false } }); }
620
625
  if (!issueIdentity) return platformResult('no-op', { error: { code: 'ISSUE_NOT_LINKED', message: 'Task has no valid platform issue identity', retryable: false } });
621
626
  const loaded = await resolvePlatformProviderContext({ cwd: resolved.repoRoot, client: options.client });
@@ -641,6 +646,7 @@ async function checkPlatformCommentOwner(taskRef: string, options: { cwd?: strin
641
646
  }
642
647
 
643
648
  export {
649
+ COMMENT_BYTE_LIMIT,
644
650
  MARKERS,
645
651
  chunkArtifactComment,
646
652
  findMarkerComments,
@@ -649,6 +655,7 @@ export {
649
655
  listPlatformComments,
650
656
  normalizeCommentContent,
651
657
  renderTaskComment,
658
+ isTaskCommentTooLarge,
652
659
  syncPlatformComment,
653
660
  validateRelatedMarkerSet,
654
661
  writeComment