@fitlab-ai/agent-infra 0.8.5 → 0.9.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 (425) hide show
  1. package/bin/cli.ts +2 -2
  2. package/dist/bin/cli.js +2 -2
  3. package/dist/bin/internal-cli.js +98 -0
  4. package/dist/lib/decide.js +81 -90
  5. package/dist/lib/defaults.json +1 -0
  6. package/dist/lib/git/review-snapshot.js +79 -0
  7. package/dist/lib/git/workflow.js +101 -0
  8. package/dist/lib/internal/git-workflow.js +42 -0
  9. package/dist/lib/internal/platform-checks.js +119 -0
  10. package/dist/lib/internal/platform-comment.js +129 -0
  11. package/dist/lib/internal/platform-context.js +46 -0
  12. package/dist/lib/internal/platform-issue.js +142 -0
  13. package/dist/lib/internal/platform-pr.js +146 -0
  14. package/dist/lib/internal/release-workflow.js +217 -0
  15. package/dist/lib/internal/task-artifact.js +67 -0
  16. package/dist/lib/internal/task-context.js +43 -0
  17. package/dist/lib/internal/task-event.js +70 -0
  18. package/dist/lib/internal/task-ledger.js +114 -0
  19. package/dist/lib/internal/task-lifecycle.js +58 -0
  20. package/dist/lib/internal/task-short-id.js +83 -0
  21. package/dist/lib/internal/task-snapshot.js +47 -0
  22. package/dist/lib/internal/task-verify.js +50 -0
  23. package/dist/lib/internal/task-warning.js +74 -0
  24. package/dist/lib/platform/adapters.js +14 -0
  25. package/dist/lib/platform/context.js +146 -0
  26. package/dist/lib/platform/github-client.js +124 -0
  27. package/dist/lib/platform/issue-comments.js +409 -0
  28. package/dist/lib/platform/issue-metadata.js +183 -0
  29. package/dist/lib/platform/issues.js +617 -0
  30. package/dist/lib/platform/metadata-labels.js +28 -0
  31. package/dist/lib/platform/pr-checks.js +216 -0
  32. package/dist/lib/platform/pr-summary.js +88 -0
  33. package/dist/lib/platform/pull-request-metadata.js +38 -0
  34. package/dist/lib/platform/pull-requests.js +338 -0
  35. package/dist/lib/platform/releases.js +82 -0
  36. package/dist/lib/platform/types.js +22 -0
  37. package/dist/lib/platform/verification-required.js +78 -0
  38. package/dist/lib/platform/verification-sync.js +1014 -0
  39. package/dist/lib/platform/verification.js +6 -0
  40. package/dist/lib/release/channels.js +31 -0
  41. package/dist/lib/release/workflow.js +32 -0
  42. package/dist/lib/render.js +3 -2
  43. package/dist/lib/run/index.js +24 -7
  44. package/dist/lib/sandbox/capture.js +25 -3
  45. package/dist/lib/sandbox/commands/create.js +36 -22
  46. package/dist/lib/sandbox/commands/enter.js +34 -11
  47. package/dist/lib/sandbox/commands/list-running.js +10 -8
  48. package/dist/lib/sandbox/commands/show.js +2 -2
  49. package/dist/lib/sandbox/commands/start.js +53 -15
  50. package/dist/lib/sandbox/index.js +6 -6
  51. package/dist/lib/sandbox/mounts.js +36 -0
  52. package/dist/lib/sandbox/recovery.js +562 -0
  53. package/dist/lib/sandbox/task-resolver.js +5 -1
  54. package/dist/lib/sandbox/tools.js +19 -0
  55. package/dist/lib/server/protocol.js +5 -5
  56. package/dist/lib/task/activity-log.js +61 -0
  57. package/dist/lib/task/artifact-lifecycle.js +427 -0
  58. package/dist/lib/task/command-options.js +30 -0
  59. package/dist/lib/task/commands/cat.js +36 -6
  60. package/dist/lib/task/commands/decisions.js +80 -46
  61. package/dist/lib/task/commands/files.js +21 -7
  62. package/dist/lib/task/commands/grep.js +55 -7
  63. package/dist/lib/task/commands/issue-body.js +23 -14
  64. package/dist/lib/task/commands/log.js +27 -70
  65. package/dist/lib/task/commands/show.js +20 -7
  66. package/dist/lib/task/commands/status.js +18 -8
  67. package/dist/lib/task/decision-intents.js +154 -0
  68. package/dist/lib/task/decision-items.js +53 -0
  69. package/dist/lib/task/events.js +318 -0
  70. package/dist/lib/task/frontmatter.js +159 -1
  71. package/dist/lib/task/implementation-inputs.js +117 -0
  72. package/dist/lib/task/index.js +12 -9
  73. package/dist/lib/task/issue-form.js +19 -6
  74. package/dist/lib/task/ledger-intents.js +185 -0
  75. package/dist/lib/task/ledger.js +65 -35
  76. package/dist/lib/task/lifecycle.js +484 -0
  77. package/dist/lib/task/resolve-ref.js +152 -32
  78. package/dist/lib/task/review-artifacts.js +101 -0
  79. package/dist/lib/task/review-fingerprint.js +46 -0
  80. package/dist/lib/task/sections.js +358 -4
  81. package/dist/lib/task/short-id.js +292 -7
  82. package/dist/lib/task/snapshot.js +95 -0
  83. package/dist/lib/task/verification-checks.js +8 -0
  84. package/dist/lib/task/verification-config.js +14 -0
  85. package/dist/lib/task/verification-engine.js +906 -0
  86. package/dist/lib/task/verification-review.js +3 -0
  87. package/dist/lib/task/verification-types.js +2 -0
  88. package/dist/lib/task/verification.js +113 -0
  89. package/dist/lib/task/workflow-warning-intents.js +131 -0
  90. package/dist/lib/task/workflow-warnings.js +10 -78
  91. package/dist/lib/task/write.js +241 -0
  92. package/lib/decide.ts +57 -97
  93. package/lib/defaults.json +1 -0
  94. package/lib/git/review-snapshot.ts +73 -0
  95. package/lib/git/workflow.ts +101 -0
  96. package/lib/internal/git-workflow.ts +37 -0
  97. package/lib/internal/platform-checks.ts +101 -0
  98. package/lib/internal/platform-comment.ts +99 -0
  99. package/lib/internal/platform-context.ts +33 -0
  100. package/lib/internal/platform-issue.ts +116 -0
  101. package/lib/internal/platform-pr.ts +119 -0
  102. package/lib/internal/release-workflow.ts +186 -0
  103. package/lib/internal/task-artifact.ts +47 -0
  104. package/lib/internal/task-context.ts +35 -0
  105. package/lib/internal/task-event.ts +51 -0
  106. package/lib/internal/task-ledger.ts +86 -0
  107. package/lib/internal/task-lifecycle.ts +41 -0
  108. package/lib/internal/task-short-id.ts +55 -0
  109. package/lib/internal/task-snapshot.ts +32 -0
  110. package/lib/internal/task-verify.ts +33 -0
  111. package/lib/internal/task-warning.ts +50 -0
  112. package/lib/platform/adapters.ts +30 -0
  113. package/lib/platform/context.ts +164 -0
  114. package/lib/platform/github-client.ts +146 -0
  115. package/lib/platform/issue-comments.ts +479 -0
  116. package/lib/platform/issue-metadata.ts +250 -0
  117. package/lib/platform/issues.ts +691 -0
  118. package/lib/platform/metadata-labels.ts +33 -0
  119. package/lib/platform/pr-checks.ts +246 -0
  120. package/lib/platform/pr-summary.ts +90 -0
  121. package/lib/platform/pull-request-metadata.ts +69 -0
  122. package/lib/platform/pull-requests.ts +380 -0
  123. package/lib/platform/releases.ts +71 -0
  124. package/lib/platform/types.ts +74 -0
  125. package/lib/platform/verification-required.ts +83 -0
  126. package/{runtime/platform-adapters/platform-sync.github.js → lib/platform/verification-sync.ts} +198 -367
  127. package/lib/platform/verification.ts +11 -0
  128. package/lib/release/channels.ts +30 -0
  129. package/lib/release/workflow.ts +31 -0
  130. package/lib/render.ts +3 -2
  131. package/lib/run/index.ts +25 -7
  132. package/lib/sandbox/capture.ts +29 -3
  133. package/lib/sandbox/commands/create.ts +43 -25
  134. package/lib/sandbox/commands/enter.ts +38 -11
  135. package/lib/sandbox/commands/list-running.ts +10 -8
  136. package/lib/sandbox/commands/show.ts +2 -2
  137. package/lib/sandbox/commands/start.ts +50 -16
  138. package/lib/sandbox/index.ts +6 -6
  139. package/lib/sandbox/mounts.ts +55 -0
  140. package/lib/sandbox/recovery.ts +828 -0
  141. package/lib/sandbox/task-resolver.ts +5 -1
  142. package/lib/sandbox/tools.ts +31 -0
  143. package/lib/server/protocol.ts +5 -5
  144. package/lib/task/activity-log.ts +62 -0
  145. package/lib/task/artifact-lifecycle.ts +484 -0
  146. package/lib/task/command-options.ts +32 -0
  147. package/lib/task/commands/cat.ts +22 -9
  148. package/lib/task/commands/decisions.ts +49 -47
  149. package/lib/task/commands/files.ts +14 -6
  150. package/lib/task/commands/grep.ts +34 -7
  151. package/lib/task/commands/issue-body.ts +16 -16
  152. package/lib/task/commands/log.ts +17 -70
  153. package/lib/task/commands/show.ts +14 -6
  154. package/lib/task/commands/status.ts +17 -7
  155. package/lib/task/decision-intents.ts +163 -0
  156. package/lib/task/decision-items.ts +64 -0
  157. package/lib/task/events.ts +320 -0
  158. package/lib/task/frontmatter.ts +202 -2
  159. package/lib/task/implementation-inputs.ts +137 -0
  160. package/lib/task/index.ts +12 -9
  161. package/lib/task/issue-form.ts +20 -6
  162. package/lib/task/ledger-intents.ts +201 -0
  163. package/lib/task/ledger.ts +77 -31
  164. package/lib/task/lifecycle.ts +458 -0
  165. package/lib/task/resolve-ref.ts +197 -36
  166. package/{templates/.agents/scripts/lib/review-artifacts.js → lib/task/review-artifacts.ts} +11 -12
  167. package/{templates/.agents/scripts/lib/post-review-commit.js → lib/task/review-fingerprint.ts} +17 -12
  168. package/lib/task/sections.ts +486 -4
  169. package/lib/task/short-id.ts +403 -9
  170. package/lib/task/snapshot.ts +143 -0
  171. package/lib/task/verification-checks.ts +9 -0
  172. package/lib/task/verification-config.ts +20 -0
  173. package/{templates/.agents/scripts/validate-artifact.js → lib/task/verification-engine.ts} +199 -406
  174. package/lib/task/verification-review.ts +9 -0
  175. package/lib/task/verification-types.ts +29 -0
  176. package/lib/task/verification.ts +156 -0
  177. package/lib/task/workflow-warning-intents.ts +142 -0
  178. package/lib/task/workflow-warnings.ts +10 -78
  179. package/lib/task/write.ts +468 -0
  180. package/package.json +4 -2
  181. package/templates/.agents/README.en.md +4 -3
  182. package/templates/.agents/README.zh-CN.md +4 -3
  183. package/templates/.agents/rules/README.en.md +6 -5
  184. package/templates/.agents/rules/README.zh-CN.md +6 -5
  185. package/templates/.agents/rules/create-issue.en.md +1 -1
  186. package/templates/.agents/rules/create-issue.github.en.md +5 -184
  187. package/templates/.agents/rules/create-issue.github.zh-CN.md +12 -178
  188. package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
  189. package/templates/.agents/rules/human-decision-context.en.md +36 -0
  190. package/templates/.agents/rules/human-decision-context.zh-CN.md +36 -0
  191. package/templates/.agents/rules/issue-fields.github.en.md +4 -148
  192. package/templates/.agents/rules/issue-fields.github.zh-CN.md +9 -144
  193. package/templates/.agents/rules/issue-pr-commands.en.md +43 -3
  194. package/templates/.agents/rules/issue-pr-commands.github.en.md +15 -220
  195. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +23 -213
  196. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +45 -3
  197. package/templates/.agents/rules/issue-sync.en.md +1 -1
  198. package/templates/.agents/rules/issue-sync.github.en.md +14 -301
  199. package/templates/.agents/rules/issue-sync.github.zh-CN.md +36 -287
  200. package/templates/.agents/rules/issue-sync.zh-CN.md +1 -1
  201. package/templates/.agents/rules/milestone-inference.en.md +1 -1
  202. package/templates/.agents/rules/milestone-inference.github.en.md +7 -119
  203. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +8 -108
  204. package/templates/.agents/rules/milestone-inference.zh-CN.md +1 -1
  205. package/templates/.agents/rules/next-step-output.en.md +12 -11
  206. package/templates/.agents/rules/next-step-output.zh-CN.md +12 -11
  207. package/templates/.agents/rules/no-mid-flow-questions.en.md +3 -3
  208. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +3 -3
  209. package/templates/.agents/rules/pr-checks-commands.en.md +16 -3
  210. package/templates/.agents/rules/pr-checks-commands.github.en.md +10 -54
  211. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +19 -47
  212. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +30 -3
  213. package/templates/.agents/rules/pr-sync.en.md +30 -3
  214. package/templates/.agents/rules/pr-sync.github.en.md +12 -115
  215. package/templates/.agents/rules/pr-sync.github.zh-CN.md +26 -104
  216. package/templates/.agents/rules/pr-sync.zh-CN.md +43 -3
  217. package/templates/.agents/rules/review-handshake.en.md +8 -5
  218. package/templates/.agents/rules/review-handshake.zh-CN.md +8 -5
  219. package/templates/.agents/rules/task-management.en.md +11 -2
  220. package/templates/.agents/rules/task-management.zh-CN.md +11 -3
  221. package/templates/.agents/rules/task-short-id.en.md +25 -29
  222. package/templates/.agents/rules/task-short-id.zh-CN.md +20 -23
  223. package/templates/.agents/scripts/lib/agent-infra-package.js +1 -9
  224. package/templates/.agents/scripts/task-short-id.js +71 -533
  225. package/templates/.agents/skills/analyze-task/SKILL.en.md +22 -55
  226. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +26 -59
  227. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -3
  228. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -3
  229. package/templates/.agents/skills/block-task/SKILL.en.md +21 -47
  230. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +23 -47
  231. package/templates/.agents/skills/block-task/config/verify.json +1 -2
  232. package/templates/.agents/skills/cancel-task/SKILL.en.md +16 -45
  233. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +16 -45
  234. package/templates/.agents/skills/cancel-task/config/verify.json +1 -2
  235. package/templates/.agents/skills/check-task/SKILL.en.md +6 -3
  236. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +6 -3
  237. package/templates/.agents/skills/close-codescan/SKILL.en.md +6 -24
  238. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +6 -24
  239. package/templates/.agents/skills/close-dependabot/SKILL.en.md +6 -24
  240. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +6 -24
  241. package/templates/.agents/skills/code-task/SKILL.en.md +22 -35
  242. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +28 -44
  243. package/templates/.agents/skills/code-task/config/verify.en.json +3 -3
  244. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +3 -3
  245. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +13 -9
  246. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +13 -9
  247. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +1 -1
  248. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +1 -1
  249. package/templates/.agents/skills/code-task/reference/report-template.en.md +11 -1
  250. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +11 -1
  251. package/templates/.agents/skills/commit/SKILL.en.md +13 -11
  252. package/templates/.agents/skills/commit/SKILL.zh-CN.md +13 -11
  253. package/templates/.agents/skills/commit/config/verify.json +1 -2
  254. package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -11
  255. package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -11
  256. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +4 -8
  257. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +4 -8
  258. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +6 -18
  259. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +5 -17
  260. package/templates/.agents/skills/commit/reference/task-status-update.en.md +13 -0
  261. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +13 -0
  262. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +13 -36
  263. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +13 -36
  264. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -3
  265. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -3
  266. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +10 -54
  267. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +10 -79
  268. package/templates/.agents/skills/complete-task/SKILL.en.md +59 -63
  269. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +59 -63
  270. package/templates/.agents/skills/complete-task/config/verify.en.json +11 -7
  271. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +11 -7
  272. package/templates/.agents/skills/create-pr/SKILL.en.md +19 -44
  273. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +19 -43
  274. package/templates/.agents/skills/create-pr/config/verify.json +1 -2
  275. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +8 -12
  276. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +7 -11
  277. package/templates/.agents/skills/create-task/SKILL.en.md +12 -13
  278. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +12 -13
  279. package/templates/.agents/skills/create-task/config/verify.json +1 -2
  280. package/templates/.agents/skills/import-codescan/SKILL.en.md +2 -2
  281. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +2 -2
  282. package/templates/.agents/skills/import-codescan/config/verify.json +1 -2
  283. package/templates/.agents/skills/import-dependabot/SKILL.en.md +2 -2
  284. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +2 -2
  285. package/templates/.agents/skills/import-dependabot/config/verify.json +1 -2
  286. package/templates/.agents/skills/import-issue/SKILL.en.md +9 -13
  287. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +10 -14
  288. package/templates/.agents/skills/import-issue/config/verify.json +1 -2
  289. package/templates/.agents/skills/plan-task/SKILL.en.md +17 -42
  290. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +22 -49
  291. package/templates/.agents/skills/plan-task/config/verify.en.json +1 -3
  292. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -3
  293. package/templates/.agents/skills/post-release/SKILL.en.md +11 -81
  294. package/templates/.agents/skills/post-release/SKILL.zh-CN.md +8 -78
  295. package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
  296. package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
  297. package/templates/.agents/skills/release/SKILL.en.md +16 -163
  298. package/templates/.agents/skills/release/SKILL.zh-CN.md +15 -162
  299. package/templates/.agents/skills/restore-task/SKILL.en.md +11 -29
  300. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +11 -29
  301. package/templates/.agents/skills/restore-task/config/verify.json +1 -2
  302. package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -25
  303. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +13 -33
  304. package/templates/.agents/skills/review-analysis/config/verify.en.json +3 -4
  305. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +3 -4
  306. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +9 -12
  307. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +9 -12
  308. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +9 -2
  309. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +9 -2
  310. package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +7 -0
  311. package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +7 -0
  312. package/templates/.agents/skills/review-code/SKILL.en.md +22 -36
  313. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +23 -41
  314. package/templates/.agents/skills/review-code/config/verify.en.json +3 -4
  315. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +3 -4
  316. package/templates/.agents/skills/review-code/reference/output-templates.en.md +56 -18
  317. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +56 -18
  318. package/templates/.agents/skills/review-code/reference/report-template.en.md +11 -4
  319. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +11 -4
  320. package/templates/.agents/skills/review-code/reference/review-criteria.en.md +7 -0
  321. package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +7 -0
  322. package/templates/.agents/skills/review-plan/SKILL.en.md +13 -25
  323. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +13 -33
  324. package/templates/.agents/skills/review-plan/config/verify.en.json +3 -4
  325. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +3 -4
  326. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +9 -12
  327. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +9 -12
  328. package/templates/.agents/skills/review-plan/reference/report-template.en.md +9 -2
  329. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +9 -2
  330. package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +7 -0
  331. package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +7 -0
  332. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +1 -2
  333. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +1 -2
  334. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +3 -15
  335. package/templates/.agents/skills/watch-pr/SKILL.en.md +24 -14
  336. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +25 -15
  337. package/templates/.agents/skills/watch-pr/config/verify.json +1 -2
  338. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +2 -2
  339. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +2 -2
  340. package/templates/.agents/templates/task.en.md +6 -1
  341. package/templates/.agents/templates/task.zh-CN.md +6 -1
  342. package/templates/.claude/commands/analyze-task.en.md +1 -1
  343. package/templates/.claude/commands/analyze-task.zh-CN.md +1 -1
  344. package/templates/.claude/commands/block-task.en.md +1 -1
  345. package/templates/.claude/commands/block-task.zh-CN.md +1 -1
  346. package/templates/.claude/commands/cancel-task.en.md +1 -1
  347. package/templates/.claude/commands/cancel-task.zh-CN.md +1 -1
  348. package/templates/.claude/commands/check-task.en.md +1 -1
  349. package/templates/.claude/commands/check-task.zh-CN.md +1 -1
  350. package/templates/.claude/commands/code-task.en.md +1 -1
  351. package/templates/.claude/commands/code-task.zh-CN.md +1 -1
  352. package/templates/.claude/commands/commit.en.md +1 -0
  353. package/templates/.claude/commands/commit.zh-CN.md +1 -0
  354. package/templates/.claude/commands/complete-manual-validation.en.md +1 -1
  355. package/templates/.claude/commands/complete-manual-validation.zh-CN.md +1 -1
  356. package/templates/.claude/commands/complete-task.en.md +1 -1
  357. package/templates/.claude/commands/complete-task.zh-CN.md +1 -1
  358. package/templates/.claude/commands/create-pr.en.md +1 -1
  359. package/templates/.claude/commands/create-pr.zh-CN.md +1 -1
  360. package/templates/.claude/commands/plan-task.en.md +1 -1
  361. package/templates/.claude/commands/plan-task.zh-CN.md +1 -1
  362. package/templates/.claude/commands/review-analysis.en.md +1 -1
  363. package/templates/.claude/commands/review-analysis.zh-CN.md +1 -1
  364. package/templates/.claude/commands/review-code.en.md +1 -1
  365. package/templates/.claude/commands/review-code.zh-CN.md +1 -1
  366. package/templates/.claude/commands/review-plan.en.md +1 -1
  367. package/templates/.claude/commands/review-plan.zh-CN.md +1 -1
  368. package/templates/.claude/commands/watch-pr.en.md +1 -1
  369. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  370. package/templates/.gemini/commands/_project_/analyze-task.en.toml +2 -0
  371. package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +2 -0
  372. package/templates/.gemini/commands/_project_/block-task.en.toml +2 -0
  373. package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +2 -0
  374. package/templates/.gemini/commands/_project_/cancel-task.en.toml +2 -0
  375. package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +2 -0
  376. package/templates/.gemini/commands/_project_/check-task.en.toml +2 -0
  377. package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +2 -0
  378. package/templates/.gemini/commands/_project_/code-task.en.toml +2 -0
  379. package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +2 -0
  380. package/templates/.gemini/commands/_project_/commit.en.toml +4 -0
  381. package/templates/.gemini/commands/_project_/commit.zh-CN.toml +4 -0
  382. package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +2 -0
  383. package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +2 -0
  384. package/templates/.gemini/commands/_project_/complete-task.en.toml +2 -0
  385. package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +2 -0
  386. package/templates/.gemini/commands/_project_/create-pr.en.toml +2 -0
  387. package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +2 -0
  388. package/templates/.gemini/commands/_project_/plan-task.en.toml +2 -0
  389. package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +2 -0
  390. package/templates/.gemini/commands/_project_/review-analysis.en.toml +2 -0
  391. package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +2 -0
  392. package/templates/.gemini/commands/_project_/review-code.en.toml +2 -0
  393. package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +2 -0
  394. package/templates/.gemini/commands/_project_/review-plan.en.toml +2 -0
  395. package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +2 -0
  396. package/templates/.gemini/commands/_project_/watch-pr.en.toml +2 -0
  397. package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +2 -0
  398. package/templates/.git-hooks/check-large-files.cjs +92 -0
  399. package/templates/.git-hooks/check-version-format.sh +5 -1
  400. package/templates/.git-hooks/pre-commit +1 -0
  401. package/templates/.opencode/commands/analyze-task.en.md +1 -1
  402. package/templates/.opencode/commands/analyze-task.zh-CN.md +1 -1
  403. package/templates/.opencode/commands/check-task.en.md +1 -1
  404. package/templates/.opencode/commands/check-task.zh-CN.md +1 -1
  405. package/templates/.opencode/commands/code-task.en.md +1 -1
  406. package/templates/.opencode/commands/code-task.zh-CN.md +1 -1
  407. package/templates/.opencode/commands/commit.en.md +2 -0
  408. package/templates/.opencode/commands/commit.zh-CN.md +2 -0
  409. package/templates/.opencode/commands/complete-task.en.md +1 -1
  410. package/templates/.opencode/commands/complete-task.zh-CN.md +1 -1
  411. package/templates/.opencode/commands/plan-task.en.md +1 -1
  412. package/templates/.opencode/commands/plan-task.zh-CN.md +1 -1
  413. package/templates/.opencode/commands/review-analysis.en.md +1 -1
  414. package/templates/.opencode/commands/review-analysis.zh-CN.md +1 -1
  415. package/templates/.opencode/commands/review-code.en.md +1 -1
  416. package/templates/.opencode/commands/review-code.zh-CN.md +1 -1
  417. package/templates/.opencode/commands/review-plan.en.md +1 -1
  418. package/templates/.opencode/commands/review-plan.zh-CN.md +1 -1
  419. package/templates/.agents/scripts/platform-adapters/platform-sync.github.js +0 -40
  420. package/templates/.agents/scripts/platform-adapters/platform-sync.js +0 -13
  421. package/templates/.agents/scripts/review-diff-fingerprint.js +0 -170
  422. package/templates/.agents/scripts/workflow-warnings.js +0 -290
  423. package/templates/.agents/skills/code-task/scripts/detect-mode.js +0 -257
  424. package/templates/.agents/skills/release/scripts/manage-milestones.github.sh +0 -80
  425. package/templates/.agents/skills/release/scripts/manage-milestones.sh +0 -6
