@fitlab-ai/agent-infra 0.9.12 → 0.9.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (402) hide show
  1. package/README.md +11 -11
  2. package/README.zh-CN.md +11 -11
  3. package/bin/cli.ts +26 -9
  4. package/dist/bin/cli.js +173 -157
  5. package/dist/bin/internal-cli.js +66 -40
  6. package/dist/lib/agent-client.js +5 -0
  7. package/dist/lib/agent-clients/next-steps.js +6 -1
  8. package/dist/lib/decide.js +3 -3
  9. package/dist/lib/internal/agent-client.js +5 -2
  10. package/dist/lib/internal/cli-route-inventory.js +152 -0
  11. package/dist/lib/internal/codex-lifecycle.js +9 -6
  12. package/dist/lib/internal/codex-sandbox-controller.js +8 -2
  13. package/dist/lib/internal/git-workflow.js +10 -6
  14. package/dist/lib/internal/platform-checks.js +19 -7
  15. package/dist/lib/internal/platform-comment.js +25 -13
  16. package/dist/lib/internal/platform-context.js +6 -3
  17. package/dist/lib/internal/platform-issue.js +20 -13
  18. package/dist/lib/internal/platform-metadata.js +88 -0
  19. package/dist/lib/internal/platform-pr-review.js +26 -13
  20. package/dist/lib/internal/platform-pr.js +84 -31
  21. package/dist/lib/internal/platform-release-notes.js +9 -6
  22. package/dist/lib/internal/platform-security.js +93 -0
  23. package/dist/lib/internal/pr-review-grade.js +25 -12
  24. package/dist/lib/internal/release-workflow.js +23 -9
  25. package/dist/lib/internal/sandbox-control.js +50 -7
  26. package/dist/lib/internal/task-activity.js +16 -7
  27. package/dist/lib/internal/task-artifact.js +235 -24
  28. package/dist/lib/internal/task-context.js +4 -1
  29. package/dist/lib/internal/task-create.js +50 -17
  30. package/dist/lib/internal/task-delivery.js +4 -1
  31. package/dist/lib/internal/task-event.js +10 -4
  32. package/dist/lib/internal/task-finalization.js +6 -3
  33. package/dist/lib/internal/task-invalidation.js +63 -0
  34. package/dist/lib/internal/task-ledger.js +20 -6
  35. package/dist/lib/internal/task-lifecycle.js +6 -3
  36. package/dist/lib/internal/task-operation-registry.js +421 -0
  37. package/dist/lib/internal/task-orchestration.js +12 -0
  38. package/dist/lib/internal/task-override.js +14 -7
  39. package/dist/lib/internal/task-qualification.js +90 -0
  40. package/dist/lib/internal/task-review.js +7 -4
  41. package/dist/lib/internal/task-short-id.js +11 -1
  42. package/dist/lib/internal/task-snapshot.js +4 -1
  43. package/dist/lib/internal/task-validate.js +7 -2
  44. package/dist/lib/internal/task-verify.js +11 -7
  45. package/dist/lib/internal/task-warning.js +11 -4
  46. package/dist/lib/platform/adapters.js +1 -3
  47. package/dist/lib/platform/change-request-git-evidence.js +27 -7
  48. package/dist/lib/platform/comment-safety.js +226 -0
  49. package/dist/lib/platform/completion-backfill.js +6 -5
  50. package/dist/lib/platform/context.js +70 -130
  51. package/dist/lib/platform/github-client.js +1 -1
  52. package/dist/lib/platform/github-provider.js +1130 -0
  53. package/dist/lib/platform/in-label-sync.js +143 -0
  54. package/dist/lib/platform/issue-comments.js +237 -72
  55. package/dist/lib/platform/issues.js +335 -189
  56. package/dist/lib/platform/metadata-labels.js +6 -2
  57. package/dist/lib/platform/none-provider.js +28 -0
  58. package/dist/lib/platform/pr-change-report.js +545 -0
  59. package/dist/lib/platform/pr-checks.js +119 -104
  60. package/dist/lib/platform/pr-review.js +88 -72
  61. package/dist/lib/platform/pr-summary.js +541 -50
  62. package/dist/lib/platform/provider-bridge.js +45 -0
  63. package/dist/lib/platform/provider-contract.d.ts +553 -0
  64. package/dist/lib/platform/provider-contract.js +99 -0
  65. package/dist/lib/platform/provider-loader.js +251 -0
  66. package/dist/lib/platform/provider-validation.js +577 -0
  67. package/dist/lib/platform/pull-request-metadata.js +8 -6
  68. package/dist/lib/platform/pull-requests.js +734 -543
  69. package/dist/lib/platform/release-notes.js +78 -55
  70. package/dist/lib/platform/releases.js +79 -50
  71. package/dist/lib/platform/repository-metadata.js +377 -0
  72. package/dist/lib/platform/resource-identity.d.ts +26 -0
  73. package/dist/lib/platform/resource-identity.js +92 -0
  74. package/dist/lib/platform/security-alerts.js +155 -0
  75. package/dist/lib/platform/task-identities.js +31 -0
  76. package/dist/lib/platform/verification-required.js +11 -12
  77. package/dist/lib/platform/verification-sync.js +129 -248
  78. package/dist/lib/pr-review/evidence-grading.js +19 -6
  79. package/dist/lib/process-data/index.js +7 -0
  80. package/dist/lib/run/index.js +68 -23
  81. package/dist/lib/sandbox/commands/control-status.js +22 -0
  82. package/dist/lib/sandbox/commands/create.js +32 -6
  83. package/dist/lib/sandbox/commands/ls.js +5 -0
  84. package/dist/lib/sandbox/commands/rm.js +827 -120
  85. package/dist/lib/sandbox/commands/show.js +16 -0
  86. package/dist/lib/sandbox/control/client.js +174 -19
  87. package/dist/lib/sandbox/control/completed-reentry.js +85 -0
  88. package/dist/lib/sandbox/control/container-identity.js +28 -31
  89. package/dist/lib/sandbox/control/executor.js +151 -16
  90. package/dist/lib/sandbox/control/lifecycle.js +621 -127
  91. package/dist/lib/sandbox/control/native-file-lock.js +177 -0
  92. package/dist/lib/sandbox/control/protocol.js +77 -0
  93. package/dist/lib/sandbox/control/server.js +677 -34
  94. package/dist/lib/sandbox/control/state.js +209 -4
  95. package/dist/lib/sandbox/control/task-view.js +183 -0
  96. package/dist/lib/sandbox/engines/authority.js +289 -0
  97. package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
  98. package/dist/lib/sandbox/index.js +5 -0
  99. package/dist/lib/sandbox/recovery.js +21 -1
  100. package/dist/lib/sandbox/workspace-view.js +2 -1
  101. package/dist/lib/sandbox/worktree-safety.js +4 -1
  102. package/dist/lib/server/index.js +8 -0
  103. package/dist/lib/server/protocol.js +38 -1
  104. package/dist/lib/task/activity-log.js +8 -1
  105. package/dist/lib/task/artifact-lifecycle.js +75 -18
  106. package/dist/lib/task/artifact-operations.js +520 -0
  107. package/dist/lib/task/artifact-repair-intent.js +59 -0
  108. package/dist/lib/task/artifact-schema.js +135 -0
  109. package/dist/lib/task/capabilities.js +310 -0
  110. package/dist/lib/task/commands/status.js +32 -0
  111. package/dist/lib/task/commit-operation.js +12 -1
  112. package/dist/lib/task/control-authority.js +12 -5
  113. package/dist/lib/task/create-service.js +111 -12
  114. package/dist/lib/task/create.js +25 -0
  115. package/dist/lib/task/current-contract.js +5 -1
  116. package/dist/lib/task/decision-details.js +1 -1
  117. package/dist/lib/task/events.js +416 -17
  118. package/dist/lib/task/finalization.js +37 -13
  119. package/dist/lib/task/human-override.js +58 -36
  120. package/dist/lib/task/index.js +11 -3
  121. package/dist/lib/task/invalidation-command.js +86 -0
  122. package/dist/lib/task/invalidation.js +260 -0
  123. package/dist/lib/task/ledger-intents.js +37 -0
  124. package/dist/lib/task/local-artifact-finalization.js +299 -0
  125. package/dist/lib/task/orchestration.js +240 -144
  126. package/dist/lib/task/pr-delivery-fact.js +102 -101
  127. package/dist/lib/task/qualification-audit.js +490 -0
  128. package/dist/lib/task/qualification-confirmation.js +109 -0
  129. package/dist/lib/task/qualification-intents.js +148 -0
  130. package/dist/lib/task/review-artifacts.js +22 -23
  131. package/dist/lib/task/review-finalization.js +121 -4
  132. package/dist/lib/task/review-fingerprint.js +24 -2
  133. package/dist/lib/task/rework-intent.js +138 -0
  134. package/dist/lib/task/sections.js +6 -4
  135. package/dist/lib/task/skill-scope.js +23 -0
  136. package/dist/lib/task/task-execution-lock.js +27 -17
  137. package/dist/lib/task/verification-config.js +11 -0
  138. package/dist/lib/task/verification-engine.js +93 -16
  139. package/dist/lib/task/verification.js +3 -3
  140. package/dist/lib/task/workflow-warning-intents.js +1 -1
  141. package/dist/lib/task/write.js +11 -0
  142. package/dist/lib/version.js +11 -1
  143. package/dist/lifecycle-build-manifest.json +3 -3
  144. package/lib/agent-client.ts +9 -0
  145. package/lib/agent-clients/next-steps.ts +6 -1
  146. package/lib/decide.ts +3 -3
  147. package/lib/init.ts +1 -1
  148. package/lib/internal/agent-client.ts +4 -2
  149. package/lib/internal/cli-route-inventory.ts +140 -0
  150. package/lib/internal/codex-lifecycle.ts +8 -6
  151. package/lib/internal/codex-sandbox-controller.ts +7 -2
  152. package/lib/internal/git-workflow.ts +9 -6
  153. package/lib/internal/platform-checks.ts +14 -6
  154. package/lib/internal/platform-comment.ts +20 -12
  155. package/lib/internal/platform-context.ts +5 -3
  156. package/lib/internal/platform-issue.ts +17 -11
  157. package/lib/internal/platform-metadata.ts +70 -0
  158. package/lib/internal/platform-pr-review.ts +23 -12
  159. package/lib/internal/platform-pr.ts +65 -27
  160. package/lib/internal/platform-release-notes.ts +8 -6
  161. package/lib/internal/platform-security.ts +83 -0
  162. package/lib/internal/pr-review-grade.ts +20 -11
  163. package/lib/internal/release-workflow.ts +21 -9
  164. package/lib/internal/sandbox-control.ts +44 -6
  165. package/lib/internal/task-activity.ts +15 -7
  166. package/lib/internal/task-artifact.ts +204 -22
  167. package/lib/internal/task-context.ts +3 -1
  168. package/lib/internal/task-create.ts +78 -17
  169. package/lib/internal/task-delivery.ts +3 -1
  170. package/lib/internal/task-event.ts +9 -4
  171. package/lib/internal/task-finalization.ts +6 -4
  172. package/lib/internal/task-invalidation.ts +41 -0
  173. package/lib/internal/task-ledger.ts +21 -8
  174. package/lib/internal/task-lifecycle.ts +5 -3
  175. package/lib/internal/task-operation-registry.ts +482 -0
  176. package/lib/internal/task-orchestration.ts +12 -0
  177. package/lib/internal/task-override.ts +15 -9
  178. package/lib/internal/task-qualification.ts +61 -0
  179. package/lib/internal/task-review.ts +6 -4
  180. package/lib/internal/task-short-id.ts +10 -1
  181. package/lib/internal/task-snapshot.ts +3 -1
  182. package/lib/internal/task-validate.ts +6 -2
  183. package/lib/internal/task-verify.ts +10 -7
  184. package/lib/internal/task-warning.ts +10 -4
  185. package/lib/platform/adapters.ts +3 -2
  186. package/lib/platform/change-request-git-evidence.ts +36 -9
  187. package/lib/platform/comment-safety.ts +250 -0
  188. package/lib/platform/completion-backfill.ts +9 -8
  189. package/lib/platform/context.ts +97 -134
  190. package/lib/platform/github-client.ts +2 -2
  191. package/lib/platform/github-provider.ts +1132 -0
  192. package/lib/platform/in-label-sync.ts +208 -0
  193. package/lib/platform/issue-comments.ts +255 -80
  194. package/lib/platform/issues.ts +344 -174
  195. package/lib/platform/metadata-labels.ts +5 -2
  196. package/lib/platform/none-provider.ts +35 -0
  197. package/lib/platform/pr-change-report.ts +639 -0
  198. package/lib/platform/pr-checks.ts +126 -106
  199. package/lib/platform/pr-review.ts +88 -85
  200. package/lib/platform/pr-summary.ts +581 -53
  201. package/lib/platform/provider-bridge.ts +82 -0
  202. package/lib/platform/provider-contract.ts +611 -0
  203. package/lib/platform/provider-loader.ts +307 -0
  204. package/lib/platform/provider-validation.ts +611 -0
  205. package/lib/platform/pull-request-metadata.ts +10 -7
  206. package/lib/platform/pull-requests.ts +781 -550
  207. package/lib/platform/release-notes.ts +76 -59
  208. package/lib/platform/releases.ts +77 -43
  209. package/lib/platform/repository-metadata.ts +453 -0
  210. package/lib/platform/resource-identity.ts +121 -0
  211. package/lib/platform/security-alerts.ts +191 -0
  212. package/lib/platform/task-identities.ts +40 -0
  213. package/lib/platform/types.ts +4 -2
  214. package/lib/platform/verification-required.ts +11 -13
  215. package/lib/platform/verification-sync.ts +128 -304
  216. package/lib/pr-review/evidence-grading.ts +25 -8
  217. package/lib/process-data/index.ts +7 -0
  218. package/lib/run/index.ts +62 -22
  219. package/lib/sandbox/commands/control-status.ts +26 -0
  220. package/lib/sandbox/commands/create.ts +46 -6
  221. package/lib/sandbox/commands/ls.ts +7 -0
  222. package/lib/sandbox/commands/rm.ts +1000 -87
  223. package/lib/sandbox/commands/show.ts +16 -0
  224. package/lib/sandbox/control/client.ts +203 -19
  225. package/lib/sandbox/control/completed-reentry.ts +98 -0
  226. package/lib/sandbox/control/container-identity.ts +27 -43
  227. package/lib/sandbox/control/executor.ts +180 -15
  228. package/lib/sandbox/control/lifecycle.ts +629 -17
  229. package/lib/sandbox/control/native-file-lock.ts +209 -0
  230. package/lib/sandbox/control/protocol.ts +118 -2
  231. package/lib/sandbox/control/server.ts +724 -34
  232. package/lib/sandbox/control/state.ts +257 -4
  233. package/lib/sandbox/control/task-view.ts +240 -0
  234. package/lib/sandbox/engines/authority.ts +365 -0
  235. package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
  236. package/lib/sandbox/index.ts +7 -0
  237. package/lib/sandbox/recovery.ts +21 -1
  238. package/lib/sandbox/workspace-view.ts +9 -3
  239. package/lib/sandbox/worktree-safety.ts +4 -1
  240. package/lib/server/index.ts +10 -0
  241. package/lib/server/protocol.ts +36 -1
  242. package/lib/task/activity-log.ts +8 -0
  243. package/lib/task/artifact-lifecycle.ts +70 -22
  244. package/lib/task/artifact-operations.ts +626 -0
  245. package/lib/task/artifact-repair-intent.ts +71 -0
  246. package/lib/task/artifact-schema.ts +192 -0
  247. package/lib/task/capabilities.ts +331 -0
  248. package/lib/task/commands/status.ts +38 -0
  249. package/lib/task/commit-operation.ts +12 -1
  250. package/lib/task/control-authority.ts +22 -9
  251. package/lib/task/create-service.ts +139 -14
  252. package/lib/task/create.ts +27 -0
  253. package/lib/task/current-contract.ts +6 -1
  254. package/lib/task/decision-details.ts +6 -2
  255. package/lib/task/events.ts +392 -16
  256. package/lib/task/finalization.ts +50 -14
  257. package/lib/task/human-override.ts +70 -46
  258. package/lib/task/index.ts +16 -3
  259. package/lib/task/invalidation-command.ts +86 -0
  260. package/lib/task/invalidation.ts +332 -0
  261. package/lib/task/ledger-intents.ts +35 -1
  262. package/lib/task/local-artifact-finalization.ts +432 -0
  263. package/lib/task/orchestration.ts +223 -133
  264. package/lib/task/pr-delivery-fact.ts +131 -148
  265. package/lib/task/qualification-audit.ts +599 -0
  266. package/lib/task/qualification-confirmation.ts +117 -0
  267. package/lib/task/qualification-intents.ts +150 -0
  268. package/lib/task/review-artifacts.ts +21 -22
  269. package/lib/task/review-finalization.ts +133 -4
  270. package/lib/task/review-fingerprint.ts +23 -2
  271. package/lib/task/rework-intent.ts +165 -0
  272. package/lib/task/sections.ts +6 -4
  273. package/lib/task/skill-scope.ts +24 -0
  274. package/lib/task/task-execution-lock.ts +23 -14
  275. package/lib/task/verification-config.ts +12 -0
  276. package/lib/task/verification-engine.ts +103 -17
  277. package/lib/task/verification.ts +4 -4
  278. package/lib/task/workflow-warning-intents.ts +1 -1
  279. package/lib/task/write.ts +19 -0
  280. package/lib/update.ts +1 -1
  281. package/lib/version.ts +15 -1
  282. package/package.json +12 -1
  283. package/templates/.agents/rules/README.en.md +3 -1
  284. package/templates/.agents/rules/README.zh-CN.md +3 -1
  285. package/templates/.agents/rules/decision-qualification.en.md +22 -0
  286. package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
  287. package/templates/.agents/rules/evidence-reporting.en.md +28 -0
  288. package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
  289. package/templates/.agents/rules/issue-pr-commands.en.md +1 -1
  290. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
  291. package/templates/.agents/rules/issue-sync.en.md +2 -0
  292. package/templates/.agents/rules/issue-sync.zh-CN.md +2 -0
  293. package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
  294. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
  295. package/templates/.agents/rules/local-artifact-repair.en.md +13 -2
  296. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +13 -2
  297. package/templates/.agents/rules/pr-sync.en.md +10 -4
  298. package/templates/.agents/rules/pr-sync.zh-CN.md +17 -4
  299. package/templates/.agents/rules/security-alerts.en.md +8 -8
  300. package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
  301. package/templates/.agents/rules/task-short-id.en.md +1 -4
  302. package/templates/.agents/rules/task-short-id.zh-CN.md +1 -3
  303. package/templates/.agents/skills/analyze-task/SKILL.en.md +28 -5
  304. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +29 -5
  305. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
  306. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
  307. package/templates/.agents/skills/check-task/SKILL.en.md +16 -37
  308. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -37
  309. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  310. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  311. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  312. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  313. package/templates/.agents/skills/code-task/SKILL.en.md +41 -9
  314. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +43 -11
  315. package/templates/.agents/skills/code-task/config/verify.en.json +6 -14
  316. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +6 -14
  317. package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
  318. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
  319. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
  320. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
  321. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
  322. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
  323. package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
  324. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
  325. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +2 -0
  326. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +2 -0
  327. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +3 -3
  328. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +3 -3
  329. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +10 -4
  330. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +10 -4
  331. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
  332. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
  333. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +4 -3
  334. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +4 -3
  335. package/templates/.agents/skills/complete-task/SKILL.en.md +26 -21
  336. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +25 -21
  337. package/templates/.agents/skills/create-pr/SKILL.en.md +7 -6
  338. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +7 -7
  339. package/templates/.agents/skills/create-pr/config/verify.json +1 -0
  340. package/templates/.agents/skills/create-pr/reference/change-report.en.md +16 -4
  341. package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +16 -4
  342. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +5 -3
  343. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +5 -3
  344. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
  345. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
  346. package/templates/.agents/skills/create-pr/scripts/change-report.mjs +3 -0
  347. package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
  348. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
  349. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  350. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  351. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  352. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  353. package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
  354. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
  355. package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
  356. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
  357. package/templates/.agents/skills/plan-task/SKILL.en.md +27 -4
  358. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +26 -4
  359. package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
  360. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
  361. package/templates/.agents/skills/review-analysis/SKILL.en.md +17 -4
  362. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +17 -4
  363. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
  364. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
  365. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
  366. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
  367. package/templates/.agents/skills/review-code/SKILL.en.md +18 -5
  368. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +18 -5
  369. package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
  370. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
  371. package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
  372. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
  373. package/templates/.agents/skills/review-plan/SKILL.en.md +17 -4
  374. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +17 -4
  375. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
  376. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
  377. package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
  378. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
  379. package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
  380. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
  381. package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
  382. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
  383. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +9 -3
  384. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +9 -3
  385. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +3 -1
  386. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +3 -1
  387. package/templates/.agents/skills/test/SKILL.en.md +13 -2
  388. package/templates/.agents/skills/test/SKILL.zh-CN.md +13 -2
  389. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
  390. package/templates/.agents/skills/watch-pr/SKILL.en.md +2 -2
  391. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +2 -2
  392. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +6 -0
  393. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +6 -0
  394. package/templates/.agents/templates/task.en.md +24 -1
  395. package/templates/.agents/templates/task.zh-CN.md +24 -1
  396. package/templates/.github/workflows/pr-label.yml +7 -26
  397. package/templates/.agents/scripts/security-alerts.github.sh +0 -151
  398. package/templates/.agents/scripts/security-alerts.sh +0 -31
  399. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
  400. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
  401. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
  402. package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
