@fitlab-ai/agent-infra 0.9.13 → 0.9.15

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 (428) hide show
  1. package/README.md +10 -0
  2. package/README.zh-CN.md +10 -0
  3. package/bin/cli.ts +26 -9
  4. package/bin/internal-cli.sh +45 -0
  5. package/dist/bin/cli.js +173 -157
  6. package/dist/bin/internal-cli.js +126 -42
  7. package/dist/lib/agent-client.js +5 -0
  8. package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +165 -27
  9. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +3 -2
  10. package/dist/lib/defaults.json +103 -103
  11. package/dist/lib/fs/durable-write.js +37 -0
  12. package/dist/lib/fs/file-lock.js +111 -0
  13. package/dist/lib/host-control/audit.js +19 -0
  14. package/dist/lib/host-control/client.js +142 -0
  15. package/dist/lib/host-control/command.js +49 -0
  16. package/dist/lib/host-control/path.js +160 -0
  17. package/dist/lib/host-control/secure-fs.js +140 -0
  18. package/dist/lib/host-control/server.js +159 -0
  19. package/dist/lib/host-control/service.js +112 -0
  20. package/dist/lib/init.js +11 -2
  21. package/dist/lib/internal/agent-client.js +5 -2
  22. package/dist/lib/internal/cli-route-inventory.js +154 -0
  23. package/dist/lib/internal/codex-lifecycle.js +15 -12
  24. package/dist/lib/internal/codex-sandbox-controller.js +8 -2
  25. package/dist/lib/internal/demo-promotion.js +322 -0
  26. package/dist/lib/internal/demo-transcript.js +454 -0
  27. package/dist/lib/internal/git-workflow.js +10 -6
  28. package/dist/lib/internal/host-control.js +28 -0
  29. package/dist/lib/internal/manual-validation.js +322 -0
  30. package/dist/lib/internal/platform-checks.js +16 -4
  31. package/dist/lib/internal/platform-comment.js +16 -4
  32. package/dist/lib/internal/platform-context.js +4 -1
  33. package/dist/lib/internal/platform-issue.js +12 -4
  34. package/dist/lib/internal/platform-metadata.js +88 -0
  35. package/dist/lib/internal/platform-pr-review.js +16 -3
  36. package/dist/lib/internal/platform-pr.js +42 -14
  37. package/dist/lib/internal/platform-release-notes.js +6 -3
  38. package/dist/lib/internal/platform-security.js +93 -0
  39. package/dist/lib/internal/pr-review-grade.js +14 -3
  40. package/dist/lib/internal/release-workflow.js +82 -89
  41. package/dist/lib/internal/sandbox-control.js +171 -7
  42. package/dist/lib/internal/task-activity.js +13 -4
  43. package/dist/lib/internal/task-artifact.js +19 -107
  44. package/dist/lib/internal/task-context.js +4 -1
  45. package/dist/lib/internal/task-create.js +48 -14
  46. package/dist/lib/internal/task-delivery.js +4 -1
  47. package/dist/lib/internal/task-event.js +38 -35
  48. package/dist/lib/internal/task-finalization.js +4 -1
  49. package/dist/lib/internal/task-invalidation.js +4 -1
  50. package/dist/lib/internal/task-ledger.js +12 -1
  51. package/dist/lib/internal/task-lifecycle.js +4 -1
  52. package/dist/lib/internal/task-operation-registry.js +519 -0
  53. package/dist/lib/internal/task-orchestration.js +12 -0
  54. package/dist/lib/internal/task-override.js +10 -3
  55. package/dist/lib/internal/task-qualification.js +90 -0
  56. package/dist/lib/internal/task-review.js +10 -52
  57. package/dist/lib/internal/task-short-id.js +11 -1
  58. package/dist/lib/internal/task-snapshot.js +4 -1
  59. package/dist/lib/internal/task-validate.js +37 -12
  60. package/dist/lib/internal/task-verify.js +5 -1
  61. package/dist/lib/internal/task-warning.js +8 -1
  62. package/dist/lib/owned-path.js +33 -0
  63. package/dist/lib/platform/check-status.js +11 -0
  64. package/dist/lib/platform/comment-safety.js +229 -0
  65. package/dist/lib/platform/completion-backfill.js +1 -1
  66. package/dist/lib/platform/github-data.js +241 -0
  67. package/dist/lib/platform/github-provider.js +248 -26
  68. package/dist/lib/platform/issue-comments.js +146 -34
  69. package/dist/lib/platform/issues.js +1 -179
  70. package/dist/lib/platform/pr-change-report.js +6 -12
  71. package/dist/lib/platform/pr-checks.js +12 -65
  72. package/dist/lib/platform/pr-summary.js +83 -10
  73. package/dist/lib/platform/provider-contract.d.ts +67 -1
  74. package/dist/lib/platform/provider-contract.js +6 -2
  75. package/dist/lib/platform/provider-validation.js +76 -3
  76. package/dist/lib/platform/pull-requests.js +117 -275
  77. package/dist/lib/platform/repository-metadata.js +377 -0
  78. package/dist/lib/platform/security-alerts.js +155 -0
  79. package/dist/lib/platform/snapshots.js +2 -0
  80. package/dist/lib/platform/verification-sync.js +154 -162
  81. package/dist/lib/process-data/index.js +7 -0
  82. package/dist/lib/release/workflow.js +1 -1
  83. package/dist/lib/run/index.js +5 -0
  84. package/dist/lib/sandbox/commands/control-status.js +22 -0
  85. package/dist/lib/sandbox/commands/create.js +39 -8
  86. package/dist/lib/sandbox/commands/ls.js +5 -0
  87. package/dist/lib/sandbox/commands/rm.js +3 -807
  88. package/dist/lib/sandbox/commands/show.js +16 -0
  89. package/dist/lib/sandbox/control/audit.js +203 -0
  90. package/dist/lib/sandbox/control/client.js +125 -12
  91. package/dist/lib/sandbox/control/completed-reentry.js +85 -0
  92. package/dist/lib/sandbox/control/container-identity.js +28 -31
  93. package/dist/lib/sandbox/control/executor.js +233 -34
  94. package/dist/lib/sandbox/control/finalization-response.js +27 -0
  95. package/dist/lib/sandbox/control/identity-sentinel.js +107 -0
  96. package/dist/lib/sandbox/control/lifecycle.js +656 -128
  97. package/dist/lib/sandbox/control/native-file-lock.js +85 -0
  98. package/dist/lib/sandbox/control/protocol.js +55 -4
  99. package/dist/lib/sandbox/control/server.js +720 -79
  100. package/dist/lib/sandbox/control/state.js +63 -3
  101. package/dist/lib/sandbox/control/task-view.js +183 -0
  102. package/dist/lib/sandbox/control/task-workflow.js +74 -0
  103. package/dist/lib/sandbox/control/workflow-executor.js +99 -0
  104. package/dist/lib/sandbox/engines/authority.js +289 -0
  105. package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
  106. package/dist/lib/sandbox/index.js +7 -2
  107. package/dist/lib/sandbox/recovery.js +49 -5
  108. package/dist/lib/sandbox/removal.js +1717 -0
  109. package/dist/lib/sandbox/task-cleanup.js +217 -0
  110. package/dist/lib/sandbox/workspace-view.js +15 -15
  111. package/dist/lib/sandbox/worktree-safety.js +4 -1
  112. package/dist/lib/server/index.js +8 -0
  113. package/dist/lib/task/activity-intent.js +2 -1
  114. package/dist/lib/task/activity-log.js +30 -24
  115. package/dist/lib/task/artifact-command.js +101 -0
  116. package/dist/lib/task/artifact-lifecycle.js +71 -40
  117. package/dist/lib/task/artifact-name.js +36 -0
  118. package/dist/lib/task/artifact-operations.js +474 -0
  119. package/dist/lib/task/artifact-receipts.js +3 -15
  120. package/dist/lib/task/artifact-repair-intent.js +130 -0
  121. package/dist/lib/task/artifact-schema.js +127 -0
  122. package/dist/lib/task/capabilities.js +83 -19
  123. package/dist/lib/task/codex-orchestration.js +71 -25
  124. package/dist/lib/task/commit-identity.js +28 -0
  125. package/dist/lib/task/commit-operation.js +2 -16
  126. package/dist/lib/task/control-authority.js +375 -5
  127. package/dist/lib/task/control-recovery.js +128 -0
  128. package/dist/lib/task/create-service.js +103 -4
  129. package/dist/lib/task/create.js +80 -2
  130. package/dist/lib/task/decision-details.js +2 -46
  131. package/dist/lib/task/events.js +306 -76
  132. package/dist/lib/task/finalization-state.js +9 -0
  133. package/dist/lib/task/human-override.js +3 -6
  134. package/dist/lib/task/implementation-inputs.js +3 -3
  135. package/dist/lib/task/index.js +11 -3
  136. package/dist/lib/task/intermediate-cleanup.js +383 -0
  137. package/dist/lib/task/invalidation.js +18 -65
  138. package/dist/lib/task/ledger-intents.js +7 -22
  139. package/dist/lib/task/ledger.js +1 -3
  140. package/dist/lib/task/lifecycle.js +19 -1
  141. package/dist/lib/task/local-artifact-finalization.js +190 -290
  142. package/dist/lib/task/manual-validation-completion.js +26 -0
  143. package/dist/lib/task/manual-validation-evidence.js +130 -0
  144. package/dist/lib/task/manual-validation-receipt.js +101 -0
  145. package/dist/lib/task/manual-validation-shared.js +40 -0
  146. package/dist/lib/task/manual-validation-transaction.js +243 -0
  147. package/dist/lib/task/markdown.js +47 -0
  148. package/dist/lib/task/orchestration.js +206 -69
  149. package/dist/lib/task/qualification-audit.js +476 -0
  150. package/dist/lib/task/qualification-confirmation.js +109 -0
  151. package/dist/lib/task/qualification-intents.js +148 -0
  152. package/dist/lib/task/review-artifacts.js +23 -40
  153. package/dist/lib/task/review-command.js +25 -0
  154. package/dist/lib/task/review-finalization.js +146 -97
  155. package/dist/lib/task/review-fingerprint.js +2 -2
  156. package/dist/lib/task/sections.js +34 -54
  157. package/dist/lib/task/verification-config.js +11 -0
  158. package/dist/lib/task/verification-engine.js +170 -327
  159. package/dist/lib/task/verification.js +1 -1
  160. package/dist/lib/task/workflow-command.js +17 -0
  161. package/dist/lib/task/workflow-warning-intents.js +0 -16
  162. package/dist/lib/task/workflow-warnings.js +28 -2
  163. package/dist/lib/update.js +2 -0
  164. package/dist/lifecycle-build-manifest.json +3 -3
  165. package/lib/agent-client.ts +9 -0
  166. package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +223 -33
  167. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +3 -2
  168. package/lib/fs/durable-write.ts +29 -0
  169. package/lib/fs/file-lock.ts +113 -0
  170. package/lib/host-control/audit.ts +22 -0
  171. package/lib/host-control/client.ts +172 -0
  172. package/lib/host-control/command.ts +60 -0
  173. package/lib/host-control/path.ts +167 -0
  174. package/lib/host-control/secure-fs.ts +135 -0
  175. package/lib/host-control/server.ts +180 -0
  176. package/lib/host-control/service.ts +133 -0
  177. package/lib/init.ts +15 -2
  178. package/lib/internal/agent-client.ts +4 -2
  179. package/lib/internal/cli-route-inventory.ts +142 -0
  180. package/lib/internal/codex-lifecycle.ts +14 -12
  181. package/lib/internal/codex-sandbox-controller.ts +7 -2
  182. package/lib/internal/demo-promotion.ts +354 -0
  183. package/lib/internal/demo-transcript.ts +419 -0
  184. package/lib/internal/git-workflow.ts +9 -6
  185. package/lib/internal/host-control.ts +28 -0
  186. package/lib/internal/manual-validation.ts +306 -0
  187. package/lib/internal/platform-checks.ts +12 -4
  188. package/lib/internal/platform-comment.ts +12 -4
  189. package/lib/internal/platform-context.ts +3 -1
  190. package/lib/internal/platform-issue.ts +11 -4
  191. package/lib/internal/platform-metadata.ts +70 -0
  192. package/lib/internal/platform-pr-review.ts +14 -3
  193. package/lib/internal/platform-pr.ts +38 -14
  194. package/lib/internal/platform-release-notes.ts +5 -3
  195. package/lib/internal/platform-security.ts +83 -0
  196. package/lib/internal/pr-review-grade.ts +10 -3
  197. package/lib/internal/release-workflow.ts +91 -87
  198. package/lib/internal/sandbox-control.ts +181 -6
  199. package/lib/internal/task-activity.ts +12 -4
  200. package/lib/internal/task-artifact.ts +15 -79
  201. package/lib/internal/task-context.ts +3 -1
  202. package/lib/internal/task-create.ts +76 -15
  203. package/lib/internal/task-delivery.ts +3 -1
  204. package/lib/internal/task-event.ts +21 -10
  205. package/lib/internal/task-finalization.ts +3 -1
  206. package/lib/internal/task-invalidation.ts +3 -1
  207. package/lib/internal/task-ledger.ts +11 -1
  208. package/lib/internal/task-lifecycle.ts +3 -1
  209. package/lib/internal/task-operation-registry.ts +590 -0
  210. package/lib/internal/task-orchestration.ts +12 -0
  211. package/lib/internal/task-override.ts +9 -3
  212. package/lib/internal/task-qualification.ts +61 -0
  213. package/lib/internal/task-review.ts +7 -50
  214. package/lib/internal/task-short-id.ts +10 -1
  215. package/lib/internal/task-snapshot.ts +3 -1
  216. package/lib/internal/task-validate.ts +32 -12
  217. package/lib/internal/task-verify.ts +4 -1
  218. package/lib/internal/task-warning.ts +7 -1
  219. package/lib/owned-path.ts +26 -0
  220. package/lib/platform/check-status.ts +9 -0
  221. package/lib/platform/comment-safety.ts +255 -0
  222. package/lib/platform/completion-backfill.ts +1 -1
  223. package/lib/platform/github-data.ts +322 -0
  224. package/lib/platform/github-provider.ts +244 -27
  225. package/lib/platform/issue-comments.ts +159 -35
  226. package/lib/platform/issues.ts +4 -245
  227. package/lib/platform/pr-change-report.ts +6 -12
  228. package/lib/platform/pr-checks.ts +13 -77
  229. package/lib/platform/pr-summary.ts +88 -11
  230. package/lib/platform/provider-contract.ts +78 -3
  231. package/lib/platform/provider-validation.ts +85 -3
  232. package/lib/platform/pull-requests.ts +129 -348
  233. package/lib/platform/repository-metadata.ts +453 -0
  234. package/lib/platform/security-alerts.ts +191 -0
  235. package/lib/platform/snapshots.ts +53 -0
  236. package/lib/platform/verification-sync.ts +171 -177
  237. package/lib/process-data/index.ts +7 -0
  238. package/lib/release/workflow.ts +3 -3
  239. package/lib/run/index.ts +5 -0
  240. package/lib/sandbox/commands/control-status.ts +26 -0
  241. package/lib/sandbox/commands/create.ts +53 -12
  242. package/lib/sandbox/commands/ls.ts +7 -0
  243. package/lib/sandbox/commands/rm.ts +3 -996
  244. package/lib/sandbox/commands/show.ts +16 -0
  245. package/lib/sandbox/control/audit.ts +253 -0
  246. package/lib/sandbox/control/client.ts +150 -13
  247. package/lib/sandbox/control/completed-reentry.ts +98 -0
  248. package/lib/sandbox/control/container-identity.ts +27 -43
  249. package/lib/sandbox/control/executor.ts +262 -37
  250. package/lib/sandbox/control/finalization-response.ts +29 -0
  251. package/lib/sandbox/control/identity-sentinel.ts +137 -0
  252. package/lib/sandbox/control/lifecycle.ts +672 -18
  253. package/lib/sandbox/control/native-file-lock.ts +108 -0
  254. package/lib/sandbox/control/protocol.ts +80 -8
  255. package/lib/sandbox/control/server.ts +779 -82
  256. package/lib/sandbox/control/state.ts +84 -3
  257. package/lib/sandbox/control/task-view.ts +240 -0
  258. package/lib/sandbox/control/task-workflow.ts +95 -0
  259. package/lib/sandbox/control/workflow-executor.ts +102 -0
  260. package/lib/sandbox/engines/authority.ts +365 -0
  261. package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
  262. package/lib/sandbox/index.ts +9 -2
  263. package/lib/sandbox/recovery.ts +49 -6
  264. package/lib/sandbox/removal.ts +2144 -0
  265. package/lib/sandbox/task-cleanup.ts +209 -0
  266. package/lib/sandbox/workspace-view.ts +26 -18
  267. package/lib/sandbox/worktree-safety.ts +4 -1
  268. package/lib/server/index.ts +10 -0
  269. package/lib/task/activity-intent.ts +2 -2
  270. package/lib/task/activity-log.ts +27 -19
  271. package/lib/task/artifact-command.ts +104 -0
  272. package/lib/task/artifact-lifecycle.ts +66 -39
  273. package/lib/task/artifact-name.ts +55 -0
  274. package/lib/task/artifact-operations.ts +580 -0
  275. package/lib/task/artifact-receipts.ts +3 -14
  276. package/lib/task/artifact-repair-intent.ts +152 -0
  277. package/lib/task/artifact-schema.ts +163 -0
  278. package/lib/task/capabilities.ts +82 -22
  279. package/lib/task/codex-orchestration.ts +85 -24
  280. package/lib/task/commit-identity.ts +31 -0
  281. package/lib/task/commit-operation.ts +2 -16
  282. package/lib/task/control-authority.ts +513 -6
  283. package/lib/task/control-recovery.ts +174 -0
  284. package/lib/task/create-service.ts +131 -6
  285. package/lib/task/create.ts +83 -1
  286. package/lib/task/decision-details.ts +3 -71
  287. package/lib/task/events.ts +292 -75
  288. package/lib/task/finalization-state.ts +11 -0
  289. package/lib/task/human-override.ts +3 -8
  290. package/lib/task/implementation-inputs.ts +3 -3
  291. package/lib/task/index.ts +16 -3
  292. package/lib/task/intermediate-cleanup.ts +455 -0
  293. package/lib/task/invalidation.ts +18 -62
  294. package/lib/task/ledger-intents.ts +7 -24
  295. package/lib/task/ledger.ts +1 -3
  296. package/lib/task/lifecycle.ts +17 -1
  297. package/lib/task/local-artifact-finalization.ts +223 -388
  298. package/lib/task/manual-validation-completion.ts +40 -0
  299. package/lib/task/manual-validation-evidence.ts +209 -0
  300. package/lib/task/manual-validation-receipt.ts +152 -0
  301. package/lib/task/manual-validation-shared.ts +50 -0
  302. package/lib/task/manual-validation-transaction.ts +304 -0
  303. package/lib/task/markdown.ts +70 -0
  304. package/lib/task/orchestration.ts +191 -68
  305. package/lib/task/qualification-audit.ts +588 -0
  306. package/lib/task/qualification-confirmation.ts +117 -0
  307. package/lib/task/qualification-intents.ts +150 -0
  308. package/lib/task/review-artifacts.ts +21 -41
  309. package/lib/task/review-command.ts +23 -0
  310. package/lib/task/review-finalization.ts +154 -153
  311. package/lib/task/review-fingerprint.ts +2 -2
  312. package/lib/task/sections.ts +33 -52
  313. package/lib/task/verification-config.ts +12 -0
  314. package/lib/task/verification-engine.ts +165 -370
  315. package/lib/task/verification-types.ts +17 -0
  316. package/lib/task/verification.ts +1 -1
  317. package/lib/task/workflow-command.ts +18 -0
  318. package/lib/task/workflow-warning-intents.ts +0 -13
  319. package/lib/task/workflow-warnings.ts +21 -2
  320. package/lib/update.ts +6 -0
  321. package/package.json +7 -2
  322. package/templates/.agents/hooks/lifecycle-delegation.js +6 -6
  323. package/templates/.agents/rules/README.en.md +2 -0
  324. package/templates/.agents/rules/README.zh-CN.md +2 -0
  325. package/templates/.agents/rules/decision-qualification.en.md +22 -0
  326. package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
  327. package/templates/.agents/rules/evidence-reporting.en.md +28 -0
  328. package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
  329. package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
  330. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
  331. package/templates/.agents/rules/local-artifact-repair.en.md +5 -1
  332. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +5 -1
  333. package/templates/.agents/rules/security-alerts.en.md +8 -8
  334. package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
  335. package/templates/.agents/rules/testing-discipline.en.md +2 -0
  336. package/templates/.agents/rules/testing-discipline.zh-CN.md +2 -0
  337. package/templates/.agents/scripts/package.json +3 -0
  338. package/templates/.agents/skills/analyze-task/SKILL.en.md +15 -2
  339. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +19 -2
  340. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
  341. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
  342. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  343. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  344. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  345. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  346. package/templates/.agents/skills/code-task/SKILL.en.md +14 -1
  347. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +14 -1
  348. package/templates/.agents/skills/code-task/config/verify.en.json +5 -14
  349. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +5 -14
  350. package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
  351. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
  352. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
  353. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
  354. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
  355. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
  356. package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
  357. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
  358. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +37 -21
  359. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +37 -21
  360. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
  361. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
  362. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +4 -0
  363. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +4 -0
  364. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +16 -7
  365. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +16 -7
  366. package/templates/.agents/skills/complete-task/SKILL.en.md +10 -23
  367. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +10 -23
  368. package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
  369. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
  370. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  371. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  372. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  373. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  374. package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
  375. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
  376. package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
  377. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
  378. package/templates/.agents/skills/plan-task/SKILL.en.md +14 -1
  379. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +16 -1
  380. package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
  381. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
  382. package/templates/.agents/skills/release/SKILL.en.md +7 -3
  383. package/templates/.agents/skills/release/SKILL.zh-CN.md +7 -3
  384. package/templates/.agents/skills/review-analysis/SKILL.en.md +14 -1
  385. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -1
  386. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
  387. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
  388. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
  389. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
  390. package/templates/.agents/skills/review-code/SKILL.en.md +14 -1
  391. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +14 -1
  392. package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
  393. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
  394. package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
  395. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
  396. package/templates/.agents/skills/review-plan/SKILL.en.md +14 -1
  397. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -1
  398. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
  399. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
  400. package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
  401. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
  402. package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
  403. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
  404. package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
  405. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
  406. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +25 -4
  407. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +25 -4
  408. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +4 -1
  409. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +4 -1
  410. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +5 -1
  411. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +5 -1
  412. package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
  413. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
  414. package/templates/.agents/skills/test/SKILL.en.md +29 -7
  415. package/templates/.agents/skills/test/SKILL.zh-CN.md +29 -7
  416. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
  417. package/templates/.agents/templates/task.en.md +6 -0
  418. package/templates/.agents/templates/task.zh-CN.md +6 -0
  419. package/templates/.claude/commands/run-manual-validation.en.md +1 -1
  420. package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
  421. package/dist/lib/platform/adapters.js +0 -56
  422. package/lib/platform/adapters.ts +0 -197
  423. package/templates/.agents/scripts/security-alerts.github.sh +0 -151
  424. package/templates/.agents/scripts/security-alerts.sh +0 -31
  425. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
  426. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
  427. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
  428. package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
