@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
@@ -60,6 +60,20 @@ interface CommandEntry {
60
60
  // listing carries only what a consumer can run (joshuafolkken/kit#1988). The audience in
61
61
  // `reference` separately decides whether the command appears in the default listing.
62
62
  is_kit_only?: boolean
63
+ // Pre-built to `dist/commands/` so a consumer's `dist/josh.js` imports it in its own process
64
+ // instead of spawning tsx for it (joshuafolkken/kit#3328, `docs/maintainers/runtime-bundling.md`).
65
+ is_bundled?: boolean
66
+ // The cores the command reserves from the machine-wide budget before it starts its heavy tools
67
+ // (joshuafolkken/kit#3345). `josh-logic.ts` claims them at the one dispatch point every command
68
+ // passes through, so the command only declares the number. A function means the weight is read
69
+ // when the command starts: the unit suite's share depends on what else is running at that moment.
70
+ // **The edit hook declares none, on purpose.** It formats one file per edit and finishes in well
71
+ // under a second, so a wait for room on the machine would stall every edit for the length of
72
+ // another lane's check.
73
+ core_weight?: number | (() => number)
74
+ // The memory the command's tools hold, claimed with its cores (joshuafolkken/kit#3371); read like
75
+ // `core_weight`, and none declared is none waited for.
76
+ memory_mb?: number | (() => number)
63
77
  }
64
78
 
65
79
  // The name `josh gate` registers under. It lives here rather than in `verification-gate.ts` so a
@@ -143,14 +143,14 @@ const AI_COMMANDS: Record<string, CommandEntry> = {
143
143
  reference: ['[<owner/repo>]', 'automation', ['none']],
144
144
  },
145
145
  'run:merge': {
146
- script: 'scripts/run/run-merge-cli.ts',
146
+ script: 'scripts/run/merge/run-merge-cli.ts',
147
147
  description:
148
148
  'Collapse a backlogrun merge event into one call: confirm the child, do the post-merge steps, offer the next child',
149
149
  category: 'AI tools',
150
150
  reference: [ISSUE_WITH_OPTIONS, 'automation', ['git', 'network']],
151
151
  },
