@joshuafolkken/kit 1.1178.0 → 1.1240.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 (442) hide show
  1. package/.claude/.claude-plugin/plugin.json +1 -1
  2. package/.claude/settings.json +2 -2
  3. package/.claude/skills/dependency-update/SKILL.md +4 -8
  4. package/.claude/skills/epic-commands/SKILL.md +2 -2
  5. package/.claude/skills/epic-commands/epic-bundle.md +1 -1
  6. package/.claude/skills/workflow-commands/SKILL.md +2 -4
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +6 -4
  8. package/.claude/skills/workflow-commands/backlogrun-lanes.md +7 -3
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +23 -2
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +9 -4
  11. package/.claude/skills/workflow-commands/backlogrun-recovery.md +4 -3
  12. package/.claude/skills/workflow-commands/backlogrun-steps.md +21 -13
  13. package/.claude/skills/workflow-commands/chain-rule.md +1 -1
  14. package/.claude/skills/workflow-commands/delegation.md +2 -2
  15. package/.claude/skills/workflow-commands/followup.md +10 -0
  16. package/.claude/skills/workflow-commands/fullrun-steps.md +1 -1
  17. package/.claude/skills/workflow-commands/halfrun.md +1 -1
  18. package/.claude/skills/workflow-commands/issue-scout.md +1 -1
  19. package/.claude/skills/workflow-commands/kickoff.md +2 -1
  20. package/.claude/skills/workflow-commands/latest-gate.md +1 -1
  21. package/.claude/skills/workflow-commands/observation-ledger.md +3 -3
  22. package/.claude/skills/workflow-commands/pre-gate-cut.md +6 -1
  23. package/.claude/skills/workflow-commands/prerequisite.md +2 -2
  24. package/.claude/skills/workflow-commands/progress-watcher.md +1 -1
  25. package/.claude/skills/workflow-commands/working-tree-hold.md +1 -1
  26. package/.codex/hooks.json +2 -2
  27. package/.cursorrules +6 -41
  28. package/.github/actions/setup-node/action.yml +1 -1
  29. package/.github/workflows/auto-tag.yml +3 -4
  30. package/.github/workflows/ci.yml +32 -31
  31. package/.github/workflows/dependabot-auto-merge.yml +13 -6
  32. package/.github/workflows/publish.yml +50 -4
  33. package/.github/workflows/sonar-qube.yml +3 -0
  34. package/.pnpmfile.mjs +4 -3
  35. package/.prettierignore +8 -2
  36. package/CLAUDE.md +18 -20
  37. package/README.md +44 -38
  38. package/SECURITY.md +15 -1
  39. package/dist/CLAUDE.md +18 -20
  40. package/dist/commands/document-section-cli.js +734 -0
  41. package/dist/hooks/audit-provision.js +346 -0
  42. package/dist/hooks/batch-guard.js +5 -4
  43. package/dist/hooks/{chunk-G6KRCKEC.js → chunk-4TZVB44A.js} +496 -378
  44. package/dist/hooks/chunk-5VNDSNG3.js +12 -0
  45. package/dist/hooks/chunk-CDY4NFQG.js +15 -0
  46. package/dist/hooks/chunk-ELCN5LCH.js +135 -0
  47. package/dist/hooks/{chunk-VQLLNFNT.js → chunk-F3ELQ2AF.js} +3 -3
  48. package/dist/hooks/{chunk-I4XSL4TT.js → chunk-GPTFMK5E.js} +1 -1
  49. package/dist/hooks/{chunk-3V37IID6.js → chunk-JBBMAPC4.js} +23 -14
  50. package/dist/hooks/{chunk-UAGLLIGZ.js → chunk-KHGB5S3Y.js} +7 -6
  51. package/dist/hooks/{chunk-GDS5N2KB.js → chunk-KHX4U3BG.js} +735 -683
  52. package/dist/hooks/{chunk-VESKRQOF.js → chunk-KRBERBBI.js} +3 -3
  53. package/dist/hooks/{chunk-DO6NWWHU.js → chunk-QVSWU24O.js} +4 -4
  54. package/dist/hooks/{chunk-S6X6WYKR.js → chunk-WK2XSHSI.js} +1643 -923
  55. package/dist/hooks/{chunk-ZAL3NRGL.js → chunk-XZYKEM6J.js} +25 -10
  56. package/dist/hooks/{chunk-32GQTL4F.js → chunk-ZQGD4GBY.js} +4 -2
  57. package/dist/hooks/codex-hook-adapter.js +14 -12
  58. package/dist/hooks/duplicate-read-guard.js +6 -5
  59. package/dist/hooks/format-edited.js +4 -3
  60. package/dist/hooks/inputs.json +203 -179
  61. package/dist/hooks/investigation-guard.js +6 -5
  62. package/dist/hooks/pretool-guard.js +12 -10
  63. package/dist/hooks/session-lang.js +2 -4
  64. package/dist/hooks/stop-guard.js +66 -72
  65. package/dist/josh.js +1088 -78
  66. package/dist/version/index.d.ts +7 -2
  67. package/dist/version/index.js +152 -75
  68. package/eslint/base.js +23 -1
  69. package/eslint/rules/code-quality.js +3 -0
  70. package/eslint/rules/early-return-one-liner.js +98 -0
  71. package/eslint/rules/unicorn.js +16 -1
  72. package/package.json +7 -6
  73. package/pnpm-workspace.yaml +9 -4
  74. package/prettier/basic.d.ts +3 -1
  75. package/prettier/index.d.ts +3 -1
  76. package/prettier/static.d.ts +3 -1
  77. package/prompts/coding-standards.md +1 -1
  78. package/prompts/collaboration-workflow/file-edits.md +4 -4
  79. package/prompts/collaboration-workflow/glossary.md +1 -1
  80. package/prompts/collaboration-workflow/issue-template.md +1 -0
  81. package/prompts/collaboration-workflow/operating-rules.md +17 -9
  82. package/prompts/collaboration-workflow/overview.md +2 -2
  83. package/prompts/collaboration-workflow/principles.md +14 -12
  84. package/prompts/collaboration-workflow/report-format.md +1 -1
  85. package/prompts/collaboration-workflow/residency.md +1 -1
  86. package/prompts/collaboration-workflow/rule-delivery.md +6 -6
  87. package/prompts/collaboration-workflow/shell-body.md +6 -6
  88. package/prompts/collaboration-workflow/turn-batching.md +1 -1
  89. package/prompts/collaboration-workflow/upstream-interrupt.md +12 -2
  90. package/prompts/collaboration-workflow/wip-cap.md +10 -10
  91. package/prompts/review-rubric.md +1 -2
  92. package/prompts/review.md +1 -1
  93. package/scripts/agent/agent-headless.ts +29 -0
  94. package/scripts/agent/agent-launch-environment.ts +6 -2
  95. package/scripts/agent/codex-agent-argv.ts +2 -1
  96. package/scripts/auto-ok/auto-ok-cli.ts +1 -1
  97. package/scripts/backlog/backlog-arrival.ts +3 -3
  98. package/scripts/backlog/backlog-budget.ts +1 -1
  99. package/scripts/backlog/backlog-drive-args.ts +135 -0
  100. package/scripts/backlog/backlog-drive-cli.ts +11 -137
  101. package/scripts/backlog/backlog-drive-launch.ts +39 -0
  102. package/scripts/backlog/backlog-drive-named-offer.ts +3 -5
  103. package/scripts/backlog/backlog-drive-named.ts +3 -3
  104. package/scripts/backlog/backlog-drive-offer-argv.ts +1 -1
  105. package/scripts/backlog/backlog-drive-owner.ts +1 -1
  106. package/scripts/backlog/backlog-drive-restore.ts +1 -1
  107. package/scripts/backlog/backlog-drive-retrospective.ts +1 -1
  108. package/scripts/backlog/backlog-drive.ts +1 -1
  109. package/scripts/backlog/backlog-next.ts +16 -5
  110. package/scripts/backlog/backlog-offer-cli.ts +6 -6
  111. package/scripts/backlog/backlog-offer.ts +1 -1
  112. package/scripts/backlog/backlog-plan-cli.ts +1 -1
  113. package/scripts/backlog/backlog-pool.ts +57 -11
  114. package/scripts/backlog/backlog-ready.ts +1 -1
  115. package/scripts/backlog/backlog-scope.ts +1 -1
  116. package/scripts/backlog/backlog-stalled-detect.ts +2 -2
  117. package/scripts/backlog/backlog-stalled.ts +1 -1
  118. package/scripts/build/build-codex-hooks.ts +3 -1
  119. package/scripts/build/build-commands.ts +66 -0
  120. package/scripts/build/build-hooks.ts +2 -1
  121. package/scripts/build/build-library.ts +12 -3
  122. package/scripts/build/build.ts +70 -0
  123. package/scripts/build/local-bin.ts +3 -13
  124. package/scripts/delegation/investigation-reads.ts +3 -1
  125. package/scripts/discovery/repo-origin.ts +5 -5
  126. package/scripts/doctor/doctor-consumer.ts +2 -2
  127. package/scripts/doctor/doctor-io.ts +2 -3
  128. package/scripts/document/capped-print-part.ts +30 -0
  129. package/scripts/document/capped-print.ts +3 -4
  130. package/scripts/document/document-byte-budget.ts +11 -2
  131. package/scripts/document/document-scan.ts +117 -0
  132. package/scripts/document/document-section.ts +143 -16
  133. package/scripts/document/entry-read-budget.ts +5 -3
  134. package/scripts/document/entry-read-set.ts +10 -89
  135. package/scripts/document/read-set-cost.ts +98 -0
  136. package/scripts/epic/epic-add-body.ts +1 -0
  137. package/scripts/epic/epic-audit-checks.ts +1 -1
  138. package/scripts/epic/epic-audit-rationale.ts +4 -3
  139. package/scripts/epic/epic-bundle-cli.ts +14 -3
  140. package/scripts/epic/epic-bundle-poll.ts +41 -0
  141. package/scripts/epic/epic-busy.ts +1 -1
  142. package/scripts/epic/epic-candidate-confirm.ts +3 -2
  143. package/scripts/epic/epic-classify.ts +1 -1
  144. package/scripts/epic/epic-cli-argv.ts +78 -46
  145. package/scripts/epic/epic-cli-remove.ts +11 -19
  146. package/scripts/epic/epic-cli.ts +74 -73
  147. package/scripts/epic/epic-close-comment.ts +1 -1
  148. package/scripts/epic/epic-close.ts +1 -1
  149. package/scripts/epic/epic-cross-repo.ts +5 -5
  150. package/scripts/epic/epic-graph.ts +1 -1
  151. package/scripts/epic/epic-index.ts +1 -1
  152. package/scripts/epic/epic-issue.ts +2 -6
  153. package/scripts/epic/epic-lane-offer.ts +2 -2
  154. package/scripts/epic/epic-next.ts +29 -42
  155. package/scripts/epic/epic-solo-stale.ts +1 -1
  156. package/scripts/epic/epic-triage.ts +8 -4
  157. package/scripts/epic/epic-validate.ts +1 -1
  158. package/scripts/followup/git-followup-finish.ts +2 -2
  159. package/scripts/followup/git-followup-label.ts +2 -2
  160. package/scripts/followup/git-followup-merged.ts +2 -2
  161. package/scripts/followup/git-pr-followup-checks.ts +142 -0
  162. package/scripts/followup/git-pr-followup.ts +4 -129
  163. package/scripts/gate/core-admission.ts +162 -0
  164. package/scripts/gate/core-budget.ts +190 -68
  165. package/scripts/gate/gate-plan.ts +80 -7
  166. package/scripts/gate/gate-report.ts +28 -9
  167. package/scripts/gate/gate-skip.ts +38 -7
  168. package/scripts/gate/hook-gate-reuse.ts +12 -10
  169. package/scripts/gate/machine-capacity.ts +175 -0
  170. package/scripts/gate/pre-commit-type-check.ts +4 -1
  171. package/scripts/gate/project-checks.ts +6 -9
  172. package/scripts/gate/type-check-step.ts +2 -3
  173. package/scripts/gate/verification-gate.ts +34 -10
  174. package/scripts/gh/git-gh-api-path.ts +2 -2
  175. package/scripts/gh/git-gh-issue-rest.ts +3 -3
  176. package/scripts/gh/git-gh-issue-write.ts +53 -7
  177. package/scripts/gh/git-gh-pr-read.ts +64 -19
  178. package/scripts/gh/git-gh-pr-rest.ts +1 -1
  179. package/scripts/gh/git-gh-pr.ts +5 -1
  180. package/scripts/gh/git-pr-ai-review.ts +1 -1
  181. package/scripts/gh/git-pr-checks-eval.ts +1 -3
  182. package/scripts/gh/git-pr-checks-parse.ts +1 -1
  183. package/scripts/gh/git-pr-checks-watch.ts +6 -5
  184. package/scripts/gh/git-pr-checks.ts +7 -5
  185. package/scripts/gh/git-pr-coderabbit.ts +1 -1
  186. package/scripts/gh/git-pr-error.ts +1 -3
  187. package/scripts/gh/git-pr.ts +9 -13
  188. package/scripts/gh/github-issue-url.ts +2 -2
  189. package/scripts/git/constants.ts +2 -6
  190. package/scripts/git/git-command.ts +20 -218
  191. package/scripts/git/git-diff-reads.ts +225 -0
  192. package/scripts/git/git-error.ts +4 -12
  193. package/scripts/git/git-pre-push-hook.ts +139 -0
  194. package/scripts/git/git-prompt.ts +2 -6
  195. package/scripts/git/git-spawn-sync.ts +3 -1
  196. package/scripts/git/git-spawn.ts +1 -1
  197. package/scripts/git/git-staging.ts +4 -6
  198. package/scripts/git/git-status.ts +3 -9
  199. package/scripts/hooks/codex-hook-adapter.ts +1 -1
  200. package/scripts/hooks/edited-cspell.ts +2 -4
  201. package/scripts/hooks/format-edited-file.ts +3 -12
  202. package/scripts/hooks/pre-push-unit.ts +31 -9
  203. package/scripts/hooks/reserved-run.ts +2 -2
  204. package/scripts/hooks/run-hook.sh +5 -4
  205. package/scripts/hooks/stop-guard.ts +5 -3
  206. package/scripts/init/init-actions.ts +0 -5
  207. package/scripts/init/init-ai-copy.ts +13 -2
  208. package/scripts/init/init-logic-json-merge.ts +19 -0
  209. package/scripts/init/init-logic-secretlint.ts +7 -7
  210. package/scripts/init/init-logic-workspace.ts +41 -2
  211. package/scripts/init/init-logic.ts +16 -26
  212. package/scripts/init/init.ts +10 -16
  213. package/scripts/init/initial-commit.ts +4 -4
  214. package/scripts/init/kit-development-versions.ts +40 -0
  215. package/scripts/init/kit-setup-state.ts +2 -2
  216. package/scripts/init/package-manager-pin.ts +35 -0
  217. package/scripts/init/start-exec.ts +68 -19
  218. package/scripts/init/start-setup-pr.ts +9 -9
  219. package/scripts/init/start-steps.ts +6 -10
  220. package/scripts/issue/defect-rate-cli.ts +1 -1
  221. package/scripts/issue/git-next-issues.ts +1 -1
  222. package/scripts/issue/issue-auto-ok.ts +32 -7
  223. package/scripts/issue/issue-backlinks-cli.ts +2 -2
  224. package/scripts/issue/issue-backlinks.ts +9 -9
  225. package/scripts/issue/issue-comment-cli.ts +19 -13
  226. package/scripts/issue/issue-file-cli.ts +72 -22
  227. package/scripts/issue/issue-file.ts +29 -1
  228. package/scripts/issue/issue-labels.ts +13 -0
  229. package/scripts/issue/issue-release-cli.ts +155 -0
  230. package/scripts/issue/issue-release.ts +58 -0
  231. package/scripts/issue/issue-scout-closed.ts +1 -1
  232. package/scripts/issue/issue-state-cli.ts +30 -74
  233. package/scripts/josh/josh-command-map.ts +2 -0
  234. package/scripts/josh/josh-command-types.ts +14 -0
  235. package/scripts/josh/josh-commands-ai.ts +4 -4
  236. package/scripts/josh/josh-commands-backlog.ts +4 -1
  237. package/scripts/josh/josh-commands-development.ts +18 -0
  238. package/scripts/josh/josh-commands-document.ts +1 -0
  239. package/scripts/josh/josh-commands-issue.ts +8 -1
  240. package/scripts/josh/josh-commands-lane.ts +24 -1
  241. package/scripts/josh/josh-commands-maintenance.ts +6 -6
  242. package/scripts/josh/josh-commands-run.ts +12 -7
  243. package/scripts/josh/josh-in-process.ts +28 -9
  244. package/scripts/josh/josh-logic.ts +34 -15
  245. package/scripts/josh/process-identity.ts +1 -3
  246. package/scripts/josh/session-language-cli.ts +3 -4
  247. package/scripts/lane/lane-await.ts +5 -1
  248. package/scripts/lane/lane-child-invocation.ts +2 -2
  249. package/scripts/lane/lane-cli.ts +12 -4
  250. package/scripts/lane/lane-dispatch.ts +14 -10
  251. package/scripts/lane/lane-environment.ts +5 -1
  252. package/scripts/lane/lane-handoff.ts +1 -1
  253. package/scripts/lane/lane-install.ts +2 -13
  254. package/scripts/lane/lane-launch-cli.ts +15 -1
  255. package/scripts/lane/lane-ledger.ts +145 -0
  256. package/scripts/lane/lane-leftover.ts +44 -30
  257. package/scripts/lane/lane-load.ts +108 -0
  258. package/scripts/lane/lane-measure-cli.ts +149 -0
  259. package/scripts/lane/lane-occupancy.ts +3 -0
  260. package/scripts/lane/lane-open.ts +5 -5
  261. package/scripts/lane/lane-paths.ts +13 -0
  262. package/scripts/lane/lane-reap.ts +1 -3
  263. package/scripts/lane/lane-registry.ts +11 -0
  264. package/scripts/lane/lane-relaunch.ts +1 -1
  265. package/scripts/lane/lane-stats.ts +224 -0
  266. package/scripts/lane/lane-stray.ts +140 -0
  267. package/scripts/lane/lane-vacant.ts +36 -0
  268. package/scripts/lane/openai-lane-ship.ts +2 -2
  269. package/scripts/lane/openai-lane-supervisor-owner.ts +180 -0
  270. package/scripts/lane/openai-lane-supervisor.ts +7 -165
  271. package/scripts/lane/openai-review-broker.ts +2 -4
  272. package/scripts/lib/ancestor-directories.ts +35 -0
  273. package/scripts/lib/animation-helpers.ts +2 -2
  274. package/scripts/lib/buffered-process.ts +3 -7
  275. package/scripts/lib/cli-flags.ts +71 -1
  276. package/scripts/lib/spawn-exit.ts +2 -2
  277. package/scripts/lib/timeouts.ts +35 -2
  278. package/scripts/lines/line-budget.ts +4 -6
  279. package/scripts/notify/telegram-test.ts +6 -0
  280. package/scripts/observations/observation-ledger-line.ts +6 -6
  281. package/scripts/observations/observation-ledger-migrate.ts +55 -4
  282. package/scripts/observations/observation-ledger.ts +26 -7
  283. package/scripts/overrides/lockfile-overrides.ts +1 -1
  284. package/scripts/overrides/overrides-logic.ts +1 -1
  285. package/scripts/propagate/propagate-git.ts +1 -1
  286. package/scripts/propagate/propagate-publish.ts +2 -2
  287. package/scripts/propagate/propagate-steps.ts +20 -15
  288. package/scripts/propagate/propagate.ts +36 -27
  289. package/scripts/refactor/import-graph.ts +18 -1
  290. package/scripts/refactor/refactor-lint.ts +4 -4
  291. package/scripts/release/github-release-environment.ts +1 -0
  292. package/scripts/release/github-release-runs.ts +115 -0
  293. package/scripts/release/github-release.ts +13 -67
  294. package/scripts/repo/repository-labels.ts +2 -2
  295. package/scripts/repo/required-checks-logic.ts +1 -3
  296. package/scripts/review/live-evidence.ts +2 -4
  297. package/scripts/review/review-brief-cli.ts +1 -1
  298. package/scripts/review/review-finding-ledger.ts +1 -1
  299. package/scripts/review/review-findings-cli.ts +1 -3
  300. package/scripts/rules/decision-oracle-batch.ts +128 -0
  301. package/scripts/rules/decision-oracle-tokens.ts +21 -0
  302. package/scripts/rules/decision-oracle.ts +8 -120
  303. package/scripts/rules/delivered-rules.ts +26 -182
  304. package/scripts/rules/direct-filing.ts +1 -1
  305. package/scripts/rules/early-heartbeat.ts +3 -3
  306. package/scripts/rules/git-argv.ts +1 -1
  307. package/scripts/rules/git-force.ts +1 -1
  308. package/scripts/rules/implementation-cut.ts +2 -2
  309. package/scripts/rules/index-guard.ts +1 -1
  310. package/scripts/rules/issue-comments.ts +118 -0
  311. package/scripts/rules/{issue-fold.ts → issue-fold-rule.ts} +2 -2
  312. package/scripts/rules/lane-background.ts +2 -2
  313. package/scripts/rules/lane-park.ts +18 -0
  314. package/scripts/rules/lane-split-park.ts +128 -0
  315. package/scripts/rules/oracle-firing.ts +1 -1
  316. package/scripts/rules/poll-loop.ts +1 -1
  317. package/scripts/rules/pre-gate-cut.ts +1 -1
  318. package/scripts/rules/protected-files.ts +59 -4
  319. package/scripts/rules/{run-tail.ts → run-tail-rule.ts} +2 -2
  320. package/scripts/rules/shell-body-trigger.ts +1 -1
  321. package/scripts/rules/stop-rules.ts +18 -7
  322. package/scripts/rules/test-declared-commit.ts +4 -4
  323. package/scripts/rules/wip-cap.ts +63 -0
  324. package/scripts/run/{run-carry-args.ts → carry/run-carry-args.ts} +37 -13
  325. package/scripts/run/{run-carry-change.ts → carry/run-carry-change.ts} +29 -7
  326. package/scripts/run/{run-carry-cli.ts → carry/run-carry-cli.ts} +4 -6
  327. package/scripts/run/{run-carry.ts → carry/run-carry.ts} +1 -1
  328. package/scripts/run/{run-cut-args.ts → cut/run-cut-args.ts} +1 -1
  329. package/scripts/run/{run-cut-cli.ts → cut/run-cut-cli.ts} +18 -5
  330. package/scripts/run/{run-cut.ts → cut/run-cut.ts} +1 -1
  331. package/scripts/run/{run-entry-cli.ts → entry/run-entry-cli.ts} +11 -11
  332. package/scripts/run/{run-entry.ts → entry/run-entry.ts} +2 -2
  333. package/scripts/run/{run-event-render.ts → event/run-event-render.ts} +1 -0
  334. package/scripts/run/{run-event-scope.ts → event/run-event-scope.ts} +1 -1
  335. package/scripts/run/{run-event-stream-emit.ts → event/run-event-stream-emit.ts} +1 -1
  336. package/scripts/run/{run-event-stream.ts → event/run-event-stream.ts} +20 -2
  337. package/scripts/run/{run-hold-cli.ts → hold/run-hold-cli.ts} +5 -5
  338. package/scripts/run/{run-merge-cli.ts → merge/run-merge-cli.ts} +10 -5
  339. package/scripts/run/{run-merge-steps.ts → merge/run-merge-steps.ts} +53 -5
  340. package/scripts/run/{run-merge.ts → merge/run-merge.ts} +1 -1
  341. package/scripts/run/{run-progress-cli.ts → progress/run-progress-cli.ts} +1 -1
  342. package/scripts/run/{run-progress-config.ts → progress/run-progress-config.ts} +2 -17
  343. package/scripts/run/{run-progress-read.ts → progress/run-progress-read.ts} +5 -5
  344. package/scripts/run/{run-progress.ts → progress/run-progress.ts} +1 -1
  345. package/scripts/run/{run-review-steps.ts → review/run-review-steps.ts} +2 -3
  346. package/scripts/run/run-ending.ts +2 -2
  347. package/scripts/run/run-halfrun-resume.ts +6 -1
  348. package/scripts/run/run-headless.ts +1 -1
  349. package/scripts/run/run-invocation.ts +85 -84
  350. package/scripts/run/run-liveness.ts +1 -1
  351. package/scripts/run/run-parent-cut-hook.ts +1 -1
  352. package/scripts/run/run-preflight.ts +6 -6
  353. package/scripts/run/run-prep-cli.ts +1 -1
  354. package/scripts/run/run-prrun-resume.ts +1 -1
  355. package/scripts/run/run-report-cli.ts +4 -4
  356. package/scripts/run/run-report.ts +2 -2
  357. package/scripts/run/run-status-cli.ts +1 -1
  358. package/scripts/run/run-step-cli.ts +3 -3
  359. package/scripts/run/run-step.ts +7 -4
  360. package/scripts/run/run-stop-notify.ts +1 -1
  361. package/scripts/run/run-stranded-detect.ts +4 -4
  362. package/scripts/run/run-stranded.ts +2 -2
  363. package/scripts/run/run-watcher-guard-cli.ts +1 -1
  364. package/scripts/run/run-watcher-guard.ts +5 -3
  365. package/scripts/run/run-watcher-hook.ts +1 -1
  366. package/scripts/run/{run-ship-cli.ts → ship/run-ship-cli.ts} +2 -2
  367. package/scripts/run/{run-ship-detach.ts → ship/run-ship-detach.ts} +3 -3
  368. package/scripts/run/ship/run-ship-lock.ts +50 -0
  369. package/scripts/run/{run-ship-preflight.ts → ship/run-ship-preflight.ts} +6 -2
  370. package/scripts/run/{run-ship-probe.ts → ship/run-ship-probe.ts} +2 -2
  371. package/scripts/run/{run-ship-return.ts → ship/run-ship-return.ts} +4 -3
  372. package/scripts/run/{run-ship-review-steps.ts → ship/run-ship-review-steps.ts} +3 -3
  373. package/scripts/run/{run-ship-scoped.ts → ship/run-ship-scoped.ts} +10 -1
  374. package/scripts/run/{run-ship-steps.ts → ship/run-ship-steps.ts} +11 -12
  375. package/scripts/run/ship/run-ship-stop-text.ts +13 -0
  376. package/scripts/run/{run-ship-sync.ts → ship/run-ship-sync.ts} +25 -11
  377. package/scripts/run/{run-tidy-lanes.ts → tidy/run-tidy-lanes.ts} +1 -1
  378. package/scripts/run/{run-wake-cli.ts → wake/run-wake-cli.ts} +25 -11
  379. package/scripts/run/{run-wake-describe.ts → wake/run-wake-describe.ts} +58 -7
  380. package/scripts/run/{run-wake-driver.ts → wake/run-wake-driver.ts} +59 -8
  381. package/scripts/run/{run-wake-handoff.ts → wake/run-wake-handoff.ts} +1 -1
  382. package/scripts/run/{run-wake-loop.ts → wake/run-wake-loop.ts} +13 -15
  383. package/scripts/run/wake/run-wake-restart.ts +58 -0
  384. package/scripts/run/{run-wake-session.ts → wake/run-wake-session.ts} +3 -3
  385. package/scripts/run/{run-wake.ts → wake/run-wake.ts} +16 -65
  386. package/scripts/safe-chain/preinstall-command.ts +20 -21
  387. package/scripts/safe-chain/project-config.ts +19 -15
  388. package/scripts/sync/sync-ai-files.ts +1 -1
  389. package/scripts/sync/sync-configs.ts +2 -1
  390. package/scripts/sync/sync.ts +15 -2
  391. package/scripts/test/unit-worker-share.ts +1 -0
  392. package/scripts/time-runtime/time-background.ts +5 -1
  393. package/scripts/time-runtime/time-instant.ts +3 -1
  394. package/scripts/time-runtime/time-spans.ts +6 -139
  395. package/scripts/time-runtime/time-tool-call.ts +160 -0
  396. package/scripts/version/effective-upstream.ts +2 -20
  397. package/scripts/version/latest-corepack.ts +124 -93
  398. package/scripts/version/latest-regression.ts +1 -1
  399. package/scripts/version/latest-update.ts +4 -4
  400. package/scripts/version/npm-registry.ts +20 -5
  401. package/scripts/version/publishable-range-check.ts +2 -2
  402. package/scripts/version/publishable-range.ts +1 -1
  403. package/scripts/version/release-age.ts +48 -38
  404. package/scripts/version/release-hold.ts +1 -1
  405. package/scripts/version/safe-chain-version-update.ts +40 -0
  406. package/scripts/version/upgrade-shell-command.ts +48 -8
  407. package/scripts/version/version-check-logic.ts +23 -14
  408. package/scripts/version/version-commands.ts +23 -11
  409. package/scripts/version/version-remote.ts +28 -13
  410. package/templates/pnpm-workspace.basic.yaml +4 -0
  411. package/templates/workflows/dependabot-auto-merge.yml +5 -5
  412. package/templates/workflows/github-release.yml +6 -0
  413. package/scripts/build/build-config-merge.ts +0 -27
  414. package/scripts/build/build-managed-marker.ts +0 -27
  415. package/scripts/build/build-self-sync-guard.ts +0 -27
  416. package/scripts/build/build-version.ts +0 -26
  417. package/scripts/version/preinstall-version-update.ts +0 -86
  418. /package/scripts/git/{schemas.ts → git-schemas.ts} +0 -0
  419. /package/scripts/overrides/{schemas.ts → overrides-schemas.ts} +0 -0
  420. /package/scripts/run/{run-carry-conversation.ts → carry/run-carry-conversation.ts} +0 -0
  421. /package/scripts/run/{run-carry-reclaim.ts → carry/run-carry-reclaim.ts} +0 -0
  422. /package/scripts/run/{run-carry-stash.ts → carry/run-carry-stash.ts} +0 -0
  423. /package/scripts/run/{run-carry-streak.ts → carry/run-carry-streak.ts} +0 -0
  424. /package/scripts/run/{run-cut-handoff.ts → cut/run-cut-handoff.ts} +0 -0
  425. /package/scripts/run/{run-cut-report.ts → cut/run-cut-report.ts} +0 -0
  426. /package/scripts/run/{run-entry-stop.ts → entry/run-entry-stop.ts} +0 -0
  427. /package/scripts/run/{run-event-cli.ts → event/run-event-cli.ts} +0 -0
  428. /package/scripts/run/{run-event-follow.ts → event/run-event-follow.ts} +0 -0
  429. /package/scripts/run/{run-event-watch.ts → event/run-event-watch.ts} +0 -0
  430. /package/scripts/run/{run-hold.ts → hold/run-hold.ts} +0 -0
  431. /package/scripts/run/{run-progress-args.ts → progress/run-progress-args.ts} +0 -0
  432. /package/scripts/run/{run-progress-clock.ts → progress/run-progress-clock.ts} +0 -0
  433. /package/scripts/run/{run-review-cli.ts → review/run-review-cli.ts} +0 -0
  434. /package/scripts/run/{run-review.ts → review/run-review.ts} +0 -0
  435. /package/scripts/run/{run-ship-next.ts → ship/run-ship-next.ts} +0 -0
  436. /package/scripts/run/{run-ship-pre-detach.ts → ship/run-ship-pre-detach.ts} +0 -0
  437. /package/scripts/run/{run-ship-review.ts → ship/run-ship-review.ts} +0 -0
  438. /package/scripts/run/{run-ship-stage.ts → ship/run-ship-stage.ts} +0 -0
  439. /package/scripts/run/{run-ship.ts → ship/run-ship.ts} +0 -0
  440. /package/scripts/run/{run-tidy-cli.ts → tidy/run-tidy-cli.ts} +0 -0
  441. /package/scripts/run/{run-tidy-stashes.ts → tidy/run-tidy-stashes.ts} +0 -0
  442. /package/scripts/run/{run-tidy.ts → tidy/run-tidy.ts} +0 -0