@@ -1,3 +1,4 @@
1
+ import { normalizePullRequest, type RemotePullRequest } from './github-data.ts';
1
2
  import fs from 'node:fs';
2
3
  import path from 'node:path';
3
4
  import { execFileSync } from 'node:child_process';
@@ -6,20 +7,14 @@ import { parseTypedTaskFrontmatter } from '../task/frontmatter.ts';
6
7
  import { resolveTaskRef } from '../task/resolve-ref.ts';
7
8
  import { extractSection } from '../task/sections.ts';
8
9
  import { captureTaskWriteMetadata, writeTask } from '../task/write.ts';
9
- import type { PlatformChangeRequestSnapshot } from './adapters.ts';
10
- import { parseGitHubRemote, resolvePlatformContext, resolvePlatformProviderContext } from './context.ts';
10
+ import type { PlatformChangeRequestSnapshot } from './snapshots.ts';
11
+ import { resolvePlatformProviderContext } from './context.ts';
11
12
  import type { PlatformClient } from './context.ts';
12
- import { createGitHubClient } from './github-client.ts';
13
13
  import { inspectPlatformIssue } from './issues.ts';
14
- import { inspectGitHubIssue } from './issues.ts';
15
- import type { IssueSnapshot } from './issues.ts';
16
14
  import { planPullRequestMetadata } from './pull-request-metadata.ts';
