@joshuafolkken/kit 1.1784.0 → 1.2116.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 (690) hide show
  1. package/.claude/agents/reviewer-verification.md +19 -0
  2. package/.claude/agents/reviewer.md +19 -0
  3. package/.claude/settings.json +5 -6
  4. package/.claude/skills/dependency-update/SKILL.md +9 -10
  5. package/.claude/skills/workflow-commands/SKILL.md +6 -6
  6. package/.claude/skills/workflow-commands/background-commands.md +8 -5
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +3 -1
  8. package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +5 -2
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -3
  11. package/.claude/skills/workflow-commands/backlogrun-recovery.md +1 -1
  12. package/.claude/skills/workflow-commands/backlogrun-steps.md +3 -2
  13. package/.claude/skills/workflow-commands/backlogrun.md +1 -1
  14. package/.claude/skills/workflow-commands/chain-rule.md +41 -32
  15. package/.claude/skills/workflow-commands/delegation.md +6 -6
  16. package/.claude/skills/workflow-commands/entry-sequence.md +2 -2
  17. package/.claude/skills/workflow-commands/followup.md +7 -5
  18. package/.claude/skills/workflow-commands/fullrun-steps.md +6 -6
  19. package/.claude/skills/workflow-commands/fullrun.md +1 -1
  20. package/.claude/skills/workflow-commands/issue-comments.md +9 -4
  21. package/.claude/skills/workflow-commands/issue-fold-existing.md +2 -1
  22. package/.claude/skills/workflow-commands/kickoff.md +2 -2
  23. package/.claude/skills/workflow-commands/observation-filing.md +1 -1
  24. package/.claude/skills/workflow-commands/observation-ledger.md +6 -4
  25. package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -7
  26. package/.claude/skills/workflow-commands/prerequisite.md +3 -2
  27. package/.claude/skills/workflow-commands/retrospective.md +2 -2
  28. package/.claude/skills/workflow-commands/split-assessment.md +7 -5
  29. package/.codex/hooks.json +5 -5
  30. package/.github/actions/setup-pnpm/action.yml +9 -16
  31. package/.github/dependabot.yml +16 -0
  32. package/.github/workflows/auto-tag.yml +45 -0
  33. package/.github/workflows/ci.yml +155 -15
  34. package/.github/workflows/dependabot-auto-merge.yml +63 -4
  35. package/.github/workflows/production.yml +8 -0
  36. package/.github/workflows/publish.yml +60 -45
  37. package/.vscode/settings.json +19 -0
  38. package/CLAUDE.md +5 -12
  39. package/SECURITY.md +2 -2
  40. package/dist/CLAUDE.md +5 -12
  41. package/dist/commands/document-read-cli.js +2 -1
  42. package/dist/commands/document-section-main.js +2 -1
  43. package/dist/commands/read-set-cli.js +194 -134
  44. package/dist/commands/run-prep-main.js +9694 -10173
  45. package/dist/commands/run-step-cli.js +22138 -18285
  46. package/dist/hooks/audit-provision.js +23 -5
  47. package/dist/hooks/chunk-3GKE653K.js +6204 -0
  48. package/dist/hooks/chunk-45CJJOO7.js +1243 -0
  49. package/dist/hooks/{chunk-CWMBGKYW.js → chunk-5PM2JRGV.js} +2153 -856
  50. package/dist/hooks/{chunk-WR2KQAYZ.js → chunk-7SIUNQXK.js} +1207 -1470
  51. package/dist/hooks/{chunk-O2YBIDSI.js → chunk-CQD4LJE6.js} +1682 -1130
  52. package/dist/hooks/{chunk-VWWCFGWK.js → chunk-OPSRGWFU.js} +1 -1
  53. package/dist/hooks/{chunk-XGBNSWEI.js → chunk-UJ3FPMMM.js} +132 -49
  54. package/dist/hooks/chunk-VVNYJWEI.js +30 -0
  55. package/dist/hooks/chunk-Z6DQJKH3.js +2806 -0
  56. package/dist/hooks/codex-hook-adapter.js +8 -8
  57. package/dist/hooks/format-edited.js +4 -5
  58. package/dist/hooks/inputs.json +386 -360
  59. package/dist/hooks/pretool-guard.js +7 -6
  60. package/dist/hooks/session-lang.js +101 -258
  61. package/dist/hooks/stop-guard.js +1744 -2576
  62. package/dist/josh.js +7133 -6368
  63. package/dist/version/index.js +161 -1
  64. package/eslint/rules/comment-why-only.js +108 -0
  65. package/package.json +16 -9
  66. package/prompts/coding-standards.md +1 -1
  67. package/prompts/collaboration-workflow/file-edits.md +14 -11
  68. package/prompts/collaboration-workflow/issue-citation.md +0 -4
  69. package/prompts/collaboration-workflow/issue-template.md +40 -21
  70. package/prompts/collaboration-workflow/lane-instructions.md +3 -1
  71. package/prompts/collaboration-workflow/measurement.md +8 -1
  72. package/prompts/collaboration-workflow/operating-rules.md +11 -2
  73. package/prompts/collaboration-workflow/output-bounds.md +6 -2
  74. package/prompts/collaboration-workflow/plan-comment.md +1 -1
  75. package/prompts/collaboration-workflow/principles.md +9 -0
  76. package/prompts/collaboration-workflow/residency.md +3 -2
  77. package/prompts/collaboration-workflow/rule-delivery.md +13 -1
  78. package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
  79. package/prompts/collaboration-workflow/wip-cap.md +3 -1
  80. package/prompts/review-rubric.md +8 -0
  81. package/prompts/review.md +31 -22
  82. package/prompts/testing-guide.md +1 -0
  83. package/scripts/agent/agent-argv.ts +14 -16
  84. package/scripts/agent/agent-provider.ts +138 -0
  85. package/scripts/agent/agent-role-profile.ts +108 -156
  86. package/scripts/agent/agent-safe-text.ts +20 -5
  87. package/scripts/agent/api-usage-limit.ts +65 -0
  88. package/scripts/agent/claude-agent-argv.ts +19 -9
  89. package/scripts/agent/codex-agent-argv.ts +118 -22
  90. package/scripts/agent/usage-limit-reset.ts +179 -0
  91. package/scripts/auth/claude-token-output.ts +2 -2
  92. package/scripts/auto-ok/auto-ok-author.ts +53 -0
  93. package/scripts/auto-ok/auto-ok-cli.ts +20 -9
  94. package/scripts/backlog/backlog-defect-priority.ts +1 -1
  95. package/scripts/backlog/backlog-drive-cli.ts +6 -1
  96. package/scripts/backlog/backlog-drive-hold.ts +3 -3
  97. package/scripts/backlog/backlog-drive-idle.ts +10 -0
  98. package/scripts/backlog/backlog-drive-launch-pass.ts +90 -0
  99. package/scripts/backlog/backlog-drive-launch.ts +8 -2
  100. package/scripts/backlog/backlog-drive-named-offer.ts +73 -30
  101. package/scripts/backlog/backlog-drive-named.ts +28 -7
  102. package/scripts/backlog/backlog-drive-paused.ts +5 -4
  103. package/scripts/backlog/backlog-drive-restore.ts +11 -3
  104. package/scripts/backlog/backlog-drive.ts +21 -60
  105. package/scripts/backlog/backlog-gate-scope.ts +61 -0
  106. package/scripts/backlog/backlog-measure-close.ts +112 -0
  107. package/scripts/backlog/backlog-next.ts +39 -49
  108. package/scripts/backlog/backlog-occupied.ts +2 -2
  109. package/scripts/backlog/backlog-overlap.ts +42 -8
  110. package/scripts/backlog/backlog-plan-cli.ts +4 -1
  111. package/scripts/backlog/backlog-plan-comment.ts +81 -0
  112. package/scripts/backlog/backlog-plan-read.ts +19 -6
  113. package/scripts/backlog/backlog-pool.ts +50 -12
  114. package/scripts/backlog/backlog-rank.ts +60 -13
  115. package/scripts/backlog/backlog-stalled-detect.ts +2 -1
  116. package/scripts/backlog/backlog-waves.ts +17 -2
  117. package/scripts/backlog/backlogrun-launch.ts +7 -4
  118. package/scripts/cost-runtime/context-cut-payback.ts +27 -25
  119. package/scripts/cost-runtime/cost-cli.ts +37 -16
  120. package/scripts/cost-runtime/cost-pricing.ts +9 -0
  121. package/scripts/cost-runtime/cost-verdict.ts +4 -1
  122. package/scripts/delegation/delegation-policy.ts +2 -2
  123. package/scripts/delegation/duplicate-read-guard.ts +1 -0
  124. package/scripts/delegation/investigation-guard.ts +14 -2
  125. package/scripts/delegation/investigation-reads.ts +45 -23
  126. package/scripts/dependabot/dependabot-cooldown.ts +3 -2
  127. package/scripts/discovery/repo-party.ts +80 -20
  128. package/scripts/discovery/session-owner-pin.ts +51 -0
  129. package/scripts/document/capped-print.ts +1 -1
  130. package/scripts/document/command-reference-line-budget.ts +42 -0
  131. package/scripts/document/document-byte-budget.ts +17 -7
  132. package/scripts/document/document-checks.ts +20 -0
  133. package/scripts/document/document-ratchet-check.ts +101 -0
  134. package/scripts/document/document-section.ts +1 -0
  135. package/scripts/document/entry-read-budget.ts +7 -3
  136. package/scripts/document/issue-citation-budget.ts +94 -0
  137. package/scripts/epic/epic-cli-argv.ts +2 -2
  138. package/scripts/epic/epic-fetch.ts +4 -2
  139. package/scripts/epic/epic-graph.ts +7 -2
  140. package/scripts/epic/epic-issue.ts +3 -1
  141. package/scripts/epic/epic-rank.ts +5 -0
  142. package/scripts/exports/unused-members-check.ts +62 -0
  143. package/scripts/exports/unused-members-cli.ts +6 -51
  144. package/scripts/followup/followup-ci-path.ts +67 -0
  145. package/scripts/followup/followup-coderabbit-retrigger.ts +261 -0
  146. package/scripts/followup/followup-coderabbit-wait.ts +13 -10
  147. package/scripts/followup/followup-failed-tests.ts +160 -0
  148. package/scripts/followup/followup-job-needs.ts +100 -0
  149. package/scripts/followup/followup-job-rerun.ts +303 -0
  150. package/scripts/followup/followup-main-move.ts +113 -0
  151. package/scripts/followup/git-followup-finish.ts +43 -11
  152. package/scripts/followup/git-followup-pending.ts +3 -3
  153. package/scripts/followup/git-followup-stages.ts +41 -11
  154. package/scripts/followup/git-pr-followup-checks.ts +55 -16
  155. package/scripts/followup/git-pr-followup-wrapup.ts +24 -5
  156. package/scripts/followup/git-pr-followup.ts +62 -27
  157. package/scripts/fresh-machine/fresh-machine-script.ts +5 -9
  158. package/scripts/fresh-machine/specs/kit-test-backlogrun-python.json +2 -2
  159. package/scripts/fresh-machine/specs/kit-test-backlogrun.json +2 -2
  160. package/scripts/gate/busy-average.ts +34 -2
  161. package/scripts/gate/check-related-pinned.ts +43 -0
  162. package/scripts/gate/check-related-reuse.ts +64 -0
  163. package/scripts/gate/check-related-section.ts +57 -0
  164. package/scripts/gate/check-related-unplanned.ts +34 -0
  165. package/scripts/gate/check-related.ts +265 -0
  166. package/scripts/gate/command-memory.ts +1 -1
  167. package/scripts/gate/core-admission.ts +24 -6
  168. package/scripts/gate/core-budget-timing.ts +20 -6
  169. package/scripts/gate/core-budget.ts +40 -11
  170. package/scripts/gate/core-wait-record.ts +3 -2
  171. package/scripts/gate/core-wait.ts +25 -2
  172. package/scripts/gate/core-weights.ts +15 -7
  173. package/scripts/gate/gate-labels.ts +46 -0
  174. package/scripts/gate/gate-ledger.ts +14 -6
  175. package/scripts/gate/gate-plan.ts +103 -58
  176. package/scripts/gate/gate-report.ts +9 -7
  177. package/scripts/gate/gate-run-steps.ts +26 -3
  178. package/scripts/gate/gate-skip.ts +45 -6
  179. package/scripts/gate/gate-static-group.ts +60 -0
  180. package/scripts/gate/gate-steps.ts +2 -1
  181. package/scripts/gate/gate-tree.ts +4 -2
  182. package/scripts/gate/hook-gate-reuse.ts +19 -2
  183. package/scripts/gate/metrics-totals.ts +59 -0
  184. package/scripts/gate/scoped-green.ts +68 -15
  185. package/scripts/gate/since-green.ts +14 -6
  186. package/scripts/gate/structural-checks.ts +96 -0
  187. package/scripts/gate/verification-gate.ts +51 -16
  188. package/scripts/gate/verification-inputs.ts +21 -6
  189. package/scripts/gate/verification-tail.ts +52 -0
  190. package/scripts/gh/gh-author-association.ts +23 -2
  191. package/scripts/gh/git-ai-review-scan.ts +1 -1
  192. package/scripts/gh/git-gh-api-path.ts +12 -3
  193. package/scripts/gh/git-gh-comments-unreadable.ts +36 -0
  194. package/scripts/gh/git-gh-exec.ts +32 -2
  195. package/scripts/gh/git-gh-issue-read.ts +4 -2
  196. package/scripts/gh/git-gh-issue-rest.ts +1 -0
  197. package/scripts/gh/git-gh-issue-write.ts +8 -2
  198. package/scripts/gh/git-gh-issue.ts +12 -5
  199. package/scripts/gh/git-gh-pr-auto-merge.ts +13 -6
  200. package/scripts/gh/git-gh-pr-graphql-state.ts +56 -0
  201. package/scripts/gh/git-gh-pr-read.ts +74 -13
  202. package/scripts/gh/git-gh-pr-rest.ts +3 -1
  203. package/scripts/gh/git-gh-pr-snapshot.ts +22 -7
  204. package/scripts/gh/git-gh-pr-too-large.ts +20 -0
  205. package/scripts/gh/git-gh-pr.ts +21 -7
  206. package/scripts/gh/git-gh-retry.ts +141 -0
  207. package/scripts/gh/git-pr-ai-review.ts +15 -6
  208. package/scripts/gh/git-pr-checks-eval.ts +3 -0
  209. package/scripts/gh/git-pr-checks.ts +5 -5
  210. package/scripts/git/base-tree.ts +30 -0
  211. package/scripts/git/change-base.ts +4 -10
  212. package/scripts/git/changed-paths-sync.ts +63 -0
  213. package/scripts/git/changed-paths.ts +16 -1
  214. package/scripts/git/git-common-directory.ts +11 -1
  215. package/scripts/git/git-diff-reads.ts +66 -20
  216. package/scripts/git/git-error.ts +9 -2
  217. package/scripts/git/git-schemas.ts +13 -0
  218. package/scripts/git/git-worktree.ts +13 -0
  219. package/scripts/git/gone-branch.ts +4 -1
  220. package/scripts/git/main-merge-budget-conflict.ts +89 -0
  221. package/scripts/git/main-merge-guard.ts +55 -18
  222. package/scripts/git/main-merge-regenerate.ts +59 -25
  223. package/scripts/git/main-merge.ts +53 -5
  224. package/scripts/git/no-base-checkout.ts +127 -0
  225. package/scripts/git/stash/git-stash.ts +11 -2
  226. package/scripts/git/stash/stash-push-cli.ts +10 -0
  227. package/scripts/hooks/batch-guard.ts +40 -21
  228. package/scripts/hooks/edited-cspell.ts +37 -11
  229. package/scripts/hooks/format-edited-file.ts +22 -2
  230. package/scripts/hooks/lane-plan-guard.ts +50 -0
  231. package/scripts/hooks/pre-commit-lint-switch.ts +9 -0
  232. package/scripts/hooks/pre-commit-lint.ts +14 -1
  233. package/scripts/hooks/pre-push-related-switch.ts +10 -0
  234. package/scripts/hooks/pre-push-unit.ts +76 -10
  235. package/scripts/hooks/pretool-guard.ts +2 -0
  236. package/scripts/hooks/reserved-run.ts +14 -1
  237. package/scripts/hooks/run-hook.sh +23 -8
  238. package/scripts/hooks/step-zero-notice.ts +6 -1
  239. package/scripts/hooks/stop-actions.ts +3 -15
  240. package/scripts/hooks/stop-guard.ts +7 -6
  241. package/scripts/init/distributed-paths.ts +1 -0
  242. package/scripts/init/hook-command-rewrite.ts +5 -1
  243. package/scripts/init/hook-launch.ts +4 -2
  244. package/scripts/issue/aggregation-split.ts +52 -0
  245. package/scripts/issue/defect-origin-line.ts +19 -1
  246. package/scripts/issue/defect-rate-cli.ts +5 -102
  247. package/scripts/issue/defect-report.ts +4 -4
  248. package/scripts/issue/effect-audit-cli.ts +178 -0
  249. package/scripts/issue/effect-audit.ts +185 -0
  250. package/scripts/issue/expected-effect-lint.ts +64 -9
  251. package/scripts/issue/git-next-issues.ts +5 -0
  252. package/scripts/issue/issue-body-or-comment.ts +38 -4
  253. package/scripts/issue/issue-cite-cli.ts +1 -3
  254. package/scripts/issue/issue-classification.ts +1 -0
  255. package/scripts/issue/issue-closing-pr.ts +8 -1
  256. package/scripts/issue/issue-evidence-exit.ts +4 -2
  257. package/scripts/issue/issue-file-cap.ts +58 -0
  258. package/scripts/issue/issue-file-cli.ts +111 -38
  259. package/scripts/issue/issue-file-deferral.ts +52 -0
  260. package/scripts/issue/issue-file-fold.ts +29 -10
  261. package/scripts/issue/issue-file-interrupt.ts +85 -0
  262. package/scripts/issue/issue-file-lane-hint.ts +30 -0
  263. package/scripts/issue/issue-file.ts +43 -6
  264. package/scripts/issue/issue-labels.ts +19 -2
  265. package/scripts/issue/issue-lint-cli.ts +27 -2
  266. package/scripts/issue/issue-measured-cli.ts +13 -35
  267. package/scripts/issue/issue-measured-close.ts +58 -0
  268. package/scripts/issue/issue-not-before-label.ts +2 -2
  269. package/scripts/issue/issue-not-before.ts +4 -1
  270. package/scripts/issue/issue-priority-cli.ts +60 -0
  271. package/scripts/issue/issue-priority-raise.ts +55 -0
  272. package/scripts/issue/issue-priority.ts +174 -43
  273. package/scripts/issue/issue-rank.ts +21 -4
  274. package/scripts/issue/issue-read-cli.ts +32 -6
  275. package/scripts/issue/issue-read.ts +37 -12
  276. package/scripts/issue/issue-sample-gate.ts +95 -74
  277. package/scripts/issue/issue-sample-prime.ts +127 -0
  278. package/scripts/issue/issue-sample-required.ts +57 -0
  279. package/scripts/issue/issue-sample-source.ts +12 -11
  280. package/scripts/issue/issue-search.ts +124 -0
  281. package/scripts/issue/issue-state.ts +13 -1
  282. package/scripts/issue/issue-template-section.ts +43 -0
  283. package/scripts/issue/issue-watch-diff.ts +31 -1
  284. package/scripts/issue/issue-watch-hook.ts +11 -2
  285. package/scripts/issue/issue-watch.ts +55 -12
  286. package/scripts/issue/markdown-section.ts +1 -0
  287. package/scripts/issue/measure-declaration.ts +121 -0
  288. package/scripts/issue/measure-rerun-cli.ts +7 -70
  289. package/scripts/issue/plan-consumers-section.ts +22 -1
  290. package/scripts/issue/reproduction-measure.ts +3 -1
  291. package/scripts/issue/size-estimate.ts +90 -0
  292. package/scripts/issue/trusted-measure.ts +84 -0
  293. package/scripts/josh/command-usage.ts +3 -2
  294. package/scripts/josh/durable-state-migrate.ts +105 -0
  295. package/scripts/josh/durable-state.ts +112 -0
  296. package/scripts/josh/josh-aliases.ts +95 -0
  297. package/scripts/josh/josh-command-map.ts +1 -82
  298. package/scripts/josh/josh-commands-agent-hooks.ts +6 -6
  299. package/scripts/josh/josh-commands-ai.ts +5 -5
  300. package/scripts/josh/josh-commands-development.ts +59 -58
  301. package/scripts/josh/josh-commands-issue-write.ts +23 -4
  302. package/scripts/josh/josh-commands-issue.ts +32 -0
  303. package/scripts/josh/josh-commands-lane.ts +87 -4
  304. package/scripts/josh/josh-commands-lint.ts +16 -3
  305. package/scripts/josh/josh-commands-maintenance.ts +15 -0
  306. package/scripts/josh/josh-commands-review.ts +41 -6
  307. package/scripts/josh/josh-commands-ship.ts +56 -8
  308. package/scripts/josh/josh-commands-test-check.ts +80 -0
  309. package/scripts/josh/josh-commands-workflow.ts +1 -1
  310. package/scripts/josh/josh-environment-file.ts +43 -3
  311. package/scripts/josh/josh-in-process.ts +2 -2
  312. package/scripts/josh/josh-logic.ts +5 -3
  313. package/scripts/josh/josh-run.ts +19 -1
  314. package/scripts/josh/run-record-path.ts +15 -0
  315. package/scripts/josh/stamp-file.ts +11 -2
  316. package/scripts/lane/lane-adopt-cli.ts +98 -0
  317. package/scripts/lane/lane-adopt.ts +208 -0
  318. package/scripts/lane/lane-await.ts +5 -8
  319. package/scripts/lane/lane-baseline.ts +123 -0
  320. package/scripts/lane/lane-breakdown-cli.ts +64 -0
  321. package/scripts/lane/lane-breakdown-implement.ts +170 -0
  322. package/scripts/lane/lane-breakdown-laps.ts +107 -0
  323. package/scripts/lane/lane-breakdown-pinned.ts +76 -0
  324. package/scripts/lane/lane-breakdown-text.ts +145 -0
  325. package/scripts/lane/lane-breakdown.ts +239 -0
  326. package/scripts/lane/lane-check-stats.ts +29 -8
  327. package/scripts/lane/lane-child-invocation.ts +9 -2
  328. package/scripts/lane/lane-child-mark-keys.ts +12 -0
  329. package/scripts/lane/lane-child-marker.ts +20 -1
  330. package/scripts/lane/lane-ci-path-stats.ts +73 -0
  331. package/scripts/lane/lane-claim-stats.ts +84 -0
  332. package/scripts/lane/lane-close.ts +8 -3
  333. package/scripts/lane/lane-dispatch-log.ts +3 -3
  334. package/scripts/lane/lane-dispatch.ts +2 -2
  335. package/scripts/lane/lane-gap-stats.ts +7 -6
  336. package/scripts/lane/lane-guard-policy.ts +7 -1
  337. package/scripts/lane/lane-implement-stats.ts +207 -0
  338. package/scripts/lane/lane-implement-subagents.ts +90 -0
  339. package/scripts/lane/lane-investigation-switch.ts +16 -0
  340. package/scripts/lane/lane-ledger-kind.ts +31 -0
  341. package/scripts/lane/lane-ledger-schema-ship.ts +49 -0
  342. package/scripts/lane/lane-ledger-schema.ts +119 -36
  343. package/scripts/lane/lane-ledger-write.ts +257 -0
  344. package/scripts/lane/lane-ledger.ts +31 -177
  345. package/scripts/lane/lane-load.ts +1 -1
  346. package/scripts/lane/lane-measure-cli.ts +176 -59
  347. package/scripts/lane/lane-net-read.ts +44 -0
  348. package/scripts/lane/lane-net-time.ts +212 -0
  349. package/scripts/lane/lane-open.ts +16 -7
  350. package/scripts/lane/lane-output.ts +2 -4
  351. package/scripts/lane/lane-overrun-prompt.ts +147 -0
  352. package/scripts/lane/lane-overrun.ts +274 -0
  353. package/scripts/lane/lane-paths.ts +24 -1
  354. package/scripts/lane/lane-pause-cli.ts +4 -1
  355. package/scripts/lane/lane-paused-spans.ts +97 -0
  356. package/scripts/lane/lane-plan-check.ts +207 -0
  357. package/scripts/lane/lane-plan-cli.ts +41 -0
  358. package/scripts/lane/lane-plan.ts +144 -0
  359. package/scripts/lane/lane-registry.ts +14 -1
  360. package/scripts/lane/lane-relaunch.ts +1 -1
  361. package/scripts/lane/lane-round-one-stats.ts +51 -0
  362. package/scripts/lane/lane-sampler.ts +23 -4
  363. package/scripts/lane/lane-session-action.ts +93 -18
  364. package/scripts/lane/lane-session-broker.ts +49 -21
  365. package/scripts/lane/lane-session-reread-main.ts +14 -0
  366. package/scripts/lane/lane-session-reread.ts +51 -0
  367. package/scripts/lane/lane-ship-lap-stats.ts +74 -0
  368. package/scripts/lane/lane-sleep.ts +58 -0
  369. package/scripts/lane/lane-spent.ts +1 -1
  370. package/scripts/lane/lane-split-stats.ts +28 -0
  371. package/scripts/lane/lane-stage-stats.ts +13 -1
  372. package/scripts/lane/lane-state.ts +41 -9
  373. package/scripts/lane/lane-stats-tables.ts +58 -0
  374. package/scripts/lane/lane-stats.ts +21 -5
  375. package/scripts/lane/lane-stop-stats.ts +51 -19
  376. package/scripts/lane/lane-tail-stats.ts +32 -0
  377. package/scripts/lane/lane-transcript-calls.ts +67 -10
  378. package/scripts/lane/lane-transcript-stats.ts +44 -12
  379. package/scripts/lane/lane-value-cell.ts +72 -0
  380. package/scripts/lane/lane-value.ts +118 -0
  381. package/scripts/lane/lane-withdraw-closed.ts +124 -0
  382. package/scripts/lane/lane-withdraw.ts +108 -31
  383. package/scripts/lane/lane-yield.ts +85 -0
  384. package/scripts/lane/openai-lane-ship.ts +12 -11
  385. package/scripts/lane/openai-lane-supervisor-decision.ts +6 -8
  386. package/scripts/lane/openai-lane-supervisor-owner.ts +5 -8
  387. package/scripts/lane/openai-lane-supervisor.ts +5 -4
  388. package/scripts/lib/poll.ts +38 -9
  389. package/scripts/lib/settled-together.ts +10 -0
  390. package/scripts/lib/shell-quote.ts +21 -0
  391. package/scripts/lib/token-shape.ts +111 -0
  392. package/scripts/lint/eslint-daemon-sources.ts +79 -0
  393. package/scripts/lint/eslint-daemon.ts +45 -6
  394. package/scripts/lint/eslint-warm-cli.ts +7 -0
  395. package/scripts/lint/eslint-warm.ts +66 -0
  396. package/scripts/lint/import-graph.ts +141 -11
  397. package/scripts/lint/lint-gate-scope.ts +2 -2
  398. package/scripts/lint/lint-parallel.ts +54 -6
  399. package/scripts/lint/lint-related.ts +154 -33
  400. package/scripts/lint/rename-cli.ts +179 -0
  401. package/scripts/lint/rename-identifier.ts +192 -0
  402. package/scripts/lint/type-only-imports.ts +58 -0
  403. package/scripts/notify/telegram-notify.ts +12 -3
  404. package/scripts/observations/observation-record.ts +42 -16
  405. package/scripts/observations/observations-flush.ts +32 -9
  406. package/scripts/overrides/overrides-check.ts +9 -1
  407. package/scripts/release/release-approval-prune.ts +7 -1
  408. package/scripts/repo/required-checks-logic.ts +4 -1
  409. package/scripts/repo/ruleset-check.ts +4 -3
  410. package/scripts/report/markdown-shape.ts +28 -0
  411. package/scripts/report/report-format-reference.ts +15 -1
  412. package/scripts/report/report-labels.ts +12 -1
  413. package/scripts/report/report-lint-child-summary.ts +94 -0
  414. package/scripts/report/report-lint-cli.ts +26 -7
  415. package/scripts/report/report-lint.ts +2 -20
  416. package/scripts/review/prose-stale-cli.ts +88 -0
  417. package/scripts/review/prose-stale-scan.ts +152 -0
  418. package/scripts/review/review-attest.ts +73 -23
  419. package/scripts/review/review-brief-cli.ts +68 -19
  420. package/scripts/review/review-brief-paths.ts +22 -0
  421. package/scripts/review/review-brief.ts +14 -7
  422. package/scripts/review/review-comment-carry.ts +47 -0
  423. package/scripts/review/review-comment-round.ts +85 -22
  424. package/scripts/review/review-finding-ledger.ts +109 -7
  425. package/scripts/review/review-finding-text.ts +43 -0
  426. package/scripts/review/review-interaction.ts +11 -0
  427. package/scripts/review/review-lane-handover.ts +68 -0
  428. package/scripts/review/review-lint-cli.ts +57 -0
  429. package/scripts/review/review-lint-findings.ts +92 -0
  430. package/scripts/review/review-lint-sections.ts +80 -0
  431. package/scripts/review/review-lint.ts +221 -0
  432. package/scripts/review/review-prior-findings.ts +102 -0
  433. package/scripts/review/review-readers-scan.ts +4 -2
  434. package/scripts/review/review-record-cli.ts +177 -54
  435. package/scripts/review/review-record-code-round.ts +55 -0
  436. package/scripts/review/review-record-comment.ts +60 -0
  437. package/scripts/review/review-record-interaction.ts +35 -0
  438. package/scripts/review/review-record-pinned.ts +108 -0
  439. package/scripts/review/review-record.ts +25 -1
  440. package/scripts/review/review-reviewed-tree.ts +307 -0
  441. package/scripts/review/review-round-one-closure.ts +62 -0
  442. package/scripts/review/review-round-reuse.ts +106 -0
  443. package/scripts/review/review-round2-cli.ts +91 -29
  444. package/scripts/review/review-round2-skip-comment.ts +55 -0
  445. package/scripts/review/review-round2.ts +24 -8
  446. package/scripts/review/review-stamps.ts +7 -3
  447. package/scripts/review/review-stop-log.ts +20 -6
  448. package/scripts/review/review-stops-cli.ts +2 -1
  449. package/scripts/review/review-submit-cli.ts +101 -0
  450. package/scripts/rules/agent-model.ts +1 -1
  451. package/scripts/rules/bash-triggers.ts +3 -3
  452. package/scripts/rules/concise-reply.ts +88 -0
  453. package/scripts/rules/credential-body.ts +77 -0
  454. package/scripts/rules/decision-oracle.ts +1 -1
  455. package/scripts/rules/delivered-rules.ts +36 -17
  456. package/scripts/rules/destructive-command.ts +3 -11
  457. package/scripts/rules/direct-issue-comment.ts +34 -12
  458. package/scripts/rules/direct-issue-read.ts +191 -0
  459. package/scripts/rules/direct-pr-create.ts +4 -24
  460. package/scripts/rules/early-heartbeat.ts +2 -0
  461. package/scripts/rules/edit-tool.ts +27 -0
  462. package/scripts/rules/file-edit-rows.ts +17 -0
  463. package/scripts/rules/file-rewrite.ts +146 -0
  464. package/scripts/rules/firing-point.ts +3 -2
  465. package/scripts/rules/gh-api.ts +128 -7
  466. package/scripts/rules/gh-repo-selector.ts +84 -0
  467. package/scripts/rules/git-force.ts +2 -2
  468. package/scripts/rules/guard-remedy.ts +14 -5
  469. package/scripts/rules/implementation-cut.ts +61 -28
  470. package/scripts/rules/investigator-foreground.ts +231 -0
  471. package/scripts/rules/issue-citation.ts +15 -60
  472. package/scripts/rules/issue-comments.ts +9 -4
  473. package/scripts/rules/josh-git-bare.ts +1 -1
  474. package/scripts/rules/lane-background.ts +41 -13
  475. package/scripts/rules/lane-direct-tool.ts +107 -9
  476. package/scripts/rules/lane-interactive-ask.ts +4 -1
  477. package/scripts/rules/lane-park.ts +4 -2
  478. package/scripts/rules/lane-spilled-read.ts +90 -0
  479. package/scripts/rules/lane-split-park.ts +1 -1
  480. package/scripts/rules/lane-switch-main.ts +4 -4
  481. package/scripts/rules/last-prompt.ts +20 -47
  482. package/scripts/rules/oracle-consulted.ts +1 -1
  483. package/scripts/rules/permission-guards.ts +5 -1
  484. package/scripts/rules/piped-verification-shapes.ts +110 -0
  485. package/scripts/rules/piped-verification.ts +67 -17
  486. package/scripts/rules/poll-loop.ts +72 -9
  487. package/scripts/rules/pr-merge.ts +5 -5
  488. package/scripts/rules/pre-gate-cut.ts +3 -3
  489. package/scripts/rules/protected-files.ts +88 -24
  490. package/scripts/rules/reply-language.ts +3 -17
  491. package/scripts/rules/reply-prose.ts +34 -0
  492. package/scripts/rules/repo-admin.ts +132 -0
  493. package/scripts/rules/reviewer-foreground.ts +88 -0
  494. package/scripts/rules/round-one-check-related.ts +120 -0
  495. package/scripts/rules/rule-body-guard.ts +5 -15
  496. package/scripts/rules/rule-value-cache.ts +53 -5
  497. package/scripts/rules/rule-value-candidates.ts +84 -0
  498. package/scripts/rules/rule-value-cli.ts +59 -11
  499. package/scripts/rules/rule-value.ts +17 -4
  500. package/scripts/rules/run-tail-rule.ts +1 -1
  501. package/scripts/rules/sed-in-place.ts +196 -0
  502. package/scripts/rules/shell-segments.ts +10 -2
  503. package/scripts/rules/stop-rule-rows.ts +1 -13
  504. package/scripts/rules/stop-rules.ts +33 -58
  505. package/scripts/rules/test-declared-commit.ts +1 -1
  506. package/scripts/rules/third-party-write.ts +110 -23
  507. package/scripts/rules/timed-rerun.ts +1 -1
  508. package/scripts/rules/turn-filings.ts +90 -0
  509. package/scripts/rules/worktree-guard.ts +22 -7
  510. package/scripts/run/board/run-board-ending-reason.ts +6 -2
  511. package/scripts/run/board/run-board-fit.ts +24 -1
  512. package/scripts/run/board/run-board-found.ts +134 -0
  513. package/scripts/run/board/run-board-header.ts +8 -0
  514. package/scripts/run/board/run-board-labels.ts +11 -1
  515. package/scripts/run/board/run-board-lane-time.ts +1 -0
  516. package/scripts/run/board/run-board-link.ts +15 -2
  517. package/scripts/run/board/run-board-notes.ts +7 -1
  518. package/scripts/run/board/run-board-operation.ts +4 -2
  519. package/scripts/run/board/run-board-phase.ts +2 -5
  520. package/scripts/run/board/run-board-plan.ts +1 -1
  521. package/scripts/run/board/run-board-read.ts +46 -1
  522. package/scripts/run/board/run-board-reason.ts +20 -8
  523. package/scripts/run/board/run-board-render-checks.ts +3 -2
  524. package/scripts/run/board/run-board-render-drawn.ts +11 -0
  525. package/scripts/run/board/run-board-render-found.ts +157 -0
  526. package/scripts/run/board/run-board-render-lead.ts +9 -0
  527. package/scripts/run/board/run-board-render-legend.ts +19 -0
  528. package/scripts/run/board/run-board-render-tail.ts +1 -1
  529. package/scripts/run/board/run-board-render.ts +82 -18
  530. package/scripts/run/board/run-board-spin.ts +1 -3
  531. package/scripts/run/board/run-board-status.ts +2 -0
  532. package/scripts/run/board/run-board-tick.ts +39 -10
  533. package/scripts/run/carry/run-carry-ended.ts +3 -2
  534. package/scripts/run/carry/run-carry.ts +3 -2
  535. package/scripts/run/cut/run-cut-cli.ts +33 -133
  536. package/scripts/run/cut/run-cut-digest.ts +152 -0
  537. package/scripts/run/cut/run-cut-handoff.ts +52 -8
  538. package/scripts/run/cut/run-cut-report.ts +24 -3
  539. package/scripts/run/cut/run-cut-resume.ts +129 -0
  540. package/scripts/run/cut/run-cut-review.ts +105 -0
  541. package/scripts/run/cut/run-cut.ts +18 -7
  542. package/scripts/run/detached-launch.ts +1 -1
  543. package/scripts/run/entry/run-entry-cli.ts +88 -19
  544. package/scripts/run/entry/run-entry-spill.ts +83 -0
  545. package/scripts/run/entry/run-entry-stop.ts +5 -1
  546. package/scripts/run/entry/run-entry-trust.ts +91 -0
  547. package/scripts/run/event/run-event-baseline.ts +56 -0
  548. package/scripts/run/event/run-event-filed.ts +9 -3
  549. package/scripts/run/event/run-event-overrun.ts +197 -0
  550. package/scripts/run/event/run-event-render.ts +4 -0
  551. package/scripts/run/event/run-event-stream.ts +25 -3
  552. package/scripts/run/hold/run-stop-notify.ts +3 -8
  553. package/scripts/run/merge/run-merge-cap.ts +57 -0
  554. package/scripts/run/merge/run-merge-cli.ts +66 -23
  555. package/scripts/run/merge/run-merge-outcome.ts +2 -0
  556. package/scripts/run/merge/run-merge-ship.ts +13 -3
  557. package/scripts/run/merge/run-merge-signals.ts +40 -23
  558. package/scripts/run/merge/run-merge-steps.ts +56 -36
  559. package/scripts/run/merge/run-merge-usage-limit.ts +53 -0
  560. package/scripts/run/merge/run-merge-withdrawn.ts +53 -0
  561. package/scripts/run/merge/run-merge.ts +41 -14
  562. package/scripts/run/review/run-review-cli.ts +306 -20
  563. package/scripts/run/review/run-review-early-push.ts +121 -0
  564. package/scripts/run/review/run-review-join-read.ts +94 -0
  565. package/scripts/run/review/run-review-pinned-accepted.ts +126 -0
  566. package/scripts/run/review/run-review-pinned-join.ts +216 -0
  567. package/scripts/run/review/run-review-pinned-steps.ts +383 -0
  568. package/scripts/run/review/run-review-pinned-tree.ts +37 -0
  569. package/scripts/run/review/run-review-pinned.ts +53 -0
  570. package/scripts/run/review/run-review-steps.ts +70 -34
  571. package/scripts/run/review/run-review.ts +26 -6
  572. package/scripts/run/run-parent-cut-hook.ts +3 -4
  573. package/scripts/run/run-prep.ts +1 -0
  574. package/scripts/run/run-stage-read.ts +2 -6
  575. package/scripts/run/run-step-cli.ts +17 -5
  576. package/scripts/run/run-step-lane-plan.ts +27 -0
  577. package/scripts/run/run-step-section.ts +26 -7
  578. package/scripts/run/run-step.ts +5 -2
  579. package/scripts/run/ship/run-ship-args.ts +19 -0
  580. package/scripts/run/ship/run-ship-brokered-review.ts +106 -0
  581. package/scripts/run/ship/run-ship-cli.ts +131 -39
  582. package/scripts/run/ship/run-ship-conflict-probe.ts +59 -0
  583. package/scripts/run/ship/run-ship-detach.ts +10 -4
  584. package/scripts/run/ship/run-ship-handover.ts +106 -0
  585. package/scripts/run/ship/run-ship-infra-retry.ts +16 -1
  586. package/scripts/run/ship/run-ship-lap.ts +63 -0
  587. package/scripts/run/ship/run-ship-next.ts +27 -26
  588. package/scripts/run/ship/run-ship-overlap.ts +8 -3
  589. package/scripts/run/ship/run-ship-place.ts +9 -2
  590. package/scripts/run/ship/run-ship-planned.ts +92 -0
  591. package/scripts/run/ship/run-ship-pre-detach-pinned.ts +197 -0
  592. package/scripts/run/ship/run-ship-pre-detach-timed.ts +7 -8
  593. package/scripts/run/ship/run-ship-pre-detach.ts +77 -23
  594. package/scripts/run/ship/run-ship-preflight.ts +16 -4
  595. package/scripts/run/ship/run-ship-probe.ts +23 -9
  596. package/scripts/run/ship/run-ship-relaunch-cap.ts +43 -7
  597. package/scripts/run/ship/run-ship-relaunch.ts +51 -0
  598. package/scripts/run/ship/run-ship-return.ts +103 -29
  599. package/scripts/run/ship/run-ship-review-reason.ts +24 -0
  600. package/scripts/run/ship/run-ship-review-steps.ts +230 -59
  601. package/scripts/run/ship/run-ship-review.ts +171 -51
  602. package/scripts/run/ship/run-ship-reviewer.ts +138 -42
  603. package/scripts/run/ship/run-ship-scoped.ts +39 -10
  604. package/scripts/run/ship/run-ship-stage.ts +49 -13
  605. package/scripts/run/ship/run-ship-steps.ts +24 -4
  606. package/scripts/run/ship/run-ship-stop-cause.ts +43 -2
  607. package/scripts/run/ship/run-ship-stop-context.ts +50 -13
  608. package/scripts/run/ship/run-ship-sync.ts +171 -30
  609. package/scripts/run/ship/run-ship-synced-scope.ts +178 -0
  610. package/scripts/run/ship/run-ship-wait-cli.ts +145 -0
  611. package/scripts/run/ship/run-ship-waiter.ts +114 -0
  612. package/scripts/run/ship/run-ship.ts +16 -2
  613. package/scripts/run/wake/run-wake-caffeinate.ts +48 -0
  614. package/scripts/run/wake/run-wake-cli.ts +6 -113
  615. package/scripts/run/wake/run-wake-code.ts +53 -11
  616. package/scripts/run/wake/run-wake-driver.ts +5 -3
  617. package/scripts/run/wake/run-wake-finish.ts +137 -0
  618. package/scripts/run/wake/run-wake-loop.ts +5 -3
  619. package/scripts/run/wake/run-wake-ports.ts +11 -3
  620. package/scripts/run/wake/run-wake-session.ts +2 -0
  621. package/scripts/run/wake/run-wake.ts +3 -2
  622. package/scripts/safe-chain/ci-installer-pin.ts +49 -8
  623. package/scripts/safe-chain/project-config.ts +3 -2
  624. package/scripts/security/secretlint-scan.ts +42 -9
  625. package/scripts/security/security-audit-provision-main.ts +9 -1
  626. package/scripts/security/security-audit-provision.ts +1 -1
  627. package/scripts/security/security-audit.ts +21 -1
  628. package/scripts/security/sonar-file.ts +10 -5
  629. package/scripts/split/split-assess.ts +12 -3
  630. package/scripts/split/split-early-notice.ts +116 -0
  631. package/scripts/split/split-measure.ts +20 -2
  632. package/scripts/split/split-resolution.ts +107 -0
  633. package/scripts/test/direct-importers.ts +185 -0
  634. package/scripts/test/pure-files-entries.ts +83 -0
  635. package/scripts/test/related-heavy-tests.ts +81 -0
  636. package/scripts/test/test-no-base.ts +88 -0
  637. package/scripts/test/test-pinned-cache-logic.ts +363 -0
  638. package/scripts/test/test-pinned-cache.ts +337 -0
  639. package/scripts/test/test-pinned-emit.ts +49 -0
  640. package/scripts/test/test-pinned-functions.ts +116 -0
  641. package/scripts/test/test-pinned-ledger.ts +80 -0
  642. package/scripts/test/test-pinned-logic.ts +208 -20
  643. package/scripts/test/test-pinned-main.ts +84 -18
  644. package/scripts/test/test-pinned-pool.ts +73 -0
  645. package/scripts/test/test-pinned-probe.ts +254 -0
  646. package/scripts/test/test-pinned-prune-logic.ts +118 -0
  647. package/scripts/test/test-pinned-reach.ts +194 -0
  648. package/scripts/test/test-pinned-record.ts +196 -0
  649. package/scripts/test/test-pinned-rewire.ts +148 -0
  650. package/scripts/test/test-pinned-spawn.ts +81 -0
  651. package/scripts/test/test-pinned-stage.ts +70 -0
  652. package/scripts/test/test-pinned.ts +258 -47
  653. package/scripts/test/test-reach-cli.ts +61 -0
  654. package/scripts/test/test-read-map.ts +35 -11
  655. package/scripts/test/test-read-recording.ts +17 -5
  656. package/scripts/test/test-read-trace.ts +26 -8
  657. package/scripts/test/test-red-logic.ts +46 -7
  658. package/scripts/test/test-red.ts +34 -14
  659. package/scripts/test/test-related-claim.ts +37 -0
  660. package/scripts/test/test-related-main.ts +4 -1
  661. package/scripts/test/test-related-moved.ts +91 -0
  662. package/scripts/test/test-related-record.ts +43 -23
  663. package/scripts/test/test-related-scope.ts +99 -34
  664. package/scripts/test/test-related-synced.ts +135 -0
  665. package/scripts/test/test-related-touched.ts +84 -0
  666. package/scripts/test/test-related.ts +167 -83
  667. package/scripts/test/test-unit-guard.ts +28 -5
  668. package/scripts/test/unit-durations.ts +41 -0
  669. package/scripts/test/unit-worker-share.ts +5 -4
  670. package/scripts/test/vitest-cache-directory.ts +19 -0
  671. package/scripts/test/vitest-cli-excludes.ts +14 -0
  672. package/scripts/test/vitest-failure-summary.ts +111 -0
  673. package/scripts/test/whole-suite-files.ts +12 -1
  674. package/scripts/time-runtime/time-batch-guard.ts +42 -4
  675. package/scripts/time-runtime/time-bundle-call.ts +1 -1
  676. package/scripts/time-runtime/time-bundles.ts +36 -5
  677. package/scripts/time-runtime/time-markers.ts +2 -2
  678. package/scripts/time-runtime/time-search-call.ts +38 -0
  679. package/scripts/time-runtime/time-shell.ts +1 -1
  680. package/scripts/time-runtime/time-transcript-line.ts +17 -5
  681. package/scripts/version/development-engines-verdict.ts +124 -0
  682. package/scripts/version/latest-corepack.ts +2 -0
  683. package/templates/gitignore +2 -0
  684. package/templates/workflows/ci.yml +41 -0
  685. package/dist/hooks/chunk-AZX4FGQ3.js +0 -207
  686. package/dist/hooks/chunk-PT5R6UJD.js +0 -7131
  687. package/dist/hooks/chunk-TUIFS5E7.js +0 -72
  688. package/dist/hooks/chunk-YCDOIR3I.js +0 -3456
  689. package/scripts/cost-runtime/context-cut-threshold.ts +0 -11
  690. package/scripts/rules/filing-cap.ts +0 -139