@@ -1,5 +1,5 @@
1
1
  import { cli_flags } from '#scripts/lib/cli-flags'
2
- import { run_issue_number } from './run-issue-number'
2
+ import { run_issue_number } from '#scripts/run/run-issue-number'
3
3
 
4
4
  // `josh run:cut` turns its `argv` into one of four requests. The contract mirrors `run-carry-args.ts`:
5
5
  // parsing lives here, acting on the record lives in `run-cut-cli.ts`, and a malformed command line is
@@ -6,12 +6,12 @@ import { git_command } from '#scripts/git/git-command'
6
6
  import { lane_registry, type LaneInfo } from '#scripts/lane/lane-registry'
7
7
  import { lane_relaunch } from '#scripts/lane/lane-relaunch'
8
8
  import { openai_lane_supervisor } from '#scripts/lane/openai-lane-supervisor'
9
+ import { run_event_stream } from '#scripts/run/event/run-event-stream'
10
+ import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
9
11
  import { run_cut, type CutState, type RunCut } from './run-cut'
10
12
  import { run_cut_args, type Request } from './run-cut-args'
11
13
  import { run_cut_handoff } from './run-cut-handoff'
12
14
  import { run_cut_report } from './run-cut-report'
13
- import { run_event_stream } from './run-event-stream'
14
- import { run_event_stream_emit } from './run-event-stream-emit'
15
15
 