17
15
  import {
18
- extractPullRequestFileNames,
19
16
  planInLabelUpdate,
20
- syncLabelDelta,
21
- validateInLabelMapping,
22
- validateRepositoryLabelPayload
17
+ validateInLabelMapping
23
18
  } from './in-label-sync.ts';
24
19
  import { platformResult } from './types.ts';
25
20
  import type { PlatformOperation, PlatformResult } from './types.ts';
@@ -43,10 +38,10 @@ import {
43
38
  resourceIdentity,
44
39
  unsupportedProviderOperation
45
40
  } from './provider-bridge.ts';
46
- import { isResourceIdentity, resourceIdentityEquals, resourceIdentityNumber } from './resource-identity.ts';
41
+ import { isResourceIdentity, resourceIdentityEquals, resourceIdentityNumber, serializeResourceIdentity } from './resource-identity.ts';
47
42
  import type { ResourceIdentity } from './resource-identity.ts';
48
43
  import { taskIssueIdentity, taskIssueIdentityError } from './task-identities.ts';
49
- import type { ChangeRequestSnapshot as ProviderChangeRequestSnapshot } from './provider-contract.ts';
44
+ import type { ChangeRequestSnapshot as ProviderChangeRequestSnapshot, IssueSnapshot as ProviderIssueSnapshot } from './provider-contract.ts';
50
45
 
