@fitlab-ai/agent-infra 0.9.11 → 0.9.13

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 (356) hide show
  1. package/README.md +13 -13
  2. package/README.zh-CN.md +13 -13
  3. package/dist/bin/internal-cli.js +29 -19
  4. package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +71 -10
  5. package/dist/lib/agent-clients/next-steps.js +6 -1
  6. package/dist/lib/decide.js +3 -3
  7. package/dist/lib/defaults.json +4 -0
  8. package/dist/lib/git/workflow.js +43 -1
  9. package/dist/lib/init.js +1 -0
  10. package/dist/lib/internal/git-workflow.js +8 -1
  11. package/dist/lib/internal/platform-checks.js +3 -3
  12. package/dist/lib/internal/platform-comment.js +9 -9
  13. package/dist/lib/internal/platform-context.js +2 -2
  14. package/dist/lib/internal/platform-issue.js +8 -9
  15. package/dist/lib/internal/platform-pr-review.js +10 -10
  16. package/dist/lib/internal/platform-pr.js +68 -23
  17. package/dist/lib/internal/platform-release-notes.js +3 -3
  18. package/dist/lib/internal/pr-review-grade.js +11 -9
  19. package/dist/lib/internal/release-workflow.js +4 -4
  20. package/dist/lib/internal/sandbox-control.js +30 -4
  21. package/dist/lib/internal/task-activity.js +3 -3
  22. package/dist/lib/internal/task-artifact.js +76 -24
  23. package/dist/lib/internal/task-create.js +2 -2
  24. package/dist/lib/internal/task-delivery.js +59 -0
  25. package/dist/lib/internal/task-event.js +6 -3
  26. package/dist/lib/internal/task-finalization.js +2 -2
  27. package/dist/lib/internal/task-invalidation.js +60 -0
  28. package/dist/lib/internal/task-ledger.js +9 -6
  29. package/dist/lib/internal/task-lifecycle.js +2 -2
  30. package/dist/lib/internal/task-override.js +4 -4
  31. package/dist/lib/internal/task-review.js +3 -3
  32. package/dist/lib/internal/task-verify.js +6 -6
  33. package/dist/lib/internal/task-warning.js +3 -3
  34. package/dist/lib/platform/adapters.js +1 -3
  35. package/dist/lib/platform/change-request-git-evidence.js +27 -7
  36. package/dist/lib/platform/completion-backfill.js +6 -5
  37. package/dist/lib/platform/context.js +70 -130
  38. package/dist/lib/platform/github-client.js +8 -2
  39. package/dist/lib/platform/github-provider.js +903 -0
  40. package/dist/lib/platform/in-label-sync.js +143 -0
  41. package/dist/lib/platform/issue-comments.js +94 -41
  42. package/dist/lib/platform/issues.js +335 -189
  43. package/dist/lib/platform/metadata-labels.js +6 -2
  44. package/dist/lib/platform/none-provider.js +28 -0
  45. package/dist/lib/platform/pr-change-report.js +551 -0
  46. package/dist/lib/platform/pr-checks.js +124 -106
  47. package/dist/lib/platform/pr-review.js +88 -72
  48. package/dist/lib/platform/pr-summary.js +523 -49
  49. package/dist/lib/platform/provider-bridge.js +45 -0
  50. package/dist/lib/platform/provider-contract.d.ts +487 -0
  51. package/dist/lib/platform/provider-contract.js +95 -0
  52. package/dist/lib/platform/provider-loader.js +251 -0
  53. package/dist/lib/platform/provider-validation.js +504 -0
  54. package/dist/lib/platform/pull-request-metadata.js +8 -6
  55. package/dist/lib/platform/pull-requests.js +1050 -502
  56. package/dist/lib/platform/release-notes.js +78 -55
  57. package/dist/lib/platform/releases.js +79 -50
  58. package/dist/lib/platform/resource-identity.d.ts +26 -0
  59. package/dist/lib/platform/resource-identity.js +92 -0
  60. package/dist/lib/platform/task-identities.js +31 -0
  61. package/dist/lib/platform/verification-required.js +22 -12
  62. package/dist/lib/platform/verification-sync.js +118 -239
  63. package/dist/lib/pr-review/evidence-grading.js +30 -9
  64. package/dist/lib/run/index.js +63 -23
  65. package/dist/lib/sandbox/config.js +5 -0
  66. package/dist/lib/sandbox/control/client.js +96 -15
  67. package/dist/lib/sandbox/control/executor.js +3 -3
  68. package/dist/lib/sandbox/control/lifecycle.js +29 -7
  69. package/dist/lib/sandbox/control/protocol.js +77 -0
  70. package/dist/lib/sandbox/control/server.js +398 -25
  71. package/dist/lib/sandbox/control/state.js +204 -1
  72. package/dist/lib/server/process-state.js +2 -2
  73. package/dist/lib/server/protocol.js +38 -1
  74. package/dist/lib/task/activity-log.js +8 -1
  75. package/dist/lib/task/artifact-lifecycle.js +35 -7
  76. package/dist/lib/task/capabilities.js +239 -0
  77. package/dist/lib/task/commands/status.js +32 -0
  78. package/dist/lib/task/commit-intent.js +100 -0
  79. package/dist/lib/task/commit-operation.js +207 -102
  80. package/dist/lib/task/control-authority.js +8 -5
  81. package/dist/lib/task/create-service.js +8 -8
  82. package/dist/lib/task/create.js +33 -7
  83. package/dist/lib/task/current-contract.js +5 -1
  84. package/dist/lib/task/decision-details.js +3 -48
  85. package/dist/lib/task/delivery-target.js +97 -0
  86. package/dist/lib/task/delivery.js +153 -0
  87. package/dist/lib/task/events.js +297 -17
  88. package/dist/lib/task/finalization.js +37 -13
  89. package/dist/lib/task/human-override.js +61 -36
  90. package/dist/lib/task/invalidation-command.js +86 -0
  91. package/dist/lib/task/invalidation.js +260 -0
  92. package/dist/lib/task/ledger-intents.js +37 -0
  93. package/dist/lib/task/lifecycle.js +106 -9
  94. package/dist/lib/task/local-artifact-finalization.js +374 -0
  95. package/dist/lib/task/orchestration.js +100 -151
  96. package/dist/lib/task/pr-delivery-fact.js +183 -0
  97. package/dist/lib/task/review-finalization.js +4 -8
  98. package/dist/lib/task/review-fingerprint.js +32 -2
  99. package/dist/lib/task/rework-intent.js +138 -0
  100. package/dist/lib/task/skill-scope.js +23 -0
  101. package/dist/lib/task/task-execution-lock.js +27 -17
  102. package/dist/lib/task/verification-engine.js +89 -38
  103. package/dist/lib/task/verification-review.js +1 -1
  104. package/dist/lib/task/verification.js +3 -3
  105. package/dist/lib/task/workflow-warning-intents.js +1 -1
  106. package/dist/lib/task/write.js +11 -0
  107. package/dist/lib/update.js +9 -0
  108. package/dist/lib/version.js +11 -1
  109. package/dist/lifecycle-build-manifest.json +3 -3
  110. package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +105 -10
  111. package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +12 -1
  112. package/lib/agent-clients/next-steps.ts +6 -1
  113. package/lib/decide.ts +3 -3
  114. package/lib/defaults.json +4 -0
  115. package/lib/git/workflow.ts +38 -1
  116. package/lib/init.ts +4 -1
  117. package/lib/internal/git-workflow.ts +7 -1
  118. package/lib/internal/platform-checks.ts +3 -3
  119. package/lib/internal/platform-comment.ts +8 -8
  120. package/lib/internal/platform-context.ts +2 -2
  121. package/lib/internal/platform-issue.ts +7 -8
  122. package/lib/internal/platform-pr-review.ts +9 -9
  123. package/lib/internal/platform-pr.ts +53 -21
  124. package/lib/internal/platform-release-notes.ts +3 -3
  125. package/lib/internal/pr-review-grade.ts +10 -8
  126. package/lib/internal/release-workflow.ts +4 -4
  127. package/lib/internal/sandbox-control.ts +27 -3
  128. package/lib/internal/task-activity.ts +3 -3
  129. package/lib/internal/task-artifact.ts +65 -22
  130. package/lib/internal/task-create.ts +2 -2
  131. package/lib/internal/task-delivery.ts +53 -0
  132. package/lib/internal/task-event.ts +6 -3
  133. package/lib/internal/task-finalization.ts +3 -3
  134. package/lib/internal/task-invalidation.ts +39 -0
  135. package/lib/internal/task-ledger.ts +11 -8
  136. package/lib/internal/task-lifecycle.ts +2 -2
  137. package/lib/internal/task-override.ts +6 -6
  138. package/lib/internal/task-review.ts +3 -3
  139. package/lib/internal/task-verify.ts +6 -6
  140. package/lib/internal/task-warning.ts +3 -3
  141. package/lib/platform/adapters.ts +3 -2
  142. package/lib/platform/change-request-git-evidence.ts +36 -9
  143. package/lib/platform/completion-backfill.ts +9 -8
  144. package/lib/platform/context.ts +97 -134
  145. package/lib/platform/github-client.ts +10 -3
  146. package/lib/platform/github-provider.ts +910 -0
  147. package/lib/platform/in-label-sync.ts +208 -0
  148. package/lib/platform/issue-comments.ts +97 -47
  149. package/lib/platform/issues.ts +344 -174
  150. package/lib/platform/metadata-labels.ts +5 -2
  151. package/lib/platform/none-provider.ts +35 -0
  152. package/lib/platform/pr-change-report.ts +645 -0
  153. package/lib/platform/pr-checks.ts +129 -107
  154. package/lib/platform/pr-review.ts +88 -85
  155. package/lib/platform/pr-summary.ts +562 -52
  156. package/lib/platform/provider-bridge.ts +82 -0
  157. package/lib/platform/provider-contract.ts +536 -0
  158. package/lib/platform/provider-loader.ts +307 -0
  159. package/lib/platform/provider-validation.ts +529 -0
  160. package/lib/platform/pull-request-metadata.ts +10 -7
  161. package/lib/platform/pull-requests.ts +1126 -505
  162. package/lib/platform/release-notes.ts +76 -59
  163. package/lib/platform/releases.ts +77 -43
  164. package/lib/platform/resource-identity.ts +121 -0
  165. package/lib/platform/task-identities.ts +40 -0
  166. package/lib/platform/types.ts +4 -2
  167. package/lib/platform/verification-required.ts +21 -13
  168. package/lib/platform/verification-sync.ts +118 -293
  169. package/lib/pr-review/evidence-grading.ts +31 -11
  170. package/lib/run/index.ts +57 -22
  171. package/lib/sandbox/config.ts +7 -0
  172. package/lib/sandbox/control/client.ts +105 -15
  173. package/lib/sandbox/control/executor.ts +4 -4
  174. package/lib/sandbox/control/lifecycle.ts +30 -8
  175. package/lib/sandbox/control/protocol.ts +113 -0
  176. package/lib/sandbox/control/server.ts +431 -23
  177. package/lib/sandbox/control/state.ts +251 -1
  178. package/lib/server/process-state.ts +2 -2
  179. package/lib/server/protocol.ts +36 -1
  180. package/lib/task/activity-log.ts +8 -0
  181. package/lib/task/artifact-lifecycle.ts +34 -8
  182. package/lib/task/capabilities.ts +262 -0
  183. package/lib/task/commands/status.ts +38 -0
  184. package/lib/task/commit-intent.ts +137 -0
  185. package/lib/task/commit-operation.ts +186 -88
  186. package/lib/task/control-authority.ts +11 -8
  187. package/lib/task/create-service.ts +8 -8
  188. package/lib/task/create.ts +34 -9
  189. package/lib/task/current-contract.ts +6 -1
  190. package/lib/task/decision-details.ts +8 -64
  191. package/lib/task/delivery-target.ts +130 -0
  192. package/lib/task/delivery.ts +160 -0
  193. package/lib/task/events.ts +296 -16
  194. package/lib/task/finalization.ts +50 -14
  195. package/lib/task/human-override.ts +73 -46
  196. package/lib/task/invalidation-command.ts +86 -0
  197. package/lib/task/invalidation.ts +332 -0
  198. package/lib/task/ledger-intents.ts +35 -1
  199. package/lib/task/lifecycle.ts +93 -4
  200. package/lib/task/local-artifact-finalization.ts +563 -0
  201. package/lib/task/orchestration.ts +110 -146
  202. package/lib/task/pr-delivery-fact.ts +237 -0
  203. package/lib/task/review-finalization.ts +4 -14
  204. package/lib/task/review-fingerprint.ts +33 -2
  205. package/lib/task/rework-intent.ts +165 -0
  206. package/lib/task/skill-scope.ts +24 -0
  207. package/lib/task/task-execution-lock.ts +23 -14
  208. package/lib/task/verification-engine.ts +95 -43
  209. package/lib/task/verification-review.ts +2 -0
  210. package/lib/task/verification.ts +4 -4
  211. package/lib/task/workflow-warning-intents.ts +1 -1
  212. package/lib/task/write.ts +19 -0
  213. package/lib/update.ts +11 -1
  214. package/lib/version.ts +15 -1
  215. package/package.json +7 -1
  216. package/templates/.agents/rules/README.en.md +4 -2
  217. package/templates/.agents/rules/README.zh-CN.md +4 -2
  218. package/templates/.agents/rules/create-issue.en.md +11 -2
  219. package/templates/.agents/rules/create-issue.zh-CN.md +24 -2
  220. package/templates/.agents/rules/issue-pr-commands.en.md +4 -17
  221. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
  222. package/templates/.agents/rules/issue-sync.en.md +28 -5
  223. package/templates/.agents/rules/issue-sync.zh-CN.md +64 -5
  224. package/templates/.agents/rules/label-milestone-setup.en.md +15 -2
  225. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +15 -2
  226. package/templates/.agents/rules/local-artifact-repair.en.md +53 -0
  227. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +53 -0
  228. package/templates/.agents/rules/milestone-inference.en.md +12 -2
  229. package/templates/.agents/rules/milestone-inference.zh-CN.md +25 -3
  230. package/templates/.agents/rules/pr-sync.en.md +28 -13
  231. package/templates/.agents/rules/pr-sync.zh-CN.md +39 -5
  232. package/templates/.agents/rules/release-commands.en.md +42 -3
  233. package/templates/.agents/rules/release-commands.zh-CN.md +42 -3
  234. package/templates/.agents/rules/security-alerts.en.md +17 -2
  235. package/templates/.agents/rules/security-alerts.zh-CN.md +17 -2
  236. package/templates/.agents/rules/sync-content-generation.en.md +8 -0
  237. package/templates/.agents/rules/sync-content-generation.zh-CN.md +8 -0
  238. package/templates/.agents/rules/task-management.en.md +1 -1
  239. package/templates/.agents/rules/task-management.zh-CN.md +1 -1
  240. package/templates/.agents/rules/task-short-id.en.md +1 -4
  241. package/templates/.agents/rules/task-short-id.zh-CN.md +1 -3
  242. package/templates/.agents/scripts/security-alerts.github.sh +151 -0
  243. package/templates/.agents/scripts/security-alerts.sh +31 -0
  244. package/templates/.agents/skills/analyze-task/SKILL.en.md +14 -3
  245. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +11 -3
  246. package/templates/.agents/skills/check-task/SKILL.en.md +16 -37
  247. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -37
  248. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  249. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  250. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  251. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  252. package/templates/.agents/skills/code-task/SKILL.en.md +32 -10
  253. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +35 -13
  254. package/templates/.agents/skills/code-task/config/verify.en.json +1 -0
  255. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +1 -0
  256. package/templates/.agents/skills/commit/SKILL.en.md +3 -3
  257. package/templates/.agents/skills/commit/SKILL.zh-CN.md +3 -3
  258. package/templates/.agents/skills/commit/config/verify.json +1 -1
  259. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +3 -3
  260. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +3 -3
  261. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +2 -0
  262. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +2 -0
  263. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +4 -4
  264. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +4 -4
  265. package/templates/.agents/skills/commit/reference/task-status-update.en.md +2 -2
  266. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +2 -2
  267. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +7 -4
  268. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +7 -4
  269. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
  270. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
  271. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +5 -4
  272. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +5 -4
  273. package/templates/.agents/skills/complete-task/SKILL.en.md +31 -13
  274. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +30 -13
  275. package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +2 -2
  276. package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +2 -2
  277. package/templates/.agents/skills/create-pr/SKILL.en.md +11 -10
  278. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +11 -11
  279. package/templates/.agents/skills/create-pr/config/verify.json +1 -0
  280. package/templates/.agents/skills/create-pr/reference/change-report.en.md +16 -4
  281. package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +16 -4
  282. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +5 -3
  283. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +5 -3
  284. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
  285. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
  286. package/templates/.agents/skills/create-pr/scripts/change-report.mjs +3 -0
  287. package/templates/.agents/skills/create-task/SKILL.en.md +1 -0
  288. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +1 -0
  289. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  290. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  291. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  292. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  293. package/templates/.agents/skills/init-labels/SKILL.en.md +9 -10
  294. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +9 -10
  295. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +57 -1
  296. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +27 -1
  297. package/templates/.agents/skills/init-milestones/SKILL.en.md +3 -5
  298. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +3 -5
  299. package/templates/.agents/skills/plan-task/SKILL.en.md +14 -3
  300. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +11 -3
  301. package/templates/.agents/skills/review-analysis/SKILL.en.md +6 -5
  302. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +6 -5
  303. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +18 -0
  304. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +18 -0
  305. package/templates/.agents/skills/review-code/SKILL.en.md +10 -9
  306. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +10 -9
  307. package/templates/.agents/skills/review-code/reference/output-templates.en.md +19 -1
  308. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +19 -1
  309. package/templates/.agents/skills/review-code/reference/report-template.en.md +4 -2
  310. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +4 -2
  311. package/templates/.agents/skills/review-plan/SKILL.en.md +6 -5
  312. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +6 -5
  313. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +18 -0
  314. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +18 -0
  315. package/templates/.agents/skills/review-pr/SKILL.en.md +1 -0
  316. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +1 -0
  317. package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +2 -2
  318. package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +2 -2
  319. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +5 -2
  320. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +5 -2
  321. package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
  322. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
  323. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +4 -0
  324. package/templates/.agents/skills/watch-pr/SKILL.en.md +6 -6
  325. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +6 -6
  326. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +6 -0
  327. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +6 -0
  328. package/templates/.agents/templates/task.en.md +23 -2
  329. package/templates/.agents/templates/task.zh-CN.md +23 -2
  330. package/templates/.agents/workflows/bug-fix.en.yaml +9 -8
  331. package/templates/.agents/workflows/bug-fix.zh-CN.yaml +9 -8
  332. package/templates/.agents/workflows/feature-development.en.yaml +9 -8
  333. package/templates/.agents/workflows/feature-development.zh-CN.yaml +9 -8
  334. package/templates/.agents/workflows/refactoring.en.yaml +9 -8
  335. package/templates/.agents/workflows/refactoring.zh-CN.yaml +9 -8
  336. package/templates/.github/workflows/pr-label.yml +7 -26
  337. package/templates/.agents/rules/create-issue.github.en.md +0 -14
  338. package/templates/.agents/rules/create-issue.github.zh-CN.md +0 -27
  339. package/templates/.agents/rules/issue-pr-commands.github.en.md +0 -34
  340. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +0 -49
  341. package/templates/.agents/rules/issue-sync.github.en.md +0 -40
  342. package/templates/.agents/rules/issue-sync.github.zh-CN.md +0 -76
  343. package/templates/.agents/rules/label-milestone-setup.github.en.md +0 -60
  344. package/templates/.agents/rules/label-milestone-setup.github.zh-CN.md +0 -60
  345. package/templates/.agents/rules/milestone-inference.github.en.md +0 -15
  346. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +0 -27
  347. package/templates/.agents/rules/pr-checks-commands.github.en.md +0 -18
  348. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +0 -34
  349. package/templates/.agents/rules/pr-sync.github.en.md +0 -43
  350. package/templates/.agents/rules/pr-sync.github.zh-CN.md +0 -69
  351. package/templates/.agents/rules/release-commands.github.en.md +0 -44
  352. package/templates/.agents/rules/release-commands.github.zh-CN.md +0 -44
  353. package/templates/.agents/rules/security-alerts.github.en.md +0 -43
  354. package/templates/.agents/rules/security-alerts.github.zh-CN.md +0 -43
  355. /package/templates/.agents/rules/{issue-fields.github.en.md → issue-fields.en.md} +0 -0
  356. /package/templates/.agents/rules/{issue-fields.github.zh-CN.md → issue-fields.zh-CN.md} +0 -0
