@fitlab-ai/agent-infra 0.9.12 → 0.9.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (402) hide show
  1. package/README.md +11 -11
  2. package/README.zh-CN.md +11 -11
  3. package/bin/cli.ts +26 -9
  4. package/dist/bin/cli.js +173 -157
  5. package/dist/bin/internal-cli.js +66 -40
  6. package/dist/lib/agent-client.js +5 -0
  7. package/dist/lib/agent-clients/next-steps.js +6 -1
  8. package/dist/lib/decide.js +3 -3
  9. package/dist/lib/internal/agent-client.js +5 -2
  10. package/dist/lib/internal/cli-route-inventory.js +152 -0
  11. package/dist/lib/internal/codex-lifecycle.js +9 -6
  12. package/dist/lib/internal/codex-sandbox-controller.js +8 -2
  13. package/dist/lib/internal/git-workflow.js +10 -6
  14. package/dist/lib/internal/platform-checks.js +19 -7
  15. package/dist/lib/internal/platform-comment.js +25 -13
  16. package/dist/lib/internal/platform-context.js +6 -3
  17. package/dist/lib/internal/platform-issue.js +20 -13
  18. package/dist/lib/internal/platform-metadata.js +88 -0
  19. package/dist/lib/internal/platform-pr-review.js +26 -13
  20. package/dist/lib/internal/platform-pr.js +84 -31
  21. package/dist/lib/internal/platform-release-notes.js +9 -6
  22. package/dist/lib/internal/platform-security.js +93 -0
  23. package/dist/lib/internal/pr-review-grade.js +25 -12
  24. package/dist/lib/internal/release-workflow.js +23 -9
  25. package/dist/lib/internal/sandbox-control.js +50 -7
  26. package/dist/lib/internal/task-activity.js +16 -7
  27. package/dist/lib/internal/task-artifact.js +235 -24
  28. package/dist/lib/internal/task-context.js +4 -1
  29. package/dist/lib/internal/task-create.js +50 -17
  30. package/dist/lib/internal/task-delivery.js +4 -1
  31. package/dist/lib/internal/task-event.js +10 -4
  32. package/dist/lib/internal/task-finalization.js +6 -3
  33. package/dist/lib/internal/task-invalidation.js +63 -0
  34. package/dist/lib/internal/task-ledger.js +20 -6
  35. package/dist/lib/internal/task-lifecycle.js +6 -3
  36. package/dist/lib/internal/task-operation-registry.js +421 -0
  37. package/dist/lib/internal/task-orchestration.js +12 -0
  38. package/dist/lib/internal/task-override.js +14 -7
  39. package/dist/lib/internal/task-qualification.js +90 -0
  40. package/dist/lib/internal/task-review.js +7 -4
  41. package/dist/lib/internal/task-short-id.js +11 -1
  42. package/dist/lib/internal/task-snapshot.js +4 -1
  43. package/dist/lib/internal/task-validate.js +7 -2
  44. package/dist/lib/internal/task-verify.js +11 -7
  45. package/dist/lib/internal/task-warning.js +11 -4
  46. package/dist/lib/platform/adapters.js +1 -3
  47. package/dist/lib/platform/change-request-git-evidence.js +27 -7
  48. package/dist/lib/platform/comment-safety.js +226 -0
  49. package/dist/lib/platform/completion-backfill.js +6 -5
  50. package/dist/lib/platform/context.js +70 -130
  51. package/dist/lib/platform/github-client.js +1 -1
  52. package/dist/lib/platform/github-provider.js +1130 -0
  53. package/dist/lib/platform/in-label-sync.js +143 -0
  54. package/dist/lib/platform/issue-comments.js +237 -72
  55. package/dist/lib/platform/issues.js +335 -189
  56. package/dist/lib/platform/metadata-labels.js +6 -2
  57. package/dist/lib/platform/none-provider.js +28 -0
  58. package/dist/lib/platform/pr-change-report.js +545 -0
  59. package/dist/lib/platform/pr-checks.js +119 -104
  60. package/dist/lib/platform/pr-review.js +88 -72
  61. package/dist/lib/platform/pr-summary.js +541 -50
  62. package/dist/lib/platform/provider-bridge.js +45 -0
  63. package/dist/lib/platform/provider-contract.d.ts +553 -0
  64. package/dist/lib/platform/provider-contract.js +99 -0
  65. package/dist/lib/platform/provider-loader.js +251 -0
  66. package/dist/lib/platform/provider-validation.js +577 -0
  67. package/dist/lib/platform/pull-request-metadata.js +8 -6
  68. package/dist/lib/platform/pull-requests.js +734 -543
  69. package/dist/lib/platform/release-notes.js +78 -55
  70. package/dist/lib/platform/releases.js +79 -50
  71. package/dist/lib/platform/repository-metadata.js +377 -0
  72. package/dist/lib/platform/resource-identity.d.ts +26 -0
  73. package/dist/lib/platform/resource-identity.js +92 -0
  74. package/dist/lib/platform/security-alerts.js +155 -0
  75. package/dist/lib/platform/task-identities.js +31 -0
  76. package/dist/lib/platform/verification-required.js +11 -12
  77. package/dist/lib/platform/verification-sync.js +129 -248
  78. package/dist/lib/pr-review/evidence-grading.js +19 -6
  79. package/dist/lib/process-data/index.js +7 -0
  80. package/dist/lib/run/index.js +68 -23
  81. package/dist/lib/sandbox/commands/control-status.js +22 -0
  82. package/dist/lib/sandbox/commands/create.js +32 -6
  83. package/dist/lib/sandbox/commands/ls.js +5 -0
  84. package/dist/lib/sandbox/commands/rm.js +827 -120
  85. package/dist/lib/sandbox/commands/show.js +16 -0
  86. package/dist/lib/sandbox/control/client.js +174 -19
  87. package/dist/lib/sandbox/control/completed-reentry.js +85 -0
  88. package/dist/lib/sandbox/control/container-identity.js +28 -31
  89. package/dist/lib/sandbox/control/executor.js +151 -16
  90. package/dist/lib/sandbox/control/lifecycle.js +621 -127
  91. package/dist/lib/sandbox/control/native-file-lock.js +177 -0
  92. package/dist/lib/sandbox/control/protocol.js +77 -0
  93. package/dist/lib/sandbox/control/server.js +677 -34
  94. package/dist/lib/sandbox/control/state.js +209 -4
  95. package/dist/lib/sandbox/control/task-view.js +183 -0
  96. package/dist/lib/sandbox/engines/authority.js +289 -0
  97. package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
  98. package/dist/lib/sandbox/index.js +5 -0
  99. package/dist/lib/sandbox/recovery.js +21 -1
  100. package/dist/lib/sandbox/workspace-view.js +2 -1
  101. package/dist/lib/sandbox/worktree-safety.js +4 -1
  102. package/dist/lib/server/index.js +8 -0
  103. package/dist/lib/server/protocol.js +38 -1
  104. package/dist/lib/task/activity-log.js +8 -1
  105. package/dist/lib/task/artifact-lifecycle.js +75 -18
  106. package/dist/lib/task/artifact-operations.js +520 -0
  107. package/dist/lib/task/artifact-repair-intent.js +59 -0
  108. package/dist/lib/task/artifact-schema.js +135 -0
  109. package/dist/lib/task/capabilities.js +310 -0
  110. package/dist/lib/task/commands/status.js +32 -0
  111. package/dist/lib/task/commit-operation.js +12 -1
  112. package/dist/lib/task/control-authority.js +12 -5
  113. package/dist/lib/task/create-service.js +111 -12
  114. package/dist/lib/task/create.js +25 -0
  115. package/dist/lib/task/current-contract.js +5 -1
  116. package/dist/lib/task/decision-details.js +1 -1
  117. package/dist/lib/task/events.js +416 -17
  118. package/dist/lib/task/finalization.js +37 -13
  119. package/dist/lib/task/human-override.js +58 -36
  120. package/dist/lib/task/index.js +11 -3
  121. package/dist/lib/task/invalidation-command.js +86 -0
  122. package/dist/lib/task/invalidation.js +260 -0
  123. package/dist/lib/task/ledger-intents.js +37 -0
  124. package/dist/lib/task/local-artifact-finalization.js +299 -0
  125. package/dist/lib/task/orchestration.js +240 -144
  126. package/dist/lib/task/pr-delivery-fact.js +102 -101
  127. package/dist/lib/task/qualification-audit.js +490 -0
  128. package/dist/lib/task/qualification-confirmation.js +109 -0
  129. package/dist/lib/task/qualification-intents.js +148 -0
  130. package/dist/lib/task/review-artifacts.js +22 -23
  131. package/dist/lib/task/review-finalization.js +121 -4
  132. package/dist/lib/task/review-fingerprint.js +24 -2
  133. package/dist/lib/task/rework-intent.js +138 -0
  134. package/dist/lib/task/sections.js +6 -4
  135. package/dist/lib/task/skill-scope.js +23 -0
  136. package/dist/lib/task/task-execution-lock.js +27 -17
  137. package/dist/lib/task/verification-config.js +11 -0
  138. package/dist/lib/task/verification-engine.js +93 -16
  139. package/dist/lib/task/verification.js +3 -3
  140. package/dist/lib/task/workflow-warning-intents.js +1 -1
  141. package/dist/lib/task/write.js +11 -0
  142. package/dist/lib/version.js +11 -1
  143. package/dist/lifecycle-build-manifest.json +3 -3
  144. package/lib/agent-client.ts +9 -0
  145. package/lib/agent-clients/next-steps.ts +6 -1
  146. package/lib/decide.ts +3 -3
  147. package/lib/init.ts +1 -1
  148. package/lib/internal/agent-client.ts +4 -2
  149. package/lib/internal/cli-route-inventory.ts +140 -0
  150. package/lib/internal/codex-lifecycle.ts +8 -6
  151. package/lib/internal/codex-sandbox-controller.ts +7 -2
  152. package/lib/internal/git-workflow.ts +9 -6
  153. package/lib/internal/platform-checks.ts +14 -6
  154. package/lib/internal/platform-comment.ts +20 -12
  155. package/lib/internal/platform-context.ts +5 -3
  156. package/lib/internal/platform-issue.ts +17 -11
  157. package/lib/internal/platform-metadata.ts +70 -0
  158. package/lib/internal/platform-pr-review.ts +23 -12
  159. package/lib/internal/platform-pr.ts +65 -27
  160. package/lib/internal/platform-release-notes.ts +8 -6
  161. package/lib/internal/platform-security.ts +83 -0
  162. package/lib/internal/pr-review-grade.ts +20 -11
  163. package/lib/internal/release-workflow.ts +21 -9
  164. package/lib/internal/sandbox-control.ts +44 -6
  165. package/lib/internal/task-activity.ts +15 -7
  166. package/lib/internal/task-artifact.ts +204 -22
  167. package/lib/internal/task-context.ts +3 -1
  168. package/lib/internal/task-create.ts +78 -17
  169. package/lib/internal/task-delivery.ts +3 -1
  170. package/lib/internal/task-event.ts +9 -4
  171. package/lib/internal/task-finalization.ts +6 -4
  172. package/lib/internal/task-invalidation.ts +41 -0
  173. package/lib/internal/task-ledger.ts +21 -8
  174. package/lib/internal/task-lifecycle.ts +5 -3
  175. package/lib/internal/task-operation-registry.ts +482 -0
  176. package/lib/internal/task-orchestration.ts +12 -0
  177. package/lib/internal/task-override.ts +15 -9
  178. package/lib/internal/task-qualification.ts +61 -0
  179. package/lib/internal/task-review.ts +6 -4
  180. package/lib/internal/task-short-id.ts +10 -1
  181. package/lib/internal/task-snapshot.ts +3 -1
  182. package/lib/internal/task-validate.ts +6 -2
  183. package/lib/internal/task-verify.ts +10 -7
  184. package/lib/internal/task-warning.ts +10 -4
  185. package/lib/platform/adapters.ts +3 -2
  186. package/lib/platform/change-request-git-evidence.ts +36 -9
  187. package/lib/platform/comment-safety.ts +250 -0
  188. package/lib/platform/completion-backfill.ts +9 -8
  189. package/lib/platform/context.ts +97 -134
  190. package/lib/platform/github-client.ts +2 -2
  191. package/lib/platform/github-provider.ts +1132 -0
  192. package/lib/platform/in-label-sync.ts +208 -0
  193. package/lib/platform/issue-comments.ts +255 -80
  194. package/lib/platform/issues.ts +344 -174
  195. package/lib/platform/metadata-labels.ts +5 -2
  196. package/lib/platform/none-provider.ts +35 -0
  197. package/lib/platform/pr-change-report.ts +639 -0
  198. package/lib/platform/pr-checks.ts +126 -106
  199. package/lib/platform/pr-review.ts +88 -85
  200. package/lib/platform/pr-summary.ts +581 -53
  201. package/lib/platform/provider-bridge.ts +82 -0
  202. package/lib/platform/provider-contract.ts +611 -0
  203. package/lib/platform/provider-loader.ts +307 -0
  204. package/lib/platform/provider-validation.ts +611 -0
  205. package/lib/platform/pull-request-metadata.ts +10 -7
  206. package/lib/platform/pull-requests.ts +781 -550
  207. package/lib/platform/release-notes.ts +76 -59
  208. package/lib/platform/releases.ts +77 -43
  209. package/lib/platform/repository-metadata.ts +453 -0
  210. package/lib/platform/resource-identity.ts +121 -0
  211. package/lib/platform/security-alerts.ts +191 -0
  212. package/lib/platform/task-identities.ts +40 -0
  213. package/lib/platform/types.ts +4 -2
  214. package/lib/platform/verification-required.ts +11 -13
  215. package/lib/platform/verification-sync.ts +128 -304
  216. package/lib/pr-review/evidence-grading.ts +25 -8
  217. package/lib/process-data/index.ts +7 -0
  218. package/lib/run/index.ts +62 -22
  219. package/lib/sandbox/commands/control-status.ts +26 -0
  220. package/lib/sandbox/commands/create.ts +46 -6
  221. package/lib/sandbox/commands/ls.ts +7 -0
  222. package/lib/sandbox/commands/rm.ts +1000 -87
  223. package/lib/sandbox/commands/show.ts +16 -0
  224. package/lib/sandbox/control/client.ts +203 -19
  225. package/lib/sandbox/control/completed-reentry.ts +98 -0
  226. package/lib/sandbox/control/container-identity.ts +27 -43
  227. package/lib/sandbox/control/executor.ts +180 -15
  228. package/lib/sandbox/control/lifecycle.ts +629 -17
  229. package/lib/sandbox/control/native-file-lock.ts +209 -0
  230. package/lib/sandbox/control/protocol.ts +118 -2
  231. package/lib/sandbox/control/server.ts +724 -34
  232. package/lib/sandbox/control/state.ts +257 -4
  233. package/lib/sandbox/control/task-view.ts +240 -0
  234. package/lib/sandbox/engines/authority.ts +365 -0
  235. package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
  236. package/lib/sandbox/index.ts +7 -0
  237. package/lib/sandbox/recovery.ts +21 -1
  238. package/lib/sandbox/workspace-view.ts +9 -3
  239. package/lib/sandbox/worktree-safety.ts +4 -1
  240. package/lib/server/index.ts +10 -0
  241. package/lib/server/protocol.ts +36 -1
  242. package/lib/task/activity-log.ts +8 -0
  243. package/lib/task/artifact-lifecycle.ts +70 -22
  244. package/lib/task/artifact-operations.ts +626 -0
  245. package/lib/task/artifact-repair-intent.ts +71 -0
  246. package/lib/task/artifact-schema.ts +192 -0
  247. package/lib/task/capabilities.ts +331 -0
  248. package/lib/task/commands/status.ts +38 -0
  249. package/lib/task/commit-operation.ts +12 -1
  250. package/lib/task/control-authority.ts +22 -9
  251. package/lib/task/create-service.ts +139 -14
  252. package/lib/task/create.ts +27 -0
  253. package/lib/task/current-contract.ts +6 -1
  254. package/lib/task/decision-details.ts +6 -2
  255. package/lib/task/events.ts +392 -16
  256. package/lib/task/finalization.ts +50 -14
  257. package/lib/task/human-override.ts +70 -46
  258. package/lib/task/index.ts +16 -3
  259. package/lib/task/invalidation-command.ts +86 -0
  260. package/lib/task/invalidation.ts +332 -0
  261. package/lib/task/ledger-intents.ts +35 -1
  262. package/lib/task/local-artifact-finalization.ts +432 -0
  263. package/lib/task/orchestration.ts +223 -133
  264. package/lib/task/pr-delivery-fact.ts +131 -148
  265. package/lib/task/qualification-audit.ts +599 -0
  266. package/lib/task/qualification-confirmation.ts +117 -0
  267. package/lib/task/qualification-intents.ts +150 -0
  268. package/lib/task/review-artifacts.ts +21 -22
  269. package/lib/task/review-finalization.ts +133 -4
  270. package/lib/task/review-fingerprint.ts +23 -2
  271. package/lib/task/rework-intent.ts +165 -0
  272. package/lib/task/sections.ts +6 -4
  273. package/lib/task/skill-scope.ts +24 -0
  274. package/lib/task/task-execution-lock.ts +23 -14
  275. package/lib/task/verification-config.ts +12 -0
  276. package/lib/task/verification-engine.ts +103 -17
  277. package/lib/task/verification.ts +4 -4
  278. package/lib/task/workflow-warning-intents.ts +1 -1
  279. package/lib/task/write.ts +19 -0
  280. package/lib/update.ts +1 -1
  281. package/lib/version.ts +15 -1
  282. package/package.json +12 -1
  283. package/templates/.agents/rules/README.en.md +3 -1
  284. package/templates/.agents/rules/README.zh-CN.md +3 -1
  285. package/templates/.agents/rules/decision-qualification.en.md +22 -0
  286. package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
  287. package/templates/.agents/rules/evidence-reporting.en.md +28 -0
  288. package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
  289. package/templates/.agents/rules/issue-pr-commands.en.md +1 -1
  290. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
  291. package/templates/.agents/rules/issue-sync.en.md +2 -0
  292. package/templates/.agents/rules/issue-sync.zh-CN.md +2 -0
  293. package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
  294. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
  295. package/templates/.agents/rules/local-artifact-repair.en.md +13 -2
  296. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +13 -2
  297. package/templates/.agents/rules/pr-sync.en.md +10 -4
  298. package/templates/.agents/rules/pr-sync.zh-CN.md +17 -4
  299. package/templates/.agents/rules/security-alerts.en.md +8 -8
  300. package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
  301. package/templates/.agents/rules/task-short-id.en.md +1 -4
  302. package/templates/.agents/rules/task-short-id.zh-CN.md +1 -3
  303. package/templates/.agents/skills/analyze-task/SKILL.en.md +28 -5
  304. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +29 -5
  305. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
  306. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
  307. package/templates/.agents/skills/check-task/SKILL.en.md +16 -37
  308. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -37
  309. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  310. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  311. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  312. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  313. package/templates/.agents/skills/code-task/SKILL.en.md +41 -9
  314. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +43 -11
  315. package/templates/.agents/skills/code-task/config/verify.en.json +6 -14
  316. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +6 -14
  317. package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
  318. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
  319. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
  320. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
  321. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
  322. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
  323. package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
  324. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
  325. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +2 -0
  326. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +2 -0
  327. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +3 -3
  328. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +3 -3
  329. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +10 -4
  330. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +10 -4
  331. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
  332. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
  333. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +4 -3
  334. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +4 -3
  335. package/templates/.agents/skills/complete-task/SKILL.en.md +26 -21
  336. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +25 -21
  337. package/templates/.agents/skills/create-pr/SKILL.en.md +7 -6
  338. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +7 -7
  339. package/templates/.agents/skills/create-pr/config/verify.json +1 -0
  340. package/templates/.agents/skills/create-pr/reference/change-report.en.md +16 -4
  341. package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +16 -4
  342. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +5 -3
  343. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +5 -3
  344. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
  345. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
  346. package/templates/.agents/skills/create-pr/scripts/change-report.mjs +3 -0
  347. package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
  348. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
  349. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  350. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  351. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  352. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  353. package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
  354. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
  355. package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
  356. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
  357. package/templates/.agents/skills/plan-task/SKILL.en.md +27 -4
  358. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +26 -4
  359. package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
  360. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
  361. package/templates/.agents/skills/review-analysis/SKILL.en.md +17 -4
  362. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +17 -4
  363. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
  364. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
  365. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
  366. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
  367. package/templates/.agents/skills/review-code/SKILL.en.md +18 -5
  368. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +18 -5
  369. package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
  370. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
  371. package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
  372. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
  373. package/templates/.agents/skills/review-plan/SKILL.en.md +17 -4
  374. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +17 -4
  375. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
  376. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
  377. package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
  378. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
  379. package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
  380. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
  381. package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
  382. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
  383. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +9 -3
  384. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +9 -3
  385. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +3 -1
  386. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +3 -1
  387. package/templates/.agents/skills/test/SKILL.en.md +13 -2
  388. package/templates/.agents/skills/test/SKILL.zh-CN.md +13 -2
  389. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
  390. package/templates/.agents/skills/watch-pr/SKILL.en.md +2 -2
  391. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +2 -2
  392. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +6 -0
  393. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +6 -0
  394. package/templates/.agents/templates/task.en.md +24 -1
  395. package/templates/.agents/templates/task.zh-CN.md +24 -1
  396. package/templates/.github/workflows/pr-label.yml +7 -26
  397. package/templates/.agents/scripts/security-alerts.github.sh +0 -151
  398. package/templates/.agents/scripts/security-alerts.sh +0 -31
  399. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
  400. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
  401. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
  402. package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