@@ -0,0 +1,453 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+
5
+ import type { PlatformClient, LoadedContext } from './context.ts';
6
+ import { resolvePlatformProviderContext } from './context.ts';
7
+ import {
8
+ providerError,
9
+ providerOperationContext,
10
+ providerStatus
11
+ } from './provider-bridge.ts';
12
+ import type {
13
+ LabelDefinition,
14
+ LabelReconciliation,
15
+ MilestoneDefinition,
16
+ MilestoneInitialization,
17
+ PlatformError,
18
+ ProviderResult
19
+ } from './provider-contract.ts';
20
+ import { platformResult } from './types.ts';
21
+ import type { PlatformResult } from './types.ts';
22
+
23
+ type RepositoryMetadataOptions = {
24
+ cwd?: string;
25
+ client?: PlatformClient;
26
+ platformType?: string;
27
+ };
28
+
29
+ type MilestoneBaseline = {
30
+ version: string;
31
+ source: string;
32
+ };
33
+
34
+ type MilestonePlan = {
35
+ baseline: MilestoneBaseline;
36
+ history: boolean;
37
+ desired: MilestoneDefinition[];
38
+ };
39
+
40
+ type LabelsResult = PlatformResult & {
41
+ operation: 'init-labels';
42
+ labels: {
43
+ commonCount: number;
44
+ inCount: number;
45
+ created: string[];
46
+ updated: string[];
47
+ removed: string[];
48
+ skipped: string[];
49
+ };
50
+ };
51
+
52
+ type MilestonesResult = PlatformResult & {
53
+ operation: 'init-milestones';
54
+ milestones: {
55
+ baseline: MilestoneBaseline | null;
56
+ history: boolean;
57
+ desired: string[];
58
+ created: string[];
59
+ skipped: string[];
60
+ };
61
+ };
62
+
63
+ const COMMON_LABELS: readonly LabelDefinition[] = [
64
+ { name: 'type: bug', color: 'DED6F9', description: 'A general bug' },
65
+ { name: 'type: enhancement', color: 'DED6F9', description: 'A general enhancement' },
66
+ { name: 'type: feature', color: 'DED6F9', description: 'A general feature' },
67
+ { name: 'type: documentation', color: 'DED6F9', description: 'A documentation task' },
68
+ { name: 'type: dependency-upgrade', color: 'DED6F9', description: 'A dependency upgrade' },
69
+ { name: 'type: task', color: 'DED6F9', description: 'A general task' },
70
+ { name: 'status: waiting-for-triage', color: 'FCF1C4', description: "An issue we've not yet triaged or decided on" },
71
+ { name: 'status: waiting-for-feedback', color: 'FCF1C4', description: 'We need additional information before we can continue' },
72
+ { name: 'status: feedback-provided', color: 'FCF1C4', description: 'Feedback has been provided' },
73
+ { name: 'status: feedback-reminder', color: 'FCF1C4', description: "We've sent a reminder that we need additional information before we can continue" },
74
+ { name: 'status: pending-design-work', color: 'FCF1C4', description: 'Needs design work before any code can be developed' },
75
+ { name: 'status: in-progress', color: 'FCF1C4', description: 'Work is actively being developed' },
76
+ { name: 'status: on-hold', color: 'FCF1C4', description: "We can't start working on this issue yet" },
77
+ { name: 'status: blocked', color: 'FCF1C4', description: "An issue that's blocked on an external project change" },
78
+ { name: 'status: declined', color: 'FCF1C4', description: "A suggestion or change that we don't feel we should currently apply" },
79
+ { name: 'status: duplicate', color: 'FCF1C4', description: 'A duplicate of another issue' },
80
+ { name: 'status: invalid', color: 'FCF1C4', description: "An issue that we don't feel is valid" },
81
+ { name: 'status: superseded', color: 'FCF1C4', description: 'An issue that has been superseded by another' },
82
+ { name: 'status: bulk-closed', color: 'FCF1C4', description: "An outdated, unresolved issue that's closed in bulk as part of a cleaning process" },
83
+ { name: 'status: ideal-for-contribution', color: 'FCF1C4', description: 'An issue that a contributor can help us with' },
84
+ { name: 'status: backported', color: 'FCF1C4', description: 'An issue that has been backported to maintenance branches' },
85
+ { name: 'status: waiting-for-internal-feedback', color: 'FCF1C4', description: 'An issue that needs input from a member or another team' },
86
+ { name: 'good first issue', color: 'F9D9E6', description: 'Good for newcomers' },
87
+ { name: 'help wanted', color: '008672', description: 'Extra attention is needed' },
88
+ { name: 'dependencies', color: '0366D6', description: 'Pull requests that update a dependency file' }
89
+ ];
90
+
91
+ type ParsedVersion = {
92
+ tag: string;
93
+ major: string;
94
+ minor: string;
95
+ patch: string;
96
+ prerelease: string;
97
+ };
98
+
99
+ function validIdentifiers(value: string, prerelease: boolean): boolean {
100
+ if (!value) return false;
101
+ return value.split('.').every((identifier) =>
102
+ /^[0-9A-Za-z-]+$/.test(identifier)
103
+ && (!prerelease || !/^\d+$/.test(identifier) || /^(0|[1-9]\d*)$/.test(identifier))
104
+ );
105
+ }
106
+
107
+ function parseVersionTag(tag: string): ParsedVersion | null {
108
+ if (!tag.startsWith('v')) return null;
109
+ let version = tag.slice(1);
110
+ const plusAt = version.indexOf('+');
111
+ if (plusAt >= 0) {
112
+ const build = version.slice(plusAt + 1);
113
+ if (!validIdentifiers(build, false)) return null;
114
+ version = version.slice(0, plusAt);
115
+ }
116
+
117
+ let prerelease = '';
118
+ const dashAt = version.indexOf('-');
119
+ if (dashAt >= 0) {
120
+ prerelease = version.slice(dashAt + 1);
121
+ if (!validIdentifiers(prerelease, true)) return null;
122
+ version = version.slice(0, dashAt);
123
+ }
124
+
125
+ const core = version.split('.');
126
+ if (core.length !== 3 || !core.every((part) => /^(0|[1-9]\d*)$/.test(part))) return null;
127
+ return { tag, major: core[0]!, minor: core[1]!, patch: core[2]!, prerelease };
128
+ }
129
+
130
+ function compareDecimal(left: string, right: string): number {
131
+ if (left.length !== right.length) return left.length > right.length ? 1 : -1;
132
+ if (left === right) return 0;
133
+ return left > right ? 1 : -1;
134
+ }
135
+
136
+ function compareAscii(left: string, right: string): number {
137
+ const alphabet = '+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
138
+ const limit = Math.min(left.length, right.length);
139
+ for (let index = 0; index < limit; index += 1) {
140
+ const leftRank = alphabet.indexOf(left[index]!);
141
+ const rightRank = alphabet.indexOf(right[index]!);
142
+ if (leftRank !== rightRank) return leftRank > rightRank ? 1 : -1;
143
+ }
144
+ if (left.length === right.length) return 0;
145
+ return left.length > right.length ? 1 : -1;
146
+ }
147
+
148
+ function comparePrerelease(left: string, right: string): number {
149
+ if (!left || !right) {
150
+ if (left === right) return 0;
151
+ return left ? -1 : 1;
152
+ }
153
+ const leftIds = left.split('.');
154
+ const rightIds = right.split('.');
155
+ const limit = Math.min(leftIds.length, rightIds.length);
156
+ for (let index = 0; index < limit; index += 1) {
157
+ const leftId = leftIds[index]!;
158
+ const rightId = rightIds[index]!;
159
+ const leftNumeric = /^\d+$/.test(leftId);
160
+ const rightNumeric = /^\d+$/.test(rightId);
161
+ const comparison = leftNumeric && rightNumeric
162
+ ? compareDecimal(leftId, rightId)
163
+ : leftNumeric !== rightNumeric
164
+ ? leftNumeric ? -1 : 1
165
+ : compareAscii(leftId, rightId);
166
+ if (comparison !== 0) return comparison;
167
+ }
168
+ if (leftIds.length === rightIds.length) return 0;
169
+ return leftIds.length > rightIds.length ? 1 : -1;
170
+ }
171
+
172
+ function compareVersions(left: ParsedVersion, right: ParsedVersion): number {
173
+ for (const [leftPart, rightPart] of [
174
+ [left.major, right.major],
175
+ [left.minor, right.minor],
176
+ [left.patch, right.patch]
177
+ ] as const) {
178
+ const comparison = compareDecimal(leftPart, rightPart);
179
+ if (comparison !== 0) return comparison;
180
+ }
181
+ const prerelease = comparePrerelease(left.prerelease, right.prerelease);
182
+ return prerelease !== 0 ? prerelease : compareAscii(left.tag, right.tag);
183
+ }
184
+
185
+ function incrementDecimal(value: string): string {
186
+ const digits = value.split('');
187
+ let carry = 1;
188
+ for (let index = digits.length - 1; index >= 0 && carry; index -= 1) {
189
+ const next = Number(digits[index]!) + carry;
190
+ digits[index] = String(next % 10);
191
+ carry = next === 10 ? 1 : 0;
192
+ }
193
+ return carry ? `1${digits.join('')}` : digits.join('');
194
+ }
195
+
196
+ function buildMilestonePlan(tags: readonly string[], history: boolean): MilestonePlan {
197
+ const parsed = tags.flatMap((tag) => {
198
+ const version = parseVersionTag(tag);
199
+ return version ? [version] : [];
200
+ });
201
+ const selected = parsed.reduce<ParsedVersion | null>((best, candidate) =>
202
+ !best || compareVersions(candidate, best) > 0 ? candidate : best, null);
203
+ const baseline: MilestoneBaseline = selected
204
+ ? { version: `${selected.major}.${selected.minor}.${selected.patch}`, source: `git tag ${selected.tag}` }
205
+ : { version: '0.1.0', source: 'compatibility default' };
206
+ const [major, minor, patch] = baseline.version.split('.');
207
+ const desired: MilestoneDefinition[] = [];
208
+ const titles = new Set<string>();
209
+ const add = (title: string, description: string, state: 'open' | 'closed') => {
210
+ if (titles.has(title)) return;
211
+ titles.add(title);
212
+ desired.push({ title, description, state });
213
+ };
214
+
215
+ const line = `${major}.${minor}.x`;
216
+ const version = selected
217
+ ? `${major}.${minor}.${incrementDecimal(patch!)}`
218
+ : baseline.version;
219
+ add('General Backlog', 'All unsorted backlogged tasks may be completed in a future version.', 'open');
220
+ add(line, `Issues that we want to resolve in ${major}.${minor} line.`, 'open');
221
+ add(version, `Issues that we want to release in v${version}.`, 'open');
222
+ if (patch === '0') {
223
+ const nextMinor = `${major}.${incrementDecimal(minor!)}.0`;
224
+ const nextLine = `${major}.${incrementDecimal(minor!)}.x`;
225
+ add(nextMinor, `Issues that we want to release in v${nextMinor}.`, 'open');
226
+ add(nextLine, `Issues that we want to resolve in ${major}.${incrementDecimal(minor!)} line.`, 'open');
227
+ }
228
+
229
+ if (history) {
230
+ for (const historical of parsed) {
231
+ const historicalVersion = `${historical.major}.${historical.minor}.${historical.patch}`;
232
+ add(`${historical.major}.${historical.minor}.x`, `Issues that we want to resolve in ${historical.major}.${historical.minor} line.`, 'open');
233
+ add(historicalVersion, `Issues that we want to release in v${historicalVersion}.`, 'closed');
234
+ }
235
+ }
236
+ return { baseline, history, desired };
237
+ }
238
+
239
+ function buildLabelDefinitions(config: unknown): LabelDefinition[] {
240
+ const labels = config && typeof config === 'object' && !Array.isArray(config)
241
+ ? (config as Record<string, unknown>).labels
242
+ : undefined;
243
+ const mapping = labels && typeof labels === 'object' && !Array.isArray(labels)
244
+ ? (labels as Record<string, unknown>).in
245
+ : undefined;
246
+ if (mapping === undefined) return [...COMMON_LABELS];
247
+ if (!mapping || typeof mapping !== 'object' || Array.isArray(mapping)) throw new Error('labels.in must be an object');
248
+ const dynamic = Object.keys(mapping).sort().map((key) => {
249
+ if (!key || /[\r\n\t]/.test(key)) throw new Error('labels.in keys must be non-empty single-line values');
250
+ return { name: `in: ${key}`, color: 'BFD4F2', description: `Module label for ${key}` };
251
+ });
252
+ return [...COMMON_LABELS, ...dynamic];
253
+ }
254
+
255
+ function configAt(root: string): unknown {
256
+ try {
257
+ return JSON.parse(fs.readFileSync(path.join(root, '.agents', '.airc.json'), 'utf8')) as unknown;
258
+ } catch {
259
+ return {};
260
+ }
261
+ }
262
+
263
+ function baseResult<T extends PlatformResult>(
264
+ status: PlatformResult['status'],
265
+ context: PlatformResult,
266
+ extra: Partial<T> = {}
267
+ ): T {
268
+ return {
269
+ ...platformResult(status, {
270
+ platform: context.platform,
271
+ capabilities: context.capabilities,
272
+ operations: context.operations,
273
+ error: context.error
274
+ }),
275
+ ...extra
276
+ } as T;
277
+ }
278
+
279
+ function unsupported(providerType: string, operation: string): PlatformError {
280
+ return {
281
+ code: 'PLATFORM_CAPABILITY_UNSUPPORTED',
282
+ message: `Platform '${providerType}' does not provide ${operation}`,
283
+ retryable: false
284
+ };
285
+ }
286
+
287
+ function operationStatus(changed: boolean): 'applied' | 'no-op' {
288
+ return changed ? 'applied' : 'no-op';
289
+ }
290
+
291
+ function errorStatus(error: PlatformError): PlatformResult['status'] {
292
+ return error.code === 'PLATFORM_CAPABILITY_UNSUPPORTED' ? 'degraded' : providerStatus(error);
293
+ }
294
+
295
+ function initialLabelsResult(context: PlatformResult, labels: LabelDefinition[]): LabelsResult {
296
+ return baseResult<LabelsResult>('degraded', context, {
297
+ operation: 'init-labels',
298
+ labels: {
299
+ commonCount: COMMON_LABELS.length,
300
+ inCount: labels.filter((item) => item.name.startsWith('in:')).length,
301
+ created: [], updated: [], removed: [], skipped: []
302
+ },
303
+ error: context.error || { code: 'PLATFORM_CAPABILITY_UNSUPPORTED', message: 'Label initialization is unavailable', retryable: false }
304
+ });
305
+ }
306
+
307
+ function initialMilestonesResult(context: PlatformResult, history: boolean): MilestonesResult {
308
+ return baseResult<MilestonesResult>('degraded', context, {
309
+ operation: 'init-milestones',
310
+ milestones: { baseline: null, history, desired: [], created: [], skipped: [] },
311
+ error: context.error || { code: 'PLATFORM_CAPABILITY_UNSUPPORTED', message: 'Milestone initialization is unavailable', retryable: false }
312
+ });
313
+ }
314
+
315
+ function labelsFromReconciliation(initial: LabelsResult, value: LabelReconciliation | undefined): LabelsResult['labels'] {
316
+ if (!value) return initial.labels;
317
+ return {
318
+ ...initial.labels,
319
+ created: value.created,
320
+ updated: value.updated,
321
+ removed: value.removed,
322
+ skipped: value.skipped
323
+ };
324
+ }
325
+
326
+ function milestonesFromInitialization(initial: MilestonesResult, value: MilestoneInitialization | undefined): MilestonesResult['milestones'] {
327
+ if (!value) return initial.milestones;
328
+ return {
329
+ ...initial.milestones,
330
+ created: value.created,
331
+ skipped: value.skipped
332
+ };
333
+ }
334
+
335
+ function usableContext(loaded: { ok: true; value: LoadedContext } | { ok: false; context: PlatformResult }): loaded is { ok: true; value: LoadedContext } {
336
+ return loaded.ok && Boolean(loaded.value.context.platform.repository);
337
+ }
338
+
339
+ async function initializeLabels(
340
+ input: { cleanupStaleIn?: boolean } = {},
341
+ options: RepositoryMetadataOptions = {}
342
+ ): Promise<LabelsResult> {
343
+ const loaded = await resolvePlatformProviderContext({ cwd: options.cwd, client: options.client, platformType: options.platformType });
344
+ const context = loaded.ok ? loaded.value.context : loaded.context;
345
+ let definitions: LabelDefinition[];
346
+ try {
347
+ definitions = buildLabelDefinitions(loaded.ok ? configAt(loaded.value.repositoryRoot) : {});
348
+ } catch (error) {
349
+ return {
350
+ ...initialLabelsResult(context, []),
351
+ status: 'failed',
352
+ error: { code: 'LABEL_CONFIG_INVALID', message: error instanceof Error ? error.message : String(error), retryable: false }
353
+ };
354
+ }
355
+ const initial = initialLabelsResult(context, definitions);
356
+ if (!usableContext(loaded)) return { ...initial, error: initial.error || context.error };
357
+ const operation = loaded.value.provider.repositoryMetadata?.reconcileLabels;
358
+ if (!operation) return { ...initial, error: unsupported(loaded.value.provider.type, 'repositoryMetadata.reconcileLabels') };
359
+ const reconciled: ProviderResult<LabelReconciliation> = await operation({
360
+ context: providerOperationContext(loaded.value),
361
+ desired: definitions,
362
+ cleanupStaleIn: input.cleanupStaleIn === true,
363
+ mutation: { idempotencyKey: 'labels:init' }
364
+ });
365
+ if (!reconciled.ok) return {
366
+ ...initial,
367
+ status: errorStatus(reconciled.error),
368
+ changed: reconciled.value?.changed || false,
369
+ operations: [{ name: 'reconcile-labels', status: 'failed', reasonCode: reconciled.error.code }],
370
+ labels: labelsFromReconciliation(initial, reconciled.value),
371
+ error: providerError(reconciled.error, 'LABEL_INITIALIZATION_FAILED')
372
+ };
373
+ return {
374
+ ...initial,
375
+ status: operationStatus(reconciled.value.changed),
376
+ changed: reconciled.value.changed,
377
+ operations: [{ name: 'reconcile-labels', status: operationStatus(reconciled.value.changed), reasonCode: null }],
378
+ labels: {
379
+ commonCount: COMMON_LABELS.length,
380
+ inCount: definitions.length - COMMON_LABELS.length,
381
+ created: reconciled.value.created,
382
+ updated: reconciled.value.updated,
383
+ removed: reconciled.value.removed,
384
+ skipped: reconciled.value.skipped
385
+ },
386
+ error: null
387
+ };
388
+ }
389
+
390
+ function gitTags(cwd: string): string[] {
391
+ const output = execFileSync('git', ['tag', '--list', 'v*'], { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim();
392
+ return output ? output.split(/\r?\n/).filter(Boolean) : [];
393
+ }
394
+
395
+ async function initializeMilestones(
396
+ input: { history?: boolean } = {},
397
+ options: RepositoryMetadataOptions = {}
398
+ ): Promise<MilestonesResult> {
399
+ const history = input.history === true;
400
+ const loaded = await resolvePlatformProviderContext({ cwd: options.cwd, client: options.client, platformType: options.platformType });
401
+ const context = loaded.ok ? loaded.value.context : loaded.context;
402
+ const initial = initialMilestonesResult(context, history);
403
+ if (!usableContext(loaded)) return initial;
404
+ let plan: MilestonePlan;
405
+ try {
406
+ plan = buildMilestonePlan(gitTags(loaded.value.workingDirectory), history);
407
+ } catch (error) {
408
+ return {
409
+ ...initial,
410
+ status: 'failed',
411
+ error: { code: 'MILESTONE_TAG_DISCOVERY_FAILED', message: error instanceof Error ? error.message : String(error), retryable: false }
412
+ };
413
+ }
414
+ const operation = loaded.value.provider.repositoryMetadata?.reconcileMilestones;
415
+ if (!operation) return {
416
+ ...initial,
417
+ milestones: { ...initial.milestones, baseline: plan.baseline, history, desired: plan.desired.map((item) => item.title) },
418
+ error: unsupported(loaded.value.provider.type, 'repositoryMetadata.reconcileMilestones')
419
+ };
420
+ const reconciled = await operation({
421
+ context: providerOperationContext(loaded.value),
422
+ desired: plan.desired,
423
+ mutation: { idempotencyKey: `milestones:init:${plan.baseline.version}:${history}` }
424
+ });
425
+ if (!reconciled.ok) return {
426
+ ...initial,
427
+ status: errorStatus(reconciled.error),
428
+ changed: reconciled.value?.changed || false,
429
+ operations: [{ name: 'reconcile-milestones', status: 'failed', reasonCode: reconciled.error.code }],
430
+ milestones: milestonesFromInitialization({
431
+ ...initial,
432
+ milestones: { ...initial.milestones, baseline: plan.baseline, history, desired: plan.desired.map((item) => item.title) }
433
+ }, reconciled.value),
434
+ error: providerError(reconciled.error, 'MILESTONE_INITIALIZATION_FAILED')
435
+ };
436
+ return {
437
+ ...initial,
438
+ status: operationStatus(reconciled.value.changed),
439
+ changed: reconciled.value.changed,
440
+ operations: [{ name: 'reconcile-milestones', status: operationStatus(reconciled.value.changed), reasonCode: null }],
441
+ milestones: {
442
+ baseline: plan.baseline,
443
+ history,
444
+ desired: plan.desired.map((item) => item.title),
445
+ created: reconciled.value.created,
446
+ skipped: reconciled.value.skipped
447
+ },
448
+ error: null
449
+ };
450
+ }
451
+
452
+ export { buildLabelDefinitions, buildMilestonePlan, initializeLabels, initializeMilestones };
453
+ export type { LabelsResult, MilestoneBaseline, MilestonePlan, MilestonesResult, RepositoryMetadataOptions };
@@ -0,0 +1,121 @@
1
+ type ResourceIdentityKind = 'id' | 'number' | 'key';
2
+ type ResourceIdentity =
3
+ | { kind: 'id'; value: string }
4
+ | { kind: 'number'; value: number }
5
+ | { kind: 'key'; value: string };
6
+ type CanonicalResourceIdentity = ResourceIdentity;
7
+
8
+ type PlatformResourceKind = 'issue' | 'pull-request' | 'comment' | 'release';
9
+ type ProviderIdentityDeclaration = Partial<Record<PlatformResourceKind, ResourceIdentityKind>>;
10
+
11
+ function identityError(message: string): Error & { code: string } {
12
+ return Object.assign(new Error(`PLATFORM_IDENTITY_INVALID: ${message}`), {
13
+ code: 'PLATFORM_IDENTITY_INVALID'
14
+ });
15
+ }
16
+
17
+ function isResourceIdentity(value: unknown): value is CanonicalResourceIdentity {
18
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
19
+ const candidate = value as Record<string, unknown>;
20
+ if (Object.keys(candidate).length !== 2 || typeof candidate.kind !== 'string') return false;
21
+ if (candidate.kind === 'number') {
22
+ return Number.isSafeInteger(candidate.value) && (candidate.value as number) > 0;
23
+ }
24
+ return (candidate.kind === 'id' || candidate.kind === 'key')
25
+ && typeof candidate.value === 'string'
26
+ && candidate.value.length > 0
27
+ && candidate.value.trim() === candidate.value;
28
+ }
29
+
30
+ function parseResourceIdentity(value: unknown, label = 'identity'): CanonicalResourceIdentity {
31
+ if (!isResourceIdentity(value)) throw identityError(`${label} must contain exactly one valid kind/value pair`);
32
+ if (value.kind === 'number') return { kind: 'number', value: value.value };
33
+ if (value.kind === 'id') return { kind: 'id', value: value.value };
34
+ return { kind: 'key', value: value.value };
35
+ }
36
+
37
+ function serializeResourceIdentity(identity: ResourceIdentity): string {
38
+ return JSON.stringify(parseResourceIdentity(identity));
39
+ }
40
+
41
+ function resourceIdentityEquals(left: unknown, right: unknown): boolean {
42
+ return isResourceIdentity(left) && isResourceIdentity(right)
43
+ && left.kind === right.kind && left.value === right.value;
44
+ }
45
+
46
+ function primaryIdentityKind(
47
+ declaration: ProviderIdentityDeclaration | undefined,
48
+ resourceKind: PlatformResourceKind
49
+ ): ResourceIdentityKind {
50
+ const kind = declaration?.[resourceKind];
51
+ if (kind !== 'id' && kind !== 'number' && kind !== 'key') {
52
+ throw identityError(`provider does not declare a primary identity for ${resourceKind}`);
53
+ }
54
+ return kind;
55
+ }
56
+
57
+ function parseResourceToken(
58
+ token: string,
59
+ resourceKind: PlatformResourceKind,
60
+ declaration: ProviderIdentityDeclaration | undefined
61
+ ): ResourceIdentity {
62
+ if (typeof token !== 'string' || token.length === 0) throw identityError('resource token must be a non-empty string');
63
+ const kind = primaryIdentityKind(declaration, resourceKind);
64
+ if (kind === 'number') {
65
+ if (!/^[1-9]\d*$/u.test(token)) throw identityError(`${resourceKind} token must be a positive safe integer`);
66
+ const value = Number(token);
67
+ if (!Number.isSafeInteger(value) || value <= 0) throw identityError(`${resourceKind} token must be a positive safe integer`);
68
+ return { kind, value };
69
+ }
70
+ const value = token.trim();
71
+ if (!value) throw identityError(`${resourceKind} token must not be empty`);
72
+ return { kind, value };
73
+ }
74
+
75
+ function identityFromRemoteValue(
76
+ value: unknown,
77
+ resourceKind: PlatformResourceKind,
78
+ declaration: ProviderIdentityDeclaration | undefined
79
+ ): ResourceIdentity {
80
+ const kind = primaryIdentityKind(declaration, resourceKind);
81
+ if (isResourceIdentity(value)) {
82
+ if (value.kind !== kind) throw identityError(`${resourceKind} response identity kind does not match provider declaration`);
83
+ return value;
84
+ }
85
+ if (kind === 'number') {
86
+ if (typeof value === 'number' && Number.isSafeInteger(value) && value > 0) return { kind, value };
87
+ if (typeof value === 'string' && /^[1-9]\d*$/u.test(value)) return parseResourceToken(value, resourceKind, declaration);
88
+ throw identityError(`${resourceKind} response does not contain a valid number identity`);
89
+ }
90
+ if (typeof value !== 'string' || !value.trim()) throw identityError(`${resourceKind} response does not contain a valid string identity`);
91
+ return { kind, value: value.trim() };
92
+ }
93
+
94
+ function resourceIdentityNumber(identity: ResourceIdentity | null | undefined): number | null {
95
+ return identity?.kind === 'number' ? identity.value : null;
96
+ }
97
+
98
+ function resourceIdentityString(identity: ResourceIdentity | null | undefined): string | null {
99
+ return identity && (identity.kind === 'id' || identity.kind === 'key') ? identity.value : null;
100
+ }
101
+
102
+ function reviewMarker(identity: ResourceIdentity): string {
103
+ const parsed = parseResourceIdentity(identity);
104
+ if (parsed.kind === 'number') return `pr${parsed.value}`;
105
+ const encoded = Buffer.from(serializeResourceIdentity(parsed), 'utf8').toString('base64url');
106
+ return `pr:${encoded}`;
107
+ }
108
+
109
+ export {
110
+ identityFromRemoteValue,
111
+ isResourceIdentity,
112
+ parseResourceIdentity,
113
+ parseResourceToken,
114
+ primaryIdentityKind,
115
+ resourceIdentityEquals,
116
+ resourceIdentityNumber,
117
+ resourceIdentityString,
118
+ reviewMarker,
119
+ serializeResourceIdentity
120
+ };
121
+ export type { CanonicalResourceIdentity, PlatformResourceKind, ProviderIdentityDeclaration, ResourceIdentity, ResourceIdentityKind };