152
152
  'run:review': {
153
- script: 'scripts/run/run-review-cli.ts',
153
+ script: 'scripts/run/review/run-review-cli.ts',
154
154
  description:
155
155
  'Start the gate in the background and print the /code-review brief in one call so the two overlap (--join to join the gate and check its verdict)',
156
156
  category: 'AI tools',
@@ -171,7 +171,7 @@ const AI_COMMANDS: Record<string, CommandEntry> = {
171
171
  // (`run:tail`) were four round trips re-billing the run's full context each. It stops at the first
172
172
  // failed step and names it, so the run reads only the step to fix.
173
173
  ship: {
174
- script: 'scripts/run/run-ship-cli.ts',
174
+ script: 'scripts/run/ship/run-ship-cli.ts',
175
175
  description:
176
176
  'Ship a change in one call: gate, commit/push/PR, the CI-wait merge and the report bookkeeping, stopping at the first failed step',
177
177
  category: 'AI tools',
@@ -182,7 +182,7 @@ const AI_COMMANDS: Record<string, CommandEntry> = {
182
182
  ],
183
183
  },
184
184
  'run:event': {
185
- script: 'scripts/run/run-event-cli.ts',
185
+ script: 'scripts/run/event/run-event-cli.ts',
186
186
  description:
187
187
  'Append to, read or watch the run’s append-only event stream (--append <kind> <text> | --from|--follow <n> | --watch [<n>] | --last)',
188
188
  category: 'AI tools',
@@ -1,4 +1,4 @@
1
- import type { CommandEntry } from './josh-command-types'
1
+ import { OPTIONAL_ENV_FILE_FLAGS, type CommandEntry } from './josh-command-types'
2
2
 
3
3
  // The `backlog:*` command registry, split out of `josh-commands-ai.ts` so that file stays under its
4
4
  // 300-code-line limit, exactly as `LANE_COMMANDS` and `SPLIT_COMMANDS` were for the same reason
@@ -41,6 +41,9 @@ const BACKLOG_COMMANDS: Record<string, CommandEntry> = {
41
41
  },
42
42
  'backlog:stalled': {
43
43
  script: 'scripts/backlog/backlog-stalled-cli.ts',
44
+ // A stall sends one Telegram warning (joshuafolkken/kit#3357). The `Stop` hook calls the detector
45
+ // directly, so this flag costs only the manual command its in-process dispatch.
46
+ tsx_arguments: OPTIONAL_ENV_FILE_FLAGS,
44
47
  description:
45
48
  'Report whether ready backlog work is sitting undispatched with a free lane and no recent dispatch',
46
49
  category: 'AI tools',
@@ -1,3 +1,5 @@
1
+ import { core_budget } from '#scripts/gate/core-budget'
2
+ import { gate_plan } from '#scripts/gate/gate-plan'
1
3
  import { GATE_COMMAND, type CommandEntry } from './josh-command-types'
2
4
 
3
5
  const FILE_ARGUMENTS = '[files...]'
@@ -25,18 +27,24 @@ const DEV_COMMANDS: Record<string, CommandEntry> = {
25
27
  description: 'Check code with prettier and eslint (skips a tool a basic project lacks)',
26
28
  category: 'Development',
27
29
  reference: ['', 'developer', ['processes']],
30
+ core_weight: core_budget.CORE_WEIGHTS.lint,
31
+ memory_mb: core_budget.MEMORY_MB.lint,
28
32
  },
29
33
  'lint:related': {
30
34
  script: 'scripts/lint/lint-related.ts',
31
35
  description: 'Check only the changed files with prettier and eslint (whole tree on fallback)',
32
36
  category: 'Development',
33
37
  reference: [FILE_ARGUMENTS, 'developer', ['processes']],
38
+ core_weight: core_budget.CORE_WEIGHTS.lint,
39
+ memory_mb: core_budget.MEMORY_MB.lint,
34
40
  },
35
41
  lines: {
36
42
  script: 'scripts/lines/lines-command.ts',
37
43
  description: "Print a file's code lines against the max-lines limit and the headroom left",
38
44
  category: 'Development',
39
45
  reference: [REQUIRED_FILE_ARGUMENTS, 'developer', ['none']],
46
+ core_weight: core_budget.CORE_WEIGHTS.eslint_scan,
47
+ memory_mb: core_budget.MEMORY_MB.eslint_scan,
40
48
  },
41
49
  'refactor:scan': {
42
50
  script: 'scripts/refactor/refactor-scan-cli.ts',
@@ -44,6 +52,8 @@ const DEV_COMMANDS: Record<string, CommandEntry> = {
44
52
  'List refactoring candidates in the changed scope by category and answer clear/candidates',
45
53
  category: 'Development',
46
54
  reference: ['', 'automation', ['processes']],
55
+ core_weight: core_budget.CORE_WEIGHTS.eslint_scan,
56
+ memory_mb: core_budget.MEMORY_MB.eslint_scan,
47
57
  },
48
58
  bytes: {
49
59
  script: 'scripts/lines/bytes-command.ts',
@@ -130,6 +140,8 @@ const DEV_COMMANDS: Record<string, CommandEntry> = {
130
140
  description: 'Run spell check including dotfiles',
131
141
  category: 'Development',
132
142
  reference: ['', 'developer', ['processes']],
143
+ core_weight: core_budget.CORE_WEIGHTS.spell_check,
144
+ memory_mb: core_budget.MEMORY_MB.spell_check,
133
145
  },
134
146
  behavior: {
135
147
  script: 'scripts/behavior/behavior-cli.ts',
@@ -151,12 +163,16 @@ const DEV_COMMANDS: Record<string, CommandEntry> = {
151
163
  'Run unit tests with Vitest (skips when Vitest is absent; fails when it has no tests)',
152
164
  category: 'Development',
153
165
  reference: [FILTER_ARGUMENTS, 'developer', ['processes']],
166
+ core_weight: gate_plan.direct_unit_weight,
167
+ memory_mb: gate_plan.direct_unit_memory,
154
168
  },
155
169
  'test:related': {
156
170
  script: 'scripts/test/test-related.ts',
157
171
  description: 'Run only the unit tests related to the changed files (full suite on fallback)',
158
172
  category: 'Development',
159
173
  reference: [FILE_ARGUMENTS, 'developer', ['processes']],
174
+ core_weight: gate_plan.direct_unit_weight,
175
+ memory_mb: gate_plan.direct_unit_memory,
160
176
  },
161
177
  'test:declared': {
162
178
  script: 'scripts/test/test-declared.ts',
@@ -203,6 +219,8 @@ const DEV_COMMANDS: Record<string, CommandEntry> = {
203
219
  description: 'Type-check with tsc (skips a basic project with no TypeScript to check)',
204
220
  category: 'Development',
205
221
  reference: ['[arguments...]', 'developer', ['processes']],
222
+ core_weight: core_budget.CORE_WEIGHTS.type_check,
223
+ memory_mb: core_budget.MEMORY_MB.type_check,
206
224
  },
207
225
  port: {
208
226
  script: 'scripts/ports/port-command.ts',
@@ -13,6 +13,7 @@ const DOCUMENT_COMMANDS: Record<string, CommandEntry> = {
13
13
  description: 'Print one section of a markdown document, for a `file.md` → "Heading" reference',
14
14
  category: 'AI tools',
15
15
  reference: ['<file> <heading>', 'automation', ['none']],
16
+ is_bundled: true,
16
17
  },
17
18
  'read:set': {
18
19
  script: 'scripts/document/read-set-cli.ts',
@@ -69,11 +69,18 @@ const ISSUE_COMMANDS: Record<string, CommandEntry> = {
69
69
  'File an Issue with every filing step: lint, Origin, WIP cap, duplicate scout, labels, then epic:bundle',
70
70
  category: 'AI tools',
71
71
  reference: [
72
- '<title> --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>] [--distinct <N,…>] [--over-cap] [--no-auto-ok]',
72
+ '<title> --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>] [--distinct <N,…>] [--over-cap] [--no-auto-ok] [--release]',
73
73
  'automation',
74
74
  ['network'],
75
75
  ],
76
76
  },
77
+ 'issue:release': {
78
+ script: 'scripts/issue/issue-release-cli.ts',
79
+ description:
80
+ "Link an Issue to the repository's open release Issue as its blocker, filing one when none is open",
81
+ category: 'AI tools',
82
+ reference: ['<issue>', 'automation', ['network']],
83
+ },
77
84
  }
78
85
  /* eslint-enable @typescript-eslint/naming-convention */
79
86
 
@@ -9,6 +9,10 @@ const LANE_SCRIPT = 'scripts/lane/lane-cli.ts'
9
9
  // has to read `.env` to see them — without this the two are documented and unreachable.
10
10
  const LANE_ARGUMENTS = { script: LANE_SCRIPT, tsx_arguments: OPTIONAL_ENV_FILE_FLAGS } as const
11
11
  const ISSUE_WITH_OPTIONS = '<issue> [options]'
12
+ const MEASURE_ARGUMENTS = {
13
+ script: 'scripts/lane/lane-measure-cli.ts',
14
+ tsx_arguments: OPTIONAL_ENV_FILE_FLAGS,
15
+ } as const
12
16
 
13
17
  /* eslint-disable @typescript-eslint/naming-convention */
14
18
  const LANE_COMMANDS: Record<string, CommandEntry> = {
@@ -35,7 +39,8 @@ const LANE_COMMANDS: Record<string, CommandEntry> = {
35
39
  },
36
40
  'lane:prune': {
37
41
  ...LANE_ARGUMENTS,
38
- description: 'Close every lane an interruption left without its work tree',
42
+ description:
43
+ 'Close every lane an interruption left without its work tree, then sweep unregistered leftovers under the lanes root',
39
44
  category: 'AI tools',
40
45
  reference: ['', 'automation', ['files', 'git']],
41
46
  default_script_arguments: ['prune'],
@@ -69,6 +74,24 @@ const LANE_COMMANDS: Record<string, CommandEntry> = {
69
74
  category: 'AI tools',
70
75
  reference: ['<issue> [--stash <message>]', 'automation', ['files', 'git', 'processes']],
71
76
  },
77
+ // The lane-limit measurement (joshuafolkken/kit#3355): `.env` is read so `lane:stats` labels the row
78
+ // with the `JOSH_LANE_LIMIT` a person set there.
79
+ 'lane:sample': {
80
+ ...MEASURE_ARGUMENTS,
81
+ description:
82
+ 'Record the machine load (load average, swap, free memory, working lanes) to the lane ledger',
83
+ category: 'AI tools',
84
+ reference: ['[--every <seconds>]', 'maintainer', ['files']],
85
+ default_script_arguments: ['sample'],
86
+ },
87
+ 'lane:stats': {
88
+ ...MEASURE_ARGUMENTS,
89
+ description:
90
+ 'Print one table row of lane throughput, gate duration and machine load over a period',
91
+ category: 'AI tools',
92
+ reference: ['--period <days> [--limit <lane-limit>]', 'maintainer', ['none']],
93
+ default_script_arguments: ['stats'],
94
+ },
72
95
  }
73
96
  /* eslint-enable @typescript-eslint/naming-convention */
74
97
 
@@ -21,7 +21,7 @@ const MAINTENANCE_COMMANDS: Record<string, CommandEntry> = {
21
21
  script: 'scripts/overrides/overrides-check.ts',
22
22
  description: 'Check pnpm overrides for drift',
23
23
  category: 'Maintenance',
24
- reference: ['[--save]', 'maintainer', ['files']],
24
+ reference: ['[--save]', 'developer', ['files']],
25
25
  },
26
26
  audit: {
27
27
  script: 'scripts/security/security-audit.ts',
@@ -45,11 +45,11 @@ const MAINTENANCE_COMMANDS: Record<string, CommandEntry> = {
45
45
  shell: [
46
46
  'sh',
47
47
  '-c',
48
- 'export NODE_AUTH_TOKEN=$(gh auth token) && pnpm josh latest:guard && pnpm josh latest:corepack && pnpm josh latest:update && pnpm josh ranges && pnpm josh audit && pnpm josh latest:scope --record',
48
+ 'export NODE_AUTH_TOKEN=$(gh auth token) && pnpm josh latest:guard && pnpm josh latest:update && pnpm josh ranges && pnpm josh audit && pnpm josh latest:corepack && pnpm josh latest:scope --record',
49
49
  ],
50
- description: 'Update pnpm, dependencies, and run security audit',
50
+ description: 'Update dependencies, run security audit, then update pnpm',
51
51
  category: 'Maintenance',
52
- reference: ['', 'maintainer', ['files', 'network', 'processes']],
52
+ reference: ['', 'developer', ['files', 'network', 'processes']],
53
53
  argument_targets: ['latest:corepack', 'latest:update', 'audit'],
54
54
  },
55
55
  'latest:scope': {
@@ -73,13 +73,13 @@ const MAINTENANCE_COMMANDS: Record<string, CommandEntry> = {
73
73
  script: 'scripts/version/latest-corepack.ts',
74
74
  description: 'Update pnpm on the current major while preserving the integrity pin',
75
75
  category: 'Maintenance',
76
- reference: ['', 'maintainer', ['files', 'network']],
76
+ reference: ['', 'developer', ['files', 'network']],
77
77
  },
78
78
  'latest:update': {
79
79
  script: 'scripts/version/latest-update.ts',
80
80
  description: 'Update all dependencies to latest',
81
81
  category: 'Maintenance',
82
- reference: ['', 'maintainer', ['files', 'network']],
82
+ reference: ['', 'developer', ['files', 'network']],
83
83
  },
84
84
  }
85
85
  /* eslint-enable @typescript-eslint/naming-convention */
@@ -6,7 +6,7 @@ import { OPTIONAL_ENV_FILE_FLAGS, type CommandEntry } from './josh-command-types
6
6
  // the generated catalog keeps their order.
7
7
 
8
8
  // One script answers both `run:hold` and `run:release`; the flag below is what tells them apart.
9
- const RUN_HOLD_SCRIPT = 'scripts/run/run-hold-cli.ts'
9
+ const RUN_HOLD_SCRIPT = 'scripts/run/hold/run-hold-cli.ts'
10
10
 
11
11
  /* eslint-disable @typescript-eslint/naming-convention */
12
12
  const RUN_COMMANDS: Record<string, CommandEntry> = {
@@ -24,19 +24,22 @@ const RUN_COMMANDS: Record<string, CommandEntry> = {
24
24
  default_script_arguments: ['--release'],
25
25
  },
26
26
  'run:tidy': {
27
- script: 'scripts/run/run-tidy-cli.ts',
27
+ script: 'scripts/run/tidy/run-tidy-cli.ts',
28
28
  description: 'Close merged lanes and drop stashes whose issues are all merged',
29
29
  category: 'AI tools',
30
30
  reference: ['', 'automation', ['git', 'network', 'files']],
31
31
  },
32
32
  'run:carry': {
33
- script: 'scripts/run/run-carry-cli.ts',
33
+ script: 'scripts/run/carry/run-carry-cli.ts',
34
+ // `--stopped` sends the stop confirmation, so the Telegram credentials come from `.env` as for
35
+ // `run:wake` below (joshuafolkken/kit#3357).
36
+ tsx_arguments: OPTIONAL_ENV_FILE_FLAGS,
34
37
  description: 'Carry one invocation’s budget across its own session cuts',
35
38
  category: 'AI tools',
36
39
  reference: ['<operation> [arguments...]', 'automation', ['files']],
37
40
  },
38
41
  'run:wake': {
39
- script: 'scripts/run/run-wake-cli.ts',
42
+ script: 'scripts/run/wake/run-wake-cli.ts',
40
43
  // `.env` rather than the ambient environment:
41
44
  // the failure warning needs the Telegram credentials, the same
42
45
  // reasons `notify` and `followup` carry these flags.
@@ -46,7 +49,7 @@ const RUN_COMMANDS: Record<string, CommandEntry> = {
46
49
  reference: ['[options]', 'automation', ['processes', 'notifications']],
47
50
  },
48
51
  'run:cut': {
49
- script: 'scripts/run/run-cut-cli.ts',
52
+ script: 'scripts/run/cut/run-cut-cli.ts',
50
53
  description: 'Cut a lane child before the gate and resume a fresh process',
51
54
  category: 'AI tools',
52
55
  reference: ['[--resume] <issue> [--impl] [--handoff <path>]', 'automation', ['files']],
@@ -64,7 +67,7 @@ const RUN_COMMANDS: Record<string, CommandEntry> = {
64
67
  reference: ['<issue> --output <path> [--repo <owner/repo>]', 'automation', ['network']],
65
68
  },
66
69
  'run:progress': {
67
- script: 'scripts/run/run-progress-cli.ts',
70
+ script: 'scripts/run/progress/run-progress-cli.ts',
68
71
  description: 'Report an unattended run’s progress once it has gone quiet for an interval',
69
72
  category: 'AI tools',
70
73
  reference: [
@@ -83,7 +86,9 @@ const RUN_COMMANDS: Record<string, CommandEntry> = {
83
86
  // read the budget, gather the issue reads and decide the pre-implementation step. `run:hold`,
84
87
  // `cost --cut`, `run:prep` and `run:step` were four round trips re-billing a lane's full context each.
85
88
  'run:entry': {
86
- script: 'scripts/run/run-entry-cli.ts',
89
+ script: 'scripts/run/entry/run-entry-cli.ts',
90
+ // A `busy` hold or an `over` budget sends the stop confirmation (joshuafolkken/kit#3357).
91
+ tsx_arguments: OPTIONAL_ENV_FILE_FLAGS,
87
92
  description:
88
93
  'Open a run in one call: claim the tree, read the budget, bundle the reads, decide the pre-implementation step',
89
94
  category: 'AI tools',
@@ -1,4 +1,5 @@
1
1
  import { realpathSync } from 'node:fs'
2
+ import path from 'node:path'
2
3
  import { pathToFileURL } from 'node:url'
3
4
  import type { CommandEntry } from './josh-command-types'
4
5
 
@@ -8,26 +9,44 @@ import type { CommandEntry } from './josh-command-types'
8
9
  // (joshuafolkken/kit#1342). The script is ordinary TypeScript and a TypeScript loader is already
9
10
  // installed by the time this file runs, so the dispatcher evaluates the script itself instead.
10
11
  const TYPESCRIPT_EXTENSION = '.ts'
12
+ const JAVASCRIPT_EXTENSION = '.js'
13
+ const BUNDLED_COMMAND_DIRECTORY = path.join('dist', 'commands')
11
14
  const FAILURE_EXIT_CODE = 1
12
15
 
13
16
  // The dispatcher may only load a `.ts` script in its own process when it was itself loaded as
14
17
  // TypeScript — which is exactly the condition under which a loader capable of it is present. A
15
- // consumer runs the bundled `dist/josh.js` under plain node, whose `import.meta.url` ends in `.js`,
16
- // so that install keeps the spawning path unchanged rather than failing on a module node cannot
17
- // load at all.
18
+ // consumer runs the bundled `dist/josh.js` under plain node, whose `import.meta.url` ends in `.js`.
18
19
  function is_typescript_dispatcher(dispatcher_url: string): boolean {
19
20
  return dispatcher_url.endsWith(TYPESCRIPT_EXTENSION)
20
21
  }
21
22
 
23
+ // A command marked `is_bundled` is pre-built to `dist/commands/<script basename>.js` by
24
+ // `scripts/build/build-commands.ts` (joshuafolkken/kit#3328). The path is derived here, in a module
25
+ // the dispatcher bundle already carries, so the build and the dispatcher cannot name two locations.
26
+ function bundled_script_path(package_directory: string, script: string): string {
27
+ const name = `${path.basename(script, TYPESCRIPT_EXTENSION)}${JAVASCRIPT_EXTENSION}`
28
+
29
+ return path.join(package_directory, BUNDLED_COMMAND_DIRECTORY, name)
30
+ }
31
+
32
+ // The file this dispatcher imports in its own process, or `undefined` to spawn tsx instead.
22
33
  // `tsx_arguments` are node flags the script needs *before* its own code runs — today every one of
23
34
  // them a form of `--env-file`, which has no in-process equivalent that reproduces node's own
24
35
  // parsing and precedence. Those commands (`doctor`, `latest:scope`, `followup`, `notify`) keep a
25
36
  // process of their own; each runs at most a few times per run, so none of them is where the cost
26
- // this saves accumulates.
27
- function can_run_in_process(entry: CommandEntry, dispatcher_url: string): boolean {
28
- if (entry.script === undefined || entry.tsx_arguments !== undefined) return false
37
+ // this saves accumulates. Under plain node, which cannot load a `.ts` script at all, only a
38
+ // pre-built command runs in-process; every other one keeps spawning tsx.
39
+ function in_process_target(
40
+ entry: CommandEntry,
41
+ package_directory: string,
42
+ dispatcher_url: string,
43
+ ): string | undefined {
44
+ if (entry.script === undefined || entry.tsx_arguments !== undefined) return undefined
45
+ if (is_typescript_dispatcher(dispatcher_url)) return path.join(package_directory, entry.script)
29
46
 
30
- return is_typescript_dispatcher(dispatcher_url)
47
+ return entry.is_bundled === true
48
+ ? bundled_script_path(package_directory, entry.script)
49
+ : undefined
31
50
  }
32
51
 
33
52
  // `process.exitCode` is typed `number | string | undefined`. Only the numeric form is an exit code
@@ -75,6 +94,6 @@ async function run_in_process(
75
94
  return read_exit_code()
76
95
  }
77
96
 
78
- const josh_in_process = { can_run_in_process, run_in_process }
97
+ const josh_in_process = { bundled_script_path, in_process_target, run_in_process }
79
98
 
80
- export { FAILURE_EXIT_CODE, josh_in_process }
99
+ export { BUNDLED_COMMAND_DIRECTORY, FAILURE_EXIT_CODE, josh_in_process }
@@ -2,6 +2,8 @@ import { existsSync, readFileSync } from 'node:fs'
2
2
  import path from 'node:path'
3
3
  import { fileURLToPath } from 'node:url'
4
4
  import { resolve_local_bin, resolve_package_bin } from '#scripts/build/local-bin'
5
+ import { core_budget } from '#scripts/gate/core-budget'
6
+ import { ancestor_directories } from '#scripts/lib/ancestor-directories'
5
7
  import { package_version_schema } from '#scripts/lib/schemas'
6
8
  import { resolve_spawn_exit } from '#scripts/lib/spawn-exit'
7
9
  import { execaSync } from 'execa'
@@ -37,15 +39,11 @@ interface TsxRunner {
37
39
  // from the bundled dist/josh.js (one level under the root) and from the tsx source at
38
40
  // scripts/josh/ (two levels), so this file's depth no longer has to be hard-coded.
39
41
  function find_package_directory(start_directory: string): string {
40
- let current = start_directory
41
-
42
- while (!existsSync(path.join(current, PACKAGE_JSON))) {
43
- const parent = path.dirname(current)
44
- if (parent === current) return start_directory
45
- current = parent
46
- }
47
-
48
- return current
42
+ return (
43
+ ancestor_directories.nearest(start_directory, (directory) =>
44
+ existsSync(path.join(directory, PACKAGE_JSON)),
45
+ ) ?? start_directory
46
+ )
49
47
  }
50
48
 
51
49
  const PACKAGE_DIR = find_package_directory(path.dirname(fileURLToPath(import.meta.url)))
@@ -226,14 +224,12 @@ async function run_script_entry(
226
224
  entry: CommandEntry,
227
225
  subcommand_arguments: Array<string>,
228
226
  ): Promise<number> {
229
- const script_path = path.join(PACKAGE_DIR, entry.script ?? '')
230
227
  const script_arguments = [...(entry.default_script_arguments ?? []), ...subcommand_arguments]
228
+ const target = josh_in_process.in_process_target(entry, PACKAGE_DIR, import.meta.url)
231
229
 
232
- if (josh_in_process.can_run_in_process(entry, import.meta.url)) {
233
- return await josh_in_process.run_in_process(script_path, script_arguments)
234
- }
230
+ if (target !== undefined) return await josh_in_process.run_in_process(target, script_arguments)
235
231
 
236
- return spawn_script_entry(entry, script_path, script_arguments)
232
+ return spawn_script_entry(entry, path.join(PACKAGE_DIR, entry.script ?? ''), script_arguments)
237
233
  }
238
234
 
239
235
  function github_prerequisite_exit(resolved: string, is_consumer: boolean): number | undefined {
@@ -274,7 +270,7 @@ function pre_dispatch_exit(
274
270
  return USAGE_ERROR_EXIT_CODE
275
271
  }
276
272
 
277
- async function dispatch_entry(
273
+ async function run_entry(
278
274
  entry: CommandEntry,
279
275
  subcommand_arguments: Array<string>,
280
276
  ): Promise<number> {
@@ -283,6 +279,29 @@ async function dispatch_entry(
283
279
  return await run_script_entry(entry, subcommand_arguments)
284
280
  }
285
281
 
282
+ function declared(value: number | (() => number) | undefined): number | undefined {
283
+ return typeof value === 'function' ? value() : value
284
+ }
285
+
286
+ // **Every command passes through here, so this is where a declared weight is reserved**
287
+ // (joshuafolkken/kit#3345). A heavy command run directly, outside `josh gate`, used to start its tools
288
+ // without claiming a place. A command under a parent that already holds its cores claims nothing:
289
+ // `core_budget.with_command_reservation` reads the mark that parent set.
290
+ async function dispatch_entry(
291
+ entry: CommandEntry,
292
+ subcommand_arguments: Array<string>,
293
+ ): Promise<number> {
294
+ const weight = declared(entry.core_weight)
295
+
296
+ if (weight === undefined) return await run_entry(entry, subcommand_arguments)
297
+
298
+ return await core_budget.with_command_reservation(
299
+ weight,
300
+ async () => await run_entry(entry, subcommand_arguments),
301
+ { memory_mb: declared(entry.memory_mb) },
302
+ )
303
+ }
304
+
286
305
  async function run_command(
287
306
  cmd: string,
288
307
  subcommand_arguments: Array<string>,
@@ -3,6 +3,7 @@ import { randomUUID } from 'node:crypto'
3
3
  import { readFileSync, rmSync } from 'node:fs'
4
4
  import { createServer, type Server } from 'node:net'
5
5
  import path from 'node:path'
6
+ import { PROBE_TIMEOUT_MS } from '#scripts/lib/timeouts'
6
7
  import { PLATFORM_TEMP_ROOT } from './platform-temporary'
7
8
 
8
9
  // Whether the process a record names is still the one that wrote it (joshuafolkken/kit#1245).
@@ -48,9 +49,6 @@ const PID_FLAG = '-p'
48
49
  // runs in** — nothing is inherited, so the token depends on the process being asked about and on
49
50
  // nothing whatever about who is asking.
50
51
  const PROBE_ENVIRONMENT = { TZ: 'UTC', LC_ALL: 'C' }
51
- // A probe that hung would hang `josh review:brief`, `josh bench` and the unit suite's worker share
52
- // alike. Failing is harmless here: it answers "cannot tell", which every caller already handles.
53
- const PROBE_TIMEOUT_MS = 2000
54
52
  // `process.kill(pid, 0)` runs every permission check and delivers nothing, so it is the standard
55
53
  // liveness probe: it throws `ESRCH` where the process is gone.
56
54
  const LIVENESS_SIGNAL = 0
@@ -20,16 +20,16 @@ import { session_language, type Resolution } from './session-language'
20
20
 
21
21
  const { DEFAULT_SESSION_LANG, ENV_KEY, resolve_session_lang } = session_language
22
22
  const ENGLISH_OPT_IN_LANG = 'en'
23
- const SCOPE_NOTE =
24
- 'write session dialogue, AskUserQuestion labels/descriptions and artifact prose (Issue bodies, comments, Telegram) in this language. English stays only for Issue/PR titles, code comments/test titles/commit messages, and script-fixed strings.'
25
23
 
26
24
  // The file load happens in `main`, on the command path only; the resolver reads the environment.
25
+ // The line carries the value alone: what the language covers is `CLAUDE.md` → "Output language",
26
+ // already in context every turn, so repeating it here only spent context on each prompt.
27
27
  function format_line(resolution: Resolution): string {
28
28
  const suffix = resolution.is_default
29
29
  ? ` (default; set ${ENV_KEY}=${ENGLISH_OPT_IN_LANG} for English)`
30
30
  : ''
31
31
 
32
- return `Session language (${ENV_KEY}): ${resolution.lang}${suffix} — ${SCOPE_NOTE}`
32
+ return `Session language (${ENV_KEY}): ${resolution.lang}${suffix}`
33
33
  }
34
34
 
35
35
  function main(): void {
@@ -42,7 +42,6 @@ const session_language_cli = {
42
42
  ENV_KEY,
43
43
  format_line,
44
44
  resolve_session_lang,
45
- SCOPE_NOTE,
46
45
  }
47
46
 
48
47
  if (process.argv[1] === fileURLToPath(import.meta.url)) main()
@@ -1,6 +1,7 @@
1
1
  import { spawnSync } from 'node:child_process'
2
2
  import { setTimeout as sleep } from 'node:timers/promises'
3
3
  import { parseArgs } from 'node:util'
4
+ import { PROBE_TIMEOUT_MS } from '#scripts/lib/timeouts'
4
5
  import { run_liveness } from '#scripts/run/run-liveness'
5
6
  import { lane_child_invocation } from './lane-child-invocation'
6
7
  import { lane_handoff } from './lane-handoff'
@@ -66,7 +67,10 @@ interface RunConfig extends CheckConfig {
66
67
 
67
68
  function is_process_running_default(issue: string): boolean {
68
69
  const pattern = lane_child_invocation.process_pattern(issue)
69
- const result = spawnSync('pgrep', ['-f', pattern], { encoding: 'utf8' })
70
+ const result = spawnSync('pgrep', ['-f', pattern], {
71
+ encoding: 'utf8',
72
+ timeout: PROBE_TIMEOUT_MS,
73
+ })
70
74
 
71
75
  if (result.status === PROCESS_FOUND) return true
72
76
 
@@ -1,6 +1,6 @@
1
1
  import { run_issue_number } from '#scripts/run/run-issue-number'
2
- import { run_ship_next, type ShipResume } from '#scripts/run/run-ship-next'
3
- import type { Stage } from '#scripts/run/run-ship-stage'
2
+ import { run_ship_next, type ShipResume } from '#scripts/run/ship/run-ship-next'
3
+ import type { Stage } from '#scripts/run/ship/run-ship-stage'
4
4
 
5
5
  interface ShipStop extends ShipResume {
6
6
  stage: Stage
@@ -2,11 +2,11 @@
2
2
  import { fileURLToPath } from 'node:url'
3
3
  import { epic_busy } from '#scripts/epic/epic-busy'
4
4
  import { git_gh_command } from '#scripts/gh/git-gh-command'
5
- import type { OpenIssueData } from '#scripts/git/schemas'
5
+ import type { OpenIssueData } from '#scripts/git/git-schemas'
6
6
  import { issue_cite, type IssueCiter } from '#scripts/issue/issue-cite'
7
7
  import { error_text } from '#scripts/lib/error-message'
8
- import { run_carry } from '#scripts/run/run-carry'
9
- import { run_carry_reclaim } from '#scripts/run/run-carry-reclaim'
8
+ import { run_carry } from '#scripts/run/carry/run-carry'
9
+ import { run_carry_reclaim } from '#scripts/run/carry/run-carry-reclaim'
10
10
  import { lane_await } from './lane-await'
11
11
  import { lane_close, type CloseOutcome, type SweepOutcome } from './lane-close'
12
12
  import { lane_dispatch, type DispatchOutcome } from './lane-dispatch'
@@ -16,6 +16,7 @@ import { lane_output, type ReadOutcome, type RecordOutcome } from './lane-output
16
16
  import { lane_registry, type LaneInfo } from './lane-registry'
17
17
  import { lane_report } from './lane-report'
18
18
  import { lane_seed_policy } from './lane-seed'
19
+ import { lane_stray } from './lane-stray'
19
20
 
20
21
  // `josh lane:open` / `lane:close` / `lane:list` / `lane:prune` — the lane's whole lifecycle
21
22
  // (joshuafolkken/kit#1490).
@@ -268,7 +269,14 @@ async function list_command(rest: ReadonlyArray<string>): Promise<number> {
268
269
  async function prune_command(rest: ReadonlyArray<string>): Promise<number> {
269
270
  if (rest.length > 0) return report_usage()
270
271
 
271
- return report_sweep(await lane_close.prune_lanes())
272
+ const code = report_sweep(await lane_close.prune_lanes())
273
+
274
+ // After the closes, so a lane whose close left its directory behind is swept in the same run. A
275
+ // kept stray is reported, never a failure: it waits on a person, and a non-zero exit would stop
276
+ // every `backlogrun` preparation until one came (joshuafolkken/kit#3370).
277
+ await lane_stray.sweep_and_report()
278
+
279
+ return code
272
280
  }
273
281
 
274
282
  // The recorded path goes to standard output on both arms, so