@joshuafolkken/kit 1.1240.0 → 1.1370.0

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 (934) hide show
  1. package/.claude/agents/investigator.md +1 -0
  2. package/.claude/settings.json +4 -0
  3. package/.claude/skills/dependency-update/SKILL.md +5 -3
  4. package/.claude/skills/epic-commands/SKILL.md +82 -113
  5. package/.claude/skills/epic-commands/epic-bundle.md +38 -63
  6. package/.claude/skills/epic-commands/execution-waves.md +30 -51
  7. package/.claude/skills/verify-ui/SKILL.md +13 -20
  8. package/.claude/skills/workflow-commands/SKILL.md +10 -10
  9. package/.claude/skills/workflow-commands/background-commands.md +4 -4
  10. package/.claude/skills/workflow-commands/backlogrun-child.md +30 -105
  11. package/.claude/skills/workflow-commands/backlogrun-handoff-report.md +29 -0
  12. package/.claude/skills/workflow-commands/backlogrun-lanes.md +45 -131
  13. package/.claude/skills/workflow-commands/backlogrun-park.md +36 -53
  14. package/.claude/skills/workflow-commands/backlogrun-progress.md +81 -331
  15. package/.claude/skills/workflow-commands/backlogrun-recovery.md +29 -83
  16. package/.claude/skills/workflow-commands/backlogrun-steps.md +105 -424
  17. package/.claude/skills/workflow-commands/backlogrun.md +50 -61
  18. package/.claude/skills/workflow-commands/chain-rule.md +36 -40
  19. package/.claude/skills/workflow-commands/entry-sequence.md +6 -6
  20. package/.claude/skills/workflow-commands/followup.md +19 -20
  21. package/.claude/skills/workflow-commands/fullrun-steps.md +23 -27
  22. package/.claude/skills/workflow-commands/fullrun.md +10 -10
  23. package/.claude/skills/workflow-commands/halfrun.md +9 -8
  24. package/.claude/skills/workflow-commands/into-target.md +12 -18
  25. package/.claude/skills/workflow-commands/issue-comments.md +11 -26
  26. package/.claude/skills/workflow-commands/kickoff.md +26 -16
  27. package/.claude/skills/workflow-commands/latest-gate.md +17 -28
  28. package/.claude/skills/workflow-commands/needs-human-review.md +13 -24
  29. package/.claude/skills/workflow-commands/observation-filing.md +37 -28
  30. package/.claude/skills/workflow-commands/observation-ledger.md +48 -38
  31. package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -9
  32. package/.claude/skills/workflow-commands/prerequisite.md +23 -15
  33. package/.claude/skills/workflow-commands/progress-watcher.md +17 -11
  34. package/.claude/skills/workflow-commands/prrun.md +3 -3
  35. package/.claude/skills/workflow-commands/retrospective.md +13 -18
  36. package/.claude/skills/workflow-commands/split-assessment.md +6 -4
  37. package/.claude/skills/workflow-commands/target-repository.md +25 -28
  38. package/.claude/skills/workflow-commands/working-tree-hold.md +11 -17
  39. package/.gitattributes +2 -1
  40. package/.github/workflows/ci.yml +14 -0
  41. package/.vscode/tasks.json +14 -0
  42. package/CLAUDE.md +10 -61
  43. package/README.md +29 -47
  44. package/SECURITY.md +1 -1
  45. package/dist/CLAUDE.md +10 -61
  46. package/dist/commands/document-section-cli.js +42 -10
  47. package/dist/config-merge/index.js +11 -2
  48. package/dist/hooks/audit-provision.js +2 -2
  49. package/dist/hooks/batch-guard.js +7 -7
  50. package/dist/hooks/{chunk-KHGB5S3Y.js → chunk-43G45XJF.js} +18 -20
  51. package/dist/hooks/{chunk-4TZVB44A.js → chunk-4TW4MQUL.js} +284 -362
  52. package/dist/hooks/{chunk-XZYKEM6J.js → chunk-76RK6E3H.js} +13 -11
  53. package/dist/hooks/{chunk-F3ELQ2AF.js → chunk-DZWZ3DKY.js} +4 -4
  54. package/dist/hooks/{chunk-5VNDSNG3.js → chunk-FZ6FUSBM.js} +1 -1
  55. package/dist/hooks/{chunk-GPTFMK5E.js → chunk-GG72ANKI.js} +1 -1
  56. package/dist/hooks/{chunk-ZQGD4GBY.js → chunk-KPM4YIIX.js} +8 -44
  57. package/dist/hooks/chunk-MXVQMLDP.js +3705 -0
  58. package/dist/hooks/{chunk-ELCN5LCH.js → chunk-NEC4AT4Z.js} +34 -12
  59. package/dist/hooks/{chunk-QVSWU24O.js → chunk-NZBHG6FW.js} +7 -5
  60. package/dist/hooks/chunk-NZN2UFI6.js +2409 -0
  61. package/dist/hooks/{chunk-KRBERBBI.js → chunk-R6CRQEAL.js} +4 -4
  62. package/dist/hooks/chunk-SYSRHRWU.js +1589 -0
  63. package/dist/hooks/{chunk-WK2XSHSI.js → chunk-TLJYAGZK.js} +549 -874
  64. package/dist/hooks/chunk-Z5TMJIPW.js +45 -0
  65. package/dist/hooks/codex-hook-adapter.js +26 -21
  66. package/dist/hooks/duplicate-read-guard.js +8 -8
  67. package/dist/hooks/format-edited.js +4 -4
  68. package/dist/hooks/inputs.json +216 -202
  69. package/dist/hooks/investigation-guard.js +8 -8
  70. package/dist/hooks/pretool-guard.js +15 -15
  71. package/dist/hooks/session-lang.js +406 -8
  72. package/dist/hooks/stop-guard.js +122 -187
  73. package/dist/josh.js +281 -94
  74. package/dist/version/index.js +15 -13
  75. package/eslint/base.js +43 -5
  76. package/eslint/rules/english-only-prose.js +3 -3
  77. package/eslint/rules/import.js +12 -0
  78. package/eslint/rules/namespace-object-export.js +2 -2
  79. package/package.json +16 -10
  80. package/pnpm-workspace.yaml +2 -4
  81. package/prompts/coding-standards.md +14 -48
  82. package/prompts/collaboration-workflow/file-edits.md +1 -1
  83. package/prompts/collaboration-workflow/issue-citation.md +1 -1
  84. package/prompts/collaboration-workflow/issue-template.md +3 -10
  85. package/prompts/collaboration-workflow/operating-rules.md +7 -8
  86. package/prompts/collaboration-workflow/output-bounds.md +1 -1
  87. package/prompts/collaboration-workflow/overview.md +1 -1
  88. package/prompts/collaboration-workflow/plan-comment.md +2 -1
  89. package/prompts/collaboration-workflow/principles.md +21 -3
  90. package/prompts/collaboration-workflow/report-format.md +16 -29
  91. package/prompts/collaboration-workflow/residency.md +1 -1
  92. package/prompts/collaboration-workflow/rule-delivery.md +7 -95
  93. package/prompts/collaboration-workflow/shell-body.md +3 -23
  94. package/prompts/collaboration-workflow/turn-batching.md +4 -13
  95. package/prompts/collaboration-workflow/wip-cap.md +5 -11
  96. package/prompts/refactoring.md +1 -1
  97. package/prompts/review-rubric.md +3 -22
  98. package/prompts/review.md +15 -38
  99. package/prompts/testing-guide.md +2 -4
  100. package/scripts/adopt/adopt-logic.ts +5 -5
  101. package/scripts/adopt/adopt-toolkits.ts +4 -5
  102. package/scripts/adopt/adopt.ts +2 -3
  103. package/scripts/agent/agent-argv.ts +7 -7
  104. package/scripts/agent/agent-diagnostics.ts +2 -2
  105. package/scripts/agent/agent-exit-record.ts +1 -1
  106. package/scripts/agent/agent-headless.ts +1 -1
  107. package/scripts/agent/agent-launch-environment.ts +6 -1
  108. package/scripts/agent/agent-role-profile.ts +49 -22
  109. package/scripts/agent/agent-session-role.ts +32 -0
  110. package/scripts/agent/api-outage.ts +1 -1
  111. package/scripts/agent/claude-agent-argv.ts +4 -4
  112. package/scripts/agent/claude-result-event.ts +4 -4
  113. package/scripts/agent/codex-hooks.ts +2 -2
  114. package/scripts/agent/interactive-ask.ts +3 -6
  115. package/scripts/auto-ok/auto-ok-cli.ts +46 -60
  116. package/scripts/backlog/backlog-arrival-added.ts +34 -0
  117. package/scripts/backlog/backlog-arrival.ts +54 -17
  118. package/scripts/backlog/backlog-budget-cli.ts +34 -6
  119. package/scripts/backlog/backlog-budget.ts +17 -24
  120. package/scripts/backlog/backlog-defect-priority.ts +1 -1
  121. package/scripts/backlog/backlog-drive-args.ts +5 -4
  122. package/scripts/backlog/backlog-drive-cli.ts +14 -10
  123. package/scripts/backlog/backlog-drive-epic.ts +85 -0
  124. package/scripts/backlog/backlog-drive-launch.ts +1 -1
  125. package/scripts/backlog/backlog-drive-named-offer.ts +60 -9
  126. package/scripts/backlog/backlog-drive-named.ts +39 -9
  127. package/scripts/backlog/backlog-drive-offer-argv.ts +1 -1
  128. package/scripts/backlog/backlog-drive-restore.ts +1 -1
  129. package/scripts/backlog/backlog-drive-retrospective.ts +2 -2
  130. package/scripts/backlog/backlog-drive.ts +43 -28
  131. package/scripts/backlog/backlog-idle.ts +88 -0
  132. package/scripts/backlog/backlog-named.ts +11 -15
  133. package/scripts/backlog/backlog-next.ts +26 -30
  134. package/scripts/backlog/backlog-offer-cli.ts +28 -23
  135. package/scripts/backlog/backlog-offer.ts +7 -7
  136. package/scripts/backlog/backlog-overlap.ts +178 -0
  137. package/scripts/backlog/backlog-plan-cli.ts +14 -90
  138. package/scripts/backlog/backlog-plan-read.ts +111 -0
  139. package/scripts/backlog/backlog-plan.ts +11 -10
  140. package/scripts/backlog/backlog-pool.ts +13 -14
  141. package/scripts/backlog/backlog-rank.ts +11 -11
  142. package/scripts/backlog/backlog-ready.ts +15 -10
  143. package/scripts/backlog/backlog-scope.ts +14 -15
  144. package/scripts/backlog/backlog-stalled-cli.ts +2 -2
  145. package/scripts/backlog/backlog-stalled-detect.ts +4 -4
  146. package/scripts/backlog/backlog-stalled.ts +5 -6
  147. package/scripts/backlog/backlog-waves.ts +4 -4
  148. package/scripts/backlog/backlogrun-args.ts +74 -0
  149. package/scripts/backlog/backlogrun-cli.ts +113 -0
  150. package/scripts/backlog/backlogrun-launch.ts +178 -0
  151. package/scripts/behavior/behavior-assertion.ts +6 -8
  152. package/scripts/behavior/behavior-cli.ts +1 -1
  153. package/scripts/behavior/behavior-rules.ts +3 -3
  154. package/scripts/build/build-claude-md.ts +4 -4
  155. package/scripts/build/build-codex-hooks.ts +2 -2
  156. package/scripts/build/build-commands.ts +1 -1
  157. package/scripts/build/build-hooks.ts +5 -5
  158. package/scripts/build/build.ts +1 -1
  159. package/scripts/build/hook-bundle-stamp.ts +109 -7
  160. package/scripts/build/local-bin.ts +2 -2
  161. package/scripts/cases/cases-cli.ts +1 -1
  162. package/scripts/cases/cases-logic.ts +2 -2
  163. package/scripts/ci/composite-actions.ts +1 -2
  164. package/scripts/ci/pr-classification.ts +2 -2
  165. package/scripts/claude/workflow-destination.ts +1 -1
  166. package/scripts/clone/clone-aggregate.ts +1 -1
  167. package/scripts/clone/clone-fingerprint.ts +1 -1
  168. package/scripts/clone/clone-scan-cli.ts +1 -1
  169. package/scripts/clone/clone-scan.ts +1 -1
  170. package/scripts/config-merge/index.ts +1 -1
  171. package/scripts/config-merge/json-format.ts +1 -3
  172. package/scripts/config-merge/patch-json-array.ts +90 -0
  173. package/scripts/config-merge/patch-json-key.ts +6 -3
  174. package/scripts/config-merge/patch-json-list.ts +1 -1
  175. package/scripts/cost-runtime/codex-usage.ts +1 -1
  176. package/scripts/cost-runtime/context-cut-payback.ts +4 -5
  177. package/scripts/cost-runtime/context-cut-threshold.ts +4 -6
  178. package/scripts/cost-runtime/cost-attribute.ts +3 -3
  179. package/scripts/cost-runtime/cost-blocks.ts +3 -4
  180. package/scripts/cost-runtime/cost-cli.ts +14 -11
  181. package/scripts/cost-runtime/cost-corpus.ts +11 -11
  182. package/scripts/cost-runtime/cost-pricing.ts +4 -4
  183. package/scripts/cost-runtime/cost-tokens.ts +1 -2
  184. package/scripts/cost-runtime/cost-transcript.ts +29 -29
  185. package/scripts/cost-runtime/cost-usage.ts +6 -7
  186. package/scripts/cost-runtime/cost-verdict.ts +10 -11
  187. package/scripts/cost-runtime/own-session.ts +1 -1
  188. package/scripts/cost-runtime/transcript-cwd.ts +2 -2
  189. package/scripts/delegation/delegation-cli.ts +4 -4
  190. package/scripts/delegation/delegation-policy.ts +13 -15
  191. package/scripts/delegation/duplicate-read-guard.ts +9 -10
  192. package/scripts/delegation/fanout-cli.ts +1 -1
  193. package/scripts/delegation/fanout.ts +1 -1
  194. package/scripts/delegation/investigation-guard.ts +18 -22
  195. package/scripts/delegation/investigation-reads.ts +48 -238
  196. package/scripts/discovery/repo-discovery.ts +1 -1
  197. package/scripts/discovery/repo-map-logic.ts +1 -2
  198. package/scripts/discovery/repo-origin.ts +3 -3
  199. package/scripts/discovery/repo-party-cli.ts +2 -2
  200. package/scripts/discovery/repo-party.ts +2 -2
  201. package/scripts/doctor/doctor-consumer.ts +1 -1
  202. package/scripts/doctor/doctor-io.ts +6 -7
  203. package/scripts/doctor/doctor-logic.ts +1 -1
  204. package/scripts/doctor/doctor-ports.ts +1 -1
  205. package/scripts/doctor/doctor.ts +8 -9
  206. package/scripts/document/backlogrun-parent-read-set.ts +5 -6
  207. package/scripts/document/bash-output-cap.ts +5 -7
  208. package/scripts/document/capped-print-part.ts +1 -1
  209. package/scripts/document/capped-print.ts +1 -1
  210. package/scripts/document/document-byte-budget.ts +33 -64
  211. package/scripts/document/document-byte-check.ts +4 -4
  212. package/scripts/document/document-reachability.ts +7 -8
  213. package/scripts/document/document-read-cli.ts +2 -2
  214. package/scripts/document/document-scan.ts +26 -2
  215. package/scripts/document/document-section-cli.ts +6 -8
  216. package/scripts/document/document-section.ts +8 -12
  217. package/scripts/document/edit-files-cli.ts +3 -4
  218. package/scripts/document/entry-read-budget.ts +8 -70
  219. package/scripts/document/entry-read-set.ts +51 -34
  220. package/scripts/document/lane-child-read-set.ts +9 -9
  221. package/scripts/document/read-files-cli.ts +1 -2
  222. package/scripts/document/read-set-cli.ts +16 -19
  223. package/scripts/document/read-set-cost.ts +4 -4
  224. package/scripts/document/read-set-point-of-use.ts +28 -38
  225. package/scripts/document/read-set-pricing.ts +1 -1
  226. package/scripts/document/read-set-trim.ts +3 -3
  227. package/scripts/document/resident-budget.ts +8 -10
  228. package/scripts/epic/epic-add-body.ts +15 -18
  229. package/scripts/epic/epic-add-plan.ts +26 -28
  230. package/scripts/epic/epic-add.ts +32 -25
  231. package/scripts/epic/epic-audit-checks.ts +27 -37
  232. package/scripts/epic/epic-audit-cli.ts +21 -22
  233. package/scripts/epic/epic-audit-orphans.ts +16 -17
  234. package/scripts/epic/epic-audit-rationale.ts +10 -15
  235. package/scripts/epic/epic-audit-report.ts +2 -5
  236. package/scripts/epic/epic-audit.ts +18 -14
  237. package/scripts/epic/epic-body.ts +10 -10
  238. package/scripts/epic/epic-bundle-cli.ts +36 -34
  239. package/scripts/epic/epic-bundle-evidence.ts +5 -5
  240. package/scripts/epic/epic-bundle-gaps.ts +6 -9
  241. package/scripts/epic/epic-bundle-poll.ts +1 -1
  242. package/scripts/epic/epic-bundle-referenced.ts +11 -14
  243. package/scripts/epic/epic-bundle.ts +19 -20
  244. package/scripts/epic/epic-busy.ts +44 -21
  245. package/scripts/epic/epic-candidate-confirm.ts +15 -18
  246. package/scripts/epic/epic-chains.ts +18 -23
  247. package/scripts/epic/epic-classify.ts +11 -12
  248. package/scripts/epic/epic-cli-argv.ts +5 -6
  249. package/scripts/epic/epic-cli-remove.ts +9 -4
  250. package/scripts/epic/epic-cli.ts +38 -26
  251. package/scripts/epic/epic-close-comment.ts +14 -15
  252. package/scripts/epic/epic-close.ts +25 -29
  253. package/scripts/epic/epic-cross-repo.ts +18 -21
  254. package/scripts/epic/epic-decision.ts +14 -18
  255. package/scripts/epic/epic-fetch.ts +25 -31
  256. package/scripts/epic/epic-graph.ts +15 -17
  257. package/scripts/epic/epic-index.ts +14 -16
  258. package/scripts/epic/epic-issue.ts +9 -11
  259. package/scripts/epic/epic-label-age.ts +74 -0
  260. package/scripts/epic/epic-lane-offer.ts +35 -24
  261. package/scripts/epic/epic-nested.ts +1 -1
  262. package/scripts/epic/epic-next-read.ts +8 -8
  263. package/scripts/epic/epic-next-views.ts +12 -12
  264. package/scripts/epic/epic-next.ts +29 -33
  265. package/scripts/epic/epic-outside-blocker.ts +11 -10
  266. package/scripts/epic/epic-parse.ts +22 -24
  267. package/scripts/epic/epic-promote.ts +3 -2
  268. package/scripts/epic/epic-rank.ts +1 -1
  269. package/scripts/epic/epic-read.ts +10 -8
  270. package/scripts/epic/epic-reconcile.ts +8 -6
  271. package/scripts/epic/epic-reference.ts +5 -4
  272. package/scripts/epic/epic-relation-recheck.ts +10 -11
  273. package/scripts/epic/epic-relations.ts +9 -8
  274. package/scripts/epic/epic-remove-plan.ts +4 -5
  275. package/scripts/epic/epic-remove.ts +7 -5
  276. package/scripts/epic/epic-report.ts +18 -20
  277. package/scripts/epic/epic-run.ts +6 -5
  278. package/scripts/epic/epic-sections.ts +2 -2
  279. package/scripts/epic/epic-shape.ts +3 -3
  280. package/scripts/epic/epic-solo-stale.ts +3 -2
  281. package/scripts/epic/epic-solo.ts +8 -8
  282. package/scripts/epic/epic-triage.ts +5 -4
  283. package/scripts/epic/epic-validate.ts +8 -7
  284. package/scripts/epic/epic.ts +5 -5
  285. package/scripts/exports/unused-members-cli.ts +1 -1
  286. package/scripts/followup/followup-issue-number.ts +1 -2
  287. package/scripts/followup/git-followup-cleanup.ts +6 -7
  288. package/scripts/followup/git-followup-finish.ts +11 -13
  289. package/scripts/followup/git-followup-flush.ts +11 -7
  290. package/scripts/followup/git-followup-issue-close.ts +16 -13
  291. package/scripts/followup/git-followup-label.ts +9 -6
  292. package/scripts/followup/git-followup-merged.ts +1 -1
  293. package/scripts/followup/git-followup-pending.ts +7 -9
  294. package/scripts/followup/git-followup-stages.ts +28 -17
  295. package/scripts/followup/git-followup-workflow.ts +19 -21
  296. package/scripts/followup/git-pr-followup-checks.ts +13 -20
  297. package/scripts/followup/git-pr-followup-wrapup.ts +7 -7
  298. package/scripts/followup/git-pr-followup.ts +18 -17
  299. package/scripts/gate/core-admission.ts +2 -2
  300. package/scripts/gate/core-budget.ts +15 -26
  301. package/scripts/gate/gate-ledger.ts +114 -0
  302. package/scripts/gate/gate-log.ts +7 -9
  303. package/scripts/gate/gate-plan.ts +70 -35
  304. package/scripts/gate/gate-report.ts +14 -15
  305. package/scripts/gate/gate-skip.ts +11 -13
  306. package/scripts/gate/gate-steps.ts +5 -1
  307. package/scripts/gate/gate-tree.ts +3 -4
  308. package/scripts/gate/hook-gate-reuse.ts +9 -9
  309. package/scripts/gate/machine-capacity.ts +168 -30
  310. package/scripts/gate/pre-commit-type-check.ts +4 -4
  311. package/scripts/gate/project-checks.ts +12 -4
  312. package/scripts/gate/scoped-green.ts +11 -18
  313. package/scripts/gate/type-check-command.ts +2 -2
  314. package/scripts/gate/type-check-step.ts +4 -4
  315. package/scripts/gate/verification-gate.ts +53 -51
  316. package/scripts/gh/gh-spawn.ts +2 -2
  317. package/scripts/gh/git-ai-review-scan.ts +3 -2
  318. package/scripts/gh/git-gh-api-path.ts +10 -11
  319. package/scripts/gh/git-gh-exec.ts +43 -48
  320. package/scripts/gh/git-gh-failure.ts +6 -9
  321. package/scripts/gh/git-gh-helpers.ts +1 -1
  322. package/scripts/gh/git-gh-issue-list.ts +15 -19
  323. package/scripts/gh/git-gh-issue-read.ts +43 -60
  324. package/scripts/gh/git-gh-issue-rest.ts +14 -15
  325. package/scripts/gh/git-gh-issue-write.ts +52 -40
  326. package/scripts/gh/git-gh-issue.ts +23 -24
  327. package/scripts/gh/git-gh-pr-auto-merge.ts +3 -3
  328. package/scripts/gh/git-gh-pr-read.ts +46 -50
  329. package/scripts/gh/git-gh-pr-rest.ts +23 -26
  330. package/scripts/gh/git-gh-pr-review.ts +2 -2
  331. package/scripts/gh/git-gh-pr-rollup.ts +4 -4
  332. package/scripts/gh/git-gh-pr-snapshot.ts +8 -10
  333. package/scripts/gh/git-gh-pr.ts +16 -16
  334. package/scripts/gh/git-gh-reachability.ts +11 -12
  335. package/scripts/gh/git-gh-repo.ts +2 -3
  336. package/scripts/gh/git-gh-rest-state.ts +1 -1
  337. package/scripts/gh/git-pr-ai-review.ts +6 -5
  338. package/scripts/gh/git-pr-checks-eval.ts +28 -30
  339. package/scripts/gh/git-pr-checks-parse.ts +14 -16
  340. package/scripts/gh/git-pr-checks-watch.ts +17 -17
  341. package/scripts/gh/git-pr-checks.ts +20 -23
  342. package/scripts/gh/git-pr-coderabbit.ts +8 -6
  343. package/scripts/gh/git-pr-confirmation.ts +5 -5
  344. package/scripts/gh/git-pr-managed-config.ts +7 -9
  345. package/scripts/gh/git-pr-messages.ts +1 -1
  346. package/scripts/gh/git-pr.ts +15 -16
  347. package/scripts/gh/github-issue-url.ts +8 -9
  348. package/scripts/git/base-tree.ts +66 -0
  349. package/scripts/git/change-base.ts +42 -2
  350. package/scripts/git/changed-file-scope.ts +5 -5
  351. package/scripts/git/changed-paths.ts +1 -2
  352. package/scripts/git/constants.ts +2 -2
  353. package/scripts/git/git-branch.ts +1 -1
  354. package/scripts/git/git-closes-keyword.ts +3 -3
  355. package/scripts/git/git-command.ts +53 -41
  356. package/scripts/git/git-common-directory.ts +3 -3
  357. package/scripts/git/git-diff-reads.ts +14 -15
  358. package/scripts/git/git-error.ts +1 -1
  359. package/scripts/git/git-execa-error.ts +1 -2
  360. package/scripts/git/git-issue.ts +10 -8
  361. package/scripts/git/git-location-environment.ts +3 -4
  362. package/scripts/git/git-ls-remote.ts +6 -8
  363. package/scripts/git/git-pre-push-hook.ts +11 -10
  364. package/scripts/git/git-preflight.ts +5 -5
  365. package/scripts/git/git-push-transport.ts +2 -2
  366. package/scripts/git/git-remote-branch.ts +1 -2
  367. package/scripts/git/git-schemas.ts +16 -23
  368. package/scripts/git/git-spawn-sync.ts +1 -1
  369. package/scripts/git/git-spawn.ts +37 -14
  370. package/scripts/git/git-ssh-keepalive.ts +12 -5
  371. package/scripts/git/git-staging.ts +7 -8
  372. package/scripts/git/git-workflow.ts +1 -1
  373. package/scripts/git/git-worktree.ts +35 -27
  374. package/scripts/git/gone-branch.ts +2 -2
  375. package/scripts/git/listing-cutoff.ts +1 -2
  376. package/scripts/git/lockfile-sync.ts +65 -0
  377. package/scripts/git/main-merge-guard.ts +1 -2
  378. package/scripts/git/main-merge.ts +7 -7
  379. package/scripts/git/main-sync.ts +23 -8
  380. package/scripts/git/parse-json-array.ts +18 -23
  381. package/scripts/git/repository-lock.ts +34 -2
  382. package/scripts/git/stash/git-stash.ts +4 -5
  383. package/scripts/git/stash/stash-orphans.ts +5 -3
  384. package/scripts/git/stash/stash-pop-args.ts +1 -1
  385. package/scripts/git/stash/stash-pop-cli.ts +3 -3
  386. package/scripts/git/stash/stash-sweep-lock.ts +2 -2
  387. package/scripts/hooks/batch-guard.ts +11 -13
  388. package/scripts/hooks/check-commit-message.ts +12 -9
  389. package/scripts/hooks/codex-hook-adapter.ts +16 -10
  390. package/scripts/hooks/edited-cspell.ts +3 -4
  391. package/scripts/hooks/format-edited-cli.ts +1 -1
  392. package/scripts/hooks/format-edited-file.ts +11 -17
  393. package/scripts/hooks/format-rewrite-notice.ts +19 -17
  394. package/scripts/hooks/pre-push-unit.ts +10 -14
  395. package/scripts/hooks/pretool-guard-cli.ts +4 -4
  396. package/scripts/hooks/pretool-guard.ts +93 -18
  397. package/scripts/hooks/reserved-run.ts +2 -2
  398. package/scripts/hooks/step-zero-notice.ts +1 -1
  399. package/scripts/hooks/stop-guard.ts +21 -10
  400. package/scripts/init/basic-path-migration.ts +2 -2
  401. package/scripts/init/claude-kit-only-settings.ts +2 -2
  402. package/scripts/init/claude-plugin-config.ts +2 -2
  403. package/scripts/init/distributed-paths.ts +4 -4
  404. package/scripts/init/hook-command-rewrite.ts +3 -3
  405. package/scripts/init/hook-launch.ts +5 -5
  406. package/scripts/init/init-actions.ts +13 -0
  407. package/scripts/init/init-ai-copy.ts +11 -11
  408. package/scripts/init/init-bootstrap.ts +3 -3
  409. package/scripts/init/init-copy-content.ts +4 -4
  410. package/scripts/init/init-logic-json-merge.ts +7 -9
  411. package/scripts/init/init-logic-migrate.ts +1 -1
  412. package/scripts/init/init-logic-templates.ts +1 -1
  413. package/scripts/init/init-logic-workspace.ts +4 -4
  414. package/scripts/init/init-logic-yaml-merge.ts +2 -2
  415. package/scripts/init/init-logic.ts +19 -22
  416. package/scripts/init/init.ts +7 -7
  417. package/scripts/init/kit-base-preset.ts +1 -1
  418. package/scripts/init/kit-setup-state.ts +1 -1
  419. package/scripts/init/kit-written-paths.ts +1 -2
  420. package/scripts/init/package-manager-pin.ts +1 -1
  421. package/scripts/init/project-profile-cli.ts +1 -1
  422. package/scripts/init/project-profile.ts +3 -3
  423. package/scripts/init/session-language-environment.ts +1 -1
  424. package/scripts/init/start-exec.ts +3 -4
  425. package/scripts/init/start-plan.ts +2 -2
  426. package/scripts/init/start-setup-pr.ts +3 -2
  427. package/scripts/init/start-steps.ts +2 -2
  428. package/scripts/init/tsconfig-preset-migration.ts +1 -1
  429. package/scripts/init/vscode-tasks.ts +62 -0
  430. package/scripts/issue/baseline-measure.ts +2 -2
  431. package/scripts/issue/behavior-change-lint.ts +2 -2
  432. package/scripts/issue/defect-rate-cli.ts +6 -7
  433. package/scripts/issue/defect-rate.ts +37 -27
  434. package/scripts/issue/git-next-issues.ts +9 -8
  435. package/scripts/issue/issue-auto-ok.ts +24 -11
  436. package/scripts/issue/issue-backlinks-cli.ts +5 -5
  437. package/scripts/issue/issue-backlinks.ts +6 -6
  438. package/scripts/issue/issue-cite-cli.ts +20 -18
  439. package/scripts/issue/issue-cite.ts +18 -8
  440. package/scripts/issue/issue-closing-pr.ts +4 -4
  441. package/scripts/issue/issue-comment-cli.ts +6 -4
  442. package/scripts/issue/issue-file-cli.ts +52 -15
  443. package/scripts/issue/issue-file-fold.ts +155 -0
  444. package/scripts/issue/issue-file.ts +9 -6
  445. package/scripts/issue/issue-fold-cli.ts +14 -9
  446. package/scripts/issue/issue-fold.ts +23 -8
  447. package/scripts/issue/issue-labels.ts +34 -38
  448. package/scripts/issue/issue-lint-cli.ts +2 -2
  449. package/scripts/issue/issue-lint.ts +1 -1
  450. package/scripts/issue/issue-merged.ts +10 -4
  451. package/scripts/issue/issue-number-shape.ts +27 -0
  452. package/scripts/issue/issue-rank.ts +1 -1
  453. package/scripts/issue/issue-read-cli.ts +4 -5
  454. package/scripts/issue/issue-read.ts +4 -5
  455. package/scripts/issue/issue-reference.ts +5 -5
  456. package/scripts/issue/issue-release-cli.ts +17 -7
  457. package/scripts/issue/issue-release.ts +3 -3
  458. package/scripts/issue/issue-report-failures.ts +7 -4
  459. package/scripts/issue/issue-scout-cli.ts +11 -11
  460. package/scripts/issue/issue-scout-closed.ts +4 -4
  461. package/scripts/issue/issue-scout.ts +4 -5
  462. package/scripts/issue/issue-state-cli.ts +17 -10
  463. package/scripts/issue/issue-state.ts +12 -13
  464. package/scripts/issue/issue-wip.ts +7 -7
  465. package/scripts/issue/markdown-section.ts +3 -3
  466. package/scripts/issue/measure-rerun-cli.ts +10 -9
  467. package/scripts/issue/reproduction-measure.ts +3 -3
  468. package/scripts/issue/session-cite.ts +56 -0
  469. package/scripts/josh/agent-session-environment.ts +10 -8
  470. package/scripts/josh/cli-body.ts +2 -2
  471. package/scripts/josh/command-suggest.ts +1 -1
  472. package/scripts/josh/file-map-stamp.ts +20 -23
  473. package/scripts/josh/hook-decision.ts +24 -28
  474. package/scripts/josh/josh-command-map.ts +4 -1
  475. package/scripts/josh/josh-command-types.ts +30 -35
  476. package/scripts/josh/josh-commands-ai.ts +6 -6
  477. package/scripts/josh/josh-commands-backlog.ts +15 -3
  478. package/scripts/josh/josh-commands-clone.ts +1 -1
  479. package/scripts/josh/josh-commands-development.ts +25 -4
  480. package/scripts/josh/josh-commands-document.ts +3 -3
  481. package/scripts/josh/josh-commands-guard.ts +3 -3
  482. package/scripts/josh/josh-commands-issue.ts +4 -5
  483. package/scripts/josh/josh-commands-lane.ts +14 -4
  484. package/scripts/josh/josh-commands-lint.ts +1 -1
  485. package/scripts/josh/josh-commands-run.ts +20 -6
  486. package/scripts/josh/josh-commands-split.ts +1 -2
  487. package/scripts/josh/josh-commands-versioning.ts +5 -5
  488. package/scripts/josh/josh-commands-workflow.ts +30 -22
  489. package/scripts/josh/josh-environment-file.ts +1 -1
  490. package/scripts/josh/josh-in-process.ts +3 -3
  491. package/scripts/josh/josh-logic.ts +6 -7
  492. package/scripts/josh/josh-run.ts +3 -3
  493. package/scripts/josh/josh-verdict.ts +9 -12
  494. package/scripts/josh/josh.ts +3 -3
  495. package/scripts/josh/kit-only.ts +2 -2
  496. package/scripts/josh/path-decision.ts +3 -3
  497. package/scripts/josh/platform-temporary.ts +7 -5
  498. package/scripts/josh/process-identity.ts +24 -6
  499. package/scripts/josh/process-owner.ts +4 -4
  500. package/scripts/josh/session-language-cli.ts +53 -11
  501. package/scripts/josh/session-language.ts +1 -1
  502. package/scripts/josh/stamp-file.ts +48 -29
  503. package/scripts/josh/stamp-record.ts +57 -0
  504. package/scripts/lane/lane-await.ts +35 -11
  505. package/scripts/lane/lane-cache.ts +6 -6
  506. package/scripts/lane/lane-capacity.ts +32 -17
  507. package/scripts/lane/lane-child-invocation.ts +17 -15
  508. package/scripts/lane/lane-child-marker.ts +12 -12
  509. package/scripts/lane/lane-cli.ts +12 -13
  510. package/scripts/lane/lane-close.ts +6 -6
  511. package/scripts/lane/lane-dispatch.ts +61 -72
  512. package/scripts/lane/lane-environment.ts +5 -5
  513. package/scripts/lane/lane-guard-policy.ts +7 -21
  514. package/scripts/lane/lane-handoff.ts +2 -2
  515. package/scripts/lane/lane-install.ts +9 -10
  516. package/scripts/lane/lane-launch-cli.ts +13 -8
  517. package/scripts/lane/lane-ledger.ts +73 -11
  518. package/scripts/lane/lane-leftover.ts +2 -2
  519. package/scripts/lane/lane-limit-cli.ts +160 -0
  520. package/scripts/lane/lane-limit-override.ts +74 -0
  521. package/scripts/lane/lane-load.ts +19 -68
  522. package/scripts/lane/lane-measure-cli.ts +15 -25
  523. package/scripts/lane/lane-occupancy.ts +6 -4
  524. package/scripts/lane/lane-open.ts +20 -19
  525. package/scripts/lane/lane-output.ts +4 -3
  526. package/scripts/lane/lane-paths.ts +12 -11
  527. package/scripts/lane/lane-phase.ts +33 -0
  528. package/scripts/lane/lane-reap.ts +2 -2
  529. package/scripts/lane/lane-registry.ts +16 -15
  530. package/scripts/lane/lane-relaunch.ts +9 -9
  531. package/scripts/lane/lane-report.ts +5 -4
  532. package/scripts/lane/lane-resume.ts +2 -2
  533. package/scripts/lane/lane-sampler.ts +55 -0
  534. package/scripts/lane/lane-seed.ts +7 -7
  535. package/scripts/lane/lane-stage-stats.ts +135 -0
  536. package/scripts/lane/lane-start-point.ts +8 -11
  537. package/scripts/lane/lane-stats.ts +60 -15
  538. package/scripts/lane/lane-stray.ts +1 -1
  539. package/scripts/lane/lane-vacant.ts +1 -1
  540. package/scripts/lane/openai-lane-supervisor-decision.ts +3 -7
  541. package/scripts/lane/openai-lane-supervisor-owner.ts +3 -9
  542. package/scripts/lane/openai-review-broker.ts +2 -4
  543. package/scripts/lib/ancestor-directories.ts +1 -1
  544. package/scripts/lib/bounded-pool.ts +2 -2
  545. package/scripts/lib/buffered-process.ts +4 -6
  546. package/scripts/lib/caddy-logs.sh +0 -0
  547. package/scripts/lib/cli-flags.ts +39 -6
  548. package/scripts/lib/error-message.ts +1 -1
  549. package/scripts/lib/json-value.ts +17 -3
  550. package/scripts/lib/poll.ts +1 -1
  551. package/scripts/lib/status-icons.ts +3 -3
  552. package/scripts/lib/timed-fetch.ts +1 -1
  553. package/scripts/lib/timeouts.ts +1 -1
  554. package/scripts/lines/bytes-command.ts +3 -4
  555. package/scripts/lines/effective-limit.ts +25 -12
  556. package/scripts/lines/line-budget.ts +47 -55
  557. package/scripts/lines/line-targets.ts +6 -2
  558. package/scripts/lines/lines-command.ts +3 -3
  559. package/scripts/lint/cspell-cached.ts +1 -1
  560. package/scripts/lint/cycle-recheck.ts +122 -0
  561. package/scripts/lint/format.ts +1 -2
  562. package/scripts/lint/lint-parallel.ts +34 -19
  563. package/scripts/lint/lint-related-scope.ts +25 -15
  564. package/scripts/lint/lint-related.ts +6 -7
  565. package/scripts/managed-marker/index.ts +1 -1
  566. package/scripts/managed-marker/managed-marker-logic.ts +1 -2
  567. package/scripts/notify/git-notify.ts +9 -7
  568. package/scripts/notify/telegram-notify.ts +53 -37
  569. package/scripts/notify/telegram-test-logic.ts +3 -3
  570. package/scripts/notify/telegram-test.ts +45 -30
  571. package/scripts/observations/observation-ledger-home.ts +14 -8
  572. package/scripts/observations/observation-ledger-line.ts +3 -2
  573. package/scripts/observations/observation-ledger-migrate.ts +3 -4
  574. package/scripts/observations/observation-ledger-prepare.ts +4 -4
  575. package/scripts/observations/observation-ledger.ts +14 -15
  576. package/scripts/observations/observation-record-cli.ts +83 -0
  577. package/scripts/observations/observation-record.ts +91 -0
  578. package/scripts/observations/observations-flush-cli.ts +1 -1
  579. package/scripts/observations/observations-flush-landing.ts +7 -6
  580. package/scripts/observations/observations-flush.ts +26 -27
  581. package/scripts/overrides/overrides-check.ts +18 -8
  582. package/scripts/package/package-scout-cli.ts +1 -1
  583. package/scripts/package/package-scout-format.ts +2 -2
  584. package/scripts/package/package-scout.ts +1 -1
  585. package/scripts/propagate/propagate-git-failure.ts +1 -1
  586. package/scripts/propagate/propagate-git.ts +7 -7
  587. package/scripts/propagate/propagate-plan.ts +2 -2
  588. package/scripts/propagate/propagate-publish.ts +2 -3
  589. package/scripts/propagate/propagate-run.ts +5 -7
  590. package/scripts/propagate/propagate-select.ts +1 -1
  591. package/scripts/propagate/propagate-steps.ts +19 -20
  592. package/scripts/propagate/propagate-targets.ts +6 -10
  593. package/scripts/propagate/propagate.ts +5 -5
  594. package/scripts/refactor/import-graph.ts +1 -1
  595. package/scripts/refactor/refactor-lint.ts +4 -10
  596. package/scripts/refactor/refactor-scan-cli.ts +1 -1
  597. package/scripts/refactor/refactor-scan.ts +2 -2
  598. package/scripts/refactor/refactor-targets.ts +1 -1
  599. package/scripts/release/github-release-cli.ts +25 -3
  600. package/scripts/release/github-release-runs.ts +1 -1
  601. package/scripts/release/release-cli.ts +21 -4
  602. package/scripts/release/release-history.ts +6 -10
  603. package/scripts/release/release-plan.ts +3 -3
  604. package/scripts/release/release-progress.ts +3 -4
  605. package/scripts/release/release-publish.ts +8 -9
  606. package/scripts/release/release-scope-cli.ts +8 -10
  607. package/scripts/release/release-tag.ts +6 -8
  608. package/scripts/release/release-worktree.ts +5 -5
  609. package/scripts/repo/auto-merge-setting-logic.ts +7 -9
  610. package/scripts/repo/auto-merge-setting.ts +1 -1
  611. package/scripts/repo/repo-setting.ts +4 -4
  612. package/scripts/repo/repository-labels.ts +1 -1
  613. package/scripts/repo/required-checks-logic.ts +3 -3
  614. package/scripts/repo/required-checks-report.ts +1 -1
  615. package/scripts/repo/ruleset-check-cli.ts +1 -1
  616. package/scripts/repo/ruleset-check.ts +1 -1
  617. package/scripts/report/report-format-reference.ts +26 -0
  618. package/scripts/report/report-lint-cli.ts +2 -2
  619. package/scripts/report/report-lint.ts +16 -2
  620. package/scripts/review/disposition-cli.ts +2 -2
  621. package/scripts/review/disposition-logic.ts +1 -1
  622. package/scripts/review/live-evidence.ts +9 -6
  623. package/scripts/review/review-attest-cli.ts +1 -2
  624. package/scripts/review/review-attest.ts +3 -3
  625. package/scripts/review/review-brief-cli.ts +19 -20
  626. package/scripts/review/review-brief.ts +29 -32
  627. package/scripts/review/review-checkout.ts +2 -2
  628. package/scripts/review/review-diff-parts.ts +3 -5
  629. package/scripts/review/review-diff-write.ts +1 -1
  630. package/scripts/review/review-finding-ledger.ts +7 -4
  631. package/scripts/review/review-findings-cli.ts +2 -2
  632. package/scripts/review/review-level.ts +4 -7
  633. package/scripts/review/review-record-cli.ts +73 -16
  634. package/scripts/review/review-record.ts +5 -4
  635. package/scripts/review/review-round2-cli.ts +2 -3
  636. package/scripts/review/review-round2.ts +13 -21
  637. package/scripts/review/review-stamps.ts +9 -71
  638. package/scripts/review/review-tree.ts +4 -5
  639. package/scripts/rules/bash-triggers.ts +4 -4
  640. package/scripts/rules/decision-oracle-batch.ts +5 -6
  641. package/scripts/rules/decision-oracle-stage.ts +1 -1
  642. package/scripts/rules/decision-oracle-tokens.ts +1 -2
  643. package/scripts/rules/decision-oracle.ts +2 -2
  644. package/scripts/rules/delivered-rules.ts +61 -406
  645. package/scripts/rules/destructive-command.ts +2 -2
  646. package/scripts/rules/direct-filing.ts +4 -4
  647. package/scripts/rules/direct-pr-create.ts +2 -2
  648. package/scripts/rules/early-heartbeat.ts +15 -19
  649. package/scripts/rules/file-body.ts +5 -6
  650. package/scripts/rules/filing-cap.ts +6 -7
  651. package/scripts/rules/filing-offer.ts +1 -1
  652. package/scripts/rules/firing-point.ts +6 -6
  653. package/scripts/rules/gh-api.ts +2 -2
  654. package/scripts/rules/git-argv.ts +3 -3
  655. package/scripts/rules/git-force.ts +2 -2
  656. package/scripts/rules/hook-context-line.ts +31 -0
  657. package/scripts/rules/implementation-cut-verdict.ts +5 -8
  658. package/scripts/rules/implementation-cut.ts +35 -32
  659. package/scripts/rules/index-guard.ts +2 -2
  660. package/scripts/rules/issue-citation.ts +7 -7
  661. package/scripts/rules/issue-comments.ts +21 -13
  662. package/scripts/rules/josh-git-bare.ts +2 -2
  663. package/scripts/rules/lane-background.ts +14 -16
  664. package/scripts/rules/lane-carry-conflict.ts +41 -5
  665. package/scripts/rules/lane-interactive-ask.ts +6 -9
  666. package/scripts/rules/lane-park.ts +12 -16
  667. package/scripts/rules/lane-split-park.ts +1 -2
  668. package/scripts/rules/lane-switch-main.ts +10 -13
  669. package/scripts/rules/last-prompt.ts +1 -1
  670. package/scripts/rules/oracle-consulted.ts +5 -5
  671. package/scripts/rules/oracle-firing.ts +6 -9
  672. package/scripts/rules/oracle-list-cli.ts +2 -2
  673. package/scripts/rules/permission-guards.ts +2 -2
  674. package/scripts/rules/piped-verification.ts +79 -9
  675. package/scripts/rules/poll-loop.ts +9 -11
  676. package/scripts/rules/pre-gate-cut.ts +33 -30
  677. package/scripts/rules/prior-comment-read.ts +3 -3
  678. package/scripts/rules/protected-files.ts +25 -13
  679. package/scripts/rules/raw-field-body.ts +3 -4
  680. package/scripts/rules/reply-language.ts +1 -1
  681. package/scripts/rules/rule-body-guard.ts +10 -12
  682. package/scripts/rules/rule-guard.ts +1 -1
  683. package/scripts/rules/rule-list.ts +51 -0
  684. package/scripts/rules/rule-registry-rows.ts +282 -0
  685. package/scripts/rules/rule-registry.ts +109 -0
  686. package/scripts/rules/rule-value-cache.ts +2 -2
  687. package/scripts/rules/rule-value-cli.ts +6 -4
  688. package/scripts/rules/rule-value.ts +61 -22
  689. package/scripts/rules/run-tail-rule.ts +11 -15
  690. package/scripts/rules/shell-body-trigger.ts +7 -7
  691. package/scripts/rules/shell-segments.ts +2 -4
  692. package/scripts/rules/stop-rules.ts +54 -41
  693. package/scripts/rules/tail-commands.ts +1 -1
  694. package/scripts/rules/test-declared-commit.ts +2 -2
  695. package/scripts/rules/third-party-write.ts +3 -3
  696. package/scripts/rules/worktree-guard.ts +12 -5
  697. package/scripts/run/add/run-add-cli.ts +165 -0
  698. package/scripts/run/add/run-add.ts +124 -0
  699. package/scripts/run/board/run-board-cli.ts +207 -0
  700. package/scripts/run/board/run-board-closed.ts +95 -0
  701. package/scripts/run/board/run-board-every.ts +60 -0
  702. package/scripts/run/board/run-board-fetch.ts +38 -0
  703. package/scripts/run/board/run-board-fit.ts +219 -0
  704. package/scripts/run/board/run-board-github.ts +162 -0
  705. package/scripts/run/board/run-board-header.ts +275 -0
  706. package/scripts/run/board/run-board-kind.ts +35 -0
  707. package/scripts/run/board/run-board-labels.ts +299 -0
  708. package/scripts/run/board/run-board-layout.ts +222 -0
  709. package/scripts/run/board/run-board-link.ts +31 -0
  710. package/scripts/run/board/run-board-machine.ts +198 -0
  711. package/scripts/run/board/run-board-notes.ts +103 -0
  712. package/scripts/run/board/run-board-phase.ts +136 -0
  713. package/scripts/run/board/run-board-plan.ts +129 -0
  714. package/scripts/run/board/run-board-read.ts +62 -0
  715. package/scripts/run/board/run-board-render-legend.ts +82 -0
  716. package/scripts/run/board/run-board-render-notes.ts +77 -0
  717. package/scripts/run/board/run-board-render-slot.ts +50 -0
  718. package/scripts/run/board/run-board-render.ts +407 -0
  719. package/scripts/run/board/run-board-scope.ts +17 -0
  720. package/scripts/run/board/run-board-screen.ts +43 -0
  721. package/scripts/run/board/run-board-span.ts +66 -0
  722. package/scripts/run/board/run-board-spin.ts +115 -0
  723. package/scripts/run/board/run-board-state.ts +113 -0
  724. package/scripts/run/board/run-board-status.ts +279 -0
  725. package/scripts/run/board/run-board-tick.ts +210 -0
  726. package/scripts/run/board/run-board-track.ts +22 -0
  727. package/scripts/run/board/run-board-usage-read.ts +255 -0
  728. package/scripts/run/board/run-board-usage-rusage.ts +124 -0
  729. package/scripts/run/board/run-board-usage-text.ts +80 -0
  730. package/scripts/run/board/run-board-usage.ts +165 -0
  731. package/scripts/run/carry/run-carry-added.ts +62 -0
  732. package/scripts/run/carry/run-carry-args.ts +25 -22
  733. package/scripts/run/carry/run-carry-change.ts +1 -1
  734. package/scripts/run/carry/run-carry-cli.ts +71 -48
  735. package/scripts/run/carry/run-carry-conversation.ts +6 -7
  736. package/scripts/run/carry/run-carry-ended.ts +85 -0
  737. package/scripts/run/carry/run-carry-reclaim.ts +1 -1
  738. package/scripts/run/carry/run-carry-stash.ts +3 -2
  739. package/scripts/run/carry/run-carry-streak.ts +8 -10
  740. package/scripts/run/carry/run-carry.ts +85 -89
  741. package/scripts/run/cut/run-cut-args.ts +7 -7
  742. package/scripts/run/cut/run-cut-cli.ts +54 -36
  743. package/scripts/run/cut/run-cut-handoff.ts +15 -15
  744. package/scripts/run/cut/run-cut-report.ts +37 -16
  745. package/scripts/run/cut/run-cut.ts +63 -77
  746. package/scripts/run/detached-launch.ts +35 -50
  747. package/scripts/run/entry/run-entry-cli.ts +48 -27
  748. package/scripts/run/entry/run-entry-stop.ts +7 -9
  749. package/scripts/run/entry/run-entry.ts +5 -6
  750. package/scripts/run/event/run-event-cli.ts +5 -6
  751. package/scripts/run/event/run-event-filed.ts +69 -0
  752. package/scripts/run/event/run-event-follow.ts +3 -3
  753. package/scripts/run/event/run-event-plan.ts +38 -0
  754. package/scripts/run/event/run-event-render.ts +9 -4
  755. package/scripts/run/event/run-event-scope.ts +47 -18
  756. package/scripts/run/event/run-event-stream-emit.ts +64 -11
  757. package/scripts/run/event/run-event-stream.ts +171 -46
  758. package/scripts/run/event/run-event-watch.ts +4 -6
  759. package/scripts/run/hold/run-hold-cli.ts +65 -62
  760. package/scripts/run/hold/run-hold.ts +88 -46
  761. package/scripts/run/merge/run-merge-cli.ts +116 -77
  762. package/scripts/run/merge/run-merge-collect.ts +107 -0
  763. package/scripts/run/merge/run-merge-steps.ts +112 -65
  764. package/scripts/run/merge/run-merge-token.ts +30 -0
  765. package/scripts/run/merge/run-merge.ts +31 -22
  766. package/scripts/run/progress/run-progress-args.ts +4 -4
  767. package/scripts/run/progress/run-progress-cli.ts +39 -50
  768. package/scripts/run/progress/run-progress-clock.ts +25 -32
  769. package/scripts/run/progress/run-progress-config.ts +6 -9
  770. package/scripts/run/progress/run-progress-read.ts +9 -10
  771. package/scripts/run/progress/run-progress.ts +48 -53
  772. package/scripts/run/review/run-review-cli.ts +6 -6
  773. package/scripts/run/review/run-review-steps.ts +6 -6
  774. package/scripts/run/review/run-review.ts +9 -11
  775. package/scripts/run/run-cli-fault.ts +29 -0
  776. package/scripts/run/run-ending-cli.ts +3 -3
  777. package/scripts/run/run-ending.ts +10 -14
  778. package/scripts/run/run-halfrun-resume.ts +6 -8
  779. package/scripts/run/run-headless.ts +25 -12
  780. package/scripts/run/run-invocation.ts +17 -22
  781. package/scripts/run/run-label.ts +7 -5
  782. package/scripts/run/run-liveness-cli.ts +19 -6
  783. package/scripts/run/run-liveness.ts +27 -38
  784. package/scripts/run/run-next-cli.ts +5 -9
  785. package/scripts/run/run-next.ts +4 -5
  786. package/scripts/run/run-parent-cut-hook.ts +10 -12
  787. package/scripts/run/run-preflight.ts +25 -29
  788. package/scripts/run/run-prep-cli.ts +17 -13
  789. package/scripts/run/run-prep-locate.ts +4 -5
  790. package/scripts/run/run-prep.ts +7 -10
  791. package/scripts/run/run-prrun-resume.ts +2 -2
  792. package/scripts/run/run-report-cli.ts +4 -4
  793. package/scripts/run/run-report.ts +9 -14
  794. package/scripts/run/run-retrospective.ts +3 -3
  795. package/scripts/run/run-section.ts +42 -0
  796. package/scripts/run/run-stage-read.ts +2 -2
  797. package/scripts/run/run-stage.ts +6 -4
  798. package/scripts/run/run-status-cli.ts +7 -5
  799. package/scripts/run/run-status.ts +6 -7
  800. package/scripts/run/run-step-cli.ts +13 -15
  801. package/scripts/run/run-step.ts +58 -47
  802. package/scripts/run/run-stop-notify.ts +7 -8
  803. package/scripts/run/run-stranded-cli.ts +1 -1
  804. package/scripts/run/run-stranded-detect.ts +4 -4
  805. package/scripts/run/run-stranded.ts +11 -13
  806. package/scripts/run/run-tail-cli.ts +15 -16
  807. package/scripts/run/run-tail.ts +14 -33
  808. package/scripts/run/run-watcher-guard-cli.ts +3 -4
  809. package/scripts/run/run-watcher-guard.ts +11 -12
  810. package/scripts/run/run-watcher-hook.ts +6 -12
  811. package/scripts/run/ship/run-ship-cli.ts +67 -33
  812. package/scripts/run/ship/run-ship-detach.ts +15 -13
  813. package/scripts/run/ship/run-ship-lock.ts +1 -1
  814. package/scripts/run/ship/run-ship-next.ts +7 -8
  815. package/scripts/run/ship/run-ship-pre-detach.ts +27 -11
  816. package/scripts/run/ship/run-ship-preflight.ts +10 -11
  817. package/scripts/run/ship/run-ship-probe.ts +4 -4
  818. package/scripts/run/ship/run-ship-return.ts +1 -1
  819. package/scripts/run/ship/run-ship-review-steps.ts +43 -24
  820. package/scripts/run/ship/run-ship-review.ts +12 -14
  821. package/scripts/run/ship/run-ship-scoped.ts +15 -6
  822. package/scripts/run/ship/run-ship-stage.ts +80 -26
  823. package/scripts/run/ship/run-ship-steps.ts +26 -16
  824. package/scripts/run/ship/run-ship-stop-text.ts +4 -2
  825. package/scripts/run/ship/run-ship-sync.ts +9 -8
  826. package/scripts/run/ship/run-ship.ts +17 -32
  827. package/scripts/run/tidy/run-tidy-cli.ts +9 -5
  828. package/scripts/run/tidy/run-tidy-lanes.ts +18 -7
  829. package/scripts/run/tidy/run-tidy-stashes.ts +8 -8
  830. package/scripts/run/tidy/run-tidy.ts +4 -3
  831. package/scripts/run/wake/run-wake-cli.ts +27 -32
  832. package/scripts/run/wake/run-wake-describe.ts +24 -28
  833. package/scripts/run/wake/run-wake-driver.ts +14 -14
  834. package/scripts/run/wake/run-wake-handoff.ts +6 -6
  835. package/scripts/run/wake/run-wake-loop.ts +9 -9
  836. package/scripts/run/wake/run-wake-restart.ts +4 -5
  837. package/scripts/run/wake/run-wake-session.ts +23 -27
  838. package/scripts/run/wake/run-wake.ts +57 -279
  839. package/scripts/safe-chain/ci-installer-pin.ts +3 -3
  840. package/scripts/safe-chain/pack-hook.ts +2 -2
  841. package/scripts/safe-chain/preinstall-command.ts +2 -2
  842. package/scripts/security/security-audit-logic.ts +1 -1
  843. package/scripts/security/security-audit-provision-logic.ts +1 -1
  844. package/scripts/security/security-audit-provision.ts +2 -2
  845. package/scripts/security/security-audit.ts +5 -5
  846. package/scripts/security/security-updates-logic.ts +2 -3
  847. package/scripts/security/security-updates.ts +2 -4
  848. package/scripts/self-sync-guard/index.ts +1 -1
  849. package/scripts/self-sync-guard/self-sync-guard-logic.ts +2 -2
  850. package/scripts/self-sync-guard/self-sync-refusal.ts +1 -1
  851. package/scripts/sonar/sonar-hotspots-cli.ts +1 -1
  852. package/scripts/sonar/sonar-hotspots.ts +1 -1
  853. package/scripts/sonar/sonar-new-code-cli.ts +1 -1
  854. package/scripts/sonar/sonar-new-code.ts +1 -1
  855. package/scripts/sonar/sonar-project.ts +1 -1
  856. package/scripts/split/split-assess-cli.ts +1 -1
  857. package/scripts/split/split-assess.ts +3 -3
  858. package/scripts/sync/directory-copy-guard.ts +2 -3
  859. package/scripts/sync/managed-config-scope-cli.ts +1 -2
  860. package/scripts/sync/managed-config-scope.ts +4 -4
  861. package/scripts/sync/plugin-skill-directories.ts +2 -2
  862. package/scripts/sync/reconcile-templates.ts +17 -8
  863. package/scripts/sync/removed-skill-manifest.ts +2 -3
  864. package/scripts/sync/sync-ai-files.ts +7 -7
  865. package/scripts/sync/sync-configs.ts +30 -3
  866. package/scripts/sync/sync-hook-safety.ts +2 -2
  867. package/scripts/sync/sync.ts +23 -10
  868. package/scripts/sync/synced-paths.ts +2 -1
  869. package/scripts/sync/workflow-pin-logic.ts +1 -1
  870. package/scripts/test/test-declared-changed.ts +4 -4
  871. package/scripts/test/test-declared-logic.ts +2 -3
  872. package/scripts/test/test-declared-match.ts +25 -4
  873. package/scripts/test/test-declared.ts +26 -9
  874. package/scripts/test/test-red-commit.ts +3 -2
  875. package/scripts/test/test-red-logic.ts +7 -14
  876. package/scripts/test/test-red.ts +12 -47
  877. package/scripts/test/test-related-scope.ts +2 -3
  878. package/scripts/test/test-related.ts +3 -3
  879. package/scripts/test/test-type-logic.ts +1 -2
  880. package/scripts/test/test-unit-guard.ts +13 -17
  881. package/scripts/test/unit-worker-share.ts +7 -8
  882. package/scripts/time-runtime/time-agent-bundles.ts +2 -4
  883. package/scripts/time-runtime/time-background.ts +17 -21
  884. package/scripts/time-runtime/time-batch-guard.ts +67 -342
  885. package/scripts/time-runtime/time-bundle-call.ts +26 -28
  886. package/scripts/time-runtime/time-bundles.ts +11 -12
  887. package/scripts/time-runtime/time-call-identity.ts +1 -1
  888. package/scripts/time-runtime/time-command-key.ts +2 -2
  889. package/scripts/time-runtime/time-density-hook.ts +8 -11
  890. package/scripts/time-runtime/time-density.ts +5 -5
  891. package/scripts/time-runtime/time-followup-stage.ts +7 -7
  892. package/scripts/time-runtime/time-format.ts +5 -5
  893. package/scripts/time-runtime/time-hook-transcript.ts +3 -3
  894. package/scripts/time-runtime/time-instant.ts +1 -1
  895. package/scripts/time-runtime/time-markers.ts +15 -19
  896. package/scripts/time-runtime/time-phase-names.ts +3 -3
  897. package/scripts/time-runtime/time-reported-failure.ts +15 -19
  898. package/scripts/time-runtime/time-round-trips.ts +20 -23
  899. package/scripts/time-runtime/time-shell.ts +8 -8
  900. package/scripts/time-runtime/time-single-check.ts +1 -2
  901. package/scripts/time-runtime/time-spans.ts +35 -40
  902. package/scripts/time-runtime/time-tool-call.ts +15 -16
  903. package/scripts/time-runtime/time-transcript-line.ts +53 -34
  904. package/scripts/time-runtime/time-writes.ts +5 -5
  905. package/scripts/ui/ui-routes-cli.ts +1 -2
  906. package/scripts/ui/ui-routes.ts +1 -2
  907. package/scripts/version/bump-version.ts +1 -1
  908. package/scripts/version/fresh-metadata-cache.ts +2 -2
  909. package/scripts/version/latest-corepack.ts +26 -26
  910. package/scripts/version/latest-lane-guard.ts +1 -1
  911. package/scripts/version/latest-scope-cli.ts +2 -2
  912. package/scripts/version/latest-stamp.ts +1 -2
  913. package/scripts/version/latest-update.ts +2 -2
  914. package/scripts/version/npm-registry.ts +2 -2
  915. package/scripts/version/package-manager-version.ts +18 -0
  916. package/scripts/version/publishable-range-check.ts +2 -1
  917. package/scripts/version/publishable-range.ts +1 -1
  918. package/scripts/version/release-age.ts +11 -11
  919. package/scripts/version/release-hold.ts +2 -2
  920. package/scripts/version/safe-chain-version-update.ts +3 -3
  921. package/scripts/version/version-check-logic.ts +2 -3
  922. package/scripts/version/version-check.ts +1 -2
  923. package/scripts/version/version-command-config.ts +2 -2
  924. package/scripts/version/version-commands.ts +3 -3
  925. package/scripts/version/version-remote.ts +4 -4
  926. package/scripts/version/version-targets.ts +2 -2
  927. package/templates/gitignore +7 -0
  928. package/dist/hooks/chunk-KHX4U3BG.js +0 -6400
  929. package/dist/hooks/chunk-RKUAD3I6.js +0 -90
  930. package/dist/hooks/chunk-WPALEIRX.js +0 -18
  931. package/scripts/backlog/backlog-restructure.ts +0 -152
  932. package/scripts/rules/issue-fold-rule.ts +0 -72
  933. package/scripts/rules/wip-cap.ts +0 -63
  934. package/scripts/run/run-issue-number.ts +0 -19