@@ -2,8 +2,9 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { execFileSync } from 'node:child_process';
4
4
  import { createHash } from 'node:crypto';
5
- import { resolvePlatformContext } from './context.js';
6
- import { fetchGitHubReleaseNoteData, publishGitHubReleaseNotes } from './github-release-notes.js';
5
+ import { resolvePlatformProviderContext } from './context.js';
6
+ import { providerError, providerOperationContext, providerStatus, unsupportedProviderOperation } from './provider-bridge.js';
7
+ import { resourceIdentityNumber } from './resource-identity.js';
7
8
  const unsupportedError = {
8
9
  code: 'PLATFORM_RELEASE_NOTES_UNSUPPORTED',
9
10
  message: 'Release notes are not supported for the configured platform',
@@ -103,14 +104,21 @@ function configuredPlatform(cwd) {
103
104
  return null;
104
105
  }
105
106
  }
106
- function releaseNoteContext(input, options = {}) {
107
+ async function releaseNoteContext(input, options = {}) {
107
108
  const historyLimit = input.historyLimit ?? 3;
108
109
  if (!input.fromTag || !input.toTag || !input.branch || !Number.isInteger(historyLimit) || historyLimit < 1 || historyLimit > 20) {
109
110
  return { ...baseResult('failed'), error: { code: 'RELEASE_NOTES_INPUT_INVALID', message: 'from-tag, to-tag, branch, and a history limit from 1 to 20 are required', retryable: false } };
110
111
  }
111
112
  const cwd = path.resolve(options.cwd || process.cwd());
112
113
  const platformType = options.platformType ?? configuredPlatform(cwd);
113
- if (platformType !== 'github')
114
+ const loaded = await resolvePlatformProviderContext({ cwd, platformType: platformType || undefined, client: options.client });
115
+ if (!loaded.ok) {
116
+ if (loaded.context.status === 'no-op')
117
+ return baseResult('no-op');
118
+ const status = loaded.context.status === 'blocked' ? 'blocked' : 'failed';
119
+ return { ...baseResult(status), error: loaded.context.error };
120
+ }
121
+ if (!loaded.value.context.platform.repository)
114
122
  return baseResult('no-op');
115
123
  let fromOid;
116
124
  let toOid;
@@ -132,28 +140,24 @@ function releaseNoteContext(input, options = {}) {
132
140
  catch {
133
141
  return { ...baseResult('failed'), error: { code: 'RELEASE_NOTES_RANGE_INVALID', message: 'The release tag range is missing or is not ancestral', retryable: false } };
134
142
  }
135
- const context = resolvePlatformContext({ cwd, platformType, client: options.client });
136
- if (!context.platform.repository) {
137
- return {
138
- ...baseResult(context.status === 'blocked' ? 'blocked' : 'failed'),
139
- error: context.error || { code: 'PLATFORM_CONTEXT_UNAVAILABLE', message: 'Platform repository is unavailable', retryable: context.status === 'blocked' }
140
- };
141
- }
142
- const platform = fetchGitHubReleaseNoteData({
143
- repository: context.platform.repository,
144
- commitOids: commitFacts.map((item) => item.oid),
145
- branch: input.branch,
146
- historyLimit,
147
- fromTime,
148
- toTime
149
- }, { cwd, client: options.client });
150
- if (platform.status === 'blocked' || platform.status === 'failed' || !('authors' in platform)) {
151
- return { ...baseResult(platform.status), error: platform.error };
152
- }
143
+ const platform = loaded.value.provider.releases?.collectNotes
144
+ ? await loaded.value.provider.releases.collectNotes({
145
+ context: providerOperationContext(loaded.value),
146
+ commitOids: commitFacts.map((item) => item.oid),
147
+ branch: input.branch,
148
+ historyLimit,
149
+ fromTime,
150
+ toTime
151
+ })
152
+ : unsupportedProviderOperation(loaded.value.provider, 'releases.collectNotes');
153
+ if (!platform.ok)
154
+ return { ...baseResult(platform.error.retryable ? 'blocked' : 'failed'), error: providerError(platform.error, 'PLATFORM_PROVIDER_OPERATION_FAILED') };
153
155
  const commits = commitFacts.map((commit) => {
154
156
  const seen = new Set();
155
- const authors = (platform.authors.get(commit.oid) || []).filter((actor) => {
156
- const key = actor.login || actor.email?.toLowerCase() || actor.name.toLowerCase();
157
+ const authors = platform.value.history.filter((item) => item.sha === commit.oid).flatMap((item) => item.author ? [item.author] : [])
158
+ .concat(platform.value.actors)
159
+ .filter((actor) => {
160
+ const key = actor.id || actor.name || '';
157
161
  if (seen.has(key))
158
162
  return false;
159
163
  seen.add(key);
@@ -161,43 +165,37 @@ function releaseNoteContext(input, options = {}) {
161
165
  });
162
166
  return { ...commit, authors };
163
167
  });
164
- const pullRequests = platform.pullRequests
168
+ const pullRequests = platform.value.mergedPullRequests
165
169
  .map((item) => ({
166
- number: Number(item.number),
167
- title: String(item.title || ''),
168
- body: String(item.body || ''),
169
- url: String(item.url || ''),
170
- mergedAt: String(item.mergedAt || ''),
171
- labels: Array.isArray(item.labels) ? item.labels.map((label) => String(label.name || label)) : [],
172
- author: item.author && typeof item.author === 'object'
173
- ? { login: String(item.author.login || '').toLowerCase(), bot: String(item.author.login || '').endsWith('[bot]') }
174
- : null,
175
- closingIssues: Array.isArray(item.closingIssuesReferences)
176
- ? item.closingIssuesReferences.map((issue) => {
177
- const value = issue;
178
- return {
179
- number: Number(value.number),
180
- title: String(value.title || ''),
181
- url: String(value.url || ''),
182
- labels: Array.isArray(value.labels) ? value.labels.map((label) => String(label.name || label)) : [],
183
- author: value.author && typeof value.author === 'object'
184
- ? { login: String(value.author.login || '').toLowerCase(), bot: String(value.author.login || '').endsWith('[bot]') }
185
- : null
186
- };
187
- }) : []
170
+ number: item.number || resourceIdentityNumber(item.identity) || 0,
171
+ ...(item.identity ? { identity: item.identity } : {}),
172
+ title: item.title,
173
+ body: item.body,
174
+ url: item.displayUrl || '',
175
+ mergedAt: item.mergedAt || '',
176
+ labels: item.labels || [],
177
+ author: item.author ? { login: item.author.name || item.author.id || '', bot: false } : null,
178
+ closingIssues: platform.value.closingIssues.filter((issue) => issue.id === item.id).map((issue) => ({
179
+ number: issue.number || resourceIdentityNumber(issue.identity) || 0,
180
+ ...(issue.identity ? { identity: issue.identity } : {}),
181
+ title: issue.title,
182
+ url: issue.displayUrl || '',
183
+ labels: issue.labels || [],
184
+ author: issue.author ? { login: issue.author.name || issue.author.id || '', bot: false } : null
185
+ }))
188
186
  }))
189
187
  .sort((left, right) => left.number - right.number);
190
188
  return {
191
189
  status: 'no-op',
192
190
  changed: false,
193
191
  range: { fromTag: input.fromTag, toTag: input.toTag, fromOid, toOid },
194
- history: platform.history,
192
+ history: platform.value.history,
195
193
  pullRequests,
196
194
  commits,
197
195
  error: null
198
196
  };
199
197
  }
200
- function publishReleaseNotes(input, options = {}) {
198
+ async function publishReleaseNotes(input, options = {}) {
201
199
  if (!input.tag || !input.title || !input.notesFile || !SHA256_PATTERN.test(input.expectedSha256)) {
202
200
  return releaseNoteFailure('RELEASE_NOTES_INPUT_INVALID', 'tag, title, notes-file, and expected-sha256 are required');
203
201
  }
@@ -213,13 +211,38 @@ function publishReleaseNotes(input, options = {}) {
213
211
  }
214
212
  const cwd = path.resolve(options.cwd || process.cwd());
215
213
  const platformType = options.platformType ?? configuredPlatform(cwd);
216
- if (platformType !== 'github')
217
- return { status: 'no-op', changed: false, operation: null, url: null, error: unsupportedError };
218
- const context = resolvePlatformContext({ cwd, platformType, client: options.client });
219
- if (!context.platform.repository) {
220
- return { status: context.status === 'blocked' ? 'blocked' : 'failed', changed: false, operation: null, url: null, error: context.error };
214
+ const loaded = await resolvePlatformProviderContext({ cwd, platformType: platformType || undefined, client: options.client });
215
+ if (!loaded.ok) {
216
+ const status = loaded.context.status === 'blocked'
217
+ ? 'blocked'
218
+ : loaded.context.status === 'no-op' ? 'no-op' : 'failed';
219
+ return {
220
+ ...baseResult(status),
221
+ error: loaded.context.error || { code: 'PLATFORM_PROVIDER_LOAD_FAILED', message: 'Selected provider failed to load', retryable: false }
222
+ };
221
223
  }
222
- return publishGitHubReleaseNotes({ ...input, repository: context.platform.repository }, { cwd, client: options.client });
224
+ if (loaded.ok) {
225
+ const context = loaded.value.context;
226
+ if (!context.platform.repository)
227
+ return { status: context.status === 'blocked' ? 'blocked' : 'failed', changed: false, operation: null, url: null, error: context.error };
228
+ const published = loaded.value.provider.releases?.publishNotes
229
+ ? await loaded.value.provider.releases.publishNotes({
230
+ context: providerOperationContext(loaded.value),
231
+ release: { kind: 'key', value: input.tag },
232
+ title: input.title,
233
+ notes: {
234
+ text: fs.readFileSync(input.notesFile, 'utf8'),
235
+ sha256: actualSha256,
236
+ byteLength: fs.statSync(input.notesFile).size
237
+ },
238
+ mutation: { idempotencyKey: `release-notes:publish:${input.tag}` }
239
+ })
240
+ : unsupportedProviderOperation(loaded.value.provider, 'releases.publishNotes');
241
+ if (!published.ok)
242
+ return { status: providerStatus(published.error), changed: false, operation: null, url: null, error: providerError(published.error, 'PLATFORM_PROVIDER_OPERATION_FAILED') };
243
+ return { status: 'applied', changed: published.value.changed, operation: 'publish-notes', url: null, error: null };
244
+ }
245
+ return { status: 'failed', changed: false, operation: null, url: null, error: { code: 'PLATFORM_PROVIDER_LOAD_FAILED', message: 'Selected provider failed to load', retryable: false } };
223
246
  }
224
247
  export { normalizeReleaseNoteBytes, publishReleaseNotes, releaseNoteContext, releaseNoteSha256, stageReleaseNotes };
225
248
  //# sourceMappingURL=release-notes.js.map
@@ -1,57 +1,80 @@
1
- import { createGitHubClient } from './github-client.js';
2
- import { resolvePlatformContext } from './context.js';
1
+ import fs from 'node:fs';
2
+ import crypto from 'node:crypto';
3
+ import { resolvePlatformProviderContext } from './context.js';
3
4
  import { platformResult } from './types.js';
5
+ import { providerError, providerOperationContext, providerStatus, unsupportedProviderOperation } from './provider-bridge.js';
4
6
  function flattenPages(value) {
5
7
  if (!Array.isArray(value))
6
8
  return [];
7
9
  return value.flatMap((entry) => Array.isArray(entry) ? entry : [entry]).filter((entry) => Boolean(entry) && typeof entry === 'object');
8
10
  }
9
- function inspectPlatformRelease(tag, options = {}) {
10
- const client = options.client ?? createGitHubClient();
11
- const context = resolvePlatformContext({ cwd: options.cwd, client });
11
+ async function inspectPlatformRelease(tag, options = {}) {
12
+ const loaded = await resolvePlatformProviderContext({ cwd: options.cwd, client: options.client });
13
+ const context = loaded.ok ? loaded.value.context : loaded.context;
12
14
  if (!context.platform.repository)
13
15
  return { ...platformResult(context.status), platform: context.platform, release: null, workflows: [], error: context.error };
14
- const result = client.json(['release', 'view', tag, '--repo', context.platform.repository, '--json', 'tagName,isDraft,url'], { cwd: options.cwd });
15
- if (!result.ok) {
16
- if (result.error.code === 'RESOURCE_NOT_FOUND')
17
- return { ...platformResult('no-op'), platform: context.platform, release: null, workflows: [], error: null };
18
- return { ...platformResult(result.error.retryable ? 'blocked' : 'failed'), platform: context.platform, release: null, workflows: [], error: result.error };
16
+ if (loaded.ok) {
17
+ const inspected = loaded.value.provider.releases?.inspect
18
+ ? await loaded.value.provider.releases.inspect({ context: providerOperationContext(loaded.value), tag })
19
+ : unsupportedProviderOperation(loaded.value.provider, 'releases.inspect');
20
+ if (!inspected.ok) {
21
+ if (inspected.error.code === 'RESOURCE_NOT_FOUND')
22
+ return { ...platformResult('no-op'), platform: context.platform, release: null, workflows: [], error: null };
23
+ return { ...platformResult(providerStatus(inspected.error)), platform: context.platform, release: null, workflows: [], error: providerError(inspected.error, 'PLATFORM_PROVIDER_OPERATION_FAILED') };
24
+ }
25
+ return {
26
+ ...platformResult('no-op'),
27
+ platform: context.platform,
28
+ release: { tag: inspected.value.tag, published: !inspected.value.draft, draft: inspected.value.draft, url: inspected.value.displayUrl || null },
29
+ workflows: inspected.value.workflows || [],
30
+ error: null
31
+ };
19
32
  }
20
- const release = { tag: String(result.value.tagName || tag), published: !Boolean(result.value.isDraft), draft: Boolean(result.value.isDraft), url: result.value.url ? String(result.value.url) : null };
21
- const runs = client.json(['run', 'list', '--repo', context.platform.repository, '--limit', '100', '--json', 'name,workflowName,displayTitle,event,headBranch,headSha,status,conclusion,createdAt,databaseId,attempt,url'], { cwd: options.cwd });
22
- return { ...platformResult(runs.ok ? 'no-op' : runs.error.retryable ? 'blocked' : 'degraded'), platform: context.platform, release, workflows: runs.ok ? runs.value : [], error: runs.ok ? null : runs.error };
33
+ return { ...platformResult('failed'), platform: context.platform, release: null, workflows: [], error: context.error };
23
34
  }
24
- function upsertPlatformRelease(input, options = {}) {
25
- const inspected = inspectPlatformRelease(input.tag, options);
35
+ async function upsertPlatformRelease(input, options = {}) {
36
+ const inspected = await inspectPlatformRelease(input.tag, options);
26
37
  if (inspected.release?.published)
27
38
  return { ...inspected, status: 'no-op', changed: false, operations: [] };
28
39
  if (inspected.status === 'blocked' || inspected.status === 'failed')
29
40
  return { ...inspected, changed: false, operations: [] };
30
41
  if (!inspected.platform.repository)
31
42
  return { ...inspected, status: 'no-op', changed: false, operations: [] };
32
- const client = options.client ?? createGitHubClient();
33
- const args = ['release', 'create', input.tag, '--repo', inspected.platform.repository, '--title', input.title ?? input.tag];
34
- if (input.notesFile)
35
- args.push('--notes-file', input.notesFile);
36
- else
37
- args.push('--generate-notes');
38
- const created = client.text(args, { cwd: options.cwd, method: 'POST' });
39
- if (!created.ok)
40
- return { ...inspected, status: created.error.retryable ? 'blocked' : 'failed', changed: false, operations: [{ name: 'create-release', status: 'failed' }], error: created.error };
41
- return { ...inspectPlatformRelease(input.tag, options), status: 'applied', changed: true, operations: [{ name: 'create-release', status: 'applied' }] };
43
+ const loaded = await resolvePlatformProviderContext({ cwd: options.cwd, client: options.client });
44
+ if (loaded.ok) {
45
+ let notes;
46
+ if (input.notesFile) {
47
+ try {
48
+ const bytes = fs.readFileSync(input.notesFile);
49
+ notes = { text: bytes.toString('utf8'), sha256: `sha256:${crypto.createHash('sha256').update(bytes).digest('hex')}`, byteLength: bytes.byteLength };
50
+ }
51
+ catch {
52
+ return { ...inspected, status: 'failed', changed: false, operations: [{ name: 'create-release', status: 'failed' }], error: { code: 'RELEASE_NOTES_FILE_UNREADABLE', message: 'notes-file could not be read', retryable: false } };
53
+ }
54
+ }
55
+ const created = loaded.value.provider.releases?.create
56
+ ? await loaded.value.provider.releases.create({
57
+ context: providerOperationContext(loaded.value),
58
+ tag: input.tag,
59
+ title: input.title ?? input.tag,
60
+ ...(notes ? { notes } : {}),
61
+ mutation: { idempotencyKey: `release:create:${input.tag}` }
62
+ })
63
+ : unsupportedProviderOperation(loaded.value.provider, 'releases.create');
64
+ if (!created.ok)
65
+ return { ...inspected, status: providerStatus(created.error), changed: false, operations: [{ name: 'create-release', status: 'failed' }], error: providerError(created.error, 'PLATFORM_PROVIDER_OPERATION_FAILED') };
66
+ return { ...inspected, status: 'applied', changed: created.value.changed, operations: [{ name: 'create-release', status: 'applied' }], error: null };
67
+ }
68
+ return { ...inspected, status: 'failed', changed: false, operations: [{ name: 'create-release', status: 'failed' }], error: { code: 'PLATFORM_PROVIDER_LOAD_FAILED', message: 'Selected provider failed to load', retryable: false } };
42
69
  }
43
- function reconcileReleaseMilestones(version, options = {}) {
70
+ async function reconcileReleaseMilestones(version, options = {}) {
44
71
  const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);
45
72
  if (!match)
46
73
  return { status: 'failed', changed: false, operations: [], error: { code: 'RELEASE_VERSION_INVALID', message: `Invalid version '${version}'` } };
47
- const client = options.client ?? createGitHubClient();
48
- const context = resolvePlatformContext({ cwd: options.cwd, client });
74
+ const loaded = await resolvePlatformProviderContext({ cwd: options.cwd, client: options.client });
75
+ const context = loaded.ok ? loaded.value.context : loaded.context;
49
76
  if (!context.platform.repository)
50
77
  return { ...platformResult(context.status), changed: false, operations: [], error: context.error };
51
- const listed = client.json(['api', '--paginate', '--slurp', `repos/${context.platform.repository}/milestones?state=all&per_page=100`], { cwd: options.cwd });
52
- if (!listed.ok)
53
- return { ...platformResult(listed.error.retryable ? 'blocked' : 'failed'), changed: false, operations: [], error: listed.error };
54
- const milestones = flattenPages(listed.value).map((item) => ({ title: String(item.title || ''), number: Number(item.number), state: String(item.state || '') }));
55
78
  const major = Number(match[1]);
56
79
  const minor = Number(match[2]);
57
80
  const patch = Number(match[3]);
@@ -66,25 +89,31 @@ function reconcileReleaseMilestones(version, options = {}) {
66
89
  const nextLine = `${major}.${minor + 1}.x`;
67
90
  ensure.push({ title: nextMinor, description: `Issues that we want to release in v${nextMinor}.` }, { title: nextLine, description: `Issues that we want to resolve in ${major}.${minor + 1} line.` });
68
91
  }
69
- const operations = [];
70
- const current = milestones.find((item) => item.title === version);
71
- if (current && current.state !== 'closed') {
72
- const closed = client.json(['api', '--method', 'PATCH', `repos/${context.platform.repository}/milestones/${current.number}`, '-f', 'state=closed'], { cwd: options.cwd });
73
- operations.push({ name: 'close-milestone', title: version, status: closed.ok ? 'applied' : 'failed' });
74
- }
75
- else
76
- operations.push({ name: 'close-milestone', title: version, status: 'no-op' });
77
- for (const { title, description } of ensure) {
78
- if (milestones.some((item) => item.title === title))
79
- operations.push({ name: 'ensure-milestone', title, status: 'no-op' });
80
- else {
81
- const created = client.json(['api', '--method', 'POST', `repos/${context.platform.repository}/milestones`, '-f', `title=${title}`, '-f', `description=${description}`], { cwd: options.cwd });
82
- operations.push({ name: 'ensure-milestone', title, status: created.ok ? 'applied' : 'failed' });
83
- }
92
+ if (loaded.ok) {
93
+ const reconciled = loaded.value.provider.releases?.reconcileMilestones
94
+ ? await loaded.value.provider.releases.reconcileMilestones({
95
+ context: providerOperationContext(loaded.value),
96
+ version,
97
+ desired: [
98
+ { key: version, title: version, description: `Issues that we want to resolve in v${version}.`, state: 'closed' },
99
+ ...ensure.map((item) => ({ key: item.title, title: item.title, description: item.description, state: 'open' }))
100
+ ],
101
+ mutation: { idempotencyKey: `milestones:reconcile:${version}` }
102
+ })
103
+ : unsupportedProviderOperation(loaded.value.provider, 'releases.reconcileMilestones');
104
+ if (!reconciled.ok)
105
+ return { status: providerStatus(reconciled.error), changed: false, operations: [], error: providerError(reconciled.error, 'PLATFORM_PROVIDER_OPERATION_FAILED') };
106
+ return {
107
+ status: reconciled.value.changed ? 'applied' : 'no-op',
108
+ changed: reconciled.value.changed,
109
+ operations: [
110
+ ...reconciled.value.closed.map((title) => ({ name: 'close-milestone', title, status: 'applied' })),
111
+ ...reconciled.value.created.map((title) => ({ name: 'ensure-milestone', title, status: 'applied' }))
112
+ ],
113
+ error: null
114
+ };
84
115
  }
85
- const failed = operations.some((operation) => operation.status === 'failed');
86
- const changed = operations.some((operation) => operation.status === 'applied');
87
- return { status: failed ? 'failed' : changed ? 'applied' : 'no-op', changed, operations, error: failed ? { code: 'MILESTONE_RECONCILE_FAILED', message: 'One or more milestone operations failed' } : null };
116
+ return { status: 'failed', changed: false, operations: [], error: { code: 'PLATFORM_CAPABILITY_UNSUPPORTED', message: 'Release milestone reconciliation is unavailable', retryable: false } };
88
117
  }
89
118
  export { inspectPlatformRelease, reconcileReleaseMilestones, upsertPlatformRelease };
90
119
  //# sourceMappingURL=releases.js.map
@@ -0,0 +1,26 @@
1
+ type ResourceIdentityKind = 'id' | 'number' | 'key';
2
+ type ResourceIdentity = {
3
+ kind: 'id';
4
+ value: string;
5
+ } | {
6
+ kind: 'number';
7
+ value: number;
8
+ } | {
9
+ kind: 'key';
10
+ value: string;
11
+ };
12
+ type CanonicalResourceIdentity = ResourceIdentity;
13
+ type PlatformResourceKind = 'issue' | 'pull-request' | 'comment' | 'release';
14
+ type ProviderIdentityDeclaration = Partial<Record<PlatformResourceKind, ResourceIdentityKind>>;
15
+ declare function isResourceIdentity(value: unknown): value is CanonicalResourceIdentity;
16
+ declare function parseResourceIdentity(value: unknown, label?: string): CanonicalResourceIdentity;
17
+ declare function serializeResourceIdentity(identity: ResourceIdentity): string;
18
+ declare function resourceIdentityEquals(left: unknown, right: unknown): boolean;
19
+ declare function primaryIdentityKind(declaration: ProviderIdentityDeclaration | undefined, resourceKind: PlatformResourceKind): ResourceIdentityKind;
20
+ declare function parseResourceToken(token: string, resourceKind: PlatformResourceKind, declaration: ProviderIdentityDeclaration | undefined): ResourceIdentity;
21
+ declare function identityFromRemoteValue(value: unknown, resourceKind: PlatformResourceKind, declaration: ProviderIdentityDeclaration | undefined): ResourceIdentity;
22
+ declare function resourceIdentityNumber(identity: ResourceIdentity | null | undefined): number | null;
23
+ declare function resourceIdentityString(identity: ResourceIdentity | null | undefined): string | null;
24
+ declare function reviewMarker(identity: ResourceIdentity): string;
25
+ export { identityFromRemoteValue, isResourceIdentity, parseResourceIdentity, parseResourceToken, primaryIdentityKind, resourceIdentityEquals, resourceIdentityNumber, resourceIdentityString, reviewMarker, serializeResourceIdentity };
26
+ export type { CanonicalResourceIdentity, PlatformResourceKind, ProviderIdentityDeclaration, ResourceIdentity, ResourceIdentityKind };
@@ -0,0 +1,92 @@
1
+ function identityError(message) {
2
+ return Object.assign(new Error(`PLATFORM_IDENTITY_INVALID: ${message}`), {
3
+ code: 'PLATFORM_IDENTITY_INVALID'
4
+ });
5
+ }
6
+ function isResourceIdentity(value) {
7
+ if (!value || typeof value !== 'object' || Array.isArray(value))
8
+ return false;
9
+ const candidate = value;
10
+ if (Object.keys(candidate).length !== 2 || typeof candidate.kind !== 'string')
11
+ return false;
12
+ if (candidate.kind === 'number') {
13
+ return Number.isSafeInteger(candidate.value) && candidate.value > 0;
14
+ }
15
+ return (candidate.kind === 'id' || candidate.kind === 'key')
16
+ && typeof candidate.value === 'string'
17
+ && candidate.value.length > 0
18
+ && candidate.value.trim() === candidate.value;
19
+ }
20
+ function parseResourceIdentity(value, label = 'identity') {
21
+ if (!isResourceIdentity(value))
22
+ throw identityError(`${label} must contain exactly one valid kind/value pair`);
23
+ if (value.kind === 'number')
24
+ return { kind: 'number', value: value.value };
25
+ if (value.kind === 'id')
26
+ return { kind: 'id', value: value.value };
27
+ return { kind: 'key', value: value.value };
28
+ }
29
+ function serializeResourceIdentity(identity) {
30
+ return JSON.stringify(parseResourceIdentity(identity));
31
+ }
32
+ function resourceIdentityEquals(left, right) {
33
+ return isResourceIdentity(left) && isResourceIdentity(right)
34
+ && left.kind === right.kind && left.value === right.value;
35
+ }
36
+ function primaryIdentityKind(declaration, resourceKind) {
37
+ const kind = declaration?.[resourceKind];
38
+ if (kind !== 'id' && kind !== 'number' && kind !== 'key') {
39
+ throw identityError(`provider does not declare a primary identity for ${resourceKind}`);
40
+ }
41
+ return kind;
42
+ }
43
+ function parseResourceToken(token, resourceKind, declaration) {
44
+ if (typeof token !== 'string' || token.length === 0)
45
+ throw identityError('resource token must be a non-empty string');
46
+ const kind = primaryIdentityKind(declaration, resourceKind);
47
+ if (kind === 'number') {
48
+ if (!/^[1-9]\d*$/u.test(token))
49
+ throw identityError(`${resourceKind} token must be a positive safe integer`);
50
+ const value = Number(token);
51
+ if (!Number.isSafeInteger(value) || value <= 0)
52
+ throw identityError(`${resourceKind} token must be a positive safe integer`);
53
+ return { kind, value };
54
+ }
55
+ const value = token.trim();
56
+ if (!value)
57
+ throw identityError(`${resourceKind} token must not be empty`);
58
+ return { kind, value };
59
+ }
60
+ function identityFromRemoteValue(value, resourceKind, declaration) {
61
+ const kind = primaryIdentityKind(declaration, resourceKind);
62
+ if (isResourceIdentity(value)) {
63
+ if (value.kind !== kind)
64
+ throw identityError(`${resourceKind} response identity kind does not match provider declaration`);
65
+ return value;
66
+ }
67
+ if (kind === 'number') {
68
+ if (typeof value === 'number' && Number.isSafeInteger(value) && value > 0)
69
+ return { kind, value };
70
+ if (typeof value === 'string' && /^[1-9]\d*$/u.test(value))
71
+ return parseResourceToken(value, resourceKind, declaration);
72
+ throw identityError(`${resourceKind} response does not contain a valid number identity`);
73
+ }
74
+ if (typeof value !== 'string' || !value.trim())
75
+ throw identityError(`${resourceKind} response does not contain a valid string identity`);
76
+ return { kind, value: value.trim() };
77
+ }
78
+ function resourceIdentityNumber(identity) {
79
+ return identity?.kind === 'number' ? identity.value : null;
80
+ }
81
+ function resourceIdentityString(identity) {
82
+ return identity && (identity.kind === 'id' || identity.kind === 'key') ? identity.value : null;
83
+ }
84
+ function reviewMarker(identity) {
85
+ const parsed = parseResourceIdentity(identity);
86
+ if (parsed.kind === 'number')
87
+ return `pr${parsed.value}`;
88
+ const encoded = Buffer.from(serializeResourceIdentity(parsed), 'utf8').toString('base64url');
89
+ return `pr:${encoded}`;
90
+ }
91
+ export { identityFromRemoteValue, isResourceIdentity, parseResourceIdentity, parseResourceToken, primaryIdentityKind, resourceIdentityEquals, resourceIdentityNumber, resourceIdentityString, reviewMarker, serializeResourceIdentity };
92
+ //# sourceMappingURL=resource-identity.js.map
@@ -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,16 +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";
7
+ import { readPrDeliveryFact } from "../task/pr-delivery-fact.js";
8
+ import { resourceIdentityNumber } from "./resource-identity.js";
8
9
  const CHECK_TYPE = "required-checks";
9
10
  const SHA_PATTERN = /^[0-9a-f]{7,40}$/i;
10
- function validPrNumber(value) {
11
- const parsed = Number(value);
12
- return Number.isInteger(parsed) && parsed > 0;
13
- }
14
11
  function readPrFlow(repoRoot) {
15
12
  try {
16
13
  const config = JSON.parse(fs.readFileSync(path.join(repoRoot, ".agents", ".airc.json"), "utf8"));
@@ -30,7 +27,14 @@ function readHead(repoRoot) {
30
27
  }
31
28
  export function evaluateRequiredChecks(context, shared) {
32
29
  const { metadata, localHead, inspection, prFlow } = context;
33
- if (prFlow === "disabled" || metadata.pr_status === "skipped" || !validPrNumber(metadata.pr_number)) {
30
+ const factRead = readPrDeliveryFact(metadata);
31
+ if (factRead.status === "invalid") {
32
+ return shared.failResult(CHECK_TYPE, factRead.error.message, "check_failed");
33
+ }
34
+ const fact = factRead.status === "valid" ? factRead.fact : null;
35
+ const prIdentity = fact?.state === "bound" ? fact.identity.resource : null;
36
+ const prNumber = resourceIdentityNumber(prIdentity);
37
+ if (prFlow === "disabled" || fact?.state === "skipped" || !prIdentity) {
34
38
  return shared.passResult(CHECK_TYPE, "Skipped: required checks are not applicable to this task");
35
39
  }
36
40
  const reviewedHead = String(metadata.last_reviewed_commit || "");
@@ -73,22 +77,28 @@ export function evaluateRequiredChecks(context, shared) {
73
77
  }
74
78
  return shared.failResult(CHECK_TYPE, inspection.error?.message || `Required checks are ${state || "unavailable"}`, "check_failed");
75
79
  }
76
- export function check({ taskDir }, shared) {
80
+ export async function check({ taskDir }, shared) {
77
81
  const task = shared.loadTask(taskDir);
78
82
  if (!task.ok)
79
83
  return shared.failResult(CHECK_TYPE, task.message);
80
84
  const prFlow = readPrFlow(shared.repoRoot);
81
- if (prFlow === "disabled" || task.metadata.pr_status === "skipped" || !validPrNumber(task.metadata.pr_number)) {
85
+ const factRead = readPrDeliveryFact(task.metadata);
86
+ if (factRead.status === "invalid")
87
+ return shared.failResult(CHECK_TYPE, factRead.error.message, "check_failed");
88
+ const bound = factRead.status === "valid" && factRead.fact.state === "bound";
89
+ if (prFlow === "disabled" || (factRead.status === "valid" && factRead.fact.state === "skipped") || !bound) {
82
90
  return evaluateRequiredChecks({ metadata: task.metadata, localHead: null, inspection: null, prFlow }, shared);
83
91
  }
84
- const platform = resolvePlatformContext({ cwd: shared.repoRoot });
85
- 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) {
86
96
  return shared.blockedResult(CHECK_TYPE, `Platform '${platform.platform.type || "none"}' does not provide required-checks inspection`, "dependency_error");
87
97
  }
88
98
  const localHead = readHead(shared.repoRoot);
89
99
  if (!localHead)
90
100
  return evaluateRequiredChecks({ metadata: task.metadata, localHead, inspection: null, prFlow }, shared);
91
- const inspection = inspectRequiredChecks(task.metadata.id, { cwd: shared.repoRoot });
101
+ const inspection = await inspectRequiredChecks(task.metadata.id, { cwd: shared.repoRoot });
92
102
  return evaluateRequiredChecks({
93
103
  metadata: task.metadata,
94
104
  localHead,