51
46
  type PullRequestSnapshot = PlatformChangeRequestSnapshot;
52
47
 
@@ -56,17 +51,17 @@ type PullRequestResult = PlatformResult & {
56
51
  result: 'pr_created' | 'pr_reused' | 'no_op' | 'pr_created_with_warnings' | 'pr_reused_with_warnings' | 'no_op_with_warnings' | 'failed' | 'blocked' | null;
57
52
  creation: CreationOutcome | null;
58
53
  warnings: readonly OperationWarning[];
59
- evidence?: { kind: string; pullRequestFiles?: string[]; closingIssues?: number[] };
54
+ evidence?: { kind: string; pullRequestFiles?: string[]; closingIssues?: ResourceIdentity[] };
60
55
  resources?: Array<{
61
56
  kind: 'issue' | 'pull-request';
62
- number: number;
57
+ number: number | null;
58
+ identity: ResourceIdentity;
63
59
  before: string[];
64
60
  expected: string[];
65
61
  after: string[] | null;
66
62
  effect: 'no-op' | 'applied' | 'unknown';
67
63
  }>;
68
64
  };
69
- type GitHubClient = PlatformClient;
70
65
  type InspectionOptions = { cwd?: string; client?: PlatformClient; runtimeVersion?: string };
71
66
  type SharedOptions = { cwd?: string; client?: PlatformClient; runtimeVersion?: string };