@@ -0,0 +1,3705 @@
1
+ import {
2
+ agent_role_profile,
3
+ detached_launch,
4
+ git_common_directory,
5
+ issue_cite,
6
+ lane_child_invocation,
7
+ repo_discovery,
8
+ repo_origin,
9
+ repository_lock,
10
+ run_ship_stage
11
+ } from "./chunk-SYSRHRWU.js";
12
+ import {
13
+ error_text
14
+ } from "./chunk-CDY4NFQG.js";
15
+ import {
16
+ CHECK_STATUS_FAIL,
17
+ CHECK_STATUS_PENDING,
18
+ PrConflictError,
19
+ blocking_issue_schema,
20
+ cost_blocks,
21
+ describe_pr_failure,
22
+ evaluate_pr_state,
23
+ is_coderabbit_check,
24
+ is_merge_conflict,
25
+ is_required_check,
26
+ is_review_decision_decisive,
27
+ parse_pr_state_snapshot,
28
+ read_string,
29
+ rest_comment_schema,
30
+ time_density_hook,
31
+ time_shell,
32
+ time_transcript_line
33
+ } from "./chunk-TLJYAGZK.js";
34
+ import {
35
+ lane_child_marker
36
+ } from "./chunk-Z5TMJIPW.js";
37
+ import {
38
+ agent_session_environment,
39
+ backlog_budget,
40
+ cost_usage,
41
+ git_command,
42
+ has_timed_out,
43
+ json_value,
44
+ process_identity,
45
+ run_carry,
46
+ stamp_record
47
+ } from "./chunk-NZN2UFI6.js";
48
+ import {
49
+ COMMAND_TIMEOUT_MS,
50
+ stamp_file
51
+ } from "./chunk-NEC4AT4Z.js";
52
+
53
+ // scripts/lib/bounded-pool.ts
54
+ function pool_width(limit, total) {
55
+ if (!Number.isFinite(limit)) return 1;
56
+ return Math.max(1, Math.min(Math.floor(limit), total));
57
+ }
58
+ function throw_first_failure(failures) {
59
+ if (failures.length === 0) return;
60
+ const [first] = failures;
61
+ throw first;
62
+ }
63
+ async function drain(pool, worker) {
64
+ for (let entry = pool.queue.shift(); entry !== void 0 && pool.failures.length === 0; entry = pool.queue.shift()) {
65
+ const [index, item] = entry;
66
+ try {
67
+ pool.results.push({ index, value: await worker(item, index) });
68
+ } catch (error) {
69
+ pool.failures.push(error);
70
+ }
71
+ }
72
+ }
73
+ async function bounded_map(items, limit, worker) {
74
+ const pool = {
75
+ failures: [],
76
+ queue: items.map((item, index) => [index, item]),
77
+ results: []
78
+ };
79
+ const consumers = Array.from({ length: pool_width(limit, items.length) }, async () => {
80
+ await drain(pool, worker);
81
+ });
82
+ await Promise.all(consumers);
83
+ throw_first_failure(pool.failures);
84
+ return pool.results.toSorted((left, right) => left.index - right.index).map((result) => result.value);
85
+ }
86
+ var bounded_pool = { bounded_map, pool_width };
87
+
88
+ // scripts/rules/shell-segments.ts
89
+ var SEGMENT_SEPARATOR = /&&|\|\||;|\n/u;
90
+ function segments_of(command) {
91
+ return command.split(SEGMENT_SEPARATOR).map((segment) => segment.trim());
92
+ }
93
+ function is_josh_command(segment, names) {
94
+ const named = time_shell.josh_command_of(segment);
95
+ if (!named.startsWith(time_shell.JOSH_PREFIX)) return false;
96
+ return names.has(named.slice(time_shell.JOSH_PREFIX.length));
97
+ }
98
+ var shell_segments = {
99
+ is_josh_command,
100
+ segments_of
101
+ };
102
+
103
+ // scripts/rules/bash-triggers.ts
104
+ function on_bash_command(is_match) {
105
+ return function is_trigger(call) {
106
+ if (call.name !== cost_blocks.BASH_TOOL) return false;
107
+ return is_match(time_shell.bash_command(call.input));
108
+ };
109
+ }
110
+ var ISSUE_CREATE_COMMAND = /\bgh\s+(?:\S+\s+)*?issue\s+create\b/u;
111
+ var ISSUES_ENDPOINT = /repos\/[^\s'"]*\/issues(?=$|["'\s])/u;
112
+ var TITLE_FIELD = /(?:-f|-F|--field|--raw-field)\s*'?title=/u;
113
+ function is_direct_filing(command) {
114
+ if (ISSUE_CREATE_COMMAND.test(command)) return true;
115
+ return ISSUES_ENDPOINT.test(command) && TITLE_FIELD.test(command);
116
+ }
117
+ var FILING_NAMES = /* @__PURE__ */ new Set(["issue:file"]);
118
+ function is_issue_filing(command) {
119
+ return shell_segments.segments_of(command).some((segment) => shell_segments.is_josh_command(segment, FILING_NAMES));
120
+ }
121
+ var bash_triggers = { is_direct_filing, is_issue_filing, on_bash_command };
122
+
123
+ // scripts/rules/tail-commands.ts
124
+ function is_bash_use(block) {
125
+ return block.type === cost_blocks.TOOL_USE_TYPE && block.name === cost_blocks.BASH_TOOL;
126
+ }
127
+ function bash_commands_of(line) {
128
+ const parsed = time_transcript_line.parse_line(line);
129
+ if (parsed === void 0) return [];
130
+ return parsed.blocks.filter((block) => is_bash_use(block)).map((block) => time_shell.bash_command(block.input));
131
+ }
132
+ function prior_bash_commands(tail) {
133
+ return tail.split("\n").flatMap((line) => bash_commands_of(line));
134
+ }
135
+ var tail_commands = { is_bash_use, prior_bash_commands };
136
+
137
+ // scripts/rules/filing-cap.ts
138
+ var FILING_CAP = 10;
139
+ var CAP_REACHED = FILING_CAP;
140
+ function is_filing_use(block) {
141
+ if (!tail_commands.is_bash_use(block)) return false;
142
+ return bash_triggers.is_issue_filing(time_shell.bash_command(block.input));
143
+ }
144
+ function collect_block(block, found) {
145
+ if (block.result_id !== "" && block.is_error === true) found.failures.add(block.result_id);
146
+ if (is_filing_use(block)) found.filing_ids.push(block.id);
147
+ }
148
+ function collect_line(line, found) {
149
+ const parsed = time_transcript_line.parse_line(line);
150
+ if (parsed === void 0) return;
151
+ for (const block of parsed.blocks) collect_block(block, found);
152
+ }
153
+ function scan_tail(tail) {
154
+ const found = { filing_ids: [], failures: /* @__PURE__ */ new Set() };
155
+ for (const line of tail.split("\n")) collect_line(line, found);
156
+ return found;
157
+ }
158
+ function prior_filing_count(tail) {
159
+ const { filing_ids, failures } = scan_tail(tail);
160
+ return filing_ids.filter((id) => !failures.has(id)).length;
161
+ }
162
+ function is_prompt_line(line) {
163
+ const parsed = time_transcript_line.parse_line(line);
164
+ if (parsed?.type !== "user") return false;
165
+ return parsed.blocks.every((block) => block.result_id === "");
166
+ }
167
+ function current_turn(tail) {
168
+ const lines = tail.split("\n");
169
+ const start = lines.findLastIndex((line) => is_prompt_line(line));
170
+ return lines.slice(Math.max(start, 0)).join("\n");
171
+ }
172
+ function turn_filing_count(tail) {
173
+ return prior_filing_count(current_turn(tail));
174
+ }
175
+ function decide(_call, run) {
176
+ return prior_filing_count(time_density_hook.read_tail(run.transcript)) >= CAP_REACHED;
177
+ }
178
+ var FILING_CAP_REASON = `\u26D4 filing cap: this run has already filed ${String(FILING_CAP)} Issues, the per-run ceiling \u2014 on reaching it, stop and report rather than filing more. Automatic filing is capped so a run cannot manufacture Issues faster than they can be closed (\`.claude/skills/workflow-commands/SKILL.md\` \u2192 \`prerequisite.md\`, \`observation-filing.md\`). A further Issue that genuinely must exist is a person's call, not this run's. **This rule fires on every filing past the cap, not once per run**, so reissuing the same filing will be refused again.`;
179
+ var ROW = {
180
+ id: "filing-cap",
181
+ is_trigger: bash_triggers.on_bash_command(bash_triggers.is_issue_filing),
182
+ reason: FILING_CAP_REASON,
183
+ decide
184
+ };
185
+ var filing_cap = {
186
+ FILING_CAP,
187
+ FILING_CAP_REASON,
188
+ ROW,
189
+ is_prompt_line,
190
+ prior_filing_count,
191
+ turn_filing_count
192
+ };
193
+
194
+ // scripts/rules/issue-citation.ts
195
+ var ISSUE_NUMBER = /#\d+/gu;
196
+ var REFERENCE_BOUNDARY = /[\s#()[\]<>|]/u;
197
+ var OWNER_REPO = /^[^\s/#]+\/[^\s/#]+$/u;
198
+ var MARKDOWN_LINK = /\[[^[\]]*\]\([^()]*\)/gu;
199
+ var NUMBER_CONTINUATION = /^(?:\w|-[a-z])/iu;
200
+ var CONTINUATION_WIDTH = 2;
201
+ var GLUED_LEAD = /[&./]/u;
202
+ var FENCE_MARKER = /^\s*(?:`{3,}|~{3,})/u;
203
+ var QUOTE_LINE = /^\s*>/u;
204
+ var PR_PREFIX = /\b(?:pr|pull request)\s*$/iu;
205
+ var BACKTICK_PAIR = 2;
206
+ function link_covers(link, index) {
207
+ const start = link.index ?? 0;
208
+ return index >= start && index < start + link[0].length;
209
+ }
210
+ function is_linked_at(line, index) {
211
+ for (const link of line.matchAll(MARKDOWN_LINK)) {
212
+ if (link_covers(link, index)) return true;
213
+ }
214
+ return false;
215
+ }
216
+ function lead_token(message, hash_index) {
217
+ let start = hash_index;
218
+ while (start > 0 && !REFERENCE_BOUNDARY.test(message.charAt(start - 1))) start -= 1;
219
+ return message.slice(start, hash_index);
220
+ }
221
+ function repo_prefix(message, hash_index) {
222
+ const token = lead_token(message, hash_index);
223
+ return OWNER_REPO.test(token) ? token : "";
224
+ }
225
+ function is_inline_code_at(line, index) {
226
+ const backticks = line.slice(0, index).split("`").length - 1;
227
+ return backticks % BACKTICK_PAIR === 1;
228
+ }
229
+ function is_bare_at(line, index) {
230
+ if (is_linked_at(line, index) || is_inline_code_at(line, index)) return false;
231
+ return !PR_PREFIX.test(line.slice(0, index));
232
+ }
233
+ function is_glued(line, reference) {
234
+ const end = reference.index + reference.text.length;
235
+ if (NUMBER_CONTINUATION.test(line.slice(end, end + CONTINUATION_WIDTH))) return true;
236
+ return reference.prefix === "" && GLUED_LEAD.test(lead_token(line, reference.index));
237
+ }
238
+ function line_references(line) {
239
+ const references = [];
240
+ for (const match of line.matchAll(ISSUE_NUMBER)) {
241
+ const reference = { index: match.index, prefix: repo_prefix(line, match.index), text: match[0] };
242
+ if (!is_glued(line, reference) && is_bare_at(line, match.index)) references.push(reference);
243
+ }
244
+ return references;
245
+ }
246
+ function collect_line_references(line, found) {
247
+ for (const reference of line_references(line)) found.push(`${reference.prefix}${reference.text}`);
248
+ }
249
+ function lines_outside_fences(message) {
250
+ const lines = [];
251
+ let is_in_fence = false;
252
+ for (const line of message.split("\n")) {
253
+ if (FENCE_MARKER.test(line)) is_in_fence = !is_in_fence;
254
+ else if (!is_in_fence) lines.push(line);
255
+ }
256
+ return lines;
257
+ }
258
+ function prose_lines(message) {
259
+ return lines_outside_fences(message).filter((line) => !QUOTE_LINE.test(line));
260
+ }
261
+ function bare_references(message) {
262
+ const found = [];
263
+ for (const line of prose_lines(message)) collect_line_references(line, found);
264
+ return [...new Set(found)];
265
+ }
266
+ function prompt_references(prompt) {
267
+ const found = /* @__PURE__ */ new Set();
268
+ for (const match of prompt.matchAll(ISSUE_NUMBER)) {
269
+ found.add(repo_prefix(prompt, match.index) + match[0]);
270
+ }
271
+ return found;
272
+ }
273
+ function unquoted_references(message, prompt) {
274
+ const quoted = prompt_references(prompt);
275
+ return bare_references(message).filter((reference) => !quoted.has(reference));
276
+ }
277
+ function has_bare_reference(message) {
278
+ return bare_references(message).length > 0;
279
+ }
280
+ function cite_argument(reference) {
281
+ return reference.startsWith("#") ? reference.slice(1) : reference;
282
+ }
283
+ function cite_arguments(references) {
284
+ return references.map((reference) => cite_argument(reference));
285
+ }
286
+ function reference_link(reference, default_slug) {
287
+ const slug = reference.prefix === "" ? default_slug : reference.prefix;
288
+ const number = reference.text.slice(1);
289
+ return `[${reference.prefix}${reference.text}](${issue_cite.issue_url(slug, number)})`;
290
+ }
291
+ function linkify_line(line, slug) {
292
+ let result = "";
293
+ let cursor = 0;
294
+ for (const reference of line_references(line)) {
295
+ const start = reference.index - reference.prefix.length;
296
+ result += line.slice(cursor, start) + reference_link(reference, slug);
297
+ cursor = reference.index + reference.text.length;
298
+ }
299
+ return result + line.slice(cursor);
300
+ }
301
+ function rewrite_line(line, slug, is_in_fence) {
302
+ if (is_in_fence || FENCE_MARKER.test(line) || QUOTE_LINE.test(line)) return line;
303
+ return linkify_line(line, slug);
304
+ }
305
+ function linkify(message, slug) {
306
+ const out = [];
307
+ let is_in_fence = false;
308
+ for (const line of message.split("\n")) {
309
+ if (FENCE_MARKER.test(line)) is_in_fence = !is_in_fence;
310
+ out.push(rewrite_line(line, slug, is_in_fence));
311
+ }
312
+ return out.join("\n");
313
+ }
314
+ var issue_citation = {
315
+ bare_references,
316
+ cite_arguments,
317
+ has_bare_reference,
318
+ linkify,
319
+ prose_lines,
320
+ unquoted_references
321
+ };
322
+
323
+ // scripts/issue/session-cite.ts
324
+ function session_repo() {
325
+ const url = repo_discovery.read_origin_url(process.cwd());
326
+ const identity = url === void 0 ? void 0 : repo_origin.parse_origin_url(url);
327
+ return identity === void 0 ? void 0 : `${identity.owner}/${identity.repo}`;
328
+ }
329
+ function issue(number, title, repo = session_repo()) {
330
+ return issue_cite.reference(repo, String(number), title);
331
+ }
332
+ function text(message) {
333
+ const repo = session_repo();
334
+ return repo === void 0 ? message : issue_citation.linkify(message, repo);
335
+ }
336
+ var session_cite = {
337
+ issue,
338
+ session_repo,
339
+ text
340
+ };
341
+
342
+ // scripts/run/hold/run-hold.ts
343
+ import { z } from "zod";
344
+ var HOLD_PREFIX = "josh-run-hold-";
345
+ var UNNUMBERED_ISSUE = "new";
346
+ var HOLD_MAX_AGE_HOURS = 8;
347
+ var MILLISECONDS_PER_HOUR = 36e5;
348
+ var HOLD_MAX_AGE_MS = HOLD_MAX_AGE_HOURS * MILLISECONDS_PER_HOUR;
349
+ var RELEASE_COMMAND = "pnpm josh run:release";
350
+ var FORCE_RELEASE_COMMAND = `${RELEASE_COMMAND} --force`;
351
+ var NOT_IDLE = 'that is not "nothing is running here"';
352
+ var FREE_READ = { kind: "free" };
353
+ var UNREADABLE_READ = { kind: "unreadable" };
354
+ function hold_path(git_directory) {
355
+ return stamp_file.stamp_path(HOLD_PREFIX, git_directory);
356
+ }
357
+ async function worktree_directory() {
358
+ const directories = await git_command.git_directories();
359
+ return directories[0];
360
+ }
361
+ async function is_linked_worktree() {
362
+ const directories = await git_command.git_directories();
363
+ return directories[0] !== void 0 && directories[0] !== directories[1];
364
+ }
365
+ var run_hold_schema = z.object({
366
+ issue: z.string(),
367
+ taken_at: z.string(),
368
+ pid: z.number(),
369
+ is_fullrun: z.boolean().optional(),
370
+ is_halfrun_stop: z.boolean().optional(),
371
+ prrun_stop_head: z.string().optional(),
372
+ owner_pid: z.number().optional(),
373
+ owner_start: z.string().optional()
374
+ });
375
+ function parse_hold(raw) {
376
+ return json_value.parse_with(raw, run_hold_schema);
377
+ }
378
+ function is_expired(hold, now) {
379
+ return stamp_record.is_older_than(hold.taken_at, HOLD_MAX_AGE_MS, now);
380
+ }
381
+ function is_owner_gone(hold) {
382
+ const is_stop_mark = hold.is_halfrun_stop === true || hold.prrun_stop_head !== void 0;
383
+ if (is_stop_mark || hold.owner_pid === void 0) return false;
384
+ return process_identity.is_same_process(hold.owner_pid, hold.owner_start) === false;
385
+ }
386
+ function is_stale(hold, now) {
387
+ return is_expired(hold, now) || is_owner_gone(hold);
388
+ }
389
+ function classify(raw, now) {
390
+ if (raw === void 0) return FREE_READ;
391
+ const hold = parse_hold(raw);
392
+ if (hold === void 0) return UNREADABLE_READ;
393
+ return { kind: is_stale(hold, now) ? "stale" : "held", hold };
394
+ }
395
+ function read_hold(target, now = /* @__PURE__ */ new Date()) {
396
+ return classify(stamp_file.read_stamp_text(target), now);
397
+ }
398
+ function session_owner(environment = process.env) {
399
+ const pid = Number(environment[agent_session_environment.AGENT_PID_KEY]);
400
+ if (!Number.isSafeInteger(pid) || pid <= 0) return {};
401
+ return { owner_pid: pid, owner_start: process_identity.read_start(pid) };
402
+ }
403
+ function build_hold(issue2, now, is_fullrun) {
404
+ return { issue: issue2, taken_at: now.toISOString(), pid: process.pid, is_fullrun, ...session_owner() };
405
+ }
406
+ function write_hold(target, issue2, now = /* @__PURE__ */ new Date()) {
407
+ const hold = build_hold(issue2, now);
408
+ stamp_file.write_stamp(target, hold);
409
+ return hold;
410
+ }
411
+ function create_hold(target, issue2, now = /* @__PURE__ */ new Date(), is_fullrun) {
412
+ return stamp_file.create_stamp(target, build_hold(issue2, now, is_fullrun));
413
+ }
414
+ var HALFRUN_STOP_FIELDS = { is_halfrun_stop: true };
415
+ function create_stop_hold(target, issue2, mark, now = /* @__PURE__ */ new Date()) {
416
+ return stamp_file.create_stamp(target, { ...build_hold(issue2, now), ...mark });
417
+ }
418
+ function create_halfrun_stop_hold(target, issue2, now = /* @__PURE__ */ new Date()) {
419
+ return create_stop_hold(target, issue2, HALFRUN_STOP_FIELDS, now);
420
+ }
421
+ async function is_tree_dirty(directory) {
422
+ try {
423
+ const status = await git_command.status(directory);
424
+ return status.trim() !== "";
425
+ } catch (error) {
426
+ error_text.trace_swallowed("run_hold.is_tree_dirty", error);
427
+ return true;
428
+ }
429
+ }
430
+ function release_hold(target) {
431
+ stamp_file.remove_stamp(target);
432
+ }
433
+ function describe_holder(hold) {
434
+ const holder = hold.issue === UNNUMBERED_ISSUE ? "an unnumbered run" : session_cite.issue(hold.issue);
435
+ return `${holder}, recorded ${hold.taken_at} (pid ${String(hold.owner_pid ?? hold.pid)})`;
436
+ }
437
+ function own_release_command(issue2) {
438
+ return issue2 === UNNUMBERED_ISSUE ? RELEASE_COMMAND : `${RELEASE_COMMAND} ${issue2}`;
439
+ }
440
+ function is_own_hold(hold, claimant) {
441
+ return hold.issue === claimant;
442
+ }
443
+ function is_reentry(hold, claimant) {
444
+ return claimant !== UNNUMBERED_ISSUE && is_own_hold(hold, claimant);
445
+ }
446
+ function held_message(hold) {
447
+ return `This working tree is already held by ${describe_holder(hold)}. One run at a time per working tree: a second run here commits its files onto the other run's branch. If that record is stale, run \`${FORCE_RELEASE_COMMAND}\` in this working tree \u2014 it removes a record this run did not write, so be sure the run that did has ended \u2014 and ask again.`;
448
+ }
449
+ function foreign_release_message(hold) {
450
+ return `This working tree is held by ${describe_holder(hold)}, and this release did not claim it \u2014 nothing was removed. Release it as that run with \`${own_release_command(hold.issue)}\`, or, once you are sure it has ended, remove the record with \`${FORCE_RELEASE_COMMAND}\`.`;
451
+ }
452
+ function forced_release_message(hold) {
453
+ return `Forced: removed the run record held by ${describe_holder(hold)}.`;
454
+ }
455
+ function unreadable_message() {
456
+ return `This working tree's run record could not be read \u2014 ${NOT_IDLE}. Run \`${FORCE_RELEASE_COMMAND}\` in this working tree to clear it, then ask again.`;
457
+ }
458
+ function stale_message(hold) {
459
+ const why = is_owner_gone(hold) ? "the session that wrote it has ended" : `older than ${String(HOLD_MAX_AGE_HOURS)} hours`;
460
+ return `Replaced a stale run record held by ${describe_holder(hold)}: ${why}, so the run that wrote it has ended without releasing it.`;
461
+ }
462
+ function uncommitted_message(hold) {
463
+ return `This working tree still has uncommitted changes, and its run record \u2014 held by ${describe_holder(hold)} \u2014 has expired or outlived its session. That is a run which stopped for a person rather than one that finished, so the tree is not free: commit or stash the work, or run \`${own_release_command(hold.issue)}\` once you are done with it, then ask again.`;
464
+ }
465
+ function race_message(read, target) {
466
+ if (read.kind === "held") return held_message(read.hold);
467
+ return `A record already exists at ${target} and this run did not write it \u2014 ${NOT_IDLE}. Either another run claimed the tree at the same moment, or the record belongs to another account. Run \`${FORCE_RELEASE_COMMAND}\`, and remove that file by hand if it is still there.`;
468
+ }
469
+ function unknown_message() {
470
+ return `Could not read this working tree's git directory \u2014 ${NOT_IDLE}. Run this from inside the checkout the run will edit.`;
471
+ }
472
+ var run_hold = {
473
+ FORCE_RELEASE_COMMAND,
474
+ HOLD_MAX_AGE_HOURS,
475
+ HOLD_MAX_AGE_MS,
476
+ RELEASE_COMMAND,
477
+ UNNUMBERED_ISSUE,
478
+ classify,
479
+ create_halfrun_stop_hold,
480
+ create_stop_hold,
481
+ HALFRUN_STOP_FIELDS,
482
+ create_hold,
483
+ foreign_release_message,
484
+ forced_release_message,
485
+ held_message,
486
+ hold_path,
487
+ is_linked_worktree,
488
+ is_own_hold,
489
+ is_reentry,
490
+ is_tree_dirty,
491
+ own_release_command,
492
+ race_message,
493
+ read_hold,
494
+ release_hold,
495
+ stale_message,
496
+ uncommitted_message,
497
+ unknown_message,
498
+ unreadable_message,
499
+ worktree_directory,
500
+ write_hold
501
+ };
502
+
503
+ // scripts/cost-runtime/cost-pricing.ts
504
+ var CACHE_WRITE_5M_MULTIPLIER = 1.25;
505
+ var CACHE_WRITE_1H_MULTIPLIER = 2;
506
+ var CACHE_READ_MULTIPLIER = 0.1;
507
+ var TOKENS_PER_MILLION = 1e6;
508
+ var MODEL_PRICES = {
509
+ "claude-fable-5": { input: 10, output: 50 },
510
+ "claude-mythos-5": { input: 10, output: 50 },
511
+ "claude-opus-5": { input: 5, output: 25 },
512
+ "claude-opus-4-8": { input: 5, output: 25 },
513
+ "claude-opus-4-7": { input: 5, output: 25 },
514
+ "claude-opus-4-6": { input: 5, output: 25 },
515
+ "claude-sonnet-5": { input: 2, output: 10 },
516
+ "claude-sonnet-4-6": { input: 3, output: 15 },
517
+ "claude-haiku-4-5": { input: 1, output: 5 }
518
+ };
519
+ var CONTEXT_MARKER = "[";
520
+ function resolve_price(model) {
521
+ const base = model.split(CONTEXT_MARKER)[0] ?? model;
522
+ const direct = MODEL_PRICES[base];
523
+ if (direct !== void 0) return direct;
524
+ const [matched] = Object.keys(MODEL_PRICES).filter((id) => base.startsWith(id)).toSorted((left, right) => right.length - left.length);
525
+ return matched === void 0 ? void 0 : MODEL_PRICES[matched];
526
+ }
527
+ function estimate_cost(totals, price) {
528
+ const weighted_input = totals.input_tokens + totals.cache_write_5m_tokens * CACHE_WRITE_5M_MULTIPLIER + totals.cache_write_1h_tokens * CACHE_WRITE_1H_MULTIPLIER + totals.cache_read_tokens * CACHE_READ_MULTIPLIER;
529
+ return (weighted_input * price.input + totals.output_tokens * price.output) / TOKENS_PER_MILLION;
530
+ }
531
+ function priced(tokens, rate) {
532
+ return tokens * rate / TOKENS_PER_MILLION;
533
+ }
534
+ function estimate_composition(totals, price) {
535
+ return {
536
+ input_usd: priced(totals.input_tokens, price.input),
537
+ cache_write_5m_usd: priced(
538
+ totals.cache_write_5m_tokens * CACHE_WRITE_5M_MULTIPLIER,
539
+ price.input
540
+ ),
541
+ cache_write_1h_usd: priced(
542
+ totals.cache_write_1h_tokens * CACHE_WRITE_1H_MULTIPLIER,
543
+ price.input
544
+ ),
545
+ cache_read_usd: priced(totals.cache_read_tokens * CACHE_READ_MULTIPLIER, price.input),
546
+ output_usd: priced(totals.output_tokens, price.output)
547
+ };
548
+ }
549
+ function to_model_cost(model, totals) {
550
+ const price = resolve_price(model);
551
+ if (price === void 0) return { model, totals };
552
+ return { model, totals, cost_usd: estimate_cost(totals, price) };
553
+ }
554
+ function cost_by_model(records) {
555
+ const grouped = /* @__PURE__ */ new Map();
556
+ for (const record of records) {
557
+ const running = grouped.get(record.model) ?? cost_usage.EMPTY_TOTALS;
558
+ grouped.set(record.model, cost_usage.add_totals(running, record.totals));
559
+ }
560
+ return [...grouped].map(([model, totals]) => to_model_cost(model, totals));
561
+ }
562
+ function total_cost(costs) {
563
+ return {
564
+ usd: costs.reduce((sum, entry) => sum + (entry.cost_usd ?? 0), 0),
565
+ unpriced: costs.filter((entry) => entry.cost_usd === void 0).map((entry) => entry.model)
566
+ };
567
+ }
568
+ function cost_of(records) {
569
+ return total_cost(cost_by_model(records)).usd;
570
+ }
571
+ var cost_pricing = {
572
+ CACHE_WRITE_5M_MULTIPLIER,
573
+ CACHE_WRITE_1H_MULTIPLIER,
574
+ CACHE_READ_MULTIPLIER,
575
+ resolve_price,
576
+ estimate_cost,
577
+ estimate_composition,
578
+ cost_by_model,
579
+ total_cost,
580
+ cost_of
581
+ };
582
+
583
+ // scripts/cost-runtime/context-cut-payback.ts
584
+ var POST_CUT_CONTEXT = 6e4;
585
+ var EXPECTED_REMAINING_REQUESTS = 10;
586
+ function write_over_read() {
587
+ return cost_pricing.CACHE_WRITE_5M_MULTIPLIER / cost_pricing.CACHE_READ_MULTIPLIER;
588
+ }
589
+ function break_even_context(remaining = EXPECTED_REMAINING_REQUESTS) {
590
+ if (remaining <= 0) return Infinity;
591
+ return Math.round(POST_CUT_CONTEXT * (1 + write_over_read() / remaining));
592
+ }
593
+ function break_even_requests(current_context) {
594
+ const saved_per_request = current_context - POST_CUT_CONTEXT;
595
+ if (saved_per_request <= 0) return Infinity;
596
+ return POST_CUT_CONTEXT * write_over_read() / saved_per_request;
597
+ }
598
+ function pays_back(current_context, remaining = EXPECTED_REMAINING_REQUESTS) {
599
+ return current_context > break_even_context(remaining);
600
+ }
601
+ var context_cut_payback = {
602
+ POST_CUT_CONTEXT,
603
+ EXPECTED_REMAINING_REQUESTS,
604
+ break_even_context,
605
+ break_even_requests,
606
+ pays_back
607
+ };
608
+
609
+ // scripts/cost-runtime/context-cut-threshold.ts
610
+ var CONTEXT_CUT_THRESHOLD = context_cut_payback.break_even_context();
611
+
612
+ // scripts/run/cut/run-cut.ts
613
+ import { z as z3 } from "zod";
614
+
615
+ // scripts/run/cut/run-cut-handoff.ts
616
+ import { readFileSync } from "node:fs";
617
+ import { z as z2 } from "zod";
618
+ var handoff_schema = z2.object({
619
+ instruction: z2.string(),
620
+ completed: z2.array(z2.string()),
621
+ remaining: z2.array(z2.string()),
622
+ untouched: z2.array(z2.string())
623
+ });
624
+ var COMPLETED_LABEL = "Completed";
625
+ var REMAINING_LABEL = "Remaining";
626
+ var UNTOUCHED_LABEL = "Deliberately untouched";
627
+ var INSTRUCTION_LABEL = "Instruction (verbatim)";
628
+ var EMPTY_LIST_NOTE = "(none)";
629
+ function describe_key(key2) {
630
+ const value = handoff_schema.shape[key2] instanceof z2.ZodArray ? '["\u2026"]' : '"\u2026"';
631
+ return `"${key2}": ${value}`;
632
+ }
633
+ var HANDOFF_FORMAT = `a JSON object {${handoff_schema.keyof().options.map((key2) => describe_key(key2)).join(", ")}}`;
634
+ function parse_handoff(raw) {
635
+ return json_value.parse_with(raw, handoff_schema);
636
+ }
637
+ function read_handoff_file(handoff_path) {
638
+ try {
639
+ return parse_handoff(readFileSync(handoff_path, "utf8"));
640
+ } catch {
641
+ return void 0;
642
+ }
643
+ }
644
+ function is_complete_handoff(handoff) {
645
+ return handoff !== void 0 && handoff.instruction.trim() !== "";
646
+ }
647
+ function is_within_bound(handoff, max_bytes) {
648
+ return Buffer.byteLength(JSON.stringify(handoff), "utf8") <= max_bytes;
649
+ }
650
+ function load_handoff(handoff_path, max_bytes) {
651
+ if (handoff_path === void 0) return { kind: "ok", handoff: void 0 };
652
+ const handoff = read_handoff_file(handoff_path);
653
+ if (handoff === void 0) {
654
+ return {
655
+ kind: "bad",
656
+ note: `--handoff ${handoff_path} is not a readable handoff file \u2014 write ${HANDOFF_FORMAT}`
657
+ };
658
+ }
659
+ if (!is_within_bound(handoff, max_bytes)) {
660
+ return { kind: "bad", note: `--handoff ${handoff_path} is too large to carry across the cut` };
661
+ }
662
+ return { kind: "ok", handoff };
663
+ }
664
+ function describe_list(label, items) {
665
+ if (items.length === 0) return `${label}: ${EMPTY_LIST_NOTE}`;
666
+ const bullets = items.map((item) => ` - ${item}`).join("\n");
667
+ return `${label}:
668
+ ${bullets}`;
669
+ }
670
+ function describe_handoff(handoff) {
671
+ return [
672
+ `${INSTRUCTION_LABEL}:
673
+ ${handoff.instruction}`,
674
+ describe_list(COMPLETED_LABEL, handoff.completed),
675
+ describe_list(REMAINING_LABEL, handoff.remaining),
676
+ describe_list(UNTOUCHED_LABEL, handoff.untouched)
677
+ ].join("\n\n");
678
+ }
679
+ var HANDOFF_PATH = ".claude/tmp/handoff-<N>.json";
680
+ var run_cut_handoff = {
681
+ HANDOFF_FORMAT,
682
+ HANDOFF_PATH,
683
+ describe_handoff,
684
+ handoff_schema,
685
+ is_complete_handoff,
686
+ load_handoff,
687
+ parse_handoff,
688
+ read_handoff_file
689
+ };
690
+
691
+ // scripts/run/cut/run-cut.ts
692
+ var CUT_PREFIX = "josh-run-cut-";
693
+ var { PRE_GATE_PHASE, IMPLEMENTATION_PHASE } = agent_role_profile;
694
+ var IMPLEMENTATION_CONTEXT_THRESHOLD = CONTEXT_CUT_THRESHOLD;
695
+ var CUT_MAX_AGE_MS = backlog_budget.WHOLE_RUN_BUDGET_MS;
696
+ var CUT_MAX_AGE_HOURS = backlog_budget.WHOLE_RUN_BUDGET_HOURS;
697
+ var END_COMMAND = "pnpm josh run:cut --end";
698
+ var READ_COMMAND = "pnpm josh run:cut --json";
699
+ var MAX_HANDOFF_BYTES = 8192;
700
+ var run_cut_schema = z3.object({
701
+ invocation: z3.string(),
702
+ issue: z3.string(),
703
+ branch: z3.string(),
704
+ phase: z3.string(),
705
+ cut_at: z3.string(),
706
+ is_handed_off: z3.boolean().optional(),
707
+ handoff: run_cut_handoff.handoff_schema.optional(),
708
+ is_merge_relaunched: z3.boolean().optional()
709
+ });
710
+ function cut_path(git_directory) {
711
+ return stamp_file.stamp_path(CUT_PREFIX, git_directory);
712
+ }
713
+ var { worktree_directory: worktree_directory2 } = run_hold;
714
+ function invocation_for(issue2) {
715
+ return lane_child_invocation.child_invocation(issue2);
716
+ }
717
+ function parse_cut(raw) {
718
+ return json_value.parse_with(raw, run_cut_schema);
719
+ }
720
+ function cut_at_of(cut) {
721
+ return cut.cut_at;
722
+ }
723
+ var CUT_SPEC = {
724
+ parse: parse_cut,
725
+ timestamp_of: cut_at_of,
726
+ max_age_ms: CUT_MAX_AGE_MS
727
+ };
728
+ function is_expired2(cut, now) {
729
+ return stamp_record.is_older_than(cut_at_of(cut), CUT_MAX_AGE_MS, now);
730
+ }
731
+ function classify2(raw, now) {
732
+ const read = stamp_record.classify(raw, CUT_SPEC, now);
733
+ if (!("record" in read)) return read;
734
+ return { kind: read.kind, cut: read.record };
735
+ }
736
+ function read_cut(target, now = /* @__PURE__ */ new Date()) {
737
+ return classify2(stamp_file.read_stamp_text(target), now);
738
+ }
739
+ function worktree_git_directory_sync() {
740
+ return git_common_directory.own();
741
+ }
742
+ function carried_cut_sync(now = /* @__PURE__ */ new Date(), directory = worktree_git_directory_sync()) {
743
+ if (directory === void 0) return void 0;
744
+ const read = read_cut(cut_path(directory), now);
745
+ return read.kind === "carried" ? read.cut : void 0;
746
+ }
747
+ function lane_cut_sync(lane_directory) {
748
+ const directory = git_common_directory.own(lane_directory);
749
+ if (directory === void 0) return void 0;
750
+ const cut = carried_cut_sync(/* @__PURE__ */ new Date(), directory);
751
+ return cut === void 0 ? void 0 : { target: cut_path(directory), cut };
752
+ }
753
+ function fresh_cut(spec, now) {
754
+ return {
755
+ invocation: invocation_for(spec.issue),
756
+ issue: spec.issue,
757
+ branch: spec.branch,
758
+ phase: spec.phase,
759
+ cut_at: now.toISOString(),
760
+ is_handed_off: true,
761
+ handoff: spec.handoff
762
+ };
763
+ }
764
+ function resumes_into_implementation(phase) {
765
+ return phase === IMPLEMENTATION_PHASE;
766
+ }
767
+ function within_handoff_bound(cut) {
768
+ return Buffer.byteLength(JSON.stringify(cut), "utf8") <= MAX_HANDOFF_BYTES;
769
+ }
770
+ function record_within_bound(spec, now = /* @__PURE__ */ new Date()) {
771
+ return within_handoff_bound(fresh_cut(spec, now));
772
+ }
773
+ function begin_cut(target, spec, now = /* @__PURE__ */ new Date()) {
774
+ const cut = fresh_cut(spec, now);
775
+ if (!within_handoff_bound(cut)) return void 0;
776
+ return stamp_file.create_stamp(target, cut) ? cut : void 0;
777
+ }
778
+ function is_declared_cut(cut, issue2) {
779
+ return cut.is_handed_off === true && cut.invocation === invocation_for(issue2);
780
+ }
781
+ function matches_state(cut, request) {
782
+ return cut.branch === request.current_branch && cut.issue === request.issue && request.is_dirty && request.is_held;
783
+ }
784
+ function is_adopted_cut(cut, issue2) {
785
+ return cut.is_handed_off === false && cut.invocation === invocation_for(issue2);
786
+ }
787
+ function has_required_handoff(cut) {
788
+ return !resumes_into_implementation(cut.phase) || run_cut_handoff.is_complete_handoff(cut.handoff);
789
+ }
790
+ function is_relaunchable(cut, issue2) {
791
+ return is_declared_cut(cut, issue2) && has_required_handoff(cut) && cut.is_merge_relaunched !== true;
792
+ }
793
+ function mark_merge_relaunched(target, cut) {
794
+ stamp_file.remove_stamp(target);
795
+ return stamp_file.create_stamp(target, { ...cut, is_merge_relaunched: true });
796
+ }
797
+ function classify_resume(cut, request) {
798
+ if (is_adopted_cut(cut, request.issue)) return "handed-off";
799
+ if (!is_declared_cut(cut, request.issue) || !matches_state(cut, request)) return "stale";
800
+ return has_required_handoff(cut) ? "resume" : "incomplete";
801
+ }
802
+ function adopt_cut(target, cut) {
803
+ const next = { ...cut, is_handed_off: false };
804
+ stamp_file.remove_stamp(target);
805
+ return stamp_file.create_stamp(target, next) ? next : void 0;
806
+ }
807
+ function end_cut(target) {
808
+ stamp_file.remove_stamp(target);
809
+ }
810
+ function hold_of(directory) {
811
+ if (directory === void 0) return void 0;
812
+ const read = run_hold.read_hold(run_hold.hold_path(directory));
813
+ return read.kind === "held" || read.kind === "stale" ? read.hold : void 0;
814
+ }
815
+ function fullrun_issue(hold) {
816
+ return hold?.is_fullrun === true ? hold.issue : void 0;
817
+ }
818
+ function held_issue_sync() {
819
+ return fullrun_issue(hold_of(worktree_git_directory_sync()));
820
+ }
821
+ async function current_state() {
822
+ const branch = await git_command.branch();
823
+ const is_dirty = await run_hold.is_tree_dirty();
824
+ const hold = hold_of(await worktree_directory2());
825
+ return { branch, is_dirty, is_held: hold !== void 0, held_issue: fullrun_issue(hold) };
826
+ }
827
+ function describe_cut(cut) {
828
+ return `${cut.invocation} cut at ${cut.cut_at} on ${cut.branch} (${cut.phase})`;
829
+ }
830
+ function busy_message(cut) {
831
+ return `Another process already resumed this cut \u2014 ${describe_cut(cut)}. Nothing was resumed here; a double launch was detected.`;
832
+ }
833
+ function handed_off_message(cut) {
834
+ return `This cut was already handed off to a successor \u2014 ${describe_cut(cut)}. Nothing was resumed here; the run is being carried on by the process that adopted it, so this one has nothing to do.`;
835
+ }
836
+ function stale_message2(cut) {
837
+ return `This cut does not match the current tree \u2014 ${describe_cut(cut)}. Resume failed; verify the branch and the uncommitted work, then clear it with \`${END_COMMAND}\` if the run is over.`;
838
+ }
839
+ function incomplete_message(cut) {
840
+ return `This cut carries no instruction to resume on \u2014 ${describe_cut(cut)}. Resume was refused rather than continuing without it; recover the run's instruction and work state before implementing, and clear the record with \`${END_COMMAND}\` if the run is over.`;
841
+ }
842
+ function unreadable_message2() {
843
+ return `A cut record is here but could not be read; clear it with \`${END_COMMAND}\` once you know no run is using it. Read it with \`${READ_COMMAND}\`.`;
844
+ }
845
+ function unknown_message2() {
846
+ return "This working tree\u2019s git directory could not be read, so no cut record was acted on.";
847
+ }
848
+ var run_cut = {
849
+ CUT_MAX_AGE_HOURS,
850
+ CUT_MAX_AGE_MS,
851
+ END_COMMAND,
852
+ IMPLEMENTATION_CONTEXT_THRESHOLD,
853
+ IMPLEMENTATION_PHASE,
854
+ MAX_HANDOFF_BYTES,
855
+ PRE_GATE_PHASE,
856
+ adopt_cut,
857
+ begin_cut,
858
+ busy_message,
859
+ carried_cut_sync,
860
+ classify: classify2,
861
+ classify_resume,
862
+ current_state,
863
+ cut_path,
864
+ describe_cut,
865
+ end_cut,
866
+ fresh_cut,
867
+ fullrun_issue,
868
+ handed_off_message,
869
+ has_required_handoff,
870
+ held_issue_sync,
871
+ incomplete_message,
872
+ invocation_for,
873
+ is_expired: is_expired2,
874
+ is_relaunchable,
875
+ lane_cut_sync,
876
+ mark_merge_relaunched,
877
+ read_cut,
878
+ record_within_bound,
879
+ resumes_into_implementation,
880
+ stale_message: stale_message2,
881
+ unknown_message: unknown_message2,
882
+ unreadable_message: unreadable_message2,
883
+ within_handoff_bound,
884
+ worktree_directory: worktree_directory2,
885
+ worktree_git_directory_sync
886
+ };
887
+
888
+ // scripts/rules/run-tail-rule.ts
889
+ var SEGMENT_PREFIX = String.raw`(?:\(\s*)?(?:[A-Za-z_][A-Za-z0-9_]*=\S*\s+)*(?:npx\s+|pnpm\s+(?:exec\s+|run\s+)?)?`;
890
+ var WORD_END = String.raw`(?=\s|$|\))`;
891
+ var PUSH_STEP_SEGMENT = new RegExp(String.raw`^${SEGMENT_PREFIX}josh\s+(?:git|g)${WORD_END}`, "u");
892
+ var CONFIRMED_FLAG = new RegExp(String.raw`(?:^|\s)(?:-y|--yes)${WORD_END}`, "u");
893
+ var SKIPS_THE_PUSH = new RegExp(String.raw`(?:^|\s)--skip-push${WORD_END}`, "u");
894
+ var BACKGROUND_KEY = "run_in_background";
895
+ var QUOTED_SPAN = /"[^"]*"|'[^']*'/gu;
896
+ function flags_of(segment) {
897
+ return segment.replaceAll(QUOTED_SPAN, " ");
898
+ }
899
+ function is_push_step_segment(segment) {
900
+ if (!PUSH_STEP_SEGMENT.test(segment)) return false;
901
+ const flags = flags_of(segment);
902
+ if (SKIPS_THE_PUSH.test(flags)) return false;
903
+ return CONFIRMED_FLAG.test(flags);
904
+ }
905
+ function is_push_step(command) {
906
+ return shell_segments.segments_of(command).some((segment) => is_push_step_segment(segment));
907
+ }
908
+ function is_backgrounded(input) {
909
+ if (!json_value.is_record(input)) return false;
910
+ return input[BACKGROUND_KEY] === true;
911
+ }
912
+ function is_push_step_call(call) {
913
+ if (call.name !== cost_blocks.BASH_TOOL) return false;
914
+ return is_push_step(time_shell.bash_command(call.input));
915
+ }
916
+ function is_backgrounded_push_step(call) {
917
+ if (!is_backgrounded(call.input)) return false;
918
+ return is_push_step_call(call);
919
+ }
920
+ function is_foreground_push_step(call) {
921
+ if (is_backgrounded(call.input)) return false;
922
+ return is_push_step_call(call);
923
+ }
924
+ function decide2() {
925
+ return true;
926
+ }
927
+ var RUN_TAIL_REASON = '\u26D4 run tail: this issues the commit-push-PR step in the foreground, where the harness decides when to stop waiting. Reissue it with `run_in_background` set. In `fullrun #1501` this call was given a 900-second timeout, the harness detached it at its own 600-second cap, and nothing read the output for a further 6m28s \u2014 45m03s of wall clock on about 17 minutes of work (joshuafolkken/kit#1510). **Never give a foreground call a timeout above the harness cap**: the cap decides, not the number. A backgrounded call re-invokes you when it exits, so the completion notification is what resumes the run. **When it arrives, the turn that reads it goes straight through any branch-2 filing and `pnpm josh epic:bundle` to `pnpm josh followup` \u2014 the turn never ends at the push.** CI went green 6m06s before the merge started in that run, and it started only because the person asked; joshuafolkken/kit#1333 had already settled that the merge is issued in the turn the review closes. While the push runs, do the work that writes nothing \u2014 drafting the completion body to a file, deciding the branch-2 disposition. `pnpm josh followup` itself stays in the **foreground** \u2014 nearly every step after it reads its result. But a tail does follow the merge, measured at 3.0 min and 5.9% of a run (joshuafolkken/kit#1462), so empty it beforehand: the steps that read the merge result stay after `followup`, and the rest are composed in the turn that issues it, bar the one exception background-commands.md names. The procedure is `.claude/skills/workflow-commands/background-commands.md`, "A command that can take minutes is issued in the background". **This rule fires on every foreground push, not once per run**, so reissuing the same call in the foreground will be refused again.';
928
+ var run_tail_rule = {
929
+ RUN_TAIL_REASON,
930
+ decide: decide2,
931
+ is_backgrounded_push_step,
932
+ is_foreground_push_step,
933
+ is_push_step,
934
+ is_push_step_call
935
+ };
936
+
937
+ // scripts/rules/lane-background.ts
938
+ var SHIP_COMMAND = `${time_shell.JOSH_PREFIX}ship`;
939
+ var LONG_RUNNING_COMMANDS = /* @__PURE__ */ new Set([
940
+ ...["gate", "git", "followup"].map((name) => `${time_shell.JOSH_PREFIX}${name}`),
941
+ SHIP_COMMAND
942
+ ]);
943
+ var BACKGROUND_KEY2 = "run_in_background";
944
+ var TIMEOUT_KEY = "timeout";
945
+ var FOREGROUND_TIMEOUT_MS = 6e5;
946
+ function is_backgrounded2(input) {
947
+ return json_value.is_record(input) && input[BACKGROUND_KEY2] === true;
948
+ }
949
+ function long_commands_of(command) {
950
+ return time_shell.josh_commands_of(command).filter((name) => LONG_RUNNING_COMMANDS.has(name));
951
+ }
952
+ function ships_alone(command) {
953
+ const names = long_commands_of(command);
954
+ return names.length > 0 && names.every((name) => name === SHIP_COMMAND);
955
+ }
956
+ function backgrounded_bash_command(call) {
957
+ if (call.name !== cost_blocks.BASH_TOOL || !is_backgrounded2(call.input)) return void 0;
958
+ return time_shell.bash_command(call.input);
959
+ }
960
+ function is_backgrounded_ship(call) {
961
+ const command = backgrounded_bash_command(call);
962
+ return command !== void 0 && ships_alone(command);
963
+ }
964
+ function is_candidate(call) {
965
+ if (run_tail_rule.is_push_step_call(call)) return true;
966
+ const command = backgrounded_bash_command(call);
967
+ if (command === void 0 || is_backgrounded_ship(call)) return false;
968
+ return long_commands_of(command).length > 0;
969
+ }
970
+ function is_background_long_run(call, is_lane_child = () => lane_child_marker.is_child_of(process.cwd())) {
971
+ return is_candidate(call) && is_lane_child();
972
+ }
973
+ function foreground_input(call, is_lane_child = () => lane_child_marker.is_child_of(process.cwd())) {
974
+ if (!is_backgrounded_ship(call) || !json_value.is_record(call.input)) return void 0;
975
+ if (!is_lane_child()) return void 0;
976
+ return { ...call.input, [BACKGROUND_KEY2]: false, [TIMEOUT_KEY]: FOREGROUND_TIMEOUT_MS };
977
+ }
978
+ var FOREGROUND_NOTE = "lane background: this lane child backgrounded `josh ship`, which would die with the headless turn before its supervisor exists \u2014 so it was run in the foreground instead, where it detaches itself after the preflight. End the turn on `launched` / `busy` (joshuafolkken/kit#3154).";
979
+ function unfinished_ids(tail, launched_ids) {
980
+ const lines = tail.split("\n").map((line) => time_transcript_line.parse_line(line));
981
+ const finished = new Set(lines.map((line) => line?.finished_background ?? ""));
982
+ const blocks = lines.flatMap((line) => line?.blocks ?? []);
983
+ const launched = blocks.flatMap((block) => launched_ids(block));
984
+ return launched.filter((id) => id !== "" && !finished.has(id));
985
+ }
986
+ function pending_background_ids(tail) {
987
+ return unfinished_ids(tail, (block) => [block.background_id, block.agent_id]);
988
+ }
989
+ function pending_agent_ids(tail) {
990
+ return unfinished_ids(tail, (block) => [block.agent_id]);
991
+ }
992
+ var LANE_BACKGROUND_REASON = '\u26D4 lane background: this session is a dispatched lane child (`JOSH_LANE_CHILD`), a headless `claude -p` process whose background Bash tasks are killed when the turn ends \u2014 so a backgrounded `josh gate` / `josh git` / `josh followup` / `josh ship` never re-invokes you; it dies at `exit code 143` (joshuafolkken/kit#2704, measured on the #2606 child: implementation, review and live verification done, the run parked instead of merged). Hand the gate-to-merge region to the detached supervisor instead: `pnpm josh ship --detach --review "<title> #<N>"` (add `--cite <N>`) issued in the foreground \u2014 its preflight runs in this process before the supervisor exists, so a backgrounded `ship` dies with the turn (joshuafolkken/kit#3027; a backgrounded `ship` issued alone is moved to the foreground for you, joshuafolkken/kit#3154) \u2014 then end the turn on `launched` / `busy`. `.claude/skills/workflow-commands/chain-rule.md` step 0 is the single source. A single check you must read before continuing runs in the foreground within the tool timeout; the commit-push step does not \u2014 in a child it too belongs to the detached ship, in either spelling. This rule fires on every occurrence, not once per run.';
993
+ var LANE_BACKGROUND_STOP_REASON = "\u26D4 lane background stop: this is a dispatched lane child (`JOSH_LANE_CHILD`) and a background task it launched has not finished \u2014 ending this headless turn kills it, and nothing re-invokes you afterwards (joshuafolkken/kit#2704). Do not send a notification and do not stop: wait for the task in the foreground and act on its result, or re-issue the work through `pnpm josh ship --detach`, whose supervisor outlives the turn (`.claude/skills/workflow-commands/chain-rule.md` step 0). Do not repeat your previous reply.";
994
+ var ROW2 = {
995
+ id: "lane-background",
996
+ is_trigger: (call) => is_background_long_run(call),
997
+ reason: LANE_BACKGROUND_REASON,
998
+ decide: () => true
999
+ };
1000
+ var lane_background = {
1001
+ FOREGROUND_NOTE,
1002
+ LANE_BACKGROUND_REASON,
1003
+ LANE_BACKGROUND_STOP_REASON,
1004
+ ROW: ROW2,
1005
+ foreground_input,
1006
+ is_background_long_run,
1007
+ pending_agent_ids,
1008
+ pending_background_ids
1009
+ };
1010
+
1011
+ // scripts/run/ship/run-ship-detach.ts
1012
+ import { randomUUID } from "node:crypto";
1013
+ import { setTimeout as sleep } from "node:timers/promises";
1014
+
1015
+ // scripts/run/event/run-event-stream.ts
1016
+ import { z as z4 } from "zod";
1017
+ var EVENT_PREFIX = "josh-run-events-";
1018
+ var EVENT_SUFFIX = ".jsonl";
1019
+ var EVENT_CAP = 500;
1020
+ var FIRST_POSITION = 0;
1021
+ var POSITION_INCREMENT = 1;
1022
+ var LINE_SEPARATOR = "\n";
1023
+ var WORD_SEPARATOR = " ";
1024
+ var STAGE_PHASE_INDEX = 2;
1025
+ var LOCK_SUFFIX = ".lock";
1026
+ var LOCK_WAIT_MS = 5e3;
1027
+ var EVENT_KIND = {
1028
+ PLAN: "plan",
1029
+ CHILD_LAUNCH: "child-launch",
1030
+ MERGE: "merge",
1031
+ PARK: "park",
1032
+ SPLIT: "split",
1033
+ OUTAGE: "outage",
1034
+ CUT: "cut",
1035
+ // A fresh session adopted an implementation cut — `run:cut --resume` answered `resume-impl`. The
1036
+ // resume clears the cut record, so without this the `cut` would stay the newest position and
1037
+ // `run:step` would keep answering the resume command it had just run.
1038
+ RESUME: "resume",
1039
+ // The backlog emptied while nothing of the run's own was in flight — the drain. It marks the position
1040
+ // at which the end-of-run retrospective is owed, *before* the idle watch opens, so `run:step` fires
1041
+ // the retrospective at the drain rather than after the watch runs its course. It is not itself a
1042
+ // stop: the run watches on once the retrospective has run, and the real `STOP` follows when the watch
1043
+ // expires.
1044
+ DRAIN: "drain",
1045
+ STOP: "stop",
1046
+ PR_OPENED: "pr-opened",
1047
+ REVIEW_ROUND: "review-round",
1048
+ // The end-of-run retrospective's result, recorded when the run marks the retrospective done. A
1049
+ // retrospective that files zero improvements and one that never ran look
1050
+ // the same from outside — no new Issue either way — so the result is put on the stream the report is
1051
+ // generated from: the issues filed (or that none were), and the candidates dropped with why. It is
1052
+ // emitted from the `run:carry --retrospective` close, so marking the retrospective done and recording
1053
+ // what it found are one action rather than two the run could do only one of.
1054
+ RETROSPECTIVE: "retrospective",
1055
+ // Ready backlog work is sitting undispatched while a lane is free and nothing has dispatched for a
1056
+ // while. Emitted once per stall episode by the stop-time detector, it is both the dedup marker —
1057
+ // `emit_once_since` refuses a second until a `CHILD_LAUNCH` intervenes — and the line a terminal
1058
+ // reader following the stream sees. `run:step` reads it as `backlog:next`, so a run that
1059
+ // stalled is pointed straight at dispatching the work rather than left waiting.
1060
+ STALL: "stall",
1061
+ // The run's own driver is gone: the cut handed the budget off, the owner has died, and no supervisor
1062
+ // is watching. Emitted once per strand episode by the stop-time detector,
1063
+ // exactly as `STALL` is — the newest-event dedup keeps a run polled every stop from notifying more
1064
+ // than once, and a terminal reader following the stream sees the line. The strand is the step before
1065
+ // the stall: a stalled run still has a driver that could dispatch, a stranded one has none.
1066
+ STRANDED: "stranded",
1067
+ // One `josh ship` stage starting, succeeding or failing. It is a trace of the
1068
+ // composite's progress rather than a position the run is at — the positions a ship leaves behind are
1069
+ // the closed issue its `followup` merges, or a detached supervisor's `SHIP_LAUNCH` / `SHIP_STOP` below
1070
+ // — so it is one of the `TRACE_KINDS` the last-event read skips.
1071
+ SHIP_STAGE: "ship-stage",
1072
+ // One progress watcher line — the `at … / next …` heartbeat `run:progress` prints. Printed only to
1073
+ // the watcher's own output, a headless successor's heartbeat would be buried in its log after a cut;
1074
+ // on the stream it reaches the attached session's relay. It says
1075
+ // the run is alive rather than where it is, so it is a trace kind like `SHIP_STAGE`.
1076
+ HEARTBEAT: "heartbeat",
1077
+ // The post-implementation region handed to a detached `josh ship --detach` supervisor. Unlike a stage
1078
+ // trace it is a position: the agent has ended and the
1079
+ // supervisor carries the run, so `run:step` answers `wait` until it stops or the issue closes.
1080
+ SHIP_LAUNCH: "ship-launch",
1081
+ // The supervisor stopped at a failed stage — a red gate, a High/Medium review, a failed push, red CI
1082
+ // The position that hands control back: `run:step` prints the command that
1083
+ // shows the stopped report, so the agent fixes it and relaunches rather than rebuilding the context.
1084
+ SHIP_STOP: "ship-stop",
1085
+ // The idle watch's window — when the run began waiting on an empty backlog and when that wait ends
1086
+ // `backlog:offer` writes it whenever the window changes, so `run:board` reads
1087
+ // the deadline rather than guessing it. It is a trace: `emit_once`'s drain dedup and `run:step`'s
1088
+ // position both read past it, so a watching loop never re-marks the drain it is waiting after.
1089
+ IDLE: "idle",
1090
+ // An Issue the run filed on its way, written by `issue:file`, so a run started from the command line
1091
+ // still surfaces what it found — `run:board`'s findings section reads it.
1092
+ FILED: "filed",
1093
+ // A one-line observation short of an Issue, written with `run:event --append note` and shown in the
1094
+ // same section.
1095
+ NOTE: "note",
1096
+ // A lane child reached a phase no other event marks — its first implementation edit, written by the
1097
+ // PreToolUse hook — so `run:board` draws how far the child has got. A trace,
1098
+ // like `SHIP_STAGE`: it says where the child's work is, not where the run is.
1099
+ LANE_PHASE: "lane-phase",
1100
+ // An issue `run:add` put into the live run. The parent's `--wait` watcher
1101
+ // ends on it, so the issue takes the next free lane without waiting out the arrival probe's minute. A
1102
+ // trace: it says what the run was handed, not where the run is.
1103
+ ADD: "add",
1104
+ // `josh lane:limit` raised a live run's lane limit. The `--wait` watcher's
1105
+ // arrival probe reads it as a wake: the lanes a raise frees are new room for a pool its baseline
1106
+ // already holds. A trace: it says the run gained room, not where the run is.
1107
+ LANE_LIMIT: "lane-limit"
1108
+ };
1109
+ var EVENT_KINDS = Object.values(EVENT_KIND);
1110
+ var TRACE_KINDS = /* @__PURE__ */ new Set([
1111
+ EVENT_KIND.SHIP_STAGE,
1112
+ EVENT_KIND.HEARTBEAT,
1113
+ EVENT_KIND.IDLE,
1114
+ EVENT_KIND.FILED,
1115
+ EVENT_KIND.NOTE,
1116
+ EVENT_KIND.LANE_PHASE,
1117
+ EVENT_KIND.ADD,
1118
+ EVENT_KIND.LANE_LIMIT
1119
+ ]);
1120
+ var DISPOSABLE_KINDS = /* @__PURE__ */ new Set([
1121
+ EVENT_KIND.SHIP_STAGE,
1122
+ EVENT_KIND.HEARTBEAT,
1123
+ EVENT_KIND.IDLE
1124
+ ]);
1125
+ var event_schema = z4.object({
1126
+ pos: z4.number(),
1127
+ at: z4.string(),
1128
+ kind: z4.string(),
1129
+ text: z4.string()
1130
+ });
1131
+ function is_event_kind(value) {
1132
+ return EVENT_KINDS.includes(value);
1133
+ }
1134
+ function target_of(repository) {
1135
+ return stamp_file.stamp_path(EVENT_PREFIX, repository, EVENT_SUFFIX);
1136
+ }
1137
+ function is_present(event) {
1138
+ return event !== void 0;
1139
+ }
1140
+ function parse_line(line) {
1141
+ return event_schema.safeParse(json_value.parse_or_undefined(line)).data;
1142
+ }
1143
+ function read_events(target) {
1144
+ const raw = stamp_file.read_stamp_text(target);
1145
+ if (raw === void 0) return [];
1146
+ return raw.split(LINE_SEPARATOR).map((line) => line.trim()).filter((line) => line.length > 0).map((line) => parse_line(line)).filter(is_present);
1147
+ }
1148
+ function last_position(events) {
1149
+ return events[events.length - POSITION_INCREMENT]?.pos ?? FIRST_POSITION;
1150
+ }
1151
+ function issue_of(event) {
1152
+ return event.text.split(WORD_SEPARATOR)[FIRST_POSITION] ?? "";
1153
+ }
1154
+ function newest_stages(events) {
1155
+ const newest = /* @__PURE__ */ new Map();
1156
+ for (const event of events) {
1157
+ if (event.kind === EVENT_KIND.SHIP_STAGE) newest.set(issue_of(event), event);
1158
+ }
1159
+ return new Set(newest.values());
1160
+ }
1161
+ function is_stage_start(event) {
1162
+ if (event.kind !== EVENT_KIND.SHIP_STAGE) return false;
1163
+ return event.text.split(WORD_SEPARATOR)[STAGE_PHASE_INDEX] === run_ship_stage.PHASE.START;
1164
+ }
1165
+ function is_drawn(event) {
1166
+ return event.kind === EVENT_KIND.IDLE || is_stage_start(event);
1167
+ }
1168
+ function droppable(events) {
1169
+ const kept = newest_stages(events);
1170
+ const disposable = events.filter((event) => DISPOSABLE_KINDS.has(event.kind) && !kept.has(event));
1171
+ return [
1172
+ ...disposable.filter((event) => !is_drawn(event)),
1173
+ ...disposable.filter((event) => is_drawn(event))
1174
+ ];
1175
+ }
1176
+ function bounded(events) {
1177
+ const excess = events.length - EVENT_CAP;
1178
+ if (excess <= 0) return events;
1179
+ const dropped = new Set(droppable(events).slice(0, excess));
1180
+ return events.filter((event) => !dropped.has(event)).slice(-EVENT_CAP);
1181
+ }
1182
+ function serialize(events) {
1183
+ return `${events.map((event) => JSON.stringify(event)).join(LINE_SEPARATOR)}${LINE_SEPARATOR}`;
1184
+ }
1185
+ function append_held(target, event) {
1186
+ const existing = read_events(target);
1187
+ const position = last_position(existing) + POSITION_INCREMENT;
1188
+ const events = bounded([...existing, { pos: position, ...event }]);
1189
+ stamp_file.replace_text_stamp(target, serialize(events));
1190
+ return position;
1191
+ }
1192
+ function append(target, kind, text2, at) {
1193
+ if (!is_event_kind(kind)) return { appended: false, position: FIRST_POSITION };
1194
+ const lock = `${target}${LOCK_SUFFIX}`;
1195
+ const position = repository_lock.with_lock_sync(
1196
+ () => append_held(target, { at, kind, text: text2 }),
1197
+ lock,
1198
+ LOCK_WAIT_MS
1199
+ );
1200
+ if (position === void 0) {
1201
+ const message = `run event stream: gave up waiting for the lock at ${lock}`;
1202
+ process.stderr.write(`${message}
1203
+ `);
1204
+ throw new Error(message);
1205
+ }
1206
+ return { appended: true, position };
1207
+ }
1208
+ function read_from(target, position) {
1209
+ const events = read_events(target);
1210
+ return {
1211
+ events: events.filter((event) => event.pos > position),
1212
+ next_position: last_position(events)
1213
+ };
1214
+ }
1215
+ function read_last(target) {
1216
+ return read_events(target).findLast((event) => !TRACE_KINDS.has(event.kind));
1217
+ }
1218
+ function has_since(events, kind, reset_kind) {
1219
+ const reset_at = events.findLastIndex((event) => event.kind === reset_kind);
1220
+ return events.slice(reset_at + POSITION_INCREMENT).some((event) => event.kind === kind);
1221
+ }
1222
+ var FIELD_SEPARATOR = " \xB7 ";
1223
+ function format_event(event) {
1224
+ return [event.at, event.kind, event.text].join(FIELD_SEPARATOR);
1225
+ }
1226
+ var run_event_stream = {
1227
+ EVENT_CAP,
1228
+ EVENT_KIND,
1229
+ EVENT_KINDS,
1230
+ TRACE_KINDS,
1231
+ append,
1232
+ format_event,
1233
+ has_since,
1234
+ is_stage_start,
1235
+ read_events,
1236
+ read_from,
1237
+ read_last,
1238
+ target_of
1239
+ };
1240
+
1241
+ // scripts/run/event/run-event-scope.ts
1242
+ var SINCE_SCOPE = "since";
1243
+ var UNKNOWN_SCOPE = "unknown";
1244
+ var UNKNOWN_EVENT_SCOPE = { kind: UNKNOWN_SCOPE };
1245
+ function moment_of(at) {
1246
+ const parsed = Date.parse(at);
1247
+ return Number.isNaN(parsed) ? void 0 : parsed;
1248
+ }
1249
+ function is_within(event, floor) {
1250
+ const at = moment_of(event.at);
1251
+ return at !== void 0 && at >= floor;
1252
+ }
1253
+ function scoped_events(events, scope) {
1254
+ if (scope.kind === UNKNOWN_SCOPE) return void 0;
1255
+ const floor = moment_of(scope.started_at);
1256
+ if (floor === void 0) return void 0;
1257
+ return events.filter((event) => is_within(event, floor));
1258
+ }
1259
+ function scope_of(read) {
1260
+ if (read.kind === "carried" || read.kind === "expired") {
1261
+ return { kind: SINCE_SCOPE, started_at: read.carry.started_at };
1262
+ }
1263
+ return UNKNOWN_EVENT_SCOPE;
1264
+ }
1265
+ function last_scoped_event(events, scope) {
1266
+ return scoped_events(events, scope)?.findLast(
1267
+ (event) => !run_event_stream.TRACE_KINDS.has(event.kind)
1268
+ );
1269
+ }
1270
+ var SHIP_POSITION_KINDS = /* @__PURE__ */ new Set([
1271
+ run_event_stream.EVENT_KIND.SHIP_LAUNCH,
1272
+ run_event_stream.EVENT_KIND.SHIP_STOP
1273
+ ]);
1274
+ var KIND = run_event_stream.EVENT_KIND;
1275
+ var BATCH_RECORD_KINDS = /* @__PURE__ */ new Set([
1276
+ KIND.CHILD_LAUNCH,
1277
+ KIND.PARK,
1278
+ KIND.SPLIT,
1279
+ KIND.RETROSPECTIVE,
1280
+ KIND.STRANDED
1281
+ ]);
1282
+ var ISSUE_REFERENCE = /#(\d+)/u;
1283
+ function is_foreign_ship_event(event, issue2) {
1284
+ return SHIP_POSITION_KINDS.has(event.kind) && !event.text.startsWith(`${issue_cite.plain(issue2)} `);
1285
+ }
1286
+ function is_own_ship_event(event, issue2) {
1287
+ return SHIP_POSITION_KINDS.has(event.kind) && !is_foreign_ship_event(event, issue2);
1288
+ }
1289
+ function issue_named(event) {
1290
+ return ISSUE_REFERENCE.exec(event.text)?.[1];
1291
+ }
1292
+ function names_issue(event, issue2) {
1293
+ return issue_named(event) === issue2;
1294
+ }
1295
+ function is_lane_position(event, issue2) {
1296
+ return !BATCH_RECORD_KINDS.has(event.kind) && names_issue(event, issue2);
1297
+ }
1298
+ function since_own_launch(events, issue2) {
1299
+ const launch2 = events.findLastIndex(
1300
+ (event) => event.kind === KIND.CHILD_LAUNCH && names_issue(event, issue2)
1301
+ );
1302
+ return events.slice(launch2 + 1);
1303
+ }
1304
+ function is_foreign_event(event, issue2, is_lane_child) {
1305
+ if (is_lane_child) return !is_lane_position(event, issue2);
1306
+ return is_foreign_ship_event(event, issue2);
1307
+ }
1308
+ function last_issue_event(events, scope, issue2, is_lane_child) {
1309
+ const attempt = is_lane_child ? since_own_launch(events, issue2) : events;
1310
+ const own = attempt.filter((event) => !is_foreign_event(event, issue2, is_lane_child));
1311
+ if (scope.kind === SINCE_SCOPE) return last_scoped_event(own, scope);
1312
+ return own.findLast((event) => is_own_ship_event(event, issue2));
1313
+ }
1314
+ var LAUNCH_OR_SETTLE_KINDS = /* @__PURE__ */ new Set([
1315
+ KIND.CHILD_LAUNCH,
1316
+ KIND.MERGE,
1317
+ KIND.PARK,
1318
+ KIND.SPLIT
1319
+ ]);
1320
+ function is_merge_owed(events, scope, issue2) {
1321
+ const newest = (scoped_events(events, scope) ?? []).findLast(
1322
+ (event) => LAUNCH_OR_SETTLE_KINDS.has(event.kind) && names_issue(event, issue2)
1323
+ );
1324
+ return newest?.kind === KIND.CHILD_LAUNCH;
1325
+ }
1326
+ var run_event_scope = {
1327
+ UNKNOWN_EVENT_SCOPE,
1328
+ is_merge_owed,
1329
+ issue_named,
1330
+ last_issue_event,
1331
+ last_scoped_event,
1332
+ moment_of,
1333
+ scope_of,
1334
+ scoped_events,
1335
+ since_own_launch
1336
+ };
1337
+
1338
+ // scripts/run/event/run-event-stream-emit.ts
1339
+ function now_iso() {
1340
+ return (/* @__PURE__ */ new Date()).toISOString();
1341
+ }
1342
+ async function stream_target() {
1343
+ const repository = await run_carry.repository_directory();
1344
+ return repository === void 0 ? void 0 : run_event_stream.target_of(repository);
1345
+ }
1346
+ async function emit(kind, text2) {
1347
+ try {
1348
+ const target = await stream_target();
1349
+ if (target === void 0) return;
1350
+ run_event_stream.append(target, kind, text2, now_iso());
1351
+ } catch {
1352
+ }
1353
+ }
1354
+ async function emit_once(kind, text2) {
1355
+ try {
1356
+ const target = await stream_target();
1357
+ if (target === void 0 || run_event_stream.read_last(target)?.kind === kind) return false;
1358
+ return run_event_stream.append(target, kind, text2, now_iso()).appended;
1359
+ } catch (error) {
1360
+ error_text.trace_swallowed("run_event_stream_emit.emit_once", error);
1361
+ return false;
1362
+ }
1363
+ }
1364
+ async function emit_changed(kind, text2) {
1365
+ try {
1366
+ const target = await stream_target();
1367
+ if (target === void 0) return false;
1368
+ const newest = run_event_stream.read_events(target).findLast((event) => event.kind === kind);
1369
+ if (newest?.text === text2) return false;
1370
+ return run_event_stream.append(target, kind, text2, now_iso()).appended;
1371
+ } catch (error) {
1372
+ error_text.trace_swallowed("run_event_stream_emit.emit_changed", error);
1373
+ return false;
1374
+ }
1375
+ }
1376
+ function invocation_events(repository, target) {
1377
+ const events = run_event_stream.read_events(target);
1378
+ const scope = run_event_scope.scope_of(run_carry.read_carry(run_carry.carry_path(repository)));
1379
+ return run_event_scope.scoped_events(events, scope) ?? events;
1380
+ }
1381
+ async function emit_once_since(kind, text2, reset_kind) {
1382
+ try {
1383
+ const repository = await run_carry.repository_directory();
1384
+ if (repository === void 0) return false;
1385
+ const target = run_event_stream.target_of(repository);
1386
+ if (run_event_stream.has_since(invocation_events(repository, target), kind, reset_kind)) {
1387
+ return false;
1388
+ }
1389
+ return run_event_stream.append(target, kind, text2, now_iso()).appended;
1390
+ } catch (error) {
1391
+ error_text.trace_swallowed("run_event_stream_emit.emit_once_since", error);
1392
+ return false;
1393
+ }
1394
+ }
1395
+ async function emit_heartbeat(line) {
1396
+ await emit(run_event_stream.EVENT_KIND.HEARTBEAT, line);
1397
+ }
1398
+ async function current_events() {
1399
+ try {
1400
+ const repository = await run_carry.repository_directory();
1401
+ if (repository === void 0) return [];
1402
+ const read = run_carry.read_carry(run_carry.carry_path(repository));
1403
+ const scope = run_event_scope.scope_of(read);
1404
+ const events = run_event_stream.read_events(run_event_stream.target_of(repository));
1405
+ return run_event_scope.scoped_events(events, scope) ?? [];
1406
+ } catch {
1407
+ return [];
1408
+ }
1409
+ }
1410
+ async function invocation_or_all_events() {
1411
+ try {
1412
+ const repository = await run_carry.repository_directory();
1413
+ return repository === void 0 ? [] : invocation_events(repository, run_event_stream.target_of(repository));
1414
+ } catch {
1415
+ return [];
1416
+ }
1417
+ }
1418
+ async function all_events() {
1419
+ try {
1420
+ const target = await stream_target();
1421
+ return target === void 0 ? [] : run_event_stream.read_events(target);
1422
+ } catch {
1423
+ return [];
1424
+ }
1425
+ }
1426
+ var run_event_stream_emit = {
1427
+ all_events,
1428
+ current_events,
1429
+ emit,
1430
+ emit_changed,
1431
+ emit_heartbeat,
1432
+ emit_once,
1433
+ emit_once_since,
1434
+ invocation_or_all_events,
1435
+ stream_target
1436
+ };
1437
+
1438
+ // scripts/run/ship/run-ship-detach.ts
1439
+ import { z as z5 } from "zod";
1440
+ var LOG_PREFIX = "josh-ship-log-";
1441
+ var PID_PREFIX = "josh-ship-pid-";
1442
+ var BODY_PREFIX = "josh-ship-notify-";
1443
+ var KEY_SEPARATOR = "-";
1444
+ var LOG_SUFFIX = ".log";
1445
+ var BODY_SUFFIX = ".txt";
1446
+ var PNPM = "pnpm";
1447
+ var INLINE_NOTIFY = "--notify-message";
1448
+ var FILE_NOTIFY = "--notify-message-file";
1449
+ var NOTIFY_VALUE_INDEX = 1;
1450
+ var SUPERVISED_KEY = "JOSH_SHIP_SUPERVISED";
1451
+ var LAUNCH_ID_KEY = "JOSH_SHIP_LAUNCH_ID";
1452
+ var SUPERVISED_VALUE = "1";
1453
+ var LAUNCHED = "launched";
1454
+ var BUSY = "busy";
1455
+ var FAILED = "failed";
1456
+ var RESULT_PREFIX = "josh-ship-result-";
1457
+ var RECORD_POLL_MS = 25;
1458
+ var RECORD_WAIT_ATTEMPTS = 200;
1459
+ var CLAIM_WINDOW_MS = 12e4;
1460
+ var ship_record_schema = z5.object({
1461
+ pid: z5.number().int().positive().optional(),
1462
+ process_start: z5.string().optional(),
1463
+ launched_at: z5.number().optional(),
1464
+ launcher_pid: z5.number().int().positive().optional(),
1465
+ launcher_start: z5.string().optional(),
1466
+ launch_id: z5.string(),
1467
+ result: z5.enum(["success", "failed"]).optional()
1468
+ });
1469
+ var LAUNCH_MARK = " \xB7 started by process ";
1470
+ var HEADER_START = "\n";
1471
+ function key(prefix, request) {
1472
+ return stamp_file.stamp_path(`${prefix}${request.number}${KEY_SEPARATOR}`, request.repository);
1473
+ }
1474
+ function log_path(repository, number) {
1475
+ return stamp_file.stamp_path(`${LOG_PREFIX}${number}${KEY_SEPARATOR}`, repository, LOG_SUFFIX);
1476
+ }
1477
+ function result_path(repository, number) {
1478
+ return stamp_file.stamp_path(`${RESULT_PREFIX}${number}${KEY_SEPARATOR}`, repository);
1479
+ }
1480
+ function read_record(repository, number) {
1481
+ try {
1482
+ const raw = stamp_file.read_stamp_text(result_path(repository, number));
1483
+ return raw === void 0 ? void 0 : json_value.parse_with(raw, ship_record_schema);
1484
+ } catch {
1485
+ return void 0;
1486
+ }
1487
+ }
1488
+ function record_launch(request, pid, launch_id) {
1489
+ stamp_file.write_text_stamp(key(PID_PREFIX, request), String(pid));
1490
+ const process_start = process_identity.read_start(pid);
1491
+ stamp_file.replace_stamp(result_path(request.repository, request.number), {
1492
+ pid,
1493
+ launch_id,
1494
+ launched_at: Date.now(),
1495
+ ...process_start !== void 0 && { process_start }
1496
+ });
1497
+ }
1498
+ function supervisor_environment(launch_id) {
1499
+ return {
1500
+ ...agent_role_profile.handoff_environment(),
1501
+ [SUPERVISED_KEY]: SUPERVISED_VALUE,
1502
+ [LAUNCH_ID_KEY]: launch_id
1503
+ };
1504
+ }
1505
+ function is_within_claim_window(record) {
1506
+ return record.launched_at !== void 0 && Date.now() - record.launched_at < CLAIM_WINDOW_MS;
1507
+ }
1508
+ function has_live_identity(pid, record) {
1509
+ if (record.process_start === void 0) {
1510
+ return is_within_claim_window(record) && process_identity.is_live_pid(pid);
1511
+ }
1512
+ return process_identity.is_same_process(pid, record.process_start) !== false;
1513
+ }
1514
+ function result_of(record) {
1515
+ if (record.pid === void 0) {
1516
+ const is_launcher = process_identity.is_same_process(record.launcher_pid, record.launcher_start);
1517
+ return is_launcher === false ? "abnormal" : "running";
1518
+ }
1519
+ if (has_live_identity(record.pid, record)) return "running";
1520
+ return record.result ?? "abnormal";
1521
+ }
1522
+ function read_result(repository, number) {
1523
+ const record = read_record(repository, number);
1524
+ return record === void 0 ? void 0 : { launch_id: record.launch_id, result: result_of(record) };
1525
+ }
1526
+ function current_record(repository, number) {
1527
+ const record = read_record(repository, number);
1528
+ return record?.launch_id === process.env[LAUNCH_ID_KEY] ? record : void 0;
1529
+ }
1530
+ function is_pending(record) {
1531
+ return record !== void 0 && record.pid === void 0;
1532
+ }
1533
+ async function ready_record(repository, number) {
1534
+ let record = current_record(repository, number);
1535
+ for (let attempt = 0; attempt < RECORD_WAIT_ATTEMPTS; attempt += 1) {
1536
+ if (!is_pending(record)) return record;
1537
+ await sleep(RECORD_POLL_MS);
1538
+ record = current_record(repository, number);
1539
+ }
1540
+ return void 0;
1541
+ }
1542
+ async function update_record(repository, number, fields) {
1543
+ const record = await ready_record(repository, number);
1544
+ if (record === void 0) return;
1545
+ stamp_file.replace_stamp(result_path(repository, number), { ...record, ...fields });
1546
+ }
1547
+ async function mark_result(repository, number, code) {
1548
+ await update_record(repository, number, { result: code === 0 ? "success" : "failed" });
1549
+ }
1550
+ async function claim_identity(repository, number) {
1551
+ const own = process_identity.own_fields();
1552
+ if (own.process_start === void 0) return;
1553
+ await update_record(repository, number, own);
1554
+ }
1555
+ function failed_launch(request, note) {
1556
+ stamp_file.remove_stamp(result_path(request.repository, request.number));
1557
+ return { verdict: FAILED, note };
1558
+ }
1559
+ function notify_arguments(request) {
1560
+ const [flag, value] = [request.notify[0], request.notify[NOTIFY_VALUE_INDEX]];
1561
+ if (flag !== INLINE_NOTIFY || value === void 0) return request.notify;
1562
+ const body_path = stamp_file.stamp_path(
1563
+ `${BODY_PREFIX}${request.number}${KEY_SEPARATOR}`,
1564
+ request.repository,
1565
+ BODY_SUFFIX
1566
+ );
1567
+ stamp_file.write_text_stamp(body_path, value);
1568
+ return [FILE_NOTIFY, body_path];
1569
+ }
1570
+ function supervisor_argv(request) {
1571
+ const review = request.is_review ? ["--review"] : [];
1572
+ const cites = request.cites.flatMap((cite) => ["--cite", cite]);
1573
+ return {
1574
+ command: PNPM,
1575
+ args: [
1576
+ "josh",
1577
+ "ship",
1578
+ ...review,
1579
+ ...notify_arguments(request),
1580
+ ...request.body,
1581
+ ...cites,
1582
+ request.title
1583
+ ]
1584
+ };
1585
+ }
1586
+ function prepare_launch(request) {
1587
+ const launch_id = randomUUID();
1588
+ const launcher = process_identity.own_fields();
1589
+ stamp_file.replace_stamp(result_path(request.repository, request.number), {
1590
+ launch_id,
1591
+ launcher_pid: launcher.pid,
1592
+ ...launcher.process_start !== void 0 && { launcher_start: launcher.process_start }
1593
+ });
1594
+ return launch_id;
1595
+ }
1596
+ function launch(request) {
1597
+ const notes = [];
1598
+ const log = log_path(request.repository, request.number);
1599
+ const launch_id = prepare_launch(request);
1600
+ const result = detached_launch.launch(
1601
+ {
1602
+ argv: supervisor_argv(request),
1603
+ cwd: request.cwd,
1604
+ log_path: log,
1605
+ // The provider travels as a mark because the launch strips the session keys that name it, and
1606
+ // `ship --review` resolves its reviewer from it.
1607
+ env: supervisor_environment(launch_id)
1608
+ },
1609
+ (note) => {
1610
+ notes.push(note);
1611
+ }
1612
+ );
1613
+ agent_role_profile.warn_of_default();
1614
+ if (result.kind === "failed") return failed_launch(request, result.note);
1615
+ record_launch(request, result.pid, launch_id);
1616
+ return {
1617
+ verdict: LAUNCHED,
1618
+ note: [`supervisor ${String(result.pid)} \u2014 log: ${log}`, ...notes].join("\n")
1619
+ };
1620
+ }
1621
+ async function detach(request) {
1622
+ if (read_result(request.repository, request.number)?.result === "running") {
1623
+ return {
1624
+ verdict: BUSY,
1625
+ note: `a ship supervisor for ${session_cite.issue(request.number)} is already running`
1626
+ };
1627
+ }
1628
+ const result = launch(request);
1629
+ if (result.verdict === LAUNCHED) {
1630
+ await run_event_stream_emit.emit(
1631
+ run_event_stream.EVENT_KIND.SHIP_LAUNCH,
1632
+ `${issue_cite.plain(request.number)} ship supervisor launched`
1633
+ );
1634
+ }
1635
+ return result;
1636
+ }
1637
+ function last_launch(text2) {
1638
+ const mark = text2.lastIndexOf(LAUNCH_MARK);
1639
+ if (mark === -1) return text2;
1640
+ return text2.slice(text2.lastIndexOf(HEADER_START, mark) + HEADER_START.length);
1641
+ }
1642
+ function read_log(repository, number) {
1643
+ const text2 = stamp_file.read_stamp_text(log_path(repository, number));
1644
+ return text2 === void 0 ? void 0 : last_launch(text2);
1645
+ }
1646
+ function is_supervised(source = process.env) {
1647
+ return source[SUPERVISED_KEY] === SUPERVISED_VALUE;
1648
+ }
1649
+ var run_ship_detach = {
1650
+ BUSY,
1651
+ FAILED,
1652
+ LAUNCHED,
1653
+ LAUNCH_ID_KEY,
1654
+ claim_identity,
1655
+ mark_result,
1656
+ read_result,
1657
+ SUPERVISED_KEY,
1658
+ detach,
1659
+ is_supervised,
1660
+ last_launch,
1661
+ log_path,
1662
+ read_log,
1663
+ supervisor_argv
1664
+ };
1665
+
1666
+ // scripts/lane/lane-handoff.ts
1667
+ function is_ship_running(issue2, directory) {
1668
+ const repository = git_common_directory.repository(directory);
1669
+ return repository !== void 0 && run_ship_detach.read_result(repository, issue2)?.result === "running";
1670
+ }
1671
+ function is_handed_off(directory, source = process.env) {
1672
+ const issue2 = lane_child_marker.marked_issue(source);
1673
+ if (issue2 === void 0 || !lane_child_marker.is_child_of(directory, source)) return false;
1674
+ return is_ship_running(issue2, directory);
1675
+ }
1676
+ var lane_handoff = { is_handed_off, is_ship_running };
1677
+
1678
+ // scripts/issue/issue-labels.ts
1679
+ var EPIC_LABEL = "epic";
1680
+ var ENHANCEMENT_LABEL = "enhancement";
1681
+ var BREAKING_CHANGE_LABEL = "breaking-change";
1682
+ var IN_PROGRESS_LABEL = "in-progress";
1683
+ var PLANNED_LABEL = "run:planned";
1684
+ var NEEDS_DECISION_LABEL = "needs-decision";
1685
+ var RUN_SOLO_LABEL = "run:solo";
1686
+ var RUN_LANE_LABEL = "run:lane";
1687
+ var PRIORITY_HIGH_LABEL = "priority:high";
1688
+ var NEEDS_HUMAN_REVIEW_LABEL = "needs-human-review";
1689
+ var ALREADY_DONE_LABEL = "already-done";
1690
+ var RELEASE_LABEL = "release";
1691
+ var INTERRUPT_ROUTE_LABEL = "route:interrupt";
1692
+ var REVIEW_CAP_ROUTE_LABEL = "route:review-cap";
1693
+ var SPLIT_ROUTE_LABEL = "route:split";
1694
+ var TIER_A_ROUTE_LABEL = "route:tier-a";
1695
+ var FILING_ROUTE_LABELS = [
1696
+ {
1697
+ name: INTERRUPT_ROUTE_LABEL,
1698
+ // Not `5319e7`, which is the `epic` label's purple: in a listing an interrupt would render as
1699
+ // an epic, and the two are read at a glance rather than by name.
1700
+ color: "1d76db",
1701
+ // Keyed to the tests rather than to severity. "A serious defect" is the self-assessment
1702
+ // `wip-cap.md` bans as a criterion, and this string is what a person reads in `gh label list`.
1703
+ description: "Filed past the WIP cap \u2014 meets one of the three interrupt tests (wip-cap.md)"
1704
+ },
1705
+ {
1706
+ name: REVIEW_CAP_ROUTE_LABEL,
1707
+ color: "eab308",
1708
+ description: "Filed by the review round cap's carry-forward (prompts/review.md \u2192 Review round cap)"
1709
+ },
1710
+ {
1711
+ name: SPLIT_ROUTE_LABEL,
1712
+ color: "0e8a16",
1713
+ description: "A child issue created by a split (split-assessment.md)"
1714
+ },
1715
+ {
1716
+ name: TIER_A_ROUTE_LABEL,
1717
+ color: "d93f0b",
1718
+ description: "Filed Tier A during implementation \u2014 an upstream defect or a prerequisite"
1719
+ }
1720
+ ];
1721
+ var DEPTH_0_LABEL = "depth:0";
1722
+ var DEPTH_1_LABEL = "depth:1";
1723
+ var DEPTH_2_LABEL = "depth:2";
1724
+ var DEPTH_LABELS = [
1725
+ {
1726
+ name: DEPTH_0_LABEL,
1727
+ color: "0e8a16",
1728
+ description: "Depth 0 \u2014 what a consumer of this package touches (observation-filing.md)"
1729
+ },
1730
+ {
1731
+ name: DEPTH_1_LABEL,
1732
+ color: "fbc02d",
1733
+ description: "Depth 1 \u2014 the run orchestration that executes an Issue (observation-filing.md)"
1734
+ },
1735
+ {
1736
+ name: DEPTH_2_LABEL,
1737
+ color: "c5def5",
1738
+ description: "Depth 2 \u2014 what measures a run (observation-filing.md)"
1739
+ }
1740
+ ];
1741
+ var WORKFLOW_LABELS = [
1742
+ {
1743
+ name: EPIC_LABEL,
1744
+ color: "5319e7",
1745
+ description: "Tracks a batch of child issues from one split"
1746
+ },
1747
+ { name: IN_PROGRESS_LABEL, color: "0075ca", description: "Work is actively in progress" },
1748
+ { name: PLANNED_LABEL, color: "c2e0c6", description: "kickoff posted the plan" },
1749
+ {
1750
+ name: RUN_SOLO_LABEL,
1751
+ color: "b60205",
1752
+ description: "Runs alone in a backlogrun: nothing starts beside it"
1753
+ },
1754
+ {
1755
+ name: RUN_LANE_LABEL,
1756
+ color: "0e8a16",
1757
+ description: "Judged safe to run beside others in a backlogrun"
1758
+ },
1759
+ {
1760
+ name: PRIORITY_HIGH_LABEL,
1761
+ color: "e99695",
1762
+ description: "Offered first in a backlogrun; only a person removes it"
1763
+ },
1764
+ {
1765
+ name: RELEASE_LABEL,
1766
+ color: "fef2c0",
1767
+ description: "Tracks the next release; its blockers are the merged work it publishes"
1768
+ },
1769
+ ...FILING_ROUTE_LABELS,
1770
+ ...DEPTH_LABELS
1771
+ ];
1772
+ var BUGFIX_LABEL = "bugfix";
1773
+ var OTHER_CHANGE_LABEL = "other-change";
1774
+ var IGNORE_FOR_RELEASE_LABEL = "ignore-for-release";
1775
+ var RELEASE_CLASSIFICATION_NAMES = [
1776
+ BREAKING_CHANGE_LABEL,
1777
+ ENHANCEMENT_LABEL,
1778
+ BUGFIX_LABEL,
1779
+ OTHER_CHANGE_LABEL,
1780
+ IGNORE_FOR_RELEASE_LABEL
1781
+ ];
1782
+ var RELEASE_CLASSIFICATION_METADATA = {
1783
+ [BREAKING_CHANGE_LABEL]: { color: "d93f0b", description: "Release: a breaking change (major)" },
1784
+ [ENHANCEMENT_LABEL]: { color: "84b6eb", description: "Release: a new feature (minor)" },
1785
+ [BUGFIX_LABEL]: { color: "d73a4a", description: "Release: a bug fix (patch)" },
1786
+ [OTHER_CHANGE_LABEL]: { color: "c2e0c6", description: "Release: any other change (patch)" },
1787
+ [IGNORE_FOR_RELEASE_LABEL]: { color: "cfd3d7", description: "Release: left out of the notes" }
1788
+ };
1789
+ var RELEASE_CLASSIFICATION_LABELS = RELEASE_CLASSIFICATION_NAMES.map((name) => ({ name, ...RELEASE_CLASSIFICATION_METADATA[name] }));
1790
+ var REPOSITORY_LABELS = [
1791
+ ...WORKFLOW_LABELS,
1792
+ ...RELEASE_CLASSIFICATION_LABELS
1793
+ ];
1794
+ function has_any_label(labels, wanted) {
1795
+ return (labels ?? []).some((label) => wanted.has(label.name.toLowerCase()));
1796
+ }
1797
+ function label_name_of(labels, wanted) {
1798
+ const target = wanted.toLowerCase();
1799
+ return labels.find((label) => label.toLowerCase() === target);
1800
+ }
1801
+ function has_label_name(labels, wanted) {
1802
+ return label_name_of(labels, wanted) !== void 0;
1803
+ }
1804
+
1805
+ // scripts/rules/lane-park.ts
1806
+ var NOTIFY_COMMANDS = /* @__PURE__ */ new Set(["notify"]);
1807
+ var CONFIRMATION_TASK_TYPE = /(?:^|\s)--task-type[=\s]+["']?confirmation\b/u;
1808
+ function is_confirmation_notify(command) {
1809
+ return shell_segments.segments_of(command).some(
1810
+ (segment) => shell_segments.is_josh_command(segment, NOTIFY_COMMANDS) && CONFIRMATION_TASK_TYPE.test(segment)
1811
+ );
1812
+ }
1813
+ var NOTIFY_INVOCATION = /josh\s+(?:notify|nf)\b/u;
1814
+ var COMMAND_NOTIFY_MARKER = "stop notified: a confirmation Telegram was sent by this command";
1815
+ function mentions_confirmation_notify(text2) {
1816
+ if (text2.includes(COMMAND_NOTIFY_MARKER)) return true;
1817
+ return NOTIFY_INVOCATION.test(text2) && CONFIRMATION_TASK_TYPE.test(text2);
1818
+ }
1819
+ function is_parking_child(directory = process.cwd()) {
1820
+ return lane_child_marker.is_child_of(directory) && !lane_handoff.is_handed_off(directory);
1821
+ }
1822
+ function is_unparked_stop(command, is_child = is_parking_child) {
1823
+ if (!is_confirmation_notify(command)) return false;
1824
+ return is_child();
1825
+ }
1826
+ var APPLIES_NEEDS_DECISION = new RegExp(
1827
+ String.raw`(?:labels\[\]=|--add-label[= ]'?)${NEEDS_DECISION_LABEL}\b`,
1828
+ "u"
1829
+ );
1830
+ function records_the_park(command) {
1831
+ return APPLIES_NEEDS_DECISION.test(command);
1832
+ }
1833
+ var LANE_PARK_REASON = '\u26D4 lane child park: this session is a dispatched lane child, and a stop that waits on a person must leave the question on the Issue before it sends this Telegram \u2014 otherwise the parent finds an OPEN Issue with `in-progress` and no question, and a person cannot tell what to answer (joshuafolkken/kit#2034 measured this twice in one run). The child is the only process that knows the question, the options and whether it stashed, so it records the park itself rather than leaving the parent to guess from a log. Before you notify and stop: apply `needs-decision` and post a comment carrying the question, the options, and whether work was stashed \u2014 `gh api repos/{owner}/{repo}/issues/<N>/labels -f \'labels[]=needs-decision\'` then `pnpm josh issue:comment <N> --body-file <path>`. If this stop is a `needs-human-review` or `already-done` one, that label is already on the Issue and there is nothing to add. Then reissue this notify \u2014 it fires once per run and cannot repeat on the call in hand. The procedure is `.claude/skills/workflow-commands/pre-gate-cut.md` \u2192 "A lane child records its park before it stops", and the park itself is `backlogrun-park.md` \u2192 "park and continue".';
1834
+ var ROW3 = {
1835
+ id: "lane-park",
1836
+ is_trigger: bash_triggers.on_bash_command(is_unparked_stop),
1837
+ reason: LANE_PARK_REASON,
1838
+ keeps: bash_triggers.on_bash_command(records_the_park)
1839
+ };
1840
+ var lane_park = {
1841
+ COMMAND_NOTIFY_MARKER,
1842
+ LANE_PARK_REASON,
1843
+ ROW: ROW3,
1844
+ is_confirmation_notify,
1845
+ is_parking_child,
1846
+ is_unparked_stop,
1847
+ mentions_confirmation_notify,
1848
+ records_the_park
1849
+ };
1850
+
1851
+ // scripts/discovery/repo-party.ts
1852
+ var FIRST_PARTY = "first-party";
1853
+ var THIRD_PARTY = "third-party";
1854
+ var UNKNOWN = "unknown";
1855
+ var GH_REPO_ENV_KEY = "GH_REPO";
1856
+ var GH_REPO_PATH_SEGMENTS = 2;
1857
+ function classify3(session_owner2, target) {
1858
+ if (session_owner2 === void 0 || target === void 0) return UNKNOWN;
1859
+ return session_owner2.toLowerCase() === target.toLowerCase() ? FIRST_PARTY : THIRD_PARTY;
1860
+ }
1861
+ function target_owner(owner_repo) {
1862
+ return repo_origin.parse_origin_url(`https://${repo_origin.GITHUB_HOST}/${owner_repo}`)?.owner;
1863
+ }
1864
+ function current_owner(repository_path = process.cwd()) {
1865
+ return repo_discovery.resolve_current_owner(repository_path);
1866
+ }
1867
+ function gh_repo_owners(gh_repo) {
1868
+ return [target_owner(gh_repo.split("/").slice(-GH_REPO_PATH_SEGMENTS).join("/"))];
1869
+ }
1870
+ function remote_owners(repository_path) {
1871
+ return repo_discovery.read_remote_urls(repository_path).map((url) => repo_origin.parse_origin_url(url)?.owner);
1872
+ }
1873
+ function placeholder_owners(repository_path = process.cwd(), environment = process.env) {
1874
+ const gh_repo = environment[GH_REPO_ENV_KEY];
1875
+ return gh_repo === void 0 || gh_repo === "" ? remote_owners(repository_path) : gh_repo_owners(gh_repo);
1876
+ }
1877
+ var repo_party = {
1878
+ FIRST_PARTY,
1879
+ THIRD_PARTY,
1880
+ UNKNOWN,
1881
+ classify: classify3,
1882
+ current_owner,
1883
+ placeholder_owners,
1884
+ target_owner
1885
+ };
1886
+
1887
+ // scripts/gh/git-gh-api-path.ts
1888
+ var FULL_PAGE_QUERY = "?per_page=100";
1889
+ function repo_api_path(repo = "{owner}/{repo}") {
1890
+ return `repos/${repo}`;
1891
+ }
1892
+ function issues_api_path(repo) {
1893
+ return `${repo_api_path(repo)}/issues`;
1894
+ }
1895
+ function issue_api_path(issue_number, repo) {
1896
+ return `${issues_api_path(repo)}/${issue_number}`;
1897
+ }
1898
+ function blocked_by_api_path(issue_number, repo) {
1899
+ return `${issue_api_path(issue_number, repo)}/dependencies/blocked_by`;
1900
+ }
1901
+ function issue_comments_api_path(issue_number, repo) {
1902
+ return `${issue_api_path(issue_number, repo)}/comments`;
1903
+ }
1904
+ function pulls_api_path(repo) {
1905
+ return `${repo_api_path(repo)}/pulls`;
1906
+ }
1907
+ function pull_api_path(pr_number, repo) {
1908
+ return `${pulls_api_path(repo)}/${pr_number}`;
1909
+ }
1910
+ function pull_merge_api_path(pr_number, repo) {
1911
+ return `${pull_api_path(pr_number, repo)}/merge`;
1912
+ }
1913
+ function pull_comments_api_path(pr_number, repo) {
1914
+ return `${pull_api_path(pr_number, repo)}/comments`;
1915
+ }
1916
+ function pull_reviews_api_path(pr_number, repo) {
1917
+ return `${pull_api_path(pr_number, repo)}/reviews`;
1918
+ }
1919
+ function commit_api_path(commit_sha, repo) {
1920
+ return `${repo_api_path(repo)}/commits/${commit_sha}`;
1921
+ }
1922
+ function commit_check_runs_api_path(commit_sha, repo) {
1923
+ return `${commit_api_path(commit_sha, repo)}/check-runs`;
1924
+ }
1925
+ function commit_status_api_path(commit_sha, repo) {
1926
+ return `${commit_api_path(commit_sha, repo)}/status`;
1927
+ }
1928
+ function tag_reference_api_path(tag, repo) {
1929
+ return `${repo_api_path(repo)}/git/ref/tags/${tag}`;
1930
+ }
1931
+ function release_by_tag_api_path(tag, repo) {
1932
+ return `${repo_api_path(repo)}/releases/tags/${tag}`;
1933
+ }
1934
+ var git_gh_api_path = {
1935
+ FULL_PAGE_QUERY,
1936
+ repo_api_path,
1937
+ tag_ref_api_path: tag_reference_api_path,
1938
+ release_by_tag_api_path,
1939
+ issues_api_path,
1940
+ issue_api_path,
1941
+ blocked_by_api_path,
1942
+ issue_comments_api_path,
1943
+ pulls_api_path,
1944
+ pull_api_path,
1945
+ pull_merge_api_path,
1946
+ pull_comments_api_path,
1947
+ pull_reviews_api_path,
1948
+ commit_api_path,
1949
+ commit_check_runs_api_path,
1950
+ commit_status_api_path
1951
+ };
1952
+
1953
+ // scripts/gh/git-gh-exec.ts
1954
+ import { execa as execa2, execaSync } from "execa";
1955
+
1956
+ // scripts/gh/git-gh-check.ts
1957
+ import { execa } from "execa";
1958
+ var GH_NOT_INSTALLED_MSG = "gh CLI is not installed. Install it from https://cli.github.com/";
1959
+ var gh_check = {};
1960
+ async function run_gh_check() {
1961
+ try {
1962
+ await execa("gh", ["--version"], { timeout: COMMAND_TIMEOUT_MS });
1963
+ } catch {
1964
+ delete gh_check.promise;
1965
+ throw new Error(GH_NOT_INSTALLED_MSG);
1966
+ }
1967
+ }
1968
+ async function check_gh_installed() {
1969
+ gh_check.promise ??= run_gh_check();
1970
+ await gh_check.promise;
1971
+ }
1972
+
1973
+ // scripts/git/parse-json-array.ts
1974
+ function parse_json_loose(raw_json) {
1975
+ return json_value.parse_or_undefined(raw_json);
1976
+ }
1977
+ function parse_json_array_or_undefined(raw_json, element_schema) {
1978
+ const value = parse_json_loose(raw_json);
1979
+ if (!Array.isArray(value)) return void 0;
1980
+ return element_schema.array().parse(value);
1981
+ }
1982
+ function read_json_listing(raw_json, element_schema) {
1983
+ try {
1984
+ const rows = parse_json_array_or_undefined(raw_json, element_schema);
1985
+ return rows === void 0 ? { kind: "unreadable" } : { kind: "read", rows };
1986
+ } catch {
1987
+ return { kind: "unexpected_shape" };
1988
+ }
1989
+ }
1990
+ function parse_json_object_or_undefined(raw_json, schema) {
1991
+ const value = parse_json_loose(raw_json);
1992
+ if (value === void 0) return void 0;
1993
+ return schema.parse(value);
1994
+ }
1995
+ var parse_json = {
1996
+ parse_json_object_or_undefined
1997
+ };
1998
+
1999
+ // scripts/gh/git-gh-failure.ts
2000
+ import { z as z6 } from "zod";
2001
+ var error_document_schema = z6.object({ status: z6.union([z6.string(), z6.number()]).optional() }).catch({});
2002
+ var GH_FAILURE_FIELD = "gh_failure";
2003
+ function has_gh_failure(error) {
2004
+ return error instanceof Error && Object.hasOwn(error, GH_FAILURE_FIELD);
2005
+ }
2006
+ function parse_response_status(stdout) {
2007
+ const document = parse_json.parse_json_object_or_undefined(stdout, error_document_schema);
2008
+ if (document?.status === void 0) return void 0;
2009
+ const status = Number(document.status);
2010
+ return Number.isSafeInteger(status) ? status : void 0;
2011
+ }
2012
+ function classify_stdout(stdout) {
2013
+ return { status: parse_response_status(stdout) };
2014
+ }
2015
+ function attach(error, failure) {
2016
+ Object.defineProperty(error, GH_FAILURE_FIELD, {
2017
+ value: failure,
2018
+ enumerable: false,
2019
+ configurable: true
2020
+ });
2021
+ return error;
2022
+ }
2023
+ function failure_of(error) {
2024
+ return has_gh_failure(error) ? error.gh_failure : void 0;
2025
+ }
2026
+ var gh_failure = { attach, classify_stdout, failure_of, parse_response_status };
2027
+
2028
+ // scripts/gh/git-gh-exec.ts
2029
+ var BODY_FROM_STDIN = "-";
2030
+ var GH_REQUEST_TIMEOUT_MS = 6e4;
2031
+ function to_timeout_option(timeout_ms) {
2032
+ return { timeout: timeout_ms ?? GH_REQUEST_TIMEOUT_MS };
2033
+ }
2034
+ function direct_environment() {
2035
+ const removed = agent_session_environment.removed_proxy_environment();
2036
+ return Object.keys(removed).length > 0 ? { env: removed } : {};
2037
+ }
2038
+ function to_spawn_options(timeout_ms, cwd) {
2039
+ return {
2040
+ ...to_timeout_option(timeout_ms),
2041
+ ...direct_environment(),
2042
+ ...cwd !== void 0 && { cwd }
2043
+ };
2044
+ }
2045
+ var GH_REQUEST_TIMEOUT_MESSAGE = "gh request timed out";
2046
+ function has_stderr_field(error) {
2047
+ return error instanceof Error && "stderr" in error && typeof error.stderr === "string";
2048
+ }
2049
+ function has_stdout_field(error) {
2050
+ return error instanceof Error && "stdout" in error && typeof error.stdout === "string";
2051
+ }
2052
+ function to_timeout_prefix(error) {
2053
+ return has_timed_out(error) ? `${GH_REQUEST_TIMEOUT_MESSAGE}: ` : "";
2054
+ }
2055
+ function to_gh_error(error) {
2056
+ const stderr = has_stderr_field(error) ? error.stderr.trim() : "";
2057
+ const stdout = has_stdout_field(error) ? error.stdout.trim() : "";
2058
+ const summary = stderr.length > 0 ? stderr : error_text.message_of(error);
2059
+ const detail = stdout.length > 0 ? `${summary}
2060
+ ${stdout}` : summary;
2061
+ return gh_failure.attach(
2062
+ new Error(`${to_timeout_prefix(error)}${detail}`, { cause: error }),
2063
+ gh_failure.classify_stdout(stdout)
2064
+ );
2065
+ }
2066
+ async function exec_gh_command(arguments_, timeout_ms, cwd) {
2067
+ await check_gh_installed();
2068
+ const options = to_spawn_options(timeout_ms, cwd);
2069
+ try {
2070
+ const { stdout } = await execa2("gh", arguments_, options);
2071
+ return stdout.trimEnd();
2072
+ } catch (error) {
2073
+ throw to_gh_error(error);
2074
+ }
2075
+ }
2076
+ async function exec_gh_command_with_stdin(input) {
2077
+ await check_gh_installed();
2078
+ const options = { input: input.stdin_body, ...to_spawn_options(input.timeout_ms, input.cwd) };
2079
+ try {
2080
+ const { stdout } = await execa2("gh", input.args, options);
2081
+ return stdout.trimEnd();
2082
+ } catch (error) {
2083
+ throw to_gh_error(error);
2084
+ }
2085
+ }
2086
+ var STATUS_LINE_PATTERN = /^HTTP\/[\d.]+ (?<status>\d{3})\b/u;
2087
+ function parse_status_line(output) {
2088
+ const { status } = STATUS_LINE_PATTERN.exec(output)?.groups ?? {};
2089
+ return status === void 0 ? void 0 : Number(status);
2090
+ }
2091
+ function status_of_failure(error) {
2092
+ return has_stdout_field(error) ? parse_status_line(error.stdout) : void 0;
2093
+ }
2094
+ async function exec_gh_api_status(path, timeout_ms) {
2095
+ const options = to_spawn_options(timeout_ms);
2096
+ try {
2097
+ await check_gh_installed();
2098
+ const { stdout } = await execa2("gh", ["api", "--include", "--silent", path], options);
2099
+ return parse_status_line(stdout);
2100
+ } catch (error) {
2101
+ return status_of_failure(error);
2102
+ }
2103
+ }
2104
+ function exec_gh_api_status_sync(path, timeout_ms) {
2105
+ const options = to_spawn_options(timeout_ms);
2106
+ try {
2107
+ const { stdout } = execaSync("gh", ["api", "--include", "--silent", path], options);
2108
+ return parse_status_line(stdout);
2109
+ } catch (error) {
2110
+ return status_of_failure(error);
2111
+ }
2112
+ }
2113
+ var METHOD_FLAG = "--method";
2114
+ var INPUT_FLAG = "--input";
2115
+ var PAGINATE_FLAG = "--paginate";
2116
+ var SLURP_FLAG = "--slurp";
2117
+ var JQ_FLAG = "--jq";
2118
+ function optional_flag(flag, value) {
2119
+ return value === void 0 ? [] : [flag, value];
2120
+ }
2121
+ function to_gh_api_args(request) {
2122
+ const body_args = request.body === void 0 ? [] : [INPUT_FLAG, BODY_FROM_STDIN];
2123
+ const paginate_args = request.should_paginate === true ? [PAGINATE_FLAG] : [];
2124
+ const slurp_args = request.should_slurp === true ? [SLURP_FLAG] : [];
2125
+ return [
2126
+ "api",
2127
+ request.path,
2128
+ ...optional_flag(METHOD_FLAG, request.method),
2129
+ ...body_args,
2130
+ ...paginate_args,
2131
+ ...slurp_args,
2132
+ ...optional_flag(JQ_FLAG, request.jq_filter)
2133
+ ];
2134
+ }
2135
+ async function exec_gh_api(request) {
2136
+ const args = to_gh_api_args(request);
2137
+ if (request.body === void 0) {
2138
+ return await exec_gh_command(args, request.timeout_ms, request.cwd);
2139
+ }
2140
+ return await exec_gh_command_with_stdin({
2141
+ args,
2142
+ stdin_body: request.body,
2143
+ timeout_ms: request.timeout_ms,
2144
+ cwd: request.cwd
2145
+ });
2146
+ }
2147
+ function exec_gh_api_sync(request) {
2148
+ const body_option = request.body === void 0 ? {} : { input: request.body };
2149
+ const options = { ...body_option, ...to_spawn_options(request.timeout_ms, request.cwd) };
2150
+ try {
2151
+ const { stdout } = execaSync("gh", to_gh_api_args(request), options);
2152
+ return stdout.trimEnd();
2153
+ } catch (error) {
2154
+ throw to_gh_error(error);
2155
+ }
2156
+ }
2157
+ function read_gh_api_sync(request) {
2158
+ try {
2159
+ return exec_gh_api_sync(request);
2160
+ } catch {
2161
+ return void 0;
2162
+ }
2163
+ }
2164
+ var git_gh_exec = {
2165
+ direct_environment,
2166
+ exec_gh_command,
2167
+ exec_gh_command_with_stdin,
2168
+ exec_gh_api,
2169
+ exec_gh_api_sync,
2170
+ read_gh_api_sync,
2171
+ exec_gh_api_status,
2172
+ exec_gh_api_status_sync,
2173
+ parse_status_line
2174
+ };
2175
+
2176
+ // scripts/gh/git-gh-helpers.ts
2177
+ function parse_pr_state_string(result) {
2178
+ const trimmed = result.trim();
2179
+ return trimmed.length > 0 ? trimmed : void 0;
2180
+ }
2181
+ function is_pr_already_exists_message(error_message) {
2182
+ return error_message.toLowerCase().includes("already exists");
2183
+ }
2184
+ function get_error_message_with_stderr(error) {
2185
+ if (!(error instanceof Error)) return String(error);
2186
+ if (has_stderr_field(error) && error.stderr.length > 0) return `${error.message}
2187
+ ${error.stderr}`;
2188
+ return error.message;
2189
+ }
2190
+ function handle_pr_create_error(error) {
2191
+ const error_message = get_error_message_with_stderr(error);
2192
+ if (is_pr_already_exists_message(error_message)) {
2193
+ throw new Error("PR_ALREADY_EXISTS");
2194
+ }
2195
+ throw error;
2196
+ }
2197
+ var git_gh_helpers = {
2198
+ parse_pr_state_string,
2199
+ get_error_message_with_stderr,
2200
+ handle_pr_create_error
2201
+ };
2202
+
2203
+ // scripts/gh/git-gh-issue-rest.ts
2204
+ import { z as z7 } from "zod";
2205
+
2206
+ // scripts/gh/git-gh-rest-state.ts
2207
+ var MERGED_STATE = "MERGED";
2208
+ function to_gh_state(state) {
2209
+ return state?.toUpperCase();
2210
+ }
2211
+
2212
+ // scripts/gh/git-gh-issue-rest.ts
2213
+ var rest_issue_schema = z7.looseObject({
2214
+ number: z7.number(),
2215
+ issue_dependencies_summary: z7.looseObject({ total_blocked_by: z7.number().optional() }).nullish(),
2216
+ // Present only on a pull request, which this endpoint serves as readily as an issue.
2217
+ pull_request: z7.looseObject({ merged_at: z7.string().nullish() }).nullish()
2218
+ });
2219
+ var REPOSITORY_URL = /\/repos\/([\w.-]+\/[\w.-]+)$/u;
2220
+ var REPOSITORY_URL_GROUP = 1;
2221
+ var BLOCKED_BY_FIELD = "blockedBy";
2222
+ var BLOCKED_BY_COUNT_FIELD = "blocked_by_count";
2223
+ var STATE_FIELD = "state";
2224
+ var BODY_FIELD = "body";
2225
+ var FIELD_SEPARATOR2 = ",";
2226
+ var EMPTY_BODY = "";
2227
+ var REST_FIELD_NAMES = /* @__PURE__ */ new Map([
2228
+ ["url", "html_url"],
2229
+ ["createdAt", "created_at"],
2230
+ ["closedAt", "closed_at"]
2231
+ ]);
2232
+ var NOT_AN_ISSUE_MESSAGE = "gh api answered something other than an issue object";
2233
+ var NOT_AN_ISSUE_LISTING_MESSAGE = "gh api answered something other than an issue listing";
2234
+ var NOT_A_BLOCKER_LISTING_MESSAGE = "gh api answered something other than a blocked-by listing";
2235
+ function rest_field_name(field) {
2236
+ return REST_FIELD_NAMES.get(field) ?? field;
2237
+ }
2238
+ function split_fields(fields) {
2239
+ return fields.split(FIELD_SEPARATOR2).map((field) => field.trim()).filter((field) => field.length > 0);
2240
+ }
2241
+ function to_issue_state(rest, value) {
2242
+ if (typeof rest.pull_request?.merged_at === "string") return MERGED_STATE;
2243
+ return typeof value === "string" ? to_gh_state(value) : value;
2244
+ }
2245
+ function total_blocked_by(rest) {
2246
+ return rest.issue_dependencies_summary?.total_blocked_by;
2247
+ }
2248
+ function to_gh_field_value(field, rest) {
2249
+ if (field === BLOCKED_BY_COUNT_FIELD) return total_blocked_by(rest);
2250
+ const value = rest[rest_field_name(field)];
2251
+ if (field === STATE_FIELD) return to_issue_state(rest, value);
2252
+ return field === BODY_FIELD ? value ?? EMPTY_BODY : value;
2253
+ }
2254
+ function parse_rest_issue(rest_json) {
2255
+ const parsed = parse_json_object_or_undefined(rest_json, rest_issue_schema);
2256
+ if (parsed === void 0) throw new Error(NOT_AN_ISSUE_MESSAGE);
2257
+ return parsed;
2258
+ }
2259
+ function is_pull_request(rest) {
2260
+ return rest.pull_request !== void 0 && rest.pull_request !== null;
2261
+ }
2262
+ function parse_rest_issues(rest_json) {
2263
+ const parsed = parse_json_array_or_undefined(rest_json, rest_issue_schema);
2264
+ if (parsed === void 0) throw new Error(NOT_AN_ISSUE_LISTING_MESSAGE);
2265
+ return parsed;
2266
+ }
2267
+ function empty_blocked_by() {
2268
+ return { nodes: [], totalCount: 0 };
2269
+ }
2270
+ function repo_of_url(repository_url = "") {
2271
+ const match = REPOSITORY_URL.exec(repository_url);
2272
+ return match?.[REPOSITORY_URL_GROUP];
2273
+ }
2274
+ function to_blocked_by(blockers_json, exact_total) {
2275
+ const parsed = parse_json_array_or_undefined(blockers_json, blocking_issue_schema);
2276
+ if (parsed === void 0) throw new Error(NOT_A_BLOCKER_LISTING_MESSAGE);
2277
+ const nodes = parsed.map((blocker) => ({ ...blocker, state: to_gh_state(blocker.state) }));
2278
+ return { nodes, totalCount: exact_total ?? nodes.length };
2279
+ }
2280
+ function to_gh_issue(rest, fields, blocked_by) {
2281
+ return Object.fromEntries(
2282
+ fields.map((field) => [
2283
+ field,
2284
+ field === BLOCKED_BY_FIELD ? blocked_by : to_gh_field_value(field, rest)
2285
+ ])
2286
+ );
2287
+ }
2288
+ function to_field_text(value) {
2289
+ if (typeof value === "string") return value;
2290
+ return value === void 0 || value === null ? EMPTY_BODY : JSON.stringify(value);
2291
+ }
2292
+ var CLOSED = "CLOSED";
2293
+ function reference_of_blocker(node, fallback_repo) {
2294
+ const repo = repo_of_url(node.repository_url) ?? fallback_repo;
2295
+ if (node.state === void 0) return { repo, number: node.number };
2296
+ return { repo, number: node.number, state: node.state.toUpperCase() === CLOSED ? CLOSED : "OPEN" };
2297
+ }
2298
+ var git_gh_issue_rest = {
2299
+ empty_blocked_by,
2300
+ repo_of_url,
2301
+ reference_of_blocker,
2302
+ split_fields,
2303
+ is_pull_request,
2304
+ parse_rest_issue,
2305
+ parse_rest_issues,
2306
+ total_blocked_by,
2307
+ to_blocked_by,
2308
+ to_gh_issue,
2309
+ to_field_text
2310
+ };
2311
+
2312
+ // scripts/gh/git-gh-reachability.ts
2313
+ var RATE_LIMITED_STATUS = 429;
2314
+ var SERVER_ERROR_FLOOR = 500;
2315
+ function is_retryable_status(status) {
2316
+ if (status >= SERVER_ERROR_FLOOR) return true;
2317
+ return status === RATE_LIMITED_STATUS;
2318
+ }
2319
+ function classify_status(status) {
2320
+ if (status === void 0) return "unreachable";
2321
+ return is_retryable_status(status) ? "unreachable" : "reachable";
2322
+ }
2323
+ var gh_reachability = { classify_status };
2324
+
2325
+ // scripts/gh/git-gh-issue-read.ts
2326
+ async function read_blocked_by_listing(issue_number, repo, exact_total) {
2327
+ const json = await git_gh_exec.exec_gh_api({
2328
+ path: `${git_gh_api_path.blocked_by_api_path(issue_number, repo)}${git_gh_api_path.FULL_PAGE_QUERY}`
2329
+ });
2330
+ return git_gh_issue_rest.to_blocked_by(json, exact_total);
2331
+ }
2332
+ async function read_blocked_by(issue_number, rest, repo) {
2333
+ if (git_gh_issue_rest.is_pull_request(rest)) return git_gh_issue_rest.empty_blocked_by();
2334
+ const exact_total = git_gh_issue_rest.total_blocked_by(rest);
2335
+ if (exact_total === 0) return git_gh_issue_rest.empty_blocked_by();
2336
+ return await read_blocked_by_listing(issue_number, repo, exact_total);
2337
+ }
2338
+ function mark_followup(error) {
2339
+ if (!(error instanceof Error)) return error;
2340
+ const failure = gh_failure.failure_of(error);
2341
+ if (failure === void 0) return error;
2342
+ return gh_failure.attach(error, { ...failure, is_followup: true });
2343
+ }
2344
+ async function read_relations(issue_number, rest, repo) {
2345
+ try {
2346
+ return await read_blocked_by(issue_number, rest, repo);
2347
+ } catch (error) {
2348
+ throw mark_followup(error);
2349
+ }
2350
+ }
2351
+ async function read_issue_fields(issue_number, fields, repo) {
2352
+ const rest = git_gh_issue_rest.parse_rest_issue(
2353
+ await git_gh_exec.exec_gh_api({ path: git_gh_api_path.issue_api_path(issue_number, repo) })
2354
+ );
2355
+ const requested = git_gh_issue_rest.split_fields(fields);
2356
+ const blocked_by = requested.includes(BLOCKED_BY_FIELD) ? await read_relations(issue_number, rest, repo) : void 0;
2357
+ return git_gh_issue_rest.to_gh_issue(rest, requested, blocked_by);
2358
+ }
2359
+ var NOT_FOUND_STATUS = 404;
2360
+ function is_number_unresolved(failure) {
2361
+ return failure.status === NOT_FOUND_STATUS && failure.is_followup !== true;
2362
+ }
2363
+ function to_unreadable_reason(status) {
2364
+ return gh_reachability.classify_status(status) === "unreachable" ? "unreachable" : "rejected";
2365
+ }
2366
+ function to_read_failure(error) {
2367
+ const failure = gh_failure.failure_of(error);
2368
+ if (failure === void 0) return { kind: "unreadable", reason: "malformed", status: void 0 };
2369
+ if (is_number_unresolved(failure)) return { kind: "missing" };
2370
+ return {
2371
+ kind: "unreadable",
2372
+ reason: to_unreadable_reason(failure.status),
2373
+ status: failure.status
2374
+ };
2375
+ }
2376
+ async function issue_view_json_classified(issue_number, fields, repo) {
2377
+ try {
2378
+ const issue2 = await read_issue_fields(issue_number, fields, repo);
2379
+ return { kind: "read", json: JSON.stringify(issue2) };
2380
+ } catch (error) {
2381
+ return to_read_failure(error);
2382
+ }
2383
+ }
2384
+ async function issue_view_field_classified(issue_number, field, repo) {
2385
+ try {
2386
+ const issue2 = await read_issue_fields(issue_number, field, repo);
2387
+ return { kind: "read", text: git_gh_issue_rest.to_field_text(issue2[field]) };
2388
+ } catch (error) {
2389
+ return to_read_failure(error);
2390
+ }
2391
+ }
2392
+ async function issue_view_field(issue_number, field, repo) {
2393
+ const read = await issue_view_field_classified(issue_number, field, repo);
2394
+ return read.kind === "read" ? read.text : void 0;
2395
+ }
2396
+ async function issue_get_title(issue_number, repo) {
2397
+ const result = await issue_view_field(issue_number, "title", repo);
2398
+ return result === void 0 ? void 0 : git_gh_helpers.parse_pr_state_string(result);
2399
+ }
2400
+ async function issue_get_body(issue_number, repo) {
2401
+ return await issue_view_field(issue_number, "body", repo);
2402
+ }
2403
+ async function issue_get_body_classified(issue_number, repo) {
2404
+ return await issue_view_field_classified(issue_number, "body", repo);
2405
+ }
2406
+ async function issue_view_json(issue_number, fields, repo) {
2407
+ const read = await issue_view_json_classified(issue_number, fields, repo);
2408
+ return read.kind === "read" ? read.json : void 0;
2409
+ }
2410
+ var STATE_AND_RELATIONS_FIELDS = "number,state,labels,blockedBy";
2411
+ async function issue_get_state_and_relations(issue_number, repo) {
2412
+ return await issue_view_json(issue_number, STATE_AND_RELATIONS_FIELDS, repo);
2413
+ }
2414
+ async function issue_get_state_and_relations_classified(issue_number, repo) {
2415
+ return await issue_view_json_classified(issue_number, STATE_AND_RELATIONS_FIELDS, repo);
2416
+ }
2417
+ function is_unreachable_read(failure) {
2418
+ return failure.kind === "unreadable" && failure.reason === "unreachable";
2419
+ }
2420
+ var PLAN_FIELDS = "number,title,body,state,url,labels,blockedBy";
2421
+ async function issue_get_plan_fields(issue_number) {
2422
+ return await issue_view_json(issue_number, PLAN_FIELDS);
2423
+ }
2424
+ async function issue_get_plan_fields_classified(issue_number) {
2425
+ return await issue_view_json_classified(issue_number, PLAN_FIELDS);
2426
+ }
2427
+ async function issue_get_labels_and_body(issue_number) {
2428
+ return await issue_view_json(issue_number, "number,state,labels,body");
2429
+ }
2430
+ async function issue_list_comments(issue_number) {
2431
+ const path = `${git_gh_api_path.issue_comments_api_path(issue_number)}${git_gh_api_path.FULL_PAGE_QUERY}`;
2432
+ try {
2433
+ return await git_gh_exec.exec_gh_api({ path, should_paginate: true });
2434
+ } catch {
2435
+ return void 0;
2436
+ }
2437
+ }
2438
+ async function has_no_relations_endpoint(issue_number, repo) {
2439
+ const status = await git_gh_exec.exec_gh_api_status(
2440
+ git_gh_api_path.blocked_by_api_path(issue_number, repo)
2441
+ );
2442
+ return status === NOT_FOUND_STATUS;
2443
+ }
2444
+ async function issue_blocked_by_references(issue_number, own_repo, repo) {
2445
+ try {
2446
+ const listing = await read_blocked_by_listing(issue_number, repo);
2447
+ return listing.nodes.map((blocker) => git_gh_issue_rest.reference_of_blocker(blocker, own_repo));
2448
+ } catch (error) {
2449
+ if (await has_no_relations_endpoint(issue_number, repo)) return [];
2450
+ throw error;
2451
+ }
2452
+ }
2453
+ async function issue_blocked_by_numbers(issue_number, repo) {
2454
+ const references = await issue_blocked_by_references(issue_number, "", repo);
2455
+ return references.map((blocker) => blocker.number);
2456
+ }
2457
+ var git_gh_issue_read = {
2458
+ issue_blocked_by_numbers,
2459
+ issue_blocked_by_references,
2460
+ issue_get_title,
2461
+ issue_get_body,
2462
+ issue_get_body_classified,
2463
+ issue_view_json,
2464
+ issue_view_json_classified,
2465
+ issue_get_state_and_relations,
2466
+ issue_get_state_and_relations_classified,
2467
+ is_unreachable_read,
2468
+ issue_get_plan_fields,
2469
+ issue_get_plan_fields_classified,
2470
+ issue_get_labels_and_body,
2471
+ issue_list_comments
2472
+ };
2473
+
2474
+ // scripts/gh/git-gh-issue-list.ts
2475
+ var PER_PAGE = 100;
2476
+ var FIRST_PAGE = 1;
2477
+ var DEFAULT_STATE = "open";
2478
+ var DEFAULT_SORT = "created";
2479
+ var LISTING_DIRECTION = "direction=desc";
2480
+ function listing_query(request) {
2481
+ const state = request.state ?? DEFAULT_STATE;
2482
+ const sort = request.sort ?? DEFAULT_SORT;
2483
+ return `state=${state}&sort=${sort}&${LISTING_DIRECTION}`;
2484
+ }
2485
+ function listing_path(request, page) {
2486
+ const label = request.label === void 0 ? "" : `&labels=${encodeURIComponent(request.label)}`;
2487
+ const paging = `&per_page=${String(PER_PAGE)}&page=${String(page)}`;
2488
+ return `${git_gh_api_path.issues_api_path(request.repo)}?${listing_query(request)}${label}${paging}`;
2489
+ }
2490
+ var DIGIT_PATTERN = /\d/u;
2491
+ function has_token_occurrence(body, term) {
2492
+ let index = body.indexOf(term);
2493
+ while (index !== -1) {
2494
+ if (!DIGIT_PATTERN.test(body.charAt(index + term.length))) return true;
2495
+ index = body.indexOf(term, index + 1);
2496
+ }
2497
+ return false;
2498
+ }
2499
+ function matches_body(rest, term) {
2500
+ if (term === void 0) return true;
2501
+ const { body } = rest;
2502
+ return typeof body === "string" && has_token_occurrence(body, term);
2503
+ }
2504
+ function is_selected(rest, request) {
2505
+ return !git_gh_issue_rest.is_pull_request(rest) && matches_body(rest, request.body_term);
2506
+ }
2507
+ async function fetch_page(request, page) {
2508
+ const path = listing_path(request, page);
2509
+ const rows = git_gh_issue_rest.parse_rest_issues(await git_gh_exec.exec_gh_api({ path }));
2510
+ return {
2511
+ selected: rows.filter((row) => is_selected(row, request)),
2512
+ is_full: rows.length >= PER_PAGE
2513
+ };
2514
+ }
2515
+ var MAX_PAGES = 5;
2516
+ var MAX_SCANNED = MAX_PAGES * PER_PAGE;
2517
+ function wants_more(has_more, selected_count, limit) {
2518
+ return has_more && selected_count < limit;
2519
+ }
2520
+ async function fetch_selected(request) {
2521
+ const selected = [];
2522
+ let page = FIRST_PAGE;
2523
+ let has_more = true;
2524
+ while (page <= MAX_PAGES && wants_more(has_more, selected.length, request.limit)) {
2525
+ const result = await fetch_page(request, page);
2526
+ selected.push(...result.selected);
2527
+ has_more = result.is_full;
2528
+ page += 1;
2529
+ }
2530
+ return {
2531
+ rows: selected.slice(0, request.limit),
2532
+ is_capped: wants_more(has_more, selected.length, request.limit)
2533
+ };
2534
+ }
2535
+ var RELATION_CONCURRENCY = 8;
2536
+ async function read_relations2(rows, repo) {
2537
+ return await bounded_pool.bounded_map(
2538
+ rows,
2539
+ RELATION_CONCURRENCY,
2540
+ async (row) => await read_blocked_by(String(row.number), row, repo)
2541
+ );
2542
+ }
2543
+ async function issue_list(request) {
2544
+ try {
2545
+ const { rows, is_capped } = await fetch_selected(request);
2546
+ const fields = git_gh_issue_rest.split_fields(request.json_fields);
2547
+ const relations = fields.includes(BLOCKED_BY_FIELD) ? await read_relations2(rows, request.repo) : void 0;
2548
+ const mapped = rows.map(
2549
+ (row, index) => git_gh_issue_rest.to_gh_issue(row, fields, relations?.[index])
2550
+ );
2551
+ return { json: JSON.stringify(mapped), is_capped };
2552
+ } catch {
2553
+ return { json: void 0, is_capped: false };
2554
+ }
2555
+ }
2556
+ var git_gh_issue_list = {
2557
+ issue_list
2558
+ };
2559
+
2560
+ // scripts/gh/git-gh-issue-write.ts
2561
+ var PATCH_METHOD = "PATCH";
2562
+ var DELETE_METHOD = "DELETE";
2563
+ var HTML_URL_FILTER = ".html_url";
2564
+ var ID_FILTER = ".id";
2565
+ var LABEL_NAMES_FILTER = ".[].name";
2566
+ var LABELS_SEGMENT = "/labels";
2567
+ var COMMENTS_SEGMENT = "/comments";
2568
+ var CLOSED_STATE = "closed";
2569
+ var COLOR_HASH = "#";
2570
+ var UNPROCESSABLE_STATUS = 422;
2571
+ var ALREADY_EXISTS_CODE = "already_exists";
2572
+ async function did_write_succeed(write) {
2573
+ try {
2574
+ await write();
2575
+ return true;
2576
+ } catch (error) {
2577
+ error_text.trace_swallowed("git_gh_issue_write.did_write_succeed", error);
2578
+ return false;
2579
+ }
2580
+ }
2581
+ async function issue_edit_body(issue_number, body) {
2582
+ return await git_gh_exec.exec_gh_api({
2583
+ path: git_gh_api_path.issue_api_path(issue_number),
2584
+ method: PATCH_METHOD,
2585
+ body: JSON.stringify({ body }),
2586
+ jq_filter: HTML_URL_FILTER
2587
+ });
2588
+ }
2589
+ async function issue_comment(issue_number, body) {
2590
+ return await git_gh_exec.exec_gh_api({
2591
+ path: `${git_gh_api_path.issue_api_path(issue_number)}${COMMENTS_SEGMENT}`,
2592
+ body: JSON.stringify({ body }),
2593
+ jq_filter: HTML_URL_FILTER
2594
+ });
2595
+ }
2596
+ async function issue_try_comment(issue_number, body) {
2597
+ return await did_write_succeed(async () => await issue_comment(issue_number, body));
2598
+ }
2599
+ async function issue_close(issue_number, comment) {
2600
+ return await did_write_succeed(async () => {
2601
+ if (comment !== void 0) await issue_comment(issue_number, comment);
2602
+ await git_gh_exec.exec_gh_api({
2603
+ path: git_gh_api_path.issue_api_path(issue_number),
2604
+ method: PATCH_METHOD,
2605
+ body: JSON.stringify({ state: CLOSED_STATE })
2606
+ });
2607
+ });
2608
+ }
2609
+ function to_label_color(color) {
2610
+ return color.startsWith(COLOR_HASH) ? color.slice(COLOR_HASH.length) : color;
2611
+ }
2612
+ function is_label_already_exists(error) {
2613
+ if (gh_failure.failure_of(error)?.status !== UNPROCESSABLE_STATUS) return false;
2614
+ return error_text.message_of(error).includes(ALREADY_EXISTS_CODE);
2615
+ }
2616
+ async function label_ensure(input) {
2617
+ try {
2618
+ await git_gh_exec.exec_gh_api({
2619
+ path: `${git_gh_api_path.repo_api_path()}${LABELS_SEGMENT}`,
2620
+ body: JSON.stringify({
2621
+ name: input.name,
2622
+ color: to_label_color(input.color),
2623
+ description: input.description
2624
+ })
2625
+ });
2626
+ } catch (error) {
2627
+ if (is_label_already_exists(error)) return;
2628
+ const [gist = ""] = error_text.message_of(error).split("\n", 1);
2629
+ console.warn(`\u26A0 could not create the \`${input.name}\` label \u2014 ${gist}`);
2630
+ }
2631
+ }
2632
+ function issue_create_request(input) {
2633
+ const { labels } = input;
2634
+ return {
2635
+ path: git_gh_api_path.issues_api_path(input.repo),
2636
+ body: JSON.stringify({
2637
+ title: input.title,
2638
+ ...labels !== void 0 && { labels },
2639
+ body: input.body
2640
+ }),
2641
+ jq_filter: HTML_URL_FILTER
2642
+ };
2643
+ }
2644
+ async function issue_create_with_label(input) {
2645
+ return await git_gh_exec.exec_gh_api(
2646
+ issue_create_request({ title: input.title, body: input.body, labels: [input.label] })
2647
+ );
2648
+ }
2649
+ async function read_label_names(issue_number) {
2650
+ try {
2651
+ const raw = await git_gh_exec.exec_gh_api({
2652
+ path: `${git_gh_api_path.issue_api_path(issue_number)}${LABELS_SEGMENT}`,
2653
+ should_paginate: true,
2654
+ jq_filter: LABEL_NAMES_FILTER
2655
+ });
2656
+ return raw.split("\n").map((name) => name.trim());
2657
+ } catch (error) {
2658
+ error_text.trace_swallowed("git_gh_issue_write.read_label_names", error);
2659
+ return void 0;
2660
+ }
2661
+ }
2662
+ async function issue_apply_label(issue_number, label) {
2663
+ const labels_path = `${git_gh_api_path.issue_api_path(issue_number)}${LABELS_SEGMENT}`;
2664
+ try {
2665
+ await git_gh_exec.exec_gh_api({ path: labels_path, body: JSON.stringify({ labels: [label] }) });
2666
+ return { is_applied: true };
2667
+ } catch (error) {
2668
+ const names = await read_label_names(issue_number);
2669
+ if (names?.includes(label) === true) return { is_applied: true };
2670
+ error_text.trace_swallowed("git_gh_issue_write.issue_apply_label", error);
2671
+ const [gist = ""] = error_text.message_of(error).split("\n", 1);
2672
+ return { is_applied: false, reason: gist };
2673
+ }
2674
+ }
2675
+ async function issue_add_label(issue_number, label) {
2676
+ const write = await issue_apply_label(issue_number, label);
2677
+ return write.is_applied;
2678
+ }
2679
+ async function issue_remove_label(issue_number, label) {
2680
+ const labels_path = `${git_gh_api_path.issue_api_path(issue_number)}${LABELS_SEGMENT}`;
2681
+ await git_gh_exec.exec_gh_api({
2682
+ path: `${labels_path}/${encodeURIComponent(label)}`,
2683
+ method: DELETE_METHOD
2684
+ });
2685
+ }
2686
+ async function read_issue_id(issue_number) {
2687
+ const raw = await git_gh_exec.exec_gh_api({
2688
+ path: git_gh_api_path.issue_api_path(issue_number),
2689
+ jq_filter: ID_FILTER
2690
+ });
2691
+ const issue_id = Number(raw.trim());
2692
+ if (!Number.isSafeInteger(issue_id) || issue_id <= 0) {
2693
+ throw new Error(`gh api answered no database id for issue ${session_cite.issue(issue_number)}`);
2694
+ }
2695
+ return issue_id;
2696
+ }
2697
+ async function issue_add_blocked_by(issue_number, blocker) {
2698
+ return await did_write_succeed(async () => {
2699
+ const issue_id = await read_issue_id(blocker);
2700
+ await git_gh_exec.exec_gh_api({
2701
+ path: git_gh_api_path.blocked_by_api_path(issue_number),
2702
+ body: JSON.stringify({ issue_id })
2703
+ });
2704
+ });
2705
+ }
2706
+ async function issue_remove_blocked_by(issue_number, blocker) {
2707
+ return await did_write_succeed(async () => {
2708
+ const issue_id = await read_issue_id(blocker);
2709
+ const relations_path = git_gh_api_path.blocked_by_api_path(issue_number);
2710
+ await git_gh_exec.exec_gh_api({
2711
+ path: `${relations_path}/${String(issue_id)}`,
2712
+ method: DELETE_METHOD
2713
+ });
2714
+ });
2715
+ }
2716
+ var git_gh_issue_write = {
2717
+ issue_edit_body,
2718
+ issue_comment,
2719
+ issue_try_comment,
2720
+ issue_close,
2721
+ label_ensure,
2722
+ issue_create_request,
2723
+ issue_create_with_label,
2724
+ issue_apply_label,
2725
+ issue_add_label,
2726
+ issue_remove_label,
2727
+ issue_add_blocked_by,
2728
+ issue_remove_blocked_by
2729
+ };
2730
+
2731
+ // scripts/gh/git-gh-issue.ts
2732
+ var NUMBER_AND_BODY_FIELDS = "number,body";
2733
+ var BACKLOG_SCAN_FIELDS = `number,title,body,${BLOCKED_BY_COUNT_FIELD}`;
2734
+ var NUMBER_TITLE_AND_LABELS_FIELDS = "number,title,labels";
2735
+ var SUMMARY_FIELDS = "number,title,labels,createdAt";
2736
+ var PICKUP_FIELDS = `${SUMMARY_FIELDS},blockedBy,body`;
2737
+ var { issue_list: issue_list2 } = git_gh_issue_list;
2738
+ async function issue_list_recent(limit) {
2739
+ return await issue_list2({ json_fields: SUMMARY_FIELDS, limit });
2740
+ }
2741
+ async function issue_list_open_bodies(limit) {
2742
+ return await issue_list2({ json_fields: BACKLOG_SCAN_FIELDS, limit });
2743
+ }
2744
+ async function issue_list_recently_closed(limit) {
2745
+ return await issue_list2({
2746
+ json_fields: NUMBER_TITLE_AND_LABELS_FIELDS,
2747
+ limit,
2748
+ state: "closed",
2749
+ sort: "updated"
2750
+ });
2751
+ }
2752
+ async function issue_search_body(term, limit) {
2753
+ return await issue_list2({
2754
+ json_fields: NUMBER_AND_BODY_FIELDS,
2755
+ limit,
2756
+ body_term: term
2757
+ });
2758
+ }
2759
+ async function issue_list_by_label(label, limit) {
2760
+ return await issue_list2({ json_fields: NUMBER_AND_BODY_FIELDS, limit, label });
2761
+ }
2762
+ async function issue_list_by_label_summary(label, limit, options) {
2763
+ return await issue_list2({
2764
+ json_fields: options?.json_fields ?? PICKUP_FIELDS,
2765
+ limit,
2766
+ label
2767
+ });
2768
+ }
2769
+ async function issue_list_by_label_in_repo(label, limit, repo) {
2770
+ return await issue_list2({ json_fields: SUMMARY_FIELDS, limit, label, repo });
2771
+ }
2772
+ var git_gh_issue = {
2773
+ ...git_gh_issue_read,
2774
+ ...git_gh_issue_write,
2775
+ issue_list_recent,
2776
+ issue_list_by_label,
2777
+ issue_list_by_label_in_repo,
2778
+ issue_list_by_label_summary,
2779
+ issue_search_body,
2780
+ issue_list_open_bodies,
2781
+ issue_list_recently_closed
2782
+ };
2783
+
2784
+ // scripts/ci/pr-classification.ts
2785
+ import { readFileSync as readFileSync2 } from "node:fs";
2786
+ import { fileURLToPath } from "node:url";
2787
+ import { z as z8 } from "zod";
2788
+ var CLASSIFICATION_SET = new Set(RELEASE_CLASSIFICATION_NAMES);
2789
+ var ISSUE_BUG_LABEL = "bug";
2790
+ var DECLARATION_PREFIX = "- \u30EA\u30EA\u30FC\u30B9\u5206\u985E: ";
2791
+ var DECLARATION = new RegExp(`^${DECLARATION_PREFIX}(.+)$`, "gmu");
2792
+ var LEGACY_LABELS = /* @__PURE__ */ new Set(["semver-major", "semver-minor"]);
2793
+ var LABEL = z8.object({ name: z8.string() });
2794
+ var USER = z8.object({ login: z8.string() });
2795
+ var PULL_REQUEST = z8.object({ number: z8.number(), user: USER });
2796
+ var EVENT = z8.object({
2797
+ pull_request: PULL_REQUEST,
2798
+ repository: z8.object({ full_name: z8.string() })
2799
+ });
2800
+ function classification_error(labels, author) {
2801
+ const legacy = labels.filter((label) => LEGACY_LABELS.has(label.toLowerCase()));
2802
+ if (legacy.length > 0) return `Remove legacy release labels: ${legacy.join(", ")}`;
2803
+ const selected = labels.filter((label) => CLASSIFICATION_SET.has(label.toLowerCase()));
2804
+ if (selected.length > 1) {
2805
+ return `Choose exactly one release classification; found: ${selected.join(", ")}`;
2806
+ }
2807
+ if (selected.length === 1 || author.endsWith("[bot]")) return void 0;
2808
+ return `Choose one release classification: ${RELEASE_CLASSIFICATION_NAMES.join(", ")}`;
2809
+ }
2810
+ function declaration(label) {
2811
+ return `${DECLARATION_PREFIX}${label}`;
2812
+ }
2813
+ function is_classification(value) {
2814
+ return CLASSIFICATION_SET.has(value);
2815
+ }
2816
+ function release_candidates(candidates) {
2817
+ if (!candidates.includes(BREAKING_CHANGE_LABEL)) return candidates;
2818
+ return candidates.filter((candidate) => candidate !== ENHANCEMENT_LABEL);
2819
+ }
2820
+ function issue_candidates(issue_json) {
2821
+ const issue2 = z8.object({ labels: z8.array(LABEL), body: z8.string().nullable() }).parse(JSON.parse(issue_json));
2822
+ const names = issue2.labels.map((label) => label.name.toLowerCase());
2823
+ const declared = [...(issue2.body ?? "").matchAll(DECLARATION)].map((match) => match[1] ?? "");
2824
+ const candidates = [...release_candidates([...names, ...declared].filter(is_classification))];
2825
+ const unknown = declared.filter((value) => !is_classification(value));
2826
+ if (unknown.length > 0) throw new Error(`Unknown release classification: ${unknown.join(", ")}`);
2827
+ if (names.includes(ISSUE_BUG_LABEL) && !candidates.includes(BREAKING_CHANGE_LABEL)) {
2828
+ candidates.push(BUGFIX_LABEL);
2829
+ }
2830
+ return candidates;
2831
+ }
2832
+ function select_issue_classification(issue_json) {
2833
+ const candidates = issue_candidates(issue_json);
2834
+ const selected = [...new Set(candidates)];
2835
+ const [label] = selected;
2836
+ if (label === void 0 || selected.length > 1) {
2837
+ throw new Error(
2838
+ `Choose one release classification before opening the PR: ${RELEASE_CLASSIFICATION_NAMES.join(", ")}; found: ${selected.join(", ") || "none"}. Add "${DECLARATION_PREFIX}<label>" to the Issue body.`
2839
+ );
2840
+ }
2841
+ return label;
2842
+ }
2843
+ function fetch_current_labels(repository, pull_number) {
2844
+ const path = `repos/${repository}/issues/${String(pull_number)}/labels`;
2845
+ try {
2846
+ const names = git_gh_exec.exec_gh_api_sync({ path, jq_filter: ".[].name" });
2847
+ return names.split("\n").filter((name) => name !== "");
2848
+ } catch (error) {
2849
+ const detail = error_text.message_of(error);
2850
+ throw new Error(`Could not read the pull request labels: ${detail}`, { cause: error });
2851
+ }
2852
+ }
2853
+ function check_event(event_path, read_labels = fetch_current_labels) {
2854
+ const event = EVENT.parse(JSON.parse(readFileSync2(event_path, "utf8")));
2855
+ const labels = read_labels(event.repository.full_name, event.pull_request.number);
2856
+ return classification_error(labels, event.pull_request.user.login);
2857
+ }
2858
+ if (process.argv[1] === fileURLToPath(import.meta.url)) {
2859
+ const event_path = process.env["GITHUB_EVENT_PATH"];
2860
+ if (!event_path) throw new Error("GITHUB_EVENT_PATH is required");
2861
+ const error = check_event(event_path);
2862
+ if (error) {
2863
+ console.error(`::error::${error}`);
2864
+ process.exitCode = 1;
2865
+ }
2866
+ }
2867
+ var pr_classification = {
2868
+ classification_error,
2869
+ check_event,
2870
+ fetch_current_labels,
2871
+ declaration,
2872
+ is_classification,
2873
+ select_issue_classification
2874
+ };
2875
+
2876
+ // scripts/lib/poll.ts
2877
+ async function sleep2(duration_ms) {
2878
+ await new Promise((resolve) => {
2879
+ setTimeout(resolve, duration_ms);
2880
+ });
2881
+ }
2882
+ async function wait_between(wait, interval_ms, attempt, attempts) {
2883
+ if (attempt < attempts - 1) await wait(interval_ms);
2884
+ }
2885
+ async function poll_until(is_done, options) {
2886
+ const wait = options.sleeper ?? sleep2;
2887
+ for (let attempt = 0; attempt < options.attempts; attempt += 1) {
2888
+ if (await is_done()) return true;
2889
+ await wait_between(wait, options.interval_ms, attempt, options.attempts);
2890
+ }
2891
+ return false;
2892
+ }
2893
+ var poll = { poll_until, sleep: sleep2 };
2894
+
2895
+ // scripts/gh/git-gh-pr.ts
2896
+ import { z as z12 } from "zod";
2897
+
2898
+ // scripts/gh/git-gh-pr-rest.ts
2899
+ import { z as z9 } from "zod";
2900
+ var rest_repo_schema = z9.looseObject({ full_name: z9.string().optional() }).nullish();
2901
+ var rest_pull_side_schema = z9.looseObject({ repo: rest_repo_schema });
2902
+ var rest_pull_schema = z9.looseObject({
2903
+ number: z9.number(),
2904
+ html_url: z9.string().optional(),
2905
+ body: z9.string().nullish(),
2906
+ state: z9.string().optional(),
2907
+ merged: z9.boolean().nullish(),
2908
+ merged_at: z9.string().nullish(),
2909
+ mergeable: z9.boolean().nullish(),
2910
+ mergeable_state: z9.string().optional(),
2911
+ // `sha` is the head commit, which is what both halves of the merge-gate rollup are keyed by —
2912
+ // REST hangs the check runs and the status contexts off the commit rather than off the pull
2913
+ // request.
2914
+ head: z9.looseObject({ ref: z9.string().optional(), sha: z9.string().optional(), repo: rest_repo_schema }).nullish(),
2915
+ base: rest_pull_side_schema.nullish(),
2916
+ // `node_id` is what the GraphQL auto-merge mutation addresses a pull request by, and `auto_merge`
2917
+ // is `null` until auto-merge is enabled — both read by `git-gh-pr-auto-merge.ts`.
2918
+ node_id: z9.string().optional(),
2919
+ auto_merge: z9.looseObject({}).nullish()
2920
+ });
2921
+ var NOT_A_PULL_MESSAGE = "gh api answered something other than a pull request object";
2922
+ var NOT_A_PULL_LISTING_MESSAGE = "gh api answered something other than a pull request listing";
2923
+ var NOT_A_COMMENT_LISTING_MESSAGE = "gh api answered something other than a comment listing";
2924
+ var OPEN_STATE = "open";
2925
+ var EMPTY_BODY2 = "";
2926
+ function parse_rest_pull(rest_json) {
2927
+ const parsed = parse_json_object_or_undefined(rest_json, rest_pull_schema);
2928
+ if (parsed === void 0) throw new Error(NOT_A_PULL_MESSAGE);
2929
+ return parsed;
2930
+ }
2931
+ function parse_rest_pulls(rest_json) {
2932
+ const parsed = parse_json_array_or_undefined(rest_json, rest_pull_schema);
2933
+ if (parsed === void 0) throw new Error(NOT_A_PULL_LISTING_MESSAGE);
2934
+ return parsed;
2935
+ }
2936
+ function select_pull(pulls) {
2937
+ return pulls.find((pull) => pull.state === OPEN_STATE) ?? pulls[0];
2938
+ }
2939
+ function is_merged(pull) {
2940
+ return pull.merged === true || typeof pull.merged_at === "string";
2941
+ }
2942
+ function to_pr_state(pull) {
2943
+ return is_merged(pull) ? MERGED_STATE : to_gh_state(pull.state);
2944
+ }
2945
+ function to_repo_name(side) {
2946
+ return side?.repo?.full_name;
2947
+ }
2948
+ function is_same_repository_head(pull) {
2949
+ const head_repo = to_repo_name(pull.head);
2950
+ return head_repo !== void 0 && head_repo === to_repo_name(pull.base);
2951
+ }
2952
+ function to_pr_info(pull) {
2953
+ return {
2954
+ mergeable: pull.mergeable,
2955
+ mergeStateStatus: to_gh_state(pull.mergeable_state),
2956
+ state: to_pr_state(pull)
2957
+ };
2958
+ }
2959
+ function to_pr_comments(rest_json) {
2960
+ const parsed = parse_json_array_or_undefined(rest_json, rest_comment_schema);
2961
+ if (parsed === void 0) throw new Error(NOT_A_COMMENT_LISTING_MESSAGE);
2962
+ return parsed.map((comment) => ({
2963
+ body: comment.body ?? EMPTY_BODY2,
2964
+ url: comment.html_url,
2965
+ author: { login: comment.user?.login }
2966
+ }));
2967
+ }
2968
+ var git_gh_pr_rest = {
2969
+ parse_rest_pull,
2970
+ parse_rest_pulls,
2971
+ select_pull,
2972
+ is_same_repository_head,
2973
+ is_merged,
2974
+ to_pr_state,
2975
+ to_pr_info,
2976
+ to_pr_comments
2977
+ };
2978
+
2979
+ // scripts/gh/git-gh-pr-read.ts
2980
+ var pr_number_by_branch = /* @__PURE__ */ new Map();
2981
+ var LOOKUP_QUERY = "state=all&sort=created&direction=desc&per_page=100";
2982
+ var COMMENTS_QUERY = FULL_PAGE_QUERY;
2983
+ var OWNER_PLACEHOLDER = "{owner}";
2984
+ var NO_PULL_REQUEST_MESSAGE = "gh api found no pull request for branch";
2985
+ var UNREADABLE_PULL_REQUEST_MESSAGE = "gh api could not read the pull requests for branch";
2986
+ function lookup_path(branch_name) {
2987
+ const head = `${OWNER_PLACEHOLDER}:${encodeURIComponent(branch_name)}`;
2988
+ return `${git_gh_api_path.pulls_api_path()}?head=${head}&${LOOKUP_QUERY}`;
2989
+ }
2990
+ async function fetch_pr_number(branch_name) {
2991
+ const json = await git_gh_exec.exec_gh_api({ path: lookup_path(branch_name) });
2992
+ return git_gh_pr_rest.select_pull(git_gh_pr_rest.parse_rest_pulls(json))?.number;
2993
+ }
2994
+ var pending_pr_number_by_branch = /* @__PURE__ */ new Map();
2995
+ var pull_by_number = /* @__PURE__ */ new Map();
2996
+ async function fetch_pr_number_read(branch_name) {
2997
+ try {
2998
+ const pr_number = await fetch_pr_number(branch_name);
2999
+ if (pr_number === void 0) return { kind: "missing" };
3000
+ pr_number_by_branch.set(branch_name, pr_number);
3001
+ return { kind: "read", pr_number };
3002
+ } catch (error) {
3003
+ return { kind: "unreadable", cause: error };
3004
+ }
3005
+ }
3006
+ async function start_pr_number_read(branch_name) {
3007
+ const pending = pending_pr_number_by_branch.get(branch_name);
3008
+ if (pending !== void 0) return await pending;
3009
+ const lookup = fetch_pr_number_read(branch_name);
3010
+ pending_pr_number_by_branch.set(branch_name, lookup);
3011
+ try {
3012
+ return await lookup;
3013
+ } finally {
3014
+ pending_pr_number_by_branch.delete(branch_name);
3015
+ }
3016
+ }
3017
+ function forget_pr_numbers() {
3018
+ pr_number_by_branch.clear();
3019
+ pending_pr_number_by_branch.clear();
3020
+ pull_by_number.clear();
3021
+ }
3022
+ async function read_pr_number(branch_name) {
3023
+ const cached = pr_number_by_branch.get(branch_name);
3024
+ if (cached !== void 0) return { kind: "read", pr_number: cached };
3025
+ return await start_pr_number_read(branch_name);
3026
+ }
3027
+ async function resolve_pr_number(branch_name) {
3028
+ const read = await read_pr_number(branch_name);
3029
+ return read.kind === "read" ? read.pr_number : void 0;
3030
+ }
3031
+ function to_unreadable_error(branch_name, cause) {
3032
+ return new Error(`${UNREADABLE_PULL_REQUEST_MESSAGE}: ${branch_name}`, { cause });
3033
+ }
3034
+ async function require_pr_number(branch_name) {
3035
+ const read = await read_pr_number(branch_name);
3036
+ if (read.kind === "read") return read.pr_number;
3037
+ if (read.kind === "missing") throw new Error(`${NO_PULL_REQUEST_MESSAGE}: ${branch_name}`);
3038
+ throw to_unreadable_error(branch_name, read.cause);
3039
+ }
3040
+ async function read_pull(pr_number) {
3041
+ const json = await git_gh_exec.exec_gh_api({
3042
+ path: git_gh_api_path.pull_api_path(String(pr_number))
3043
+ });
3044
+ return git_gh_pr_rest.parse_rest_pull(json);
3045
+ }
3046
+ async function read_remembered_pull(pr_number) {
3047
+ const pending = pull_by_number.get(pr_number) ?? read_pull(pr_number);
3048
+ pull_by_number.set(pr_number, pending);
3049
+ try {
3050
+ return await pending;
3051
+ } catch (error) {
3052
+ if (pull_by_number.get(pr_number) === pending) pull_by_number.delete(pr_number);
3053
+ throw error;
3054
+ }
3055
+ }
3056
+ async function read_pull_of_branch(branch_name, read = read_remembered_pull) {
3057
+ const number_read = await read_pr_number(branch_name);
3058
+ if (number_read.kind !== "read") return number_read;
3059
+ try {
3060
+ return { kind: "read", pull: await read(number_read.pr_number) };
3061
+ } catch (error) {
3062
+ return { kind: "unreadable", cause: error };
3063
+ }
3064
+ }
3065
+ async function read_pull_or_undefined(branch_name) {
3066
+ const read = await read_pull_of_branch(branch_name);
3067
+ return read.kind === "read" ? read.pull : void 0;
3068
+ }
3069
+ async function pr_exists(branch_name) {
3070
+ const read = await read_pr_number(branch_name);
3071
+ if (read.kind === "unreadable") throw to_unreadable_error(branch_name, read.cause);
3072
+ return read.kind === "read";
3073
+ }
3074
+ async function pr_get_number(branch_name) {
3075
+ return await resolve_pr_number(branch_name);
3076
+ }
3077
+ async function pr_get_url(branch_name) {
3078
+ const pull = await read_pull_or_undefined(branch_name);
3079
+ if (pull?.html_url === void 0) return void 0;
3080
+ return git_gh_helpers.parse_pr_state_string(pull.html_url);
3081
+ }
3082
+ async function pr_get_merge_state(branch_name) {
3083
+ const read = await read_pull_of_branch(branch_name, read_pull);
3084
+ if (read.kind !== "read") return void 0;
3085
+ const { pull } = read;
3086
+ return {
3087
+ is_merged: git_gh_pr_rest.is_merged(pull),
3088
+ merged_at: pull.merged_at ?? void 0,
3089
+ head_sha: pull.head?.sha,
3090
+ merge_state_status: to_gh_state(pull.mergeable_state)
3091
+ };
3092
+ }
3093
+ async function pr_get_body(branch_name) {
3094
+ const pull = await read_pull_or_undefined(branch_name);
3095
+ const body = pull?.body;
3096
+ return typeof body === "string" && body.length > 0 ? body : void 0;
3097
+ }
3098
+ async function pr_view(branch_name) {
3099
+ const read = await read_pull_of_branch(branch_name, read_pull);
3100
+ if (read.kind === "unreadable") throw to_unreadable_error(branch_name, read.cause);
3101
+ if (read.kind === "missing") return "";
3102
+ return JSON.stringify(git_gh_pr_rest.to_pr_info(read.pull));
3103
+ }
3104
+ async function read_comments(branch_name, to_path, to_json) {
3105
+ const pr_number = await resolve_pr_number(branch_name);
3106
+ if (pr_number === void 0) return void 0;
3107
+ const path = `${to_path(String(pr_number))}${COMMENTS_QUERY}`;
3108
+ try {
3109
+ return to_json(await git_gh_exec.exec_gh_api({ path, should_paginate: true }));
3110
+ } catch {
3111
+ return void 0;
3112
+ }
3113
+ }
3114
+ function to_comments_json(raw) {
3115
+ return JSON.stringify(git_gh_pr_rest.to_pr_comments(raw));
3116
+ }
3117
+ function as_served(raw) {
3118
+ return raw;
3119
+ }
3120
+ async function pr_get_comments(branch_name) {
3121
+ return await read_comments(branch_name, git_gh_api_path.issue_comments_api_path, to_comments_json);
3122
+ }
3123
+ async function pr_get_review_comments(branch_name) {
3124
+ return await read_comments(branch_name, git_gh_api_path.pull_comments_api_path, as_served);
3125
+ }
3126
+ var git_gh_pr_read = {
3127
+ pr_exists,
3128
+ pr_get_number,
3129
+ pr_get_url,
3130
+ pr_get_body,
3131
+ pr_get_merge_state,
3132
+ pr_view,
3133
+ pr_get_comments,
3134
+ pr_get_review_comments
3135
+ };
3136
+
3137
+ // scripts/gh/git-gh-pr-review.ts
3138
+ import { z as z10 } from "zod";
3139
+ var REVIEW_APPROVED = "APPROVED";
3140
+ var REVIEW_CHANGES_REQUESTED = "CHANGES_REQUESTED";
3141
+ var REVIEW_NONE = "";
3142
+ var STATE_CHANGING_REVIEWS = /* @__PURE__ */ new Set([REVIEW_APPROVED, REVIEW_CHANGES_REQUESTED]);
3143
+ var rest_review_schema = z10.looseObject({
3144
+ state: z10.string().optional(),
3145
+ user: z10.looseObject({ login: z10.string().optional() }).nullish()
3146
+ });
3147
+ var NOT_A_REVIEW_LISTING = "gh api answered something other than a review listing";
3148
+ function parse_rest_reviews(reviews_json) {
3149
+ const parsed = parse_json_array_or_undefined(reviews_json, rest_review_schema);
3150
+ if (parsed === void 0) throw new Error(NOT_A_REVIEW_LISTING);
3151
+ return parsed;
3152
+ }
3153
+ var UNATTRIBUTED_REVIEWER = "(no author)";
3154
+ function read_reviewer(review) {
3155
+ const login = review.user?.login;
3156
+ return typeof login === "string" && login.length > 0 ? login : UNATTRIBUTED_REVIEWER;
3157
+ }
3158
+ function read_state_changing(review) {
3159
+ const state = review.state?.toUpperCase();
3160
+ return state !== void 0 && STATE_CHANGING_REVIEWS.has(state) ? state : void 0;
3161
+ }
3162
+ function fold_latest_states(reviews) {
3163
+ const latest = /* @__PURE__ */ new Map();
3164
+ for (const review of reviews) {
3165
+ const state = read_state_changing(review);
3166
+ if (state !== void 0) latest.set(read_reviewer(review), state);
3167
+ }
3168
+ return latest;
3169
+ }
3170
+ function to_review_decision(reviews_json) {
3171
+ const latest = new Set(fold_latest_states(parse_rest_reviews(reviews_json)).values());
3172
+ if (latest.has(REVIEW_CHANGES_REQUESTED)) return REVIEW_CHANGES_REQUESTED;
3173
+ return latest.has(REVIEW_APPROVED) ? REVIEW_APPROVED : REVIEW_NONE;
3174
+ }
3175
+ var git_gh_pr_review = { to_review_decision };
3176
+
3177
+ // scripts/gh/git-gh-pr-rollup.ts
3178
+ import { z as z11 } from "zod";
3179
+ var STATUS_CONTEXT_TYPE_NAME = "StatusContext";
3180
+ var TYPE_NAME_KEY = "__typename";
3181
+ var rollup_element_schema = z11.looseObject({});
3182
+ var check_runs_page_schema = z11.looseObject({
3183
+ // Required, not optional: GitHub always names the key, and accepting a page without one would
3184
+ // answer an empty rollup — which `git-pr-followup.ts` reports as "this branch has no checks".
3185
+ check_runs: z11.array(rollup_element_schema)
3186
+ });
3187
+ var id_holder_schema = z11.object({ id: z11.number() });
3188
+ var status_page_schema = z11.looseObject({
3189
+ statuses: z11.array(rollup_element_schema)
3190
+ });
3191
+ var NOT_A_CHECK_RUNS_LISTING = "gh api answered something other than a check run listing";
3192
+ var NOT_A_STATUS_LISTING = "gh api answered something other than a commit status listing";
3193
+ function read_pages(raw_json, schema, message) {
3194
+ const pages = parse_json_array_or_undefined(raw_json, schema);
3195
+ if (pages === void 0) throw new Error(message);
3196
+ return pages;
3197
+ }
3198
+ var NO_SUITE = -1;
3199
+ function read_id(value) {
3200
+ const parsed = id_holder_schema.safeParse(value);
3201
+ return parsed.success ? parsed.data.id : void 0;
3202
+ }
3203
+ function check_run_group_key(run) {
3204
+ const { name, app } = run;
3205
+ if (typeof name !== "string") return void 0;
3206
+ return JSON.stringify([name, read_id(app)]);
3207
+ }
3208
+ function read_rank(run) {
3209
+ const id = read_id(run);
3210
+ if (id === void 0) return void 0;
3211
+ return { suite: read_id(run["check_suite"]) ?? NO_SUITE, run: id };
3212
+ }
3213
+ function is_ranked_above(candidate, current) {
3214
+ if (candidate.suite !== current.suite) return candidate.suite > current.suite;
3215
+ return candidate.run > current.run;
3216
+ }
3217
+ function should_replace(previous, rank) {
3218
+ const previous_rank = previous === void 0 ? void 0 : read_rank(previous);
3219
+ return previous_rank === void 0 || is_ranked_above(rank, previous_rank);
3220
+ }
3221
+ function remember_newest_run(run, newest) {
3222
+ const key2 = check_run_group_key(run);
3223
+ const rank = read_rank(run);
3224
+ if (key2 === void 0 || rank === void 0) return;
3225
+ if (should_replace(newest.get(key2), rank)) newest.set(key2, run);
3226
+ }
3227
+ function is_newest_run(run, newest) {
3228
+ const key2 = check_run_group_key(run);
3229
+ if (key2 === void 0 || read_rank(run) === void 0) return true;
3230
+ return newest.get(key2) === run;
3231
+ }
3232
+ function to_check_run_items(check_runs_json) {
3233
+ const pages = read_pages(check_runs_json, check_runs_page_schema, NOT_A_CHECK_RUNS_LISTING);
3234
+ const runs = pages.flatMap((page) => page.check_runs);
3235
+ const newest = /* @__PURE__ */ new Map();
3236
+ for (const run of runs) remember_newest_run(run, newest);
3237
+ return runs.filter((run) => is_newest_run(run, newest));
3238
+ }
3239
+ function to_status_context_items(status_json) {
3240
+ const pages = read_pages(status_json, status_page_schema, NOT_A_STATUS_LISTING);
3241
+ return pages.flatMap((page) => page.statuses).map((status) => ({ ...status, [TYPE_NAME_KEY]: STATUS_CONTEXT_TYPE_NAME }));
3242
+ }
3243
+ function to_status_check_rollup(input) {
3244
+ return [
3245
+ ...to_check_run_items(input.check_runs_json),
3246
+ ...to_status_context_items(input.status_json)
3247
+ ];
3248
+ }
3249
+ var git_gh_pr_rollup = {
3250
+ to_status_check_rollup
3251
+ };
3252
+
3253
+ // scripts/gh/git-gh-pr-snapshot.ts
3254
+ var NO_HEAD_SHA_MESSAGE = "gh api answered a pull request with no head commit";
3255
+ async function read_object_pages(path) {
3256
+ return await git_gh_exec.exec_gh_api({
3257
+ path: `${path}${FULL_PAGE_QUERY}`,
3258
+ should_paginate: true,
3259
+ should_slurp: true
3260
+ });
3261
+ }
3262
+ async function read_array_pages(path) {
3263
+ return await git_gh_exec.exec_gh_api({
3264
+ path: `${path}${FULL_PAGE_QUERY}`,
3265
+ should_paginate: true
3266
+ });
3267
+ }
3268
+ function read_head_sha(pull) {
3269
+ const sha = pull.head?.sha;
3270
+ if (sha === void 0) throw new Error(NO_HEAD_SHA_MESSAGE);
3271
+ return sha;
3272
+ }
3273
+ async function read_status_check_rollup(commit_sha) {
3274
+ const [check_runs_json, status_json] = await Promise.all([
3275
+ read_object_pages(git_gh_api_path.commit_check_runs_api_path(commit_sha)),
3276
+ read_object_pages(git_gh_api_path.commit_status_api_path(commit_sha))
3277
+ ]);
3278
+ return git_gh_pr_rollup.to_status_check_rollup({ check_runs_json, status_json });
3279
+ }
3280
+ async function pr_get_review_decision(pr_number) {
3281
+ const path = git_gh_api_path.pull_reviews_api_path(String(pr_number));
3282
+ return git_gh_pr_review.to_review_decision(await read_array_pages(path));
3283
+ }
3284
+ async function build_checks_fields(pull) {
3285
+ return {
3286
+ statusCheckRollup: await read_status_check_rollup(read_head_sha(pull)),
3287
+ mergeStateStatus: to_gh_state(pull.mergeable_state)
3288
+ };
3289
+ }
3290
+ async function resolve_pull(branch_name) {
3291
+ const pr_number = await require_pr_number(branch_name);
3292
+ return { pr_number, pull: await read_pull(pr_number) };
3293
+ }
3294
+ async function pr_get_checks_snapshot(branch_name) {
3295
+ const { pr_number, pull } = await resolve_pull(branch_name);
3296
+ return { pr_number, snapshot_json: JSON.stringify(await build_checks_fields(pull)) };
3297
+ }
3298
+ async function pr_get_state_snapshot(branch_name) {
3299
+ const { pr_number, pull } = await resolve_pull(branch_name);
3300
+ const [fields, review_decision] = await Promise.all([
3301
+ build_checks_fields(pull),
3302
+ pr_get_review_decision(pr_number)
3303
+ ]);
3304
+ return JSON.stringify({ ...fields, reviewDecision: review_decision });
3305
+ }
3306
+ var git_gh_pr_snapshot = {
3307
+ pr_get_state_snapshot,
3308
+ pr_get_checks_snapshot,
3309
+ pr_get_review_decision
3310
+ };
3311
+
3312
+ // scripts/gh/git-gh-pr.ts
3313
+ var HTML_URL_FILTER2 = ".html_url";
3314
+ var PUT_METHOD = "PUT";
3315
+ var PATCH_METHOD2 = "PATCH";
3316
+ var MERGE_COMMIT_METHOD = "merge";
3317
+ var MERGE_REQUEST_TIMEOUT_MS = 18e4;
3318
+ var MERGE_UNCONFIRMED_MESSAGE = "gh api could not read the pull request back after the merge request failed";
3319
+ var MERGE_READ_BACK_ATTEMPTS = 3;
3320
+ var MERGE_READ_BACK_INTERVAL_MS = 1e3;
3321
+ var PR_NUMBER_PATTERN = /\/pull\/([1-9]\d*)$/u;
3322
+ var LABELS_SEGMENT2 = "/labels";
3323
+ var PR_LABELS = z12.array(z12.object({ name: z12.string() }));
3324
+ async function add_pr_classification(number, label) {
3325
+ await git_gh_exec.exec_gh_api({
3326
+ path: `${git_gh_api_path.issue_api_path(number)}${LABELS_SEGMENT2}`,
3327
+ body: JSON.stringify({ labels: [label] })
3328
+ });
3329
+ }
3330
+ async function pr_get_classification(branch_name) {
3331
+ const number = await require_pr_number(branch_name);
3332
+ const response = await git_gh_exec.exec_gh_api({
3333
+ path: `${git_gh_api_path.issue_api_path(String(number))}${LABELS_SEGMENT2}`
3334
+ });
3335
+ const names = PR_LABELS.parse(JSON.parse(response)).map((label) => label.name.toLowerCase());
3336
+ const selected = names.filter((name) => pr_classification.is_classification(name));
3337
+ if (selected.length === 0) return void 0;
3338
+ const error = pr_classification.classification_error(names, "human");
3339
+ if (error !== void 0) throw new Error(error);
3340
+ return selected[0];
3341
+ }
3342
+ async function pr_ensure_classification(branch_name, label) {
3343
+ if (await pr_get_classification(branch_name) !== void 0) return;
3344
+ const number = await require_pr_number(branch_name);
3345
+ await add_pr_classification(String(number), label);
3346
+ }
3347
+ async function post_pull_request(title, body) {
3348
+ const base = await git_command.get_default_branch();
3349
+ const head = await git_command.branch();
3350
+ forget_pr_numbers();
3351
+ try {
3352
+ return await git_gh_exec.exec_gh_api({
3353
+ path: git_gh_api_path.pulls_api_path(),
3354
+ body: JSON.stringify({ title, body, head, base }),
3355
+ jq_filter: HTML_URL_FILTER2
3356
+ });
3357
+ } catch (error) {
3358
+ return git_gh_helpers.handle_pr_create_error(error);
3359
+ }
3360
+ }
3361
+ async function pr_create(title, body, label) {
3362
+ const classification_error2 = pr_classification.classification_error([label], "human");
3363
+ if (classification_error2 !== void 0) throw new Error(classification_error2);
3364
+ const url = await post_pull_request(title, body);
3365
+ const number = PR_NUMBER_PATTERN.exec(url)?.[1];
3366
+ if (number === void 0) throw new Error(`Could not identify the created pull request: ${url}`);
3367
+ await add_pr_classification(number, label);
3368
+ return url;
3369
+ }
3370
+ async function pr_comment(branch_name, body) {
3371
+ const pr_number = await require_pr_number(branch_name);
3372
+ return await git_gh_issue_write.issue_comment(String(pr_number), body);
3373
+ }
3374
+ async function pr_update_body(branch_name, body) {
3375
+ const pr_number = await require_pr_number(branch_name);
3376
+ forget_pr_numbers();
3377
+ await git_gh_exec.exec_gh_api({
3378
+ path: git_gh_api_path.pull_api_path(String(pr_number)),
3379
+ method: PATCH_METHOD2,
3380
+ body: JSON.stringify({ body })
3381
+ });
3382
+ }
3383
+ async function put_merge(pr_number) {
3384
+ forget_pr_numbers();
3385
+ await git_gh_exec.exec_gh_api({
3386
+ path: git_gh_api_path.pull_merge_api_path(String(pr_number)),
3387
+ method: PUT_METHOD,
3388
+ body: JSON.stringify({ merge_method: MERGE_COMMIT_METHOD }),
3389
+ timeout_ms: MERGE_REQUEST_TIMEOUT_MS
3390
+ });
3391
+ }
3392
+ async function read_merge_state(pr_number) {
3393
+ try {
3394
+ return git_gh_pr_rest.is_merged(await read_pull(pr_number));
3395
+ } catch (error) {
3396
+ console.warn(`Could not read the pull request back: ${String(error)}`);
3397
+ return void 0;
3398
+ }
3399
+ }
3400
+ async function sleep_between_read_backs(attempt) {
3401
+ if (attempt < MERGE_READ_BACK_ATTEMPTS - 1) await poll.sleep(MERGE_READ_BACK_INTERVAL_MS);
3402
+ }
3403
+ async function has_merge_landed(pr_number, merge_error) {
3404
+ for (let attempt = 0; attempt < MERGE_READ_BACK_ATTEMPTS; attempt += 1) {
3405
+ const is_merged2 = await read_merge_state(pr_number);
3406
+ if (is_merged2 !== void 0) return is_merged2;
3407
+ await sleep_between_read_backs(attempt);
3408
+ }
3409
+ throw new Error(MERGE_UNCONFIRMED_MESSAGE, { cause: merge_error });
3410
+ }
3411
+ async function pr_merge(branch_name) {
3412
+ const pr_number = await require_pr_number(branch_name);
3413
+ try {
3414
+ await put_merge(pr_number);
3415
+ } catch (error) {
3416
+ if (!await has_merge_landed(pr_number, error)) throw error;
3417
+ }
3418
+ }
3419
+ var git_gh_pr = {
3420
+ ...git_gh_pr_read,
3421
+ ...git_gh_pr_snapshot,
3422
+ pr_create,
3423
+ pr_get_classification,
3424
+ pr_ensure_classification,
3425
+ pr_comment,
3426
+ pr_merge,
3427
+ pr_update_body
3428
+ };
3429
+
3430
+ // scripts/gh/git-gh-pr-auto-merge.ts
3431
+ var GRAPHQL_PATH = "graphql";
3432
+ var OPEN_PULLS_QUERY = `${git_gh_api_path.FULL_PAGE_QUERY}&state=open`;
3433
+ var MISSING_NODE_ID_MESSAGE = "gh api answered a pull request without a node_id";
3434
+ var ENABLE_AUTO_MERGE_MUTATION = "mutation($id: ID!) { enablePullRequestAutoMerge(input: { pullRequestId: $id, mergeMethod: MERGE }) { clientMutationId } }";
3435
+ async function pr_enable_auto_merge(branch_name) {
3436
+ const pull = await read_pull(await require_pr_number(branch_name));
3437
+ if (pull.node_id === void 0) throw new Error(MISSING_NODE_ID_MESSAGE);
3438
+ await git_gh_exec.exec_gh_api({
3439
+ path: GRAPHQL_PATH,
3440
+ body: JSON.stringify({ query: ENABLE_AUTO_MERGE_MUTATION, variables: { id: pull.node_id } })
3441
+ });
3442
+ }
3443
+ async function pr_is_merged(branch_name) {
3444
+ try {
3445
+ return git_gh_pr_rest.is_merged(await read_pull(await require_pr_number(branch_name)));
3446
+ } catch (error) {
3447
+ error_text.trace_swallowed("git_gh_pr_auto_merge.pr_is_merged", error);
3448
+ return false;
3449
+ }
3450
+ }
3451
+ function head_reference_of(pull) {
3452
+ return pull.head?.ref ?? "";
3453
+ }
3454
+ function has_head_prefix(pull, prefix) {
3455
+ return git_gh_pr_rest.is_same_repository_head(pull) && head_reference_of(pull).startsWith(prefix);
3456
+ }
3457
+ function to_open_pull(pull) {
3458
+ return {
3459
+ number: pull.number,
3460
+ head_ref: head_reference_of(pull),
3461
+ has_auto_merge: pull.auto_merge !== null && pull.auto_merge !== void 0
3462
+ };
3463
+ }
3464
+ async function pr_list_open_with_head_prefix(prefix) {
3465
+ const json = await git_gh_exec.exec_gh_api({
3466
+ path: `${git_gh_api_path.pulls_api_path()}${OPEN_PULLS_QUERY}`,
3467
+ should_paginate: true
3468
+ });
3469
+ return git_gh_pr_rest.parse_rest_pulls(json).filter((pull) => has_head_prefix(pull, prefix)).map((pull) => to_open_pull(pull));
3470
+ }
3471
+ var git_gh_pr_auto_merge = {
3472
+ pr_enable_auto_merge,
3473
+ pr_is_merged,
3474
+ pr_list_open_with_head_prefix
3475
+ };
3476
+
3477
+ // scripts/gh/git-gh-repo.ts
3478
+ async function repo_get_name_with_owner() {
3479
+ try {
3480
+ const result = await git_gh_exec.exec_gh_api({
3481
+ path: git_gh_api_path.repo_api_path(),
3482
+ jq_filter: ".full_name"
3483
+ });
3484
+ return git_gh_helpers.parse_pr_state_string(result);
3485
+ } catch {
3486
+ return void 0;
3487
+ }
3488
+ }
3489
+ var git_gh_repo = {
3490
+ repo_get_name_with_owner
3491
+ };
3492
+
3493
+ // scripts/gh/git-pr-checks.ts
3494
+ var SECONDS_TO_MS = 1e3;
3495
+ var CHECK_WAIT_INTERVAL_MS = 1e4;
3496
+ var DEFAULT_TIMEOUT_SECONDS = 1920;
3497
+ function compute_max_attempts(timeout_seconds, interval_ms) {
3498
+ return Math.ceil(timeout_seconds / (interval_ms / SECONDS_TO_MS)) + 1;
3499
+ }
3500
+ var DEFAULT_MAX_ATTEMPTS = compute_max_attempts(DEFAULT_TIMEOUT_SECONDS, CHECK_WAIT_INTERVAL_MS);
3501
+ function get_configured_max_attempts() {
3502
+ const environment_seconds = Number(process.env["JOSH_CI_TIMEOUT_SECONDS"]);
3503
+ return Number.isFinite(environment_seconds) && environment_seconds > 0 ? compute_max_attempts(environment_seconds, CHECK_WAIT_INTERVAL_MS) : DEFAULT_MAX_ATTEMPTS;
3504
+ }
3505
+ var CHECK_MAX_ATTEMPTS = get_configured_max_attempts();
3506
+ var DEFAULT_STABLE_READS = 2;
3507
+ var MAX_CONSECUTIVE_READ_FAILURES = 3;
3508
+ var PR_CHECKS_TIMEOUT_MESSAGE = "Timed out while waiting for PR checks to complete.";
3509
+ function is_pr_checks_timeout(error) {
3510
+ return error instanceof Error && error.message === PR_CHECKS_TIMEOUT_MESSAGE;
3511
+ }
3512
+ function should_always_read_review_decision() {
3513
+ return true;
3514
+ }
3515
+ var MERGE_GATE_EVALUATOR = {
3516
+ evaluate: evaluate_pr_state,
3517
+ describe: describe_pr_failure,
3518
+ should_read_review_decision: is_review_decision_decisive
3519
+ };
3520
+ function advance_stable_count(previous, state) {
3521
+ return state === "success" ? previous + 1 : 0;
3522
+ }
3523
+ function failure_error(message, snapshot) {
3524
+ return is_merge_conflict(snapshot.merge_state_status) ? new PrConflictError(message) : new Error(message);
3525
+ }
3526
+ function classify_poll_result(input) {
3527
+ const state = input.evaluator.evaluate(input.snapshot);
3528
+ if (state === "failure") {
3529
+ throw failure_error(input.evaluator.describe(input.snapshot), input.snapshot);
3530
+ }
3531
+ const next_stable_count = advance_stable_count(input.stable_count, state);
3532
+ return {
3533
+ is_done: next_stable_count >= input.required_stable_reads,
3534
+ next_stable_count
3535
+ };
3536
+ }
3537
+ async function read_pr_state(input, evaluator) {
3538
+ try {
3539
+ const snapshot = await input.options.fetcher(
3540
+ input.options.branch_name,
3541
+ evaluator.should_read_review_decision ?? should_always_read_review_decision
3542
+ );
3543
+ return { kind: "read", snapshot };
3544
+ } catch (error) {
3545
+ return { kind: "unreadable", cause: error };
3546
+ }
3547
+ }
3548
+ async function sleep_before_next_attempt(input) {
3549
+ if (input.attempt < input.options.max_attempts - 1) {
3550
+ await poll.sleep(input.options.interval_ms);
3551
+ }
3552
+ }
3553
+ async function retry_after_unreadable(input, cause) {
3554
+ const next_failure_count = input.failure_count + 1;
3555
+ if (next_failure_count >= MAX_CONSECUTIVE_READ_FAILURES) throw cause;
3556
+ console.warn(
3557
+ `Could not read the PR state (${String(next_failure_count)}/${String(MAX_CONSECUTIVE_READ_FAILURES)}); asking again on the next poll: ${String(cause)}`
3558
+ );
3559
+ await sleep_before_next_attempt(input);
3560
+ return { next_stable_count: 0, next_failure_count, read_failure: cause };
3561
+ }
3562
+ function to_exhaustion_error(last_read_failure) {
3563
+ return last_read_failure ?? new Error(PR_CHECKS_TIMEOUT_MESSAGE);
3564
+ }
3565
+ async function attempt_pr_success_poll(input) {
3566
+ const evaluator = input.options.evaluator ?? MERGE_GATE_EVALUATOR;
3567
+ const read = await read_pr_state(input, evaluator);
3568
+ if (read.kind === "unreadable") return await retry_after_unreadable(input, read.cause);
3569
+ const classification = classify_poll_result({
3570
+ snapshot: read.snapshot,
3571
+ stable_count: input.stable_count,
3572
+ required_stable_reads: input.options.required_stable_reads,
3573
+ evaluator
3574
+ });
3575
+ if (classification.is_done) {
3576
+ return { snapshot: read.snapshot, next_stable_count: 0, next_failure_count: 0 };
3577
+ }
3578
+ await sleep_before_next_attempt(input);
3579
+ return { next_stable_count: classification.next_stable_count, next_failure_count: 0 };
3580
+ }
3581
+ async function wait_for_pr_success(options) {
3582
+ let carried = { next_stable_count: 0, next_failure_count: 0 };
3583
+ for (let attempt = 0; attempt < options.max_attempts; attempt += 1) {
3584
+ console.info(`Checking PR status\u2026 (${String(attempt + 1)}/${String(options.max_attempts)})`);
3585
+ carried = await attempt_pr_success_poll({
3586
+ options,
3587
+ stable_count: carried.next_stable_count,
3588
+ failure_count: carried.next_failure_count,
3589
+ attempt
3590
+ });
3591
+ if (carried.snapshot !== void 0) return carried.snapshot;
3592
+ }
3593
+ throw to_exhaustion_error(carried.read_failure);
3594
+ }
3595
+ async function default_fetch_pr_state(branch_name, should_read_review_decision = should_always_read_review_decision) {
3596
+ const checks = await git_gh_pr_snapshot.pr_get_checks_snapshot(branch_name);
3597
+ const snapshot = parse_pr_state_snapshot(checks.snapshot_json);
3598
+ if (!should_read_review_decision(snapshot)) return snapshot;
3599
+ const decision = await git_gh_pr_snapshot.pr_get_review_decision(checks.pr_number);
3600
+ return { ...snapshot, review_decision: read_string(decision) };
3601
+ }
3602
+
3603
+ // scripts/gh/git-pr-checks-watch.ts
3604
+ var PR_CHECKS_WATCH_TIMEOUT_MS = 12e4;
3605
+ var WATCH_TIMED_OUT_NOTE = "\u23F1\uFE0F pr checks --watch timed out.";
3606
+ var NO_CHECKS_MESSAGE = "gh api reported no checks on the branch";
3607
+ var CHECKS_FAILED_MESSAGE = "gh api reported a failing check on the branch";
3608
+ function is_awaited_check(check) {
3609
+ return !is_coderabbit_check(check.name) || is_required_check(check.name);
3610
+ }
3611
+ function evaluate_checks_settled(snapshot) {
3612
+ const awaited = snapshot.rollup.filter((check) => is_awaited_check(check));
3613
+ const considered = awaited.length === 0 ? snapshot.rollup : awaited;
3614
+ if (considered.length === 0 || considered.some((check) => check.status === CHECK_STATUS_PENDING)) {
3615
+ return "pending";
3616
+ }
3617
+ return snapshot.rollup.some((check) => check.status === CHECK_STATUS_FAIL) ? "failure" : "success";
3618
+ }
3619
+ function describe_checks_failure(snapshot) {
3620
+ const failed = snapshot.rollup.filter((check) => check.status === CHECK_STATUS_FAIL);
3621
+ return `${CHECKS_FAILED_MESSAGE}: ${failed.map((check) => check.name).join(", ")}`;
3622
+ }
3623
+ function should_never_read_review_decision() {
3624
+ return false;
3625
+ }
3626
+ var CHECKS_SETTLED_EVALUATOR = {
3627
+ evaluate: evaluate_checks_settled,
3628
+ describe: describe_checks_failure,
3629
+ should_read_review_decision: should_never_read_review_decision
3630
+ };
3631
+ async function watch_until_settled(branch_name) {
3632
+ await wait_for_pr_success({
3633
+ branch_name,
3634
+ fetcher: default_fetch_pr_state,
3635
+ interval_ms: CHECK_WAIT_INTERVAL_MS,
3636
+ max_attempts: compute_max_attempts(
3637
+ PR_CHECKS_WATCH_TIMEOUT_MS / SECONDS_TO_MS,
3638
+ CHECK_WAIT_INTERVAL_MS
3639
+ ),
3640
+ required_stable_reads: DEFAULT_STABLE_READS,
3641
+ evaluator: CHECKS_SETTLED_EVALUATOR
3642
+ });
3643
+ }
3644
+ async function fail_when_no_checks(branch_name) {
3645
+ const snapshot = await default_fetch_pr_state(branch_name, should_never_read_review_decision);
3646
+ if (snapshot.rollup.length === 0) throw new Error(NO_CHECKS_MESSAGE);
3647
+ }
3648
+ async function pr_checks_watch(branch_name) {
3649
+ try {
3650
+ await watch_until_settled(branch_name);
3651
+ return { timed_out: false };
3652
+ } catch (error) {
3653
+ if (!is_pr_checks_timeout(error)) throw error;
3654
+ await fail_when_no_checks(branch_name);
3655
+ console.info(WATCH_TIMED_OUT_NOTE);
3656
+ return { timed_out: true };
3657
+ }
3658
+ }
3659
+ var git_pr_checks_watch = { pr_checks_watch };
3660
+
3661
+ // scripts/gh/git-gh-command.ts
3662
+ var git_gh_command = {
3663
+ ...git_gh_pr,
3664
+ ...git_gh_pr_auto_merge,
3665
+ pr_checks_watch: git_pr_checks_watch.pr_checks_watch,
3666
+ ...git_gh_issue,
3667
+ ...git_gh_repo
3668
+ };
3669
+
3670
+ export {
3671
+ bounded_pool,
3672
+ run_event_stream,
3673
+ run_event_scope,
3674
+ run_event_stream_emit,
3675
+ shell_segments,
3676
+ bash_triggers,
3677
+ tail_commands,
3678
+ filing_cap,
3679
+ CONTEXT_CUT_THRESHOLD,
3680
+ issue_citation,
3681
+ session_cite,
3682
+ run_hold,
3683
+ run_cut_handoff,
3684
+ run_cut,
3685
+ run_tail_rule,
3686
+ lane_background,
3687
+ IN_PROGRESS_LABEL,
3688
+ NEEDS_DECISION_LABEL,
3689
+ RUN_SOLO_LABEL,
3690
+ RUN_LANE_LABEL,
3691
+ NEEDS_HUMAN_REVIEW_LABEL,
3692
+ ALREADY_DONE_LABEL,
3693
+ has_any_label,
3694
+ has_label_name,
3695
+ lane_handoff,
3696
+ lane_park,
3697
+ repo_party,
3698
+ git_gh_api_path,
3699
+ read_json_listing,
3700
+ parse_json_object_or_undefined,
3701
+ git_gh_exec,
3702
+ git_gh_issue_read,
3703
+ git_gh_pr_read,
3704
+ git_gh_command
3705
+ };