@@ -1,3456 +0,0 @@
1
- import {
2
- ENV_FILE_NAME,
3
- LANE_SEAT_KEY,
4
- PORCELAIN_FLAG,
5
- PORT_SEED_KEY,
6
- agent_session_environment,
7
- blocking_issue_schema,
8
- file_reader,
9
- git_command,
10
- git_spawn,
11
- has_timed_out,
12
- issue_cite,
13
- issue_number_shape,
14
- json_value,
15
- lane_paths,
16
- ports,
17
- process_identity,
18
- repo_discovery,
19
- repository_lock,
20
- rest_comment_schema,
21
- run_carry,
22
- run_ship_stage,
23
- session_cite
24
- } from "./chunk-WR2KQAYZ.js";
25
- import {
26
- COMMAND_TIMEOUT_MS,
27
- INSTALL_TIMEOUT_MS,
28
- PLATFORM_TEMP_ROOT,
29
- PROBE_TIMEOUT_MS,
30
- PROJECT_ROOT,
31
- SUITE_TIMEOUT_MS,
32
- error_text,
33
- stamp_file
34
- } from "./chunk-AZX4FGQ3.js";
35
-
36
- // scripts/josh/josh-environment-file.ts
37
- function load_environment_file() {
38
- try {
39
- process.loadEnvFile(ENV_FILE_NAME);
40
- } catch {
41
- }
42
- }
43
- var josh_environment_file = {
44
- load_environment_file
45
- };
46
-
47
- // scripts/lane/lane-child-marker.ts
48
- var KEY = "JOSH_LANE_CHILD";
49
- var CACHE_TTL_KEY = "CLAUDE_CODE_PROMPT_CACHE_TTL";
50
- var CACHE_TTL = "5m";
51
- function environment_for(issue) {
52
- issue_number_shape.require_issue_number(issue);
53
- return { [KEY]: issue, [CACHE_TTL_KEY]: CACHE_TTL };
54
- }
55
- function marked_issue(source = process.env) {
56
- const value = source[KEY];
57
- if (value === void 0) return void 0;
58
- return issue_number_shape.ISSUE_NUMBER_PATTERN.test(value) ? value : void 0;
59
- }
60
- function is_child_of(directory, source = process.env) {
61
- const marked = marked_issue(source);
62
- return marked !== void 0 && marked === lane_paths.lane_issue_of(directory, { ...source });
63
- }
64
- var lane_child_marker = {
65
- KEY,
66
- env_for: environment_for,
67
- is_child_of,
68
- marked_issue
69
- };
70
-
71
- // scripts/josh/stamp-record.ts
72
- var NONE_READ = { kind: "none" };
73
- var UNREADABLE_READ = { kind: "unreadable" };
74
- function is_older_than(iso, max_age_ms, now) {
75
- const at = Date.parse(iso);
76
- if (Number.isNaN(at)) return true;
77
- return now.getTime() - at > max_age_ms;
78
- }
79
- function classify(raw, spec, now) {
80
- if (raw === void 0) return NONE_READ;
81
- const record = spec.parse(raw);
82
- if (record === void 0) return UNREADABLE_READ;
83
- const is_expired2 = is_older_than(spec.timestamp_of(record), spec.max_age_ms, now);
84
- return { kind: is_expired2 ? "expired" : "carried", record };
85
- }
86
- var stamp_record = { classify, is_older_than };
87
-
88
- // scripts/run/hold/run-hold.ts
89
- import { z } from "zod";
90
- var HOLD_PREFIX = "josh-run-hold-";
91
- var UNNUMBERED_ISSUE = "new";
92
- var HOLD_MAX_AGE_HOURS = 8;
93
- var MILLISECONDS_PER_HOUR = 36e5;
94
- var HOLD_MAX_AGE_MS = HOLD_MAX_AGE_HOURS * MILLISECONDS_PER_HOUR;
95
- var RELEASE_COMMAND = "pnpm josh run:release";
96
- var FORCE_RELEASE_COMMAND = `${RELEASE_COMMAND} --force`;
97
- var NOT_IDLE = 'that is not "nothing is running here"';
98
- var FREE_READ = { kind: "free" };
99
- var UNREADABLE_READ2 = { kind: "unreadable" };
100
- function hold_path(git_directory) {
101
- return stamp_file.stamp_path(HOLD_PREFIX, git_directory);
102
- }
103
- async function worktree_directory() {
104
- const directories = await git_command.git_directories();
105
- return directories[0];
106
- }
107
- async function is_linked_worktree() {
108
- const directories = await git_command.git_directories();
109
- return directories[0] !== void 0 && directories[0] !== directories[1];
110
- }
111
- var run_hold_schema = z.object({
112
- issue: z.string(),
113
- taken_at: z.string(),
114
- pid: z.number(),
115
- is_fullrun: z.boolean().optional(),
116
- is_halfrun_stop: z.boolean().optional(),
117
- prrun_stop_head: z.string().optional(),
118
- owner_pid: z.number().optional(),
119
- owner_start: z.string().optional(),
120
- notified_at: z.string().optional()
121
- });
122
- function parse_hold(raw) {
123
- return json_value.parse_with(raw, run_hold_schema);
124
- }
125
- function is_expired(hold, now) {
126
- return stamp_record.is_older_than(hold.taken_at, HOLD_MAX_AGE_MS, now);
127
- }
128
- function is_stop_marked(hold) {
129
- return hold.is_halfrun_stop === true || hold.prrun_stop_head !== void 0;
130
- }
131
- function is_owner_gone(hold) {
132
- if (is_stop_marked(hold) || hold.owner_pid === void 0) return false;
133
- return process_identity.is_same_process(hold.owner_pid, hold.owner_start) === false;
134
- }
135
- function is_stale(hold, now) {
136
- return is_expired(hold, now) || is_owner_gone(hold);
137
- }
138
- function classify2(raw, now) {
139
- if (raw === void 0) return FREE_READ;
140
- const hold = parse_hold(raw);
141
- if (hold === void 0) return UNREADABLE_READ2;
142
- return { kind: is_stale(hold, now) ? "stale" : "held", hold };
143
- }
144
- function read_hold(target, now = /* @__PURE__ */ new Date()) {
145
- return classify2(stamp_file.read_stamp_text(target), now);
146
- }
147
- function session_owner(environment3 = process.env) {
148
- const pid = Number(environment3[agent_session_environment.AGENT_PID_KEY]);
149
- if (!Number.isSafeInteger(pid) || pid <= 0) return {};
150
- return { owner_pid: pid, owner_start: process_identity.read_start(pid) };
151
- }
152
- function build_hold(issue, now, is_fullrun) {
153
- return { issue, taken_at: now.toISOString(), pid: process.pid, is_fullrun, ...session_owner() };
154
- }
155
- function write_hold(target, issue, now = /* @__PURE__ */ new Date()) {
156
- const hold = build_hold(issue, now);
157
- stamp_file.write_stamp(target, hold);
158
- return hold;
159
- }
160
- function create_hold(target, issue, now = /* @__PURE__ */ new Date(), is_fullrun) {
161
- return stamp_file.create_stamp(target, build_hold(issue, now, is_fullrun));
162
- }
163
- var HALFRUN_STOP_FIELDS = { is_halfrun_stop: true };
164
- function create_stop_hold(target, issue, mark, now = /* @__PURE__ */ new Date()) {
165
- return stamp_file.create_stamp(target, { ...build_hold(issue, now), ...mark });
166
- }
167
- function create_halfrun_stop_hold(target, issue, now = /* @__PURE__ */ new Date()) {
168
- return create_stop_hold(target, issue, HALFRUN_STOP_FIELDS, now);
169
- }
170
- async function is_tree_dirty(directory) {
171
- try {
172
- const status = await git_command.status(directory);
173
- return status.trim() !== "";
174
- } catch (error) {
175
- error_text.trace_swallowed("run_hold.is_tree_dirty", error);
176
- return true;
177
- }
178
- }
179
- function release_hold(target) {
180
- stamp_file.remove_stamp(target);
181
- }
182
- function describe_holder(hold) {
183
- const holder = hold.issue === UNNUMBERED_ISSUE ? "an unnumbered run" : session_cite.issue(hold.issue);
184
- return `${holder}, recorded ${hold.taken_at} (pid ${String(hold.owner_pid ?? hold.pid)})`;
185
- }
186
- function own_release_command(issue) {
187
- return issue === UNNUMBERED_ISSUE ? RELEASE_COMMAND : `${RELEASE_COMMAND} ${issue}`;
188
- }
189
- function is_own_hold(hold, claimant) {
190
- return hold.issue === claimant;
191
- }
192
- function is_reentry(hold, claimant) {
193
- return claimant !== UNNUMBERED_ISSUE && is_own_hold(hold, claimant);
194
- }
195
- function held_message(hold) {
196
- 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.`;
197
- }
198
- function foreign_release_message(hold) {
199
- 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}\`.`;
200
- }
201
- function forced_release_message(hold) {
202
- return `Forced: removed the run record held by ${describe_holder(hold)}.`;
203
- }
204
- function unreadable_message() {
205
- 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.`;
206
- }
207
- function stale_message(hold) {
208
- const why = is_owner_gone(hold) ? "the session that wrote it has ended" : `older than ${String(HOLD_MAX_AGE_HOURS)} hours`;
209
- return `Replaced a stale run record held by ${describe_holder(hold)}: ${why}, so the run that wrote it has ended without releasing it.`;
210
- }
211
- function uncommitted_message(hold) {
212
- 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.`;
213
- }
214
- function race_message(read, target) {
215
- if (read.kind === "held") return held_message(read.hold);
216
- 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.`;
217
- }
218
- function unknown_message() {
219
- return `Could not read this working tree's git directory \u2014 ${NOT_IDLE}. Run this from inside the checkout the run will edit.`;
220
- }
221
- var run_hold = {
222
- is_stop_marked,
223
- FORCE_RELEASE_COMMAND,
224
- HOLD_MAX_AGE_HOURS,
225
- HOLD_MAX_AGE_MS,
226
- RELEASE_COMMAND,
227
- UNNUMBERED_ISSUE,
228
- classify: classify2,
229
- create_halfrun_stop_hold,
230
- create_stop_hold,
231
- HALFRUN_STOP_FIELDS,
232
- create_hold,
233
- foreign_release_message,
234
- forced_release_message,
235
- held_message,
236
- hold_path,
237
- is_linked_worktree,
238
- is_own_hold,
239
- is_reentry,
240
- is_tree_dirty,
241
- own_release_command,
242
- race_message,
243
- read_hold,
244
- release_hold,
245
- session_owner,
246
- stale_message,
247
- uncommitted_message,
248
- unknown_message,
249
- unreadable_message,
250
- worktree_directory,
251
- write_hold
252
- };
253
-
254
- // scripts/agent/agent-headless.ts
255
- var KEY2 = "JOSH_AGENT_HEADLESS";
256
- var VALUE = "1";
257
- function environment() {
258
- return { [KEY2]: VALUE };
259
- }
260
- function is_headless(source = process.env) {
261
- return source[KEY2] === VALUE;
262
- }
263
- var agent_headless = { KEY: KEY2, environment, is_headless };
264
-
265
- // scripts/josh/session-language.ts
266
- var ENV_KEY = "JOSH_SESSION_LANG";
267
- var DEFAULT_SESSION_LANG = "ja";
268
- function resolve_session_lang() {
269
- const value = process.env[ENV_KEY]?.trim();
270
- if (value) return { lang: value, is_default: false };
271
- return { lang: DEFAULT_SESSION_LANG, is_default: true };
272
- }
273
- function is_japanese(lang) {
274
- return lang.toLowerCase().startsWith(DEFAULT_SESSION_LANG);
275
- }
276
- var session_language = { DEFAULT_SESSION_LANG, ENV_KEY, resolve_session_lang, is_japanese };
277
-
278
- // scripts/lane/lane-reap.ts
279
- import { execFileSync } from "node:child_process";
280
-
281
- // scripts/agent/agent-role-profile.ts
282
- import { z as z2 } from "zod";
283
-
284
- // scripts/agent/agent-safe-text.ts
285
- var FIRST_PRINTABLE_CODE = 32;
286
- var DELETE_CODE = 127;
287
- var FIRST_CODE_POINT = 0;
288
- var EMPTY_LENGTH = 0;
289
- var MAX_VALUE_LENGTH = 4096;
290
- var LINE_FEED = "\n";
291
- var SPACE = " ";
292
- function is_control_character(character) {
293
- const code = character.codePointAt(FIRST_CODE_POINT) ?? FIRST_PRINTABLE_CODE;
294
- return code < FIRST_PRINTABLE_CODE || code === DELETE_CODE;
295
- }
296
- function is_line_feed(character) {
297
- return character === LINE_FEED;
298
- }
299
- function is_never_allowed() {
300
- return false;
301
- }
302
- function is_refused(character, is_allowed) {
303
- return is_control_character(character) && !is_allowed(character);
304
- }
305
- function is_safe_text(value, is_allowed) {
306
- if (value.length === EMPTY_LENGTH || value.length > MAX_VALUE_LENGTH) return false;
307
- for (const character of value) if (is_refused(character, is_allowed)) return false;
308
- return true;
309
- }
310
- function is_safe_value(value) {
311
- return is_safe_text(value, is_never_allowed);
312
- }
313
- function is_safe_prompt(value) {
314
- return is_safe_text(value, is_line_feed);
315
- }
316
- function printable_character(character) {
317
- return is_refused(character, is_line_feed) ? SPACE : character;
318
- }
319
- function printable(text) {
320
- return Array.from(text, printable_character).join("");
321
- }
322
- var agent_safe_text = { MAX_VALUE_LENGTH, is_safe_prompt, is_safe_value, printable };
323
-
324
- // scripts/agent/agent-role-profile.ts
325
- var EMPTY_LENGTH2 = 0;
326
- var ROLE_SCHEMA = z2.enum(["scheduler", "worker", "reviewer"]);
327
- var PROVIDER_SCHEMA = z2.enum(["anthropic", "openai"]);
328
- var EFFORT_SCHEMA = z2.enum(["low", "medium", "high", "xhigh", "max"]);
329
- var PHASE_SCHEMA = z2.enum(["implementation", "pre-gate"]);
330
- var PROFILE_SCHEMA = z2.object({
331
- provider: PROVIDER_SCHEMA.default("anthropic"),
332
- role: ROLE_SCHEMA,
333
- model: z2.string(),
334
- effort: EFFORT_SCHEMA
335
- });
336
- var SCHEDULER = "scheduler";
337
- var WORKER = "worker";
338
- var REVIEWER = "reviewer";
339
- var IMPLEMENTATION_PHASE = "implementation";
340
- var PRE_GATE_PHASE = "pre-gate";
341
- var ANTHROPIC_PROVIDER = "anthropic";
342
- var OPENAI_PROVIDER = "openai";
343
- var OPENAI_MODEL = "gpt-6.1-sol";
344
- var ANTHROPIC_MODEL = "claude-opus-5-5";
345
- var CODEX_SESSION_KEY = "CODEX_THREAD_ID";
346
- var DEFAULT_PROFILES = {
347
- scheduler: {
348
- provider: ANTHROPIC_PROVIDER,
349
- role: SCHEDULER,
350
- model: ANTHROPIC_MODEL,
351
- effort: "medium"
352
- },
353
- worker: { provider: ANTHROPIC_PROVIDER, role: WORKER, model: ANTHROPIC_MODEL, effort: "medium" },
354
- reviewer: {
355
- provider: ANTHROPIC_PROVIDER,
356
- role: REVIEWER,
357
- model: ANTHROPIC_MODEL,
358
- effort: "high"
359
- }
360
- };
361
- var OPENAI_PROFILES = {
362
- scheduler: { provider: OPENAI_PROVIDER, role: SCHEDULER, model: OPENAI_MODEL, effort: "medium" },
363
- worker: { provider: OPENAI_PROVIDER, role: WORKER, model: OPENAI_MODEL, effort: "medium" },
364
- reviewer: { provider: OPENAI_PROVIDER, role: REVIEWER, model: OPENAI_MODEL, effort: "high" }
365
- };
366
- var PROVIDER_PROFILES = { anthropic: DEFAULT_PROFILES, openai: OPENAI_PROFILES };
367
- var FIRST_REVIEW_ROUND = 1;
368
- var VERIFICATION_MODEL = "claude-sonnet-5-5";
369
- var VERIFICATION_PROFILES = {
370
- anthropic: { ...DEFAULT_PROFILES.reviewer, model: VERIFICATION_MODEL },
371
- openai: OPENAI_PROFILES.reviewer
372
- };
373
- var VERIFICATION_KEYS = {
374
- model: "JOSH_REVIEWER_VERIFICATION_MODEL",
375
- effort: "JOSH_REVIEWER_VERIFICATION_EFFORT"
376
- };
377
- var SHIP_EFFORT = "low";
378
- var PHASE_EFFORT = {
379
- worker: { [PRE_GATE_PHASE]: SHIP_EFFORT }
380
- };
381
- var ENV_KEYS = {
382
- scheduler: { model: "JOSH_SCHEDULER_MODEL", effort: "JOSH_SCHEDULER_EFFORT" },
383
- worker: { model: "JOSH_WORKER_MODEL", effort: "JOSH_WORKER_EFFORT" },
384
- reviewer: { model: "JOSH_REVIEWER_MODEL", effort: "JOSH_REVIEWER_EFFORT" }
385
- };
386
- var LEGACY_WORKER_KEYS = { model: "JOSH_LANE_MODEL", effort: "JOSH_LANE_EFFORT" };
387
- var { MAX_VALUE_LENGTH: MAX_VALUE_LENGTH2, is_safe_prompt: is_safe_prompt2, is_safe_value: is_safe_value2, printable: printable2 } = agent_safe_text;
388
- function trimmed(value) {
389
- const result = value?.trim();
390
- return result === void 0 || result.length === EMPTY_LENGTH2 ? void 0 : result;
391
- }
392
- function is_verification(role, round) {
393
- return role === REVIEWER && round !== void 0 && round > FIRST_REVIEW_ROUND;
394
- }
395
- function override_keys(role, field, round) {
396
- const key = ENV_KEYS[role][field];
397
- if (role === WORKER) return [key, LEGACY_WORKER_KEYS[field]];
398
- return is_verification(role, round) ? [VERIFICATION_KEYS[field], key] : [key];
399
- }
400
- function override_value(role, field, environment3, round) {
401
- const keys = override_keys(role, field, round);
402
- const key = keys.find((candidate) => trimmed(environment3[candidate]) !== void 0);
403
- return key === void 0 ? { key: keys[0], value: void 0 } : { key, value: trimmed(environment3[key]) };
404
- }
405
- function model_override(role, environment3, provider, round) {
406
- return provider === OPENAI_PROVIDER ? { key: ENV_KEYS[role].model, value: void 0 } : override_value(role, "model", environment3, round);
407
- }
408
- function rejection(key, value, expected) {
409
- return { kind: "rejected", note: `${key}=${value} ${expected}, so the agent was not started` };
410
- }
411
- function resolved_effort(override, fallback) {
412
- const parsed = EFFORT_SCHEMA.safeParse(override.value ?? fallback);
413
- return parsed.success ? { kind: "effort", effort: parsed.data } : rejection(override.key, override.value ?? "", "is not an allowed effort");
414
- }
415
- function has_session(environment3, keys) {
416
- return keys.some((key) => trimmed(environment3[key]) !== void 0);
417
- }
418
- var CONFLICTING_SESSIONS = {
419
- kind: "rejected",
420
- note: "both Codex and Claude Code sessions were detected"
421
- };
422
- var HANDED_PROVIDER_KEY = "JOSH_AGENT_PROVIDER";
423
- var DEFAULT_PROVIDER = {
424
- kind: "provider",
425
- provider: ANTHROPIC_PROVIDER,
426
- is_default: true
427
- };
428
- var DEFAULT_NOTICE = ` No agent session or ${HANDED_PROVIDER_KEY} was found, so the provider defaulted to ${ANTHROPIC_PROVIDER} (Claude Code).`;
429
- function handed_provider(environment3) {
430
- const value = trimmed(environment3[HANDED_PROVIDER_KEY]);
431
- if (value === void 0) return DEFAULT_PROVIDER;
432
- const parsed = PROVIDER_SCHEMA.safeParse(value);
433
- return parsed.success ? { kind: "provider", provider: parsed.data } : rejection(HANDED_PROVIDER_KEY, value, "is not an allowed provider");
434
- }
435
- function detected_provider(environment3) {
436
- const has_codex = has_session(environment3, [CODEX_SESSION_KEY]);
437
- const has_claude = has_session(environment3, agent_session_environment.PARENT_SESSION_KEYS);
438
- if (has_codex === has_claude) return has_codex ? CONFLICTING_SESSIONS : void 0;
439
- return { kind: "provider", provider: has_codex ? OPENAI_PROVIDER : ANTHROPIC_PROVIDER };
440
- }
441
- function resolve_provider(environment3 = process.env) {
442
- return detected_provider(environment3) ?? handed_provider(environment3);
443
- }
444
- function default_notice(environment3 = process.env) {
445
- const selected = resolve_provider(environment3);
446
- return selected.kind === "provider" && selected.is_default === true ? DEFAULT_NOTICE : "";
447
- }
448
- function warn_of_default(environment3 = process.env) {
449
- const notice = default_notice(environment3).trim();
450
- if (notice !== "") console.error(notice);
451
- }
452
- function has_completion_callback(environment3 = process.env) {
453
- const selected = resolve_provider(environment3);
454
- return selected.kind !== "provider" || selected.provider !== OPENAI_PROVIDER;
455
- }
456
- function handoff_environment(environment3 = process.env) {
457
- const selected = resolve_provider(environment3);
458
- return selected.kind === "provider" ? { [HANDED_PROVIDER_KEY]: selected.provider } : {};
459
- }
460
- function validate(profile, model_key) {
461
- if (!is_safe_value2(profile.model)) {
462
- return rejection(model_key, profile.model, "is not a safe model");
463
- }
464
- return { kind: "profile", profile };
465
- }
466
- function phase_effort(role, phase, fallback) {
467
- const parsed = PHASE_SCHEMA.safeParse(phase);
468
- if (!parsed.success) return fallback;
469
- return PHASE_EFFORT[role]?.[parsed.data] ?? fallback;
470
- }
471
- function overridden_effort(profile, phase, environment3) {
472
- const parsed = EFFORT_SCHEMA.safeParse(override_value(profile.role, "effort", environment3).value);
473
- return parsed.success ? parsed.data : phase_effort(profile.role, phase, profile.effort);
474
- }
475
- function with_phase_effort(profile, phase, environment3 = process.env) {
476
- return { ...profile, effort: overridden_effort(profile, phase, environment3) };
477
- }
478
- function stage_defaults(provider, role, round) {
479
- return is_verification(role, round) ? VERIFICATION_PROFILES[provider] : PROVIDER_PROFILES[provider][role];
480
- }
481
- function resolve_stage(role, environment3, stage) {
482
- const selected = resolve_provider(environment3);
483
- if (selected.kind === "rejected") return selected;
484
- const defaults = stage_defaults(selected.provider, role, stage.round);
485
- const model = model_override(role, environment3, selected.provider, stage.round);
486
- const effort = override_value(role, "effort", environment3, stage.round);
487
- const resolved = resolved_effort(effort, phase_effort(role, stage.phase, defaults.effort));
488
- if (resolved.kind === "rejected") return resolved;
489
- const profile = {
490
- provider: selected.provider,
491
- role,
492
- model: model.value ?? defaults.model,
493
- effort: resolved.effort
494
- };
495
- return validate(profile, model.key);
496
- }
497
- function resolve(role, environment3 = process.env, phase) {
498
- return resolve_stage(role, environment3, { phase });
499
- }
500
- function resolve_review(round, environment3 = process.env) {
501
- return resolve_stage(REVIEWER, environment3, { round });
502
- }
503
- function describe(profile) {
504
- return `provider=${profile.provider} role=${profile.role} model=${profile.model} effort=${profile.effort}`;
505
- }
506
- function describe_review(round, profile) {
507
- return `review round ${String(round)} \xB7 ${describe(profile)}`;
508
- }
509
- function parse(value) {
510
- const parsed = PROFILE_SCHEMA.safeParse(value);
511
- return parsed.success && is_safe_value2(parsed.data.model) ? parsed.data : void 0;
512
- }
513
- var agent_role_profile = {
514
- CODEX_SESSION_KEY,
515
- DEFAULT_PROFILES,
516
- HANDED_PROVIDER_KEY,
517
- IMPLEMENTATION_PHASE,
518
- MAX_VALUE_LENGTH: MAX_VALUE_LENGTH2,
519
- OPENAI_PROFILES,
520
- PRE_GATE_PHASE,
521
- PROFILE_SCHEMA,
522
- REVIEWER,
523
- SCHEDULER,
524
- VERIFICATION_PROFILES,
525
- WORKER,
526
- default_notice,
527
- describe,
528
- describe_review,
529
- handoff_environment,
530
- has_completion_callback,
531
- is_safe_prompt: is_safe_prompt2,
532
- is_safe_value: is_safe_value2,
533
- parse,
534
- printable: printable2,
535
- resolve,
536
- resolve_provider,
537
- resolve_review,
538
- warn_of_default,
539
- with_phase_effort
540
- };
541
-
542
- // scripts/run/ship/run-ship-next.ts
543
- var { STAGE } = run_ship_stage;
544
- var COMMAND = {
545
- LOG: "pnpm josh ship --log",
546
- DETACH: "pnpm josh ship --detach",
547
- DETACH_REVIEW: "pnpm josh ship --detach --review"
548
- };
549
- var ESCAPED_QUOTE = String.raw`'\''`;
550
- var BARE_WORD = /^[\w%+,./:=@-]+$/u;
551
- function quoted(title) {
552
- return `'${title.split("'").join(ESCAPED_QUOTE)}'`;
553
- }
554
- function shell_word(token) {
555
- return BARE_WORD.test(token) ? token : quoted(token);
556
- }
557
- function resume_of(args) {
558
- const cites = args.cites.flatMap((cite) => ["--cite", cite]);
559
- return {
560
- title: args.title,
561
- flags: [...args.notify, ...args.body, ...cites],
562
- is_review: args.is_review
563
- };
564
- }
565
- function ship_command(command, resume) {
566
- const words = [...resume.flags, resume.title].map((token) => shell_word(token));
567
- return [command, ...words].join(" ");
568
- }
569
- function detach_again(resume) {
570
- return `leave the fix uncommitted and run \`${ship_command(COMMAND.DETACH, resume)}\`.`;
571
- }
572
- function detach_as_started(resume) {
573
- const command = resume.is_review ? COMMAND.DETACH_REVIEW : COMMAND.DETACH;
574
- return `leave the fix uncommitted and run \`${ship_command(command, resume)}\`.`;
575
- }
576
- var AFTER_FIX = {
577
- [STAGE.PREFLIGHT]: detach_as_started,
578
- [STAGE.REVIEW]: detach_as_started,
579
- [STAGE.GATE]: detach_as_started,
580
- [STAGE.SYNC]: detach_as_started,
581
- [STAGE.COMMIT]: detach_as_started,
582
- [STAGE.ROUND_TWO]: detach_again,
583
- [STAGE.FOLLOWUP]: detach_again,
584
- [STAGE.REPORT]: detach_again
585
- };
586
- function detach_review_again(resume) {
587
- return `leave the fix uncommitted and run \`${ship_command(COMMAND.DETACH_REVIEW, resume)}\` \u2014 the review read the issue before its update, so the supervisor reviews round 1 again.`;
588
- }
589
- function after_fix(stage, resume) {
590
- return resume.is_review_stale === true ? detach_review_again(resume) : AFTER_FIX[stage](resume);
591
- }
592
- function conflict_step(conflicts) {
593
- return `Resolve the conflict with origin/main in ${conflicts.join(", ")} (the merge is left in progress: remove the conflict markers in those files), then`;
594
- }
595
- function fix_step(issue, stage, is_excerpted) {
596
- if (is_excerpted) return `Fix the ${stage} failure shown in the output below`;
597
- return `Read the stopped report with \`${COMMAND.LOG} ${issue}\`, fix the ${stage} failure`;
598
- }
599
- function next_step(issue, stage, resume, is_excerpted = false) {
600
- const conflicts = resume.conflicts ?? [];
601
- if (conflicts.length > 0) return `${conflict_step(conflicts)} ${after_fix(stage, resume)}`;
602
- return `${fix_step(issue, stage, is_excerpted)}, then ${after_fix(stage, resume)}`;
603
- }
604
- var run_ship_next = { COMMAND, next_step, quoted, resume_of };
605
-
606
- // scripts/run/ship/run-ship-stop-context.ts
607
- import { stripVTControlCharacters } from "node:util";
608
-
609
- // scripts/git/changed-paths.ts
610
- function to_paths(raw) {
611
- return raw.split("\n").map((line) => line.trim()).filter((line) => line !== "");
612
- }
613
- async function read_changed_paths(is_staged) {
614
- if (is_staged) return to_paths(await git_command.diff_cached_names());
615
- const tracked = to_paths(await git_command.diff_main_names());
616
- const untracked = to_paths(await git_command.untracked_names());
617
- return [...tracked, ...untracked];
618
- }
619
- async function read_changed_since(commit) {
620
- const tracked = to_paths(await git_command.diff_names_since(commit));
621
- const untracked = to_paths(await git_command.untracked_names());
622
- return [.../* @__PURE__ */ new Set([...tracked, ...untracked])];
623
- }
624
- async function read_held_at(commit, paths) {
625
- if (paths.length === 0) return [];
626
- return to_paths(await git_command.tree_names_at(commit, paths));
627
- }
628
- var changed_paths = { read_changed_paths, read_changed_since, read_held_at, to_paths };
629
-
630
- // scripts/run/ship/run-ship-stop-context.ts
631
- import { z as z10 } from "zod";
632
-
633
- // scripts/git/git-ls-remote.ts
634
- var LS_REMOTE_COMMAND = "ls-remote";
635
- var HEADS_FLAG = "--heads";
636
- var ORIGIN_REMOTE = "origin";
637
- var HEADS_REF_PREFIX = "refs/heads/";
638
- function ls_remote_branch_arguments(branch_name) {
639
- return [LS_REMOTE_COMMAND, HEADS_FLAG, ORIGIN_REMOTE, `${HEADS_REF_PREFIX}${branch_name}`];
640
- }
641
-
642
- // scripts/git/git-worktree.ts
643
- var WORKTREE = "worktree";
644
- var WORKTREE_LOCK_PREFIX = "josh-worktree-lock-";
645
- var WORKTREE_LOCK_MAX_WAIT_MS = 12e4;
646
- async function locked(arguments_, timeout_ms) {
647
- const target = repository_lock.lock_path(WORKTREE_LOCK_PREFIX);
648
- const output = await repository_lock.with_lock(
649
- async () => await git_spawn.read(arguments_, timeout_ms),
650
- target,
651
- WORKTREE_LOCK_MAX_WAIT_MS
652
- );
653
- if (output === void 0) {
654
- throw new Error(
655
- `git ${arguments_.join(" ")}: timed out waiting for the work-tree lock ${target}`
656
- );
657
- }
658
- return output;
659
- }
660
- async function worktree_list() {
661
- return await git_spawn.read([WORKTREE, "list", PORCELAIN_FLAG]);
662
- }
663
- async function worktree_add(directory, branch_name, start_point) {
664
- const flags = start_point === void 0 ? ["add"] : ["add", "--no-track", "-b", branch_name];
665
- return await locked([WORKTREE, ...flags, directory, start_point ?? branch_name], SUITE_TIMEOUT_MS);
666
- }
667
- async function worktree_add_detached(directory, commit) {
668
- return await locked([WORKTREE, "add", "--detach", directory, commit], SUITE_TIMEOUT_MS);
669
- }
670
- async function worktree_remove(directory) {
671
- return await locked([WORKTREE, "remove", "--force", directory], INSTALL_TIMEOUT_MS);
672
- }
673
- async function worktree_prune() {
674
- return await locked([WORKTREE, "prune"]);
675
- }
676
- async function ls_remote_branch(branch_name) {
677
- return await git_spawn.read_remote(ls_remote_branch_arguments(branch_name));
678
- }
679
- async function branch_delete(branch_name) {
680
- return await git_spawn.read(["branch", "-D", branch_name]);
681
- }
682
- var git_worktree = {
683
- branch_delete,
684
- ls_remote_branch,
685
- worktree_add,
686
- worktree_add_detached,
687
- worktree_list,
688
- worktree_prune,
689
- worktree_remove
690
- };
691
-
692
- // scripts/review/review-attest.ts
693
- import { randomBytes } from "node:crypto";
694
- import { lstatSync } from "node:fs";
695
-
696
- // scripts/review/review-checkout.ts
697
- async function read_checkout() {
698
- const [root, branch, head] = await Promise.all([
699
- git_command.repository_root(),
700
- git_command.branch(),
701
- git_command.head_commit()
702
- ]);
703
- return { root, branch, head };
704
- }
705
- function is_same_checkout(expected, actual) {
706
- return expected.root === actual.root && expected.branch === actual.branch && expected.head === actual.head;
707
- }
708
- function describe_checkout(checkout) {
709
- return `${checkout.root} (branch ${checkout.branch}, HEAD ${checkout.head})`;
710
- }
711
- var review_checkout = { describe_checkout, is_same_checkout, read_checkout };
712
-
713
- // scripts/review/review-attest.ts
714
- var POINTER_PREFIX = "josh-review-target-";
715
- var EXPECT_PREFIX = "josh-review-expect-";
716
- var ATTEST_PREFIX = "josh-review-attest-";
717
- var NONCE_BYTES = 8;
718
- var HOURS_BEFORE_STALE = 8;
719
- var MILLISECONDS_PER_HOUR2 = 36e5;
720
- var STALE_AFTER_MS = HOURS_BEFORE_STALE * MILLISECONDS_PER_HOUR2;
721
- function pointer_path(root = PROJECT_ROOT) {
722
- return stamp_file.stamp_path(POINTER_PREFIX, root);
723
- }
724
- function expect_path(nonce) {
725
- return stamp_file.stamp_path(EXPECT_PREFIX, nonce);
726
- }
727
- function attest_path(nonce) {
728
- return stamp_file.stamp_path(ATTEST_PREFIX, nonce);
729
- }
730
- function read_json(source) {
731
- const raw = stamp_file.read_stamp_text(source);
732
- return raw === void 0 ? void 0 : json_value.parse_or_undefined(raw);
733
- }
734
- function string_field(value, key) {
735
- const field = value[key];
736
- return typeof field === "string" ? field : void 0;
737
- }
738
- function to_checkout(value) {
739
- if (!json_value.is_record(value)) return void 0;
740
- const root = string_field(value, "root");
741
- const branch = string_field(value, "branch");
742
- const head = string_field(value, "head");
743
- if (root === void 0 || branch === void 0 || head === void 0) return void 0;
744
- return { root, branch, head };
745
- }
746
- function to_pointer(value) {
747
- if (!json_value.is_record(value)) return void 0;
748
- const nonce = string_field(value, "nonce");
749
- const taken_at = string_field(value, "taken_at");
750
- if (nonce !== void 0 && taken_at !== void 0) return { nonce, taken_at };
751
- return void 0;
752
- }
753
- function read_pointer(root) {
754
- return to_pointer(read_json(pointer_path(root)));
755
- }
756
- function read_expectation(nonce) {
757
- return to_checkout(read_json(expect_path(nonce)));
758
- }
759
- function read_attestation(nonce) {
760
- return to_checkout(read_json(attest_path(nonce)));
761
- }
762
- function drop_records(pointer) {
763
- if (pointer === void 0) return;
764
- stamp_file.remove_stamp(expect_path(pointer.nonce));
765
- stamp_file.remove_stamp(attest_path(pointer.nonce));
766
- }
767
- function is_stale2(taken_at, now) {
768
- const taken = Date.parse(taken_at);
769
- return Number.isNaN(taken) || now - taken > STALE_AFTER_MS;
770
- }
771
- function record_target(checkout, root) {
772
- const nonce = randomBytes(NONCE_BYTES).toString("hex");
773
- const taken_at = (/* @__PURE__ */ new Date()).toISOString();
774
- drop_records(read_pointer(root));
775
- stamp_file.write_stamp(expect_path(nonce), { ...checkout, taken_at });
776
- stamp_file.write_stamp(pointer_path(root), { nonce, taken_at });
777
- return nonce;
778
- }
779
- function attest(nonce, actual) {
780
- const expected = read_expectation(nonce);
781
- if (expected === void 0) return { status: "missing", nonce, actual };
782
- stamp_file.write_stamp(attest_path(nonce), { ...actual, taken_at: (/* @__PURE__ */ new Date()).toISOString() });
783
- if (review_checkout.is_same_checkout(expected, actual)) {
784
- return { status: "ok", nonce, expected, actual };
785
- }
786
- return { status: "mismatch", nonce, expected, actual };
787
- }
788
- function not_required() {
789
- return { status: "not-required" };
790
- }
791
- function verdict_for(nonce) {
792
- const expected = read_expectation(nonce);
793
- if (expected === void 0) return { status: "missing", nonce };
794
- const actual = read_attestation(nonce);
795
- if (actual === void 0) return { status: "missing", nonce, expected };
796
- if (review_checkout.is_same_checkout(expected, actual)) {
797
- return { status: "ok", nonce, expected, actual };
798
- }
799
- return { status: "mismatch", nonce, expected, actual };
800
- }
801
- function check(now = Date.now(), root) {
802
- const pointer = read_pointer(root);
803
- if (pointer === void 0) return not_required();
804
- const verdict = verdict_for(pointer.nonce);
805
- if (verdict.status === "missing" && is_stale2(pointer.taken_at, now)) return not_required();
806
- return verdict;
807
- }
808
- function is_written_since(source, taken_at) {
809
- try {
810
- const stats = lstatSync(source);
811
- return stats.isFile() && stats.mtimeMs >= Date.parse(taken_at);
812
- } catch {
813
- return false;
814
- }
815
- }
816
- function is_reviewed_on(checkout, findings_path, root) {
817
- const pointer = read_pointer(root);
818
- if (pointer === void 0) return false;
819
- const verdict = verdict_for(pointer.nonce);
820
- if (verdict.status !== "ok" || verdict.expected?.branch !== checkout.branch) return false;
821
- return is_written_since(findings_path, pointer.taken_at);
822
- }
823
- function is_briefed_since(written_at, root) {
824
- const pointer = read_pointer(root);
825
- return pointer !== void 0 && written_at >= pointer.taken_at;
826
- }
827
- async function check_here(now = Date.now()) {
828
- return check(now, await git_command.repository_root());
829
- }
830
- function clear(root) {
831
- const pointer = read_pointer(root);
832
- stamp_file.remove_stamp(pointer_path(root));
833
- drop_records(pointer);
834
- }
835
- async function clear_here() {
836
- clear(await git_command.repository_root());
837
- }
838
- var MISMATCH_VERDICT = "REVIEW TARGET MISMATCH";
839
- function describe_side(label, checkout) {
840
- if (checkout === void 0) return `${label}: unknown`;
841
- return `${label}: ${review_checkout.describe_checkout(checkout)}`;
842
- }
843
- var MISSING_REASON = "The review left no attestation, so there is no evidence it read this checkout at all. A review that read the wrong tree finds nothing wrong and reports no findings, which is indistinguishable from a clean review \u2014 so an absent attestation is treated as no review (joshuafolkken/kit#1522).";
844
- var MISMATCH_REASON = `${MISMATCH_VERDICT}: the review attested a different checkout from the one it was briefed on. Its findings \u2014 including "no findings" \u2014 describe another tree.`;
845
- var REMEDY = "Re-run `/code-review` with the brief `pnpm josh review:brief` prints, against the checkout named above, and let it run `pnpm josh review:attest <nonce>` from there before it reports.";
846
- function refusal_message(verdict) {
847
- const reason = verdict.status === "mismatch" ? MISMATCH_REASON : MISSING_REASON;
848
- return [
849
- reason,
850
- describe_side("Briefed on", verdict.expected),
851
- describe_side("Reviewed", verdict.actual),
852
- REMEDY
853
- ].join("\n");
854
- }
855
- var review_attest = {
856
- attest,
857
- attest_path,
858
- check,
859
- check_here,
860
- clear,
861
- clear_here,
862
- expect_path,
863
- is_briefed_since,
864
- is_reviewed_on,
865
- MISMATCH_VERDICT,
866
- MISSING_REASON,
867
- pointer_path,
868
- read_attestation,
869
- read_expectation,
870
- read_pointer,
871
- record_target,
872
- refusal_message,
873
- STALE_AFTER_MS
874
- };
875
-
876
- // scripts/gh/git-gh-api-path.ts
877
- var FULL_PAGE_QUERY = "?per_page=100";
878
- function repo_api_path(repo = "{owner}/{repo}") {
879
- return `repos/${repo}`;
880
- }
881
- function issues_api_path(repo) {
882
- return `${repo_api_path(repo)}/issues`;
883
- }
884
- function issue_api_path(issue_number, repo) {
885
- return `${issues_api_path(repo)}/${issue_number}`;
886
- }
887
- function issue_labels_api_path(issue_number, repo) {
888
- return `${issue_api_path(issue_number, repo)}/labels`;
889
- }
890
- function blocked_by_api_path(issue_number, repo) {
891
- return `${issue_api_path(issue_number, repo)}/dependencies/blocked_by`;
892
- }
893
- function issue_comments_api_path(issue_number, repo) {
894
- return `${issue_api_path(issue_number, repo)}/comments`;
895
- }
896
- function pulls_api_path(repo) {
897
- return `${repo_api_path(repo)}/pulls`;
898
- }
899
- function pull_api_path(pr_number, repo) {
900
- return `${pulls_api_path(repo)}/${pr_number}`;
901
- }
902
- function pull_merge_api_path(pr_number, repo) {
903
- return `${pull_api_path(pr_number, repo)}/merge`;
904
- }
905
- function pull_comments_api_path(pr_number, repo) {
906
- return `${pull_api_path(pr_number, repo)}/comments`;
907
- }
908
- function pull_reviews_api_path(pr_number, repo) {
909
- return `${pull_api_path(pr_number, repo)}/reviews`;
910
- }
911
- function commit_api_path(commit_sha, repo) {
912
- return `${repo_api_path(repo)}/commits/${commit_sha}`;
913
- }
914
- function commit_check_runs_api_path(commit_sha, repo) {
915
- return `${commit_api_path(commit_sha, repo)}/check-runs`;
916
- }
917
- function commit_status_api_path(commit_sha, repo) {
918
- return `${commit_api_path(commit_sha, repo)}/status`;
919
- }
920
- function branch_rules_api_path(branch_name, repo) {
921
- return `${repo_api_path(repo)}/rules/branches/${branch_name}`;
922
- }
923
- function tag_reference_api_path(tag, repo) {
924
- return `${repo_api_path(repo)}/git/ref/tags/${tag}`;
925
- }
926
- function release_by_tag_api_path(tag, repo) {
927
- return `${repo_api_path(repo)}/releases/tags/${tag}`;
928
- }
929
- var git_gh_api_path = {
930
- FULL_PAGE_QUERY,
931
- repo_api_path,
932
- tag_ref_api_path: tag_reference_api_path,
933
- release_by_tag_api_path,
934
- issues_api_path,
935
- issue_api_path,
936
- issue_labels_api_path,
937
- blocked_by_api_path,
938
- issue_comments_api_path,
939
- pulls_api_path,
940
- pull_api_path,
941
- pull_merge_api_path,
942
- pull_comments_api_path,
943
- pull_reviews_api_path,
944
- commit_api_path,
945
- commit_check_runs_api_path,
946
- commit_status_api_path,
947
- branch_rules_api_path
948
- };
949
-
950
- // scripts/gh/git-gh-exec.ts
951
- import { execa as execa2, execaSync } from "execa";
952
-
953
- // scripts/gh/git-gh-check.ts
954
- import { execa } from "execa";
955
- var GH_NOT_INSTALLED_MSG = "gh CLI is not installed. Install it from https://cli.github.com/";
956
- var gh_check = {};
957
- async function run_gh_check() {
958
- try {
959
- await execa("gh", ["--version"], { timeout: COMMAND_TIMEOUT_MS });
960
- } catch {
961
- delete gh_check.promise;
962
- throw new Error(GH_NOT_INSTALLED_MSG);
963
- }
964
- }
965
- async function check_gh_installed() {
966
- gh_check.promise ??= run_gh_check();
967
- await gh_check.promise;
968
- }
969
-
970
- // scripts/git/parse-json-array.ts
971
- function parse_json_loose(raw_json) {
972
- return json_value.parse_or_undefined(raw_json);
973
- }
974
- function parse_json_array_or_undefined(raw_json, element_schema) {
975
- const value = parse_json_loose(raw_json);
976
- if (!Array.isArray(value)) return void 0;
977
- return element_schema.array().parse(value);
978
- }
979
- function read_json_listing(raw_json, element_schema) {
980
- try {
981
- const rows = parse_json_array_or_undefined(raw_json, element_schema);
982
- return rows === void 0 ? { kind: "unreadable" } : { kind: "read", rows };
983
- } catch {
984
- return { kind: "unexpected_shape" };
985
- }
986
- }
987
- function parse_json_array_safe(raw_json, element_schema) {
988
- const value = parse_json_loose(raw_json);
989
- if (value === void 0) return [];
990
- return element_schema.array().parse(value);
991
- }
992
- function parse_json_object_or_undefined(raw_json, schema) {
993
- const value = parse_json_loose(raw_json);
994
- if (value === void 0) return void 0;
995
- return schema.parse(value);
996
- }
997
- var parse_json = {
998
- parse_json_object_or_undefined
999
- };
1000
-
1001
- // scripts/gh/git-gh-failure.ts
1002
- import { z as z3 } from "zod";
1003
- var error_document_schema = z3.object({ status: z3.union([z3.string(), z3.number()]).optional() }).catch({});
1004
- var GH_FAILURE_FIELD = "gh_failure";
1005
- function has_gh_failure(error) {
1006
- return error instanceof Error && Object.hasOwn(error, GH_FAILURE_FIELD);
1007
- }
1008
- function parse_response_status(stdout) {
1009
- const document = parse_json.parse_json_object_or_undefined(stdout, error_document_schema);
1010
- if (document?.status === void 0) return void 0;
1011
- const status = Number(document.status);
1012
- return Number.isSafeInteger(status) ? status : void 0;
1013
- }
1014
- function classify_stdout(stdout) {
1015
- return { status: parse_response_status(stdout) };
1016
- }
1017
- function attach(error, failure) {
1018
- Object.defineProperty(error, GH_FAILURE_FIELD, {
1019
- value: failure,
1020
- enumerable: false,
1021
- configurable: true
1022
- });
1023
- return error;
1024
- }
1025
- function failure_of(error) {
1026
- return has_gh_failure(error) ? error.gh_failure : void 0;
1027
- }
1028
- var gh_failure = { attach, classify_stdout, failure_of, parse_response_status };
1029
-
1030
- // scripts/gh/git-gh-exec.ts
1031
- var BODY_FROM_STDIN = "-";
1032
- var GH_REQUEST_TIMEOUT_MS = 6e4;
1033
- function to_timeout_option(timeout_ms) {
1034
- return { timeout: timeout_ms ?? GH_REQUEST_TIMEOUT_MS };
1035
- }
1036
- function direct_environment() {
1037
- const removed = agent_session_environment.removed_proxy_environment();
1038
- return Object.keys(removed).length > 0 ? { env: removed } : {};
1039
- }
1040
- function to_spawn_options(timeout_ms, cwd) {
1041
- return {
1042
- ...to_timeout_option(timeout_ms),
1043
- ...direct_environment(),
1044
- ...cwd !== void 0 && { cwd }
1045
- };
1046
- }
1047
- var GH_REQUEST_TIMEOUT_MESSAGE = "gh request timed out";
1048
- function has_stderr_field(error) {
1049
- return error instanceof Error && "stderr" in error && typeof error.stderr === "string";
1050
- }
1051
- function has_stdout_field(error) {
1052
- return error instanceof Error && "stdout" in error && typeof error.stdout === "string";
1053
- }
1054
- function to_timeout_prefix(error) {
1055
- return has_timed_out(error) ? `${GH_REQUEST_TIMEOUT_MESSAGE}: ` : "";
1056
- }
1057
- function to_gh_error(error) {
1058
- const stderr = has_stderr_field(error) ? error.stderr.trim() : "";
1059
- const stdout = has_stdout_field(error) ? error.stdout.trim() : "";
1060
- const summary = stderr.length > 0 ? stderr : error_text.message_of(error);
1061
- const detail = stdout.length > 0 ? `${summary}
1062
- ${stdout}` : summary;
1063
- return gh_failure.attach(
1064
- new Error(`${to_timeout_prefix(error)}${detail}`, { cause: error }),
1065
- gh_failure.classify_stdout(stdout)
1066
- );
1067
- }
1068
- async function exec_gh_command(arguments_, timeout_ms, cwd) {
1069
- await check_gh_installed();
1070
- const options = to_spawn_options(timeout_ms, cwd);
1071
- try {
1072
- const { stdout } = await execa2("gh", arguments_, options);
1073
- return stdout.trimEnd();
1074
- } catch (error) {
1075
- throw to_gh_error(error);
1076
- }
1077
- }
1078
- async function exec_gh_command_with_stdin(input) {
1079
- await check_gh_installed();
1080
- const options = { input: input.stdin_body, ...to_spawn_options(input.timeout_ms, input.cwd) };
1081
- try {
1082
- const { stdout } = await execa2("gh", input.args, options);
1083
- return stdout.trimEnd();
1084
- } catch (error) {
1085
- throw to_gh_error(error);
1086
- }
1087
- }
1088
- var STATUS_LINE_PATTERN = /^HTTP\/[\d.]+ (?<status>\d{3})\b/u;
1089
- function parse_status_line(output) {
1090
- const { status } = STATUS_LINE_PATTERN.exec(output)?.groups ?? {};
1091
- return status === void 0 ? void 0 : Number(status);
1092
- }
1093
- function status_of_failure(error) {
1094
- return has_stdout_field(error) ? parse_status_line(error.stdout) : void 0;
1095
- }
1096
- async function exec_gh_api_status(path5, timeout_ms) {
1097
- const options = to_spawn_options(timeout_ms);
1098
- try {
1099
- await check_gh_installed();
1100
- const { stdout } = await execa2("gh", ["api", "--include", "--silent", path5], options);
1101
- return parse_status_line(stdout);
1102
- } catch (error) {
1103
- return status_of_failure(error);
1104
- }
1105
- }
1106
- function exec_gh_api_status_sync(path5, timeout_ms) {
1107
- const options = to_spawn_options(timeout_ms);
1108
- try {
1109
- const { stdout } = execaSync("gh", ["api", "--include", "--silent", path5], options);
1110
- return parse_status_line(stdout);
1111
- } catch (error) {
1112
- return status_of_failure(error);
1113
- }
1114
- }
1115
- var METHOD_FLAG = "--method";
1116
- var INPUT_FLAG = "--input";
1117
- var PAGINATE_FLAG = "--paginate";
1118
- var SLURP_FLAG = "--slurp";
1119
- var JQ_FLAG = "--jq";
1120
- function optional_flag(flag, value) {
1121
- return value === void 0 ? [] : [flag, value];
1122
- }
1123
- function to_gh_api_args(request) {
1124
- const body_args = request.body === void 0 ? [] : [INPUT_FLAG, BODY_FROM_STDIN];
1125
- const paginate_args = request.should_paginate === true ? [PAGINATE_FLAG] : [];
1126
- const slurp_args = request.should_slurp === true ? [SLURP_FLAG] : [];
1127
- return [
1128
- "api",
1129
- request.path,
1130
- ...optional_flag(METHOD_FLAG, request.method),
1131
- ...body_args,
1132
- ...paginate_args,
1133
- ...slurp_args,
1134
- ...optional_flag(JQ_FLAG, request.jq_filter)
1135
- ];
1136
- }
1137
- async function exec_gh_api(request) {
1138
- const args = to_gh_api_args(request);
1139
- if (request.body === void 0) {
1140
- return await exec_gh_command(args, request.timeout_ms, request.cwd);
1141
- }
1142
- return await exec_gh_command_with_stdin({
1143
- args,
1144
- stdin_body: request.body,
1145
- timeout_ms: request.timeout_ms,
1146
- cwd: request.cwd
1147
- });
1148
- }
1149
- function exec_gh_api_sync(request) {
1150
- const body_option = request.body === void 0 ? {} : { input: request.body };
1151
- const options = { ...body_option, ...to_spawn_options(request.timeout_ms, request.cwd) };
1152
- try {
1153
- const { stdout } = execaSync("gh", to_gh_api_args(request), options);
1154
- return stdout.trimEnd();
1155
- } catch (error) {
1156
- throw to_gh_error(error);
1157
- }
1158
- }
1159
- function read_gh_api_sync(request) {
1160
- try {
1161
- return exec_gh_api_sync(request);
1162
- } catch {
1163
- return void 0;
1164
- }
1165
- }
1166
- var git_gh_exec = {
1167
- direct_environment,
1168
- exec_gh_command,
1169
- exec_gh_command_with_stdin,
1170
- exec_gh_api,
1171
- exec_gh_api_sync,
1172
- read_gh_api_sync,
1173
- exec_gh_api_status,
1174
- exec_gh_api_status_sync,
1175
- parse_status_line
1176
- };
1177
-
1178
- // scripts/gh/git-gh-conditional.ts
1179
- var NOT_MODIFIED_STATUS = 304;
1180
- var OK_STATUS = 200;
1181
- var INCLUDE_FLAG = "--include";
1182
- var HEADER_FLAG = "-H";
1183
- var IF_NONE_MATCH = "If-None-Match: ";
1184
- var HEADER_BODY_SEPARATOR = /\r?\n\r?\n/u;
1185
- var ETAG_HEADER = /^etag: *(?<etag>[^\r\n]+)/imu;
1186
- var UNCHANGED = { kind: "unchanged" };
1187
- var UNREADABLE = { kind: "unreadable" };
1188
- function to_args(path5, etag) {
1189
- const header = etag === void 0 ? [] : [HEADER_FLAG, `${IF_NONE_MATCH}${etag}`];
1190
- return ["api", INCLUDE_FLAG, ...header, path5];
1191
- }
1192
- function to_changed(output) {
1193
- const [headers = "", ...rest] = output.split(HEADER_BODY_SEPARATOR);
1194
- const etag = ETAG_HEADER.exec(headers)?.groups?.["etag"];
1195
- return { kind: "changed", etag, body: rest.join("\n\n") };
1196
- }
1197
- function to_read(output) {
1198
- return git_gh_exec.parse_status_line(output) === OK_STATUS ? to_changed(output) : UNREADABLE;
1199
- }
1200
- function failure_status(error) {
1201
- const cause = error instanceof Error ? error.cause : void 0;
1202
- return has_stdout_field(cause) ? git_gh_exec.parse_status_line(cause.stdout) : void 0;
1203
- }
1204
- async function read_conditional(path5, etag, timeout_ms) {
1205
- try {
1206
- return to_read(await git_gh_exec.exec_gh_command(to_args(path5, etag), timeout_ms));
1207
- } catch (error) {
1208
- return failure_status(error) === NOT_MODIFIED_STATUS ? UNCHANGED : { kind: "unreadable", cause: error };
1209
- }
1210
- }
1211
- var git_gh_conditional = { read_conditional, to_args };
1212
-
1213
- // scripts/gh/git-gh-helpers.ts
1214
- function parse_pr_state_string(result) {
1215
- const trimmed2 = result.trim();
1216
- return trimmed2.length > 0 ? trimmed2 : void 0;
1217
- }
1218
- function is_pr_already_exists_message(error_message) {
1219
- return error_message.toLowerCase().includes("already exists");
1220
- }
1221
- function get_error_message_with_stderr(error) {
1222
- if (!(error instanceof Error)) return String(error);
1223
- if (has_stderr_field(error) && error.stderr.length > 0) return `${error.message}
1224
- ${error.stderr}`;
1225
- return error.message;
1226
- }
1227
- function handle_pr_create_error(error) {
1228
- const error_message = get_error_message_with_stderr(error);
1229
- if (is_pr_already_exists_message(error_message)) {
1230
- throw new Error("PR_ALREADY_EXISTS");
1231
- }
1232
- throw error;
1233
- }
1234
- var git_gh_helpers = {
1235
- parse_pr_state_string,
1236
- get_error_message_with_stderr,
1237
- handle_pr_create_error
1238
- };
1239
-
1240
- // scripts/gh/git-gh-issue-rest.ts
1241
- import { z as z4 } from "zod";
1242
-
1243
- // scripts/gh/git-gh-rest-state.ts
1244
- var MERGED_STATE = "MERGED";
1245
- function to_gh_state(state) {
1246
- return state?.toUpperCase();
1247
- }
1248
-
1249
- // scripts/gh/git-gh-issue-rest.ts
1250
- var rest_issue_schema = z4.looseObject({
1251
- number: z4.number(),
1252
- issue_dependencies_summary: z4.looseObject({ total_blocked_by: z4.number().optional() }).nullish(),
1253
- // Present only on a pull request, which this endpoint serves as readily as an issue.
1254
- pull_request: z4.looseObject({ merged_at: z4.string().nullish() }).nullish()
1255
- });
1256
- var REPOSITORY_URL = /\/repos\/([\w.-]+\/[\w.-]+)$/u;
1257
- var REPOSITORY_URL_GROUP = 1;
1258
- var BLOCKED_BY_FIELD = "blockedBy";
1259
- var BLOCKED_BY_COUNT_FIELD = "blocked_by_count";
1260
- var STATE_FIELD = "state";
1261
- var BODY_FIELD = "body";
1262
- var FIELD_SEPARATOR = ",";
1263
- var EMPTY_BODY = "";
1264
- var REST_FIELD_NAMES = /* @__PURE__ */ new Map([
1265
- ["url", "html_url"],
1266
- ["createdAt", "created_at"],
1267
- ["closedAt", "closed_at"],
1268
- ["stateReason", "state_reason"],
1269
- ["updatedAt", "updated_at"]
1270
- ]);
1271
- var NOT_AN_ISSUE_MESSAGE = "gh api answered something other than an issue object";
1272
- var NOT_AN_ISSUE_LISTING_MESSAGE = "gh api answered something other than an issue listing";
1273
- var NOT_A_BLOCKER_LISTING_MESSAGE = "gh api answered something other than a blocked-by listing";
1274
- function rest_field_name(field) {
1275
- return REST_FIELD_NAMES.get(field) ?? field;
1276
- }
1277
- function split_fields(fields) {
1278
- return fields.split(FIELD_SEPARATOR).map((field) => field.trim()).filter((field) => field.length > 0);
1279
- }
1280
- function to_issue_state(rest, value) {
1281
- if (typeof rest.pull_request?.merged_at === "string") return MERGED_STATE;
1282
- return typeof value === "string" ? to_gh_state(value) : value;
1283
- }
1284
- function total_blocked_by(rest) {
1285
- return rest.issue_dependencies_summary?.total_blocked_by;
1286
- }
1287
- function to_gh_field_value(field, rest) {
1288
- if (field === BLOCKED_BY_COUNT_FIELD) return total_blocked_by(rest);
1289
- const value = rest[rest_field_name(field)];
1290
- if (field === STATE_FIELD) return to_issue_state(rest, value);
1291
- return field === BODY_FIELD ? value ?? EMPTY_BODY : value;
1292
- }
1293
- function parse_rest_issue(rest_json) {
1294
- const parsed = parse_json_object_or_undefined(rest_json, rest_issue_schema);
1295
- if (parsed === void 0) throw new Error(NOT_AN_ISSUE_MESSAGE);
1296
- return parsed;
1297
- }
1298
- function is_pull_request(rest) {
1299
- return rest.pull_request !== void 0 && rest.pull_request !== null;
1300
- }
1301
- function parse_rest_issues(rest_json) {
1302
- const parsed = parse_json_array_or_undefined(rest_json, rest_issue_schema);
1303
- if (parsed === void 0) throw new Error(NOT_AN_ISSUE_LISTING_MESSAGE);
1304
- return parsed;
1305
- }
1306
- function empty_blocked_by() {
1307
- return { nodes: [], totalCount: 0 };
1308
- }
1309
- function repo_of_url(repository_url = "") {
1310
- const match = REPOSITORY_URL.exec(repository_url);
1311
- return match?.[REPOSITORY_URL_GROUP];
1312
- }
1313
- function to_blocked_by(blockers_json, exact_total) {
1314
- const parsed = parse_json_array_or_undefined(blockers_json, blocking_issue_schema);
1315
- if (parsed === void 0) throw new Error(NOT_A_BLOCKER_LISTING_MESSAGE);
1316
- const nodes = parsed.map((blocker) => ({ ...blocker, state: to_gh_state(blocker.state) }));
1317
- return { nodes, totalCount: exact_total ?? nodes.length };
1318
- }
1319
- function to_gh_issue(rest, fields, blocked_by) {
1320
- return Object.fromEntries(
1321
- fields.map((field) => [
1322
- field,
1323
- field === BLOCKED_BY_FIELD ? blocked_by : to_gh_field_value(field, rest)
1324
- ])
1325
- );
1326
- }
1327
- function to_field_text(value) {
1328
- if (typeof value === "string") return value;
1329
- return value === void 0 || value === null ? EMPTY_BODY : JSON.stringify(value);
1330
- }
1331
- var CLOSED = "CLOSED";
1332
- function reference_of_blocker(node, fallback_repo) {
1333
- const repo = repo_of_url(node.repository_url) ?? fallback_repo;
1334
- if (node.state === void 0) return { repo, number: node.number };
1335
- return { repo, number: node.number, state: node.state.toUpperCase() === CLOSED ? CLOSED : "OPEN" };
1336
- }
1337
- var git_gh_issue_rest = {
1338
- empty_blocked_by,
1339
- repo_of_url,
1340
- reference_of_blocker,
1341
- split_fields,
1342
- is_pull_request,
1343
- parse_rest_issue,
1344
- parse_rest_issues,
1345
- total_blocked_by,
1346
- to_blocked_by,
1347
- to_gh_issue,
1348
- to_field_text
1349
- };
1350
-
1351
- // scripts/gh/git-gh-reachability.ts
1352
- var RATE_LIMITED_STATUS = 429;
1353
- var SERVER_ERROR_FLOOR = 500;
1354
- function is_retryable_status(status) {
1355
- if (status >= SERVER_ERROR_FLOOR) return true;
1356
- return status === RATE_LIMITED_STATUS;
1357
- }
1358
- function classify_status(status) {
1359
- if (status === void 0) return "unreachable";
1360
- return is_retryable_status(status) ? "unreachable" : "reachable";
1361
- }
1362
- var gh_reachability = { classify_status };
1363
-
1364
- // scripts/gh/git-gh-issue-read.ts
1365
- async function read_blocked_by_listing(issue_number, repo, exact_total) {
1366
- const json = await git_gh_exec.exec_gh_api({
1367
- path: `${git_gh_api_path.blocked_by_api_path(issue_number, repo)}${git_gh_api_path.FULL_PAGE_QUERY}`
1368
- });
1369
- return git_gh_issue_rest.to_blocked_by(json, exact_total);
1370
- }
1371
- async function read_blocked_by(issue_number, rest, repo) {
1372
- if (git_gh_issue_rest.is_pull_request(rest)) return git_gh_issue_rest.empty_blocked_by();
1373
- const exact_total = git_gh_issue_rest.total_blocked_by(rest);
1374
- if (exact_total === 0) return git_gh_issue_rest.empty_blocked_by();
1375
- return await read_blocked_by_listing(issue_number, repo, exact_total);
1376
- }
1377
- function mark_followup(error) {
1378
- if (!(error instanceof Error)) return error;
1379
- const failure = gh_failure.failure_of(error);
1380
- if (failure === void 0) return error;
1381
- return gh_failure.attach(error, { ...failure, is_followup: true });
1382
- }
1383
- async function read_relations(issue_number, rest, repo) {
1384
- try {
1385
- return await read_blocked_by(issue_number, rest, repo);
1386
- } catch (error) {
1387
- throw mark_followup(error);
1388
- }
1389
- }
1390
- async function read_issue_fields(issue_number, fields, repo) {
1391
- const rest = git_gh_issue_rest.parse_rest_issue(
1392
- await git_gh_exec.exec_gh_api({ path: git_gh_api_path.issue_api_path(issue_number, repo) })
1393
- );
1394
- const requested = git_gh_issue_rest.split_fields(fields);
1395
- const blocked_by = requested.includes(BLOCKED_BY_FIELD) ? await read_relations(issue_number, rest, repo) : void 0;
1396
- return git_gh_issue_rest.to_gh_issue(rest, requested, blocked_by);
1397
- }
1398
- var NOT_FOUND_STATUS = 404;
1399
- function is_number_unresolved(failure) {
1400
- return failure.status === NOT_FOUND_STATUS && failure.is_followup !== true;
1401
- }
1402
- function to_unreadable_reason(status) {
1403
- return gh_reachability.classify_status(status) === "unreachable" ? "unreachable" : "rejected";
1404
- }
1405
- function to_read_failure(error) {
1406
- const failure = gh_failure.failure_of(error);
1407
- if (failure === void 0) return { kind: "unreadable", reason: "malformed", status: void 0 };
1408
- if (is_number_unresolved(failure)) return { kind: "missing" };
1409
- return {
1410
- kind: "unreadable",
1411
- reason: to_unreadable_reason(failure.status),
1412
- status: failure.status
1413
- };
1414
- }
1415
- async function issue_view_json_classified(issue_number, fields, repo) {
1416
- try {
1417
- const issue = await read_issue_fields(issue_number, fields, repo);
1418
- return { kind: "read", json: JSON.stringify(issue) };
1419
- } catch (error) {
1420
- return to_read_failure(error);
1421
- }
1422
- }
1423
- async function issue_view_field_classified(issue_number, field, repo) {
1424
- try {
1425
- const issue = await read_issue_fields(issue_number, field, repo);
1426
- return { kind: "read", text: git_gh_issue_rest.to_field_text(issue[field]) };
1427
- } catch (error) {
1428
- return to_read_failure(error);
1429
- }
1430
- }
1431
- async function issue_view_field(issue_number, field, repo) {
1432
- const read = await issue_view_field_classified(issue_number, field, repo);
1433
- return read.kind === "read" ? read.text : void 0;
1434
- }
1435
- async function issue_get_title(issue_number, repo) {
1436
- const result = await issue_view_field(issue_number, "title", repo);
1437
- return result === void 0 ? void 0 : git_gh_helpers.parse_pr_state_string(result);
1438
- }
1439
- async function issue_get_body(issue_number, repo) {
1440
- return await issue_view_field(issue_number, "body", repo);
1441
- }
1442
- async function issue_get_body_classified(issue_number, repo) {
1443
- return await issue_view_field_classified(issue_number, "body", repo);
1444
- }
1445
- async function issue_view_json(issue_number, fields, repo) {
1446
- const read = await issue_view_json_classified(issue_number, fields, repo);
1447
- return read.kind === "read" ? read.json : void 0;
1448
- }
1449
- var STATE_AND_RELATIONS_FIELDS = "number,state,labels,blockedBy,body";
1450
- async function issue_get_state_and_relations(issue_number, repo) {
1451
- return await issue_view_json(issue_number, STATE_AND_RELATIONS_FIELDS, repo);
1452
- }
1453
- async function issue_get_state_and_relations_classified(issue_number, repo) {
1454
- return await issue_view_json_classified(issue_number, STATE_AND_RELATIONS_FIELDS, repo);
1455
- }
1456
- function is_unreachable_read(failure) {
1457
- return failure.kind === "unreadable" && failure.reason === "unreachable";
1458
- }
1459
- var PLAN_FIELDS = "number,title,body,state,url,labels,blockedBy";
1460
- async function issue_get_plan_fields(issue_number) {
1461
- return await issue_view_json(issue_number, PLAN_FIELDS);
1462
- }
1463
- async function issue_get_plan_fields_classified(issue_number) {
1464
- return await issue_view_json_classified(issue_number, PLAN_FIELDS);
1465
- }
1466
- async function issue_get_labels_and_body(issue_number) {
1467
- return await issue_view_json(issue_number, "number,state,labels,body");
1468
- }
1469
- async function issue_list_comments(issue_number, timeout_ms) {
1470
- const path5 = `${git_gh_api_path.issue_comments_api_path(issue_number)}${git_gh_api_path.FULL_PAGE_QUERY}`;
1471
- try {
1472
- return await git_gh_exec.exec_gh_api({ path: path5, should_paginate: true, timeout_ms });
1473
- } catch {
1474
- return void 0;
1475
- }
1476
- }
1477
- async function has_no_relations_endpoint(issue_number, repo) {
1478
- const status = await git_gh_exec.exec_gh_api_status(
1479
- git_gh_api_path.blocked_by_api_path(issue_number, repo)
1480
- );
1481
- return status === NOT_FOUND_STATUS;
1482
- }
1483
- async function issue_blocked_by_references(issue_number, own_repo, repo) {
1484
- try {
1485
- const listing = await read_blocked_by_listing(issue_number, repo);
1486
- return listing.nodes.map((blocker) => git_gh_issue_rest.reference_of_blocker(blocker, own_repo));
1487
- } catch (error) {
1488
- if (await has_no_relations_endpoint(issue_number, repo)) return [];
1489
- throw error;
1490
- }
1491
- }
1492
- async function issue_blocked_by_numbers(issue_number, repo) {
1493
- const references = await issue_blocked_by_references(issue_number, "", repo);
1494
- return references.map((blocker) => blocker.number);
1495
- }
1496
- var git_gh_issue_read = {
1497
- issue_blocked_by_numbers,
1498
- issue_blocked_by_references,
1499
- issue_get_title,
1500
- issue_get_body,
1501
- issue_get_body_classified,
1502
- issue_view_json,
1503
- issue_view_json_classified,
1504
- issue_get_state_and_relations,
1505
- issue_get_state_and_relations_classified,
1506
- is_unreachable_read,
1507
- issue_get_plan_fields,
1508
- issue_get_plan_fields_classified,
1509
- issue_get_labels_and_body,
1510
- issue_list_comments
1511
- };
1512
-
1513
- // scripts/issue/issue-watch.ts
1514
- import { z as z7 } from "zod";
1515
-
1516
- // scripts/gh/gh-author-association.ts
1517
- import { z as z5 } from "zod";
1518
- var OWNER = "OWNER";
1519
- var ASKED_ASSOCIATIONS = /* @__PURE__ */ new Set(["MEMBER", "COLLABORATOR"]);
1520
- var WRITE_ROLES = /* @__PURE__ */ new Set(["admin", "maintain", "write"]);
1521
- var LOGIN_PATTERN = /^[\da-z](?:[\w-]*[\da-z])?$/iu;
1522
- var TRUSTED_LIST = "OWNER, or MEMBER / COLLABORATOR with write access";
1523
- var permission_schema = z5.looseObject({
1524
- permission: z5.string().nullish(),
1525
- role_name: z5.string().nullish()
1526
- });
1527
- var answers = /* @__PURE__ */ new Map();
1528
- function permission_path(login) {
1529
- return `${git_gh_api_path.repo_api_path()}/collaborators/${login}/permission`;
1530
- }
1531
- function has_write_role(raw) {
1532
- const parsed = parse_json.parse_json_object_or_undefined(raw, permission_schema);
1533
- const roles = [parsed?.role_name, parsed?.permission];
1534
- return roles.some((role) => typeof role === "string" && WRITE_ROLES.has(role));
1535
- }
1536
- async function ask_permission(login, timeout_ms) {
1537
- try {
1538
- const raw = await git_gh_exec.exec_gh_api({ path: permission_path(login), timeout_ms });
1539
- return has_write_role(raw);
1540
- } catch {
1541
- return void 0;
1542
- }
1543
- }
1544
- async function can_write(login, timeout_ms) {
1545
- const asked = answers.get(login) ?? ask_permission(login, timeout_ms);
1546
- answers.set(login, asked);
1547
- const has_write = await asked;
1548
- if (has_write === void 0 && answers.get(login) === asked) answers.delete(login);
1549
- return has_write;
1550
- }
1551
- function is_user_login(login) {
1552
- return login !== void 0 && LOGIN_PATTERN.test(login);
1553
- }
1554
- function is_asked(author) {
1555
- return ASKED_ASSOCIATIONS.has(author.association ?? "") && is_user_login(author.login);
1556
- }
1557
- async function trust_of(author) {
1558
- if (author.association === OWNER) return true;
1559
- if (author.login === void 0 || !is_asked(author)) return false;
1560
- return await can_write(author.login, author.timeout_ms);
1561
- }
1562
- async function is_trusted(author) {
1563
- return await trust_of(author) === true;
1564
- }
1565
- var gh_author_association = { TRUSTED_LIST, is_trusted, trust_of };
1566
-
1567
- // scripts/issue/issue-watch-diff.ts
1568
- import { z as z6 } from "zod";
1569
- var RUN_MARKER = "<!-- josh:run -->";
1570
- var BOT_TYPE = "Bot";
1571
- var BOT_SUFFIX = "[bot]";
1572
- var NO_COMMENT_ID = 0;
1573
- var UNKNOWN_AUTHOR = "(unknown)";
1574
- var UNKNOWN_TIME = "(undated)";
1575
- var UNVERIFIED_BODY = "(body withheld \u2014 the author's write access could not be checked; read it with `josh issue:read`)";
1576
- var BODY_HEADING = "Body edited:";
1577
- var REMOVED_PREFIX = "- ";
1578
- var ADDED_PREFIX = "+ ";
1579
- var COMMENT_HEADING = "New comment by ";
1580
- var AT = " at ";
1581
- var SECTION_SEPARATOR = "\n\n";
1582
- var LINE_SEPARATOR = "\n";
1583
- var CRLF = "\r\n";
1584
- var comment_schema = z6.looseObject({
1585
- id: z6.number(),
1586
- user: z6.looseObject({ login: z6.string(), type: z6.string().optional() }).nullish(),
1587
- created_at: z6.string().optional(),
1588
- body: z6.string().nullish(),
1589
- author_association: z6.string().nullish()
1590
- });
1591
- function is_bot(user) {
1592
- return user?.type === BOT_TYPE || (user?.login.endsWith(BOT_SUFFIX) ?? false);
1593
- }
1594
- function is_automated(raw, is_trusted2) {
1595
- return is_bot(raw.user) || is_trusted2 === true && (raw.body?.includes(RUN_MARKER) ?? false);
1596
- }
1597
- async function to_comment(raw, timeout_ms) {
1598
- const login = raw.user?.login;
1599
- const is_trusted2 = await gh_author_association.trust_of({
1600
- login,
1601
- association: raw.author_association,
1602
- timeout_ms
1603
- });
1604
- return {
1605
- id: raw.id,
1606
- author: login ?? UNKNOWN_AUTHOR,
1607
- is_trusted: is_trusted2,
1608
- is_automated: is_automated(raw, is_trusted2),
1609
- created_at: raw.created_at ?? UNKNOWN_TIME,
1610
- body: raw.body ?? ""
1611
- };
1612
- }
1613
- async function parse_comments(json, timeout_ms) {
1614
- if (json === void 0) return void 0;
1615
- const listing = read_json_listing(json, comment_schema);
1616
- if (listing.kind !== "read") return void 0;
1617
- return await Promise.all(listing.rows.map(async (row) => await to_comment(row, timeout_ms)));
1618
- }
1619
- function last_comment_id(comments) {
1620
- return Math.max(NO_COMMENT_ID, ...comments.map((comment) => comment.id));
1621
- }
1622
- function baseline_of(snapshot) {
1623
- return { body: snapshot.body, last_comment_id: last_comment_id(snapshot.comments) };
1624
- }
1625
- function lines_missing_from(source, other) {
1626
- const present = new Set(other.split(LINE_SEPARATOR));
1627
- return source.split(LINE_SEPARATOR).filter((line) => line.trim() !== "" && !present.has(line));
1628
- }
1629
- function to_lf(body) {
1630
- return body.split(CRLF).join(LINE_SEPARATOR);
1631
- }
1632
- function body_section(previous_raw, current_raw) {
1633
- const previous = to_lf(previous_raw);
1634
- const current = to_lf(current_raw);
1635
- if (previous === current) return void 0;
1636
- const removed = lines_missing_from(previous, current).map((line) => `${REMOVED_PREFIX}${line}`);
1637
- const added = lines_missing_from(current, previous).map((line) => `${ADDED_PREFIX}${line}`);
1638
- return [BODY_HEADING, ...removed, ...added].join(LINE_SEPARATOR);
1639
- }
1640
- function comment_section(comment) {
1641
- const body = comment.is_trusted === true ? comment.body : UNVERIFIED_BODY;
1642
- return `${COMMENT_HEADING}${comment.author}${AT}${comment.created_at}${LINE_SEPARATOR}${body}`;
1643
- }
1644
- function new_person_comments(baseline, snapshot) {
1645
- return snapshot.comments.filter(
1646
- (comment) => comment.id > baseline.last_comment_id && comment.is_trusted !== false && !comment.is_automated
1647
- );
1648
- }
1649
- function unread_diff(baseline, snapshot) {
1650
- const body = body_section(baseline.body, snapshot.body);
1651
- const comments = new_person_comments(baseline, snapshot).map(
1652
- (comment) => comment_section(comment)
1653
- );
1654
- const sections = [...body === void 0 ? [] : [body], ...comments];
1655
- return sections.length === 0 ? void 0 : sections.join(SECTION_SEPARATOR);
1656
- }
1657
- var issue_watch_diff = {
1658
- RUN_MARKER,
1659
- baseline_of,
1660
- parse_comments,
1661
- unread_diff
1662
- };
1663
-
1664
- // scripts/issue/issue-watch.ts
1665
- var RECORD_PREFIX = "josh-issue-watch-";
1666
- var CLOSED_STATE = "closed";
1667
- var record_schema = z7.object({
1668
- issue: z7.string(),
1669
- body: z7.string(),
1670
- last_comment_id: z7.number(),
1671
- acknowledged_at: z7.string(),
1672
- checked_at: z7.string(),
1673
- etag: z7.string().optional(),
1674
- pending: z7.string().optional(),
1675
- shown: z7.string().optional()
1676
- });
1677
- var issue_schema = z7.looseObject({ body: z7.string().nullish(), state: z7.string() });
1678
- var UNREADABLE2 = { kind: "unreadable" };
1679
- function record_path(root = PROJECT_ROOT) {
1680
- return stamp_file.stamp_path(RECORD_PREFIX, root);
1681
- }
1682
- function read_record(root) {
1683
- const raw = stamp_file.read_stamp_text(record_path(root));
1684
- return raw === void 0 ? void 0 : json_value.parse_with(raw, record_schema);
1685
- }
1686
- function write_record(record, root) {
1687
- stamp_file.replace_stamp(record_path(root), record);
1688
- return record;
1689
- }
1690
- function clear2(root) {
1691
- stamp_file.remove_stamp(record_path(root));
1692
- }
1693
- async function read_snapshot(request, body, etag) {
1694
- const comments = await issue_watch_diff.parse_comments(
1695
- await git_gh_issue_read.issue_list_comments(request.issue, request.timeout_ms),
1696
- request.timeout_ms
1697
- );
1698
- return comments === void 0 ? UNREADABLE2 : { kind: "read", snapshot: { body, comments }, etag };
1699
- }
1700
- async function fetch_issue(request) {
1701
- const read = await git_gh_conditional.read_conditional(
1702
- git_gh_api_path.issue_api_path(request.issue),
1703
- request.etag,
1704
- request.timeout_ms
1705
- );
1706
- if (read.kind !== "changed") return read;
1707
- const fields = json_value.parse_with(read.body, issue_schema);
1708
- if (fields === void 0) return UNREADABLE2;
1709
- if (fields.state === CLOSED_STATE) return { kind: "closed" };
1710
- return await read_snapshot(request, fields.body ?? "", read.etag);
1711
- }
1712
- function fresh_record(issue, fetched, now, acknowledged_at = now.toISOString()) {
1713
- const baseline = issue_watch_diff.baseline_of(fetched.snapshot);
1714
- const checked_at = now.toISOString();
1715
- return { issue, ...baseline, acknowledged_at, checked_at, etag: fetched.etag };
1716
- }
1717
- async function record_baseline(issue, root, now = /* @__PURE__ */ new Date()) {
1718
- const fetched = await fetch_issue({ issue });
1719
- if (fetched.kind !== "read") return false;
1720
- write_record(fresh_record(issue, fetched, now), root);
1721
- return true;
1722
- }
1723
- async function record_baseline_here(issue) {
1724
- return await record_baseline(issue, await git_command.repository_root());
1725
- }
1726
- async function clear_here2() {
1727
- clear2(await git_command.repository_root());
1728
- }
1729
- function with_fetched(record, fetched, checked_at) {
1730
- if (fetched.kind !== "read") return { ...record, checked_at };
1731
- const pending = issue_watch_diff.unread_diff(record, fetched.snapshot);
1732
- return { ...record, checked_at, etag: fetched.etag, pending };
1733
- }
1734
- function is_due(record, options, now) {
1735
- return now.getTime() - Date.parse(record.checked_at) >= options.interval_ms;
1736
- }
1737
- async function refresh(record, options, now, root) {
1738
- const fetched = await fetch_issue({
1739
- issue: record.issue,
1740
- etag: record.etag,
1741
- timeout_ms: options.timeout_ms
1742
- });
1743
- if (fetched.kind === "closed") {
1744
- clear2(root);
1745
- return void 0;
1746
- }
1747
- return write_record(with_fetched(record, fetched, now.toISOString()), root);
1748
- }
1749
- async function poll(options, root) {
1750
- const record = read_record(root);
1751
- const now = options.now ?? /* @__PURE__ */ new Date();
1752
- if (record === void 0 || !is_due(record, options, now)) return record;
1753
- return await refresh(record, options, now, root);
1754
- }
1755
- function mark_shown(record, root) {
1756
- return write_record({ ...record, shown: record.pending }, root);
1757
- }
1758
- async function acknowledge(root, now = /* @__PURE__ */ new Date()) {
1759
- const record = read_record(root);
1760
- if (record === void 0) return void 0;
1761
- const fetched = await fetch_issue({ issue: record.issue });
1762
- if (fetched.kind !== "read") return void 0;
1763
- const diff = issue_watch_diff.unread_diff(record, fetched.snapshot);
1764
- const acknowledged_at = diff === void 0 ? record.acknowledged_at : now.toISOString();
1765
- write_record(fresh_record(record.issue, fetched, now, acknowledged_at), root);
1766
- return { issue: record.issue, diff };
1767
- }
1768
- var issue_watch = {
1769
- acknowledge,
1770
- clear: clear2,
1771
- clear_here: clear_here2,
1772
- mark_shown,
1773
- poll,
1774
- read_record,
1775
- record_baseline,
1776
- record_baseline_here,
1777
- record_path
1778
- };
1779
-
1780
- // scripts/issue/issue-watch-gate.ts
1781
- var EVERY_CALL_MS = 0;
1782
- function ack_command(issue) {
1783
- return `pnpm josh issue:ack ${issue}`;
1784
- }
1785
- function unread_message(record) {
1786
- return [
1787
- `A person updated issue ${session_cite.issue(record.issue)} after this run read it, and the run has not taken the update in:`,
1788
- record.pending ?? "",
1789
- `Read it, compare it with the acceptance criteria, fix what it changes, then run \`${ack_command(record.issue)}\` to record that it was read.`
1790
- ].join("\n\n");
1791
- }
1792
- function review_message(record, briefed_at) {
1793
- return [
1794
- `Issue ${session_cite.issue(record.issue)} was updated after the review was briefed (taken in at ${record.acknowledged_at}, briefed at ${briefed_at}), so the review read the earlier specification.`,
1795
- "Re-run `/code-review` with a fresh `pnpm josh review:brief`, so the review reads the change against the updated issue."
1796
- ].join("\n");
1797
- }
1798
- async function polled(root) {
1799
- return await issue_watch.poll({ interval_ms: EVERY_CALL_MS }, root);
1800
- }
1801
- async function unread_refusal(root) {
1802
- const record = await polled(root);
1803
- return record?.pending === void 0 ? void 0 : unread_message(record);
1804
- }
1805
- async function review_refusal(root) {
1806
- const record = await polled(root);
1807
- if (record === void 0) return void 0;
1808
- if (record.pending !== void 0) return unread_message(record);
1809
- const pointer = review_attest.read_pointer(root);
1810
- if (pointer === void 0 || record.acknowledged_at <= pointer.taken_at) return void 0;
1811
- return review_message(record, pointer.taken_at);
1812
- }
1813
- async function review_refusal_here() {
1814
- return await review_refusal(await git_command.repository_root());
1815
- }
1816
- async function assert_read_here() {
1817
- const refusal = await unread_refusal(await git_command.repository_root());
1818
- if (refusal !== void 0) throw new Error(refusal);
1819
- }
1820
- var issue_watch_gate = {
1821
- assert_read_here,
1822
- review_refusal,
1823
- review_refusal_here,
1824
- unread_message,
1825
- unread_refusal
1826
- };
1827
-
1828
- // scripts/gh/git-gh-pr-rest.ts
1829
- import { z as z8 } from "zod";
1830
- var rest_repo_schema = z8.looseObject({ full_name: z8.string().optional() }).nullish();
1831
- var rest_pull_side_schema = z8.looseObject({ ref: z8.string().optional(), repo: rest_repo_schema });
1832
- var rest_pull_schema = z8.looseObject({
1833
- number: z8.number(),
1834
- html_url: z8.string().optional(),
1835
- body: z8.string().nullish(),
1836
- state: z8.string().optional(),
1837
- merged: z8.boolean().nullish(),
1838
- merged_at: z8.string().nullish(),
1839
- mergeable: z8.boolean().nullish(),
1840
- mergeable_state: z8.string().optional(),
1841
- // `sha` is the head commit, which is what both halves of the merge-gate rollup are keyed by —
1842
- // REST hangs the check runs and the status contexts off the commit rather than off the pull
1843
- // request.
1844
- head: z8.looseObject({ ref: z8.string().optional(), sha: z8.string().optional(), repo: rest_repo_schema }).nullish(),
1845
- base: rest_pull_side_schema.nullish(),
1846
- // `node_id` is what the GraphQL auto-merge mutation addresses a pull request by, and `auto_merge`
1847
- // is `null` until auto-merge is enabled — both read by `git-gh-pr-auto-merge.ts`.
1848
- node_id: z8.string().optional(),
1849
- auto_merge: z8.looseObject({}).nullish()
1850
- });
1851
- var NOT_A_PULL_MESSAGE = "gh api answered something other than a pull request object";
1852
- var NOT_A_PULL_LISTING_MESSAGE = "gh api answered something other than a pull request listing";
1853
- var NOT_A_COMMENT_LISTING_MESSAGE = "gh api answered something other than a comment listing";
1854
- var OPEN_STATE = "open";
1855
- var EMPTY_BODY2 = "";
1856
- function parse_rest_pull(rest_json) {
1857
- const parsed = parse_json_object_or_undefined(rest_json, rest_pull_schema);
1858
- if (parsed === void 0) throw new Error(NOT_A_PULL_MESSAGE);
1859
- return parsed;
1860
- }
1861
- function parse_rest_pulls(rest_json) {
1862
- const parsed = parse_json_array_or_undefined(rest_json, rest_pull_schema);
1863
- if (parsed === void 0) throw new Error(NOT_A_PULL_LISTING_MESSAGE);
1864
- return parsed;
1865
- }
1866
- function select_pull(pulls) {
1867
- return pulls.find((pull) => pull.state === OPEN_STATE) ?? pulls[0];
1868
- }
1869
- function is_merged(pull) {
1870
- return pull.merged === true || typeof pull.merged_at === "string";
1871
- }
1872
- function to_pr_state(pull) {
1873
- return is_merged(pull) ? MERGED_STATE : to_gh_state(pull.state);
1874
- }
1875
- function to_repo_name(side) {
1876
- return side?.repo?.full_name;
1877
- }
1878
- function is_same_repository_head(pull) {
1879
- const head_repo = to_repo_name(pull.head);
1880
- return head_repo !== void 0 && head_repo === to_repo_name(pull.base);
1881
- }
1882
- function to_pr_info(pull) {
1883
- return {
1884
- mergeable: pull.mergeable,
1885
- mergeStateStatus: to_gh_state(pull.mergeable_state),
1886
- state: to_pr_state(pull)
1887
- };
1888
- }
1889
- function to_pr_comments(rest_json) {
1890
- const parsed = parse_json_array_or_undefined(rest_json, rest_comment_schema);
1891
- if (parsed === void 0) throw new Error(NOT_A_COMMENT_LISTING_MESSAGE);
1892
- return parsed.map((comment) => ({
1893
- body: comment.body ?? EMPTY_BODY2,
1894
- url: comment.html_url,
1895
- author: { login: comment.user?.login }
1896
- }));
1897
- }
1898
- var git_gh_pr_rest = {
1899
- parse_rest_pull,
1900
- parse_rest_pulls,
1901
- select_pull,
1902
- is_same_repository_head,
1903
- is_merged,
1904
- to_pr_state,
1905
- to_pr_info,
1906
- to_pr_comments
1907
- };
1908
-
1909
- // scripts/gh/git-gh-pr-read.ts
1910
- var pr_number_by_branch = /* @__PURE__ */ new Map();
1911
- var LOOKUP_QUERY = "state=all&sort=created&direction=desc&per_page=100";
1912
- var COMMENTS_QUERY = FULL_PAGE_QUERY;
1913
- var OWNER_PLACEHOLDER = "{owner}";
1914
- var NO_PULL_REQUEST_MESSAGE = "gh api found no pull request for branch";
1915
- var UNREADABLE_PULL_REQUEST_MESSAGE = "gh api could not read the pull requests for branch";
1916
- function lookup_path(branch_name) {
1917
- const head = `${OWNER_PLACEHOLDER}:${encodeURIComponent(branch_name)}`;
1918
- return `${git_gh_api_path.pulls_api_path()}?head=${head}&${LOOKUP_QUERY}`;
1919
- }
1920
- async function fetch_pr_number(branch_name) {
1921
- const json = await git_gh_exec.exec_gh_api({ path: lookup_path(branch_name) });
1922
- return git_gh_pr_rest.select_pull(git_gh_pr_rest.parse_rest_pulls(json))?.number;
1923
- }
1924
- var pending_pr_number_by_branch = /* @__PURE__ */ new Map();
1925
- var pull_by_number = /* @__PURE__ */ new Map();
1926
- async function fetch_pr_number_read(branch_name) {
1927
- try {
1928
- const pr_number = await fetch_pr_number(branch_name);
1929
- if (pr_number === void 0) return { kind: "missing" };
1930
- pr_number_by_branch.set(branch_name, pr_number);
1931
- return { kind: "read", pr_number };
1932
- } catch (error) {
1933
- return { kind: "unreadable", cause: error };
1934
- }
1935
- }
1936
- async function start_pr_number_read(branch_name) {
1937
- const pending = pending_pr_number_by_branch.get(branch_name);
1938
- if (pending !== void 0) return await pending;
1939
- const lookup = fetch_pr_number_read(branch_name);
1940
- pending_pr_number_by_branch.set(branch_name, lookup);
1941
- try {
1942
- return await lookup;
1943
- } finally {
1944
- pending_pr_number_by_branch.delete(branch_name);
1945
- }
1946
- }
1947
- function forget_pr_numbers() {
1948
- pr_number_by_branch.clear();
1949
- pending_pr_number_by_branch.clear();
1950
- pull_by_number.clear();
1951
- }
1952
- async function read_pr_number(branch_name) {
1953
- const cached = pr_number_by_branch.get(branch_name);
1954
- if (cached !== void 0) return { kind: "read", pr_number: cached };
1955
- return await start_pr_number_read(branch_name);
1956
- }
1957
- async function resolve_pr_number(branch_name) {
1958
- const read = await read_pr_number(branch_name);
1959
- return read.kind === "read" ? read.pr_number : void 0;
1960
- }
1961
- function to_unreadable_error(branch_name, cause) {
1962
- return new Error(`${UNREADABLE_PULL_REQUEST_MESSAGE}: ${branch_name}`, { cause });
1963
- }
1964
- async function require_pr_number(branch_name) {
1965
- const read = await read_pr_number(branch_name);
1966
- if (read.kind === "read") return read.pr_number;
1967
- if (read.kind === "missing") throw new Error(`${NO_PULL_REQUEST_MESSAGE}: ${branch_name}`);
1968
- throw to_unreadable_error(branch_name, read.cause);
1969
- }
1970
- async function read_pull(pr_number) {
1971
- const json = await git_gh_exec.exec_gh_api({
1972
- path: git_gh_api_path.pull_api_path(String(pr_number))
1973
- });
1974
- return git_gh_pr_rest.parse_rest_pull(json);
1975
- }
1976
- async function read_remembered_pull(pr_number) {
1977
- const pending = pull_by_number.get(pr_number) ?? read_pull(pr_number);
1978
- pull_by_number.set(pr_number, pending);
1979
- try {
1980
- return await pending;
1981
- } catch (error) {
1982
- if (pull_by_number.get(pr_number) === pending) pull_by_number.delete(pr_number);
1983
- throw error;
1984
- }
1985
- }
1986
- async function read_pull_of_branch(branch_name, read = read_remembered_pull) {
1987
- const number_read = await read_pr_number(branch_name);
1988
- if (number_read.kind !== "read") return number_read;
1989
- try {
1990
- return { kind: "read", pull: await read(number_read.pr_number) };
1991
- } catch (error) {
1992
- return { kind: "unreadable", cause: error };
1993
- }
1994
- }
1995
- async function read_pull_or_undefined(branch_name) {
1996
- const read = await read_pull_of_branch(branch_name);
1997
- return read.kind === "read" ? read.pull : void 0;
1998
- }
1999
- async function pr_exists(branch_name) {
2000
- const read = await read_pr_number(branch_name);
2001
- if (read.kind === "unreadable") throw to_unreadable_error(branch_name, read.cause);
2002
- return read.kind === "read";
2003
- }
2004
- async function pr_get_number(branch_name) {
2005
- return await resolve_pr_number(branch_name);
2006
- }
2007
- async function pr_get_url(branch_name) {
2008
- const pull = await read_pull_or_undefined(branch_name);
2009
- if (pull?.html_url === void 0) return void 0;
2010
- return git_gh_helpers.parse_pr_state_string(pull.html_url);
2011
- }
2012
- async function pr_get_merge_state(branch_name) {
2013
- const read = await read_pull_of_branch(branch_name, read_pull);
2014
- if (read.kind !== "read") return void 0;
2015
- const { pull } = read;
2016
- return {
2017
- is_merged: git_gh_pr_rest.is_merged(pull),
2018
- merged_at: pull.merged_at ?? void 0,
2019
- head_sha: pull.head?.sha,
2020
- merge_state_status: to_gh_state(pull.mergeable_state)
2021
- };
2022
- }
2023
- async function pr_get_body(branch_name) {
2024
- const pull = await read_pull_or_undefined(branch_name);
2025
- const body = pull?.body;
2026
- return typeof body === "string" && body.length > 0 ? body : void 0;
2027
- }
2028
- async function pr_view(branch_name) {
2029
- const read = await read_pull_of_branch(branch_name, read_pull);
2030
- if (read.kind === "unreadable") throw to_unreadable_error(branch_name, read.cause);
2031
- if (read.kind === "missing") return "";
2032
- return JSON.stringify(git_gh_pr_rest.to_pr_info(read.pull));
2033
- }
2034
- async function read_comments(branch_name, to_path, to_json) {
2035
- const pr_number = await resolve_pr_number(branch_name);
2036
- if (pr_number === void 0) return void 0;
2037
- const path5 = `${to_path(String(pr_number))}${COMMENTS_QUERY}`;
2038
- try {
2039
- return to_json(await git_gh_exec.exec_gh_api({ path: path5, should_paginate: true }));
2040
- } catch {
2041
- return void 0;
2042
- }
2043
- }
2044
- function to_comments_json(raw) {
2045
- return JSON.stringify(git_gh_pr_rest.to_pr_comments(raw));
2046
- }
2047
- function as_served(raw) {
2048
- return raw;
2049
- }
2050
- async function pr_get_comments(branch_name) {
2051
- return await read_comments(branch_name, git_gh_api_path.issue_comments_api_path, to_comments_json);
2052
- }
2053
- async function pr_get_review_comments(branch_name) {
2054
- return await read_comments(branch_name, git_gh_api_path.pull_comments_api_path, as_served);
2055
- }
2056
- var git_gh_pr_read = {
2057
- pr_exists,
2058
- pr_get_number,
2059
- pr_get_url,
2060
- pr_get_body,
2061
- pr_get_merge_state,
2062
- pr_view,
2063
- pr_get_comments,
2064
- pr_get_review_comments
2065
- };
2066
-
2067
- // scripts/observations/observation-ledger.ts
2068
- var OBSERVATION_LEDGER_DIRECTORY = ".josh/observations";
2069
- var LEGACY_OBSERVATION_LEDGER_DIRECTORY = "docs/maintainers/observations";
2070
- var LEDGER_DIRECTORIES = [
2071
- OBSERVATION_LEDGER_DIRECTORY,
2072
- LEGACY_OBSERVATION_LEDGER_DIRECTORY
2073
- ];
2074
- var LEDGER_FILE_EXTENSION = ".md";
2075
- var LEGACY_LEDGER_FILE = `legacy${LEDGER_FILE_EXTENSION}`;
2076
- var LEGACY_OBSERVATION_LEDGER_PATHS = [
2077
- "docs/maintainers/observations.md",
2078
- "docs/observations.md"
2079
- ];
2080
- var STATUS_PATH_INDEX = 3;
2081
- function status_path(line) {
2082
- return line.slice(STATUS_PATH_INDEX).trim();
2083
- }
2084
- function ledger_file(name) {
2085
- return `${OBSERVATION_LEDGER_DIRECTORY}/${String(name)}${LEDGER_FILE_EXTENSION}`;
2086
- }
2087
- function is_ledger_file_name(name) {
2088
- return name.endsWith(LEDGER_FILE_EXTENSION);
2089
- }
2090
- var MIGRATION_CLAIM_SUFFIX = ".migrating";
2091
- function is_legacy_directory_file(file_path) {
2092
- return file_path.startsWith(`${LEGACY_OBSERVATION_LEDGER_DIRECTORY}/`);
2093
- }
2094
- function is_migration_claim(file_path) {
2095
- if (!file_path.endsWith(MIGRATION_CLAIM_SUFFIX)) return false;
2096
- return is_legacy_directory_file(file_path) || LEGACY_OBSERVATION_LEDGER_PATHS.some((legacy) => file_path.startsWith(`${legacy}.`));
2097
- }
2098
- function is_in_directory(file_path) {
2099
- return LEDGER_DIRECTORIES.some((directory) => file_path.startsWith(`${directory}/`));
2100
- }
2101
- function is_ledger_path(file_path) {
2102
- return is_in_directory(file_path) || LEGACY_OBSERVATION_LEDGER_PATHS.includes(file_path) || is_migration_claim(file_path);
2103
- }
2104
- var LEDGER_EXCLUSION_PATHSPEC = [
2105
- ":/",
2106
- ...LEDGER_DIRECTORIES.map((directory) => `:(top,exclude)${directory}`),
2107
- ...LEGACY_OBSERVATION_LEDGER_PATHS.map((legacy) => `:(top,exclude)${legacy}`),
2108
- ...LEGACY_OBSERVATION_LEDGER_PATHS.map(
2109
- (legacy) => `:(top,exclude,glob)${legacy}.*${MIGRATION_CLAIM_SUFFIX}`
2110
- )
2111
- ];
2112
- function is_ledger_line(line) {
2113
- return is_ledger_path(status_path(line));
2114
- }
2115
- function ledger_paths(status_output) {
2116
- return status_output.split("\n").filter((line) => is_ledger_line(line)).map((line) => status_path(line));
2117
- }
2118
- function has_pending_append(status_output) {
2119
- return status_output.split("\n").some((line) => is_ledger_line(line));
2120
- }
2121
- var observation_ledger = {
2122
- has_pending_append,
2123
- is_ledger_file_name,
2124
- is_ledger_line,
2125
- is_ledger_path,
2126
- is_migration_claim,
2127
- ledger_file,
2128
- ledger_paths,
2129
- status_path
2130
- };
2131
-
2132
- // scripts/git/stash/git-stash.ts
2133
- var ENTRY_SEPARATOR = "\n";
2134
- var FIELD_SEPARATOR2 = "\0";
2135
- var LIST_FORMAT = "--format=%gd%x00%gs";
2136
- var SUBJECT_MESSAGE_SEPARATOR = ": ";
2137
- var HASH_FORMAT = "--format=%H%x00%gs";
2138
- var HASH_POSITION_FORMAT = "--format=%H%x00%gd";
2139
- var NAME_ONLY_FLAG = "--name-only";
2140
- var ADDED_PREFIX2 = "+";
2141
- var FILE_HEADER_PREFIX = "+++";
2142
- function to_entry(line) {
2143
- const [selector, subject] = line.split(FIELD_SEPARATOR2);
2144
- if (selector === void 0 || subject === void 0) return void 0;
2145
- return { selector, subject };
2146
- }
2147
- function parse_entries(raw) {
2148
- if (raw === "") return [];
2149
- return raw.split(ENTRY_SEPARATOR).map((line) => to_entry(line)).filter((entry) => entry !== void 0);
2150
- }
2151
- function matches(subject, message) {
2152
- return subject === message || subject.endsWith(`${SUBJECT_MESSAGE_SEPARATOR}${message}`);
2153
- }
2154
- function select(entries, message) {
2155
- const found = entries.filter((entry) => matches(entry.subject, message));
2156
- const [first] = found;
2157
- if (first === void 0) return { kind: "none" };
2158
- if (found.length > 1) {
2159
- return { kind: "ambiguous", selectors: found.map((entry) => entry.selector) };
2160
- }
2161
- return { kind: "match", selector: first.selector };
2162
- }
2163
- function git_args(directory, args) {
2164
- return directory === void 0 ? args : ["-C", directory, ...args];
2165
- }
2166
- async function list(directory) {
2167
- return parse_entries(await git_spawn.read(git_args(directory, ["stash", "list", LIST_FORMAT])));
2168
- }
2169
- async function pop(selector, directory) {
2170
- await git_spawn.read(git_args(directory, ["stash", "pop", selector]));
2171
- }
2172
- async function has_conflict(directory) {
2173
- const unmerged = await git_spawn.read(
2174
- git_args(directory, ["diff", NAME_ONLY_FLAG, "--diff-filter=U"])
2175
- );
2176
- return unmerged !== "";
2177
- }
2178
- async function has_changes(directory, pathspec = []) {
2179
- const status = await git_spawn.read(git_args(directory, ["status", "--porcelain", ...pathspec]));
2180
- return status !== "";
2181
- }
2182
- var STASHABLE_PATHSPEC = ["--", ...LEDGER_EXCLUSION_PATHSPEC];
2183
- async function has_stashable_changes(directory) {
2184
- return await has_changes(directory, STASHABLE_PATHSPEC);
2185
- }
2186
- async function push(message, directory, pathspec = []) {
2187
- await git_spawn.read(git_args(directory, ["stash", "push", "-u", "-m", message, ...pathspec]));
2188
- }
2189
- async function list_by_hash(directory) {
2190
- return parse_entries(await git_spawn.read(git_args(directory, ["stash", "list", HASH_FORMAT])));
2191
- }
2192
- async function changed_paths2(hash, directory) {
2193
- const raw = await git_spawn.read(
2194
- git_args(directory, ["stash", "show", "--include-untracked", NAME_ONLY_FLAG, hash])
2195
- );
2196
- return raw === "" ? [] : raw.split(ENTRY_SEPARATOR);
2197
- }
2198
- async function untracked_lines(hash, file, directory) {
2199
- try {
2200
- const raw = await git_spawn.read(git_args(directory, ["show", `${hash}^3:${file}`]));
2201
- return raw === "" ? [] : raw.split(ENTRY_SEPARATOR);
2202
- } catch {
2203
- return [];
2204
- }
2205
- }
2206
- async function added_lines(hash, file, directory) {
2207
- const diff = await git_spawn.read(git_args(directory, ["diff", `${hash}^1`, hash, "--", file]));
2208
- if (diff === "") return await untracked_lines(hash, file, directory);
2209
- return diff.split(ENTRY_SEPARATOR).filter((line) => line.startsWith(ADDED_PREFIX2) && !line.startsWith(FILE_HEADER_PREFIX)).map((line) => line.slice(ADDED_PREFIX2.length));
2210
- }
2211
- async function drop_by_hash(hash, directory) {
2212
- const raw = await git_spawn.read(git_args(directory, ["stash", "list", HASH_POSITION_FORMAT]));
2213
- const entry = parse_entries(raw).find((candidate) => candidate.selector === hash);
2214
- if (entry === void 0) return false;
2215
- await git_spawn.read(git_args(directory, ["stash", "drop", entry.subject]));
2216
- return true;
2217
- }
2218
- function work_message(issue, occasion) {
2219
- return `${issue}: uncommitted work at ${occasion}`;
2220
- }
2221
- var git_stash = {
2222
- added_lines,
2223
- changed_paths: changed_paths2,
2224
- drop_by_hash,
2225
- has_changes,
2226
- has_conflict,
2227
- has_stashable_changes,
2228
- list,
2229
- list_by_hash,
2230
- matches,
2231
- parse_entries,
2232
- pop,
2233
- push,
2234
- select,
2235
- STASHABLE_PATHSPEC,
2236
- work_message
2237
- };
2238
-
2239
- // scripts/lane/lane-registry.ts
2240
- import { existsSync, statSync } from "node:fs";
2241
- import path from "node:path";
2242
-
2243
- // scripts/lane/lane-environment.ts
2244
- var LANE_OUTPUT_KEY = "JOSH_LANE_OUTPUT";
2245
- var LANE_PROVIDER_KEY = "JOSH_LANE_AGENT_PROVIDER";
2246
- var LANE_ROLE_KEY = "JOSH_LANE_AGENT_ROLE";
2247
- var LANE_MODEL_KEY = "JOSH_LANE_AGENT_MODEL";
2248
- var LANE_EFFORT_KEY = "JOSH_LANE_AGENT_EFFORT";
2249
- var ASSIGNMENT_SEPARATOR = "=";
2250
- var EXPORT_PREFIX = "export ";
2251
- var QUOTE_CHARACTERS = /* @__PURE__ */ new Set(['"', "'"]);
2252
- var MIN_QUOTED_LENGTH = 2;
2253
- var FIRST_CHARACTER_END = 1;
2254
- var LAST_CHARACTER_START = -1;
2255
- function strip_export(line) {
2256
- const trimmed2 = line.trimStart();
2257
- return trimmed2.startsWith(EXPORT_PREFIX) ? trimmed2.slice(EXPORT_PREFIX.length).trimStart() : trimmed2;
2258
- }
2259
- function is_key_line(line, key) {
2260
- const body = strip_export(line);
2261
- if (!body.startsWith(key)) return false;
2262
- return body.slice(key.length).trimStart().startsWith(ASSIGNMENT_SEPARATOR);
2263
- }
2264
- function is_seat_line(line) {
2265
- return is_key_line(line, LANE_SEAT_KEY);
2266
- }
2267
- function is_output_line(line) {
2268
- return is_key_line(line, LANE_OUTPUT_KEY);
2269
- }
2270
- function split_lines(content) {
2271
- const trimmed2 = content.trimEnd();
2272
- return trimmed2.length === 0 ? [] : trimmed2.split("\n");
2273
- }
2274
- function is_quoted(raw) {
2275
- const first = raw.slice(0, FIRST_CHARACTER_END);
2276
- if (!QUOTE_CHARACTERS.has(first)) return false;
2277
- return raw.length >= MIN_QUOTED_LENGTH && raw.endsWith(first);
2278
- }
2279
- function unquote(raw) {
2280
- return is_quoted(raw) ? raw.slice(FIRST_CHARACTER_END, LAST_CHARACTER_START) : raw;
2281
- }
2282
- function assignment_value(line) {
2283
- return unquote(line.slice(line.indexOf(ASSIGNMENT_SEPARATOR) + FIRST_CHARACTER_END).trim());
2284
- }
2285
- function read_assignment(content, key) {
2286
- const line = split_lines(content).findLast((entry) => is_key_line(entry, key));
2287
- return line === void 0 ? void 0 : assignment_value(line);
2288
- }
2289
- function read_root_seed(content) {
2290
- return ports.resolve_seed({ [PORT_SEED_KEY]: read_assignment(content, PORT_SEED_KEY) });
2291
- }
2292
- function read_lane_seat(content) {
2293
- const raw = read_assignment(content, LANE_SEAT_KEY);
2294
- return raw === void 0 ? void 0 : ports.resolve_lane({ [LANE_SEAT_KEY]: raw });
2295
- }
2296
- function read_lane_ports(content) {
2297
- const environment3 = {
2298
- [PORT_SEED_KEY]: read_assignment(content, PORT_SEED_KEY),
2299
- [LANE_SEAT_KEY]: read_assignment(content, LANE_SEAT_KEY)
2300
- };
2301
- return {
2302
- development: ports.resolve_development_port(environment3),
2303
- preview: ports.resolve_preview_port(environment3)
2304
- };
2305
- }
2306
- function read_lane_output(content) {
2307
- const line = split_lines(content).findLast((entry) => is_output_line(entry));
2308
- const raw = line === void 0 ? void 0 : assignment_value(line);
2309
- return raw === void 0 || raw.length === 0 ? void 0 : raw;
2310
- }
2311
- function read_lane_profile(content) {
2312
- return agent_role_profile.parse({
2313
- provider: read_assignment(content, LANE_PROVIDER_KEY),
2314
- role: read_assignment(content, LANE_ROLE_KEY),
2315
- model: read_assignment(content, LANE_MODEL_KEY),
2316
- effort: read_assignment(content, LANE_EFFORT_KEY)
2317
- });
2318
- }
2319
- function replace_assignment(lines, keep, assignment, key) {
2320
- return lines.flatMap((entry, index) => {
2321
- if (index === keep) return [assignment];
2322
- if (is_key_line(entry, key)) return [];
2323
- return [entry];
2324
- });
2325
- }
2326
- function upsert_assignment(content, key, value) {
2327
- const assignment = `${key}${ASSIGNMENT_SEPARATOR}${value}`;
2328
- const lines = split_lines(content);
2329
- const last = lines.findLastIndex((entry) => is_key_line(entry, key));
2330
- const body = last === -1 ? [...lines, assignment] : replace_assignment(lines, last, assignment, key);
2331
- return `${body.join("\n")}
2332
- `;
2333
- }
2334
- function lane_file_content(root_content, seat) {
2335
- return upsert_assignment(root_content, LANE_SEAT_KEY, String(seat));
2336
- }
2337
- function with_lane_output(content, output, profile) {
2338
- const recorded = upsert_assignment(content, LANE_OUTPUT_KEY, `"${output}"`);
2339
- if (profile === void 0) return recorded;
2340
- const with_provider = upsert_assignment(recorded, LANE_PROVIDER_KEY, profile.provider);
2341
- const with_role = upsert_assignment(with_provider, LANE_ROLE_KEY, profile.role);
2342
- const with_model = upsert_assignment(with_role, LANE_MODEL_KEY, profile.model);
2343
- return upsert_assignment(with_model, LANE_EFFORT_KEY, profile.effort);
2344
- }
2345
- var lane_environment = {
2346
- is_seat_line,
2347
- lane_file_content,
2348
- read_lane_output,
2349
- read_lane_profile,
2350
- read_lane_ports,
2351
- read_lane_seat,
2352
- read_root_seed,
2353
- with_lane_output
2354
- };
2355
-
2356
- // scripts/lane/lane-registry.ts
2357
- var WORKTREE_PREFIX = "worktree ";
2358
- var BRANCH_PREFIX = "branch refs/heads/";
2359
- var BLOCK_SEPARATOR = "\n\n";
2360
- function line_value(lines, prefix) {
2361
- return lines.find((line) => line.startsWith(prefix))?.slice(prefix.length);
2362
- }
2363
- function seat_from_content(content) {
2364
- const seat = lane_environment.read_lane_seat(content);
2365
- if (seat === void 0) return void 0;
2366
- const port_pair = lane_environment.read_lane_ports(content);
2367
- return { seat, development_port: port_pair.development, preview_port: port_pair.preview };
2368
- }
2369
- var EMPTY_SEAT = {
2370
- seat: void 0,
2371
- development_port: void 0,
2372
- preview_port: void 0
2373
- };
2374
- function held_seat(content) {
2375
- if (content === void 0) return EMPTY_SEAT;
2376
- return seat_from_content(content) ?? EMPTY_SEAT;
2377
- }
2378
- function read_environment(directory) {
2379
- return file_reader.read_if_readable(path.join(directory, ENV_FILE_NAME));
2380
- }
2381
- function dispatched_at(directory) {
2382
- return statSync(path.join(directory, ENV_FILE_NAME), { throwIfNoEntry: false })?.mtimeMs;
2383
- }
2384
- function branch_issue(branch) {
2385
- if (!branch?.endsWith(lane_paths.LANE_BRANCH_SUFFIX)) return void 0;
2386
- const issue = branch.slice(0, -lane_paths.LANE_BRANCH_SUFFIX.length);
2387
- return issue_number_shape.ISSUE_NUMBER_PATTERN.test(issue) ? issue : void 0;
2388
- }
2389
- function is_gone(directory) {
2390
- return !existsSync(directory);
2391
- }
2392
- function build_lane(issue, branch, directory, is_stranded) {
2393
- const content = is_stranded ? void 0 : read_environment(directory);
2394
- const held = held_seat(content);
2395
- const output = content === void 0 ? void 0 : lane_environment.read_lane_output(content);
2396
- const profile = content === void 0 ? void 0 : lane_environment.read_lane_profile(content);
2397
- return {
2398
- issue,
2399
- branch,
2400
- directory,
2401
- seat: held.seat,
2402
- development_port: held.development_port,
2403
- preview_port: held.preview_port,
2404
- output,
2405
- profile,
2406
- dispatched_ms: is_stranded ? void 0 : dispatched_at(directory),
2407
- is_stranded
2408
- };
2409
- }
2410
- function is_lane_directory(root, issue, directory) {
2411
- return directory === lane_paths.lane_directory(root, issue);
2412
- }
2413
- function parse_block(block, root) {
2414
- const lines = block.split("\n");
2415
- const directory = line_value(lines, WORKTREE_PREFIX);
2416
- const branch = line_value(lines, BRANCH_PREFIX);
2417
- const issue = branch_issue(branch);
2418
- if (directory === void 0 || branch === void 0 || issue === void 0 || !is_lane_directory(root, issue, directory)) {
2419
- return void 0;
2420
- }
2421
- return build_lane(issue, branch, directory, is_gone(directory));
2422
- }
2423
- function is_lane(lane) {
2424
- return lane !== void 0;
2425
- }
2426
- async function worktree_blocks() {
2427
- const listing = await git_worktree.worktree_list();
2428
- return listing.split(BLOCK_SEPARATOR);
2429
- }
2430
- async function main_repository_root() {
2431
- return repo_discovery.main_worktree(await git_command.repository_root());
2432
- }
2433
- async function lane_root_directory() {
2434
- return lane_paths.lane_root(await main_repository_root());
2435
- }
2436
- async function lane_location(issue) {
2437
- return { issue, directory: lane_paths.lane_directory(await lane_root_directory(), issue) };
2438
- }
2439
- async function list_lanes(main_root) {
2440
- const root = lane_paths.lane_root(main_root ?? await main_repository_root());
2441
- const blocks = await worktree_blocks();
2442
- const lanes = blocks.map((block) => parse_block(block, root)).filter(is_lane);
2443
- return lanes.toSorted((left, right) => Number(left.issue) - Number(right.issue));
2444
- }
2445
- async function registered_directories() {
2446
- const blocks = await worktree_blocks();
2447
- return blocks.flatMap((block) => line_value(block.split("\n"), WORKTREE_PREFIX) ?? []);
2448
- }
2449
- async function has_lanes_in_flight() {
2450
- const lanes = await list_lanes();
2451
- return lanes.some((lane) => !lane.is_stranded);
2452
- }
2453
- function used_seats(lanes) {
2454
- return lanes.map((lane) => lane.seat).filter((seat) => seat !== void 0);
2455
- }
2456
- function unreadable_lanes(lanes) {
2457
- return lanes.filter((lane) => !lane.is_stranded && lane.seat === void 0);
2458
- }
2459
- function find_lane(lanes, issue) {
2460
- return lanes.find((lane) => lane.issue === issue);
2461
- }
2462
- async function find_open_lane(issue) {
2463
- return find_lane(await list_lanes(), issue);
2464
- }
2465
- var lane_registry = {
2466
- find_lane,
2467
- find_open_lane,
2468
- has_lanes_in_flight,
2469
- lane_location,
2470
- lane_root_directory,
2471
- list_lanes,
2472
- main_repository_root,
2473
- parse_block,
2474
- read_environment,
2475
- registered_directories,
2476
- unreadable_lanes,
2477
- used_seats
2478
- };
2479
-
2480
- // scripts/run/run-preflight.ts
2481
- import { z as z9 } from "zod";
2482
- var CLEAN_VERDICT = "clean";
2483
- var RECLAIM_VERDICT = "reclaim";
2484
- var RESUME_VERDICT = "resume";
2485
- var PARK_VERDICT = "park";
2486
- var NO_PR = "none";
2487
- var OPEN_PR = "open";
2488
- var MERGED_PR = "merged";
2489
- var CLOSED_PR = "closed";
2490
- var NO_CHILD_WORK = { branch_name: void 0, pr_state: NO_PR };
2491
- var pr_info_schema = z9.object({ state: z9.string().optional() });
2492
- var GH_PR_STATES = /* @__PURE__ */ new Map([
2493
- ["CLOSED", CLOSED_PR],
2494
- ["MERGED", MERGED_PR],
2495
- ["OPEN", OPEN_PR]
2496
- ]);
2497
- var CLEAN_REASON = "Nothing was left behind: the tree is clean, HEAD is on the default branch, and this issue has no pull request and no branch holding work.";
2498
- var CLEAN_ADVICE = "Start the child.";
2499
- var RESUME_ADVICE = "Reuse the branch and run the whole verification gate from the start \u2014 refactor, `pnpm josh gate`, `/code-review` \u2014 never only the part the interrupted run had not reached. Nobody verified what it already committed.";
2500
- var PARK_ADVICE = "Park the child: add `needs-decision` and comment what was found. Do not delete the branch, do not reopen the pull request, and do not commit on top of it.";
2501
- var STASH_LABEL_PREFIX = "run:hold reclaimed before #";
2502
- var { require_issue_number } = issue_number_shape;
2503
- var UNREADABLE_PR_MESSAGE = "The pull request could not be read for branch ";
2504
- function needs_reclaim(tree) {
2505
- return tree.is_dirty || tree.branch !== tree.default_branch;
2506
- }
2507
- function is_pr_decided(state) {
2508
- return state === MERGED_PR || state === CLOSED_PR;
2509
- }
2510
- function has_leftover_work(child) {
2511
- return child.branch_name !== void 0 || child.pr_state === OPEN_PR;
2512
- }
2513
- function to_verdict(tree, child) {
2514
- if (needs_reclaim(tree)) return RECLAIM_VERDICT;
2515
- if (is_pr_decided(child.pr_state)) return PARK_VERDICT;
2516
- if (has_leftover_work(child)) return RESUME_VERDICT;
2517
- return CLEAN_VERDICT;
2518
- }
2519
- function reclaim_reason(tree) {
2520
- const findings = [
2521
- tree.is_dirty ? "uncommitted changes" : void 0,
2522
- tree.branch === tree.default_branch ? void 0 : `HEAD on ${tree.branch}`
2523
- ].filter((entry) => entry !== void 0);
2524
- return `An earlier run left ${findings.join(" and ")} in this working tree.`;
2525
- }
2526
- function park_reason(state) {
2527
- return `The pull request for this issue is ${state}, so whether any work is still owed is a person's call.`;
2528
- }
2529
- function resume_reason(child) {
2530
- const branch_part = child.branch_name === void 0 ? "" : ` on branch ${child.branch_name}`;
2531
- const pr_part = child.pr_state === OPEN_PR ? ", and its pull request is still open" : "";
2532
- return `An earlier run left a partial implementation${branch_part}${pr_part}.`;
2533
- }
2534
- function to_reason(verdict, tree, child) {
2535
- if (verdict === RECLAIM_VERDICT) return reclaim_reason(tree);
2536
- if (verdict === PARK_VERDICT) return park_reason(child.pr_state);
2537
- if (verdict === RESUME_VERDICT) return resume_reason(child);
2538
- return CLEAN_REASON;
2539
- }
2540
- function reclaim_steps(tree, issue) {
2541
- if (!tree.is_dirty) return [];
2542
- return [
2543
- `pnpm josh stash:push "${STASH_LABEL_PREFIX}${issue}"`,
2544
- `Record the stash on ${session_cite.issue(issue)} \u2014 the comment is what gets it popped; nothing pops it for you.`
2545
- ];
2546
- }
2547
- function reclaim_advice(tree, issue) {
2548
- return [
2549
- ...reclaim_steps(tree, issue),
2550
- "pnpm josh ms",
2551
- "Then ask this command again: it is re-askable, and the clean tree gets its own answer."
2552
- ].join("\n");
2553
- }
2554
- function to_advice(verdict, issue, tree) {
2555
- if (verdict === RECLAIM_VERDICT) return reclaim_advice(tree, issue);
2556
- if (verdict === RESUME_VERDICT) return RESUME_ADVICE;
2557
- if (verdict === PARK_VERDICT) return PARK_ADVICE;
2558
- return CLEAN_ADVICE;
2559
- }
2560
- function decide(tree, child, issue) {
2561
- const verdict = to_verdict(tree, child);
2562
- return {
2563
- advice: to_advice(verdict, issue, tree),
2564
- reason: to_reason(verdict, tree, child),
2565
- verdict
2566
- };
2567
- }
2568
- function read_pr_field(raw) {
2569
- return json_value.parse_with(raw, pr_info_schema)?.state;
2570
- }
2571
- function to_pr_state2(raw) {
2572
- const state = read_pr_field(raw);
2573
- return (state === void 0 ? void 0 : GH_PR_STATES.get(state)) ?? NO_PR;
2574
- }
2575
- async function has_stashable_work() {
2576
- try {
2577
- return await git_stash.has_stashable_changes();
2578
- } catch (error) {
2579
- error_text.trace_swallowed("run_preflight.has_stashable_work", error);
2580
- return true;
2581
- }
2582
- }
2583
- async function read_tree_state() {
2584
- const [is_dirty, current, default_branch] = await Promise.all([
2585
- has_stashable_work(),
2586
- git_command.branch(),
2587
- git_command.get_default_branch()
2588
- ]);
2589
- return { branch: current, default_branch, is_dirty };
2590
- }
2591
- async function read_pr_state(branch_name) {
2592
- if (!await git_gh_pr_read.pr_exists(branch_name)) return NO_PR;
2593
- const raw = await git_gh_pr_read.pr_view(branch_name);
2594
- if (raw === "") throw new Error(`${UNREADABLE_PR_MESSAGE}${branch_name}`);
2595
- return to_pr_state2(raw);
2596
- }
2597
- function is_pr_open(state) {
2598
- return state === OPEN_PR;
2599
- }
2600
- async function read_pr_of_branch(branch_name) {
2601
- return { branch_name, pr_state: await read_pr_state(branch_name) };
2602
- }
2603
- function pick_child_state(reads) {
2604
- const decided = reads.find((read) => is_pr_decided(read.pr_state));
2605
- const open = reads.find((read) => is_pr_open(read.pr_state));
2606
- return decided ?? open ?? { branch_name: reads[0]?.branch_name, pr_state: NO_PR };
2607
- }
2608
- var ISSUE_BRANCH_SUFFIX = "-*";
2609
- var ANY_REMOTE_PREFIX = "*/";
2610
- var REMOTE_SEPARATOR = "/";
2611
- var NOT_FOUND_INDEX = -1;
2612
- function to_head_branch(name) {
2613
- const separator_index = name.indexOf(REMOTE_SEPARATOR);
2614
- return separator_index === NOT_FOUND_INDEX ? name : name.slice(separator_index + 1);
2615
- }
2616
- function group_by_head(pairs) {
2617
- const groups = /* @__PURE__ */ new Map();
2618
- for (const [name, reference] of pairs) groups.set(name, [...groups.get(name) ?? [], reference]);
2619
- return groups;
2620
- }
2621
- async function read_branch_candidates(issue) {
2622
- const pattern = `${issue}${ISSUE_BRANCH_SUFFIX}`;
2623
- const [local, remote] = await Promise.all([
2624
- git_command.branch_names(pattern),
2625
- git_command.branch_names_remote(`${ANY_REMOTE_PREFIX}${pattern}`)
2626
- ]);
2627
- return group_by_head([
2628
- ...local.map((name) => [name, name]),
2629
- ...remote.map((reference) => [to_head_branch(reference), reference])
2630
- ]);
2631
- }
2632
- async function has_commits_beyond(base, references) {
2633
- const counts = await Promise.all(
2634
- references.map(async (reference) => await git_command.commit_count_beyond(base, reference))
2635
- );
2636
- return counts.some((count) => count > 0);
2637
- }
2638
- async function is_held_dirty(name, lane) {
2639
- if (lane?.branch !== name || lane.is_stranded) return false;
2640
- return await run_hold.is_tree_dirty(lane.directory);
2641
- }
2642
- async function read_candidate(name, references, context) {
2643
- const state = await read_pr_of_branch(name);
2644
- if (state.pr_state !== NO_PR || await has_commits_beyond(context.base, references)) return state;
2645
- return await is_held_dirty(name, context.lane) ? state : void 0;
2646
- }
2647
- async function read_child_state(issue) {
2648
- const candidates = await read_branch_candidates(issue);
2649
- if (candidates.size === 0) return NO_CHILD_WORK;
2650
- const [base, lane] = await Promise.all([
2651
- git_command.default_branch_reference(),
2652
- lane_registry.find_open_lane(issue)
2653
- ]);
2654
- const reads = await Promise.all(
2655
- [...candidates].map(
2656
- async ([name, references]) => await read_candidate(name, references, { base, lane })
2657
- )
2658
- );
2659
- return pick_child_state(reads.filter((read) => read !== void 0));
2660
- }
2661
- async function check2(issue) {
2662
- require_issue_number(issue);
2663
- const tree = await read_tree_state();
2664
- if (needs_reclaim(tree)) return decide(tree, NO_CHILD_WORK, issue);
2665
- return decide(tree, await read_child_state(issue), issue);
2666
- }
2667
- var run_preflight = {
2668
- CLEAN_VERDICT,
2669
- RESUME_ADVICE,
2670
- MERGED_PR,
2671
- STASH_LABEL_PREFIX,
2672
- check: check2,
2673
- decide,
2674
- read_child_state,
2675
- read_pr_state,
2676
- to_pr_state: to_pr_state2
2677
- };
2678
-
2679
- // scripts/run/ship/run-ship-probe.ts
2680
- var REPOSITORY_DIRECTORY_INDEX = 1;
2681
- var REMOTE_SHA_INDEX = 0;
2682
- var REMOTE_FIELD_SEPARATOR = /\s/u;
2683
- var HEAD_REFERENCE = "HEAD";
2684
- async function or_false(is_true) {
2685
- try {
2686
- return await is_true();
2687
- } catch (error) {
2688
- error_text.trace_swallowed("run_ship_probe.or_false", error);
2689
- return false;
2690
- }
2691
- }
2692
- async function read_committed() {
2693
- if (await run_hold.is_tree_dirty()) return false;
2694
- const base = await git_command.default_branch_reference();
2695
- return await git_command.commit_count_beyond(base, HEAD_REFERENCE) > 0;
2696
- }
2697
- async function read_pushed(branch_name) {
2698
- const [remote, head] = await Promise.all([
2699
- git_worktree.ls_remote_branch(branch_name),
2700
- git_command.head_commit()
2701
- ]);
2702
- return remote.split(REMOTE_FIELD_SEPARATOR)[REMOTE_SHA_INDEX] === head;
2703
- }
2704
- async function read_merged(branch_name) {
2705
- if (await run_preflight.read_pr_state(branch_name) !== run_preflight.MERGED_PR) return false;
2706
- const base = await git_command.default_branch_reference();
2707
- return await git_command.commit_count_beyond(base, HEAD_REFERENCE) === 0;
2708
- }
2709
- async function read_review_stale() {
2710
- return await or_false(async () => await issue_watch_gate.review_refusal_here() !== void 0);
2711
- }
2712
- var NOTHING_DONE = { is_committed: false, is_pushed: false, is_merged: false };
2713
- async function read_branch_state(branch_name) {
2714
- const [is_committed, is_pushed, is_merged2, is_review_stale] = await Promise.all([
2715
- or_false(read_committed),
2716
- or_false(async () => await read_pushed(branch_name)),
2717
- or_false(async () => await read_merged(branch_name)),
2718
- read_review_stale()
2719
- ]);
2720
- return { is_committed, is_pushed, is_merged: is_merged2, is_review_stale };
2721
- }
2722
- async function read_state() {
2723
- try {
2724
- return await read_branch_state(await git_command.branch());
2725
- } catch {
2726
- return NOTHING_DONE;
2727
- }
2728
- }
2729
- async function repository_directory() {
2730
- try {
2731
- const directories = await git_command.git_directories();
2732
- return directories[REPOSITORY_DIRECTORY_INDEX];
2733
- } catch {
2734
- return void 0;
2735
- }
2736
- }
2737
- async function record_target2(issue) {
2738
- const repository = await repository_directory();
2739
- return repository === void 0 ? void 0 : run_ship_stage.record_path(repository, issue);
2740
- }
2741
- var run_ship_probe = { read_review_stale, read_state, record_target: record_target2, repository_directory };
2742
-
2743
- // scripts/run/ship/run-ship-stop-context.ts
2744
- var EXCERPT_LINE_LIMIT = 40;
2745
- var EXCERPT_LINE_WIDTH = 240;
2746
- var CHANGED_PATH_LIMIT = 30;
2747
- var OUTPUT_PREFIX = "josh-ship-stop-";
2748
- var OUTPUT_SUFFIX = ".log";
2749
- var KEY_SEPARATOR = "-";
2750
- var LINE_BREAK = "\n";
2751
- var CARRIAGE_RETURN = "\r";
2752
- var omitted_schema = z10.object({ path: z10.string().optional(), last_line: z10.number().int() }).strict();
2753
- var stop_context_schema = z10.object({
2754
- excerpt: z10.array(z10.string()).readonly(),
2755
- omitted: omitted_schema.optional(),
2756
- changed: z10.array(z10.string()).readonly().optional(),
2757
- more_changed: z10.number().int()
2758
- }).strict();
2759
- function shown_frame(line) {
2760
- return line.trimEnd().split(CARRIAGE_RETURN).at(-1) ?? "";
2761
- }
2762
- function output_lines(output) {
2763
- return stripVTControlCharacters(output).trimEnd().split(LINE_BREAK).map((line) => agent_role_profile.printable(shown_frame(line)));
2764
- }
2765
- async function keep_full_output(issue, output) {
2766
- const repository = await run_ship_probe.repository_directory();
2767
- if (repository === void 0) return void 0;
2768
- const target = stamp_file.stamp_path(
2769
- `${OUTPUT_PREFIX}${issue}${KEY_SEPARATOR}`,
2770
- repository,
2771
- OUTPUT_SUFFIX
2772
- );
2773
- try {
2774
- return stamp_file.replace_text_stamp(target, output);
2775
- } catch {
2776
- return void 0;
2777
- }
2778
- }
2779
- async function omitted_range(issue, lines) {
2780
- const path5 = await keep_full_output(issue, lines.join(LINE_BREAK));
2781
- const last_line = lines.length - EXCERPT_LINE_LIMIT;
2782
- return path5 === void 0 ? { last_line } : { path: path5, last_line };
2783
- }
2784
- function clipped(lines) {
2785
- return lines.map((line) => line.slice(0, EXCERPT_LINE_WIDTH));
2786
- }
2787
- async function excerpt_of(issue, output) {
2788
- const lines = output.trim() === "" ? [] : output_lines(output);
2789
- if (lines.length <= EXCERPT_LINE_LIMIT) return { excerpt: clipped(lines) };
2790
- return {
2791
- excerpt: clipped(lines.slice(-EXCERPT_LINE_LIMIT)),
2792
- omitted: await omitted_range(issue, lines)
2793
- };
2794
- }
2795
- async function read_paths() {
2796
- try {
2797
- return await changed_paths.read_changed_paths(false);
2798
- } catch {
2799
- return void 0;
2800
- }
2801
- }
2802
- async function changed_of() {
2803
- const paths = await read_paths();
2804
- if (paths === void 0) return { more_changed: 0 };
2805
- return {
2806
- changed: paths.slice(0, CHANGED_PATH_LIMIT),
2807
- more_changed: Math.max(0, paths.length - CHANGED_PATH_LIMIT)
2808
- };
2809
- }
2810
- async function build(issue, output) {
2811
- return { ...await excerpt_of(issue, output), ...await changed_of() };
2812
- }
2813
- function has_excerpt(context) {
2814
- return context !== void 0 && context.excerpt.length > 0;
2815
- }
2816
- function excerpt_heading(issue, omitted, shown) {
2817
- if (omitted === void 0) return "The failed stage output:";
2818
- const source = omitted.path ?? `the stopped report (\`${run_ship_next.COMMAND.LOG} ${issue}\`)`;
2819
- const range = `lines 1-${String(omitted.last_line)} are in ${source}`;
2820
- return `The failed stage output (its last ${String(shown)} lines; ${range}):`;
2821
- }
2822
- function with_dropped(omitted, dropped) {
2823
- if (dropped === 0) return omitted;
2824
- return { ...omitted, last_line: (omitted?.last_line ?? 0) + dropped };
2825
- }
2826
- function excerpt_block(issue, context, changed, dropped) {
2827
- const shown = context.excerpt.slice(dropped);
2828
- const heading = excerpt_heading(issue, with_dropped(context.omitted, dropped), shown.length);
2829
- return [heading, ...shown, changed].join(LINE_BREAK);
2830
- }
2831
- function changed_text(context) {
2832
- if (context.changed === void 0) return "The changed files could not be read from git.";
2833
- if (context.changed.length === 0) return "No files changed against the default branch.";
2834
- const more = context.more_changed > 0 ? ` (and ${String(context.more_changed)} more)` : "";
2835
- return `Changed files on the branch: ${context.changed.join(", ")}${more}.`;
2836
- }
2837
- function describe2(issue, context, budget = agent_role_profile.MAX_VALUE_LENGTH) {
2838
- const changed = changed_text(context);
2839
- if (!has_excerpt(context)) return changed;
2840
- let dropped = 0;
2841
- let block = excerpt_block(issue, context, changed, dropped);
2842
- while (block.length > budget && dropped < context.excerpt.length - 1) {
2843
- dropped += 1;
2844
- block = excerpt_block(issue, context, changed, dropped);
2845
- }
2846
- return block;
2847
- }
2848
- var run_ship_stop_context = {
2849
- CHANGED_PATH_LIMIT,
2850
- EXCERPT_LINE_LIMIT,
2851
- build,
2852
- describe: describe2,
2853
- has_excerpt,
2854
- stop_context_schema
2855
- };
2856
-
2857
- // scripts/lane/lane-child-invocation.ts
2858
- var CHILD_INVOCATION = "fullrun";
2859
- var LINE_BREAK2 = "\n";
2860
- var REVIEW_INVOCATION = "the reviewer of lane";
2861
- var RESUME_GUIDE = ".claude/skills/workflow-commands/pre-gate-cut.md";
2862
- var SHIP_PROCESS = String.raw`(josh(\.[jt]s)? ship|run-ship-cli\.ts)`;
2863
- function child_invocation(issue) {
2864
- issue_number_shape.require_issue_number(issue);
2865
- return `${CHILD_INVOCATION} ${issue_cite.plain(issue)}`;
2866
- }
2867
- function process_pattern(issue) {
2868
- issue_number_shape.require_issue_number(issue);
2869
- return `(${CHILD_INVOCATION}|${REVIEW_INVOCATION}|${SHIP_PROCESS} .*) ${issue_cite.plain(issue)}$`;
2870
- }
2871
- function ship_pattern(issue) {
2872
- issue_number_shape.require_issue_number(issue);
2873
- return `${SHIP_PROCESS} .* ${issue_cite.plain(issue)}$`;
2874
- }
2875
- function review_invocation(issue) {
2876
- issue_number_shape.require_issue_number(issue);
2877
- return `${REVIEW_INVOCATION} ${issue_cite.plain(issue)}`;
2878
- }
2879
- function resume_invocation(issue) {
2880
- const preamble = `Resuming the lane child for issue ${issue_cite.plain(issue)} \u2014 do not re-read the workflow-commands entry documents (SKILL.md, fullrun.md). Run \`pnpm josh run:cut --resume ${issue}\` before anything else and follow the matching verdict in ${RESUME_GUIDE}: \`resume\` goes to the gate, \`resume-impl\` continues implementation. Only on \`fresh\` proceed as an ordinary`;
2881
- return `${preamble} ${child_invocation(issue)}`;
2882
- }
2883
- function outage_resume_invocation(issue) {
2884
- const preamble = `Resuming the lane child for issue ${issue_cite.plain(issue)} after an API disconnection \u2014 your session was restored with its full context, so do not re-read the workflow-commands entry documents (SKILL.md, fullrun.md). Continue the run from where it stopped: run \`pnpm josh run:step ${issue}\` to find the next action, redoing only the last step if it did not complete.`;
2885
- return `${preamble} ${child_invocation(issue)}`;
2886
- }
2887
- function known_stop_lines(issue, stop, frame) {
2888
- const { context } = stop;
2889
- const is_excerpted = run_ship_stop_context.has_excerpt(context);
2890
- const next = run_ship_next.next_step(issue, stop.stage, stop, is_excerpted);
2891
- if (context === void 0) return [next];
2892
- const fixed = [...frame, next].join(LINE_BREAK2).length + LINE_BREAK2.length;
2893
- const budget = agent_role_profile.MAX_VALUE_LENGTH - fixed;
2894
- return [next, run_ship_stop_context.describe(issue, context, budget)];
2895
- }
2896
- function ship_stop_invocation(issue, stop) {
2897
- const opening = `Resuming the lane child for issue ${issue_cite.plain(issue)} after its detached ship supervisor stopped at a failed stage \u2014 do not re-read the workflow-commands entry documents (SKILL.md, fullrun.md).`;
2898
- const closing = `Do not re-plan or re-implement what is already on the branch. ${child_invocation(issue)}`;
2899
- const middle = stop === void 0 ? [
2900
- `Run \`pnpm josh run:step ${issue}\` and read the stopped report it names, fix what stopped the ship, then hand the region back per chain-rule.md.`
2901
- ] : known_stop_lines(issue, stop, [opening, closing]);
2902
- return [opening, ...middle, closing].join(LINE_BREAK2);
2903
- }
2904
- var lane_child_invocation = {
2905
- child_invocation,
2906
- outage_resume_invocation,
2907
- process_pattern,
2908
- resume_invocation,
2909
- review_invocation,
2910
- ship_pattern,
2911
- ship_stop_invocation
2912
- };
2913
-
2914
- // scripts/lane/process-tools.ts
2915
- import path2 from "node:path";
2916
- var NOT_FOUND_CODE = "ENOENT";
2917
- var PACKAGE_HINT = "install the package that provides it (procps on Debian/Ubuntu: `apt-get install procps`)";
2918
- function is_not_found(error) {
2919
- return error instanceof Error && "code" in error && error.code === NOT_FOUND_CODE;
2920
- }
2921
- function missing_notice(command) {
2922
- return `\`${path2.basename(command)}\` is not installed \u2014 kit's lane commands read processes with ps and pgrep; ${PACKAGE_HINT}`;
2923
- }
2924
- function throw_if_missing(command, error) {
2925
- if (is_not_found(error)) throw new Error(missing_notice(command), { cause: error });
2926
- }
2927
- var process_tools = { missing_notice, throw_if_missing };
2928
-
2929
- // scripts/lane/lane-reap.ts
2930
- var PGREP_COMMAND = "pgrep";
2931
- var MATCH_FULL_COMMAND_LINE = "-f";
2932
- var CHILDREN_OF_FLAG = "-P";
2933
- var PS_COMMAND = "/bin/ps";
2934
- var PARENT_FORMAT = ["-o", "ppid=", "-p"];
2935
- var TERMINATE_SIGNAL = "SIGTERM";
2936
- var CONTINUE_SIGNAL = "SIGCONT";
2937
- var LOWEST_CHILD_PID = 2;
2938
- function parse_pids(printed) {
2939
- return printed.split("\n").map((line) => Number(line.trim())).filter((pid) => Number.isSafeInteger(pid) && pid >= LOWEST_CHILD_PID);
2940
- }
2941
- function run_probe(command, args) {
2942
- try {
2943
- return execFileSync(command, [...args], {
2944
- encoding: "utf8",
2945
- timeout: PROBE_TIMEOUT_MS,
2946
- stdio: ["ignore", "pipe", "ignore"]
2947
- });
2948
- } catch (error) {
2949
- process_tools.throw_if_missing(command, error);
2950
- return "";
2951
- }
2952
- }
2953
- function parent_of(pid) {
2954
- return parse_pids(run_probe(PS_COMMAND, [...PARENT_FORMAT, String(pid)]))[0];
2955
- }
2956
- function send(pid, name) {
2957
- try {
2958
- process.kill(pid, name);
2959
- return true;
2960
- } catch {
2961
- return false;
2962
- }
2963
- }
2964
- function terminate(pid) {
2965
- if (!send(pid, TERMINATE_SIGNAL)) return false;
2966
- send(pid, CONTINUE_SIGNAL);
2967
- return true;
2968
- }
2969
- var SYSTEM_PROBES = {
2970
- matching: (pattern) => parse_pids(run_probe(PGREP_COMMAND, [MATCH_FULL_COMMAND_LINE, pattern])),
2971
- children_of: (pid) => parse_pids(run_probe(PGREP_COMMAND, [CHILDREN_OF_FLAG, String(pid)])),
2972
- parent_of,
2973
- terminate
2974
- };
2975
- function ancestry_of(pid, probes) {
2976
- const ancestry = /* @__PURE__ */ new Set([pid]);
2977
- let current = probes.parent_of(pid);
2978
- while (current !== void 0 && !ancestry.has(current)) {
2979
- ancestry.add(current);
2980
- current = probes.parent_of(current);
2981
- }
2982
- return ancestry;
2983
- }
2984
- function own_ancestry(probes = SYSTEM_PROBES) {
2985
- return ancestry_of(process.pid, probes);
2986
- }
2987
- function tree_of(roots, probes) {
2988
- const tree = [];
2989
- const pending = [...roots];
2990
- let next = pending.shift();
2991
- while (next !== void 0) {
2992
- if (!tree.includes(next)) {
2993
- tree.push(next);
2994
- pending.push(...probes.children_of(next));
2995
- }
2996
- next = pending.shift();
2997
- }
2998
- return tree;
2999
- }
3000
- function roots_of(issue, own, probes) {
3001
- const pattern = lane_child_invocation.process_pattern(issue);
3002
- return probes.matching(pattern).filter((pid) => !own.has(pid));
3003
- }
3004
- function lane_tree(issue, probes = SYSTEM_PROBES) {
3005
- const own = own_ancestry(probes);
3006
- return tree_of(roots_of(issue, own, probes), probes).filter((pid) => !own.has(pid));
3007
- }
3008
- function reap_child(lane, probes = SYSTEM_PROBES) {
3009
- return lane_tree(lane.issue, probes).filter((pid) => probes.terminate(pid));
3010
- }
3011
- function is_child_running(issue, probes = SYSTEM_PROBES) {
3012
- return roots_of(issue, own_ancestry(probes), probes).length > 0;
3013
- }
3014
- var lane_reap = {
3015
- is_child_running,
3016
- lane_tree,
3017
- own_ancestry,
3018
- parse_pids,
3019
- PS_COMMAND,
3020
- reap_child,
3021
- run_probe,
3022
- SYSTEM_PROBES
3023
- };
3024
-
3025
- // scripts/run/run-headless.ts
3026
- var HEADLESS_ENV_KEY = "JOSH_RUN_HEADLESS";
3027
- var HEADLESS_VALUE = "1";
3028
- function environment2() {
3029
- return { [HEADLESS_ENV_KEY]: HEADLESS_VALUE };
3030
- }
3031
- function is_headless2(source = process.env) {
3032
- return source[HEADLESS_ENV_KEY] === HEADLESS_VALUE;
3033
- }
3034
- function is_headless_parent(source) {
3035
- return is_headless2(source) && lane_child_marker.marked_issue(source) === void 0;
3036
- }
3037
- function is_cut_capped(carry, source = process.env) {
3038
- return !is_headless_parent(source) && run_carry.is_at_cut_cap(carry);
3039
- }
3040
- function is_driving(read) {
3041
- return read?.kind === "carried" && read.carry.is_handed_off !== true;
3042
- }
3043
- async function read_carry_here() {
3044
- const repository = await run_carry.repository_directory();
3045
- return repository === void 0 ? void 0 : run_carry.read_carry(run_carry.carry_path(repository));
3046
- }
3047
- async function must_keep_waiting(source = process.env) {
3048
- if (!is_headless_parent(source) || !await lane_registry.has_lanes_in_flight()) return false;
3049
- return is_driving(await read_carry_here());
3050
- }
3051
- async function current_carry() {
3052
- const read = await read_carry_here();
3053
- return read?.kind === "carried" ? read.carry : void 0;
3054
- }
3055
- function is_owned_here(carry, ancestry) {
3056
- return carry.owner_pid !== void 0 && ancestry().has(carry.owner_pid);
3057
- }
3058
- function driven_here(read, ancestry) {
3059
- if (read?.kind !== "carried" || !is_driving(read)) return void 0;
3060
- return is_owned_here(read.carry, ancestry) ? read.carry : void 0;
3061
- }
3062
- async function driving_carry(source = process.env, ancestry = lane_reap.own_ancestry) {
3063
- if (lane_child_marker.marked_issue(source) !== void 0) return void 0;
3064
- return driven_here(await read_carry_here(), ancestry);
3065
- }
3066
- async function is_backlog_parent(source = process.env, ancestry = lane_reap.own_ancestry) {
3067
- return await driving_carry(source, ancestry) !== void 0;
3068
- }
3069
- var run_headless = {
3070
- HEADLESS_ENV_KEY,
3071
- current_carry,
3072
- driven_here,
3073
- driving_carry,
3074
- environment: environment2,
3075
- is_backlog_parent,
3076
- is_cut_capped,
3077
- is_headless: is_headless2,
3078
- is_headless_parent,
3079
- is_owned_here,
3080
- must_keep_waiting
3081
- };
3082
-
3083
- // scripts/agent/agent-session-role.ts
3084
- var KEY3 = "JOSH_AGENT_ROLE";
3085
- function environment_for2(role) {
3086
- return { [KEY3]: role };
3087
- }
3088
- function is_reviewer(source = process.env) {
3089
- return source[KEY3] === agent_role_profile.REVIEWER;
3090
- }
3091
- var agent_session_role = { KEY: KEY3, env_for: environment_for2, is_reviewer };
3092
-
3093
- // scripts/run/detached-launch.ts
3094
- import { spawn } from "node:child_process";
3095
- import { closeSync, constants, openSync, writeSync } from "node:fs";
3096
-
3097
- // scripts/agent/agent-launch-environment.ts
3098
- import { existsSync as existsSync2, lstatSync as lstatSync2, mkdirSync, readlinkSync, symlinkSync, unlinkSync } from "node:fs";
3099
- import path4 from "node:path";
3100
-
3101
- // scripts/gh/gh-cli-token.ts
3102
- import { execaSync as execaSync2 } from "execa";
3103
- var GH_CLI_TIMEOUT_MS = 5e3;
3104
- function get() {
3105
- try {
3106
- const { stdout } = execaSync2("gh", ["auth", "token"], { timeout: GH_CLI_TIMEOUT_MS });
3107
- const token = stdout.trim();
3108
- return token.length > 0 ? token : void 0;
3109
- } catch {
3110
- return void 0;
3111
- }
3112
- }
3113
- var gh_cli_token = { get };
3114
-
3115
- // scripts/agent/codex-home-source.ts
3116
- import os from "node:os";
3117
- import path3 from "node:path";
3118
- function default_home() {
3119
- return path3.join(os.homedir(), ".codex");
3120
- }
3121
- var codex_home_source = { default_home };
3122
-
3123
- // scripts/agent/agent-launch-environment.ts
3124
- var OPENAI_PROVIDER2 = "openai";
3125
- var REVIEWER_HOME = ["node_modules", ".cache", "josh", "openai", "reviewer-home"];
3126
- var HOME_FILES = ["auth.json", "config.toml"];
3127
- var PRIVATE_DIRECTORY_MODE = 448;
3128
- function openai_environment() {
3129
- const token = gh_cli_token.get();
3130
- return token === void 0 ? { TMPDIR: PLATFORM_TEMP_ROOT } : { GH_TOKEN: token, TMPDIR: PLATFORM_TEMP_ROOT };
3131
- }
3132
- function remove_old_home_link(source, target) {
3133
- const current = lstatSync2(target, { throwIfNoEntry: false });
3134
- if (current === void 0) return false;
3135
- if (!current.isSymbolicLink()) throw new Error(`Reviewer home file is not a link: ${target}`);
3136
- if (existsSync2(source) && readlinkSync(target) === source) return true;
3137
- unlinkSync(target);
3138
- return false;
3139
- }
3140
- function link_home_file(source_home, target_home, name) {
3141
- const source = path4.join(source_home, name);
3142
- const target = path4.join(target_home, name);
3143
- if (!remove_old_home_link(source, target) && existsSync2(source)) symlinkSync(source, target);
3144
- }
3145
- function reviewer_home(cwd, environment3) {
3146
- const source = environment3["CODEX_HOME"] ?? process.env["CODEX_HOME"] ?? codex_home_source.default_home();
3147
- const target = path4.resolve(cwd, ...REVIEWER_HOME);
3148
- mkdirSync(target, { recursive: true, mode: PRIVATE_DIRECTORY_MODE });
3149
- for (const name of HOME_FILES) link_home_file(source, target, name);
3150
- return target;
3151
- }
3152
- function build2(cwd, profile, environment3 = {}) {
3153
- if (profile === void 0) return environment3;
3154
- const marked = {
3155
- ...agent_headless.environment(),
3156
- ...agent_session_role.env_for(profile.role),
3157
- ...environment3
3158
- };
3159
- if (profile.provider !== OPENAI_PROVIDER2) return marked;
3160
- const base = { ...openai_environment(), ...marked };
3161
- return profile.role === agent_role_profile.REVIEWER ? { ...base, CODEX_HOME: reviewer_home(cwd, environment3) } : base;
3162
- }
3163
- var agent_launch_environment = { build: build2 };
3164
-
3165
- // scripts/run/launch-priority.ts
3166
- import { setPriority } from "node:os";
3167
- var LANE_NICENESS = 10;
3168
- function lower(pid, set_priority = setPriority) {
3169
- if (pid === void 0) return;
3170
- try {
3171
- set_priority(pid, LANE_NICENESS);
3172
- } catch {
3173
- }
3174
- }
3175
- var launch_priority = {
3176
- LANE_NICENESS,
3177
- lower
3178
- };
3179
-
3180
- // scripts/run/detached-launch.ts
3181
- var NO_PID_NOTE = "the process started without a pid";
3182
- var UNSAFE_NOTE = "the wake command or its arguments contain characters that are not safe to execute";
3183
- var { is_safe_prompt: is_safe_prompt3, is_safe_value: is_safe_value3 } = agent_role_profile;
3184
- var LAST = -1;
3185
- function is_safe_element(argv, value, index) {
3186
- const is_prompt = argv.ends_with_prompt === true && index === argv.args.length + LAST;
3187
- return is_prompt ? is_safe_prompt3(value) : is_safe_value3(value);
3188
- }
3189
- function is_safe_argv(argv) {
3190
- return is_safe_value3(argv.command) && argv.args.every((value, index) => is_safe_element(argv, value, index));
3191
- }
3192
- function note_of(error) {
3193
- return error instanceof Error ? error.message : JSON.stringify(error);
3194
- }
3195
- function launched(pid) {
3196
- return { kind: "launched", pid };
3197
- }
3198
- var LOG_FLAGS = constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | constants.O_NOFOLLOW;
3199
- var LOG_MODE = 384;
3200
- function profile_suffix(profile) {
3201
- return profile === void 0 ? "" : ` \xB7 ${agent_role_profile.describe(profile)}`;
3202
- }
3203
- function log_header(argv, profile) {
3204
- const stamp = (/* @__PURE__ */ new Date()).toISOString();
3205
- return `
3206
- === ${stamp} \xB7 started by process ${String(process.pid)} \xB7 ${argv.command}${profile_suffix(profile)} ===
3207
- `;
3208
- }
3209
- function opened_log(log_path, on_error) {
3210
- const descriptor = openSync(log_path, LOG_FLAGS, LOG_MODE);
3211
- if (!stamp_file.is_own_regular_file(log_path)) {
3212
- closeSync(descriptor);
3213
- on_error(`${log_path} is not this account's own file, so nothing is kept there`);
3214
- return void 0;
3215
- }
3216
- return descriptor;
3217
- }
3218
- function stamped(descriptor, argv, profile, on_error) {
3219
- if (descriptor === void 0) return;
3220
- try {
3221
- writeSync(descriptor, log_header(argv, profile));
3222
- } catch (error) {
3223
- on_error(`the session log could not be written: ${note_of(error)}`);
3224
- }
3225
- }
3226
- function open_log(log_path, on_error) {
3227
- if (log_path === void 0) return void 0;
3228
- try {
3229
- return opened_log(log_path, on_error);
3230
- } catch (error) {
3231
- on_error(`the session log at ${log_path} could not be opened: ${note_of(error)}`);
3232
- return void 0;
3233
- }
3234
- }
3235
- function ensure_log(log_path, on_error) {
3236
- const descriptor = open_log(log_path, on_error);
3237
- if (descriptor !== void 0) closeSync(descriptor);
3238
- }
3239
- function spawn_options(cwd, log, environment3 = {}, is_detached = true) {
3240
- return {
3241
- cwd,
3242
- detached: is_detached,
3243
- stdio: log === void 0 ? "ignore" : ["ignore", log, log],
3244
- env: { ...process.env, ...agent_session_environment.removed_environment(), ...environment3 }
3245
- };
3246
- }
3247
- function notify_spawn(pid, on_spawn, on_error) {
3248
- if (pid === void 0) return;
3249
- try {
3250
- on_spawn(pid);
3251
- } catch (error) {
3252
- on_error(`the child state could not be recorded: ${note_of(error)}`);
3253
- }
3254
- }
3255
- async function attached_spawn(request, log, on_error, on_spawn) {
3256
- return await new Promise((resolve2) => {
3257
- const environment3 = agent_launch_environment.build(request.cwd, request.profile, request.env);
3258
- const child = spawn(
3259
- request.argv.command,
3260
- [...request.argv.args],
3261
- spawn_options(request.cwd, log, environment3, false)
3262
- );
3263
- child.once("error", (error) => {
3264
- on_error(note_of(error));
3265
- resolve2({ kind: "failed", note: note_of(error) });
3266
- });
3267
- child.once("exit", (exit_code) => {
3268
- resolve2({ kind: "completed", pid: child.pid ?? 0, exit_code });
3269
- });
3270
- launch_priority.lower(child.pid);
3271
- notify_spawn(child.pid, on_spawn, on_error);
3272
- });
3273
- }
3274
- function ignore_spawn(_pid) {
3275
- }
3276
- function spawned(request, log, on_error) {
3277
- const { command, args } = request.argv;
3278
- const environment3 = agent_launch_environment.build(request.cwd, request.profile, request.env);
3279
- const child = spawn(command, [...args], spawn_options(request.cwd, log, environment3));
3280
- child.on("error", (error) => {
3281
- on_error(note_of(error));
3282
- });
3283
- child.unref();
3284
- launch_priority.lower(child.pid);
3285
- return child.pid === void 0 ? { kind: "failed", note: NO_PID_NOTE } : launched(child.pid);
3286
- }
3287
- function launch(request, on_error) {
3288
- if (!is_safe_argv(request.argv)) return { kind: "failed", note: UNSAFE_NOTE };
3289
- const log = open_log(request.log_path, on_error);
3290
- try {
3291
- stamped(log, request.argv, request.profile, on_error);
3292
- return spawned(request, log, on_error);
3293
- } catch (error) {
3294
- return { kind: "failed", note: note_of(error) };
3295
- } finally {
3296
- if (log !== void 0) closeSync(log);
3297
- }
3298
- }
3299
- async function launch_attached(request, on_error, on_spawn = ignore_spawn) {
3300
- if (!is_safe_argv(request.argv)) return { kind: "failed", note: UNSAFE_NOTE };
3301
- const log = open_log(request.log_path, on_error);
3302
- try {
3303
- stamped(log, request.argv, request.profile, on_error);
3304
- return await attached_spawn(request, log, on_error, on_spawn);
3305
- } catch (error) {
3306
- return { kind: "failed", note: note_of(error) };
3307
- } finally {
3308
- if (log !== void 0) closeSync(log);
3309
- }
3310
- }
3311
- var detached_launch = {
3312
- UNSAFE_NOTE,
3313
- ensure_log,
3314
- is_safe_argv,
3315
- is_safe_value: is_safe_value3,
3316
- launch,
3317
- launch_attached,
3318
- log_header,
3319
- note_of
3320
- };
3321
-
3322
- // scripts/init/distributed-paths.ts
3323
- var KIT_PACKAGE_PATH_PREFIX = "node_modules/@joshuafolkken/kit/";
3324
- var PROMPTS_PACKAGE_PREFIX = `${KIT_PACKAGE_PATH_PREFIX}prompts/`;
3325
- var ESLINT_PACKAGE_PREFIX = `${KIT_PACKAGE_PATH_PREFIX}eslint/`;
3326
- var GITHUB_REPO_BLOB_BASE = "https://github.com/joshuafolkken/kit/blob/main/";
3327
- var GITHUB_REPO_TREE_BASE = "https://github.com/joshuafolkken/kit/tree/main/";
3328
- var CLAUDE_MD_IMPORT_LINE = "@node_modules/@joshuafolkken/kit/dist/CLAUDE.md";
3329
- var OLD_CLAUDE_MD_BOOTSTRAP = "> Fresh checkout: if kit is not installed, run `pnpm install` first, then reread this file before doing any other work.";
3330
- var CLAUDE_MD_BOOTSTRAP = '> Fresh checkout: before `pnpm install`, run `pnpm config get "@joshuafolkken:registry"` from the project root to check the effective registry, including user-level settings. If it points to GitHub Packages, [set up authentication](https://github.com/joshuafolkken/kit/blob/main/docs/authentication.md#1-get-a-token-from-the-gh-cli) first. Then run `pnpm install` and reread this file before doing any other work.';
3331
- function transform_prompt_paths(content) {
3332
- return content.replaceAll(
3333
- /`prompts\/([^`*]+)`/gu,
3334
- (_match, prompt_path) => `\`${PROMPTS_PACKAGE_PREFIX}${prompt_path}\``
3335
- );
3336
- }
3337
- function transform_eslint_paths(content) {
3338
- return content.replaceAll(
3339
- /`eslint\/([^`*]+)`/gu,
3340
- (_match, eslint_path) => `\`${ESLINT_PACKAGE_PREFIX}${eslint_path}\``
3341
- );
3342
- }
3343
- function transform_test_file_paths(content) {
3344
- return content.replaceAll(
3345
- /`([^`*]+\.(?:test|spec)\.ts)`/gu,
3346
- (_match, test_path) => `\`${GITHUB_REPO_BLOB_BASE}${test_path}\``
3347
- );
3348
- }
3349
- function github_url_base(reference_path) {
3350
- return reference_path.endsWith("/") ? GITHUB_REPO_TREE_BASE : GITHUB_REPO_BLOB_BASE;
3351
- }
3352
- function transform_documentation_paths(content) {
3353
- return content.replaceAll(
3354
- /`(docs\/[^`*]*)`/gu,
3355
- (_match, documentation_path) => `\`${github_url_base(documentation_path)}${documentation_path}\``
3356
- );
3357
- }
3358
- function transform_distributed_paths(content) {
3359
- const with_prompts = transform_prompt_paths(content);
3360
- const with_eslint = transform_eslint_paths(with_prompts);
3361
- const with_tests = transform_test_file_paths(with_eslint);
3362
- return transform_documentation_paths(with_tests);
3363
- }
3364
- function ensure_claude_md_import(existing) {
3365
- if (existing === void 0) return `${CLAUDE_MD_BOOTSTRAP}
3366
-
3367
- ${CLAUDE_MD_IMPORT_LINE}
3368
- `;
3369
- const updated = existing.replace(OLD_CLAUDE_MD_BOOTSTRAP, () => CLAUDE_MD_BOOTSTRAP);
3370
- if (updated.includes(CLAUDE_MD_IMPORT_LINE)) {
3371
- if (updated.includes(CLAUDE_MD_BOOTSTRAP)) return updated;
3372
- return `${CLAUDE_MD_BOOTSTRAP}
3373
-
3374
- ${updated}`;
3375
- }
3376
- return `${CLAUDE_MD_BOOTSTRAP}
3377
-
3378
- ${CLAUDE_MD_IMPORT_LINE}
3379
-
3380
- ${updated}`;
3381
- }
3382
- var FULL_CLAUDE_MD_LINES = /* @__PURE__ */ new Set([
3383
- CLAUDE_MD_BOOTSTRAP,
3384
- OLD_CLAUDE_MD_BOOTSTRAP,
3385
- CLAUDE_MD_IMPORT_LINE
3386
- ]);
3387
- function remove_claude_md_import(content) {
3388
- const lines = content.split("\n");
3389
- return lines.filter((line, index) => {
3390
- if (FULL_CLAUDE_MD_LINES.has(line)) return false;
3391
- return line !== "" || !FULL_CLAUDE_MD_LINES.has(lines[index - 1] ?? "");
3392
- }).join("\n");
3393
- }
3394
- var distributed_paths = {
3395
- transform_prompt_paths,
3396
- transform_distributed_paths,
3397
- ensure_claude_md_import,
3398
- remove_claude_md_import,
3399
- CLAUDE_MD_IMPORT_LINE
3400
- };
3401
-
3402
- export {
3403
- josh_environment_file,
3404
- lane_child_marker,
3405
- agent_role_profile,
3406
- agent_session_role,
3407
- FULL_PAGE_QUERY,
3408
- git_gh_api_path,
3409
- parse_json_array_or_undefined,
3410
- read_json_listing,
3411
- parse_json_array_safe,
3412
- parse_json_object_or_undefined,
3413
- parse_json,
3414
- gh_failure,
3415
- has_stderr_field,
3416
- git_gh_exec,
3417
- git_gh_conditional,
3418
- git_gh_helpers,
3419
- to_gh_state,
3420
- BLOCKED_BY_FIELD,
3421
- BLOCKED_BY_COUNT_FIELD,
3422
- git_gh_issue_rest,
3423
- read_blocked_by,
3424
- git_gh_issue_read,
3425
- issue_watch_diff,
3426
- issue_watch,
3427
- review_checkout,
3428
- issue_watch_gate,
3429
- stamp_record,
3430
- changed_paths,
3431
- git_worktree,
3432
- run_hold,
3433
- git_gh_pr_rest,
3434
- forget_pr_numbers,
3435
- require_pr_number,
3436
- read_pull,
3437
- git_gh_pr_read,
3438
- OBSERVATION_LEDGER_DIRECTORY,
3439
- LEGACY_OBSERVATION_LEDGER_DIRECTORY,
3440
- LEDGER_FILE_EXTENSION,
3441
- LEGACY_LEDGER_FILE,
3442
- LEGACY_OBSERVATION_LEDGER_PATHS,
3443
- MIGRATION_CLAIM_SUFFIX,
3444
- observation_ledger,
3445
- git_stash,
3446
- lane_registry,
3447
- run_preflight,
3448
- lane_child_invocation,
3449
- agent_headless,
3450
- detached_launch,
3451
- distributed_paths,
3452
- session_language,
3453
- process_tools,
3454
- lane_reap,
3455
- run_headless
3456
- };