72
67
  type CreateOptions = SharedOptions & {
@@ -98,54 +93,6 @@ type ExternalPullRequestResult = PullRequestResult & {
98
93
 
99
94
  type CreatePhase = 'before-post' | 'post-dispatched' | 'post-accepted';
100
95
 
101
- type RemotePullRequest = {
102
- number?: number;
103
- node_id?: string;
104
- html_url?: string;
105
- state?: string;
106
- title?: string;
107
- body?: string | null;
108
- draft?: boolean;
109
- pull_request?: unknown;
110
- head?: { ref?: string; sha?: string; repo?: { full_name?: string } | null };
111
- base?: { ref?: string; sha?: string; repo?: { full_name?: string } | null };
112
- merged_at?: string | null;
113
- merge_commit_sha?: string | null;
114
- labels?: Array<string | { name?: string }>;
115
- assignees?: Array<{ login?: string }>;
116
- milestone?: { title?: string } | null;
117
- mergeable?: boolean | null;
118
- mergeable_state?: string | null;
119
- };
120
-
121
- type ClosingPullRequestNode = {
122
- number?: number;
123
- id?: string;
124
- url?: string;
125
- state?: string;
126
- title?: string;
127
- body?: string | null;
128
- isDraft?: boolean;
129
- headRefName?: string;
130
- headRefOid?: string;
131
- headRepository?: { nameWithOwner?: string } | null;
132
- baseRefName?: string;
133
- baseRefOid?: string;
134
- baseRepository?: { nameWithOwner?: string } | null;
135
- mergedAt?: string | null;
136
- mergeCommit?: { oid?: string } | null;
137
- labels?: { nodes?: Array<{ name?: string }> };
138
- assignees?: { nodes?: Array<{ login?: string }> };
139
- milestone?: { title?: string } | null;
140
- };
141
-
142
- type ClosingPullRequestPage = {
143
- data?: { repository?: { issue?: { closedByPullRequestsReferences?: {
144
- nodes?: ClosingPullRequestNode[];
145
- pageInfo?: { hasNextPage?: boolean; endCursor?: string | null };
146
- } } } };
147
- };
148
-
149
96
  function warningResultForPrimary(primaryResult: PullRequestPrimaryResult): NonNullable<PullRequestResult['result']> {
150
97
  if (primaryResult === 'pr_created') return 'pr_created_with_warnings';
151
98
  if (primaryResult === 'pr_reused') return 'pr_reused_with_warnings';
@@ -194,57 +141,6 @@ const PRECONDITION_NOT_CREATED: CreationOutcome = {
194
141
  kind: 'not-created', reason: 'precondition-failed', createdByCurrentOperation: false
195
142
  };
196
143
 
197
- function normalizePullRequest(remote: RemotePullRequest, repository: string): PullRequestSnapshot | null {
198
- const number = Number(remote.number);
199
- const headRepository = remote.head?.repo?.full_name;
200
- const baseRepository = remote.base?.repo?.full_name;
201
- if (!Number.isInteger(number) || number <= 0 || !remote.node_id || !remote.html_url ||
202
- !remote.head?.ref || !remote.head.sha || !headRepository || !remote.base?.ref || !baseRepository) return null;
203
- const mergeabilityDetail = remote.mergeable_state?.trim().toLowerCase() || null;
204
- const mergeability = remote.mergeable === false
205
- ? { state: 'conflicting' as const, detail: mergeabilityDetail }
206
- : remote.mergeable === true && mergeabilityDetail !== 'dirty'
207
- ? { state: 'mergeable' as const, detail: mergeabilityDetail }
208
- : { state: 'unknown' as const, detail: mergeabilityDetail };
209
- return {
210
- repository,
211
- number,
212
- nodeId: remote.node_id,
213
- url: remote.html_url,
214
- state: remote.state === 'closed' ? 'closed' : 'open',
215
- title: remote.title || '',
216
- body: remote.body || '',
217
- draft: Boolean(remote.draft),
218
- head: { repository: headRepository, ref: remote.head.ref, sha: remote.head.sha },
219
- base: { repository: baseRepository, ref: remote.base.ref, sha: remote.base.sha || '' },
220
- mergedAt: remote.merged_at || null,
221
- mergeCommitSha: remote.merge_commit_sha || null,
222
- labels: (remote.labels || []).map((label) => typeof label === 'string' ? label : label.name || '').filter(Boolean).sort(),
223
- assignees: (remote.assignees || []).map((assignee) => assignee.login || '').filter(Boolean).sort(),
224
- milestone: remote.milestone?.title || null,
225
- mergeability
226
- };
227
- }
228
-
229
- function normalizeClosingPullRequest(node: ClosingPullRequestNode, repository: string): PullRequestSnapshot | null {
230
- return normalizePullRequest({
231
- number: node.number,
232
- node_id: node.id,
233
- html_url: node.url,
234
- state: node.state === 'OPEN' ? 'open' : 'closed',
235
- title: node.title,
236
- body: node.body,
237
- draft: node.isDraft,
238
- head: { ref: node.headRefName, sha: node.headRefOid, repo: node.headRepository ? { full_name: node.headRepository.nameWithOwner } : null },
239
- base: { ref: node.baseRefName, sha: node.baseRefOid, repo: node.baseRepository ? { full_name: node.baseRepository.nameWithOwner } : null },
240
- merged_at: node.mergedAt,
241
- merge_commit_sha: node.mergeCommit?.oid,
242
- labels: node.labels?.nodes,
243
- assignees: node.assignees?.nodes,
244
- milestone: node.milestone
245
- }, repository);
246
- }
247
-
248
144
  function repositoryKey(repository: string): string {
249
145
  return repository.trim().toLowerCase();
250
146
  }
@@ -334,51 +230,6 @@ function selectExternalPullRequest(
334
230
  return { status: 'selected', source: 'unique', selected: eligible[0]!, candidates, eligible };
335
231
  }
336
232
 
337
- const CLOSING_PULL_REQUESTS_QUERY = `query($owner:String!,$name:String!,$issue:Int!,$cursor:String){repository(owner:$owner,name:$name){issue(number:$issue){closedByPullRequestsReferences(first:100,after:$cursor){nodes{number id url state title body isDraft headRefName headRefOid headRepository{nameWithOwner} baseRefName baseRefOid baseRepository{nameWithOwner} mergedAt mergeCommit{oid} labels(first:100){nodes{name}} assignees(first:100){nodes{login}} milestone{title}} pageInfo{hasNextPage endCursor}}}}}`;
338
-
339
- function inspectGitHubIssueClosingChangeRequests(
340
- client: GitHubClient,
341
- repository: string,
342
- issueNumber: number,
343
- cwd: string
344
- ) {
345
- const [owner, name] = repository.split('/');
346
- if (!owner || !name || !Number.isInteger(issueNumber) || issueNumber <= 0) return {
347
- ok: false as const,
348
- error: { code: 'PR_IDENTITY_INVALID', message: 'Repository or Issue identity is invalid', retryable: false }
349
- };
350
- const candidates: PullRequestSnapshot[] = [];
351
- let cursor: string | null = null;
352
- for (;;) {
353
- const args = [
354
- 'api', 'graphql', '-f', `query=${CLOSING_PULL_REQUESTS_QUERY}`,
355
- '-F', `owner=${owner}`, '-F', `name=${name}`, '-F', `issue=${issueNumber}`
356
- ];
357
- if (cursor) args.push('-F', `cursor=${cursor}`);
358
- const response = client.json<ClosingPullRequestPage>(args, { cwd });
359
- if (!response.ok) return response;
360
- const connection = response.value?.data?.repository?.issue?.closedByPullRequestsReferences;
361
- if (!connection || !Array.isArray(connection.nodes) || !connection.pageInfo) return {
362
- ok: false as const,
363
- error: { code: 'PR_IDENTITY_INVALID', message: 'Closing pull request response is incomplete', retryable: false }
364
- };
365
- for (const node of connection.nodes) {
366
- const normalized = normalizeClosingPullRequest(node, repository);
367
- if (!normalized) return {
368
- ok: false as const,
369
- error: { code: 'PR_IDENTITY_INVALID', message: 'Closing pull request identity is incomplete', retryable: false }
370
- };
371
- candidates.push(normalized);
372
- }
373
- if (!connection.pageInfo.hasNextPage) return { ok: true as const, value: candidates };
374
- if (!connection.pageInfo.endCursor || connection.pageInfo.endCursor === cursor) return {
375
- ok: false as const,
376
- error: { code: 'PR_IDENTITY_INVALID', message: 'Closing pull request pagination cursor is invalid', retryable: false }
377
- };
378
- cursor = connection.pageInfo.endCursor;
379
- }
380
- }
381
-
382
233
  function expectedHead(repository: string, head: string): { repository: string; ref: string } {
383
234
  const colon = head.indexOf(':');
384
235
  if (colon === -1) return { repository, ref: head };
@@ -611,15 +462,6 @@ async function inspectExternalPullRequest(
611
462
  });
612
463
  }
613
464
 
614
- function inspectGitHubPullRequest(client: GitHubClient, repository: string, number: number, cwd: string) {
615
- const fetched = client.json<RemotePullRequest>(['api', `repos/${repository}/pulls/${number}`], { cwd });
616
- if (!fetched.ok) return fetched;
617
- const pullRequest = normalizePullRequest(fetched.value, repository);
618
- return pullRequest
619
- ? { ok: true as const, value: pullRequest }
620
- : { ok: false as const, error: { code: 'PR_IDENTITY_INVALID', message: 'Remote resource is not a valid pull request', retryable: false } };
621
- }
622
-
623
465
  async function inspectPlatformPullRequest(taskRef: string, options: InspectionOptions = {}): Promise<PullRequestResult> {
624
466
  const base = await resolvedContext(taskRef, options);
625
467
  if (!base.ok) return base.output;
@@ -672,8 +514,6 @@ async function inspectPlatformPullRequestByNumber(prNumber: string | number, opt
672
514
  });
673
515
  }
674
516
 
675
- const CLOSING_ISSUES_QUERY = 'query($owner:String!,$name:String!,$number:Int!,$cursor:String){repository(owner:$owner,name:$name){pullRequest(number:$number){closingIssuesReferences(first:100,after:$cursor){nodes{number} pageInfo{hasNextPage endCursor}}}}}';
676
-
677
517
  function readInLabelMapping(repoRoot: string): { ok: true; value: Record<string, unknown> } | { ok: false; error: { code: string; message: string; retryable: boolean } } {
678
518
  try {
679
519
  const config = JSON.parse(fs.readFileSync(path.join(repoRoot, '.agents', '.airc.json'), 'utf8')) as {
@@ -718,176 +558,108 @@ function taskInLabelTarget(
718
558
  return { ok: true as const, value: planned.target };
719
559
  }
720
560
 
721
- function inspectClosingIssueNumbers(client: GitHubClient, repository: string, pullRequest: number, cwd: string) {
722
- const [owner, name] = repository.split('/');
723
- if (!owner || !name) return {
724
- ok: false as const,
725
- error: { code: 'IN_LABEL_SYNC_REPOSITORY_INVALID', message: 'Repository identity is invalid', retryable: false }
726
- };
727
- let cursor: string | null = null;
728
- const numbers: number[] = [];
729
- for (;;) {
730
- const args = ['api', 'graphql', '-f', `query=${CLOSING_ISSUES_QUERY}`, '-F', `owner=${owner}`, '-F', `name=${name}`, '-F', `number=${pullRequest}`];
731
- if (cursor) args.push('-F', `cursor=${cursor}`);
732
- const response = client.json<unknown>(args, { cwd });
733
- if (!response.ok) return response;
734
- const connection = (response.value as {
735
- data?: { repository?: { pullRequest?: { closingIssuesReferences?: {
736
- nodes?: unknown[]; pageInfo?: { hasNextPage?: boolean; endCursor?: string | null };
737
- } } } };
738
- })?.data?.repository?.pullRequest?.closingIssuesReferences;
739
- if (!connection || !Array.isArray(connection.nodes) || !connection.pageInfo) return {
740
- ok: false as const,
741
- error: { code: 'IN_LABEL_SYNC_ASSOCIATION_INVALID', message: 'Closing Issue response is incomplete', retryable: false }
742
- };
743
- for (const node of connection.nodes) {
744
- const issue = Number((node as { number?: unknown })?.number);
745
- if (!Number.isSafeInteger(issue) || issue <= 0) return {
746
- ok: false as const,
747
- error: { code: 'IN_LABEL_SYNC_ASSOCIATION_INVALID', message: 'Closing Issue identity is invalid', retryable: false }
748
- };
749
- numbers.push(issue);
750
- }
751
- if (!connection.pageInfo.hasNextPage) return { ok: true as const, value: [...new Set(numbers)] };
752
- if (!connection.pageInfo.endCursor || connection.pageInfo.endCursor === cursor) return {
753
- ok: false as const,
754
- error: { code: 'IN_LABEL_SYNC_ASSOCIATION_INVALID', message: 'Closing Issue pagination cursor is invalid', retryable: false }
755
- };
756
- cursor = connection.pageInfo.endCursor;
757
- }
758
- }
759
-
760
- function inspectRepositoryLabels(client: GitHubClient, repository: string, cwd: string) {
761
- const response = client.json<unknown>(['api', '--paginate', '--slurp', `repos/${repository}/labels?per_page=100`], { cwd });
762
- if (!response.ok) return response;
763
- const labels = validateRepositoryLabelPayload(response.value);
764
- return labels.ok ? { ok: true as const, value: new Set(labels.value) } : labels;
765
- }
766
-
767
- function inspectPullRequestFiles(client: GitHubClient, repository: string, pullRequest: number, cwd: string) {
768
- const response = client.json<unknown>(['api', '--paginate', '--slurp', `repos/${repository}/pulls/${pullRequest}/files?per_page=100`], { cwd });
769
- if (!response.ok) return response;
770
- const files = extractPullRequestFileNames(response.value);
771
- return files ? { ok: true as const, value: files } : {
772
- ok: false as const,
773
- error: { code: 'IN_LABEL_SYNC_FILES_INVALID', message: 'Pull request files response is incomplete', retryable: false }
774
- };
775
- }
776
-
777
- function inspectTaskInLabelTarget(
778
- repoRoot: string,
779
- frontmatter: Record<string, unknown>,
780
- pullRequest: PullRequestSnapshot,
781
- repository: string,
782
- client: GitHubClient
783
- ) {
784
- const baseRef = typeof frontmatter.delivery_base_ref === 'string' ? frontmatter.delivery_base_ref.trim() : '';
785
- if (!baseRef) return {
786
- ok: false as const,
787
- error: { code: 'IN_LABEL_SYNC_BASE_MISSING', message: 'Task has no delivery_base_ref for in-label evidence', retryable: false }
788
- };
789
- let changedFiles: string[];
790
- try {
791
- changedFiles = execFileSync('git', ['diff', `${baseRef}...HEAD`, '--name-only'], {
792
- cwd: repoRoot, encoding: 'utf8'
793
- }).trim().split(/\r?\n/).filter(Boolean);
794
- } catch (error) {
795
- return {
796
- ok: false as const,
797
- error: { code: 'IN_LABEL_SYNC_EVIDENCE_UNAVAILABLE', message: error instanceof Error ? error.message : String(error), retryable: false }
798
- };
799
- }
800
- const mapping = readInLabelMapping(repoRoot);
801
- if (!mapping.ok) return mapping;
802
- const labels = inspectRepositoryLabels(client, repository, repoRoot);
803
- if (!labels.ok) return labels;
804
- const planned = planInLabelUpdate({
805
- changedFiles, currentLabels: pullRequest.labels, mapping: mapping.value, repositoryLabels: labels.value
806
- });
807
- if (planned.error) return { ok: false as const, error: planned.error };
808
- return { ok: true as const, value: { changedFiles, target: planned.target } };
561
+ function resourceIdentityLabel(identity: ResourceIdentity): string {
562
+ const number = resourceIdentityNumber(identity);
563
+ return number === null ? `${identity.kind} ${identity.value}` : `#${number}`;
809
564
  }
810
565
 
811
566
  function inLabelResource(
812
567
  kind: 'issue' | 'pull-request',
813
- number: number,
568
+ identity: ResourceIdentity,
814
569
  before: string[],
815
570
  expected: string[],
816
571
  after: string[] | null,
817
572
  effect: 'no-op' | 'applied' | 'unknown'
818
573
  ) {
819
- return { kind, number, before: [...before].sort(), expected: [...expected].sort(), after: after ? [...after].sort() : null, effect };
574
+ return { kind, number: resourceIdentityNumber(identity), identity, before: [...before].sort(), expected: [...expected].sort(), after: after ? [...after].sort() : null, effect };
820
575
  }
821
576
 
822
577
  async function syncPlatformPullRequestInLabels(prNumber: number, options: SharedOptions & { dryRun?: boolean } = {}): Promise<PullRequestResult> {
823
578
  const cwd = path.resolve(options.cwd || process.cwd());
824
- const client = options.client || createGitHubClient();
825
- const context = await resolvePlatformContext({ cwd, client });
579
+ const loaded = await resolvePlatformProviderContext({ cwd, client: options.client });
580
+ const context = loaded.ok ? loaded.value.context : loaded.context;
826
581
  const usable = (context.status === 'no-op' || context.status === 'degraded') && context.platform.repository;
827
- if (!usable) return result(context.status, null, null, prNumber, {
582
+ if (!loaded.ok || !usable) return result(context.status, null, null, prNumber, {
828
583
  platform: context.platform, capabilities: context.capabilities, operations: context.operations, error: context.error
829
584
  });
830
585
  if (!Number.isSafeInteger(prNumber) || prNumber <= 0) return result('failed', null, null, prNumber, {
831
586
  platform: context.platform, capabilities: context.capabilities,
832
587
  error: { code: 'PR_NUMBER_INVALID', message: 'PR number must be positive', retryable: false }
833
588
  });
589
+ const provider = loaded.value.provider;
590
+ const operationContext = providerOperationContext(loaded.value);
834
591
  const repository = context.platform.repository!;
835
- const fetched = inspectGitHubPullRequest(client, repository, prNumber, cwd);
836
- if (!fetched.ok) return result(fetched.error.retryable ? 'blocked' : 'failed', null, null, prNumber, {
837
- platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, error: fetched.error
838
- });
839
- const files = inspectPullRequestFiles(client, repository, prNumber, cwd);
840
- if (!files.ok) return result(files.error.retryable ? 'blocked' : 'failed', null, null, prNumber, {
841
- platform: context.platform, capabilities: context.capabilities, pullRequest: fetched.value,
842
- resource: { kind: 'pull-request', number: prNumber }, error: files.error
843
- });
592
+ const pullRequestIdentity = providerResourceToken(provider, 'pull-request', String(prNumber));
593
+ const providerFailure = (error: { code: string; message: string; retryable: boolean }): PullRequestResult => result(
594
+ error.code === 'PLATFORM_CAPABILITY_UNSUPPORTED' ? 'degraded' : providerStatus(error),
595
+ null,
596
+ null,
597
+ prNumber,
598
+ {
599
+ platform: context.platform,
600
+ capabilities: context.capabilities,
601
+ resource: { kind: 'pull-request', number: prNumber, identity: pullRequestIdentity },
602
+ error: providerError(error, 'PLATFORM_PROVIDER_OPERATION_FAILED')
603
+ }
604
+ );
605
+ const inspected = provider.changeRequests?.inspect
606
+ ? await provider.changeRequests.inspect({ context: operationContext, target: pullRequestIdentity })
607
+ : unsupportedProviderOperation(provider, 'changeRequests.inspect');
608
+ if (!inspected.ok) return providerFailure(inspected.error);
609
+ const fetched = normalizeProviderPullRequest(inspected.value, repository, prNumber);
610
+ const files = provider.changeRequests?.listFiles
611
+ ? await provider.changeRequests.listFiles({ context: operationContext, target: pullRequestIdentity })
612
+ : unsupportedProviderOperation(provider, 'changeRequests.listFiles');
613
+ if (!files.ok) return providerFailure(files.error);
844
614
  const mapping = readInLabelMapping(cwd);
845
615
  if (!mapping.ok) return result('failed', null, null, prNumber, {
846
- platform: context.platform, capabilities: context.capabilities, pullRequest: fetched.value,
847
- resource: { kind: 'pull-request', number: prNumber }, error: mapping.error
848
- });
849
- const repositoryLabels = inspectRepositoryLabels(client, repository, cwd);
850
- if (!repositoryLabels.ok) return result(repositoryLabels.error.retryable ? 'blocked' : 'failed', null, null, prNumber, {
851
- platform: context.platform, capabilities: context.capabilities, pullRequest: fetched.value,
852
- resource: { kind: 'pull-request', number: prNumber }, error: repositoryLabels.error
616
+ platform: context.platform, capabilities: context.capabilities, pullRequest: fetched,
617
+ resource: { kind: 'pull-request', number: prNumber, identity: pullRequestIdentity }, error: mapping.error
853
618
  });
619
+ let repositoryLabels = new Set<string>();
620
+ if (Object.keys(mapping.value).length > 0) {
621
+ const labels = provider.issues?.listLabels
622
+ ? await provider.issues.listLabels({ context: operationContext })
623
+ : unsupportedProviderOperation(provider, 'issues.listLabels');
624
+ if (!labels.ok) return providerFailure(labels.error);
625
+ repositoryLabels = new Set(labels.value);
626
+ }
854
627
  const plannedTarget = planInLabelUpdate({
855
- changedFiles: files.value, currentLabels: fetched.value.labels,
856
- mapping: mapping.value, repositoryLabels: repositoryLabels.value
628
+ changedFiles: files.value, currentLabels: fetched.labels,
629
+ mapping: mapping.value, repositoryLabels
857
630
  });
858
631
  if (plannedTarget.error) return result('failed', null, null, prNumber, {
859
- platform: context.platform, capabilities: context.capabilities, pullRequest: fetched.value,
860
- resource: { kind: 'pull-request', number: prNumber }, error: plannedTarget.error
861
- });
862
- const target = plannedTarget.target;
863
- const association = inspectClosingIssueNumbers(client, repository, prNumber, cwd);
864
- if (!association.ok) return result(association.error.retryable ? 'blocked' : 'failed', null, null, prNumber, {
865
- platform: context.platform, capabilities: context.capabilities, pullRequest: fetched.value,
866
- resource: { kind: 'pull-request', number: prNumber }, evidence: { kind: 'pull-request-files', pullRequestFiles: files.value }, error: association.error
632
+ platform: context.platform, capabilities: context.capabilities, pullRequest: fetched,
633
+ resource: { kind: 'pull-request', number: prNumber, identity: pullRequestIdentity }, error: plannedTarget.error
867
634
  });
868
-
869
- const issueNumber = association.value.length === 1 ? association.value[0]! : null;
870
- let issue: IssueSnapshot | null = null;
871
- if (issueNumber) {
872
- const fetchedIssue = inspectGitHubIssue(client, repository, issueNumber, cwd);
873
- if (!fetchedIssue.ok) return result(fetchedIssue.error.retryable ? 'blocked' : 'failed', null, issueNumber, prNumber, {
874
- platform: context.platform, capabilities: context.capabilities, pullRequest: fetched.value,
875
- resource: { kind: 'issue', number: issueNumber }, evidence: { kind: 'pull-request-files', pullRequestFiles: files.value, closingIssues: association.value }, error: fetchedIssue.error
876
- });
635
+ const association = provider.changeRequests?.listClosingIssues
636
+ ? await provider.changeRequests.listClosingIssues({ context: operationContext, target: pullRequestIdentity })
637
+ : unsupportedProviderOperation(provider, 'changeRequests.listClosingIssues');
638
+ if (!association.ok) return providerFailure(association.error);
639
+
640
+ const issueIdentity = association.value.length === 1 ? association.value[0]! : null;
641
+ const issueNumber = issueIdentity ? resourceIdentityNumber(issueIdentity) : null;
642
+ const closingIssueIdentities = association.value;
643
+ let issue: ProviderIssueSnapshot | null = null;
644
+ if (issueIdentity) {
645
+ const fetchedIssue = provider.issues?.inspect
646
+ ? await provider.issues.inspect({ context: operationContext, target: issueIdentity })
647
+ : unsupportedProviderOperation(provider, 'issues.inspect');
648
+ if (!fetchedIssue.ok) return providerFailure(fetchedIssue.error);
877
649
  issue = fetchedIssue.value;
878
650
  }
879
651
 
880
652
  const resources = issue
881
653
  ? [
882
- { kind: 'issue' as const, number: issue.number, snapshot: issue },
883
- { kind: 'pull-request' as const, number: prNumber, snapshot: fetched.value }
654
+ { kind: 'issue' as const, identity: issueIdentity!, number: issueNumber, snapshot: issue },
655
+ { kind: 'pull-request' as const, identity: pullRequestIdentity, number: prNumber, snapshot: fetched }
884
656
  ]
885
- : [{ kind: 'pull-request' as const, number: prNumber, snapshot: fetched.value }];
657
+ : [{ kind: 'pull-request' as const, identity: pullRequestIdentity, number: prNumber, snapshot: fetched }];
886
658
  const plans = resources.map((resource) => ({
887
659
  ...resource,
888
660
  plan: planInLabelUpdate({
889
661
  changedFiles: files.value, currentLabels: resource.snapshot.labels,
890
- mapping: mapping.value, repositoryLabels: repositoryLabels.value
662
+ mapping: mapping.value, repositoryLabels
891
663
  })
892
664
  }));
893
665
  const operations: PlatformOperation[] = [
@@ -901,67 +673,90 @@ async function syncPlatformPullRequestInLabels(prNumber: number, options: Shared
901
673
  const willWrite = context.capabilities.triage && !options.dryRun;
902
674
  const resourcesState = plans.map((item) => inLabelResource(
903
675
  item.kind,
904
- item.number,
676
+ item.identity,
905
677
  item.snapshot.labels,
906
- target,
678
+ item.plan.target,
907
679
  item.plan.changed && willWrite ? null : item.snapshot.labels,
908
680
  item.plan.changed && willWrite ? 'unknown' : 'no-op'
909
681
  ));
910
682
  if (options.dryRun || !context.capabilities.triage) return result(
911
683
  !context.capabilities.triage || association.value.length !== 1 ? 'degraded' : plans.some((item) => item.plan.changed) ? 'planned' : 'no-op',
912
684
  null, issueNumber, prNumber, {
913
- platform: context.platform, capabilities: context.capabilities, pullRequest: fetched.value,
914
- resource: { kind: 'pull-request', number: prNumber }, operations, resources: resourcesState,
915
- evidence: { kind: 'pull-request-files', pullRequestFiles: files.value, closingIssues: association.value }, error: null
685
+ platform: context.platform, capabilities: context.capabilities, pullRequest: fetched,
686
+ resource: { kind: 'pull-request', number: prNumber, identity: pullRequestIdentity }, operations, resources: resourcesState,
687
+ evidence: { kind: 'pull-request-files', pullRequestFiles: files.value, closingIssues: closingIssueIdentities }, error: null
916
688
  }
917
689
  );
918
690
 
919
- let currentPullRequest = fetched.value;
691
+ let currentPullRequest = fetched;
920
692
  let successfulWrites = 0;
921
693
  for (const item of plans) {
922
694
  if (!item.plan.changed) continue;
923
- const synced = syncLabelDelta(client, repository, item.number, cwd, item.snapshot.labels, item.plan.target);
924
- if (synced.status === 'failed' || synced.status === 'blocked') {
925
- const state = resourcesState.find((resource) => resource.kind === item.kind && resource.number === item.number)!;
926
- state.effect = synced.status === 'blocked' ? 'unknown' : 'no-op';
927
- state.after = synced.status === 'blocked' ? null : item.snapshot.labels;
928
- const partial = successfulWrites > 0 || synced.status === 'blocked';
929
- const error = partial && synced.error
695
+ const targetIdentity = item.kind === 'issue' ? issueIdentity! : pullRequestIdentity;
696
+ const synced = item.kind === 'issue'
697
+ ? provider.issues?.update
698
+ ? await provider.issues.update({
699
+ context: operationContext,
700
+ target: targetIdentity,
701
+ currentLabels: item.snapshot.labels,
702
+ patch: { labels: item.plan.labels },
703
+ mutation: { idempotencyKey: `issue:update:${serializeResourceIdentity(targetIdentity)}:in-labels`, target: targetIdentity }
704
+ })
705
+ : unsupportedProviderOperation(provider, 'issues.update')
706
+ : provider.changeRequests?.update
707
+ ? await provider.changeRequests.update({
708
+ context: operationContext,
709
+ target: targetIdentity,
710
+ currentLabels: item.snapshot.labels,
711
+ patch: { labels: item.plan.labels },
712
+ mutation: { idempotencyKey: `pull-request:update:${serializeResourceIdentity(targetIdentity)}:in-labels`, target: targetIdentity }
713
+ })
714
+ : unsupportedProviderOperation(provider, 'changeRequests.update');
715
+ if (!synced.ok) {
716
+ const state = resourcesState.find((resource) => resource.kind === item.kind && resourceIdentityEquals(resource.identity, item.identity))!;
717
+ state.effect = synced.error.retryable ? 'unknown' : 'no-op';
718
+ state.after = state.effect === 'unknown' ? null : item.snapshot.labels;
719
+ const partial = successfulWrites > 0 || synced.error.retryable;
720
+ const error = partial
930
721
  ? { ...synced.error, code: 'IN_LABEL_SYNC_PARTIAL', message: `In-label synchronization is partial or unknown: ${synced.error.message}` }
931
722
  : synced.error;
932
- return result(partial ? 'blocked' : synced.status, null, issueNumber, prNumber, {
933
- changed: successfulWrites > 0 || synced.changed, platform: context.platform, capabilities: context.capabilities,
934
- pullRequest: currentPullRequest, resource: { kind: 'pull-request', number: prNumber }, operations, resources: resourcesState,
935
- evidence: { kind: 'pull-request-files', pullRequestFiles: files.value, closingIssues: association.value }, error
723
+ return result(partial ? 'blocked' : providerStatus(synced.error), null, issueNumber, prNumber, {
724
+ changed: successfulWrites > 0, platform: context.platform, capabilities: context.capabilities,
725
+ pullRequest: currentPullRequest, resource: { kind: 'pull-request', number: prNumber, identity: pullRequestIdentity }, operations, resources: resourcesState,
726
+ evidence: { kind: 'pull-request-files', pullRequestFiles: files.value, closingIssues: closingIssueIdentities }, error: providerError(error, 'PLATFORM_PROVIDER_OPERATION_FAILED')
936
727
  });
937
728
  }
938
- successfulWrites += synced.changed ? 1 : 0;
729
+ successfulWrites += synced.value.changed ? 1 : 0;
939
730
  const reread = item.kind === 'issue'
940
- ? inspectGitHubIssue(client, repository, item.number, cwd)
941
- : inspectGitHubPullRequest(client, repository, item.number, cwd);
731
+ ? provider.issues?.inspect
732
+ ? await provider.issues.inspect({ context: operationContext, target: targetIdentity })
733
+ : unsupportedProviderOperation(provider, 'issues.inspect')
734
+ : provider.changeRequests?.inspect
735
+ ? await provider.changeRequests.inspect({ context: operationContext, target: targetIdentity })
736
+ : unsupportedProviderOperation(provider, 'changeRequests.inspect');
942
737
  if (!reread.ok) return result('blocked', null, issueNumber, prNumber, {
943
738
  changed: true, platform: context.platform, capabilities: context.capabilities,
944
- pullRequest: currentPullRequest, resource: { kind: 'pull-request', number: prNumber }, operations, resources: resourcesState,
945
- evidence: { kind: 'pull-request-files', pullRequestFiles: files.value, closingIssues: association.value },
946
- error: { ...reread.error, code: 'IN_LABEL_SYNC_PARTIAL', message: `In-label synchronization is partial or unknown: ${reread.error.message}` }
739
+ pullRequest: currentPullRequest, resource: { kind: 'pull-request', number: prNumber, identity: pullRequestIdentity }, operations, resources: resourcesState,
740
+ evidence: { kind: 'pull-request-files', pullRequestFiles: files.value, closingIssues: closingIssueIdentities },
741
+ error: { ...providerError(reread.error, 'PLATFORM_PROVIDER_OPERATION_FAILED'), code: 'IN_LABEL_SYNC_PARTIAL', message: `In-label synchronization is partial or unknown: ${reread.error.message}` }
947
742
  });
948
- const after = reread.value.labels;
949
- const state = resourcesState.find((resource) => resource.kind === item.kind && resource.number === item.number)!;
743
+ const after = reread.value.labels || [];
744
+ const state = resourcesState.find((resource) => resource.kind === item.kind && resourceIdentityEquals(resource.identity, item.identity))!;
950
745
  state.after = after;
951
- state.effect = after.filter((label: string) => label.startsWith('in:')).sort().join('\0') === target.join('\0') ? 'applied' : 'unknown';
746
+ state.effect = after.filter((label: string) => label.startsWith('in:')).sort().join('\0') === item.plan.target.join('\0') ? 'applied' : 'unknown';
952
747
  if (state.effect === 'unknown') return result('blocked', null, issueNumber, prNumber, {
953
748
  changed: true, platform: context.platform, capabilities: context.capabilities,
954
- pullRequest: currentPullRequest, resource: { kind: 'pull-request', number: prNumber }, operations, resources: resourcesState,
955
- evidence: { kind: 'pull-request-files', pullRequestFiles: files.value, closingIssues: association.value },
956
- error: { code: 'IN_LABEL_SYNC_PARTIAL', message: `${item.kind} #${item.number} did not converge to the expected in: labels`, retryable: true }
749
+ pullRequest: currentPullRequest, resource: { kind: 'pull-request', number: prNumber, identity: pullRequestIdentity }, operations, resources: resourcesState,
750
+ evidence: { kind: 'pull-request-files', pullRequestFiles: files.value, closingIssues: closingIssueIdentities },
751
+ error: { code: 'IN_LABEL_SYNC_PARTIAL', message: `${item.kind} ${resourceIdentityLabel(item.identity)} did not converge to the expected in: labels`, retryable: true }
957
752
  });
958
- if (item.kind === 'pull-request') currentPullRequest = reread.value as PullRequestSnapshot;
753
+ if (item.kind === 'pull-request') currentPullRequest = normalizeProviderPullRequest(reread.value as ProviderChangeRequestSnapshot, repository, prNumber, currentPullRequest);
959
754
  }
960
755
  return result(association.value.length !== 1 ? 'degraded' : successfulWrites > 0 ? 'applied' : 'no-op', null, issueNumber, prNumber, {
961
756
  changed: successfulWrites > 0, platform: context.platform, capabilities: context.capabilities,
962
- pullRequest: currentPullRequest, resource: { kind: 'pull-request', number: prNumber },
757
+ pullRequest: currentPullRequest, resource: { kind: 'pull-request', number: prNumber, identity: pullRequestIdentity },
963
758
  operations: operations.map((operation) => operation.status === 'planned' ? { ...operation, status: 'applied' as const } : operation),
964
- resources: resourcesState, evidence: { kind: 'pull-request-files', pullRequestFiles: files.value, closingIssues: association.value }, error: null
759
+ resources: resourcesState, evidence: { kind: 'pull-request-files', pullRequestFiles: files.value, closingIssues: closingIssueIdentities }, error: null
965
760
  });
966
761
  }
967
762
 
@@ -1708,20 +1503,6 @@ async function skipPlatformPullRequestFact(taskRef: string, options: SkipFactOpt
1708
1503
  }
1709
1504
  }
1710
1505
 
1711
- export {
1712
- bindPlatformPullRequest,
1713
- createPlatformPullRequest,
1714
- inspectGitHubPullRequest,
1715
- inspectGitHubIssueClosingChangeRequests,
1716
- inspectPlatformPullRequest,
1717
- inspectPlatformPullRequestByNumber,
1718
- normalizePullRequest,
1719
- resolveExternalPullRequest,
1720
- skipPlatformPullRequestFact,
1721
- selectExternalPullRequest,
1722
- selectPullRequest,
1723
- syncPlatformPullRequest,
1724
- syncPlatformPullRequestInLabels
1725
- };
1506
+ export { bindPlatformPullRequest, createPlatformPullRequest, inspectPlatformPullRequest, inspectPlatformPullRequestByNumber, resolveExternalPullRequest, skipPlatformPullRequestFact, selectExternalPullRequest, selectPullRequest, syncPlatformPullRequest, syncPlatformPullRequestInLabels };
1726
1507
  export type { BindOptions, CreateOptions, ExternalPullRequestResult, ExternalPullRequestSelection, PullRequestPrimaryResult, PullRequestResult, PullRequestSnapshot, ResolveExternalOptions, SkipFactOptions, SyncOptions };
1727
1508
  export { warningResultForPrimary };