@fitlab-ai/agent-infra 0.9.13 → 0.9.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (428) hide show
  1. package/README.md +10 -0
  2. package/README.zh-CN.md +10 -0
  3. package/bin/cli.ts +26 -9
  4. package/bin/internal-cli.sh +45 -0
  5. package/dist/bin/cli.js +173 -157
  6. package/dist/bin/internal-cli.js +126 -42
  7. package/dist/lib/agent-client.js +5 -0
  8. package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +165 -27
  9. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +3 -2
  10. package/dist/lib/defaults.json +103 -103
  11. package/dist/lib/fs/durable-write.js +37 -0
  12. package/dist/lib/fs/file-lock.js +111 -0
  13. package/dist/lib/host-control/audit.js +19 -0
  14. package/dist/lib/host-control/client.js +142 -0
  15. package/dist/lib/host-control/command.js +49 -0
  16. package/dist/lib/host-control/path.js +160 -0
  17. package/dist/lib/host-control/secure-fs.js +140 -0
  18. package/dist/lib/host-control/server.js +159 -0
  19. package/dist/lib/host-control/service.js +112 -0
  20. package/dist/lib/init.js +11 -2
  21. package/dist/lib/internal/agent-client.js +5 -2
  22. package/dist/lib/internal/cli-route-inventory.js +154 -0
  23. package/dist/lib/internal/codex-lifecycle.js +15 -12
  24. package/dist/lib/internal/codex-sandbox-controller.js +8 -2
  25. package/dist/lib/internal/demo-promotion.js +322 -0
  26. package/dist/lib/internal/demo-transcript.js +454 -0
  27. package/dist/lib/internal/git-workflow.js +10 -6
  28. package/dist/lib/internal/host-control.js +28 -0
  29. package/dist/lib/internal/manual-validation.js +322 -0
  30. package/dist/lib/internal/platform-checks.js +16 -4
  31. package/dist/lib/internal/platform-comment.js +16 -4
  32. package/dist/lib/internal/platform-context.js +4 -1
  33. package/dist/lib/internal/platform-issue.js +12 -4
  34. package/dist/lib/internal/platform-metadata.js +88 -0
  35. package/dist/lib/internal/platform-pr-review.js +16 -3
  36. package/dist/lib/internal/platform-pr.js +42 -14
  37. package/dist/lib/internal/platform-release-notes.js +6 -3
  38. package/dist/lib/internal/platform-security.js +93 -0
  39. package/dist/lib/internal/pr-review-grade.js +14 -3
  40. package/dist/lib/internal/release-workflow.js +82 -89
  41. package/dist/lib/internal/sandbox-control.js +171 -7
  42. package/dist/lib/internal/task-activity.js +13 -4
  43. package/dist/lib/internal/task-artifact.js +19 -107
  44. package/dist/lib/internal/task-context.js +4 -1
  45. package/dist/lib/internal/task-create.js +48 -14
  46. package/dist/lib/internal/task-delivery.js +4 -1
  47. package/dist/lib/internal/task-event.js +38 -35
  48. package/dist/lib/internal/task-finalization.js +4 -1
  49. package/dist/lib/internal/task-invalidation.js +4 -1
  50. package/dist/lib/internal/task-ledger.js +12 -1
  51. package/dist/lib/internal/task-lifecycle.js +4 -1
  52. package/dist/lib/internal/task-operation-registry.js +519 -0
  53. package/dist/lib/internal/task-orchestration.js +12 -0
  54. package/dist/lib/internal/task-override.js +10 -3
  55. package/dist/lib/internal/task-qualification.js +90 -0
  56. package/dist/lib/internal/task-review.js +10 -52
  57. package/dist/lib/internal/task-short-id.js +11 -1
  58. package/dist/lib/internal/task-snapshot.js +4 -1
  59. package/dist/lib/internal/task-validate.js +37 -12
  60. package/dist/lib/internal/task-verify.js +5 -1
  61. package/dist/lib/internal/task-warning.js +8 -1
  62. package/dist/lib/owned-path.js +33 -0
  63. package/dist/lib/platform/check-status.js +11 -0
  64. package/dist/lib/platform/comment-safety.js +229 -0
  65. package/dist/lib/platform/completion-backfill.js +1 -1
  66. package/dist/lib/platform/github-data.js +241 -0
  67. package/dist/lib/platform/github-provider.js +248 -26
  68. package/dist/lib/platform/issue-comments.js +146 -34
  69. package/dist/lib/platform/issues.js +1 -179
  70. package/dist/lib/platform/pr-change-report.js +6 -12
  71. package/dist/lib/platform/pr-checks.js +12 -65
  72. package/dist/lib/platform/pr-summary.js +83 -10
  73. package/dist/lib/platform/provider-contract.d.ts +67 -1
  74. package/dist/lib/platform/provider-contract.js +6 -2
  75. package/dist/lib/platform/provider-validation.js +76 -3
  76. package/dist/lib/platform/pull-requests.js +117 -275
  77. package/dist/lib/platform/repository-metadata.js +377 -0
  78. package/dist/lib/platform/security-alerts.js +155 -0
  79. package/dist/lib/platform/snapshots.js +2 -0
  80. package/dist/lib/platform/verification-sync.js +154 -162
  81. package/dist/lib/process-data/index.js +7 -0
  82. package/dist/lib/release/workflow.js +1 -1
  83. package/dist/lib/run/index.js +5 -0
  84. package/dist/lib/sandbox/commands/control-status.js +22 -0
  85. package/dist/lib/sandbox/commands/create.js +39 -8
  86. package/dist/lib/sandbox/commands/ls.js +5 -0
  87. package/dist/lib/sandbox/commands/rm.js +3 -807
  88. package/dist/lib/sandbox/commands/show.js +16 -0
  89. package/dist/lib/sandbox/control/audit.js +203 -0
  90. package/dist/lib/sandbox/control/client.js +125 -12
  91. package/dist/lib/sandbox/control/completed-reentry.js +85 -0
  92. package/dist/lib/sandbox/control/container-identity.js +28 -31
  93. package/dist/lib/sandbox/control/executor.js +233 -34
  94. package/dist/lib/sandbox/control/finalization-response.js +27 -0
  95. package/dist/lib/sandbox/control/identity-sentinel.js +107 -0
  96. package/dist/lib/sandbox/control/lifecycle.js +656 -128
  97. package/dist/lib/sandbox/control/native-file-lock.js +85 -0
  98. package/dist/lib/sandbox/control/protocol.js +55 -4
  99. package/dist/lib/sandbox/control/server.js +720 -79
  100. package/dist/lib/sandbox/control/state.js +63 -3
  101. package/dist/lib/sandbox/control/task-view.js +183 -0
  102. package/dist/lib/sandbox/control/task-workflow.js +74 -0
  103. package/dist/lib/sandbox/control/workflow-executor.js +99 -0
  104. package/dist/lib/sandbox/engines/authority.js +289 -0
  105. package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
  106. package/dist/lib/sandbox/index.js +7 -2
  107. package/dist/lib/sandbox/recovery.js +49 -5
  108. package/dist/lib/sandbox/removal.js +1717 -0
  109. package/dist/lib/sandbox/task-cleanup.js +217 -0
  110. package/dist/lib/sandbox/workspace-view.js +15 -15
  111. package/dist/lib/sandbox/worktree-safety.js +4 -1
  112. package/dist/lib/server/index.js +8 -0
  113. package/dist/lib/task/activity-intent.js +2 -1
  114. package/dist/lib/task/activity-log.js +30 -24
  115. package/dist/lib/task/artifact-command.js +101 -0
  116. package/dist/lib/task/artifact-lifecycle.js +71 -40
  117. package/dist/lib/task/artifact-name.js +36 -0
  118. package/dist/lib/task/artifact-operations.js +474 -0
  119. package/dist/lib/task/artifact-receipts.js +3 -15
  120. package/dist/lib/task/artifact-repair-intent.js +130 -0
  121. package/dist/lib/task/artifact-schema.js +127 -0
  122. package/dist/lib/task/capabilities.js +83 -19
  123. package/dist/lib/task/codex-orchestration.js +71 -25
  124. package/dist/lib/task/commit-identity.js +28 -0
  125. package/dist/lib/task/commit-operation.js +2 -16
  126. package/dist/lib/task/control-authority.js +375 -5
  127. package/dist/lib/task/control-recovery.js +128 -0
  128. package/dist/lib/task/create-service.js +103 -4
  129. package/dist/lib/task/create.js +80 -2
  130. package/dist/lib/task/decision-details.js +2 -46
  131. package/dist/lib/task/events.js +306 -76
  132. package/dist/lib/task/finalization-state.js +9 -0
  133. package/dist/lib/task/human-override.js +3 -6
  134. package/dist/lib/task/implementation-inputs.js +3 -3
  135. package/dist/lib/task/index.js +11 -3
  136. package/dist/lib/task/intermediate-cleanup.js +383 -0
  137. package/dist/lib/task/invalidation.js +18 -65
  138. package/dist/lib/task/ledger-intents.js +7 -22
  139. package/dist/lib/task/ledger.js +1 -3
  140. package/dist/lib/task/lifecycle.js +19 -1
  141. package/dist/lib/task/local-artifact-finalization.js +190 -290
  142. package/dist/lib/task/manual-validation-completion.js +26 -0
  143. package/dist/lib/task/manual-validation-evidence.js +130 -0
  144. package/dist/lib/task/manual-validation-receipt.js +101 -0
  145. package/dist/lib/task/manual-validation-shared.js +40 -0
  146. package/dist/lib/task/manual-validation-transaction.js +243 -0
  147. package/dist/lib/task/markdown.js +47 -0
  148. package/dist/lib/task/orchestration.js +206 -69
  149. package/dist/lib/task/qualification-audit.js +476 -0
  150. package/dist/lib/task/qualification-confirmation.js +109 -0
  151. package/dist/lib/task/qualification-intents.js +148 -0
  152. package/dist/lib/task/review-artifacts.js +23 -40
  153. package/dist/lib/task/review-command.js +25 -0
  154. package/dist/lib/task/review-finalization.js +146 -97
  155. package/dist/lib/task/review-fingerprint.js +2 -2
  156. package/dist/lib/task/sections.js +34 -54
  157. package/dist/lib/task/verification-config.js +11 -0
  158. package/dist/lib/task/verification-engine.js +170 -327
  159. package/dist/lib/task/verification.js +1 -1
  160. package/dist/lib/task/workflow-command.js +17 -0
  161. package/dist/lib/task/workflow-warning-intents.js +0 -16
  162. package/dist/lib/task/workflow-warnings.js +28 -2
  163. package/dist/lib/update.js +2 -0
  164. package/dist/lifecycle-build-manifest.json +3 -3
  165. package/lib/agent-client.ts +9 -0
  166. package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +223 -33
  167. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +3 -2
  168. package/lib/fs/durable-write.ts +29 -0
  169. package/lib/fs/file-lock.ts +113 -0
  170. package/lib/host-control/audit.ts +22 -0
  171. package/lib/host-control/client.ts +172 -0
  172. package/lib/host-control/command.ts +60 -0
  173. package/lib/host-control/path.ts +167 -0
  174. package/lib/host-control/secure-fs.ts +135 -0
  175. package/lib/host-control/server.ts +180 -0
  176. package/lib/host-control/service.ts +133 -0
  177. package/lib/init.ts +15 -2
  178. package/lib/internal/agent-client.ts +4 -2
  179. package/lib/internal/cli-route-inventory.ts +142 -0
  180. package/lib/internal/codex-lifecycle.ts +14 -12
  181. package/lib/internal/codex-sandbox-controller.ts +7 -2
  182. package/lib/internal/demo-promotion.ts +354 -0
  183. package/lib/internal/demo-transcript.ts +419 -0
  184. package/lib/internal/git-workflow.ts +9 -6
  185. package/lib/internal/host-control.ts +28 -0
  186. package/lib/internal/manual-validation.ts +306 -0
  187. package/lib/internal/platform-checks.ts +12 -4
  188. package/lib/internal/platform-comment.ts +12 -4
  189. package/lib/internal/platform-context.ts +3 -1
  190. package/lib/internal/platform-issue.ts +11 -4
  191. package/lib/internal/platform-metadata.ts +70 -0
  192. package/lib/internal/platform-pr-review.ts +14 -3
  193. package/lib/internal/platform-pr.ts +38 -14
  194. package/lib/internal/platform-release-notes.ts +5 -3
  195. package/lib/internal/platform-security.ts +83 -0
  196. package/lib/internal/pr-review-grade.ts +10 -3
  197. package/lib/internal/release-workflow.ts +91 -87
  198. package/lib/internal/sandbox-control.ts +181 -6
  199. package/lib/internal/task-activity.ts +12 -4
  200. package/lib/internal/task-artifact.ts +15 -79
  201. package/lib/internal/task-context.ts +3 -1
  202. package/lib/internal/task-create.ts +76 -15
  203. package/lib/internal/task-delivery.ts +3 -1
  204. package/lib/internal/task-event.ts +21 -10
  205. package/lib/internal/task-finalization.ts +3 -1
  206. package/lib/internal/task-invalidation.ts +3 -1
  207. package/lib/internal/task-ledger.ts +11 -1
  208. package/lib/internal/task-lifecycle.ts +3 -1
  209. package/lib/internal/task-operation-registry.ts +590 -0
  210. package/lib/internal/task-orchestration.ts +12 -0
  211. package/lib/internal/task-override.ts +9 -3
  212. package/lib/internal/task-qualification.ts +61 -0
  213. package/lib/internal/task-review.ts +7 -50
  214. package/lib/internal/task-short-id.ts +10 -1
  215. package/lib/internal/task-snapshot.ts +3 -1
  216. package/lib/internal/task-validate.ts +32 -12
  217. package/lib/internal/task-verify.ts +4 -1
  218. package/lib/internal/task-warning.ts +7 -1
  219. package/lib/owned-path.ts +26 -0
  220. package/lib/platform/check-status.ts +9 -0
  221. package/lib/platform/comment-safety.ts +255 -0
  222. package/lib/platform/completion-backfill.ts +1 -1
  223. package/lib/platform/github-data.ts +322 -0
  224. package/lib/platform/github-provider.ts +244 -27
  225. package/lib/platform/issue-comments.ts +159 -35
  226. package/lib/platform/issues.ts +4 -245
  227. package/lib/platform/pr-change-report.ts +6 -12
  228. package/lib/platform/pr-checks.ts +13 -77
  229. package/lib/platform/pr-summary.ts +88 -11
  230. package/lib/platform/provider-contract.ts +78 -3
  231. package/lib/platform/provider-validation.ts +85 -3
  232. package/lib/platform/pull-requests.ts +129 -348
  233. package/lib/platform/repository-metadata.ts +453 -0
  234. package/lib/platform/security-alerts.ts +191 -0
  235. package/lib/platform/snapshots.ts +53 -0
  236. package/lib/platform/verification-sync.ts +171 -177
  237. package/lib/process-data/index.ts +7 -0
  238. package/lib/release/workflow.ts +3 -3
  239. package/lib/run/index.ts +5 -0
  240. package/lib/sandbox/commands/control-status.ts +26 -0
  241. package/lib/sandbox/commands/create.ts +53 -12
  242. package/lib/sandbox/commands/ls.ts +7 -0
  243. package/lib/sandbox/commands/rm.ts +3 -996
  244. package/lib/sandbox/commands/show.ts +16 -0
  245. package/lib/sandbox/control/audit.ts +253 -0
  246. package/lib/sandbox/control/client.ts +150 -13
  247. package/lib/sandbox/control/completed-reentry.ts +98 -0
  248. package/lib/sandbox/control/container-identity.ts +27 -43
  249. package/lib/sandbox/control/executor.ts +262 -37
  250. package/lib/sandbox/control/finalization-response.ts +29 -0
  251. package/lib/sandbox/control/identity-sentinel.ts +137 -0
  252. package/lib/sandbox/control/lifecycle.ts +672 -18
  253. package/lib/sandbox/control/native-file-lock.ts +108 -0
  254. package/lib/sandbox/control/protocol.ts +80 -8
  255. package/lib/sandbox/control/server.ts +779 -82
  256. package/lib/sandbox/control/state.ts +84 -3
  257. package/lib/sandbox/control/task-view.ts +240 -0
  258. package/lib/sandbox/control/task-workflow.ts +95 -0
  259. package/lib/sandbox/control/workflow-executor.ts +102 -0
  260. package/lib/sandbox/engines/authority.ts +365 -0
  261. package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
  262. package/lib/sandbox/index.ts +9 -2
  263. package/lib/sandbox/recovery.ts +49 -6
  264. package/lib/sandbox/removal.ts +2144 -0
  265. package/lib/sandbox/task-cleanup.ts +209 -0
  266. package/lib/sandbox/workspace-view.ts +26 -18
  267. package/lib/sandbox/worktree-safety.ts +4 -1
  268. package/lib/server/index.ts +10 -0
  269. package/lib/task/activity-intent.ts +2 -2
  270. package/lib/task/activity-log.ts +27 -19
  271. package/lib/task/artifact-command.ts +104 -0
  272. package/lib/task/artifact-lifecycle.ts +66 -39
  273. package/lib/task/artifact-name.ts +55 -0
  274. package/lib/task/artifact-operations.ts +580 -0
  275. package/lib/task/artifact-receipts.ts +3 -14
  276. package/lib/task/artifact-repair-intent.ts +152 -0
  277. package/lib/task/artifact-schema.ts +163 -0
  278. package/lib/task/capabilities.ts +82 -22
  279. package/lib/task/codex-orchestration.ts +85 -24
  280. package/lib/task/commit-identity.ts +31 -0
  281. package/lib/task/commit-operation.ts +2 -16
  282. package/lib/task/control-authority.ts +513 -6
  283. package/lib/task/control-recovery.ts +174 -0
  284. package/lib/task/create-service.ts +131 -6
  285. package/lib/task/create.ts +83 -1
  286. package/lib/task/decision-details.ts +3 -71
  287. package/lib/task/events.ts +292 -75
  288. package/lib/task/finalization-state.ts +11 -0
  289. package/lib/task/human-override.ts +3 -8
  290. package/lib/task/implementation-inputs.ts +3 -3
  291. package/lib/task/index.ts +16 -3
  292. package/lib/task/intermediate-cleanup.ts +455 -0
  293. package/lib/task/invalidation.ts +18 -62
  294. package/lib/task/ledger-intents.ts +7 -24
  295. package/lib/task/ledger.ts +1 -3
  296. package/lib/task/lifecycle.ts +17 -1
  297. package/lib/task/local-artifact-finalization.ts +223 -388
  298. package/lib/task/manual-validation-completion.ts +40 -0
  299. package/lib/task/manual-validation-evidence.ts +209 -0
  300. package/lib/task/manual-validation-receipt.ts +152 -0
  301. package/lib/task/manual-validation-shared.ts +50 -0
  302. package/lib/task/manual-validation-transaction.ts +304 -0
  303. package/lib/task/markdown.ts +70 -0
  304. package/lib/task/orchestration.ts +191 -68
  305. package/lib/task/qualification-audit.ts +588 -0
  306. package/lib/task/qualification-confirmation.ts +117 -0
  307. package/lib/task/qualification-intents.ts +150 -0
  308. package/lib/task/review-artifacts.ts +21 -41
  309. package/lib/task/review-command.ts +23 -0
  310. package/lib/task/review-finalization.ts +154 -153
  311. package/lib/task/review-fingerprint.ts +2 -2
  312. package/lib/task/sections.ts +33 -52
  313. package/lib/task/verification-config.ts +12 -0
  314. package/lib/task/verification-engine.ts +165 -370
  315. package/lib/task/verification-types.ts +17 -0
  316. package/lib/task/verification.ts +1 -1
  317. package/lib/task/workflow-command.ts +18 -0
  318. package/lib/task/workflow-warning-intents.ts +0 -13
  319. package/lib/task/workflow-warnings.ts +21 -2
  320. package/lib/update.ts +6 -0
  321. package/package.json +7 -2
  322. package/templates/.agents/hooks/lifecycle-delegation.js +6 -6
  323. package/templates/.agents/rules/README.en.md +2 -0
  324. package/templates/.agents/rules/README.zh-CN.md +2 -0
  325. package/templates/.agents/rules/decision-qualification.en.md +22 -0
  326. package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
  327. package/templates/.agents/rules/evidence-reporting.en.md +28 -0
  328. package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
  329. package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
  330. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
  331. package/templates/.agents/rules/local-artifact-repair.en.md +5 -1
  332. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +5 -1
  333. package/templates/.agents/rules/security-alerts.en.md +8 -8
  334. package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
  335. package/templates/.agents/rules/testing-discipline.en.md +2 -0
  336. package/templates/.agents/rules/testing-discipline.zh-CN.md +2 -0
  337. package/templates/.agents/scripts/package.json +3 -0
  338. package/templates/.agents/skills/analyze-task/SKILL.en.md +15 -2
  339. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +19 -2
  340. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
  341. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
  342. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  343. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  344. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  345. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  346. package/templates/.agents/skills/code-task/SKILL.en.md +14 -1
  347. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +14 -1
  348. package/templates/.agents/skills/code-task/config/verify.en.json +5 -14
  349. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +5 -14
  350. package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
  351. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
  352. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
  353. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
  354. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
  355. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
  356. package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
  357. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
  358. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +37 -21
  359. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +37 -21
  360. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
  361. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
  362. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +4 -0
  363. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +4 -0
  364. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +16 -7
  365. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +16 -7
  366. package/templates/.agents/skills/complete-task/SKILL.en.md +10 -23
  367. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +10 -23
  368. package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
  369. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
  370. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  371. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  372. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  373. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  374. package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
  375. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
  376. package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
  377. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
  378. package/templates/.agents/skills/plan-task/SKILL.en.md +14 -1
  379. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +16 -1
  380. package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
  381. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
  382. package/templates/.agents/skills/release/SKILL.en.md +7 -3
  383. package/templates/.agents/skills/release/SKILL.zh-CN.md +7 -3
  384. package/templates/.agents/skills/review-analysis/SKILL.en.md +14 -1
  385. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -1
  386. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
  387. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
  388. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
  389. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
  390. package/templates/.agents/skills/review-code/SKILL.en.md +14 -1
  391. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +14 -1
  392. package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
  393. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
  394. package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
  395. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
  396. package/templates/.agents/skills/review-plan/SKILL.en.md +14 -1
  397. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -1
  398. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
  399. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
  400. package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
  401. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
  402. package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
  403. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
  404. package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
  405. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
  406. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +25 -4
  407. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +25 -4
  408. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +4 -1
  409. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +4 -1
  410. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +5 -1
  411. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +5 -1
  412. package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
  413. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
  414. package/templates/.agents/skills/test/SKILL.en.md +29 -7
  415. package/templates/.agents/skills/test/SKILL.zh-CN.md +29 -7
  416. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
  417. package/templates/.agents/templates/task.en.md +6 -0
  418. package/templates/.agents/templates/task.zh-CN.md +6 -0
  419. package/templates/.claude/commands/run-manual-validation.en.md +1 -1
  420. package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
  421. package/dist/lib/platform/adapters.js +0 -56
  422. package/lib/platform/adapters.ts +0 -197
  423. package/templates/.agents/scripts/security-alerts.github.sh +0 -151
  424. package/templates/.agents/scripts/security-alerts.sh +0 -31
  425. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
  426. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
  427. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
  428. package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