@@ -1,10 +1,17 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import process from "node:process";
4
- import spawn from "cross-spawn";
4
+ import { execFileSync } from "node:child_process";
5
+
6
+ import { createGitHubClient } from "./github-client.ts";
7
+ import { resolvePlatformContext } from "./context.ts";
8
+ import { hasCheckedRequirement, resolveRequirementSection } from "./issue-metadata.ts";
9
+ import { inspectGitHubIssueMetadata, requirementSectionAnchors } from "./issues.ts";
10
+ import { listRemoteComments } from "./issue-comments.ts";
11
+ import { taskTypeLabel } from "./metadata-labels.ts";
12
+ import { inspectGitHubPullRequest } from "./pull-requests.ts";
5
13
 
6
14
  const CHECK_TYPE = "platform-sync";
7
- const DEFAULT_RETRY_DELAYS_MS = [3000, 10000];
8
15
  const VERSION_LINE_REGEX = /^[0-9]+\.[0-9]+\.x$/;
9
16
  const FRONTMATTER_FIELD_MAP = {
10
17
  priority: "Priority",
@@ -12,17 +19,18 @@ const FRONTMATTER_FIELD_MAP = {
12
19
  start_date: "Start date",
13
20
  target_date: "Target date"
14
21
  };
15
- const OPTION_LOCALIZATION = {
22
+ const OPTION_LOCALIZATION: Record<string, string> = {
16
23
  "紧急": "Urgent",
17
24
  "高": "High",
18
25
  "中": "Medium",
19
26
  "低": "Low"
20
27
  };
21
28
 
22
- let activeShared = null;
29
+ let activeShared: any = null;
23
30
  let repoRoot = "";
31
+ const githubClient = createGitHubClient();
24
32
 
25
- export function getDefaults() {
33
+ export function getDefaults(): any {
26
34
  return {
27
35
  statusLabels: {
28
36
  pendingDesignWork: "status: pending-design-work",
@@ -42,7 +50,7 @@ export function getDefaults() {
42
50
  };
43
51
  }
44
52
 
45
- function getShared() {
53
+ function getShared(): any {
46
54
  if (!activeShared) {
47
55
  throw new Error("platform-sync adapter shared utilities are unavailable");
48
56
  }
@@ -50,51 +58,51 @@ function getShared() {
50
58
  return activeShared;
51
59
  }
52
60
 
53
- function loadTask(...args) {
61
+ function loadTask(...args: any[]): any {
54
62
  return getShared().loadTask(...args);
55
63
  }
56
64
 
57
- function getCheckedRequirements(...args) {
65
+ function getCheckedRequirements(...args: any[]): any {
58
66
  return getShared().getCheckedRequirements(...args);
59
67
  }
60
68
 
61
- function normalizeContent(...args) {
69
+ function normalizeContent(...args: any[]): any {
62
70
  return getShared().normalizeContent(...args);
63
71
  }
64
72
 
65
- function isBlank(...args) {
73
+ function isBlank(...args: any[]): any {
66
74
  return getShared().isBlank(...args);
67
75
  }
68
76
 
69
- function escapeRegExp(...args) {
77
+ function escapeRegExp(...args: any[]): any {
70
78
  return getShared().escapeRegExp(...args);
71
79
  }
72
80
 
73
- function passResult(...args) {
81
+ function passResult(...args: any[]): any {
74
82
  return getShared().passResult(...args);
75
83
  }
76
84
 
77
- function failResult(...args) {
85
+ function failResult(...args: any[]): any {
78
86
  return getShared().failResult(...args);
79
87
  }
80
88
 
81
- function blockedResult(...args) {
89
+ function blockedResult(...args: any[]): any {
82
90
  return getShared().blockedResult(...args);
83
91
  }
84
92
 
85
- function safeStat(...args) {
93
+ function safeStat(...args: any[]): any {
86
94
  return getShared().safeStat(...args);
87
95
  }
88
96
 
89
- function parseIssueNumber(...args) {
97
+ function parseIssueNumber(...args: any[]): any {
90
98
  return getShared().parseIssueNumber(...args);
91
99
  }
92
100
 
93
- function parsePrNumber(...args) {
101
+ function parsePrNumber(...args: any[]): any {
94
102
  return getShared().parsePrNumber(...args);
95
103
  }
96
104
 
97
- export function check({ taskDir, config, artifactFile }, shared) {
105
+ export function check({ taskDir, config, artifactFile }: any, shared: any): any {
98
106
  activeShared = shared;
99
107
  repoRoot = shared.repoRoot;
100
108
  const context = buildSyncContext({ taskDir, config, artifactFile });
@@ -136,7 +144,7 @@ export function check({ taskDir, config, artifactFile }, shared) {
136
144
  return passResult(CHECK_TYPE, `GitHub sync checks passed for Issue #${context.issueNumber}`);
137
145
  }
138
146
 
139
- function buildSyncContext({ taskDir, config, artifactFile }) {
147
+ function buildSyncContext({ taskDir, config, artifactFile }: any): any {
140
148
  const task = loadTask(taskDir);
141
149
  if (!task.ok) {
142
150
  return { earlyReturn: failResult(CHECK_TYPE, task.message) };
@@ -155,12 +163,20 @@ function buildSyncContext({ taskDir, config, artifactFile }) {
155
163
  return { earlyReturn: passResult(CHECK_TYPE, "Skipped: platform-sync not required for this task") };
156
164
  }
157
165
 
158
- const upstreamRepo = resolveUpstreamRepo(taskDir);
159
- if (!upstreamRepo.ok) {
160
- return { earlyReturn: blockedResult(CHECK_TYPE, upstreamRepo.message, "network_error") };
166
+ const platformContext = resolvePlatformContext({ cwd: repoRoot, client: githubClient });
167
+ if (platformContext.status === "failed") {
168
+ return { earlyReturn: failResult(CHECK_TYPE, platformContext.error?.message || "Platform context failed", "check_failed") };
169
+ }
170
+ if (platformContext.status === "blocked") {
171
+ return { earlyReturn: blockedResult(CHECK_TYPE, platformContext.error?.message || "Platform context blocked", "network_error") };
172
+ }
173
+ if (!platformContext.platform.repository) {
174
+ if (platformContext.error?.code === "REMOTE_MISSING" || platformContext.error?.code === "REMOTE_INVALID") {
175
+ return { earlyReturn: blockedResult(CHECK_TYPE, platformContext.error.message, "network_error") };
176
+ }
177
+ return { earlyReturn: passResult(CHECK_TYPE, `Skipped: ${platformContext.error?.message || "platform unavailable"}`) };
161
178
  }
162
- const permissions = detectPermissions(upstreamRepo.value, taskDir);
163
- const repoOwnerType = detectRepoOwnerType(upstreamRepo.value, taskDir);
179
+ const repoOwnerType = detectRepoOwnerType(platformContext.platform.repository, taskDir);
164
180
  const expectedValues = resolveExpectedValues(config);
165
181
  if (!expectedValues.ok) {
166
182
  return { earlyReturn: failResult(CHECK_TYPE, expectedValues.message, "check_failed") };
@@ -182,17 +198,17 @@ function buildSyncContext({ taskDir, config, artifactFile }) {
182
198
  artifactPath,
183
199
  issueNumber,
184
200
  prNumber,
185
- upstreamRepo: upstreamRepo.value,
201
+ upstreamRepo: platformContext.platform.repository,
186
202
  repoOwnerType,
187
- hasTriage: permissions.hasTriage,
188
- hasPush: permissions.hasPush,
203
+ hasTriage: platformContext.capabilities.triage,
204
+ hasPush: platformContext.capabilities.push,
189
205
  expectedStatusLabel: expectedValues.statusLabel,
190
206
  marker,
191
207
  prMarker
192
208
  };
193
209
  }
194
210
 
195
- function resolveExpectedValues(config) {
211
+ function resolveExpectedValues(config: any): any {
196
212
  const defaults = getDefaults();
197
213
  const statusLabel = resolveDefaultValue({
198
214
  collection: defaults.statusLabels,
@@ -232,7 +248,7 @@ function resolveExpectedValues(config) {
232
248
  };
233
249
  }
234
250
 
235
- function resolveDefaultValue({ collection, key, value, configKey }) {
251
+ function resolveDefaultValue({ collection, key, value, configKey }: any): any {
236
252
  if (!key) {
237
253
  return { ok: true, value: value || null };
238
254
  }
@@ -245,30 +261,28 @@ function resolveDefaultValue({ collection, key, value, configKey }) {
245
261
  return { ok: true, value: resolvedValue };
246
262
  }
247
263
 
248
- function fetchRemoteData(context) {
249
- let issueResult = withRetry(() => ghJson([
250
- "issue",
251
- "view",
252
- String(context.issueNumber),
253
- "-R",
264
+ function fetchRemoteData(context: any): any {
265
+ const sharedIssue = inspectGitHubIssueMetadata(
266
+ githubClient,
254
267
  context.upstreamRepo,
255
- "--json",
256
- "state,labels,body,milestone"
257
- ], context.taskDir));
258
- if (!issueResult.ok && issueResult.type !== "check_failed") {
259
- const fallbackIssueResult = withRetry(() => ghJson([
260
- "api",
261
- `repos/${context.upstreamRepo}/issues/${context.issueNumber}`
262
- ], context.taskDir));
263
- if (fallbackIssueResult.ok) {
264
- issueResult = {
268
+ context.issueNumber,
269
+ context.taskDir
270
+ );
271
+ const issueResult = sharedIssue.ok
272
+ ? {
265
273
  ok: true,
266
- value: normalizeIssuePayload(fallbackIssueResult.value)
274
+ value: {
275
+ state: sharedIssue.value.state.toUpperCase(),
276
+ labels: sharedIssue.value.labels.map((name) => ({ name })),
277
+ body: sharedIssue.value.body,
278
+ milestone: sharedIssue.value.milestone ? { title: sharedIssue.value.milestone } : null
279
+ }
280
+ }
281
+ : {
282
+ ok: false,
283
+ type: sharedIssue.error.retryable ? "network_error" : "check_failed",
284
+ message: sharedIssue.error.message
267
285
  };
268
- } else {
269
- issueResult = fallbackIssueResult;
270
- }
271
- }
272
286
  if (!issueResult.ok) {
273
287
  return {
274
288
  earlyReturn: issueResult.type === "check_failed"
@@ -312,22 +326,22 @@ function fetchRemoteData(context) {
312
326
  };
313
327
  }
314
328
 
315
- const prCommentsResult = withRetry(() => ghPaginatedJson([
316
- "api",
317
- "--paginate",
318
- "--slurp",
319
- `repos/${context.upstreamRepo}/issues/${context.prNumber}/comments?per_page=100`
320
- ], context.taskDir));
329
+ const prCommentsResult = listRemoteComments(
330
+ githubClient,
331
+ context.upstreamRepo,
332
+ context.prNumber,
333
+ context.taskDir
334
+ );
321
335
 
322
336
  if (!prCommentsResult.ok) {
323
337
  return {
324
- earlyReturn: prCommentsResult.type === "check_failed"
325
- ? failResult(CHECK_TYPE, prCommentsResult.message, prCommentsResult.type)
326
- : blockedResult(CHECK_TYPE, prCommentsResult.message, prCommentsResult.type)
338
+ earlyReturn: prCommentsResult.error.retryable
339
+ ? blockedResult(CHECK_TYPE, prCommentsResult.error.message, "network_error")
340
+ : failResult(CHECK_TYPE, prCommentsResult.error.message, "check_failed")
327
341
  };
328
342
  }
329
343
 
330
- prComments = flattenComments(prCommentsResult.value);
344
+ prComments = prCommentsResult.value;
331
345
  }
332
346
 
333
347
  let issueType;
@@ -368,46 +382,37 @@ function fetchRemoteData(context) {
368
382
  let prLabels = null;
369
383
  let prMilestone;
370
384
  let prAssignees;
385
+ let prHeadSha;
371
386
  if (((context.config.verify_in_labels_match_pr && context.hasTriage)
372
387
  || (context.config.verify_pr_type_label && context.hasTriage)
373
388
  || (context.config.verify_milestone && context.hasTriage)
374
- || (context.config.verify_pr_assignee && context.hasPush)) && context.prNumber) {
375
- const prFields = [];
376
- if (context.config.verify_in_labels_match_pr || context.config.verify_pr_type_label) {
377
- prFields.push("labels");
378
- }
379
- if (context.config.verify_milestone) {
380
- prFields.push("milestone");
381
- }
382
- if (context.config.verify_pr_assignee) {
383
- prFields.push("assignees");
384
- }
385
-
386
- const prResult = withRetry(() => ghJson([
387
- "pr",
388
- "view",
389
- String(context.prNumber),
390
- "--json",
391
- prFields.join(",")
392
- ], context.taskDir));
389
+ || (context.config.verify_pr_assignee && context.hasPush)
390
+ || context.config.verify_pr_comment_last_commit_matches_head) && context.prNumber) {
391
+ const prResult = inspectGitHubPullRequest(
392
+ githubClient,
393
+ context.upstreamRepo,
394
+ context.prNumber,
395
+ context.taskDir
396
+ );
393
397
 
394
398
  if (!prResult.ok) {
395
399
  return {
396
- earlyReturn: prResult.type === "check_failed"
397
- ? failResult(CHECK_TYPE, prResult.message, prResult.type)
398
- : blockedResult(CHECK_TYPE, prResult.message, prResult.type)
400
+ earlyReturn: prResult.error.retryable
401
+ ? blockedResult(CHECK_TYPE, prResult.error.message, "network_error")
402
+ : failResult(CHECK_TYPE, prResult.error.message, "check_failed")
399
403
  };
400
404
  }
401
405
 
402
406
  prLabels = (context.config.verify_in_labels_match_pr || context.config.verify_pr_type_label)
403
- ? extractLabelNames(prResult.value?.labels)
407
+ ? prResult.value.labels
404
408
  : null;
405
409
  prMilestone = context.config.verify_milestone
406
- ? prResult.value?.milestone ?? null
410
+ ? prResult.value.milestone ? { title: prResult.value.milestone } : null
407
411
  : undefined;
408
412
  prAssignees = context.config.verify_pr_assignee
409
- ? (prResult.value?.assignees || []).map((a) => a.login).filter(Boolean)
413
+ ? prResult.value.assignees
410
414
  : undefined;
415
+ prHeadSha = prResult.value.head.sha;
411
416
  }
412
417
 
413
418
  return {
@@ -418,27 +423,16 @@ function fetchRemoteData(context) {
418
423
  issueType,
419
424
  issueFields,
420
425
  prMilestone,
421
- prAssignees
426
+ prAssignees,
427
+ prHeadSha
422
428
  };
423
429
  }
424
430
 
425
- function mapTaskTypeToLabel(taskType) {
426
- const mapping = {
427
- bug: "type: bug",
428
- bugfix: "type: bug",
429
- feature: "type: feature",
430
- enhancement: "type: enhancement",
431
- refactor: "type: enhancement",
432
- refactoring: "type: enhancement",
433
- documentation: "type: documentation",
434
- "dependency-upgrade": "type: dependency-upgrade",
435
- task: "type: task"
436
- };
437
-
438
- return mapping[taskType] || null;
431
+ function mapTaskTypeToLabel(taskType: any): any {
432
+ return taskTypeLabel(taskType);
439
433
  }
440
434
 
441
- function shouldFetchComments(config) {
435
+ function shouldFetchComments(config: any): any {
442
436
  return Boolean(
443
437
  config.expected_comment_marker
444
438
  || config.expected_comment_marker_key
@@ -450,7 +444,7 @@ function shouldFetchComments(config) {
450
444
  );
451
445
  }
452
446
 
453
- function flattenComments(value) {
447
+ function flattenComments(value: any): any {
454
448
  if (!Array.isArray(value)) {
455
449
  return [];
456
450
  }
@@ -458,7 +452,7 @@ function flattenComments(value) {
458
452
  return value.flatMap((page) => Array.isArray(page) ? page : []);
459
453
  }
460
454
 
461
- function checkStatusLabel(context, remoteData) {
455
+ function checkStatusLabel(context: any, remoteData: any): any {
462
456
  if (!context.expectedStatusLabel || !context.hasTriage) {
463
457
  return null;
464
458
  }
@@ -478,7 +472,7 @@ function checkStatusLabel(context, remoteData) {
478
472
  );
479
473
  }
480
474
 
481
- function checkClosedIssueStatusLabels(context, remoteData) {
475
+ function checkClosedIssueStatusLabels(context: any, remoteData: any): any {
482
476
  if (!context.config.verify_closed_issue_has_no_status_labels) {
483
477
  return null;
484
478
  }
@@ -488,7 +482,7 @@ function checkClosedIssueStatusLabels(context, remoteData) {
488
482
  }
489
483
 
490
484
  const statusLabels = extractLabelNames(remoteData.issue.labels)
491
- .filter((label) => label.startsWith("status:"));
485
+ .filter((label: any) => label.startsWith("status:"));
492
486
  if (statusLabels.length === 0) {
493
487
  return null;
494
488
  }
@@ -499,7 +493,7 @@ function checkClosedIssueStatusLabels(context, remoteData) {
499
493
  );
500
494
  }
501
495
 
502
- function checkCommentMarker(context, remoteData) {
496
+ function checkCommentMarker(context: any, remoteData: any): any {
503
497
  if (!context.marker) {
504
498
  return null;
505
499
  }
@@ -515,7 +509,7 @@ function checkCommentMarker(context, remoteData) {
515
509
  );
516
510
  }
517
511
 
518
- function checkPrCommentMarker(context, remoteData) {
512
+ function checkPrCommentMarker(context: any, remoteData: any): any {
519
513
  if (!context.prMarker) {
520
514
  return null;
521
515
  }
@@ -531,7 +525,7 @@ function checkPrCommentMarker(context, remoteData) {
531
525
  );
532
526
  }
533
527
 
534
- function checkPrCommentLastCommit(context, remoteData) {
528
+ function checkPrCommentLastCommit(context: any, remoteData: any): any {
535
529
  if (!context.config.verify_pr_comment_last_commit_matches_head) {
536
530
  return null;
537
531
  }
@@ -559,15 +553,9 @@ function checkPrCommentLastCommit(context, remoteData) {
559
553
  );
560
554
  }
561
555
 
562
- const headResult = resolvePrHeadSha(context);
563
- if (!headResult.ok) {
564
- return headResult.type === "check_failed"
565
- ? failResult(CHECK_TYPE, headResult.message, headResult.type)
566
- : blockedResult(CHECK_TYPE, headResult.message, headResult.type);
567
- }
568
-
569
- const expectedHead = String(headResult.value || "").trim();
570
- const actualHead = match[1].trim();
556
+ const expectedHead = String(remoteData.prHeadSha || "").trim();
557
+ if (!expectedHead) return blockedResult(CHECK_TYPE, "Unable to resolve the PR head SHA", "network_error");
558
+ const actualHead = match[1]!.trim();
571
559
  if (expectedHead === actualHead) {
572
560
  return null;
573
561
  }
@@ -578,7 +566,7 @@ function checkPrCommentLastCommit(context, remoteData) {
578
566
  );
579
567
  }
580
568
 
581
- function checkPrCommentRequiredPatterns(context, remoteData) {
569
+ function checkPrCommentRequiredPatterns(context: any, remoteData: any): any {
582
570
  const patterns = context.config.expected_pr_comment_required_patterns || [];
583
571
  if (!Array.isArray(patterns) || patterns.length === 0) {
584
572
  return null;
@@ -613,7 +601,7 @@ function checkPrCommentRequiredPatterns(context, remoteData) {
613
601
  return null;
614
602
  }
615
603
 
616
- function checkCommentContent(context, remoteData) {
604
+ function checkCommentContent(context: any, remoteData: any): any {
617
605
  if (!context.config.verify_comment_content) {
618
606
  return null;
619
607
  }
@@ -648,7 +636,7 @@ function checkCommentContent(context, remoteData) {
648
636
  );
649
637
  }
650
638
 
651
- function checkTaskCommentContent(context, remoteData) {
639
+ function checkTaskCommentContent(context: any, remoteData: any): any {
652
640
  if (!context.config.verify_task_comment_content) {
653
641
  return null;
654
642
  }
@@ -675,7 +663,7 @@ function checkTaskCommentContent(context, remoteData) {
675
663
  );
676
664
  }
677
665
 
678
- function checkPrTypeLabel(context, remoteData) {
666
+ function checkPrTypeLabel(context: any, remoteData: any): any {
679
667
  if (!context.config.verify_pr_type_label || !context.hasTriage || !context.prNumber || !remoteData.prLabels) {
680
668
  return null;
681
669
  }
@@ -695,16 +683,16 @@ function checkPrTypeLabel(context, remoteData) {
695
683
  );
696
684
  }
697
685
 
698
- function checkInLabelsMatchPr(context, remoteData) {
686
+ function checkInLabelsMatchPr(context: any, remoteData: any): any {
699
687
  if (!context.config.verify_in_labels_match_pr || !context.hasTriage || !context.prNumber || !remoteData.prLabels) {
700
688
  return null;
701
689
  }
702
690
 
703
691
  const issueInLabels = extractLabelNames(remoteData.issue.labels)
704
- .filter((label) => label.startsWith("in:"))
692
+ .filter((label: any) => label.startsWith("in:"))
705
693
  .sort();
706
694
  const prInLabels = remoteData.prLabels
707
- .filter((label) => label.startsWith("in:"))
695
+ .filter((label: any) => label.startsWith("in:"))
708
696
  .sort();
709
697
 
710
698
  if (arraysEqual(issueInLabels, prInLabels)) {
@@ -717,7 +705,7 @@ function checkInLabelsMatchPr(context, remoteData) {
717
705
  );
718
706
  }
719
707
 
720
- function checkInLabelsComputed(context, remoteData) {
708
+ function checkInLabelsComputed(context: any, remoteData: any): any {
721
709
  if (!context.config.verify_in_labels_computed || !context.hasTriage) {
722
710
  return null;
723
711
  }
@@ -734,7 +722,7 @@ function checkInLabelsComputed(context, remoteData) {
734
722
  }
735
723
 
736
724
  const actualInLabels = extractLabelNames(remoteData.issue.labels)
737
- .filter((label) => label.startsWith("in:"))
725
+ .filter((label: any) => label.startsWith("in:"))
738
726
  .sort();
739
727
 
740
728
  if (arraysEqual(expectedInLabels.labels, actualInLabels)) {
@@ -748,7 +736,7 @@ function checkInLabelsComputed(context, remoteData) {
748
736
  );
749
737
  }
750
738
 
751
- function checkSyncedRequirements(context, remoteData) {
739
+ function checkSyncedRequirements(context: any, remoteData: any): any {
752
740
  if (!context.config.sync_checked_requirements || !context.hasTriage) {
753
741
  return null;
754
742
  }
@@ -759,8 +747,22 @@ function checkSyncedRequirements(context, remoteData) {
759
747
  }
760
748
 
761
749
  const issueBody = remoteData.issue.body || "";
750
+ const resolution = resolveRequirementSection(
751
+ issueBody,
752
+ requirementSectionAnchors(repoRoot, context.task.metadata.type || "task")
753
+ );
754
+ if (resolution.status === "missing") {
755
+ return null;
756
+ }
757
+ if (resolution.status === "ambiguous") {
758
+ return failResult(CHECK_TYPE,
759
+ `Issue #${context.issueNumber} requirements section is ambiguous`,
760
+ "check_failed"
761
+ );
762
+ }
763
+ const requirementBody = issueBody.slice(resolution.bodyStart, resolution.bodyEnd);
762
764
  const missingRequirements = checkedRequirements.filter(
763
- (item) => !new RegExp(`^- \\[x\\] ${escapeRegExp(item)}$`, "m").test(issueBody)
765
+ (item: any) => !hasCheckedRequirement(requirementBody, item)
764
766
  );
765
767
  if (missingRequirements.length === 0) {
766
768
  return null;
@@ -772,7 +774,7 @@ function checkSyncedRequirements(context, remoteData) {
772
774
  );
773
775
  }
774
776
 
775
- function checkIssueType(context, remoteData) {
777
+ function checkIssueType(context: any, remoteData: any): any {
776
778
  if (!context.config.verify_issue_type || !context.hasPush) {
777
779
  return null;
778
780
  }
@@ -803,7 +805,7 @@ function checkIssueType(context, remoteData) {
803
805
  return null;
804
806
  }
805
807
 
806
- function checkIssueFields(context, remoteData) {
808
+ function checkIssueFields(context: any, remoteData: any): any {
807
809
  if (!context.config.verify_issue_fields || !context.hasPush) {
808
810
  return null;
809
811
  }
@@ -842,7 +844,7 @@ function checkIssueFields(context, remoteData) {
842
844
  return null;
843
845
  }
844
846
 
845
- function checkPrAssignee(context, remoteData) {
847
+ function checkPrAssignee(context: any, remoteData: any): any {
846
848
  if (!context.config.verify_pr_assignee || !context.hasPush || !context.prNumber) {
847
849
  return null;
848
850
  }
@@ -857,7 +859,7 @@ function checkPrAssignee(context, remoteData) {
857
859
  return null;
858
860
  }
859
861
 
860
- function checkMilestone(context, remoteData) {
862
+ function checkMilestone(context: any, remoteData: any): any {
861
863
  if (!context.config.verify_milestone || !context.hasTriage) {
862
864
  return null;
863
865
  }
@@ -895,48 +897,48 @@ function checkMilestone(context, remoteData) {
895
897
  return null;
896
898
  }
897
899
 
898
- function findCommentByMarker(comments, marker) {
899
- return (comments || []).find((comment) => typeof comment.body === "string" && comment.body.includes(marker)) || null;
900
+ function findCommentByMarker(comments: any, marker: any): any {
901
+ return (comments || []).find((comment: any) => typeof comment.body === "string" && comment.body.includes(marker)) || null;
900
902
  }
901
903
 
902
- function isGeneratedMarkerLine(line) {
904
+ function isGeneratedMarkerLine(line: any): any {
903
905
  return line.startsWith("<!--") && line.endsWith("-->");
904
906
  }
905
907
 
906
- function extractCommentBody(commentBody) {
908
+ function extractCommentBody(commentBody: any): any {
907
909
  const lines = String(commentBody || "").split(/\r?\n/);
908
910
 
909
911
  let start = 0;
910
- while (start < lines.length && (lines[start].trim() === "" || isGeneratedMarkerLine(lines[start].trim()))) {
912
+ while (start < lines.length && (lines[start]!.trim() === "" || isGeneratedMarkerLine(lines[start]!.trim()))) {
911
913
  start += 1;
912
914
  }
913
915
 
914
- if (start < lines.length && lines[start].startsWith("## ")) {
916
+ if (start < lines.length && lines[start]!.startsWith("## ")) {
915
917
  start += 1;
916
918
  }
917
919
 
918
- while (start < lines.length && lines[start].trim() === "") {
920
+ while (start < lines.length && lines[start]!.trim() === "") {
919
921
  start += 1;
920
922
  }
921
923
 
922
- if (start < lines.length && /^> \*\*.+\*\* · .+$/.test(lines[start].trim())) {
924
+ if (start < lines.length && /^> \*\*.+\*\* · .+$/.test(lines[start]!.trim())) {
923
925
  start += 1;
924
926
  }
925
927
 
926
- while (start < lines.length && lines[start].trim() === "") {
928
+ while (start < lines.length && lines[start]!.trim() === "") {
927
929
  start += 1;
928
930
  }
929
931
 
930
932
  let end = lines.length;
931
933
  for (let index = lines.length - 1; index >= start; index -= 1) {
932
- const trimmed = lines[index].trim();
934
+ const trimmed = lines[index]!.trim();
933
935
  if (trimmed === "") {
934
936
  continue;
935
937
  }
936
938
 
937
939
  if (/^\*.*\*$/.test(trimmed)) {
938
940
  end = index;
939
- if (end > start && lines[end - 1].trim() === "---") {
941
+ if (end > start && lines[end - 1]!.trim() === "---") {
940
942
  end -= 1;
941
943
  }
942
944
  }
@@ -946,7 +948,7 @@ function extractCommentBody(commentBody) {
946
948
  return lines.slice(start, end).join("\n");
947
949
  }
948
950
 
949
- function buildExpectedTaskBody(taskContent) {
951
+ function buildExpectedTaskBody(taskContent: any): any {
950
952
  const frontmatterMatch = taskContent.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
951
953
  if (!frontmatterMatch) {
952
954
  return taskContent.trim();
@@ -966,7 +968,7 @@ function buildExpectedTaskBody(taskContent) {
966
968
  ].join("\n").trim();
967
969
  }
968
970
 
969
- function buildTaskFrontmatterSummary() {
971
+ function buildTaskFrontmatterSummary(): any {
970
972
  const language = loadProjectLanguage();
971
973
  if (language === "en" || language === "en-US") {
972
974
  return "<details><summary>Metadata (frontmatter)</summary>";
@@ -975,7 +977,7 @@ function buildTaskFrontmatterSummary() {
975
977
  return "<details><summary>元数据 (frontmatter)</summary>";
976
978
  }
977
979
 
978
- function loadProjectLanguage() {
980
+ function loadProjectLanguage(): any {
979
981
  const override = process.env.VALIDATE_ARTIFACT_LANGUAGE;
980
982
  if (!isBlank(override)) {
981
983
  return String(override).trim();
@@ -994,14 +996,14 @@ function loadProjectLanguage() {
994
996
  }
995
997
  }
996
998
 
997
- function buildCommentContentMismatchMessage(fileStem, issueNumber, localContent, commentContent) {
999
+ function buildCommentContentMismatchMessage(fileStem: any, issueNumber: any, localContent: any, commentContent: any): any {
998
1000
  const diffIndex = firstDifferenceIndex(localContent, commentContent);
999
1001
  const position = indexToLineColumn(localContent, diffIndex);
1000
1002
 
1001
1003
  return `Comment content mismatch for '${fileStem}' on Issue #${issueNumber}: local file has ${localContent.length} chars, comment body has ${commentContent.length} chars (first difference near char ${diffIndex + 1}, line ${position.line}, column ${position.column})`;
1002
1004
  }
1003
1005
 
1004
- function firstDifferenceIndex(left, right) {
1006
+ function firstDifferenceIndex(left: any, right: any): any {
1005
1007
  const limit = Math.max(left.length, right.length);
1006
1008
  for (let index = 0; index < limit; index += 1) {
1007
1009
  if (left[index] !== right[index]) {
@@ -1012,7 +1014,7 @@ function firstDifferenceIndex(left, right) {
1012
1014
  return limit;
1013
1015
  }
1014
1016
 
1015
- function indexToLineColumn(text, index) {
1017
+ function indexToLineColumn(text: any, index: any): any {
1016
1018
  const prefix = text.slice(0, Math.min(index, text.length));
1017
1019
  const lines = prefix.split("\n");
1018
1020
  return {
@@ -1021,14 +1023,14 @@ function indexToLineColumn(text, index) {
1021
1023
  };
1022
1024
  }
1023
1025
 
1024
- function extractLabelNames(labels) {
1026
+ function extractLabelNames(labels: any): any {
1025
1027
  return (labels || [])
1026
- .map((label) => typeof label === "string" ? label : label?.name)
1027
- .filter((label) => typeof label === "string" && label.length > 0);
1028
+ .map((label: any) => typeof label === "string" ? label : label?.name)
1029
+ .filter((label: any) => typeof label === "string" && label.length > 0);
1028
1030
  }
1029
1031
 
1030
- function mapTaskTypeToIssueType(taskType) {
1031
- const mapping = {
1032
+ function mapTaskTypeToIssueType(taskType: any): any {
1033
+ const mapping: Record<string, string> = {
1032
1034
  bug: "Bug",
1033
1035
  bugfix: "Bug",
1034
1036
  enhancement: "Feature",
@@ -1047,7 +1049,7 @@ function mapTaskTypeToIssueType(taskType) {
1047
1049
 
1048
1050
  const ISSUE_FIELDS_QUERY = `query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){issue(number:$number){issueType{name pinnedFields{__typename ... on IssueFieldSingleSelect{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{name}}} ... on IssueFieldDateValue{value field{... on IssueFieldDate{name}}} ... on IssueFieldTextValue{value field{... on IssueFieldText{name}}} ... on IssueFieldNumberValue{value field{... on IssueFieldNumber{name}}}}}}}}`;
1049
1051
 
1050
- function normalizeIssueFields(payload) {
1052
+ function normalizeIssueFields(payload: any): any {
1051
1053
  const issue = payload?.data?.repository?.issue;
1052
1054
  const pinnedFields = Array.isArray(issue?.issueType?.pinnedFields)
1053
1055
  ? issue.issueType.pinnedFields
@@ -1057,7 +1059,7 @@ function normalizeIssueFields(payload) {
1057
1059
  : [];
1058
1060
  const pinnedNames = new Set(
1059
1061
  pinnedFields
1060
- .map((field) => typeof field?.name === "string" ? field.name : "")
1062
+ .map((field: any) => typeof field?.name === "string" ? field.name : "")
1061
1063
  .filter(Boolean)
1062
1064
  );
1063
1065
  const normalizedValues = new Map();
@@ -1084,7 +1086,7 @@ function normalizeIssueFields(payload) {
1084
1086
  return { pinnedNames, values: normalizedValues };
1085
1087
  }
1086
1088
 
1087
- function normalizeExpectedIssueField(metadataKey, rawValue) {
1089
+ function normalizeExpectedIssueField(metadataKey: any, rawValue: any): any {
1088
1090
  const value = String(rawValue || "").trim();
1089
1091
  if (!value) {
1090
1092
  return null;
@@ -1097,30 +1099,30 @@ function normalizeExpectedIssueField(metadataKey, rawValue) {
1097
1099
  return { kind: "single-select", value: normalizeOptionName(value) };
1098
1100
  }
1099
1101
 
1100
- function normalizeOptionName(value) {
1102
+ function normalizeOptionName(value: any): any {
1101
1103
  const normalized = String(value || "").trim();
1102
1104
  return OPTION_LOCALIZATION[normalized] || normalized;
1103
1105
  }
1104
1106
 
1105
- function normalizeDateValue(value) {
1107
+ function normalizeDateValue(value: any): any {
1106
1108
  const normalized = String(value || "").trim();
1107
1109
  const match = normalized.match(/^\d{4}-\d{2}-\d{2}/);
1108
1110
  return match ? match[0] : normalized;
1109
1111
  }
1110
1112
 
1111
- function arraysEqual(left, right) {
1113
+ function arraysEqual(left: any, right: any): any {
1112
1114
  if (left.length !== right.length) {
1113
1115
  return false;
1114
1116
  }
1115
1117
 
1116
- return left.every((value, index) => value === right[index]);
1118
+ return left.every((value: any, index: any) => value === right[index]);
1117
1119
  }
1118
1120
 
1119
- function formatLabelList(labels) {
1121
+ function formatLabelList(labels: any): any {
1120
1122
  return labels.length > 0 ? labels.join(", ") : "none";
1121
1123
  }
1122
1124
 
1123
- function computeExpectedInLabels(taskDir) {
1125
+ function computeExpectedInLabels(taskDir: any): any {
1124
1126
  const changedFilesResult = gitText(["diff", "main...HEAD", "--name-only"], taskDir);
1125
1127
  if (!changedFilesResult.ok) {
1126
1128
  return changedFilesResult;
@@ -1136,12 +1138,12 @@ function computeExpectedInLabels(taskDir) {
1136
1138
  return mapping;
1137
1139
  }
1138
1140
 
1139
- if (Object.keys(mapping.value).length > 0) {
1141
+ if (Object.keys(mapping.value ?? {}).length > 0) {
1140
1142
  const labels = new Set();
1141
1143
 
1142
1144
  for (const file of changedFiles) {
1143
- for (const [label, prefixes] of Object.entries(mapping.value)) {
1144
- if (prefixes.some((prefix) => file.startsWith(prefix))) {
1145
+ for (const [label, prefixes] of Object.entries(mapping.value ?? {}) as Array<[string, string[]]>) {
1146
+ if (prefixes.some((prefix: any) => file.startsWith(prefix))) {
1145
1147
  labels.add(`in: ${label}`);
1146
1148
  }
1147
1149
  }
@@ -1164,7 +1166,7 @@ function computeExpectedInLabels(taskDir) {
1164
1166
 
1165
1167
  const repoInLabels = new Set(
1166
1168
  extractLabelNames(repoLabelsResult.value)
1167
- .filter((label) => label.startsWith("in:"))
1169
+ .filter((label: any) => label.startsWith("in:"))
1168
1170
  );
1169
1171
 
1170
1172
  if (repoInLabels.size === 0) {
@@ -1187,7 +1189,7 @@ function computeExpectedInLabels(taskDir) {
1187
1189
  return { ok: true, labels: Array.from(labels).sort(), mode: "fallback" };
1188
1190
  }
1189
1191
 
1190
- function loadInLabelMapping() {
1192
+ function loadInLabelMapping(): any {
1191
1193
  const configPath = path.join(repoRoot, ".agents", ".airc.json");
1192
1194
  if (!fs.existsSync(configPath)) {
1193
1195
  return { ok: true, value: {} };
@@ -1200,7 +1202,7 @@ function loadInLabelMapping() {
1200
1202
  return { ok: true, value: {} };
1201
1203
  }
1202
1204
 
1203
- const normalized = {};
1205
+ const normalized: Record<string, string[]> = {};
1204
1206
  for (const [label, prefixes] of Object.entries(mapping)) {
1205
1207
  if (!Array.isArray(prefixes)) {
1206
1208
  continue;
@@ -1215,89 +1217,14 @@ function loadInLabelMapping() {
1215
1217
  }
1216
1218
 
1217
1219
  return { ok: true, value: normalized };
1218
- } catch (error) {
1220
+ } catch (error: any) {
1219
1221
  return { ok: false, type: "check_failed", message: `Unable to parse .agents/.airc.json: ${error.message}` };
1220
1222
  }
1221
1223
  }
1222
1224
 
1223
1225
  // === GitHub API ===
1224
1226
 
1225
- function normalizeIssuePayload(payload) {
1226
- return {
1227
- state: String(payload?.state || "").toUpperCase(),
1228
- labels: Array.isArray(payload?.labels) ? payload.labels : [],
1229
- body: typeof payload?.body === "string" ? payload.body : "",
1230
- milestone: payload?.milestone ?? null
1231
- };
1232
- }
1233
-
1234
- function resolveUpstreamRepo(taskDir) {
1235
- const ownerRepo = resolveOwnerRepo(taskDir);
1236
- if (!ownerRepo.ok) {
1237
- return ownerRepo;
1238
- }
1239
-
1240
- const repoResult = withRetry(() => ghJson([
1241
- "api",
1242
- `repos/${ownerRepo.value}`
1243
- ], taskDir));
1244
-
1245
- if (!repoResult.ok) {
1246
- return repoResult;
1247
- }
1248
-
1249
- const repo = repoResult.value && typeof repoResult.value === "object" ? repoResult.value : {};
1250
- const upstreamRepo = repo.fork ? repo.parent?.full_name : repo.full_name;
1251
- if (isBlank(upstreamRepo)) {
1252
- return { ok: false, message: "Unable to resolve upstream repository" };
1253
- }
1254
-
1255
- return { ok: true, value: upstreamRepo };
1256
- }
1257
-
1258
- function resolveOwnerRepo(taskDir) {
1259
- const gitResult = spawn.sync("git", ["remote", "get-url", "origin"], {
1260
- cwd: taskDir,
1261
- encoding: "utf8",
1262
- env: process.env
1263
- });
1264
-
1265
- if (gitResult.status !== 0) {
1266
- return { ok: false, message: `Unable to resolve git remote: ${gitResult.stderr.trim() || gitResult.stdout.trim()}` };
1267
- }
1268
-
1269
- const remote = gitResult.stdout.trim();
1270
- const sshMatch = remote.match(/[:/]([^/]+\/[^/]+?)(?:\.git)?$/);
1271
- if (!sshMatch) {
1272
- return { ok: false, message: `Unable to parse owner/repo from remote '${remote}'` };
1273
- }
1274
-
1275
- return { ok: true, value: sshMatch[1] };
1276
- }
1277
-
1278
- function detectPermissions(upstreamRepo, taskDir) {
1279
- const permissionsResult = withRetry(() => ghJson([
1280
- "api",
1281
- `repos/${upstreamRepo}`,
1282
- "--jq",
1283
- ".permissions"
1284
- ], taskDir));
1285
-
1286
- if (!permissionsResult.ok) {
1287
- return { hasTriage: false, hasPush: false };
1288
- }
1289
-
1290
- const permissions = permissionsResult.value && typeof permissionsResult.value === "object"
1291
- ? permissionsResult.value
1292
- : {};
1293
-
1294
- return {
1295
- hasTriage: permissions.triage === true,
1296
- hasPush: permissions.push === true
1297
- };
1298
- }
1299
-
1300
- function detectRepoOwnerType(upstreamRepo, taskDir) {
1227
+ function detectRepoOwnerType(upstreamRepo: any, taskDir: any): any {
1301
1228
  const ownerTypeResult = withRetry(() => ghText([
1302
1229
  "api",
1303
1230
  `repos/${upstreamRepo}`,
@@ -1312,88 +1239,43 @@ function detectRepoOwnerType(upstreamRepo, taskDir) {
1312
1239
  return ownerTypeResult.value || "unknown";
1313
1240
  }
1314
1241
 
1315
- function ghJson(args, cwd) {
1316
- const result = ghCommand(args, cwd);
1317
- if (!result.ok) {
1318
- return result;
1319
- }
1320
-
1321
- try {
1322
- return { ok: true, value: JSON.parse(result.value || "null") };
1323
- } catch (error) {
1324
- return { ok: false, type: "network_error", message: `Invalid JSON from gh: ${error.message}` };
1325
- }
1326
- }
1327
-
1328
- function ghText(args, cwd) {
1329
- const result = ghCommand(args, cwd);
1330
- if (!result.ok) {
1331
- return result;
1332
- }
1333
-
1334
- return { ok: true, value: String(result.value || "").trim() };
1335
- }
1336
-
1337
- function ghCommand(args, cwd) {
1338
- const gh = resolveGhCommand();
1339
- const result = spawn.sync(gh.command, [...gh.preArgs, ...args], {
1340
- cwd,
1341
- encoding: "utf8",
1342
- env: process.env
1343
- });
1344
-
1345
- if (result.status !== 0) {
1346
- const stderr = `${result.stderr || ""}${result.stdout || ""}`.trim();
1347
- const classified = classifyGhFailure(stderr, args);
1348
- return { ok: false, type: classified.type, message: classified.message };
1349
- }
1350
-
1351
- return { ok: true, value: result.stdout };
1242
+ function ghJson(args: any, cwd: any): any {
1243
+ return mapClientResult(githubClient.json(args, { cwd }));
1352
1244
  }
1353
1245
 
1354
- function resolveGhCommand() {
1355
- const command = process.env.AGENT_INFRA_GH_BIN || "gh";
1356
- const rawPreArgs = process.env.AGENT_INFRA_GH_ARGS_JSON;
1357
- if (!rawPreArgs) {
1358
- return { command, preArgs: [] };
1359
- }
1360
-
1361
- try {
1362
- const preArgs = JSON.parse(rawPreArgs);
1363
- if (Array.isArray(preArgs) && preArgs.every((arg) => typeof arg === "string")) {
1364
- return { command, preArgs };
1365
- }
1366
- } catch {
1367
- return { command, preArgs: [] };
1368
- }
1369
-
1370
- return { command, preArgs: [] };
1246
+ function ghText(args: any, cwd: any): any {
1247
+ return mapClientResult(githubClient.text(args, { cwd }));
1371
1248
  }
1372
1249
 
1373
- function ghPaginatedJson(args, cwd) {
1250
+ function ghPaginatedJson(args: any, cwd: any): any {
1374
1251
  return ghJson(args, cwd);
1375
1252
  }
1376
1253
 
1377
- function gitText(args, cwd) {
1378
- const result = spawn.sync("git", args, {
1379
- cwd,
1380
- encoding: "utf8",
1381
- env: process.env
1382
- });
1254
+ function mapClientResult(result: any): any {
1255
+ if (result.ok) return result;
1256
+ const checkFailed = ["RESOURCE_NOT_FOUND", "PERMISSION_DENIED", "PLATFORM_REQUEST_INVALID"].includes(result.error.code);
1257
+ return {
1258
+ ok: false,
1259
+ type: checkFailed ? "check_failed" : "network_error",
1260
+ message: result.error.message
1261
+ };
1262
+ }
1383
1263
 
1384
- if (result.status !== 0) {
1385
- const stderr = `${result.stderr || ""}${result.stdout || ""}`.trim();
1264
+ function gitText(args: any, cwd: any): any {
1265
+ try {
1266
+ const value = execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
1267
+ return { ok: true, value: String(value || "").trim() };
1268
+ } catch (error: any) {
1269
+ const stderr = `${error?.stderr || ""}${error?.stdout || ""}`.trim();
1386
1270
  return {
1387
1271
  ok: false,
1388
1272
  type: "check_failed",
1389
1273
  message: stderr || `git ${args.join(" ")} failed`
1390
1274
  };
1391
1275
  }
1392
-
1393
- return { ok: true, value: String(result.stdout || "").trim() };
1394
1276
  }
1395
1277
 
1396
- function resolvePrHeadSha(context) {
1278
+ function resolvePrHeadSha(context: any): any {
1397
1279
  const fallback = () => withRetry(() => gitText(["rev-parse", "HEAD"], context.taskDir));
1398
1280
  const branch = String(context.task?.metadata?.branch || "").trim();
1399
1281
  if (!branch) {
@@ -1418,7 +1300,7 @@ function resolvePrHeadSha(context) {
1418
1300
  return headInWorktree;
1419
1301
  }
1420
1302
 
1421
- function findWorktreeForBranch(porcelainOutput, branch) {
1303
+ function findWorktreeForBranch(porcelainOutput: any, branch: any): any {
1422
1304
  let currentWorktree = "";
1423
1305
  for (const rawLine of String(porcelainOutput || "").split("\n")) {
1424
1306
  const line = rawLine.trimEnd();
@@ -1438,62 +1320,11 @@ function findWorktreeForBranch(porcelainOutput, branch) {
1438
1320
  return null;
1439
1321
  }
1440
1322
 
1441
- function withRetry(operation) {
1442
- const delays = getRetryDelays();
1443
- let lastFailure = null;
1444
-
1445
- for (let attempt = 0; attempt <= delays.length; attempt += 1) {
1446
- const result = operation();
1447
- if (result.ok) {
1448
- return result;
1449
- }
1450
-
1451
- lastFailure = result;
1452
- if (result.type === "check_failed") {
1453
- return result;
1454
- }
1455
-
1456
- if (attempt < delays.length) {
1457
- sleep(delays[attempt]);
1458
- }
1459
- }
1460
-
1461
- return lastFailure || { ok: false, type: "network_error", message: "Unknown GitHub sync failure" };
1462
- }
1463
-
1464
- function classifyGhFailure(stderr, args) {
1465
- const message = stderr || `gh ${args.join(" ")} failed`;
1466
-
1467
- if (/not found|could not resolve to an issue|http 404/i.test(message)) {
1468
- return { type: "check_failed", message };
1469
- }
1470
-
1471
- return { type: "network_error", message };
1472
- }
1473
-
1474
- function getRetryDelays() {
1475
- const override = process.env.VALIDATE_ARTIFACT_RETRY_DELAYS_MS;
1476
- if (!override) {
1477
- return DEFAULT_RETRY_DELAYS_MS;
1478
- }
1479
-
1480
- const parsed = override
1481
- .split(",")
1482
- .map((value) => Number(value.trim()))
1483
- .filter((value) => Number.isFinite(value) && value >= 0);
1484
-
1485
- return parsed.length > 0 ? parsed : DEFAULT_RETRY_DELAYS_MS;
1486
- }
1487
-
1488
- function sleep(delayMs) {
1489
- if (delayMs <= 0) {
1490
- return;
1491
- }
1492
-
1493
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, delayMs);
1323
+ function withRetry(operation: any): any {
1324
+ return operation();
1494
1325
  }
1495
1326
 
1496
- function interpolate(template, taskDir, artifactFile) {
1327
+ function interpolate(template: any, taskDir: any, artifactFile: any): any {
1497
1328
  const artifactStem = artifactFile ? path.basename(artifactFile, path.extname(artifactFile)) : "";
1498
1329
  return template
1499
1330
  .replace(/\{task-id\}/g, path.basename(taskDir))