@@ -0,0 +1,31 @@
1
+ import { parseResourceIdentity } from './resource-identity.js';
2
+ import { isLegacyCompatibilityEnabled, legacyCompatibilityError, VERSION } from '../version.js';
3
+ import { parse as parseYaml } from 'yaml';
4
+ function taskIssueIdentity(frontmatter, _declaration, runtimeVersion = VERSION) {
5
+ const serialized = frontmatter.platform_issue_identity;
6
+ if (typeof serialized === 'string' && serialized.trim()) {
7
+ try {
8
+ const decoded = parseYaml(serialized);
9
+ return parseResourceIdentity(JSON.parse(typeof decoded === 'string' ? decoded : serialized), 'platform_issue_identity');
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ }
15
+ const legacy = frontmatter.issue_number;
16
+ const number = typeof legacy === 'number' ? legacy : typeof legacy === 'string' && /^[1-9]\d*$/u.test(legacy) ? Number(legacy) : NaN;
17
+ // TODO(compat): Remove the numeric issue_number fallback before the first stable v1.0.0 release.
18
+ if (Number.isSafeInteger(number) && number > 0 && !isLegacyCompatibilityEnabled(runtimeVersion)) {
19
+ throw legacyCompatibilityError('issue_number', runtimeVersion);
20
+ }
21
+ return Number.isSafeInteger(number) && number > 0 ? { kind: 'number', value: number } : null;
22
+ }
23
+ function taskIssueIdentityError(error) {
24
+ const value = error && typeof error === 'object' ? error : {};
25
+ return {
26
+ code: typeof value.code === 'string' ? value.code : 'PLATFORM_IDENTITY_INVALID',
27
+ message: error instanceof Error ? error.message : String(error)
28
+ };
29
+ }
30
+ export { taskIssueIdentity, taskIssueIdentityError };
31
+ //# sourceMappingURL=task-identities.js.map
@@ -1,17 +1,13 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { execFileSync } from "node:child_process";
4
- import { hasPlatformCapability } from "./adapters.js";
5
4
  import { inspectRequiredChecks } from "./pr-checks.js";
6
- import { resolvePlatformContext } from "./context.js";
5
+ import { resolvePlatformProviderContext } from "./context.js";
7
6
  import { resolveReviewedHeadRelation } from "./merged-pr-equivalence.js";
8
7
  import { readPrDeliveryFact } from "../task/pr-delivery-fact.js";
8
+ import { resourceIdentityNumber } from "./resource-identity.js";
9
9
  const CHECK_TYPE = "required-checks";
10
10
  const SHA_PATTERN = /^[0-9a-f]{7,40}$/i;
11
- function validPrNumber(value) {
12
- const parsed = Number(value);
13
- return Number.isInteger(parsed) && parsed > 0;
14
- }
15
11
  function readPrFlow(repoRoot) {
16
12
  try {
17
13
  const config = JSON.parse(fs.readFileSync(path.join(repoRoot, ".agents", ".airc.json"), "utf8"));
@@ -36,8 +32,9 @@ export function evaluateRequiredChecks(context, shared) {
36
32
  return shared.failResult(CHECK_TYPE, factRead.error.message, "check_failed");
37
33
  }
38
34
  const fact = factRead.status === "valid" ? factRead.fact : null;
39
- const prNumber = fact?.state === "bound" ? fact.identity.number : null;
40
- if (prFlow === "disabled" || fact?.state === "skipped" || !validPrNumber(prNumber)) {
35
+ const prIdentity = fact?.state === "bound" ? fact.identity.resource : null;
36
+ const prNumber = resourceIdentityNumber(prIdentity);
37
+ if (prFlow === "disabled" || fact?.state === "skipped" || !prIdentity) {
41
38
  return shared.passResult(CHECK_TYPE, "Skipped: required checks are not applicable to this task");
42
39
  }
43
40
  const reviewedHead = String(metadata.last_reviewed_commit || "");
@@ -80,7 +77,7 @@ export function evaluateRequiredChecks(context, shared) {
80
77
  }
81
78
  return shared.failResult(CHECK_TYPE, inspection.error?.message || `Required checks are ${state || "unavailable"}`, "check_failed");
82
79
  }
83
- export function check({ taskDir }, shared) {
80
+ export async function check({ taskDir }, shared) {
84
81
  const task = shared.loadTask(taskDir);
85
82
  if (!task.ok)
86
83
  return shared.failResult(CHECK_TYPE, task.message);
@@ -92,14 +89,16 @@ export function check({ taskDir }, shared) {
92
89
  if (prFlow === "disabled" || (factRead.status === "valid" && factRead.fact.state === "skipped") || !bound) {
93
90
  return evaluateRequiredChecks({ metadata: task.metadata, localHead: null, inspection: null, prFlow }, shared);
94
91
  }
95
- const platform = resolvePlatformContext({ cwd: shared.repoRoot });
96
- if (!hasPlatformCapability(platform.platform.type, "required-checks")) {
92
+ const loaded = await resolvePlatformProviderContext({ cwd: shared.repoRoot });
93
+ const platform = loaded.ok ? loaded.value.context : loaded.context;
94
+ const supportsChecks = loaded.ok && Boolean(loaded.value.provider.checks?.inspectRequired);
95
+ if (!supportsChecks) {
97
96
  return shared.blockedResult(CHECK_TYPE, `Platform '${platform.platform.type || "none"}' does not provide required-checks inspection`, "dependency_error");
98
97
  }
99
98
  const localHead = readHead(shared.repoRoot);
100
99
  if (!localHead)
101
100
  return evaluateRequiredChecks({ metadata: task.metadata, localHead, inspection: null, prFlow }, shared);
102
- const inspection = inspectRequiredChecks(task.metadata.id, { cwd: shared.repoRoot });
101
+ const inspection = await inspectRequiredChecks(task.metadata.id, { cwd: shared.repoRoot });
103
102
  return evaluateRequiredChecks({
104
103
  metadata: task.metadata,
105
104
  localHead,
@@ -2,14 +2,14 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import process from "node:process";
4
4
  import { execFileSync } from "node:child_process";
5
- import { createGitHubClient } from "./github-client.js";
6
- import { resolvePlatformContext } from "./context.js";
5
+ import { resolvePlatformProviderContext } from "./context.js";
7
6
  import { hasCheckedRequirement, resolveRequirementSection } from "./issue-metadata.js";
8
- import { inspectGitHubIssueMetadata, requirementSectionAnchors } from "./issues.js";
9
- import { listRemoteComments } from "./issue-comments.js";
7
+ import { requirementSectionAnchors } from "./issues.js";
10
8
  import { taskTypeLabel } from "./metadata-labels.js";
11
- import { inspectGitHubPullRequest } from "./pull-requests.js";
9
+ import { planInLabelUpdate, validateInLabelMapping } from "./in-label-sync.js";
12
10
  import { readPrDeliveryFact } from "../task/pr-delivery-fact.js";
11
+ import { providerError, providerOperationContext, resourceIdentityNumber, unsupportedProviderOperation } from "./provider-bridge.js";
12
+ import { taskIssueIdentity } from "./task-identities.js";
13
13
  const CHECK_TYPE = "platform-sync";
14
14
  const VERSION_LINE_REGEX = /^[0-9]+\.[0-9]+\.x$/;
15
15
  const FRONTMATTER_FIELD_MAP = {
@@ -26,7 +26,6 @@ const OPTION_LOCALIZATION = {
26
26
  };
27
27
  let activeShared = null;
28
28
  let repoRoot = "";
29
- const githubClient = createGitHubClient();
30
29
  export function getDefaults() {
31
30
  return {
32
31
  statusLabels: {
@@ -79,20 +78,14 @@ function blockedResult(...args) {
79
78
  function safeStat(...args) {
80
79
  return getShared().safeStat(...args);
81
80
  }
82
- function parseIssueNumber(...args) {
83
- return getShared().parseIssueNumber(...args);
84
- }
85
- function parsePrNumber(...args) {
86
- return getShared().parsePrNumber(...args);
87
- }
88
- export function check({ taskDir, config, artifactFile }, shared) {
81
+ export async function check({ taskDir, config, artifactFile }, shared) {
89
82
  activeShared = shared;
90
83
  repoRoot = shared.repoRoot;
91
- const context = buildSyncContext({ taskDir, config, artifactFile });
84
+ const context = await buildSyncContext({ taskDir, config, artifactFile });
92
85
  if (context.earlyReturn) {
93
86
  return context.earlyReturn;
94
87
  }
95
- const remoteData = fetchRemoteData(context);
88
+ const remoteData = await fetchRemoteData(context);
96
89
  if (remoteData.earlyReturn) {
97
90
  return remoteData.earlyReturn;
98
91
  }
@@ -120,29 +113,32 @@ export function check({ taskDir, config, artifactFile }, shared) {
120
113
  return result;
121
114
  }
122
115
  }
123
- return passResult(CHECK_TYPE, `GitHub sync checks passed for Issue #${context.issueNumber}`);
116
+ return passResult(CHECK_TYPE, `Platform sync checks passed for Issue ${context.issueNumber || "identity"}`);
124
117
  }
125
- function buildSyncContext({ taskDir, config, artifactFile }) {
118
+ async function buildSyncContext({ taskDir, config, artifactFile }) {
126
119
  const task = loadTask(taskDir);
127
120
  if (!task.ok) {
128
121
  return { earlyReturn: failResult(CHECK_TYPE, task.message) };
129
122
  }
130
- const issueNumber = parseIssueNumber(task.metadata.issue_number);
123
+ const issueIdentity = taskIssueIdentity(task.metadata);
124
+ const issueNumber = resourceIdentityNumber(issueIdentity);
131
125
  const fact = readPrDeliveryFact(task.metadata);
132
126
  if (fact.status === "invalid") {
133
127
  return { earlyReturn: failResult(CHECK_TYPE, fact.error.message, "check_failed") };
134
128
  }
135
- const prNumber = fact.status === "valid" && fact.fact.state === "bound" ? fact.fact.identity.number : null;
136
- if (config.when === "issue_number_exists" && !issueNumber) {
129
+ const prIdentity = fact.status === "valid" && fact.fact.state === "bound" ? fact.fact.identity.resource : null;
130
+ const prNumber = resourceIdentityNumber(prIdentity);
131
+ if (config.when === "issue_number_exists" && !issueIdentity) {
137
132
  return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no issue_number") };
138
133
  }
139
- if (config.when === "pr_fact_bound" && !prNumber) {
134
+ if (config.when === "pr_fact_bound" && !prIdentity) {
140
135
  return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no verified bound pull request") };
141
136
  }
142
- if (!issueNumber) {
137
+ if (!issueIdentity) {
143
138
  return { earlyReturn: passResult(CHECK_TYPE, "Skipped: platform-sync not required for this task") };
144
139
  }
145
- const platformContext = resolvePlatformContext({ cwd: repoRoot, client: githubClient });
140
+ const loaded = await resolvePlatformProviderContext({ cwd: repoRoot });
141
+ const platformContext = loaded.ok ? loaded.value.context : loaded.context;
146
142
  if (platformContext.status === "failed") {
147
143
  return { earlyReturn: failResult(CHECK_TYPE, platformContext.error?.message || "Platform context failed", "check_failed") };
148
144
  }
@@ -155,7 +151,6 @@ function buildSyncContext({ taskDir, config, artifactFile }) {
155
151
  }
156
152
  return { earlyReturn: passResult(CHECK_TYPE, `Skipped: ${platformContext.error?.message || "platform unavailable"}`) };
157
153
  }
158
- const repoOwnerType = detectRepoOwnerType(platformContext.platform.repository, taskDir);
159
154
  const expectedValues = resolveExpectedValues(config);
160
155
  if (!expectedValues.ok) {
161
156
  return { earlyReturn: failResult(CHECK_TYPE, expectedValues.message, "check_failed") };
@@ -173,15 +168,19 @@ function buildSyncContext({ taskDir, config, artifactFile }) {
173
168
  config,
174
169
  artifactFile,
175
170
  artifactPath,
171
+ issueIdentity,
172
+ prIdentity,
176
173
  issueNumber,
177
174
  prNumber,
178
- upstreamRepo: platformContext.platform.repository,
179
- repoOwnerType,
175
+ repoOwnerType: String(loaded.ok ? loaded.value.snapshot.metadata?.ownerType || "unknown" : "unknown"),
180
176
  hasTriage: platformContext.capabilities.triage,
181
177
  hasPush: platformContext.capabilities.push,
182
178
  expectedStatusLabel: expectedValues.statusLabel,
183
179
  marker,
184
- prMarker
180
+ prMarker,
181
+ provider: loaded.ok ? loaded.value.provider : null,
182
+ providerType: loaded.ok ? loaded.value.providerType : null,
183
+ loadedContext: loaded.ok ? loaded.value : null
185
184
  };
186
185
  }
187
186
  function resolveExpectedValues(config) {
@@ -230,139 +229,93 @@ function resolveDefaultValue({ collection, key, value, configKey }) {
230
229
  }
231
230
  return { ok: true, value: resolvedValue };
232
231
  }
233
- function fetchRemoteData(context) {
234
- const sharedIssue = inspectGitHubIssueMetadata(githubClient, context.upstreamRepo, context.issueNumber, context.taskDir);
235
- const issueResult = sharedIssue.ok
236
- ? {
237
- ok: true,
238
- value: {
239
- state: sharedIssue.value.state.toUpperCase(),
240
- labels: sharedIssue.value.labels.map((name) => ({ name })),
241
- body: sharedIssue.value.body,
242
- milestone: sharedIssue.value.milestone ? { title: sharedIssue.value.milestone } : null
243
- }
244
- }
245
- : {
246
- ok: false,
247
- type: sharedIssue.error.retryable ? "network_error" : "check_failed",
248
- message: sharedIssue.error.message
249
- };
250
- if (!issueResult.ok) {
232
+ async function fetchRemoteData(context) {
233
+ const provider = context.provider;
234
+ const operationContext = providerOperationContext(context.loadedContext, context.taskDir);
235
+ const facts = provider?.verification?.fetchRemoteFacts
236
+ ? await provider.verification.fetchRemoteFacts({
237
+ context: operationContext,
238
+ taskId: context.task?.metadata?.id || context.task?.id || "",
239
+ ...(context.issueIdentity ? { issue: context.issueIdentity } : {}),
240
+ ...(context.prIdentity ? { changeRequest: context.prIdentity } : {}),
241
+ includeComments: shouldFetchComments(context.config),
242
+ includeFields: Boolean(context.config.verify_issue_fields)
243
+ })
244
+ : unsupportedProviderOperation(provider, "verification.fetchRemoteFacts");
245
+ if (!facts.ok) {
251
246
  return {
252
- earlyReturn: issueResult.type === "check_failed"
253
- ? failResult(CHECK_TYPE, issueResult.message, issueResult.type)
254
- : blockedResult(CHECK_TYPE, issueResult.message, issueResult.type)
247
+ earlyReturn: facts.error.retryable
248
+ ? blockedResult(CHECK_TYPE, providerError(facts.error, "PLATFORM_PROVIDER_OPERATION_FAILED").message, "network_error")
249
+ : failResult(CHECK_TYPE, providerError(facts.error, "PLATFORM_PROVIDER_OPERATION_FAILED").message, "check_failed")
255
250
  };
256
251
  }
257
- const issue = issueResult.value;
258
- if (context.config.issue_must_exist !== false && !issue) {
259
- return {
260
- earlyReturn: failResult(CHECK_TYPE, `Issue #${context.issueNumber} not found`, "check_failed")
261
- };
262
- }
263
- let comments = null;
264
- if (shouldFetchComments(context.config)) {
265
- const commentsResult = withRetry(() => ghPaginatedJson([
266
- "api",
267
- "--paginate",
268
- "--slurp",
269
- `repos/${context.upstreamRepo}/issues/${context.issueNumber}/comments?per_page=100`
270
- ], context.taskDir));
271
- if (!commentsResult.ok) {
272
- return {
273
- earlyReturn: commentsResult.type === "check_failed"
274
- ? failResult(CHECK_TYPE, commentsResult.message, commentsResult.type)
275
- : blockedResult(CHECK_TYPE, commentsResult.message, commentsResult.type)
276
- };
277
- }
278
- comments = flattenComments(commentsResult.value);
279
- }
280
- let prComments = null;
281
- if (context.prMarker) {
282
- if (!context.prNumber) {
283
- return {
284
- earlyReturn: failResult(CHECK_TYPE, "Expected a verified bound pull request for PR comment verification", "check_failed")
285
- };
286
- }
287
- const prCommentsResult = listRemoteComments(githubClient, context.upstreamRepo, context.prNumber, context.taskDir);
288
- if (!prCommentsResult.ok) {
289
- return {
290
- earlyReturn: prCommentsResult.error.retryable
291
- ? blockedResult(CHECK_TYPE, prCommentsResult.error.message, "network_error")
292
- : failResult(CHECK_TYPE, prCommentsResult.error.message, "check_failed")
293
- };
294
- }
295
- prComments = prCommentsResult.value;
296
- }
297
- let issueType;
298
- if (context.config.verify_issue_type && context.hasPush) {
299
- const issueTypeResult = withRetry(() => ghText([
300
- "api",
301
- `repos/${context.upstreamRepo}/issues/${context.issueNumber}`,
302
- "--jq",
303
- ".type.name // empty"
304
- ], context.taskDir));
305
- if (issueTypeResult.ok) {
306
- issueType = issueTypeResult.value || null;
252
+ const issueSnapshot = facts.value.issue;
253
+ const issue = issueSnapshot
254
+ ? {
255
+ state: issueSnapshot.state.toUpperCase(),
256
+ labels: issueSnapshot.labels.map((name) => ({ name })),
257
+ body: issueSnapshot.body,
258
+ milestone: issueSnapshot.milestone ? { title: issueSnapshot.milestone } : null
307
259
  }
308
- }
260
+ : null;
309
261
  let issueFields;
310
- if (context.config.verify_issue_fields && context.hasPush) {
311
- const [owner, name] = context.upstreamRepo.split("/");
312
- const issueFieldsResult = withRetry(() => ghJson([
313
- "api",
314
- "graphql",
315
- "-f",
316
- `query=${ISSUE_FIELDS_QUERY}`,
317
- "-F",
318
- `owner=${owner}`,
319
- "-F",
320
- `name=${name}`,
321
- "-F",
322
- `number=${context.issueNumber}`
323
- ], context.taskDir));
324
- if (issueFieldsResult.ok) {
325
- issueFields = normalizeIssueFields(issueFieldsResult.value);
326
- }
262
+ if (context.config.verify_issue_fields && issueSnapshot?.issueType) {
263
+ const fieldKinds = new Map(issueSnapshot.issueType.fields.map((field) => [field.name, field.kind]));
264
+ issueFields = {
265
+ pinnedNames: new Set(issueSnapshot.issueType.fields.map((field) => field.name)),
266
+ values: new Map(Object.entries(issueSnapshot.fields).map(([name, value]) => [name, { kind: fieldKinds.get(name) || (typeof value === "number" ? "number" : "single-select"), value }]))
267
+ };
327
268
  }
328
- let prLabels = null;
329
- let prMilestone;
330
- let prAssignees;
331
- let prHeadSha;
332
- if (((context.config.verify_in_labels_match_pr && context.hasTriage)
333
- || (context.config.verify_pr_type_label && context.hasTriage)
334
- || (context.config.verify_milestone && context.hasTriage)
335
- || (context.config.verify_pr_assignee && context.hasPush)
336
- || context.config.verify_pr_comment_last_commit_matches_head) && context.prNumber) {
337
- const prResult = inspectGitHubPullRequest(githubClient, context.upstreamRepo, context.prNumber, context.taskDir);
338
- if (!prResult.ok) {
269
+ let prComments = null;
270
+ if (context.prMarker && context.prIdentity && shouldFetchComments(context.config) && provider?.comments?.list) {
271
+ const listed = await provider.comments.list({ context: operationContext, parent: context.prIdentity });
272
+ if (!listed.ok)
339
273
  return {
340
- earlyReturn: prResult.error.retryable
341
- ? blockedResult(CHECK_TYPE, prResult.error.message, "network_error")
342
- : failResult(CHECK_TYPE, prResult.error.message, "check_failed")
274
+ earlyReturn: listed.error.retryable
275
+ ? blockedResult(CHECK_TYPE, listed.error.message, "network_error")
276
+ : failResult(CHECK_TYPE, listed.error.message, "check_failed")
343
277
  };
278
+ prComments = listed.value.map((comment) => ({ id: comment.id, body: comment.body }));
279
+ }
280
+ const changeRequest = facts.value.changeRequest;
281
+ let inLabelMapping = {};
282
+ let repositoryLabels = [];
283
+ if (context.config.verify_in_labels_computed && context.hasTriage) {
284
+ const mapping = loadInLabelMapping();
285
+ if (!mapping.ok)
286
+ return { earlyReturn: failResult(CHECK_TYPE, mapping.message, "check_failed") };
287
+ inLabelMapping = mapping.value;
288
+ if (Object.keys(inLabelMapping).length > 0) {
289
+ const labels = provider?.issues?.listLabels
290
+ ? await provider.issues.listLabels({ context: operationContext })
291
+ : unsupportedProviderOperation(provider, "issues.listLabels");
292
+ if (!labels.ok) {
293
+ const error = providerError(labels.error, "PLATFORM_PROVIDER_OPERATION_FAILED");
294
+ return {
295
+ earlyReturn: error.retryable
296
+ ? blockedResult(CHECK_TYPE, `${error.code}: ${error.message}`, "network_error")
297
+ : failResult(CHECK_TYPE, `${error.code}: ${error.message}`, "check_failed")
298
+ };
299
+ }
300
+ repositoryLabels = labels.value;
344
301
  }
345
- prLabels = (context.config.verify_in_labels_match_pr || context.config.verify_pr_type_label)
346
- ? prResult.value.labels
347
- : null;
348
- prMilestone = context.config.verify_milestone
349
- ? prResult.value.milestone ? { title: prResult.value.milestone } : null
350
- : undefined;
351
- prAssignees = context.config.verify_pr_assignee
352
- ? prResult.value.assignees
353
- : undefined;
354
- prHeadSha = prResult.value.head.sha;
355
302
  }
356
303
  return {
357
304
  issue,
358
- comments,
305
+ comments: facts.value.comments.map((comment) => ({ id: comment.id, body: comment.body })),
359
306
  prComments,
360
- prLabels,
361
- issueType,
307
+ prLabels: changeRequest?.labels || null,
308
+ issueType: issueSnapshot
309
+ ? (issueSnapshot.issueType ? issueSnapshot.issueType.name : null)
310
+ : undefined,
362
311
  issueFields,
363
- prMilestone,
364
- prAssignees,
365
- prHeadSha
312
+ prMilestone: changeRequest
313
+ ? (changeRequest.milestone ? { title: changeRequest.milestone } : null)
314
+ : undefined,
315
+ prAssignees: changeRequest?.assignees,
316
+ prHeadSha: changeRequest?.headSha,
317
+ inLabelMapping,
318
+ repositoryLabels
366
319
  };
367
320
  }
368
321
  function mapTaskTypeToLabel(taskType) {
@@ -377,12 +330,6 @@ function shouldFetchComments(config) {
377
330
  || config.verify_comment_content
378
331
  || config.verify_task_comment_content);
379
332
  }
380
- function flattenComments(value) {
381
- if (!Array.isArray(value)) {
382
- return [];
383
- }
384
- return value.flatMap((page) => Array.isArray(page) ? page : []);
385
- }
386
333
  function checkStatusLabel(context, remoteData) {
387
334
  if (!context.expectedStatusLabel || !context.hasTriage) {
388
335
  return null;
@@ -541,7 +488,7 @@ function checkInLabelsComputed(context, remoteData) {
541
488
  if (!context.config.verify_in_labels_computed || !context.hasTriage) {
542
489
  return null;
543
490
  }
544
- const expectedInLabels = computeExpectedInLabels(context.taskDir);
491
+ const expectedInLabels = computeExpectedInLabels(context.taskDir, remoteData.repositoryLabels, remoteData.inLabelMapping);
545
492
  if (!expectedInLabels.ok) {
546
493
  return expectedInLabels.type === "check_failed"
547
494
  ? failResult(CHECK_TYPE, expectedInLabels.message, expectedInLabels.type)
@@ -781,7 +728,6 @@ function mapTaskTypeToIssueType(taskType) {
781
728
  };
782
729
  return mapping[taskType] || "Task";
783
730
  }
784
- 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}}}}}}}}`;
785
731
  function normalizeIssueFields(payload) {
786
732
  const issue = payload?.data?.repository?.issue;
787
733
  const pinnedFields = Array.isArray(issue?.issueType?.pinnedFields)
@@ -842,58 +788,37 @@ function arraysEqual(left, right) {
842
788
  function formatLabelList(labels) {
843
789
  return labels.length > 0 ? labels.join(", ") : "none";
844
790
  }
845
- function computeExpectedInLabels(taskDir) {
846
- const changedFilesResult = gitText(["diff", "main...HEAD", "--name-only"], taskDir);
791
+ function computeExpectedInLabels(taskDir, repositoryLabels = [], mappingOverride) {
792
+ const task = loadTask(taskDir);
793
+ if (!task.ok) {
794
+ return task;
795
+ }
796
+ const baseRef = String(task.metadata?.delivery_base_ref || "").trim();
797
+ if (!baseRef) {
798
+ return { ok: false, type: "check_failed", message: "Task has no delivery_base_ref for in-label evidence" };
799
+ }
800
+ const changedFilesResult = gitText(["diff", `${baseRef}...HEAD`, "--name-only"], taskDir);
847
801
  if (!changedFilesResult.ok) {
848
- return changedFilesResult;
802
+ return { ...changedFilesResult, type: "network_error" };
849
803
  }
850
804
  const changedFiles = String(changedFilesResult.value || "")
851
805
  .split(/\r?\n/)
852
806
  .map((value) => value.trim())
853
807
  .filter(Boolean);
854
- const mapping = loadInLabelMapping();
855
- if (!mapping.ok) {
856
- return mapping;
857
- }
858
- if (Object.keys(mapping.value ?? {}).length > 0) {
859
- const labels = new Set();
860
- for (const file of changedFiles) {
861
- for (const [label, prefixes] of Object.entries(mapping.value ?? {})) {
862
- if (prefixes.some((prefix) => file.startsWith(prefix))) {
863
- labels.add(`in: ${label}`);
864
- }
865
- }
866
- }
867
- return { ok: true, labels: Array.from(labels).sort(), mode: "mapped" };
868
- }
869
- const repoLabelsResult = withRetry(() => ghJson([
870
- "label",
871
- "list",
872
- "--limit",
873
- "200",
874
- "--json",
875
- "name"
876
- ], taskDir));
877
- if (!repoLabelsResult.ok) {
878
- return repoLabelsResult;
879
- }
880
- const repoInLabels = new Set(extractLabelNames(repoLabelsResult.value)
881
- .filter((label) => label.startsWith("in:")));
882
- if (repoInLabels.size === 0) {
883
- return { ok: true, labels: [], mode: "fallback" };
884
- }
885
- const labels = new Set();
886
- for (const file of changedFiles) {
887
- const topLevel = file.split("/")[0];
888
- if (!topLevel) {
889
- continue;
890
- }
891
- const candidate = `in: ${topLevel}`;
892
- if (repoInLabels.has(candidate)) {
893
- labels.add(candidate);
894
- }
808
+ const mapping = mappingOverride ?? {};
809
+ if (Object.keys(mapping).length === 0) {
810
+ return { ok: true, labels: [], mode: "mapped" };
811
+ }
812
+ const planned = planInLabelUpdate({
813
+ changedFiles,
814
+ currentLabels: [],
815
+ mapping,
816
+ repositoryLabels: new Set(repositoryLabels)
817
+ });
818
+ if (planned.error) {
819
+ return { ok: false, type: "check_failed", message: planned.error.message };
895
820
  }
896
- return { ok: true, labels: Array.from(labels).sort(), mode: "fallback" };
821
+ return { ok: true, labels: planned.target, mode: "mapped" };
897
822
  }
898
823
  function loadInLabelMapping() {
899
824
  const configPath = path.join(repoRoot, ".agents", ".airc.json");
@@ -902,60 +827,16 @@ function loadInLabelMapping() {
902
827
  }
903
828
  try {
904
829
  const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
905
- const mapping = config?.labels?.in;
906
- if (!mapping || typeof mapping !== "object" || Array.isArray(mapping)) {
907
- return { ok: true, value: {} };
908
- }
909
- const normalized = {};
910
- for (const [label, prefixes] of Object.entries(mapping)) {
911
- if (!Array.isArray(prefixes)) {
912
- continue;
913
- }
914
- const cleaned = prefixes
915
- .map((value) => String(value || "").trim())
916
- .filter(Boolean);
917
- if (cleaned.length > 0) {
918
- normalized[label] = cleaned;
919
- }
920
- }
921
- return { ok: true, value: normalized };
830
+ const mapping = validateInLabelMapping(config?.labels?.in);
831
+ return mapping.ok
832
+ ? { ok: true, value: mapping.value }
833
+ : { ok: false, type: "check_failed", message: mapping.error.message };
922
834
  }
923
835
  catch (error) {
924
836
  return { ok: false, type: "check_failed", message: `Unable to parse .agents/.airc.json: ${error.message}` };
925
837
  }
926
838
  }
927
- // === GitHub API ===
928
- function detectRepoOwnerType(upstreamRepo, taskDir) {
929
- const ownerTypeResult = withRetry(() => ghText([
930
- "api",
931
- `repos/${upstreamRepo}`,
932
- "--jq",
933
- ".owner.type // empty"
934
- ], taskDir));
935
- if (!ownerTypeResult.ok) {
936
- return "unknown";
937
- }
938
- return ownerTypeResult.value || "unknown";
939
- }
940
- function ghJson(args, cwd) {
941
- return mapClientResult(githubClient.json(args, { cwd }));
942
- }
943
- function ghText(args, cwd) {
944
- return mapClientResult(githubClient.text(args, { cwd }));
945
- }
946
- function ghPaginatedJson(args, cwd) {
947
- return ghJson(args, cwd);
948
- }
949
- function mapClientResult(result) {
950
- if (result.ok)
951
- return result;
952
- const checkFailed = ["RESOURCE_NOT_FOUND", "PERMISSION_DENIED", "PLATFORM_REQUEST_INVALID"].includes(result.error.code);
953
- return {
954
- ok: false,
955
- type: checkFailed ? "check_failed" : "network_error",
956
- message: result.error.message
957
- };
958
- }
839
+ // === Git working tree ===
959
840
  function gitText(args, cwd) {
960
841
  try {
961
842
  const value = execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
@@ -2,6 +2,8 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { parseTypedTaskFrontmatter } from '../task/frontmatter.js';
4
4
  import { readPrDeliveryFact } from '../task/pr-delivery-fact.js';
5
+ import { resourceIdentityEquals, resourceIdentityNumber } from '../platform/resource-identity.js';
6
+ import { taskIssueIdentity } from '../platform/task-identities.js';
5
7
  export class HostResolutionError extends Error {
6
8
  code;
7
9
  constructor(code, message) {
@@ -70,14 +72,23 @@ export function collectHostCandidates(input) {
70
72
  catch {
71
73
  continue;
72
74
  }
73
- const issueNumber = toPositiveNumber(frontmatter.issue_number);
75
+ const issueIdentity = taskIssueIdentity(frontmatter);
76
+ const issueNumber = resourceIdentityNumber(issueIdentity) ?? toPositiveNumber(frontmatter.issue_number);
74
77
  const fact = readPrDeliveryFact(frontmatter);
75
- const prNumber = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.number : null;
76
- if (prNumber === input.prNumber) {
77
- candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber });
78
+ const prIdentity = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.resource : null;
79
+ const prNumber = resourceIdentityNumber(prIdentity);
80
+ const matchesPr = input.prIdentity
81
+ ? Boolean(prIdentity && resourceIdentityEquals(prIdentity, input.prIdentity))
82
+ : input.prNumber !== undefined && prNumber === input.prNumber;
83
+ const identityDetails = {
84
+ ...(issueIdentity && issueIdentity.kind !== 'number' ? { issueIdentity } : {}),
85
+ ...(prIdentity && prIdentity.kind !== 'number' ? { prIdentity } : {})
86
+ };
87
+ if (matchesPr) {
88
+ candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber, ...identityDetails });
78
89
  }
79
90
  else if (issueNumber !== null && input.closingIssues.includes(issueNumber)) {
80
- candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber });
91
+ candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber, ...identityDetails });
81
92
  }
82
93
  }
83
94
  return candidates;
@@ -97,7 +108,9 @@ export function resolveHostFromCandidates(candidates) {
97
108
  taskId: candidate.taskId,
98
109
  taskDir: candidate.taskDir,
99
110
  issueNumber: candidate.issueNumber ?? 0,
100
- prNumber: candidate.prNumber ?? 0
111
+ prNumber: candidate.prNumber ?? 0,
112
+ ...(candidate.issueIdentity ? { issueIdentity: candidate.issueIdentity } : {}),
113
+ ...(candidate.prIdentity ? { prIdentity: candidate.prIdentity } : {})
101
114
  };
102
115
  }
103
116
  return {