@@ -0,0 +1,255 @@
1
+ type SanitizationError = { code: 'COMMENT_DOCUMENT_INVALID'; message: string; offset: number };
2
+ type SanitizationResult<T> = { ok: true; value: T } | { ok: false; error: SanitizationError };
3
+ type SanitizationOptions = { reservedMarkers?: readonly RegExp[] };
4
+ type PlaceholderSplit = { prefix: string; suffix: string };
5
+ type FenceRange = {
6
+ start: number;
7
+ end: number;
8
+ openingEnd: number;
9
+ closingStart: number;
10
+ character: '`' | '~';
11
+ opening: string;
12
+ closing: string;
13
+ };
14
+ type Line = { start: number; end: number; text: string };
15
+
16
+ const CONTROL_MARKER_PATTERN = /<!--\s*(?:sync-issue|sync-pr|last-commit)\b[\s\S]*?-->|<!--\s*canonical-pr-change-report\s*-->/gi;
17
+
18
+ function ok<T>(value: T): SanitizationResult<T> {
19
+ return { ok: true, value };
20
+ }
21
+
22
+ function invalid(message: string, offset: number): SanitizationResult<never> {
23
+ return { ok: false, error: { code: 'COMMENT_DOCUMENT_INVALID', message, offset } };
24
+ }
25
+
26
+ function normalized(value: string): string {
27
+ return value.replace(/\r\n?/g, '\n');
28
+ }
29
+
30
+ function linesOf(value: string): Line[] {
31
+ const lines: Line[] = [];
32
+ let start = 0;
33
+ while (start < value.length) {
34
+ const newline = value.indexOf('\n', start);
35
+ const end = newline === -1 ? value.length : newline;
36
+ lines.push({ start, end: newline === -1 ? end : newline + 1, text: value.slice(start, end) });
37
+ start = newline === -1 ? value.length : newline + 1;
38
+ }
39
+ if (value.length === 0) lines.push({ start: 0, end: 0, text: '' });
40
+ return lines;
41
+ }
42
+
43
+ function openingFence(line: string): { character: '`' | '~'; length: number } | null | 'invalid' {
44
+ const match = line.match(/^ {0,3}(`{3,}|~{3,})(.*)$/);
45
+ if (!match) return null;
46
+ const character = match[1]![0] as '`' | '~';
47
+ const info = match[2]!;
48
+ if (character === '`' && info.includes('`')) return 'invalid';
49
+ return { character, length: match[1]!.length };
50
+ }
51
+
52
+ function closesFence(line: string, fence: { character: '`' | '~'; length: number }): boolean {
53
+ const escaped = fence.character === '`' ? '`' : '~';
54
+ return new RegExp(`^ {0,3}${escaped}{${fence.length},}[ \\t]*$`).test(line);
55
+ }
56
+
57
+ function fenceRanges(value: string): SanitizationResult<FenceRange[]> {
58
+ const ranges: FenceRange[] = [];
59
+ let fence: { character: '`' | '~'; length: number; start: number; openingEnd: number } | null = null;
60
+ for (const line of linesOf(value)) {
61
+ if (!fence) {
62
+ const opening = openingFence(line.text);
63
+ if (opening === 'invalid') return invalid('fenced code info string is invalid', line.start);
64
+ if (opening) fence = { ...opening, start: line.start, openingEnd: line.end };
65
+ continue;
66
+ }
67
+ if (closesFence(line.text, fence)) {
68
+ ranges.push({
69
+ start: fence.start,
70
+ end: line.end,
71
+ openingEnd: fence.openingEnd,
72
+ closingStart: line.start,
73
+ character: fence.character,
74
+ opening: value.slice(fence.start, fence.openingEnd),
75
+ closing: value.slice(line.start, line.end)
76
+ });
77
+ fence = null;
78
+ }
79
+ }
80
+ if (fence) return invalid('fenced code block is not closed', fence.start);
81
+ return ok(ranges);
82
+ }
83
+
84
+ function escapeHtml(value: string): string {
85
+ return value
86
+ .replace(/&/g, '&amp;')
87
+ .replace(/</g, '&lt;')
88
+ .replace(/>/g, '&gt;')
89
+ .replace(/"/g, '&quot;')
90
+ .replace(/'/g, '&#39;');
91
+ }
92
+
93
+ function escapeHtmlText(value: string): string {
94
+ return escapeHtml(value);
95
+ }
96
+
97
+ function escapeHtmlAttribute(value: string): string {
98
+ return escapeHtml(value);
99
+ }
100
+
101
+ function escapeMarkdownLiteral(value: string): string {
102
+ return value.replace(/[\\`*_{}\[\]()#+.!|<>-]/g, '\\$&');
103
+ }
104
+
105
+ function markerSafe(value: string, markers: readonly RegExp[]): string {
106
+ let result = value;
107
+ for (const marker of markers) {
108
+ const flags = marker.flags.includes('g') ? marker.flags : `${marker.flags}g`;
109
+ const pattern = new RegExp(marker.source, flags);
110
+ result = result.replace(pattern, (match) => escapeHtmlText(match));
111
+ }
112
+ return result;
113
+ }
114
+
115
+ function tagEnd(value: string, start: number): number {
116
+ let quote: '"' | "'" | null = null;
117
+ for (let index = start + 1; index < value.length; index += 1) {
118
+ const character = value[index]!;
119
+ if (quote) {
120
+ if (character === quote) quote = null;
121
+ } else if (character === '"' || character === "'") {
122
+ quote = character;
123
+ } else if (character === '>') {
124
+ return index;
125
+ }
126
+ }
127
+ return -1;
128
+ }
129
+
130
+ function isMarkdownAutolink(value: string, start: number): boolean {
131
+ const end = value.indexOf('>', start + 1);
132
+ if (end === -1) return false;
133
+ const target = value.slice(start + 1, end);
134
+ return /^(?:https?:\/\/|mailto:)[^<>\s]+$/i.test(target)
135
+ || /^[^<>\s@]+@[^<>\s@]+\.[^<>\s@]+$/.test(target);
136
+ }
137
+
138
+ function sanitizeOutside(value: string, baseOffset: number): SanitizationResult<string> {
139
+ let result = '';
140
+ let index = 0;
141
+ while (index < value.length) {
142
+ if (value.startsWith('<!--', index)) {
143
+ const end = value.indexOf('-->', index + 4);
144
+ if (end === -1) return invalid('HTML comment is not closed', baseOffset + index);
145
+ const token = value.slice(index, end + 3);
146
+ result += escapeHtmlText(token);
147
+ index = end + 3;
148
+ continue;
149
+ }
150
+ if (value[index] === '<' && isMarkdownAutolink(value, index)) {
151
+ const end = value.indexOf('>', index + 1);
152
+ result += value.slice(index, end + 1);
153
+ index = end + 1;
154
+ continue;
155
+ }
156
+ if (value[index] === '<' && /[\\/!?A-Za-z]/.test(value[index + 1] || '')) {
157
+ const end = tagEnd(value, index);
158
+ if (end === -1) return invalid('HTML-like tag is not closed', baseOffset + index);
159
+ result += escapeHtmlText(value.slice(index, end + 1));
160
+ index = end + 1;
161
+ continue;
162
+ }
163
+ result += value[index]!;
164
+ index += 1;
165
+ }
166
+ return ok(result);
167
+ }
168
+
169
+ function sanitizeMarkdownDocument(value: string, options: SanitizationOptions = {}): SanitizationResult<string> {
170
+ const source = normalized(value);
171
+ const ranges = fenceRanges(source);
172
+ if (!ranges.ok) return ranges;
173
+ const markers = options.reservedMarkers || [];
174
+ let result = '';
175
+ let cursor = 0;
176
+ for (const range of ranges.value) {
177
+ const outside = sanitizeOutside(source.slice(cursor, range.start), cursor);
178
+ if (!outside.ok) return outside;
179
+ result += outside.value;
180
+ result += markerSafe(source.slice(range.start, range.end), markers);
181
+ cursor = range.end;
182
+ }
183
+ const tail = sanitizeOutside(source.slice(cursor), cursor);
184
+ if (!tail.ok) return tail;
185
+ return ok(result + tail.value);
186
+ }
187
+
188
+ function canonicalizeCommentBody(value: string): SanitizationResult<string> {
189
+ return sanitizeMarkdownDocument(value, { reservedMarkers: [CONTROL_MARKER_PATTERN] });
190
+ }
191
+
192
+ function renderSafeCodeFence(value: string, language = '', reservedMarkers: readonly RegExp[] = [CONTROL_MARKER_PATTERN]): string {
193
+ const content = markerSafe(normalized(value), reservedMarkers);
194
+ const longestRun = Math.max(0, ...(content.match(/`+/g) || []).map((run) => run.length));
195
+ const delimiter = '`'.repeat(Math.max(3, longestRun + 1));
196
+ const suffix = content.endsWith('\n') ? '' : '\n';
197
+ return `${delimiter}${language}\n${content}${suffix}${delimiter}`;
198
+ }
199
+
200
+ function commentRangesOutsideFences(source: string, ranges: readonly FenceRange[]): SanitizationResult<Array<{ start: number; end: number }>> {
201
+ const comments: Array<{ start: number; end: number }> = [];
202
+ let cursor = 0;
203
+ for (const fence of [...ranges, { start: source.length, end: source.length }]) {
204
+ const segment = source.slice(cursor, fence.start);
205
+ let index = 0;
206
+ while (index < segment.length) {
207
+ const opening = segment.indexOf('<!--', index);
208
+ if (opening === -1) break;
209
+ const absoluteStart = cursor + opening;
210
+ const closing = segment.indexOf('-->', opening + 4);
211
+ if (closing === -1) return invalid('HTML comment is not closed', absoluteStart);
212
+ comments.push({ start: absoluteStart, end: cursor + closing + 3 });
213
+ index = closing + 3;
214
+ }
215
+ cursor = fence.end;
216
+ }
217
+ return ok(comments);
218
+ }
219
+
220
+ function splitDocumentPlaceholder(value: string, placeholder: string): SanitizationResult<PlaceholderSplit> {
221
+ const source = normalized(value);
222
+ const ranges = fenceRanges(source);
223
+ if (!ranges.ok) return ranges;
224
+ const positions: number[] = [];
225
+ let cursor = source.indexOf(placeholder);
226
+ while (cursor !== -1) {
227
+ positions.push(cursor);
228
+ cursor = source.indexOf(placeholder, cursor + placeholder.length);
229
+ }
230
+ if (positions.length !== 1) return invalid('document must contain exactly one placeholder', positions[1] ?? positions[0] ?? source.length);
231
+ const position = positions[0]!;
232
+ if (ranges.value.some((range) => position >= range.start && position < range.end)) {
233
+ return invalid('placeholder must be outside fenced code', position);
234
+ }
235
+ const comments = commentRangesOutsideFences(source, ranges.value);
236
+ if (!comments.ok) return comments;
237
+ const containing = comments.value.find((comment) => position >= comment.start && position < comment.end);
238
+ if (containing && (containing.start !== position || containing.end !== position + placeholder.length)) {
239
+ return invalid('placeholder must not be nested in another HTML comment', position);
240
+ }
241
+ return ok({ prefix: source.slice(0, position), suffix: source.slice(position + placeholder.length) });
242
+ }
243
+
244
+ export {
245
+ CONTROL_MARKER_PATTERN,
246
+ escapeHtmlAttribute,
247
+ escapeHtmlText,
248
+ escapeMarkdownLiteral,
249
+ fenceRanges,
250
+ renderSafeCodeFence,
251
+ canonicalizeCommentBody,
252
+ sanitizeMarkdownDocument,
253
+ splitDocumentPlaceholder
254
+ };
255
+ export type { FenceRange, SanitizationError, SanitizationOptions, SanitizationResult };
@@ -2,7 +2,7 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
 
4
4
  import { COMPLETION_BACKFILL_FAMILIES, inspectCompletionArtifacts } from '../task/finalization-artifacts.ts';
5
- import { parseArtifactName } from '../task/artifact-lifecycle.ts';
5
+ import { parseArtifactName } from '../task/artifact-name.ts';
6
6
  import { parseTaskFrontmatter } from '../task/frontmatter.ts';
7
7
  import { resolveTaskRef } from '../task/resolve-ref.ts';
8
8
  import { getOpenWorkflowWarnings } from '../task/workflow-warnings.ts';
@@ -0,0 +1,322 @@
1
+ import type { PlatformClient as GitHubClient } from './context.ts';
2
+ import type { PlatformIssueSnapshot as IssueSnapshot, PlatformChangeRequestSnapshot as PullRequestSnapshot } from './snapshots.ts';
3
+ import type { RequiredCheckSnapshot } from './provider-contract.ts';
4
+ import { checkStatusBucket } from './check-status.ts';
5
+
6
+ type RemoteIssue = {
7
+ number?: number;
8
+ id?: number;
9
+ node_id?: string;
10
+ html_url?: string;
11
+ state?: string;
12
+ title?: string;
13
+ body?: string | null;
14
+ labels?: Array<string | { name?: string }>;
15
+ assignees?: Array<{ login?: string }>;
16
+ milestone?: { title?: string } | null;
17
+ type?: { name?: string } | null;
18
+ pull_request?: unknown;
19
+ };
20
+
21
+ type IssueFieldSchema = {
22
+ id: string;
23
+ name: string;
24
+ kind: 'single-select' | 'date' | 'text' | 'number';
25
+ options: Array<{ id: string; name: string }>;
26
+ };
27
+
28
+ type IssueTypeSchema = { id: string; name: string; fields: IssueFieldSchema[] };
29
+
30
+ type CurrentField = { id: string; name: string; kind: IssueFieldSchema['kind']; value: string | number | null };
31
+
32
+ const ISSUE_FIELDS_QUERY = `query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){issue(number:$number){id issueType{id name pinnedFields{__typename ... on IssueFieldSingleSelect{id name options{id name}} ... on IssueFieldDate{id name} ... on IssueFieldText{id name} ... on IssueFieldNumber{id name}}} issueFieldValues(first:50){nodes{__typename ... on IssueFieldSingleSelectValue{name optionId field{... on IssueFieldSingleSelect{id name}}} ... on IssueFieldDateValue{value field{... on IssueFieldDate{id name}}} ... on IssueFieldTextValue{value field{... on IssueFieldText{id name}}} ... on IssueFieldNumberValue{value field{... on IssueFieldNumber{id name}}}}}}}}`;
33
+
34
+ function normalizeIssue(remote: RemoteIssue, repository: string, fallbackNumber?: number): IssueSnapshot | null {
35
+ const number = Number.isInteger(remote.number) && Number(remote.number) > 0
36
+ ? Number(remote.number)
37
+ : fallbackNumber;
38
+ if (!number || !Number.isSafeInteger(number) || remote.pull_request) return null;
39
+ return {
40
+ repository,
41
+ number,
42
+ databaseId: Number.isInteger(remote.id) ? Number(remote.id) : null,
43
+ nodeId: remote.node_id || `issue-${number}`,
44
+ url: remote.html_url || `https://github.com/${repository}/issues/${number}`,
45
+ state: String(remote.state || '').toLowerCase() === 'closed' ? 'closed' : 'open',
46
+ title: remote.title || '',
47
+ body: remote.body || '',
48
+ labels: (remote.labels || []).map((label) => typeof label === 'string' ? label : label.name || '').filter(Boolean).sort(),
49
+ assignees: (remote.assignees || []).map((assignee) => assignee.login || '').filter(Boolean).sort(),
50
+ milestone: remote.milestone?.title || null,
51
+ issueType: remote.type?.name || null,
52
+ fields: {}
53
+ };
54
+ }
55
+
56
+ function fieldKind(value: { __typename?: string }): IssueFieldSchema['kind'] | null {
57
+ if (value.__typename === 'IssueFieldSingleSelect' || value.__typename === 'IssueFieldSingleSelectValue') return 'single-select';
58
+ if (value.__typename === 'IssueFieldDate' || value.__typename === 'IssueFieldDateValue') return 'date';
59
+ if (value.__typename === 'IssueFieldText' || value.__typename === 'IssueFieldTextValue') return 'text';
60
+ if (value.__typename === 'IssueFieldNumber' || value.__typename === 'IssueFieldNumberValue') return 'number';
61
+ return null;
62
+ }
63
+
64
+ function normalizeFieldSchemas(value: unknown): IssueFieldSchema[] {
65
+ if (!Array.isArray(value)) return [];
66
+ return value.flatMap((raw) => {
67
+ const item = raw as { id?: string; name?: string; __typename?: string; options?: Array<{ id?: string; name?: string }> };
68
+ const kind = fieldKind(item);
69
+ return item.id && item.name && kind ? [{
70
+ id: item.id,
71
+ name: item.name,
72
+ kind,
73
+ options: (item.options || []).flatMap((option) => option.id && option.name ? [{ id: option.id, name: option.name }] : [])
74
+ }] : [];
75
+ });
76
+ }
77
+
78
+ function normalizeCurrentFields(value: unknown): { issueId: string | null; type: IssueTypeSchema | null; values: CurrentField[] } {
79
+ const issue = (value as { data?: { repository?: { issue?: {
80
+ id?: string;
81
+ issueType?: { id?: string; name?: string; pinnedFields?: unknown[] } | null;
82
+ issueFieldValues?: { nodes?: unknown[] };
83
+ } } } })?.data?.repository?.issue;
84
+ const type = issue?.issueType?.name ? {
85
+ id: issue.issueType.id || issue.issueType.name,
86
+ name: issue.issueType.name,
87
+ fields: normalizeFieldSchemas(issue.issueType.pinnedFields)
88
+ } : null;
89
+ const values = (issue?.issueFieldValues?.nodes || []).flatMap((raw) => {
90
+ const item = raw as { __typename?: string; name?: string; value?: string | number; field?: { id?: string; name?: string } };
91
+ const kind = fieldKind(item);
92
+ const value = kind === 'single-select' ? item.name : item.value;
93
+ return item.field?.name && kind && value !== undefined
94
+ ? [{ id: item.field.id || item.field.name, name: item.field.name, kind, value: value ?? null }]
95
+ : [];
96
+ });
97
+ return { issueId: issue?.id || null, type, values };
98
+ }
99
+
100
+ function graphState(client: GitHubClient, repository: string, issue: number, cwd: string) {
101
+ const [owner, name] = repository.split('/');
102
+ if (!owner || !name) return null;
103
+ const current = client.json<unknown>([
104
+ 'api', 'graphql', '-f', `query=${ISSUE_FIELDS_QUERY}`, '-F', `owner=${owner}`, '-F', `name=${name}`, '-F', `number=${issue}`
105
+ ], { cwd });
106
+ if (!current.ok) return null;
107
+ return normalizeCurrentFields(current.value);
108
+ }
109
+
110
+ function fetchIssue(client: GitHubClient, repository: string, issue: number, cwd: string) {
111
+ return client.json<RemoteIssue>(['api', `repos/${repository}/issues/${issue}`], { cwd });
112
+ }
113
+
114
+ function inspectGitHubIssue(client: GitHubClient, repository: string, issue: number, cwd: string) {
115
+ const fetched = fetchIssue(client, repository, issue, cwd);
116
+ if (!fetched.ok) return fetched;
117
+ const snapshot = normalizeIssue(fetched.value, repository, issue);
118
+ return snapshot
119
+ ? { ok: true as const, value: snapshot }
120
+ : { ok: false as const, error: { code: 'ISSUE_IDENTITY_INVALID', message: 'Remote resource is not a valid Issue', retryable: false } };
121
+ }
122
+
123
+ type RemotePullRequest = {
124
+ number?: number;
125
+ node_id?: string;
126
+ html_url?: string;
127
+ state?: string;
128
+ title?: string;
129
+ body?: string | null;
130
+ draft?: boolean;
131
+ pull_request?: unknown;
132
+ head?: { ref?: string; sha?: string; repo?: { full_name?: string } | null };
133
+ base?: { ref?: string; sha?: string; repo?: { full_name?: string } | null };
134
+ merged_at?: string | null;
135
+ merge_commit_sha?: string | null;
136
+ labels?: Array<string | { name?: string }>;
137
+ assignees?: Array<{ login?: string }>;
138
+ milestone?: { title?: string } | null;
139
+ mergeable?: boolean | null;
140
+ mergeable_state?: string | null;
141
+ };
142
+
143
+ type ClosingPullRequestNode = {
144
+ number?: number;
145
+ id?: string;
146
+ url?: string;
147
+ state?: string;
148
+ title?: string;
149
+ body?: string | null;
150
+ isDraft?: boolean;
151
+ headRefName?: string;
152
+ headRefOid?: string;
153
+ headRepository?: { nameWithOwner?: string } | null;
154
+ baseRefName?: string;
155
+ baseRefOid?: string;
156
+ baseRepository?: { nameWithOwner?: string } | null;
157
+ mergedAt?: string | null;
158
+ mergeCommit?: { oid?: string } | null;
159
+ labels?: { nodes?: Array<{ name?: string }> };
160
+ assignees?: { nodes?: Array<{ login?: string }> };
161
+ milestone?: { title?: string } | null;
162
+ };
163
+
164
+ type ClosingPullRequestPage = {
165
+ data?: { repository?: { issue?: { closedByPullRequestsReferences?: {
166
+ nodes?: ClosingPullRequestNode[];
167
+ pageInfo?: { hasNextPage?: boolean; endCursor?: string | null };
168
+ } } } };
169
+ };
170
+
171
+ const CLOSING_PULL_REQUESTS_QUERY = `query($owner:String!,$name:String!,$issue:Int!,$cursor:String){repository(owner:$owner,name:$name){issue(number:$issue){closedByPullRequestsReferences(first:100,after:$cursor){nodes{number id url state title body isDraft headRefName headRefOid headRepository{nameWithOwner} baseRefName baseRefOid baseRepository{nameWithOwner} mergedAt mergeCommit{oid} labels(first:100){nodes{name}} assignees(first:100){nodes{login}} milestone{title}} pageInfo{hasNextPage endCursor}}}}}`;
172
+
173
+ function normalizePullRequest(remote: RemotePullRequest, repository: string): PullRequestSnapshot | null {
174
+ const number = Number(remote.number);
175
+ const headRepository = remote.head?.repo?.full_name;
176
+ const baseRepository = remote.base?.repo?.full_name;
177
+ if (!Number.isInteger(number) || number <= 0 || !remote.node_id || !remote.html_url ||
178
+ !remote.head?.ref || !remote.head.sha || !headRepository || !remote.base?.ref || !baseRepository) return null;
179
+ const mergeabilityDetail = remote.mergeable_state?.trim().toLowerCase() || null;
180
+ const mergeability = remote.mergeable === false
181
+ ? { state: 'conflicting' as const, detail: mergeabilityDetail }
182
+ : remote.mergeable === true && mergeabilityDetail !== 'dirty'
183
+ ? { state: 'mergeable' as const, detail: mergeabilityDetail }
184
+ : { state: 'unknown' as const, detail: mergeabilityDetail };
185
+ return {
186
+ repository,
187
+ number,
188
+ nodeId: remote.node_id,
189
+ url: remote.html_url,
190
+ state: remote.state === 'closed' ? 'closed' : 'open',
191
+ title: remote.title || '',
192
+ body: remote.body || '',
193
+ draft: Boolean(remote.draft),
194
+ head: { repository: headRepository, ref: remote.head.ref, sha: remote.head.sha },
195
+ base: { repository: baseRepository, ref: remote.base.ref, sha: remote.base.sha || '' },
196
+ mergedAt: remote.merged_at || null,
197
+ mergeCommitSha: remote.merge_commit_sha || null,
198
+ labels: (remote.labels || []).map((label) => typeof label === 'string' ? label : label.name || '').filter(Boolean).sort(),
199
+ assignees: (remote.assignees || []).map((assignee) => assignee.login || '').filter(Boolean).sort(),
200
+ milestone: remote.milestone?.title || null,
201
+ mergeability
202
+ };
203
+ }
204
+
205
+ function normalizeClosingPullRequest(node: ClosingPullRequestNode, repository: string): PullRequestSnapshot | null {
206
+ return normalizePullRequest({
207
+ number: node.number,
208
+ node_id: node.id,
209
+ html_url: node.url,
210
+ state: node.state === 'OPEN' ? 'open' : 'closed',
211
+ title: node.title,
212
+ body: node.body,
213
+ draft: node.isDraft,
214
+ head: { ref: node.headRefName, sha: node.headRefOid, repo: node.headRepository ? { full_name: node.headRepository.nameWithOwner } : null },
215
+ base: { ref: node.baseRefName, sha: node.baseRefOid, repo: node.baseRepository ? { full_name: node.baseRepository.nameWithOwner } : null },
216
+ merged_at: node.mergedAt,
217
+ merge_commit_sha: node.mergeCommit?.oid,
218
+ labels: node.labels?.nodes,
219
+ assignees: node.assignees?.nodes,
220
+ milestone: node.milestone
221
+ }, repository);
222
+ }
223
+
224
+ function inspectGitHubIssueClosingChangeRequests(
225
+ client: GitHubClient,
226
+ repository: string,
227
+ issueNumber: number,
228
+ cwd: string
229
+ ) {
230
+ const [owner, name] = repository.split('/');
231
+ if (!owner || !name || !Number.isInteger(issueNumber) || issueNumber <= 0) return {
232
+ ok: false as const,
233
+ error: { code: 'PR_IDENTITY_INVALID', message: 'Repository or Issue identity is invalid', retryable: false }
234
+ };
235
+ const candidates: PullRequestSnapshot[] = [];
236
+ let cursor: string | null = null;
237
+ for (;;) {
238
+ const args = [
239
+ 'api', 'graphql', '-f', `query=${CLOSING_PULL_REQUESTS_QUERY}`,
240
+ '-F', `owner=${owner}`, '-F', `name=${name}`, '-F', `issue=${issueNumber}`
241
+ ];
242
+ if (cursor) args.push('-F', `cursor=${cursor}`);
243
+ const response = client.json<ClosingPullRequestPage>(args, { cwd });
244
+ if (!response.ok) return response;
245
+ const connection = response.value?.data?.repository?.issue?.closedByPullRequestsReferences;
246
+ if (!connection || !Array.isArray(connection.nodes) || !connection.pageInfo) return {
247
+ ok: false as const,
248
+ error: { code: 'PR_IDENTITY_INVALID', message: 'Closing pull request response is incomplete', retryable: false }
249
+ };
250
+ for (const node of connection.nodes) {
251
+ const normalized = normalizeClosingPullRequest(node, repository);
252
+ if (!normalized) return {
253
+ ok: false as const,
254
+ error: { code: 'PR_IDENTITY_INVALID', message: 'Closing pull request identity is incomplete', retryable: false }
255
+ };
256
+ candidates.push(normalized);
257
+ }
258
+ if (!connection.pageInfo.hasNextPage) return { ok: true as const, value: candidates };
259
+ if (!connection.pageInfo.endCursor || connection.pageInfo.endCursor === cursor) return {
260
+ ok: false as const,
261
+ error: { code: 'PR_IDENTITY_INVALID', message: 'Closing pull request pagination cursor is invalid', retryable: false }
262
+ };
263
+ cursor = connection.pageInfo.endCursor;
264
+ }
265
+ }
266
+
267
+ function inspectGitHubPullRequest(client: GitHubClient, repository: string, number: number, cwd: string) {
268
+ const fetched = client.json<RemotePullRequest>(['api', `repos/${repository}/pulls/${number}`], { cwd });
269
+ if (!fetched.ok) return fetched;
270
+ const pullRequest = normalizePullRequest(fetched.value, repository);
271
+ return pullRequest
272
+ ? { ok: true as const, value: pullRequest }
273
+ : { ok: false as const, error: { code: 'PR_IDENTITY_INVALID', message: 'Remote resource is not a valid pull request', retryable: false } };
274
+ }
275
+
276
+ function normalizeGitHubChecks(value: unknown): RequiredCheckSnapshot[] {
277
+ if (!Array.isArray(value)) return [];
278
+ return value.flatMap((raw) => {
279
+ const item = raw as Record<string, unknown>;
280
+ const name = String(item.name || item.context || '');
281
+ return name ? [{
282
+ name,
283
+ status: checkStatusBucket(String(item.bucket || item.status || item.conclusion || item.state || '')),
284
+ conclusion: item.conclusion ? String(item.conclusion) : item.state ? String(item.state) : null,
285
+ detailsUrl: item.link ? String(item.link) : item.detailsUrl ? String(item.detailsUrl) : null
286
+ }] : [];
287
+ });
288
+ }
289
+
290
+ function inspectGitHubRequiredChecks(client: GitHubClient, repository: string, number: number, cwd: string) {
291
+ const inspected = client.json<unknown>([
292
+ 'pr', 'checks', String(number), '--repo', repository,
293
+ '--json', 'name,state,bucket,link,workflow,startedAt,completedAt'
294
+ ], { cwd });
295
+ return inspected.ok
296
+ ? { ok: true as const, value: normalizeGitHubChecks(inspected.value) }
297
+ : { ok: false as const, error: inspected.error };
298
+ }
299
+
300
+ function parseRunJobIdentity(detailsUrl: string): { runId: number; jobId: number | null } | null {
301
+ try {
302
+ const url = new URL(detailsUrl);
303
+ if (url.hostname !== 'github.com') return null;
304
+ const match = url.pathname.match(/\/actions\/runs\/(\d+)(?:\/job\/(\d+))?/);
305
+ if (!match) return null;
306
+ return { runId: Number(match[1]), jobId: match[2] ? Number(match[2]) : null };
307
+ } catch {
308
+ return null;
309
+ }
310
+ }
311
+
312
+ function fetchCheckLogText(client: GitHubClient, args: string[], cwd: string) {
313
+ if (!client.text) return { ok: false as const, error: { code: 'PLATFORM_CLIENT_TEXT_UNAVAILABLE', message: 'Platform client does not support text responses', retryable: false } };
314
+ const fetched = client.text(args, { cwd });
315
+ if (fetched.ok || args[0] !== 'api' || !/response contains terminal escape sequences/i.test(fetched.error.message)) {
316
+ return fetched;
317
+ }
318
+ return client.text([...args, '--allow-escape-sequences'], { cwd });
319
+ }
320
+
321
+ export { ISSUE_FIELDS_QUERY, graphState, inspectGitHubIssue, normalizePullRequest, inspectGitHubIssueClosingChangeRequests, inspectGitHubPullRequest, inspectGitHubRequiredChecks, parseRunJobIdentity, fetchCheckLogText };
322
+ export type { IssueFieldSchema, RemotePullRequest };