@fitlab-ai/agent-infra 0.8.4 → 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 (443) 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 +9 -0
  6. package/dist/lib/git/review-snapshot.js +79 -0
  7. package/dist/lib/git/workflow.js +101 -0
  8. package/dist/lib/init.js +5 -0
  9. package/dist/lib/internal/git-workflow.js +42 -0
  10. package/dist/lib/internal/platform-checks.js +119 -0
  11. package/dist/lib/internal/platform-comment.js +129 -0
  12. package/dist/lib/internal/platform-context.js +46 -0
  13. package/dist/lib/internal/platform-issue.js +142 -0
  14. package/dist/lib/internal/platform-pr.js +146 -0
  15. package/dist/lib/internal/release-workflow.js +217 -0
  16. package/dist/lib/internal/task-artifact.js +67 -0
  17. package/dist/lib/internal/task-context.js +43 -0
  18. package/dist/lib/internal/task-event.js +70 -0
  19. package/dist/lib/internal/task-ledger.js +114 -0
  20. package/dist/lib/internal/task-lifecycle.js +58 -0
  21. package/dist/lib/internal/task-short-id.js +83 -0
  22. package/dist/lib/internal/task-snapshot.js +47 -0
  23. package/dist/lib/internal/task-verify.js +50 -0
  24. package/dist/lib/internal/task-warning.js +74 -0
  25. package/dist/lib/platform/adapters.js +14 -0
  26. package/dist/lib/platform/context.js +146 -0
  27. package/dist/lib/platform/github-client.js +124 -0
  28. package/dist/lib/platform/issue-comments.js +409 -0
  29. package/dist/lib/platform/issue-metadata.js +183 -0
  30. package/dist/lib/platform/issues.js +617 -0
  31. package/dist/lib/platform/metadata-labels.js +28 -0
  32. package/dist/lib/platform/pr-checks.js +216 -0
  33. package/dist/lib/platform/pr-summary.js +88 -0
  34. package/dist/lib/platform/pull-request-metadata.js +38 -0
  35. package/dist/lib/platform/pull-requests.js +338 -0
  36. package/dist/lib/platform/releases.js +82 -0
  37. package/dist/lib/platform/types.js +22 -0
  38. package/dist/lib/platform/verification-required.js +78 -0
  39. package/dist/lib/platform/verification-sync.js +1014 -0
  40. package/dist/lib/platform/verification.js +6 -0
  41. package/dist/lib/release/channels.js +31 -0
  42. package/dist/lib/release/workflow.js +32 -0
  43. package/dist/lib/render.js +3 -2
  44. package/dist/lib/run/index.js +24 -7
  45. package/dist/lib/sandbox/capture.js +25 -3
  46. package/dist/lib/sandbox/commands/create.js +66 -26
  47. package/dist/lib/sandbox/commands/enter.js +34 -11
  48. package/dist/lib/sandbox/commands/list-running.js +10 -8
  49. package/dist/lib/sandbox/commands/show.js +2 -2
  50. package/dist/lib/sandbox/commands/start.js +53 -15
  51. package/dist/lib/sandbox/engine.js +33 -3
  52. package/dist/lib/sandbox/engines/colima.js +2 -2
  53. package/dist/lib/sandbox/index.js +6 -6
  54. package/dist/lib/sandbox/mounts.js +36 -0
  55. package/dist/lib/sandbox/recovery.js +562 -0
  56. package/dist/lib/sandbox/runtimes/base.dockerfile +4 -0
  57. package/dist/lib/sandbox/task-resolver.js +5 -1
  58. package/dist/lib/sandbox/tools.js +19 -0
  59. package/dist/lib/server/daemon.js +9 -0
  60. package/dist/lib/server/process-control.js +66 -73
  61. package/dist/lib/server/process-state.js +168 -0
  62. package/dist/lib/server/protocol.js +5 -5
  63. package/dist/lib/task/activity-log.js +61 -0
  64. package/dist/lib/task/artifact-lifecycle.js +427 -0
  65. package/dist/lib/task/command-options.js +30 -0
  66. package/dist/lib/task/commands/cat.js +36 -6
  67. package/dist/lib/task/commands/decisions.js +80 -46
  68. package/dist/lib/task/commands/files.js +21 -7
  69. package/dist/lib/task/commands/grep.js +55 -7
  70. package/dist/lib/task/commands/issue-body.js +23 -14
  71. package/dist/lib/task/commands/log.js +27 -70
  72. package/dist/lib/task/commands/show.js +20 -7
  73. package/dist/lib/task/commands/status.js +18 -8
  74. package/dist/lib/task/decision-intents.js +154 -0
  75. package/dist/lib/task/decision-items.js +53 -0
  76. package/dist/lib/task/events.js +318 -0
  77. package/dist/lib/task/frontmatter.js +159 -1
  78. package/dist/lib/task/implementation-inputs.js +117 -0
  79. package/dist/lib/task/index.js +12 -9
  80. package/dist/lib/task/issue-form.js +19 -6
  81. package/dist/lib/task/ledger-intents.js +185 -0
  82. package/dist/lib/task/ledger.js +65 -35
  83. package/dist/lib/task/lifecycle.js +484 -0
  84. package/dist/lib/task/resolve-ref.js +152 -32
  85. package/dist/lib/task/review-artifacts.js +101 -0
  86. package/dist/lib/task/review-fingerprint.js +46 -0
  87. package/dist/lib/task/sections.js +358 -4
  88. package/dist/lib/task/short-id.js +292 -7
  89. package/dist/lib/task/snapshot.js +95 -0
  90. package/dist/lib/task/verification-checks.js +8 -0
  91. package/dist/lib/task/verification-config.js +14 -0
  92. package/dist/lib/task/verification-engine.js +906 -0
  93. package/dist/lib/task/verification-review.js +3 -0
  94. package/dist/lib/task/verification-types.js +2 -0
  95. package/dist/lib/task/verification.js +113 -0
  96. package/dist/lib/task/workflow-warning-intents.js +131 -0
  97. package/dist/lib/task/workflow-warnings.js +10 -78
  98. package/dist/lib/task/write.js +241 -0
  99. package/dist/lib/update.js +2 -0
  100. package/lib/decide.ts +57 -97
  101. package/lib/defaults.json +9 -0
  102. package/lib/git/review-snapshot.ts +73 -0
  103. package/lib/git/workflow.ts +101 -0
  104. package/lib/init.ts +9 -0
  105. package/lib/internal/git-workflow.ts +37 -0
  106. package/lib/internal/platform-checks.ts +101 -0
  107. package/lib/internal/platform-comment.ts +99 -0
  108. package/lib/internal/platform-context.ts +33 -0
  109. package/lib/internal/platform-issue.ts +116 -0
  110. package/lib/internal/platform-pr.ts +119 -0
  111. package/lib/internal/release-workflow.ts +186 -0
  112. package/lib/internal/task-artifact.ts +47 -0
  113. package/lib/internal/task-context.ts +35 -0
  114. package/lib/internal/task-event.ts +51 -0
  115. package/lib/internal/task-ledger.ts +86 -0
  116. package/lib/internal/task-lifecycle.ts +41 -0
  117. package/lib/internal/task-short-id.ts +55 -0
  118. package/lib/internal/task-snapshot.ts +32 -0
  119. package/lib/internal/task-verify.ts +33 -0
  120. package/lib/internal/task-warning.ts +50 -0
  121. package/lib/platform/adapters.ts +30 -0
  122. package/lib/platform/context.ts +164 -0
  123. package/lib/platform/github-client.ts +146 -0
  124. package/lib/platform/issue-comments.ts +479 -0
  125. package/lib/platform/issue-metadata.ts +250 -0
  126. package/lib/platform/issues.ts +691 -0
  127. package/lib/platform/metadata-labels.ts +33 -0
  128. package/lib/platform/pr-checks.ts +246 -0
  129. package/lib/platform/pr-summary.ts +90 -0
  130. package/lib/platform/pull-request-metadata.ts +69 -0
  131. package/lib/platform/pull-requests.ts +380 -0
  132. package/lib/platform/releases.ts +71 -0
  133. package/lib/platform/types.ts +74 -0
  134. package/lib/platform/verification-required.ts +83 -0
  135. package/{templates/.agents/scripts/platform-adapters/platform-sync.github.js → lib/platform/verification-sync.ts} +221 -363
  136. package/lib/platform/verification.ts +11 -0
  137. package/lib/release/channels.ts +30 -0
  138. package/lib/release/workflow.ts +31 -0
  139. package/lib/render.ts +3 -2
  140. package/lib/run/index.ts +25 -7
  141. package/lib/sandbox/capture.ts +29 -3
  142. package/lib/sandbox/commands/create.ts +75 -28
  143. package/lib/sandbox/commands/enter.ts +38 -11
  144. package/lib/sandbox/commands/list-running.ts +10 -8
  145. package/lib/sandbox/commands/show.ts +2 -2
  146. package/lib/sandbox/commands/start.ts +50 -16
  147. package/lib/sandbox/engine.ts +37 -3
  148. package/lib/sandbox/engines/colima.ts +2 -2
  149. package/lib/sandbox/index.ts +6 -6
  150. package/lib/sandbox/mounts.ts +55 -0
  151. package/lib/sandbox/recovery.ts +828 -0
  152. package/lib/sandbox/runtimes/base.dockerfile +4 -0
  153. package/lib/sandbox/task-resolver.ts +5 -1
  154. package/lib/sandbox/tools.ts +31 -0
  155. package/lib/server/daemon.ts +9 -0
  156. package/lib/server/process-control.ts +70 -71
  157. package/lib/server/process-state.ts +183 -0
  158. package/lib/server/protocol.ts +5 -5
  159. package/lib/task/activity-log.ts +62 -0
  160. package/lib/task/artifact-lifecycle.ts +484 -0
  161. package/lib/task/command-options.ts +32 -0
  162. package/lib/task/commands/cat.ts +22 -9
  163. package/lib/task/commands/decisions.ts +49 -47
  164. package/lib/task/commands/files.ts +14 -6
  165. package/lib/task/commands/grep.ts +34 -7
  166. package/lib/task/commands/issue-body.ts +16 -16
  167. package/lib/task/commands/log.ts +17 -70
  168. package/lib/task/commands/show.ts +14 -6
  169. package/lib/task/commands/status.ts +17 -7
  170. package/lib/task/decision-intents.ts +163 -0
  171. package/lib/task/decision-items.ts +64 -0
  172. package/lib/task/events.ts +320 -0
  173. package/lib/task/frontmatter.ts +202 -2
  174. package/lib/task/implementation-inputs.ts +137 -0
  175. package/lib/task/index.ts +12 -9
  176. package/lib/task/issue-form.ts +20 -6
  177. package/lib/task/ledger-intents.ts +201 -0
  178. package/lib/task/ledger.ts +77 -31
  179. package/lib/task/lifecycle.ts +458 -0
  180. package/lib/task/resolve-ref.ts +197 -36
  181. package/{templates/.agents/scripts/lib/review-artifacts.js → lib/task/review-artifacts.ts} +11 -12
  182. package/{templates/.agents/scripts/lib/post-review-commit.js → lib/task/review-fingerprint.ts} +20 -10
  183. package/lib/task/sections.ts +486 -4
  184. package/lib/task/short-id.ts +403 -9
  185. package/lib/task/snapshot.ts +143 -0
  186. package/lib/task/verification-checks.ts +9 -0
  187. package/lib/task/verification-config.ts +20 -0
  188. package/{templates/.agents/scripts/validate-artifact.js → lib/task/verification-engine.ts} +257 -451
  189. package/lib/task/verification-review.ts +9 -0
  190. package/lib/task/verification-types.ts +29 -0
  191. package/lib/task/verification.ts +156 -0
  192. package/lib/task/workflow-warning-intents.ts +142 -0
  193. package/lib/task/workflow-warnings.ts +10 -78
  194. package/lib/task/write.ts +468 -0
  195. package/lib/update.ts +6 -0
  196. package/package.json +5 -2
  197. package/templates/.agents/README.en.md +6 -3
  198. package/templates/.agents/README.zh-CN.md +6 -3
  199. package/templates/.agents/rules/README.en.md +6 -5
  200. package/templates/.agents/rules/README.zh-CN.md +6 -5
  201. package/templates/.agents/rules/create-issue.en.md +1 -1
  202. package/templates/.agents/rules/create-issue.github.en.md +5 -184
  203. package/templates/.agents/rules/create-issue.github.zh-CN.md +12 -178
  204. package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
  205. package/templates/.agents/rules/human-decision-context.en.md +36 -0
  206. package/templates/.agents/rules/human-decision-context.zh-CN.md +36 -0
  207. package/templates/.agents/rules/issue-fields.github.en.md +4 -148
  208. package/templates/.agents/rules/issue-fields.github.zh-CN.md +9 -144
  209. package/templates/.agents/rules/issue-pr-commands.en.md +43 -3
  210. package/templates/.agents/rules/issue-pr-commands.github.en.md +15 -220
  211. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +23 -213
  212. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +45 -3
  213. package/templates/.agents/rules/issue-sync.en.md +1 -1
  214. package/templates/.agents/rules/issue-sync.github.en.md +14 -301
  215. package/templates/.agents/rules/issue-sync.github.zh-CN.md +36 -287
  216. package/templates/.agents/rules/issue-sync.zh-CN.md +1 -1
  217. package/templates/.agents/rules/milestone-inference.en.md +1 -1
  218. package/templates/.agents/rules/milestone-inference.github.en.md +7 -119
  219. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +8 -108
  220. package/templates/.agents/rules/milestone-inference.zh-CN.md +1 -1
  221. package/templates/.agents/rules/next-step-output.en.md +12 -11
  222. package/templates/.agents/rules/next-step-output.zh-CN.md +12 -11
  223. package/templates/.agents/rules/no-mid-flow-questions.en.md +3 -3
  224. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +3 -3
  225. package/templates/.agents/rules/pr-checks-commands.en.md +16 -3
  226. package/templates/.agents/rules/pr-checks-commands.github.en.md +10 -54
  227. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +19 -47
  228. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +30 -3
  229. package/templates/.agents/rules/pr-sync.en.md +30 -3
  230. package/templates/.agents/rules/pr-sync.github.en.md +12 -115
  231. package/templates/.agents/rules/pr-sync.github.zh-CN.md +26 -104
  232. package/templates/.agents/rules/pr-sync.zh-CN.md +43 -3
  233. package/templates/.agents/rules/review-handshake.en.md +13 -9
  234. package/templates/.agents/rules/review-handshake.zh-CN.md +13 -9
  235. package/templates/.agents/rules/task-management.en.md +11 -2
  236. package/templates/.agents/rules/task-management.zh-CN.md +11 -3
  237. package/templates/.agents/rules/task-short-id.en.md +25 -29
  238. package/templates/.agents/rules/task-short-id.zh-CN.md +20 -23
  239. package/templates/.agents/scripts/lib/agent-infra-package.js +141 -0
  240. package/templates/.agents/scripts/task-short-id.js +71 -533
  241. package/templates/.agents/skills/analyze-task/SKILL.en.md +22 -55
  242. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +26 -59
  243. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -3
  244. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -3
  245. package/templates/.agents/skills/block-task/SKILL.en.md +21 -47
  246. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +23 -47
  247. package/templates/.agents/skills/block-task/config/verify.json +1 -2
  248. package/templates/.agents/skills/cancel-task/SKILL.en.md +16 -45
  249. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +16 -45
  250. package/templates/.agents/skills/cancel-task/config/verify.json +1 -2
  251. package/templates/.agents/skills/check-task/SKILL.en.md +6 -3
  252. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +6 -3
  253. package/templates/.agents/skills/close-codescan/SKILL.en.md +6 -24
  254. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +6 -24
  255. package/templates/.agents/skills/close-dependabot/SKILL.en.md +6 -24
  256. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +6 -24
  257. package/templates/.agents/skills/code-task/SKILL.en.md +22 -35
  258. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +28 -44
  259. package/templates/.agents/skills/code-task/config/verify.en.json +3 -3
  260. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +3 -3
  261. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +13 -9
  262. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +13 -9
  263. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +1 -1
  264. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +1 -1
  265. package/templates/.agents/skills/code-task/reference/report-template.en.md +11 -1
  266. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +11 -1
  267. package/templates/.agents/skills/commit/SKILL.en.md +18 -14
  268. package/templates/.agents/skills/commit/SKILL.zh-CN.md +18 -14
  269. package/templates/.agents/skills/commit/config/verify.json +1 -2
  270. package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -11
  271. package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -11
  272. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +4 -8
  273. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +4 -8
  274. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +6 -18
  275. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +5 -17
  276. package/templates/.agents/skills/commit/reference/task-status-update.en.md +42 -2
  277. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +42 -2
  278. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +13 -36
  279. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +13 -36
  280. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -3
  281. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -3
  282. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +10 -54
  283. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +10 -79
  284. package/templates/.agents/skills/complete-task/SKILL.en.md +59 -63
  285. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +59 -63
  286. package/templates/.agents/skills/complete-task/config/verify.en.json +11 -6
  287. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +11 -6
  288. package/templates/.agents/skills/create-pr/SKILL.en.md +19 -44
  289. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +19 -43
  290. package/templates/.agents/skills/create-pr/config/verify.json +1 -2
  291. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +8 -12
  292. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +7 -11
  293. package/templates/.agents/skills/create-task/SKILL.en.md +12 -13
  294. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +12 -13
  295. package/templates/.agents/skills/create-task/config/verify.json +1 -2
  296. package/templates/.agents/skills/import-codescan/SKILL.en.md +2 -2
  297. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +2 -2
  298. package/templates/.agents/skills/import-codescan/config/verify.json +1 -2
  299. package/templates/.agents/skills/import-dependabot/SKILL.en.md +2 -2
  300. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +2 -2
  301. package/templates/.agents/skills/import-dependabot/config/verify.json +1 -2
  302. package/templates/.agents/skills/import-issue/SKILL.en.md +9 -13
  303. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +10 -14
  304. package/templates/.agents/skills/import-issue/config/verify.json +1 -2
  305. package/templates/.agents/skills/init-milestones/SKILL.en.md +2 -2
  306. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +2 -2
  307. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +5 -4
  308. package/templates/.agents/skills/plan-task/SKILL.en.md +17 -42
  309. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +22 -49
  310. package/templates/.agents/skills/plan-task/config/verify.en.json +1 -3
  311. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -3
  312. package/templates/.agents/skills/post-release/SKILL.en.md +11 -81
  313. package/templates/.agents/skills/post-release/SKILL.zh-CN.md +8 -78
  314. package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
  315. package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
  316. package/templates/.agents/skills/release/SKILL.en.md +16 -163
  317. package/templates/.agents/skills/release/SKILL.zh-CN.md +15 -162
  318. package/templates/.agents/skills/restore-task/SKILL.en.md +11 -29
  319. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +11 -29
  320. package/templates/.agents/skills/restore-task/config/verify.json +1 -2
  321. package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -25
  322. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +13 -33
  323. package/templates/.agents/skills/review-analysis/config/verify.en.json +3 -4
  324. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +3 -4
  325. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +9 -12
  326. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +9 -12
  327. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +9 -2
  328. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +9 -2
  329. package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +7 -0
  330. package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +7 -0
  331. package/templates/.agents/skills/review-code/SKILL.en.md +22 -36
  332. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +23 -41
  333. package/templates/.agents/skills/review-code/config/verify.en.json +5 -5
  334. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +5 -5
  335. package/templates/.agents/skills/review-code/reference/output-templates.en.md +56 -18
  336. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +56 -18
  337. package/templates/.agents/skills/review-code/reference/report-template.en.md +12 -4
  338. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +12 -4
  339. package/templates/.agents/skills/review-code/reference/review-criteria.en.md +7 -0
  340. package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +7 -0
  341. package/templates/.agents/skills/review-plan/SKILL.en.md +13 -25
  342. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +13 -33
  343. package/templates/.agents/skills/review-plan/config/verify.en.json +3 -4
  344. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +3 -4
  345. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +9 -12
  346. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +9 -12
  347. package/templates/.agents/skills/review-plan/reference/report-template.en.md +9 -2
  348. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +9 -2
  349. package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +7 -0
  350. package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +7 -0
  351. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +6 -3
  352. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +6 -3
  353. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +177 -151
  354. package/templates/.agents/skills/watch-pr/SKILL.en.md +24 -14
  355. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +25 -15
  356. package/templates/.agents/skills/watch-pr/config/verify.json +1 -2
  357. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +2 -2
  358. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +2 -2
  359. package/templates/.agents/templates/task.en.md +6 -1
  360. package/templates/.agents/templates/task.zh-CN.md +6 -1
  361. package/templates/.claude/commands/analyze-task.en.md +1 -1
  362. package/templates/.claude/commands/analyze-task.zh-CN.md +1 -1
  363. package/templates/.claude/commands/block-task.en.md +1 -1
  364. package/templates/.claude/commands/block-task.zh-CN.md +1 -1
  365. package/templates/.claude/commands/cancel-task.en.md +1 -1
  366. package/templates/.claude/commands/cancel-task.zh-CN.md +1 -1
  367. package/templates/.claude/commands/check-task.en.md +1 -1
  368. package/templates/.claude/commands/check-task.zh-CN.md +1 -1
  369. package/templates/.claude/commands/code-task.en.md +1 -1
  370. package/templates/.claude/commands/code-task.zh-CN.md +1 -1
  371. package/templates/.claude/commands/commit.en.md +1 -0
  372. package/templates/.claude/commands/commit.zh-CN.md +1 -0
  373. package/templates/.claude/commands/complete-manual-validation.en.md +1 -1
  374. package/templates/.claude/commands/complete-manual-validation.zh-CN.md +1 -1
  375. package/templates/.claude/commands/complete-task.en.md +1 -1
  376. package/templates/.claude/commands/complete-task.zh-CN.md +1 -1
  377. package/templates/.claude/commands/create-pr.en.md +1 -1
  378. package/templates/.claude/commands/create-pr.zh-CN.md +1 -1
  379. package/templates/.claude/commands/plan-task.en.md +1 -1
  380. package/templates/.claude/commands/plan-task.zh-CN.md +1 -1
  381. package/templates/.claude/commands/review-analysis.en.md +1 -1
  382. package/templates/.claude/commands/review-analysis.zh-CN.md +1 -1
  383. package/templates/.claude/commands/review-code.en.md +1 -1
  384. package/templates/.claude/commands/review-code.zh-CN.md +1 -1
  385. package/templates/.claude/commands/review-plan.en.md +1 -1
  386. package/templates/.claude/commands/review-plan.zh-CN.md +1 -1
  387. package/templates/.claude/commands/watch-pr.en.md +1 -1
  388. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  389. package/templates/.gemini/commands/_project_/analyze-task.en.toml +2 -0
  390. package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +2 -0
  391. package/templates/.gemini/commands/_project_/block-task.en.toml +2 -0
  392. package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +2 -0
  393. package/templates/.gemini/commands/_project_/cancel-task.en.toml +2 -0
  394. package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +2 -0
  395. package/templates/.gemini/commands/_project_/check-task.en.toml +2 -0
  396. package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +2 -0
  397. package/templates/.gemini/commands/_project_/code-task.en.toml +2 -0
  398. package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +2 -0
  399. package/templates/.gemini/commands/_project_/commit.en.toml +4 -0
  400. package/templates/.gemini/commands/_project_/commit.zh-CN.toml +4 -0
  401. package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +2 -0
  402. package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +2 -0
  403. package/templates/.gemini/commands/_project_/complete-task.en.toml +2 -0
  404. package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +2 -0
  405. package/templates/.gemini/commands/_project_/create-pr.en.toml +2 -0
  406. package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +2 -0
  407. package/templates/.gemini/commands/_project_/plan-task.en.toml +2 -0
  408. package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +2 -0
  409. package/templates/.gemini/commands/_project_/review-analysis.en.toml +2 -0
  410. package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +2 -0
  411. package/templates/.gemini/commands/_project_/review-code.en.toml +2 -0
  412. package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +2 -0
  413. package/templates/.gemini/commands/_project_/review-plan.en.toml +2 -0
  414. package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +2 -0
  415. package/templates/.gemini/commands/_project_/watch-pr.en.toml +2 -0
  416. package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +2 -0
  417. package/templates/.git-hooks/check-large-files.cjs +92 -0
  418. package/templates/.git-hooks/check-version-format.sh +5 -1
  419. package/templates/.git-hooks/pre-commit +1 -0
  420. package/templates/.opencode/commands/analyze-task.en.md +1 -1
  421. package/templates/.opencode/commands/analyze-task.zh-CN.md +1 -1
  422. package/templates/.opencode/commands/check-task.en.md +1 -1
  423. package/templates/.opencode/commands/check-task.zh-CN.md +1 -1
  424. package/templates/.opencode/commands/code-task.en.md +1 -1
  425. package/templates/.opencode/commands/code-task.zh-CN.md +1 -1
  426. package/templates/.opencode/commands/commit.en.md +2 -0
  427. package/templates/.opencode/commands/commit.zh-CN.md +2 -0
  428. package/templates/.opencode/commands/complete-task.en.md +1 -1
  429. package/templates/.opencode/commands/complete-task.zh-CN.md +1 -1
  430. package/templates/.opencode/commands/plan-task.en.md +1 -1
  431. package/templates/.opencode/commands/plan-task.zh-CN.md +1 -1
  432. package/templates/.opencode/commands/review-analysis.en.md +1 -1
  433. package/templates/.opencode/commands/review-analysis.zh-CN.md +1 -1
  434. package/templates/.opencode/commands/review-code.en.md +1 -1
  435. package/templates/.opencode/commands/review-code.zh-CN.md +1 -1
  436. package/templates/.opencode/commands/review-plan.en.md +1 -1
  437. package/templates/.opencode/commands/review-plan.zh-CN.md +1 -1
  438. package/templates/.agents/scripts/platform-adapters/platform-sync.js +0 -13
  439. package/templates/.agents/scripts/review-diff-fingerprint.js +0 -99
  440. package/templates/.agents/scripts/workflow-warnings.js +0 -290
  441. package/templates/.agents/skills/code-task/scripts/detect-mode.js +0 -257
  442. package/templates/.agents/skills/release/scripts/manage-milestones.github.sh +0 -80
  443. 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 });