16
16
  // `josh run:cut` — the record that lets a lane child end its process before the gate and a fresh one
17
17
  // resume from it (joshuafolkken/kit#1839). `run:cut <N>` writes the record and relaunches a fresh
@@ -290,14 +290,27 @@ function announce_handoff(cut_record: RunCut): void {
290
290
  }
291
291
  }
292
292
 
293
- function adopt(target: string, cut_record: RunCut): number {
293
+ // **An implementation resume appends a `resume` event** (joshuafolkken/kit#3375). It clears the record
294
+ // the `cut` event stood for, so the stream is what moves `run:step` back to implementation; a pre-gate
295
+ // resume keeps its record and appends nothing. Best-effort, as the cut's own append is.
296
+ async function emit_resume_event(issue: string, verdict: string): Promise<void> {
297
+ if (verdict !== RESUME_IMPL_VERDICT) return
298
+
299
+ await run_event_stream_emit.emit(run_event_stream.EVENT_KIND.RESUME, `#${issue} resumed`)
300
+ }
301
+
302
+ async function adopt(target: string, cut_record: RunCut): Promise<number> {
294
303
  const taken = take_over(target, cut_record)
295
304
 
296
305
  if (taken === undefined) return report_busy(cut_record)
297
306
 
298
307
  announce_handoff(cut_record)
299
308
 
300
- return report(resume_verdict_for(cut_record), SUCCESS_EXIT_CODE)
309
+ const verdict = resume_verdict_for(cut_record)
310
+
311
+ await emit_resume_event(cut_record.issue, verdict)
312
+
313
+ return report(verdict, SUCCESS_EXIT_CODE)
301
314
  }
302
315
 
303
316
  // A relaunched lane child and a fresh session both measure `under`, so only the session that took an
@@ -329,7 +342,7 @@ async function verify_and_adopt(
329
342
 
330
343
  if (is_over_threshold_resume(cut_record)) return report_over()
331
344
 
332
- return adopt(target, cut_record)
345
+ return await adopt(target, cut_record)
333
346
  }
334
347
 
335
348
  async function resume(target: string, issue: string): Promise<number> {
@@ -5,9 +5,9 @@ import { git_command } from '#scripts/git/git-command'
5
5
  import { git_common_directory } from '#scripts/git/git-common-directory'
6
6
  import { stamp_file } from '#scripts/josh/stamp-file'
7
7
  import { lane_child_invocation } from '#scripts/lane/lane-child-invocation'
8
+ import { run_hold, type RunHold } from '#scripts/run/hold/run-hold'
8
9
  import { z } from 'zod'
9
10
  import { run_cut_handoff, type Handoff } from './run-cut-handoff'
10
- import { run_hold, type RunHold } from './run-hold'
11
11
 
12
12
  // joshuafolkken/kit#1839: a lane child is a detached `fullrun #<N>` process, and the thinking it
13
13
  // accumulates while implementing rides on every later API call in the same session — measured at 176K
@@ -2,19 +2,19 @@
2
2
  import { fileURLToPath } from 'node:url'
3
3
  import { josh_command } from '#scripts/josh/josh-run'
4
4
  import { lane_child_marker } from '#scripts/lane/lane-child-marker'
5
- import { run_cut_report } from './run-cut-report'
5
+ import { run_cut_report } from '#scripts/run/cut/run-cut-report'
6
+ import { run_hold_cli } from '#scripts/run/hold/run-hold-cli'
7
+ import { run_halfrun_resume } from '#scripts/run/run-halfrun-resume'
8
+ import { run_label } from '#scripts/run/run-label'
9
+ import { run_next } from '#scripts/run/run-next'
10
+ import { run_prep } from '#scripts/run/run-prep'
11
+ import { run_prep_cli } from '#scripts/run/run-prep-cli'
12
+ import { run_prrun_resume } from '#scripts/run/run-prrun-resume'
13
+ import { run_stage, type StageCommand, type StageDecision } from '#scripts/run/run-stage'
14
+ import { run_stage_read, type StageRead } from '#scripts/run/run-stage-read'
15
+ import { run_step } from '#scripts/run/run-step'
6
16
  import { run_entry, type EntryParts } from './run-entry'
7
17
  import { run_entry_stop } from './run-entry-stop'
8
- import { run_halfrun_resume } from './run-halfrun-resume'
9
- import { run_hold_cli } from './run-hold-cli'
10
- import { run_label } from './run-label'
11
- import { run_next } from './run-next'
12
- import { run_prep } from './run-prep'
13
- import { run_prep_cli } from './run-prep-cli'
14
- import { run_prrun_resume } from './run-prrun-resume'
15
- import { run_stage, type StageCommand, type StageDecision } from './run-stage'
16
- import { run_stage_read, type StageRead } from './run-stage-read'
17
- import { run_step } from './run-step'
18
18
 
19
19
  // `josh run:entry <N>` — one call for the fixed entry sequence a lane opens on (joshuafolkken/kit#2372).
20
20
  // The loop used to spend a round trip on `run:hold`, one on `cost --cut`, one on `run:prep` and one on
@@ -1,5 +1,5 @@
1
- import { run_hold_cli } from './run-hold-cli'
2
- import { run_step } from './run-step'
1
+ import { run_hold_cli } from '#scripts/run/hold/run-hold-cli'
2
+ import { run_step } from '#scripts/run/run-step'
3
3
 
4
4
  // `josh run:entry <N>` — the one call a `fullrun` makes to open a run (joshuafolkken/kit#2372). It
5
5
  // folds the fixed entry sequence a lane spends four separate round trips on — claim the tree
@@ -28,6 +28,7 @@ const KIND_LABELS: Readonly<Record<EventKind, KindLabel>> = {
28
28
  split: { ja: '分割', en: 'split' },
29
29
  outage: { ja: '障害', en: 'outage' },
30
30
  cut: { ja: 'セッション交代', en: 'session cut' },
31
+ resume: { ja: '実装を再開', en: 'implementation resumed' },
31
32
  drain: { ja: 'バックログが空', en: 'backlog drained' },
32
33
  stop: { ja: '停止', en: 'stopped' },
33
34
  'pr-opened': { ja: 'PR 作成', en: 'PR opened' },
@@ -1,4 +1,4 @@
1
- import type { CarryRead } from './run-carry'
1
+ import type { CarryRead } from '#scripts/run/carry/run-carry'
2
2
  import { run_event_stream, type RunEvent } from './run-event-stream'
3
3
 
4
4
  // The one place a stream consumer scopes the event stream to a single invocation (joshuafolkken/kit#2395).
@@ -1,5 +1,5 @@
1
1
  import { error_text } from '#scripts/lib/error-message'
2
- import { run_carry } from './run-carry'
2
+ import { run_carry } from '#scripts/run/carry/run-carry'
3
3
  import { run_event_scope } from './run-event-scope'
4
4
  import { run_event_stream, type RunEvent } from './run-event-stream'
5
5
 
@@ -48,6 +48,10 @@ const EVENT_KIND = {
48
48
  SPLIT: 'split',
49
49
  OUTAGE: 'outage',
50
50
  CUT: 'cut',
51
+ // A fresh session adopted an implementation cut — `run:cut --resume` answered `resume-impl`
52
+ // (joshuafolkken/kit#3375). The resume clears the cut record, so without this the `cut` stayed the
53
+ // newest position and `run:step` kept answering the resume command it had just run.
54
+ RESUME: 'resume',
51
55
  // The backlog emptied while nothing of the run's own was in flight — the drain
52
56
  // (joshuafolkken/kit#2335). It marks the position at which the end-of-run retrospective is owed,
53
57
  // *before* the idle watch opens, so `run:step` fires the retrospective at the drain rather than after
@@ -168,6 +172,20 @@ function last_position(events: ReadonlyArray<RunEvent>): number {
168
172
 
169
173
  // The bounded stream serialized back to JSONL. The newest `EVENT_CAP` are kept and the oldest roll off;
170
174
  // each survivor keeps its original `pos`, so the bound never renumbers a position a reader is holding.
175
+ // The stream held to `EVENT_CAP`, dropping the oldest trace events before any position
176
+ // (joshuafolkken/kit#3245). A long run's ship-stage and heartbeat lines once filled 396 of the 500 slots
177
+ // and pushed its cuts off, so the retrospective counted `cut 0` for a run with thirteen; a trace says only
178
+ // that the run was alive, so it is the first to go. Only a stream of positions alone rolls them off.
179
+ function bounded(events: ReadonlyArray<RunEvent>): ReadonlyArray<RunEvent> {
180
+ const excess = events.length - EVENT_CAP
181
+
182
+ if (excess <= 0) return events
183
+
184
+ const dropped = new Set(events.filter((event) => TRACE_KINDS.has(event.kind)).slice(0, excess))
185
+
186
+ return events.filter((event) => !dropped.has(event)).slice(-EVENT_CAP)
187
+ }
188
+
171
189
  function serialize(events: ReadonlyArray<RunEvent>): string {
172
190
  return `${events.map((event) => JSON.stringify(event)).join(LINE_SEPARATOR)}${LINE_SEPARATOR}`
173
191
  }
@@ -184,9 +202,9 @@ function append(target: string, kind: string, text: string, at: string): AppendR
184
202
 
185
203
  const existing = read_events(target)
186
204
  const position = last_position(existing) + POSITION_INCREMENT
187
- const bounded = [...existing, { pos: position, at, kind, text }].slice(-EVENT_CAP)
205
+ const events = bounded([...existing, { pos: position, at, kind, text }])
188
206
 
189
- stamp_file.write_text_stamp(target, serialize(bounded))
207
+ stamp_file.write_text_stamp(target, serialize(events))
190
208
 
191
209
  return { appended: true, position }
192
210
  }
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env tsx
2
2
  import { fileURLToPath } from 'node:url'
3
- import { run_halfrun_resume } from './run-halfrun-resume'
3
+ import { run_halfrun_resume } from '#scripts/run/run-halfrun-resume'
4
+ import { run_label } from '#scripts/run/run-label'
5
+ import { run_preflight, type PreflightDecision } from '#scripts/run/run-preflight'
6
+ import { run_prrun_resume } from '#scripts/run/run-prrun-resume'
7
+ import { run_tidy_cli } from '#scripts/run/tidy/run-tidy-cli'
4
8
  import { run_hold, type HoldRead, type RunHold } from './run-hold'
5
- import { run_label } from './run-label'
6
- import { run_preflight, type PreflightDecision } from './run-preflight'
7
- import { run_prrun_resume } from './run-prrun-resume'
8
- import { run_tidy_cli } from './run-tidy-cli'
9
9
 
10
10
  // `josh run:hold [<N>]` and `josh run:release [<N> | --force]` — the working-tree guard the typed
11
11
  // entry points ask before they start (joshuafolkken/kit#1091).
@@ -5,12 +5,13 @@ import { CONTEXT_CUT_THRESHOLD } from '#scripts/cost-runtime/context-cut-thresho
5
5
  import { issue_closing_pr } from '#scripts/issue/issue-closing-pr'
6
6
  import { issue_state_cli } from '#scripts/issue/issue-state-cli'
7
7
  import { lane_handoff } from '#scripts/lane/lane-handoff'
8
+ import { lane_ledger } from '#scripts/lane/lane-ledger'
8
9
  import { cli_flags } from '#scripts/lib/cli-flags'
9
- import { run_carry, type CarryOwner, type RunCarry } from './run-carry'
10
- import { run_ending } from './run-ending'
11
- import { run_event_stream } from './run-event-stream'
12
- import { run_event_stream_emit } from './run-event-stream-emit'
13
- import { run_issue_number } from './run-issue-number'
10
+ import { run_carry, type CarryOwner, type RunCarry } from '#scripts/run/carry/run-carry'
11
+ import { run_event_stream } from '#scripts/run/event/run-event-stream'
12
+ import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
13
+ import { run_ending } from '#scripts/run/run-ending'
14
+ import { run_issue_number } from '#scripts/run/run-issue-number'
14
15
  import { run_merge, type ChildOutcome, type EndingSignals } from './run-merge'
15
16
  import { run_merge_steps, type MergeContext } from './run-merge-steps'
16
17
 
@@ -234,6 +235,7 @@ async function on_merged(ctx: MergeContext): Promise<MergeVerdict> {
234
235
  if (refused !== undefined) return report_count_refused(refused)
235
236
 
236
237
  await run_event_stream_emit.emit(run_event_stream.EVENT_KIND.MERGE, `#${ctx.child} merged`)
238
+ await lane_ledger.record_merge(Number(ctx.child))
237
239
 
238
240
  if (await run_merge_steps.is_over_budget(ctx.over)) return emit(OVER_TOKEN, SUCCESS_EXIT_CODE)
239
241
 
@@ -316,7 +318,10 @@ async function on_parked(ctx: MergeContext): Promise<MergeVerdict> {
316
318
  return emit(await run_merge_steps.ask_next(ctx), SUCCESS_EXIT_CODE)
317
319
  }
318
320
 
321
+ // A split child: nothing is counted, and its lane is closed when it holds nothing, so the promoted
322
+ // epic does not keep a seat the next child needs (joshuafolkken/kit#3334).
319
323
  async function on_skipped(ctx: MergeContext): Promise<MergeVerdict> {
324
+ await run_merge_steps.close_split_lane(ctx.child)
320
325
  await run_event_stream_emit.emit(run_event_stream.EVENT_KIND.SPLIT, `#${ctx.child} split`)
321
326
 
322
327
  return emit(await run_merge_steps.ask_next(ctx), SUCCESS_EXIT_CODE)
@@ -9,9 +9,16 @@ import { lane_close } from '#scripts/lane/lane-close'
9
9
  import { lane_reap } from '#scripts/lane/lane-reap'
10
10
  import { lane_registry, type LaneInfo } from '#scripts/lane/lane-registry'
11
11
  import { lane_relaunch } from '#scripts/lane/lane-relaunch'
12
- import { run_carry, type CarryChange, type CarryOwner, type RunCarry } from './run-carry'
13
- import { run_carry_conversation } from './run-carry-conversation'
14
- import { run_cut, type RunCut } from './run-cut'
12
+ import { lane_vacant } from '#scripts/lane/lane-vacant'
13
+ import { poll } from '#scripts/lib/poll'
14
+ import {
15
+ run_carry,
16
+ type CarryChange,
17
+ type CarryOwner,
18
+ type RunCarry,
19
+ } from '#scripts/run/carry/run-carry'
20
+ import { run_carry_conversation } from '#scripts/run/carry/run-carry-conversation'
21
+ import { run_cut, type RunCut } from '#scripts/run/cut/run-cut'
15
22
  import { run_merge } from './run-merge'
16
23
 
17
24
  // The result of attempting to apply a carry change. Distinguishing `refused` from `applied` lets
@@ -38,6 +45,7 @@ const LANE_CLOSE_OCCASION = 'lane close'
38
45
  const GIT_ENTRY = '.git'
39
46
  const MERGE_CLOSER = 'pnpm josh run:merge'
40
47
  const SINGLE_READ = { attempts: 1, interval_ms: 0 }
48
+ const SYNC_RETRY = { attempts: 3, interval_ms: 5000 }
41
49
  // What the driver judged when it parks a child, stated on the issue (joshuafolkken/kit#2769).
42
50
  const FAILED_CAUSE = 'the child’s session ended with its issue still open and unfinished.'
43
51
  const CUT_RELAUNCH_CAUSE =
@@ -125,10 +133,27 @@ async function refused_carry(ctx: MergeContext): Promise<RunCarry | undefined> {
125
133
  return record.carry
126
134
  }
127
135
 
136
+ // **A failed `main:sync` is retried before it ends the run** (joshuafolkken/kit#3323): one failure
137
+ // right after a merge — measured while several lanes merged at once — stopped the whole drive, and a
138
+ // hand-run `main:sync` minutes later succeeded. **The error carries the step's stderr, not its
139
+ // stdout**: `main:sync` reports git's refusal on stderr, while stdout carries the wrapper's guard
140
+ // statistics, which is all the old message showed.
128
141
  async function sync_main(): Promise<void> {
129
- const result = await josh(['main:sync'])
142
+ // `poll_until` answers only whether it succeeded, so the last attempt's stderr is kept here.
143
+ let error_output = ''
130
144
 
131
- if (result.code !== 0) throw new Error(`main:sync failed: ${result.out}`)
145
+ const is_synced = await poll.poll_until(
146
+ async () => {
147
+ const result = await josh(['main:sync'])
148
+
149
+ error_output = result.err ?? ''
150
+
151
+ return result.code === 0
152
+ },
153
+ { ...SYNC_RETRY, sleeper: poll.sleep },
154
+ )
155
+
156
+ if (!is_synced) throw new Error(`main:sync failed: ${error_output}`)
132
157
  }
133
158
 
134
159
  async function close_lane(child: string): Promise<void> {
@@ -172,6 +197,28 @@ async function preserve_uncommitted(child: string): Promise<boolean> {
172
197
  }
173
198
  }
174
199
 
200
+ function kept_lane_comment(directory: string): string {
201
+ return `The split left this issue's lane open: it still holds a commit, an uncommitted change or a live process — ${directory}`
202
+ }
203
+
204
+ // A child promoted to an epic by a split leaves its lane holding a seat (joshuafolkken/kit#3334): the
205
+ // epic root is never dispatched again, so nothing else would ever close it. The lane is closed only
206
+ // when it holds nothing — no commit, no change, no live process (`lane_vacant`); any other lane is
207
+ // kept, and why is stated on the issue.
208
+ async function close_split_lane(child: string): Promise<void> {
209
+ const lane = await lane_registry.find_open_lane(child)
210
+
211
+ if (lane === undefined) return
212
+
213
+ if (await lane_vacant.is_vacant(lane)) {
214
+ await close_lane(child)
215
+
216
+ return
217
+ }
218
+
219
+ await git_gh_issue_write.issue_try_comment(child, kept_lane_comment(lane.directory))
220
+ }
221
+
175
222
  // The progress comment is a human-readable mirror of the carry record, so it is best-effort and only
176
223
  // where a named epic has a body to carry it — a pure backlog run keeps the record alone.
177
224
  async function post_counters(ctx: MergeContext, carry: RunCarry | undefined): Promise<void> {
@@ -356,6 +403,7 @@ async function ask_next(ctx: MergeContext): Promise<string> {
356
403
  const run_merge_steps = {
357
404
  CUT_RELAUNCH_CAUSE,
358
405
  ask_next,
406
+ close_split_lane,
359
407
  do_failed,
360
408
  do_merged,
361
409
  do_outage,
@@ -5,7 +5,7 @@ import {
5
5
  NEEDS_DECISION_LABEL,
6
6
  } from '#scripts/issue/issue-labels'
7
7
  import type { IssueState } from '#scripts/issue/issue-state'
8
- import type { CarryChange, RunCarry } from './run-carry'
8
+ import type { CarryChange, RunCarry } from '#scripts/run/carry/run-carry'
9
9
 
10
10
  // joshuafolkken/kit#2024: a `backlogrun` merge event was two parent turns — a reading turn and an
11
11
  // acting turn — spent at the session whose context is largest and whose per-turn cost is highest.
@@ -6,7 +6,7 @@ import { backlog_ready } from '#scripts/backlog/backlog-ready'
6
6
  import { gh_spawn } from '#scripts/gh/gh-spawn'
7
7
  import { lane_child_marker } from '#scripts/lane/lane-child-marker'
8
8
  import { error_text } from '#scripts/lib/error-message'
9
- import { run_event_stream_emit } from './run-event-stream-emit'
9
+ import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
10
10
  import { run_progress, type ProgressState } from './run-progress'
11
11
  import { run_progress_args, type ParsedValues } from './run-progress-args'
12
12
  import { run_progress_clock } from './run-progress-clock'
@@ -1,5 +1,6 @@
1
1
  import { readFileSync } from 'node:fs'
2
2
  import path from 'node:path'
3
+ import { ancestor_directories } from '#scripts/lib/ancestor-directories'
3
4
  import { z } from 'zod'
4
5
  import { run_progress } from './run-progress'
5
6
 
@@ -28,10 +29,6 @@ import { run_progress } from './run-progress'
28
29
 
29
30
  const PACKAGE_FILE = 'package.json'
30
31
 
31
- // Deep enough to cross a workspace package and its root, and bounded so a path that never reaches a
32
- // root — a broken mount, a mocked `dirname` — cannot spin.
33
- const MAX_DEPTH = 10
34
-
35
32
  // Unknown keys are stripped rather than rejected: this reads a whole `package.json`, and every other
36
33
  // field in it is none of this module's business. A present-but-unusable interval fails the parse and
37
34
  // falls through, which is the same answer an unusable environment variable already gets.
@@ -39,18 +36,6 @@ const package_schema = z.object({
39
36
  josh: z.object({ progress_interval_minutes: z.number().positive() }).optional(),
40
37
  })
41
38
 
42
- function ancestors_of(start: string): ReadonlyArray<string> {
43
- const directories: Array<string> = []
44
- let current = path.resolve(start)
45
-
46
- while (directories.length < MAX_DEPTH && !directories.includes(current)) {
47
- directories.push(current)
48
- current = path.dirname(current)
49
- }
50
-
51
- return directories
52
- }
53
-
54
39
  function read_declared_minutes(directory: string): number | undefined {
55
40
  try {
56
41
  const raw = readFileSync(path.join(directory, PACKAGE_FILE), 'utf8')
@@ -63,7 +48,7 @@ function read_declared_minutes(directory: string): number | undefined {
63
48
  }
64
49
 
65
50
  function read_package_minutes(start: string): number | undefined {
66
- for (const directory of ancestors_of(start)) {
51
+ for (const directory of ancestor_directories.list(start)) {
67
52
  const minutes = read_declared_minutes(directory)
68
53
 
69
54
  if (minutes !== undefined) return minutes
@@ -1,13 +1,13 @@
1
1
  import { loadavg } from 'node:os'
2
2
  import { epic_busy } from '#scripts/epic/epic-busy'
3
3
  import { git_command } from '#scripts/git/git-command'
4
- import type { OpenIssueData } from '#scripts/git/schemas'
4
+ import type { OpenIssueData } from '#scripts/git/git-schemas'
5
5
  import { lane_registry } from '#scripts/lane/lane-registry'
6
6
  import { lane_report } from '#scripts/lane/lane-report'
7
- import { run_carry, type CarryRead } from './run-carry'
8
- import { run_hold, type HoldRead } from './run-hold'
9
- import { run_liveness } from './run-liveness'
10
- import { run_preflight } from './run-preflight'
7
+ import { run_carry, type CarryRead } from '#scripts/run/carry/run-carry'
8
+ import { run_hold, type HoldRead } from '#scripts/run/hold/run-hold'
9
+ import { run_liveness } from '#scripts/run/run-liveness'
10
+ import { run_preflight } from '#scripts/run/run-preflight'
11
11
  import type { ChildObservation, LaneObservation, Observations } from './run-progress'
12
12
  import { run_progress_clock } from './run-progress-clock'
13
13
 
@@ -257,7 +257,7 @@ interface LineTiming {
257
257
  * this is that same move for one value.
258
258
  *
259
259
  * **It is a schedule rather than an observation, and the two conditions on it are said in prose**
260
- * (`docs/josh-commands-automation.md` → `josh run:progress`): it holds only while the silence continues, and a
260
+ * (`docs/josh-commands-run.md` → `josh run:progress`): it holds only while the silence continues, and a
261
261
  * real report arriving first restarts the clock through `--mark` and supersedes it. The line printing
262
262
  * it is itself a report, so the clock starts at this observation.
263
263
  */
@@ -8,7 +8,7 @@ import { GATE_COMMAND } from '#scripts/josh/josh-command-types'
8
8
  import { stamp_file } from '#scripts/josh/stamp-file'
9
9
  import { review_stamps } from '#scripts/review/review-stamps'
10
10
  import { review_tree } from '#scripts/review/review-tree'
11
- import { detached_launch, type LaunchArgv, type LaunchResult } from './detached-launch'
11
+ import { detached_launch, type LaunchArgv, type LaunchResult } from '#scripts/run/detached-launch'
12
12
  import { run_review, type GateState, type ReviewTiming, type TimingStart } from './run-review'
13
13
 
14
14
  // The side effects `josh run:review` performs, kept out of `run-review.ts` the way `run-merge-steps.ts`
@@ -114,8 +114,7 @@ function write_timing_start(start: TimingStart, target: string = PROJECT_ROOT):
114
114
  function to_timing(value: unknown): TimingStart | undefined {
115
115
  if (typeof value !== 'object' || value === null) return undefined
116
116
 
117
- const record = value as Record<string, unknown>
118
- const { gate_started_at, review_started_at } = record
117
+ const { gate_started_at, review_started_at } = value as Record<string, unknown>
119
118
 
120
119
  if (typeof gate_started_at !== 'string' || typeof review_started_at !== 'string') return undefined
121
120
 
@@ -4,8 +4,8 @@ import { api_outage } from '#scripts/agent/api-outage'
4
4
  import type { ClaudeResultEvent } from '#scripts/agent/claude-result-event'
5
5
  import { git_gh_issue_read } from '#scripts/gh/git-gh-issue-read'
6
6
  import { issue_state } from '#scripts/issue/issue-state'
7
- import { run_cut } from './run-cut'
8
- import { run_hold } from './run-hold'
7
+ import { run_cut } from '#scripts/run/cut/run-cut'
8
+ import { run_hold } from '#scripts/run/hold/run-hold'
9
9
  import { run_issue_number } from './run-issue-number'
10
10
  import { run_liveness } from './run-liveness'
11
11
 
@@ -1,4 +1,9 @@
1
- import { run_hold, type HoldRead, type RunHold, type StopMarkFields } from './run-hold'
1
+ import {
2
+ run_hold,
3
+ type HoldRead,
4
+ type RunHold,
5
+ type StopMarkFields,
6
+ } from '#scripts/run/hold/run-hold'
2
7
 
3
8
  // joshuafolkken/kit#2796: a `halfrun` stops before its commit and **keeps** its hold, because the
4
9
  // uncommitted, hand-verified work is exactly what a second run would trample. The person then types
@@ -1,7 +1,7 @@
1
1
  import { lane_child_marker } from '#scripts/lane/lane-child-marker'
2
2
  import { lane_reap } from '#scripts/lane/lane-reap'
3
3
  import { lane_registry } from '#scripts/lane/lane-registry'
4
- import { run_carry, type CarryRead, type RunCarry } from './run-carry'
4
+ import { run_carry, type CarryRead, type RunCarry } from '#scripts/run/carry/run-carry'
5
5
 
6
6
  // The headless `backlogrun` parent (joshuafolkken/kit#2437). `run:wake` starts a cut's successor as
7
7
  // `claude -p`, and there a turn that ends is the process that ends: its background `lane:await` and