@@ -108,6 +116,7 @@ export function check({ taskDir, config, artifactFile }, shared) {
108
116
  }
109
117
 
110
118
  const subChecks = [
119
+ checkClosedIssueStatusLabels,
111
120
  checkStatusLabel,
112
121
  checkCommentMarker,
113
122
  checkPrCommentMarker,
@@ -135,7 +144,7 @@ export function check({ taskDir, config, artifactFile }, shared) {
135
144
  return passResult(CHECK_TYPE, `GitHub sync checks passed for Issue #${context.issueNumber}`);
136
145
  }
137
146
 
138
- function buildSyncContext({ taskDir, config, artifactFile }) {
147
+ function buildSyncContext({ taskDir, config, artifactFile }: any): any {
139
148
  const task = loadTask(taskDir);
140
149
  if (!task.ok) {
141
150
  return { earlyReturn: failResult(CHECK_TYPE, task.message) };
@@ -154,12 +163,20 @@ function buildSyncContext({ taskDir, config, artifactFile }) {
154
163
  return { earlyReturn: passResult(CHECK_TYPE, "Skipped: platform-sync not required for this task") };
155
164
  }
156
165
 
157
- const upstreamRepo = resolveUpstreamRepo(taskDir);
158
- if (!upstreamRepo.ok) {
159
- 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") };
160
172
  }
161
- const permissions = detectPermissions(upstreamRepo.value, taskDir);
162
- const repoOwnerType = detectRepoOwnerType(upstreamRepo.value, taskDir);
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"}`) };
178
+ }
179
+ const repoOwnerType = detectRepoOwnerType(platformContext.platform.repository, taskDir);
163
180
  const expectedValues = resolveExpectedValues(config);
164
181
  if (!expectedValues.ok) {
165
182
  return { earlyReturn: failResult(CHECK_TYPE, expectedValues.message, "check_failed") };
@@ -181,17 +198,17 @@ function buildSyncContext({ taskDir, config, artifactFile }) {
181
198
  artifactPath,
182
199
  issueNumber,
183
200
  prNumber,
184
- upstreamRepo: upstreamRepo.value,
201
+ upstreamRepo: platformContext.platform.repository,
185
202
  repoOwnerType,
186
- hasTriage: permissions.hasTriage,
187
- hasPush: permissions.hasPush,
203
+ hasTriage: platformContext.capabilities.triage,
204
+ hasPush: platformContext.capabilities.push,
188
205
  expectedStatusLabel: expectedValues.statusLabel,
189
206
  marker,
190
207
  prMarker
191
208
  };
192
209
  }
193
210
 
194
- function resolveExpectedValues(config) {
211
+ function resolveExpectedValues(config: any): any {
195
212
  const defaults = getDefaults();
196
213
  const statusLabel = resolveDefaultValue({
197
214
  collection: defaults.statusLabels,
@@ -231,7 +248,7 @@ function resolveExpectedValues(config) {
231
248
  };
232
249
  }
233
250
 
234
- function resolveDefaultValue({ collection, key, value, configKey }) {
251
+ function resolveDefaultValue({ collection, key, value, configKey }: any): any {
235
252
  if (!key) {
236
253
  return { ok: true, value: value || null };
237
254
  }
@@ -244,30 +261,28 @@ function resolveDefaultValue({ collection, key, value, configKey }) {
244
261
  return { ok: true, value: resolvedValue };
245
262
  }
246
263
 
247
- function fetchRemoteData(context) {
248
- let issueResult = withRetry(() => ghJson([
249
- "issue",
250
- "view",
251
- String(context.issueNumber),
252
- "-R",
264
+ function fetchRemoteData(context: any): any {
265
+ const sharedIssue = inspectGitHubIssueMetadata(
266
+ githubClient,
253
267
  context.upstreamRepo,
254
- "--json",
255
- "state,labels,body,milestone"
256
- ], context.taskDir));
257
- if (!issueResult.ok && issueResult.type !== "check_failed") {
258
- const fallbackIssueResult = withRetry(() => ghJson([
259
- "api",
260
- `repos/${context.upstreamRepo}/issues/${context.issueNumber}`
261
- ], context.taskDir));
262
- if (fallbackIssueResult.ok) {
263
- issueResult = {
268
+ context.issueNumber,
269
+ context.taskDir
270
+ );
271
+ const issueResult = sharedIssue.ok
272
+ ? {
264
273
  ok: true,
265
- 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
266
285
  };
267
- } else {
268
- issueResult = fallbackIssueResult;
269
- }
270
- }
271
286
  if (!issueResult.ok) {
272
287
  return {
273
288
  earlyReturn: issueResult.type === "check_failed"
@@ -311,22 +326,22 @@ function fetchRemoteData(context) {
311
326
  };
312
327
  }
313
328
 
314
- const prCommentsResult = withRetry(() => ghPaginatedJson([
315
- "api",
316
- "--paginate",
317
- "--slurp",
318
- `repos/${context.upstreamRepo}/issues/${context.prNumber}/comments?per_page=100`
319
- ], context.taskDir));
329
+ const prCommentsResult = listRemoteComments(
330
+ githubClient,
331
+ context.upstreamRepo,
332
+ context.prNumber,
333
+ context.taskDir
334
+ );
320
335
 
321
336
  if (!prCommentsResult.ok) {
322
337
  return {
323
- earlyReturn: prCommentsResult.type === "check_failed"
324
- ? failResult(CHECK_TYPE, prCommentsResult.message, prCommentsResult.type)
325
- : 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")
326
341
  };
327
342
  }
328
343
 
329
- prComments = flattenComments(prCommentsResult.value);
344
+ prComments = prCommentsResult.value;
330
345
  }
331
346
 
332
347
  let issueType;
@@ -367,46 +382,37 @@ function fetchRemoteData(context) {
367
382
  let prLabels = null;
368
383
  let prMilestone;
369
384
  let prAssignees;
385
+ let prHeadSha;
370
386
  if (((context.config.verify_in_labels_match_pr && context.hasTriage)
371
387
  || (context.config.verify_pr_type_label && context.hasTriage)
372
388
  || (context.config.verify_milestone && context.hasTriage)
373
- || (context.config.verify_pr_assignee && context.hasPush)) && context.prNumber) {
374
- const prFields = [];
375
- if (context.config.verify_in_labels_match_pr || context.config.verify_pr_type_label) {
376
- prFields.push("labels");
377
- }
378
- if (context.config.verify_milestone) {
379
- prFields.push("milestone");
380
- }
381
- if (context.config.verify_pr_assignee) {
382
- prFields.push("assignees");
383
- }
384
-
385
- const prResult = withRetry(() => ghJson([
386
- "pr",
387
- "view",
388
- String(context.prNumber),
389
- "--json",
390
- prFields.join(",")
391
- ], 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
+ );
392
397
 
393
398
  if (!prResult.ok) {
394
399
  return {
395
- earlyReturn: prResult.type === "check_failed"
396
- ? failResult(CHECK_TYPE, prResult.message, prResult.type)
397
- : 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")
398
403
  };
399
404
  }
400
405
 
401
406
  prLabels = (context.config.verify_in_labels_match_pr || context.config.verify_pr_type_label)
402
- ? extractLabelNames(prResult.value?.labels)
407
+ ? prResult.value.labels
403
408
  : null;
404
409
  prMilestone = context.config.verify_milestone
405
- ? prResult.value?.milestone ?? null
410
+ ? prResult.value.milestone ? { title: prResult.value.milestone } : null
406
411
  : undefined;
407
412
  prAssignees = context.config.verify_pr_assignee
408
- ? (prResult.value?.assignees || []).map((a) => a.login).filter(Boolean)
413
+ ? prResult.value.assignees
409
414
  : undefined;
415
+ prHeadSha = prResult.value.head.sha;
410
416
  }
411
417
 
412
418
  return {
@@ -417,27 +423,16 @@ function fetchRemoteData(context) {
417
423
  issueType,
418
424
  issueFields,
419
425
  prMilestone,
420
- prAssignees
426
+ prAssignees,
427
+ prHeadSha
421
428
  };
422
429
  }
423
430
 
424
- function mapTaskTypeToLabel(taskType) {
425
- const mapping = {
426
- bug: "type: bug",
427
- bugfix: "type: bug",
428
- feature: "type: feature",
429
- enhancement: "type: enhancement",
430
- refactor: "type: enhancement",
431
- refactoring: "type: enhancement",
432
- documentation: "type: documentation",
433
- "dependency-upgrade": "type: dependency-upgrade",
434
- task: "type: task"
435
- };
436
-
437
- return mapping[taskType] || null;
431
+ function mapTaskTypeToLabel(taskType: any): any {
432
+ return taskTypeLabel(taskType);
438
433
  }
439
434
 
440
- function shouldFetchComments(config) {
435
+ function shouldFetchComments(config: any): any {
441
436
  return Boolean(
442
437
  config.expected_comment_marker
443
438
  || config.expected_comment_marker_key
@@ -449,7 +444,7 @@ function shouldFetchComments(config) {
449
444
  );
450
445
  }
451
446
 
452
- function flattenComments(value) {
447
+ function flattenComments(value: any): any {
453
448
  if (!Array.isArray(value)) {
454
449
  return [];
455
450
  }
@@ -457,7 +452,7 @@ function flattenComments(value) {
457
452
  return value.flatMap((page) => Array.isArray(page) ? page : []);
458
453
  }
459
454
 
460
- function checkStatusLabel(context, remoteData) {
455
+ function checkStatusLabel(context: any, remoteData: any): any {
461
456
  if (!context.expectedStatusLabel || !context.hasTriage) {
462
457
  return null;
463
458
  }
@@ -477,7 +472,28 @@ function checkStatusLabel(context, remoteData) {
477
472
  );
478
473
  }
479
474
 
480
- function checkCommentMarker(context, remoteData) {
475
+ function checkClosedIssueStatusLabels(context: any, remoteData: any): any {
476
+ if (!context.config.verify_closed_issue_has_no_status_labels) {
477
+ return null;
478
+ }
479
+
480
+ if (String(remoteData.issue.state || "").toUpperCase() !== "CLOSED") {
481
+ return null;
482
+ }
483
+
484
+ const statusLabels = extractLabelNames(remoteData.issue.labels)
485
+ .filter((label: any) => label.startsWith("status:"));
486
+ if (statusLabels.length === 0) {
487
+ return null;
488
+ }
489
+
490
+ return failResult(CHECK_TYPE,
491
+ `Closed Issue #${context.issueNumber} retains status labels: ${statusLabels.join(", ")}`,
492
+ "check_failed"
493
+ );
494
+ }
495
+
496
+ function checkCommentMarker(context: any, remoteData: any): any {
481
497
  if (!context.marker) {
482
498
  return null;
483
499
  }
@@ -493,7 +509,7 @@ function checkCommentMarker(context, remoteData) {
493
509
  );
494
510
  }
495
511
 
496
- function checkPrCommentMarker(context, remoteData) {
512
+ function checkPrCommentMarker(context: any, remoteData: any): any {
497
513
  if (!context.prMarker) {
498
514
  return null;
499
515
  }
@@ -509,7 +525,7 @@ function checkPrCommentMarker(context, remoteData) {
509
525
  );
510
526
  }
511
527
 
512
- function checkPrCommentLastCommit(context, remoteData) {
528
+ function checkPrCommentLastCommit(context: any, remoteData: any): any {
513
529
  if (!context.config.verify_pr_comment_last_commit_matches_head) {
514
530
  return null;
515
531
  }
@@ -537,15 +553,9 @@ function checkPrCommentLastCommit(context, remoteData) {
537
553
  );
538
554
  }
539
555
 
540
- const headResult = resolvePrHeadSha(context);
541
- if (!headResult.ok) {
542
- return headResult.type === "check_failed"
543
- ? failResult(CHECK_TYPE, headResult.message, headResult.type)
544
- : blockedResult(CHECK_TYPE, headResult.message, headResult.type);
545
- }
546
-
547
- const expectedHead = String(headResult.value || "").trim();
548
- 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();
549
559
  if (expectedHead === actualHead) {
550
560
  return null;
551
561
  }
@@ -556,7 +566,7 @@ function checkPrCommentLastCommit(context, remoteData) {
556
566
  );
557
567
  }
558
568
 
559
- function checkPrCommentRequiredPatterns(context, remoteData) {
569
+ function checkPrCommentRequiredPatterns(context: any, remoteData: any): any {
560
570
  const patterns = context.config.expected_pr_comment_required_patterns || [];
561
571
  if (!Array.isArray(patterns) || patterns.length === 0) {
562
572
  return null;
@@ -591,7 +601,7 @@ function checkPrCommentRequiredPatterns(context, remoteData) {
591
601
  return null;
592
602
  }
593
603
 
594
- function checkCommentContent(context, remoteData) {
604
+ function checkCommentContent(context: any, remoteData: any): any {
595
605
  if (!context.config.verify_comment_content) {
596
606
  return null;
597
607
  }
@@ -626,7 +636,7 @@ function checkCommentContent(context, remoteData) {
626
636
  );
627
637
  }
628
638
 
629
- function checkTaskCommentContent(context, remoteData) {
639
+ function checkTaskCommentContent(context: any, remoteData: any): any {
630
640
  if (!context.config.verify_task_comment_content) {
631
641
  return null;
632
642
  }
@@ -653,7 +663,7 @@ function checkTaskCommentContent(context, remoteData) {
653
663
  );
654
664
  }
655
665
 
656
- function checkPrTypeLabel(context, remoteData) {
666
+ function checkPrTypeLabel(context: any, remoteData: any): any {
657
667
  if (!context.config.verify_pr_type_label || !context.hasTriage || !context.prNumber || !remoteData.prLabels) {
658
668
  return null;
659
669
  }
@@ -673,16 +683,16 @@ function checkPrTypeLabel(context, remoteData) {
673
683
  );
674
684
  }
675
685
 
676
- function checkInLabelsMatchPr(context, remoteData) {
686
+ function checkInLabelsMatchPr(context: any, remoteData: any): any {
677
687
  if (!context.config.verify_in_labels_match_pr || !context.hasTriage || !context.prNumber || !remoteData.prLabels) {
678
688
  return null;
679
689
  }
680
690
 
681
691
  const issueInLabels = extractLabelNames(remoteData.issue.labels)
682
- .filter((label) => label.startsWith("in:"))
692
+ .filter((label: any) => label.startsWith("in:"))
683
693
  .sort();
684
694
  const prInLabels = remoteData.prLabels
685
- .filter((label) => label.startsWith("in:"))
695
+ .filter((label: any) => label.startsWith("in:"))
686
696
  .sort();
687
697
 
688
698
  if (arraysEqual(issueInLabels, prInLabels)) {
@@ -695,7 +705,7 @@ function checkInLabelsMatchPr(context, remoteData) {
695
705
  );
696
706
  }
697
707
 
698
- function checkInLabelsComputed(context, remoteData) {
708
+ function checkInLabelsComputed(context: any, remoteData: any): any {
699
709
  if (!context.config.verify_in_labels_computed || !context.hasTriage) {
700
710
  return null;
701
711
  }
@@ -712,7 +722,7 @@ function checkInLabelsComputed(context, remoteData) {
712
722
  }
713
723
 
714
724
  const actualInLabels = extractLabelNames(remoteData.issue.labels)
715
- .filter((label) => label.startsWith("in:"))
725
+ .filter((label: any) => label.startsWith("in:"))
716
726
  .sort();
717
727
 
718
728
  if (arraysEqual(expectedInLabels.labels, actualInLabels)) {
@@ -726,7 +736,7 @@ function checkInLabelsComputed(context, remoteData) {
726
736
  );
727
737
  }
728
738
 
729
- function checkSyncedRequirements(context, remoteData) {
739
+ function checkSyncedRequirements(context: any, remoteData: any): any {
730
740
  if (!context.config.sync_checked_requirements || !context.hasTriage) {
731
741
  return null;
732
742
  }
@@ -737,8 +747,22 @@ function checkSyncedRequirements(context, remoteData) {
737
747
  }
738
748
 
739
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);
740
764
  const missingRequirements = checkedRequirements.filter(
741
- (item) => !new RegExp(`^- \\[x\\] ${escapeRegExp(item)}$`, "m").test(issueBody)
765
+ (item: any) => !hasCheckedRequirement(requirementBody, item)
742
766
  );
743
767
  if (missingRequirements.length === 0) {
744
768
  return null;
@@ -750,7 +774,7 @@ function checkSyncedRequirements(context, remoteData) {
750
774
  );
751
775
  }
752
776
 
753
- function checkIssueType(context, remoteData) {
777
+ function checkIssueType(context: any, remoteData: any): any {
754
778
  if (!context.config.verify_issue_type || !context.hasPush) {
755
779
  return null;
756
780
  }
@@ -781,7 +805,7 @@ function checkIssueType(context, remoteData) {
781
805
  return null;
782
806
  }
783
807
 
784
- function checkIssueFields(context, remoteData) {
808
+ function checkIssueFields(context: any, remoteData: any): any {
785
809
  if (!context.config.verify_issue_fields || !context.hasPush) {
786
810
  return null;
787
811
  }
@@ -820,7 +844,7 @@ function checkIssueFields(context, remoteData) {
820
844
  return null;
821
845
  }
822
846
 
823
- function checkPrAssignee(context, remoteData) {
847
+ function checkPrAssignee(context: any, remoteData: any): any {
824
848
  if (!context.config.verify_pr_assignee || !context.hasPush || !context.prNumber) {
825
849
  return null;
826
850
  }
@@ -835,7 +859,7 @@ function checkPrAssignee(context, remoteData) {
835
859
  return null;
836
860
  }
837
861
 
838
- function checkMilestone(context, remoteData) {
862
+ function checkMilestone(context: any, remoteData: any): any {
839
863
  if (!context.config.verify_milestone || !context.hasTriage) {
840
864
  return null;
841
865
  }
@@ -873,44 +897,48 @@ function checkMilestone(context, remoteData) {
873
897
  return null;
874
898
  }
875
899
 
876
- function findCommentByMarker(comments, marker) {
877
- 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;
902
+ }
903
+
904
+ function isGeneratedMarkerLine(line: any): any {
905
+ return line.startsWith("<!--") && line.endsWith("-->");
878
906
  }
879
907
 
880
- function extractCommentBody(commentBody) {
908
+ function extractCommentBody(commentBody: any): any {
881
909
  const lines = String(commentBody || "").split(/\r?\n/);
882
910
 
883
911
  let start = 0;
884
- while (start < lines.length && (lines[start].trim() === "" || /^<!--.*-->$/.test(lines[start].trim()))) {
912
+ while (start < lines.length && (lines[start]!.trim() === "" || isGeneratedMarkerLine(lines[start]!.trim()))) {
885
913
  start += 1;
886
914
  }
887
915
 
888
- if (start < lines.length && lines[start].startsWith("## ")) {
916
+ if (start < lines.length && lines[start]!.startsWith("## ")) {
889
917
  start += 1;
890
918
  }
891
919
 
892
- while (start < lines.length && lines[start].trim() === "") {
920
+ while (start < lines.length && lines[start]!.trim() === "") {
893
921
  start += 1;
894
922
  }
895
923
 
896
- if (start < lines.length && /^> \*\*.+\*\* · .+$/.test(lines[start].trim())) {
924
+ if (start < lines.length && /^> \*\*.+\*\* · .+$/.test(lines[start]!.trim())) {
897
925
  start += 1;
898
926
  }
899
927
 
900
- while (start < lines.length && lines[start].trim() === "") {
928
+ while (start < lines.length && lines[start]!.trim() === "") {
901
929
  start += 1;
902
930
  }
903
931
 
904
932
  let end = lines.length;
905
933
  for (let index = lines.length - 1; index >= start; index -= 1) {
906
- const trimmed = lines[index].trim();
934
+ const trimmed = lines[index]!.trim();
907
935
  if (trimmed === "") {
908
936
  continue;
909
937
  }
910
938
 
911
939
  if (/^\*.*\*$/.test(trimmed)) {
912
940
  end = index;
913
- if (end > start && lines[end - 1].trim() === "---") {
941
+ if (end > start && lines[end - 1]!.trim() === "---") {
914
942
  end -= 1;
915
943
  }
916
944
  }
@@ -920,7 +948,7 @@ function extractCommentBody(commentBody) {
920
948
  return lines.slice(start, end).join("\n");
921
949
  }
922
950
 
923
- function buildExpectedTaskBody(taskContent) {
951
+ function buildExpectedTaskBody(taskContent: any): any {
924
952
  const frontmatterMatch = taskContent.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
925
953
  if (!frontmatterMatch) {
926
954
  return taskContent.trim();
@@ -940,7 +968,7 @@ function buildExpectedTaskBody(taskContent) {
940
968
  ].join("\n").trim();
941
969
  }
942
970
 
943
- function buildTaskFrontmatterSummary() {
971
+ function buildTaskFrontmatterSummary(): any {
944
972
  const language = loadProjectLanguage();
945
973
  if (language === "en" || language === "en-US") {
946
974
  return "<details><summary>Metadata (frontmatter)</summary>";
@@ -949,7 +977,7 @@ function buildTaskFrontmatterSummary() {
949
977
  return "<details><summary>元数据 (frontmatter)</summary>";
950
978
  }
951
979
 
952
- function loadProjectLanguage() {
980
+ function loadProjectLanguage(): any {
953
981
  const override = process.env.VALIDATE_ARTIFACT_LANGUAGE;
954
982
  if (!isBlank(override)) {
955
983
  return String(override).trim();
@@ -968,14 +996,14 @@ function loadProjectLanguage() {
968
996
  }
969
997
  }
970
998
 
971
- function buildCommentContentMismatchMessage(fileStem, issueNumber, localContent, commentContent) {
999
+ function buildCommentContentMismatchMessage(fileStem: any, issueNumber: any, localContent: any, commentContent: any): any {
972
1000
  const diffIndex = firstDifferenceIndex(localContent, commentContent);
973
1001
  const position = indexToLineColumn(localContent, diffIndex);
974
1002
 
975
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})`;
976
1004
  }
977
1005
 
978
- function firstDifferenceIndex(left, right) {
1006
+ function firstDifferenceIndex(left: any, right: any): any {
979
1007
  const limit = Math.max(left.length, right.length);
980
1008
  for (let index = 0; index < limit; index += 1) {
981
1009
  if (left[index] !== right[index]) {
@@ -986,7 +1014,7 @@ function firstDifferenceIndex(left, right) {
986
1014
  return limit;
987
1015
  }
988
1016
 
989
- function indexToLineColumn(text, index) {
1017
+ function indexToLineColumn(text: any, index: any): any {
990
1018
  const prefix = text.slice(0, Math.min(index, text.length));
991
1019
  const lines = prefix.split("\n");
992
1020
  return {
@@ -995,14 +1023,14 @@ function indexToLineColumn(text, index) {
995
1023
  };
996
1024
  }
997
1025
 
998
- function extractLabelNames(labels) {
1026
+ function extractLabelNames(labels: any): any {
999
1027
  return (labels || [])
1000
- .map((label) => typeof label === "string" ? label : label?.name)
1001
- .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);
1002
1030
  }
1003
1031
 
1004
- function mapTaskTypeToIssueType(taskType) {
1005
- const mapping = {
1032
+ function mapTaskTypeToIssueType(taskType: any): any {
1033
+ const mapping: Record<string, string> = {
1006
1034
  bug: "Bug",
1007
1035
  bugfix: "Bug",
1008
1036
  enhancement: "Feature",
@@ -1021,7 +1049,7 @@ function mapTaskTypeToIssueType(taskType) {
1021
1049
 
1022
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}}}}}}}}`;
1023
1051
 
1024
- function normalizeIssueFields(payload) {
1052
+ function normalizeIssueFields(payload: any): any {
1025
1053
  const issue = payload?.data?.repository?.issue;
1026
1054
  const pinnedFields = Array.isArray(issue?.issueType?.pinnedFields)
1027
1055
  ? issue.issueType.pinnedFields
@@ -1031,7 +1059,7 @@ function normalizeIssueFields(payload) {
1031
1059
  : [];
1032
1060
  const pinnedNames = new Set(
1033
1061
  pinnedFields
1034
- .map((field) => typeof field?.name === "string" ? field.name : "")
1062
+ .map((field: any) => typeof field?.name === "string" ? field.name : "")
1035
1063
  .filter(Boolean)
1036
1064
  );
1037
1065
  const normalizedValues = new Map();
@@ -1058,7 +1086,7 @@ function normalizeIssueFields(payload) {
1058
1086
  return { pinnedNames, values: normalizedValues };
1059
1087
  }
1060
1088
 
1061
- function normalizeExpectedIssueField(metadataKey, rawValue) {
1089
+ function normalizeExpectedIssueField(metadataKey: any, rawValue: any): any {
1062
1090
  const value = String(rawValue || "").trim();
1063
1091
  if (!value) {
1064
1092
  return null;
@@ -1071,30 +1099,30 @@ function normalizeExpectedIssueField(metadataKey, rawValue) {
1071
1099
  return { kind: "single-select", value: normalizeOptionName(value) };
1072
1100
  }
1073
1101
 
1074
- function normalizeOptionName(value) {
1102
+ function normalizeOptionName(value: any): any {
1075
1103
  const normalized = String(value || "").trim();
1076
1104
  return OPTION_LOCALIZATION[normalized] || normalized;
1077
1105
  }
1078
1106
 
1079
- function normalizeDateValue(value) {
1107
+ function normalizeDateValue(value: any): any {
1080
1108
  const normalized = String(value || "").trim();
1081
1109
  const match = normalized.match(/^\d{4}-\d{2}-\d{2}/);
1082
1110
  return match ? match[0] : normalized;
1083
1111
  }
1084
1112
 
1085
- function arraysEqual(left, right) {
1113
+ function arraysEqual(left: any, right: any): any {
1086
1114
  if (left.length !== right.length) {
1087
1115
  return false;
1088
1116
  }
1089
1117
 
1090
- return left.every((value, index) => value === right[index]);
1118
+ return left.every((value: any, index: any) => value === right[index]);
1091
1119
  }
1092
1120
 
1093
- function formatLabelList(labels) {
1121
+ function formatLabelList(labels: any): any {
1094
1122
  return labels.length > 0 ? labels.join(", ") : "none";
1095
1123
  }
1096
1124
 
1097
- function computeExpectedInLabels(taskDir) {
1125
+ function computeExpectedInLabels(taskDir: any): any {
1098
1126
  const changedFilesResult = gitText(["diff", "main...HEAD", "--name-only"], taskDir);
1099
1127
  if (!changedFilesResult.ok) {
1100
1128
  return changedFilesResult;
@@ -1110,12 +1138,12 @@ function computeExpectedInLabels(taskDir) {
1110
1138
  return mapping;
1111
1139
  }
1112
1140
 
1113
- if (Object.keys(mapping.value).length > 0) {
1141
+ if (Object.keys(mapping.value ?? {}).length > 0) {
1114
1142
  const labels = new Set();
1115
1143
 
1116
1144
  for (const file of changedFiles) {
1117
- for (const [label, prefixes] of Object.entries(mapping.value)) {
1118
- 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))) {
1119
1147
  labels.add(`in: ${label}`);
1120
1148
  }
1121
1149
  }
@@ -1138,7 +1166,7 @@ function computeExpectedInLabels(taskDir) {
1138
1166
 
1139
1167
  const repoInLabels = new Set(
1140
1168
  extractLabelNames(repoLabelsResult.value)
1141
- .filter((label) => label.startsWith("in:"))
1169
+ .filter((label: any) => label.startsWith("in:"))
1142
1170
  );
1143
1171
 
1144
1172
  if (repoInLabels.size === 0) {
@@ -1161,7 +1189,7 @@ function computeExpectedInLabels(taskDir) {
1161
1189
  return { ok: true, labels: Array.from(labels).sort(), mode: "fallback" };
1162
1190
  }
1163
1191
 
1164
- function loadInLabelMapping() {
1192
+ function loadInLabelMapping(): any {
1165
1193
  const configPath = path.join(repoRoot, ".agents", ".airc.json");
1166
1194
  if (!fs.existsSync(configPath)) {
1167
1195
  return { ok: true, value: {} };
@@ -1174,7 +1202,7 @@ function loadInLabelMapping() {
1174
1202
  return { ok: true, value: {} };
1175
1203
  }
1176
1204
 
1177
- const normalized = {};
1205
+ const normalized: Record<string, string[]> = {};
1178
1206
  for (const [label, prefixes] of Object.entries(mapping)) {
1179
1207
  if (!Array.isArray(prefixes)) {
1180
1208
  continue;
@@ -1189,88 +1217,14 @@ function loadInLabelMapping() {
1189
1217
  }
1190
1218
 
1191
1219
  return { ok: true, value: normalized };
1192
- } catch (error) {
1220
+ } catch (error: any) {
1193
1221
  return { ok: false, type: "check_failed", message: `Unable to parse .agents/.airc.json: ${error.message}` };
1194
1222
  }
1195
1223
  }
1196
1224
 
1197
1225
  // === GitHub API ===
1198
1226
 
1199
- function normalizeIssuePayload(payload) {
1200
- return {
1201
- state: String(payload?.state || "").toUpperCase(),
1202
- labels: Array.isArray(payload?.labels) ? payload.labels : [],
1203
- body: typeof payload?.body === "string" ? payload.body : "",
1204
- milestone: payload?.milestone ?? null
1205
- };
1206
- }
1207
-
1208
- function resolveUpstreamRepo(taskDir) {
1209
- const ownerRepo = resolveOwnerRepo(taskDir);
1210
- if (!ownerRepo.ok) {
1211
- return ownerRepo;
1212
- }
1213
-
1214
- const repoResult = withRetry(() => ghJson([
1215
- "api",
1216
- `repos/${ownerRepo.value}`
1217
- ], taskDir));
1218
-
1219
- if (!repoResult.ok) {
1220
- return repoResult;
1221
- }
1222
-
1223
- const repo = repoResult.value && typeof repoResult.value === "object" ? repoResult.value : {};
1224
- const upstreamRepo = repo.fork ? repo.parent?.full_name : repo.full_name;
1225
- if (isBlank(upstreamRepo)) {
1226
- return { ok: false, message: "Unable to resolve upstream repository" };
1227
- }
1228
-
1229
- return { ok: true, value: upstreamRepo };
1230
- }
1231
-
1232
- function resolveOwnerRepo(taskDir) {
1233
- const gitResult = spawn.sync("git", ["remote", "get-url", "origin"], {
1234
- cwd: taskDir,
1235
- encoding: "utf8"
1236
- });
1237
-
1238
- if (gitResult.status !== 0) {
1239
- return { ok: false, message: `Unable to resolve git remote: ${gitResult.stderr.trim() || gitResult.stdout.trim()}` };
1240
- }
1241
-
1242
- const remote = gitResult.stdout.trim();
1243
- const sshMatch = remote.match(/[:/]([^/]+\/[^/]+?)(?:\.git)?$/);
1244
- if (!sshMatch) {
1245
- return { ok: false, message: `Unable to parse owner/repo from remote '${remote}'` };
1246
- }
1247
-
1248
- return { ok: true, value: sshMatch[1] };
1249
- }
1250
-
1251
- function detectPermissions(upstreamRepo, taskDir) {
1252
- const permissionsResult = withRetry(() => ghJson([
1253
- "api",
1254
- `repos/${upstreamRepo}`,
1255
- "--jq",
1256
- ".permissions"
1257
- ], taskDir));
1258
-
1259
- if (!permissionsResult.ok) {
1260
- return { hasTriage: false, hasPush: false };
1261
- }
1262
-
1263
- const permissions = permissionsResult.value && typeof permissionsResult.value === "object"
1264
- ? permissionsResult.value
1265
- : {};
1266
-
1267
- return {
1268
- hasTriage: permissions.triage === true,
1269
- hasPush: permissions.push === true
1270
- };
1271
- }
1272
-
1273
- function detectRepoOwnerType(upstreamRepo, taskDir) {
1227
+ function detectRepoOwnerType(upstreamRepo: any, taskDir: any): any {
1274
1228
  const ownerTypeResult = withRetry(() => ghText([
1275
1229
  "api",
1276
1230
  `repos/${upstreamRepo}`,
@@ -1285,88 +1239,43 @@ function detectRepoOwnerType(upstreamRepo, taskDir) {
1285
1239
  return ownerTypeResult.value || "unknown";
1286
1240
  }
1287
1241
 
1288
- function ghJson(args, cwd) {
1289
- const result = ghCommand(args, cwd);
1290
- if (!result.ok) {
1291
- return result;
1292
- }
1293
-
1294
- try {
1295
- return { ok: true, value: JSON.parse(result.value || "null") };
1296
- } catch (error) {
1297
- return { ok: false, type: "network_error", message: `Invalid JSON from gh: ${error.message}` };
1298
- }
1242
+ function ghJson(args: any, cwd: any): any {
1243
+ return mapClientResult(githubClient.json(args, { cwd }));
1299
1244
  }
1300
1245
 
1301
- function ghText(args, cwd) {
1302
- const result = ghCommand(args, cwd);
1303
- if (!result.ok) {
1304
- return result;
1305
- }
1306
-
1307
- return { ok: true, value: String(result.value || "").trim() };
1308
- }
1309
-
1310
- function ghCommand(args, cwd) {
1311
- const gh = resolveGhCommand();
1312
- const result = spawn.sync(gh.command, [...gh.preArgs, ...args], {
1313
- cwd,
1314
- encoding: "utf8",
1315
- env: process.env
1316
- });
1317
-
1318
- if (result.status !== 0) {
1319
- const stderr = `${result.stderr || ""}${result.stdout || ""}`.trim();
1320
- const classified = classifyGhFailure(stderr, args);
1321
- return { ok: false, type: classified.type, message: classified.message };
1322
- }
1323
-
1324
- return { ok: true, value: result.stdout };
1325
- }
1326
-
1327
- function resolveGhCommand() {
1328
- const command = process.env.AGENT_INFRA_GH_BIN || "gh";
1329
- const rawPreArgs = process.env.AGENT_INFRA_GH_ARGS_JSON;
1330
- if (!rawPreArgs) {
1331
- return { command, preArgs: [] };
1332
- }
1333
-
1334
- try {
1335
- const preArgs = JSON.parse(rawPreArgs);
1336
- if (Array.isArray(preArgs) && preArgs.every((arg) => typeof arg === "string")) {
1337
- return { command, preArgs };
1338
- }
1339
- } catch {
1340
- return { command, preArgs: [] };
1341
- }
1342
-
1343
- return { command, preArgs: [] };
1246
+ function ghText(args: any, cwd: any): any {
1247
+ return mapClientResult(githubClient.text(args, { cwd }));
1344
1248
  }
1345
1249
 
1346
- function ghPaginatedJson(args, cwd) {
1250
+ function ghPaginatedJson(args: any, cwd: any): any {
1347
1251
  return ghJson(args, cwd);
1348
1252
  }
1349
1253
 
1350
- function gitText(args, cwd) {
1351
- const result = spawn.sync("git", args, {
1352
- cwd,
1353
- encoding: "utf8",
1354
- env: process.env
1355
- });
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
+ }
1356
1263
 
1357
- if (result.status !== 0) {
1358
- 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();
1359
1270
  return {
1360
1271
  ok: false,
1361
1272
  type: "check_failed",
1362
1273
  message: stderr || `git ${args.join(" ")} failed`
1363
1274
  };
1364
1275
  }
1365
-
1366
- return { ok: true, value: String(result.stdout || "").trim() };
1367
1276
  }
1368
1277
 
1369
- function resolvePrHeadSha(context) {
1278
+ function resolvePrHeadSha(context: any): any {
1370
1279
  const fallback = () => withRetry(() => gitText(["rev-parse", "HEAD"], context.taskDir));
1371
1280
  const branch = String(context.task?.metadata?.branch || "").trim();
1372
1281
  if (!branch) {
@@ -1391,7 +1300,7 @@ function resolvePrHeadSha(context) {
1391
1300
  return headInWorktree;
1392
1301
  }
1393
1302
 
1394
- function findWorktreeForBranch(porcelainOutput, branch) {
1303
+ function findWorktreeForBranch(porcelainOutput: any, branch: any): any {
1395
1304
  let currentWorktree = "";
1396
1305
  for (const rawLine of String(porcelainOutput || "").split("\n")) {
1397
1306
  const line = rawLine.trimEnd();
@@ -1411,62 +1320,11 @@ function findWorktreeForBranch(porcelainOutput, branch) {
1411
1320
  return null;
1412
1321
  }
1413
1322
 
1414
- function withRetry(operation) {
1415
- const delays = getRetryDelays();
1416
- let lastFailure = null;
1417
-
1418
- for (let attempt = 0; attempt <= delays.length; attempt += 1) {
1419
- const result = operation();
1420
- if (result.ok) {
1421
- return result;
1422
- }
1423
-
1424
- lastFailure = result;
1425
- if (result.type === "check_failed") {
1426
- return result;
1427
- }
1428
-
1429
- if (attempt < delays.length) {
1430
- sleep(delays[attempt]);
1431
- }
1432
- }
1433
-
1434
- return lastFailure || { ok: false, type: "network_error", message: "Unknown GitHub sync failure" };
1435
- }
1436
-
1437
- function classifyGhFailure(stderr, args) {
1438
- const message = stderr || `gh ${args.join(" ")} failed`;
1439
-
1440
- if (/not found|could not resolve to an issue|http 404/i.test(message)) {
1441
- return { type: "check_failed", message };
1442
- }
1443
-
1444
- return { type: "network_error", message };
1445
- }
1446
-
1447
- function getRetryDelays() {
1448
- const override = process.env.VALIDATE_ARTIFACT_RETRY_DELAYS_MS;
1449
- if (!override) {
1450
- return DEFAULT_RETRY_DELAYS_MS;
1451
- }
1452
-
1453
- const parsed = override
1454
- .split(",")
1455
- .map((value) => Number(value.trim()))
1456
- .filter((value) => Number.isFinite(value) && value >= 0);
1457
-
1458
- return parsed.length > 0 ? parsed : DEFAULT_RETRY_DELAYS_MS;
1459
- }
1460
-
1461
- function sleep(delayMs) {
1462
- if (delayMs <= 0) {
1463
- return;
1464
- }
1465
-
1466
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, delayMs);
1323
+ function withRetry(operation: any): any {
1324
+ return operation();
1467
1325
  }
1468
1326
 
1469
- function interpolate(template, taskDir, artifactFile) {
1327
+ function interpolate(template: any, taskDir: any, artifactFile: any): any {
1470
1328
  const artifactStem = artifactFile ? path.basename(artifactFile, path.extname(artifactFile)) : "";
1471
1329
  return template
1472
1330
  .replace(/\{task-id\}/g, path.basename(taskDir))