@joshuafolkken/kit 1.1178.0 → 1.1229.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 (425) 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 +6 -2
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +23 -2
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +7 -2
  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 +5 -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 +1 -1
  20. package/.claude/skills/workflow-commands/observation-ledger.md +3 -3
  21. package/.claude/skills/workflow-commands/pre-gate-cut.md +6 -1
  22. package/.claude/skills/workflow-commands/prerequisite.md +2 -2
  23. package/.claude/skills/workflow-commands/progress-watcher.md +1 -1
  24. package/.claude/skills/workflow-commands/working-tree-hold.md +1 -1
  25. package/.codex/hooks.json +2 -2
  26. package/.cursorrules +6 -41
  27. package/.github/actions/setup-node/action.yml +1 -1
  28. package/.github/workflows/auto-tag.yml +3 -4
  29. package/.github/workflows/ci.yml +32 -31
  30. package/.github/workflows/dependabot-auto-merge.yml +13 -6
  31. package/.github/workflows/publish.yml +48 -4
  32. package/.github/workflows/sonar-qube.yml +3 -0
  33. package/.pnpmfile.mjs +4 -3
  34. package/.prettierignore +8 -2
  35. package/CLAUDE.md +18 -20
  36. package/README.md +26 -19
  37. package/SECURITY.md +15 -1
  38. package/dist/CLAUDE.md +18 -20
  39. package/dist/commands/document-section-cli.js +734 -0
  40. package/dist/hooks/audit-provision.js +346 -0
  41. package/dist/hooks/batch-guard.js +5 -4
  42. package/dist/hooks/{chunk-S6X6WYKR.js → chunk-55HHG5PX.js} +1210 -711
  43. package/dist/hooks/{chunk-ZAL3NRGL.js → chunk-5VMKCCC4.js} +25 -10
  44. package/dist/hooks/chunk-5VNDSNG3.js +12 -0
  45. package/dist/hooks/{chunk-32GQTL4F.js → chunk-6HJJXRBX.js} +4 -2
  46. package/dist/hooks/chunk-CDY4NFQG.js +15 -0
  47. package/dist/hooks/chunk-ELCN5LCH.js +135 -0
  48. package/dist/hooks/{chunk-VESKRQOF.js → chunk-F56MFS4B.js} +3 -3
  49. package/dist/hooks/{chunk-UAGLLIGZ.js → chunk-FIVDHQGT.js} +7 -6
  50. package/dist/hooks/{chunk-3V37IID6.js → chunk-JBBMAPC4.js} +23 -14
  51. package/dist/hooks/{chunk-G6KRCKEC.js → chunk-JUDKDCDP.js} +496 -378
  52. package/dist/hooks/{chunk-GDS5N2KB.js → chunk-NV2JRZZO.js} +718 -681
  53. package/dist/hooks/{chunk-VQLLNFNT.js → chunk-RNWHN5BP.js} +3 -3
  54. package/dist/hooks/{chunk-DO6NWWHU.js → chunk-TQNPDZNH.js} +4 -4
  55. package/dist/hooks/{chunk-I4XSL4TT.js → chunk-VC3PZPZO.js} +1 -1
  56. package/dist/hooks/codex-hook-adapter.js +14 -12
  57. package/dist/hooks/duplicate-read-guard.js +6 -5
  58. package/dist/hooks/format-edited.js +4 -3
  59. package/dist/hooks/inputs.json +217 -195
  60. package/dist/hooks/investigation-guard.js +6 -5
  61. package/dist/hooks/pretool-guard.js +12 -10
  62. package/dist/hooks/session-lang.js +2 -4
  63. package/dist/hooks/stop-guard.js +66 -58
  64. package/dist/josh.js +868 -74
  65. package/dist/version/index.d.ts +7 -2
  66. package/dist/version/index.js +152 -75
  67. package/eslint/base.js +23 -1
  68. package/eslint/rules/code-quality.js +3 -0
  69. package/eslint/rules/early-return-one-liner.js +98 -0
  70. package/eslint/rules/unicorn.js +16 -1
  71. package/package.json +7 -6
  72. package/pnpm-workspace.yaml +9 -4
  73. package/prettier/basic.d.ts +3 -1
  74. package/prettier/index.d.ts +3 -1
  75. package/prettier/static.d.ts +3 -1
  76. package/prompts/coding-standards.md +1 -1
  77. package/prompts/collaboration-workflow/file-edits.md +4 -4
  78. package/prompts/collaboration-workflow/glossary.md +1 -1
  79. package/prompts/collaboration-workflow/operating-rules.md +17 -9
  80. package/prompts/collaboration-workflow/overview.md +2 -2
  81. package/prompts/collaboration-workflow/principles.md +14 -12
  82. package/prompts/collaboration-workflow/report-format.md +1 -1
  83. package/prompts/collaboration-workflow/residency.md +1 -1
  84. package/prompts/collaboration-workflow/rule-delivery.md +6 -6
  85. package/prompts/collaboration-workflow/shell-body.md +6 -6
  86. package/prompts/collaboration-workflow/turn-batching.md +1 -1
  87. package/prompts/collaboration-workflow/upstream-interrupt.md +12 -2
  88. package/prompts/collaboration-workflow/wip-cap.md +10 -10
  89. package/prompts/review-rubric.md +1 -2
  90. package/prompts/review.md +1 -1
  91. package/scripts/agent/agent-headless.ts +29 -0
  92. package/scripts/agent/agent-launch-environment.ts +6 -2
  93. package/scripts/agent/codex-agent-argv.ts +2 -1
  94. package/scripts/auto-ok/auto-ok-cli.ts +1 -1
  95. package/scripts/backlog/backlog-arrival.ts +3 -3
  96. package/scripts/backlog/backlog-budget.ts +1 -1
  97. package/scripts/backlog/backlog-drive-args.ts +135 -0
  98. package/scripts/backlog/backlog-drive-cli.ts +11 -137
  99. package/scripts/backlog/backlog-drive-launch.ts +39 -0
  100. package/scripts/backlog/backlog-drive-named-offer.ts +3 -5
  101. package/scripts/backlog/backlog-drive-named.ts +3 -3
  102. package/scripts/backlog/backlog-drive-offer-argv.ts +1 -1
  103. package/scripts/backlog/backlog-drive-owner.ts +1 -1
  104. package/scripts/backlog/backlog-drive-restore.ts +1 -1
  105. package/scripts/backlog/backlog-drive-retrospective.ts +1 -1
  106. package/scripts/backlog/backlog-drive.ts +1 -1
  107. package/scripts/backlog/backlog-next.ts +16 -5
  108. package/scripts/backlog/backlog-offer-cli.ts +6 -6
  109. package/scripts/backlog/backlog-offer.ts +1 -1
  110. package/scripts/backlog/backlog-plan-cli.ts +1 -1
  111. package/scripts/backlog/backlog-pool.ts +57 -11
  112. package/scripts/backlog/backlog-ready.ts +1 -1
  113. package/scripts/backlog/backlog-scope.ts +1 -1
  114. package/scripts/backlog/backlog-stalled-detect.ts +2 -2
  115. package/scripts/backlog/backlog-stalled.ts +1 -1
  116. package/scripts/build/build-codex-hooks.ts +3 -1
  117. package/scripts/build/build-commands.ts +66 -0
  118. package/scripts/build/build-hooks.ts +2 -1
  119. package/scripts/build/build-library.ts +12 -3
  120. package/scripts/build/build.ts +70 -0
  121. package/scripts/build/local-bin.ts +3 -13
  122. package/scripts/delegation/investigation-reads.ts +3 -1
  123. package/scripts/discovery/repo-origin.ts +5 -5
  124. package/scripts/doctor/doctor-consumer.ts +2 -2
  125. package/scripts/doctor/doctor-io.ts +2 -3
  126. package/scripts/document/capped-print-part.ts +30 -0
  127. package/scripts/document/capped-print.ts +3 -4
  128. package/scripts/document/document-byte-budget.ts +11 -2
  129. package/scripts/document/document-scan.ts +117 -0
  130. package/scripts/document/document-section.ts +143 -16
  131. package/scripts/document/entry-read-budget.ts +5 -3
  132. package/scripts/document/entry-read-set.ts +10 -89
  133. package/scripts/document/read-set-cost.ts +98 -0
  134. package/scripts/epic/epic-add-body.ts +1 -0
  135. package/scripts/epic/epic-audit-checks.ts +1 -1
  136. package/scripts/epic/epic-audit-rationale.ts +4 -3
  137. package/scripts/epic/epic-bundle-cli.ts +14 -3
  138. package/scripts/epic/epic-bundle-poll.ts +41 -0
  139. package/scripts/epic/epic-busy.ts +1 -1
  140. package/scripts/epic/epic-candidate-confirm.ts +3 -2
  141. package/scripts/epic/epic-classify.ts +1 -1
  142. package/scripts/epic/epic-cli-argv.ts +78 -46
  143. package/scripts/epic/epic-cli-remove.ts +11 -19
  144. package/scripts/epic/epic-cli.ts +74 -73
  145. package/scripts/epic/epic-close-comment.ts +1 -1
  146. package/scripts/epic/epic-close.ts +1 -1
  147. package/scripts/epic/epic-cross-repo.ts +5 -5
  148. package/scripts/epic/epic-graph.ts +1 -1
  149. package/scripts/epic/epic-index.ts +1 -1
  150. package/scripts/epic/epic-issue.ts +2 -6
  151. package/scripts/epic/epic-lane-offer.ts +2 -2
  152. package/scripts/epic/epic-next.ts +29 -42
  153. package/scripts/epic/epic-solo-stale.ts +1 -1
  154. package/scripts/epic/epic-triage.ts +8 -4
  155. package/scripts/epic/epic-validate.ts +1 -1
  156. package/scripts/followup/git-followup-finish.ts +2 -2
  157. package/scripts/followup/git-followup-label.ts +2 -2
  158. package/scripts/followup/git-followup-merged.ts +2 -2
  159. package/scripts/followup/git-pr-followup-checks.ts +142 -0
  160. package/scripts/followup/git-pr-followup.ts +4 -129
  161. package/scripts/gate/core-budget.ts +69 -1
  162. package/scripts/gate/gate-plan.ts +47 -7
  163. package/scripts/gate/gate-skip.ts +38 -7
  164. package/scripts/gate/hook-gate-reuse.ts +12 -10
  165. package/scripts/gate/pre-commit-type-check.ts +4 -1
  166. package/scripts/gate/project-checks.ts +6 -9
  167. package/scripts/gate/type-check-step.ts +2 -3
  168. package/scripts/gate/verification-gate.ts +27 -8
  169. package/scripts/gh/git-gh-api-path.ts +2 -2
  170. package/scripts/gh/git-gh-issue-rest.ts +3 -3
  171. package/scripts/gh/git-gh-issue-write.ts +53 -7
  172. package/scripts/gh/git-gh-pr-read.ts +64 -19
  173. package/scripts/gh/git-gh-pr-rest.ts +1 -1
  174. package/scripts/gh/git-gh-pr.ts +5 -1
  175. package/scripts/gh/git-pr-ai-review.ts +1 -1
  176. package/scripts/gh/git-pr-checks-eval.ts +1 -3
  177. package/scripts/gh/git-pr-checks-parse.ts +1 -1
  178. package/scripts/gh/git-pr-checks-watch.ts +6 -5
  179. package/scripts/gh/git-pr-checks.ts +7 -5
  180. package/scripts/gh/git-pr-coderabbit.ts +1 -1
  181. package/scripts/gh/git-pr-error.ts +1 -3
  182. package/scripts/gh/git-pr.ts +9 -13
  183. package/scripts/gh/github-issue-url.ts +2 -2
  184. package/scripts/git/constants.ts +2 -6
  185. package/scripts/git/git-command.ts +20 -218
  186. package/scripts/git/git-diff-reads.ts +225 -0
  187. package/scripts/git/git-error.ts +4 -12
  188. package/scripts/git/git-pre-push-hook.ts +139 -0
  189. package/scripts/git/git-prompt.ts +2 -6
  190. package/scripts/git/git-spawn-sync.ts +3 -1
  191. package/scripts/git/git-spawn.ts +1 -1
  192. package/scripts/git/git-staging.ts +4 -6
  193. package/scripts/git/git-status.ts +3 -9
  194. package/scripts/hooks/codex-hook-adapter.ts +1 -1
  195. package/scripts/hooks/edited-cspell.ts +2 -4
  196. package/scripts/hooks/format-edited-file.ts +3 -12
  197. package/scripts/hooks/pre-push-unit.ts +31 -9
  198. package/scripts/hooks/reserved-run.ts +2 -2
  199. package/scripts/hooks/run-hook.sh +5 -4
  200. package/scripts/hooks/stop-guard.ts +5 -3
  201. package/scripts/init/init-actions.ts +0 -5
  202. package/scripts/init/init-ai-copy.ts +13 -2
  203. package/scripts/init/init-logic-json-merge.ts +19 -0
  204. package/scripts/init/init-logic-secretlint.ts +7 -7
  205. package/scripts/init/init-logic-workspace.ts +41 -2
  206. package/scripts/init/init-logic.ts +16 -26
  207. package/scripts/init/init.ts +5 -15
  208. package/scripts/init/initial-commit.ts +4 -4
  209. package/scripts/init/kit-development-versions.ts +40 -0
  210. package/scripts/init/kit-setup-state.ts +2 -2
  211. package/scripts/init/start-exec.ts +68 -19
  212. package/scripts/init/start-setup-pr.ts +9 -9
  213. package/scripts/init/start-steps.ts +6 -10
  214. package/scripts/issue/defect-rate-cli.ts +1 -1
  215. package/scripts/issue/git-next-issues.ts +1 -1
  216. package/scripts/issue/issue-auto-ok.ts +1 -1
  217. package/scripts/issue/issue-backlinks-cli.ts +2 -2
  218. package/scripts/issue/issue-backlinks.ts +9 -9
  219. package/scripts/issue/issue-comment-cli.ts +19 -13
  220. package/scripts/issue/issue-file-cli.ts +45 -18
  221. package/scripts/issue/issue-file.ts +24 -1
  222. package/scripts/issue/issue-scout-closed.ts +1 -1
  223. package/scripts/issue/issue-state-cli.ts +30 -74
  224. package/scripts/josh/josh-command-map.ts +2 -0
  225. package/scripts/josh/josh-command-types.ts +11 -0
  226. package/scripts/josh/josh-commands-ai.ts +4 -4
  227. package/scripts/josh/josh-commands-backlog.ts +4 -1
  228. package/scripts/josh/josh-commands-development.ts +10 -0
  229. package/scripts/josh/josh-commands-document.ts +1 -0
  230. package/scripts/josh/josh-commands-lane.ts +22 -0
  231. package/scripts/josh/josh-commands-maintenance.ts +4 -4
  232. package/scripts/josh/josh-commands-run.ts +12 -7
  233. package/scripts/josh/josh-in-process.ts +28 -9
  234. package/scripts/josh/josh-logic.ts +33 -15
  235. package/scripts/josh/process-identity.ts +1 -3
  236. package/scripts/josh/session-language-cli.ts +3 -4
  237. package/scripts/lane/lane-await.ts +5 -1
  238. package/scripts/lane/lane-child-invocation.ts +2 -2
  239. package/scripts/lane/lane-cli.ts +3 -3
  240. package/scripts/lane/lane-dispatch.ts +14 -10
  241. package/scripts/lane/lane-environment.ts +5 -1
  242. package/scripts/lane/lane-handoff.ts +1 -1
  243. package/scripts/lane/lane-install.ts +2 -13
  244. package/scripts/lane/lane-launch-cli.ts +15 -1
  245. package/scripts/lane/lane-ledger.ts +145 -0
  246. package/scripts/lane/lane-leftover.ts +1 -1
  247. package/scripts/lane/lane-load.ts +108 -0
  248. package/scripts/lane/lane-measure-cli.ts +149 -0
  249. package/scripts/lane/lane-occupancy.ts +3 -0
  250. package/scripts/lane/lane-reap.ts +1 -3
  251. package/scripts/lane/lane-relaunch.ts +1 -1
  252. package/scripts/lane/lane-stats.ts +224 -0
  253. package/scripts/lane/lane-vacant.ts +36 -0
  254. package/scripts/lane/openai-lane-ship.ts +2 -2
  255. package/scripts/lane/openai-lane-supervisor-owner.ts +180 -0
  256. package/scripts/lane/openai-lane-supervisor.ts +7 -165
  257. package/scripts/lane/openai-review-broker.ts +2 -4
  258. package/scripts/lib/ancestor-directories.ts +35 -0
  259. package/scripts/lib/animation-helpers.ts +2 -2
  260. package/scripts/lib/buffered-process.ts +3 -7
  261. package/scripts/lib/cli-flags.ts +71 -1
  262. package/scripts/lib/spawn-exit.ts +2 -2
  263. package/scripts/lib/timeouts.ts +35 -2
  264. package/scripts/lines/line-budget.ts +4 -6
  265. package/scripts/notify/telegram-test.ts +6 -0
  266. package/scripts/observations/observation-ledger-line.ts +6 -6
  267. package/scripts/observations/observation-ledger-migrate.ts +55 -4
  268. package/scripts/observations/observation-ledger.ts +26 -7
  269. package/scripts/overrides/lockfile-overrides.ts +1 -1
  270. package/scripts/overrides/overrides-logic.ts +1 -1
  271. package/scripts/propagate/propagate-git.ts +1 -1
  272. package/scripts/propagate/propagate-publish.ts +2 -2
  273. package/scripts/propagate/propagate-steps.ts +20 -15
  274. package/scripts/propagate/propagate.ts +36 -27
  275. package/scripts/refactor/import-graph.ts +18 -1
  276. package/scripts/refactor/refactor-lint.ts +4 -4
  277. package/scripts/repo/repository-labels.ts +2 -2
  278. package/scripts/repo/required-checks-logic.ts +1 -3
  279. package/scripts/review/live-evidence.ts +2 -4
  280. package/scripts/review/review-brief-cli.ts +1 -1
  281. package/scripts/review/review-finding-ledger.ts +1 -1
  282. package/scripts/review/review-findings-cli.ts +1 -3
  283. package/scripts/rules/decision-oracle-batch.ts +128 -0
  284. package/scripts/rules/decision-oracle-tokens.ts +21 -0
  285. package/scripts/rules/decision-oracle.ts +8 -120
  286. package/scripts/rules/delivered-rules.ts +26 -182
  287. package/scripts/rules/direct-filing.ts +1 -1
  288. package/scripts/rules/early-heartbeat.ts +3 -3
  289. package/scripts/rules/git-argv.ts +1 -1
  290. package/scripts/rules/git-force.ts +1 -1
  291. package/scripts/rules/implementation-cut.ts +2 -2
  292. package/scripts/rules/index-guard.ts +1 -1
  293. package/scripts/rules/issue-comments.ts +118 -0
  294. package/scripts/rules/{issue-fold.ts → issue-fold-rule.ts} +2 -2
  295. package/scripts/rules/lane-background.ts +2 -2
  296. package/scripts/rules/lane-park.ts +18 -0
  297. package/scripts/rules/lane-split-park.ts +128 -0
  298. package/scripts/rules/oracle-firing.ts +1 -1
  299. package/scripts/rules/poll-loop.ts +1 -1
  300. package/scripts/rules/pre-gate-cut.ts +1 -1
  301. package/scripts/rules/protected-files.ts +59 -4
  302. package/scripts/rules/{run-tail.ts → run-tail-rule.ts} +2 -2
  303. package/scripts/rules/shell-body-trigger.ts +1 -1
  304. package/scripts/rules/stop-rules.ts +18 -7
  305. package/scripts/rules/test-declared-commit.ts +4 -4
  306. package/scripts/rules/wip-cap.ts +63 -0
  307. package/scripts/run/{run-carry-args.ts → carry/run-carry-args.ts} +37 -13
  308. package/scripts/run/{run-carry-change.ts → carry/run-carry-change.ts} +29 -7
  309. package/scripts/run/{run-carry-cli.ts → carry/run-carry-cli.ts} +4 -6
  310. package/scripts/run/{run-carry.ts → carry/run-carry.ts} +1 -1
  311. package/scripts/run/{run-cut-args.ts → cut/run-cut-args.ts} +1 -1
  312. package/scripts/run/{run-cut-cli.ts → cut/run-cut-cli.ts} +2 -2
  313. package/scripts/run/{run-cut.ts → cut/run-cut.ts} +1 -1
  314. package/scripts/run/{run-entry-cli.ts → entry/run-entry-cli.ts} +11 -11
  315. package/scripts/run/{run-entry.ts → entry/run-entry.ts} +2 -2
  316. package/scripts/run/{run-event-scope.ts → event/run-event-scope.ts} +1 -1
  317. package/scripts/run/{run-event-stream-emit.ts → event/run-event-stream-emit.ts} +1 -1
  318. package/scripts/run/{run-event-stream.ts → event/run-event-stream.ts} +16 -2
  319. package/scripts/run/{run-hold-cli.ts → hold/run-hold-cli.ts} +5 -5
  320. package/scripts/run/{run-merge-cli.ts → merge/run-merge-cli.ts} +10 -5
  321. package/scripts/run/{run-merge-steps.ts → merge/run-merge-steps.ts} +53 -5
  322. package/scripts/run/{run-merge.ts → merge/run-merge.ts} +1 -1
  323. package/scripts/run/{run-progress-cli.ts → progress/run-progress-cli.ts} +1 -1
  324. package/scripts/run/{run-progress-config.ts → progress/run-progress-config.ts} +2 -17
  325. package/scripts/run/{run-progress-read.ts → progress/run-progress-read.ts} +5 -5
  326. package/scripts/run/{run-progress.ts → progress/run-progress.ts} +1 -1
  327. package/scripts/run/{run-review-steps.ts → review/run-review-steps.ts} +2 -3
  328. package/scripts/run/run-ending.ts +2 -2
  329. package/scripts/run/run-halfrun-resume.ts +6 -1
  330. package/scripts/run/run-headless.ts +1 -1
  331. package/scripts/run/run-invocation.ts +85 -84
  332. package/scripts/run/run-liveness.ts +1 -1
  333. package/scripts/run/run-parent-cut-hook.ts +1 -1
  334. package/scripts/run/run-preflight.ts +6 -6
  335. package/scripts/run/run-prep-cli.ts +1 -1
  336. package/scripts/run/run-prrun-resume.ts +1 -1
  337. package/scripts/run/run-report-cli.ts +4 -4
  338. package/scripts/run/run-report.ts +2 -2
  339. package/scripts/run/run-status-cli.ts +1 -1
  340. package/scripts/run/run-step-cli.ts +3 -3
  341. package/scripts/run/run-step.ts +2 -2
  342. package/scripts/run/run-stop-notify.ts +1 -1
  343. package/scripts/run/run-stranded-detect.ts +4 -4
  344. package/scripts/run/run-stranded.ts +2 -2
  345. package/scripts/run/run-watcher-guard-cli.ts +1 -1
  346. package/scripts/run/run-watcher-guard.ts +5 -3
  347. package/scripts/run/run-watcher-hook.ts +1 -1
  348. package/scripts/run/{run-ship-cli.ts → ship/run-ship-cli.ts} +2 -2
  349. package/scripts/run/{run-ship-detach.ts → ship/run-ship-detach.ts} +3 -3
  350. package/scripts/run/ship/run-ship-lock.ts +50 -0
  351. package/scripts/run/{run-ship-preflight.ts → ship/run-ship-preflight.ts} +6 -2
  352. package/scripts/run/{run-ship-probe.ts → ship/run-ship-probe.ts} +2 -2
  353. package/scripts/run/{run-ship-return.ts → ship/run-ship-return.ts} +4 -3
  354. package/scripts/run/{run-ship-review-steps.ts → ship/run-ship-review-steps.ts} +3 -3
  355. package/scripts/run/{run-ship-scoped.ts → ship/run-ship-scoped.ts} +10 -1
  356. package/scripts/run/{run-ship-steps.ts → ship/run-ship-steps.ts} +11 -12
  357. package/scripts/run/ship/run-ship-stop-text.ts +13 -0
  358. package/scripts/run/{run-ship-sync.ts → ship/run-ship-sync.ts} +25 -11
  359. package/scripts/run/{run-tidy-lanes.ts → tidy/run-tidy-lanes.ts} +1 -1
  360. package/scripts/run/{run-wake-cli.ts → wake/run-wake-cli.ts} +23 -8
  361. package/scripts/run/{run-wake-describe.ts → wake/run-wake-describe.ts} +3 -3
  362. package/scripts/run/{run-wake-driver.ts → wake/run-wake-driver.ts} +59 -8
  363. package/scripts/run/{run-wake-handoff.ts → wake/run-wake-handoff.ts} +1 -1
  364. package/scripts/run/{run-wake-loop.ts → wake/run-wake-loop.ts} +8 -2
  365. package/scripts/run/wake/run-wake-restart.ts +58 -0
  366. package/scripts/run/{run-wake-session.ts → wake/run-wake-session.ts} +3 -3
  367. package/scripts/run/{run-wake.ts → wake/run-wake.ts} +1 -1
  368. package/scripts/safe-chain/preinstall-command.ts +20 -21
  369. package/scripts/safe-chain/project-config.ts +19 -15
  370. package/scripts/sync/sync-ai-files.ts +1 -1
  371. package/scripts/sync/sync-configs.ts +2 -1
  372. package/scripts/sync/sync.ts +15 -2
  373. package/scripts/test/unit-worker-share.ts +1 -0
  374. package/scripts/time-runtime/time-background.ts +5 -1
  375. package/scripts/time-runtime/time-instant.ts +3 -1
  376. package/scripts/time-runtime/time-spans.ts +6 -139
  377. package/scripts/time-runtime/time-tool-call.ts +160 -0
  378. package/scripts/version/effective-upstream.ts +2 -20
  379. package/scripts/version/latest-corepack.ts +17 -17
  380. package/scripts/version/latest-regression.ts +1 -1
  381. package/scripts/version/latest-update.ts +4 -4
  382. package/scripts/version/npm-registry.ts +20 -5
  383. package/scripts/version/publishable-range-check.ts +2 -2
  384. package/scripts/version/publishable-range.ts +1 -1
  385. package/scripts/version/release-age.ts +48 -38
  386. package/scripts/version/release-hold.ts +1 -1
  387. package/scripts/version/safe-chain-version-update.ts +40 -0
  388. package/scripts/version/upgrade-shell-command.ts +48 -8
  389. package/scripts/version/version-check-logic.ts +23 -14
  390. package/scripts/version/version-commands.ts +23 -11
  391. package/scripts/version/version-remote.ts +28 -13
  392. package/templates/pnpm-workspace.basic.yaml +4 -0
  393. package/templates/workflows/dependabot-auto-merge.yml +5 -5
  394. package/templates/workflows/github-release.yml +2 -0
  395. package/scripts/build/build-config-merge.ts +0 -27
  396. package/scripts/build/build-managed-marker.ts +0 -27
  397. package/scripts/build/build-self-sync-guard.ts +0 -27
  398. package/scripts/build/build-version.ts +0 -26
  399. package/scripts/version/preinstall-version-update.ts +0 -86
  400. /package/scripts/git/{schemas.ts → git-schemas.ts} +0 -0
  401. /package/scripts/overrides/{schemas.ts → overrides-schemas.ts} +0 -0
  402. /package/scripts/run/{run-carry-conversation.ts → carry/run-carry-conversation.ts} +0 -0
  403. /package/scripts/run/{run-carry-reclaim.ts → carry/run-carry-reclaim.ts} +0 -0
  404. /package/scripts/run/{run-carry-stash.ts → carry/run-carry-stash.ts} +0 -0
  405. /package/scripts/run/{run-carry-streak.ts → carry/run-carry-streak.ts} +0 -0
  406. /package/scripts/run/{run-cut-handoff.ts → cut/run-cut-handoff.ts} +0 -0
  407. /package/scripts/run/{run-cut-report.ts → cut/run-cut-report.ts} +0 -0
  408. /package/scripts/run/{run-entry-stop.ts → entry/run-entry-stop.ts} +0 -0
  409. /package/scripts/run/{run-event-cli.ts → event/run-event-cli.ts} +0 -0
  410. /package/scripts/run/{run-event-follow.ts → event/run-event-follow.ts} +0 -0
  411. /package/scripts/run/{run-event-render.ts → event/run-event-render.ts} +0 -0
  412. /package/scripts/run/{run-event-watch.ts → event/run-event-watch.ts} +0 -0
  413. /package/scripts/run/{run-hold.ts → hold/run-hold.ts} +0 -0
  414. /package/scripts/run/{run-progress-args.ts → progress/run-progress-args.ts} +0 -0
  415. /package/scripts/run/{run-progress-clock.ts → progress/run-progress-clock.ts} +0 -0
  416. /package/scripts/run/{run-review-cli.ts → review/run-review-cli.ts} +0 -0
  417. /package/scripts/run/{run-review.ts → review/run-review.ts} +0 -0
  418. /package/scripts/run/{run-ship-next.ts → ship/run-ship-next.ts} +0 -0
  419. /package/scripts/run/{run-ship-pre-detach.ts → ship/run-ship-pre-detach.ts} +0 -0
  420. /package/scripts/run/{run-ship-review.ts → ship/run-ship-review.ts} +0 -0
  421. /package/scripts/run/{run-ship-stage.ts → ship/run-ship-stage.ts} +0 -0
  422. /package/scripts/run/{run-ship.ts → ship/run-ship.ts} +0 -0
  423. /package/scripts/run/{run-tidy-cli.ts → tidy/run-tidy-cli.ts} +0 -0
  424. /package/scripts/run/{run-tidy-stashes.ts → tidy/run-tidy-stashes.ts} +0 -0
  425. /package/scripts/run/{run-tidy.ts → tidy/run-tidy.ts} +0 -0
@@ -0,0 +1,39 @@
1
+ import { git_stash } from '#scripts/git/stash/git-stash'
2
+ import { lane_launch_cli, type LaunchOutcome } from '#scripts/lane/lane-launch-cli'
3
+ import { backlog_drive_owner } from './backlog-drive-owner'
4
+
5
+ // The driver's lane launch (joshuafolkken/kit#3272). The parent that ran `josh latest` in the primary
6
+ // checkout leaves its rewritten lock file in a stash under this message — `backlogrun-lanes.md` →
7
+ // "Once per repository, before the first lane opens" — and the lane that pops it carries the update
8
+ // into its pull request. **The stash itself is the "first lane" marker**: each launch asks whether it
9
+ // is still on the stack, and the pop that `lane:launch --stash` runs consumes it, so the first launch
10
+ // after the push takes it and every later one finds nothing. A restarted driver needs no memory of
11
+ // which lane was first. Two entries under the message are a state a person resolves, so neither is
12
+ // guessed at — the launch goes ahead without one, as `stash:pop` would refuse it anyway. That skip is
13
+ // said on stderr, because `stash:pop` refusing would have been heard and a silent skip would let the
14
+ // update never reach a pull request.
15
+ const LATEST_STASH_MESSAGE = 'backlogrun: josh latest before lanes'
16
+
17
+ async function latest_stash(): Promise<string | undefined> {
18
+ const selection = git_stash.select(await git_stash.list(), LATEST_STASH_MESSAGE)
19
+
20
+ if (selection.kind === 'ambiguous') {
21
+ console.error(
22
+ `Launching without the "${LATEST_STASH_MESSAGE}" stash: ${selection.selectors.join(', ')} all match — keep one.`,
23
+ )
24
+ }
25
+
26
+ return selection.kind === 'match' ? LATEST_STASH_MESSAGE : undefined
27
+ }
28
+
29
+ async function launch(issue: string, owner: string): Promise<LaunchOutcome['kind']> {
30
+ await backlog_drive_owner.assert_current(owner)
31
+
32
+ const outcome = await lane_launch_cli.launch_lane({ issue, stash: await latest_stash() })
33
+
34
+ return outcome.kind
35
+ }
36
+
37
+ const backlog_drive_launch = { LATEST_STASH_MESSAGE, launch }
38
+
39
+ export { backlog_drive_launch }
@@ -1,8 +1,8 @@
1
1
  import { EPIC_LABEL, has_label_name, NEEDS_DECISION_LABEL } from '#scripts/issue/issue-labels'
2
2
  import type { IssueState } from '#scripts/issue/issue-state'
3
3
  import { issue_state_cli } from '#scripts/issue/issue-state-cli'
4
- import type { RunCarry } from '#scripts/run/run-carry'
5
- import type { MergeResult } from '#scripts/run/run-merge-cli'
4
+ import type { RunCarry } from '#scripts/run/carry/run-carry'
5
+ import type { MergeResult } from '#scripts/run/merge/run-merge-cli'
6
6
  import { backlog_budget } from './backlog-budget'
7
7
  import type { DriveState, OfferRead } from './backlog-drive'
8
8
  import { backlog_drive_named } from './backlog-drive-named'
@@ -58,9 +58,7 @@ function settled_outcome(state: IssueState): MergeResult['outcome'] | undefined
58
58
  async function classify(issue: string, named: OfferRead, owner: string): Promise<OfferRead> {
59
59
  const result = await issue_state_cli.read_issue(issue)
60
60
 
61
- if (result.kind !== 'state') {
62
- return { verdict: 'issue-state', issues: [], retries: NO_RETRIES }
63
- }
61
+ if (result.kind !== 'state') return { verdict: 'issue-state', issues: [], retries: NO_RETRIES }
64
62
 
65
63
  const outcome = settled_outcome(result.state)
66
64
 
@@ -1,8 +1,8 @@
1
1
  import { has_label_name, NEEDS_DECISION_LABEL } from '#scripts/issue/issue-labels'
2
2
  import { issue_state_cli } from '#scripts/issue/issue-state-cli'
3
- import { run_carry, type RunCarry } from '#scripts/run/run-carry'
4
- import type { RunEvent } from '#scripts/run/run-event-stream'
5
- import type { MergeResult } from '#scripts/run/run-merge-cli'
3
+ import { run_carry, type RunCarry } from '#scripts/run/carry/run-carry'
4
+ import type { RunEvent } from '#scripts/run/event/run-event-stream'
5
+ import type { MergeResult } from '#scripts/run/merge/run-merge-cli'
6
6
  import type { DriveState, OfferRead } from './backlog-drive'
7
7
  import { backlog_drive_restore } from './backlog-drive-restore'
8
8
  import { backlog_named } from './backlog-named'
@@ -1,4 +1,4 @@
1
- import type { RunCarry } from '#scripts/run/run-carry'
1
+ import type { RunCarry } from '#scripts/run/carry/run-carry'
2
2
  import type { DriveState } from './backlog-drive'
3
3
 
4
4
  const LIST_SEPARATOR = ','
@@ -1,4 +1,4 @@
1
- import { run_carry, type RunCarry } from '#scripts/run/run-carry'
1
+ import { run_carry, type RunCarry } from '#scripts/run/carry/run-carry'
2
2
 
3
3
  function owns_record(carry: RunCarry, owner: string): boolean {
4
4
  const current = run_carry.owner_of(Number(owner))
@@ -1,4 +1,4 @@
1
- import { run_event_stream, type RunEvent } from '#scripts/run/run-event-stream'
1
+ import { run_event_stream, type RunEvent } from '#scripts/run/event/run-event-stream'
2
2
 
3
3
  const ISSUE_IN_EVENT = /#([1-9]\d*)\b/u
4
4
  const SETTLED_KINDS: ReadonlySet<string> = new Set([
@@ -1,6 +1,6 @@
1
1
  import { doctor_consumer } from '#scripts/doctor/doctor-consumer'
2
2
  import { find_package_directory } from '#scripts/josh/josh-logic'
3
- import type { RunCarry } from '#scripts/run/run-carry'
3
+ import type { RunCarry } from '#scripts/run/carry/run-carry'
4
4
  import { run_retrospective } from '#scripts/run/run-retrospective'
5
5
 
6
6
  // Whether a drain owes the retrospective, read through the owed rule `run:step` reads, so a drain it
@@ -17,7 +17,7 @@
17
17
  // without a process, a network or a clock.
18
18
 
19
19
  import type { LaunchOutcome } from '#scripts/lane/lane-launch-cli'
20
- import type { MergeResult } from '#scripts/run/run-merge-cli'
20
+ import type { MergeResult } from '#scripts/run/merge/run-merge-cli'
21
21
 
22
22
  const RUN_VERDICT = 'run'
23
23
  const STOP_VERDICT = 'stop'
@@ -146,6 +146,19 @@ function report(result: EpicNextResult, context: PoolContext): number {
146
146
  return SUCCESS_EXIT_CODE
147
147
  }
148
148
 
149
+ // The settled set the views were classified against, so a standalone row and an epic child weigh the
150
+ // same blocker the same way.
151
+ function running_of(
152
+ views: ReadonlyArray<EpicView>,
153
+ graphs: ReadonlyArray<ReadonlyArray<EpicChild>>,
154
+ context: PoolContext,
155
+ ): ReadonlySet<string> {
156
+ return (
157
+ views[0]?.running ??
158
+ backlog_pool.running_set(graphs, context.opted_in.issues, context.repo, context.tracking.index)
159
+ )
160
+ }
161
+
149
162
  // The two halves as one result. The epic half is already classified by `epic:next`; the standalone
150
163
  // half is classified here; the verdict is decided from the merge, so a backlog with a runnable epic
151
164
  // child and nothing else says `run` exactly as one with a runnable standalone issue does.
@@ -161,10 +174,7 @@ function combine(views: ReadonlyArray<EpicView>, context: PoolContext): EpicNext
161
174
  tracked: epic_index.withheld_children(context.tracking.index, context.opted_in.issues),
162
175
  exclude: context.exclude,
163
176
  repo: context.repo,
164
- // The settled set the views were classified against, so a standalone row and an epic child weigh
165
- // the same blocker the same way.
166
- running:
167
- views[0]?.running ?? backlog_pool.running_set(graphs, context.opted_in.issues, context.repo),
177
+ running: running_of(views, graphs, context),
168
178
  })
169
179
 
170
180
  // The same checkout map `epic:next` hands `build_result`. Without it every bundle heading reads
@@ -194,6 +204,7 @@ function settled_views(
194
204
  views[0]?.running ?? running,
195
205
  context.opted_in.issues,
196
206
  context.repo,
207
+ context.tracking.index,
197
208
  )
198
209
 
199
210
  return settled.size === running.size ? views : settled_views(reads, settled, context)
@@ -212,7 +223,7 @@ function views_from(reads: ReadonlyArray<EpicRead>, context: PoolContext): Reado
212
223
 
213
224
  return settled_views(
214
225
  reads,
215
- backlog_pool.running_set(graphs, context.opted_in.issues, context.repo),
226
+ backlog_pool.running_set(graphs, context.opted_in.issues, context.repo, context.tracking.index),
216
227
  context,
217
228
  )
218
229
  }
@@ -3,8 +3,8 @@ import { fileURLToPath } from 'node:url'
3
3
  import { josh_command } from '#scripts/josh/josh-run'
4
4
  import { cli_flags } from '#scripts/lib/cli-flags'
5
5
  import { rule_value_cache } from '#scripts/rules/rule-value-cache'
6
- import { run_event_stream } from '#scripts/run/run-event-stream'
7
- import { run_event_stream_emit } from '#scripts/run/run-event-stream-emit'
6
+ import { run_event_stream } from '#scripts/run/event/run-event-stream'
7
+ import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
8
8
  import { z } from 'zod'
9
9
  import { backlog_offer, type OfferAnswer } from './backlog-offer'
10
10
 
@@ -74,8 +74,8 @@ function to_count(raw: string | undefined): number | undefined {
74
74
 
75
75
  // A count flag that was given but unreadable makes the invocation unreadable rather than defaulted —
76
76
  // the contract `backlog:budget` follows for its own counts.
77
- function count_of(raw: string | undefined, fallback: number): number | undefined {
78
- return raw === undefined ? fallback : to_count(raw)
77
+ function count_of(raw: string | undefined): number | undefined {
78
+ return raw === undefined ? DEFAULT_COUNT : to_count(raw)
79
79
  }
80
80
 
81
81
  interface OfferCounts {
@@ -86,8 +86,8 @@ interface OfferCounts {
86
86
  // The two counts the mapping needs: `--running` decides `wait`, `--retries` decides `retry`. Either
87
87
  // given but unreadable refuses the whole invocation.
88
88
  function counts_of(values: ParsedValues): OfferCounts | undefined {
89
- const running = count_of(cli_flags.string_of(values.running), DEFAULT_COUNT)
90
- const retries = count_of(cli_flags.string_of(values.retries), DEFAULT_COUNT)
89
+ const running = count_of(cli_flags.string_of(values.running))
90
+ const retries = count_of(cli_flags.string_of(values.retries))
91
91
 
92
92
  if (running === undefined || retries === undefined) return undefined
93
93
 
@@ -5,7 +5,7 @@ import { backlog_next } from './backlog-next'
5
5
  // answered — its stdout tokens and its exit code — into the one word `backlog:budget` is then asked
6
6
  // with, plus the issue numbers to start and the consecutive-retry count carried to the next ask.
7
7
  //
8
- // **The mapping is `docs/josh-commands-automation.md` → "`josh backlog:offer`", held here so it cannot
8
+ // **The mapping is `docs/josh-commands-backlog.md` → "`josh backlog:offer`", held here so it cannot
9
9
  // drift.** It fixes which `backlog:next` answer becomes which `backlog:budget` word, and it carries two
10
10
  // context branches an agent once applied by hand every iteration: `wait` is `blocked` while this run
11
11
  // has children in flight and `exhausted` when it has none, and `retry` is `blocked` until the third
@@ -4,8 +4,8 @@ import { auto_ok_cli } from '#scripts/auto-ok/auto-ok-cli'
4
4
  import { epic_index } from '#scripts/epic/epic-index'
5
5
  import type { EpicNextResult } from '#scripts/epic/epic-report'
6
6
  import { git_gh_command } from '#scripts/gh/git-gh-command'
7
+ import { open_issue_schema, type OpenIssueData } from '#scripts/git/git-schemas'
7
8
  import { read_json_listing } from '#scripts/git/parse-json-array'
8
- import { open_issue_schema, type OpenIssueData } from '#scripts/git/schemas'
9
9
  import { run_invocation } from '#scripts/run/run-invocation'
10
10
  import { backlog_named } from './backlog-named'
11
11
  import { backlog_next, type OptedIn } from './backlog-next'
@@ -5,7 +5,7 @@ import { epic_index } from '#scripts/epic/epic-index'
5
5
  import { epic_issue } from '#scripts/epic/epic-issue'
6
6
  import type { EpicView } from '#scripts/epic/epic-next-views'
7
7
  import { epic_outside_blocker } from '#scripts/epic/epic-outside-blocker'
8
- import type { OpenIssueData } from '#scripts/git/schemas'
8
+ import type { OpenIssueData } from '#scripts/git/git-schemas'
9
9
  import { git_next_issues } from '#scripts/issue/git-next-issues'
10
10
  import {
11
11
  ALREADY_DONE_LABEL,
@@ -37,6 +37,9 @@ const DECISION_LABELS: ReadonlySet<string> = new Set([NEEDS_DECISION_LABEL, ALRE
37
37
  // `tracked` is the narrowed set `epic_index.withheld_children` builds, not every child an epic
38
38
  // tracks (joshuafolkken/kit#1668) — the narrowing itself is defined there, once, for this half and
39
39
  // `auto-ok:next` alike.
40
+ // Child number to every open epic whose task list names it — `epic_index.build_tracking_index`.
41
+ type TrackingIndex = ReadonlyMap<number, ReadonlyArray<number>>
42
+
40
43
  // The part of the context that decides which rows the standalone half considers at all.
41
44
  type ConsideredContext = Pick<StandaloneContext, 'tracked' | 'exclude' | 'repo'>
42
45
 
@@ -69,24 +72,64 @@ function needs_person(issue: OpenIssueData, context: StandaloneContext): boolean
69
72
  )
70
73
  }
71
74
 
75
+ // Each open epic's key, read off the tracking index — child number to the epics listing it.
76
+ function epic_keys_of(tracking: TrackingIndex, repo: string): ReadonlySet<string> {
77
+ return new Set([...tracking.values()].flat().map((number) => epic_graph.key_of({ repo, number })))
78
+ }
79
+
80
+ // The set with every epic that tracks a member added, nested epics included (joshuafolkken/kit#3289).
81
+ // An epic is a container rather than work, so it is never run itself — but it closes once its children
82
+ // do, so a row blocked by it waits on time exactly when one of those children is in this run.
83
+ function with_tracking_epics(
84
+ running: ReadonlySet<string>,
85
+ tracking: TrackingIndex,
86
+ repo: string,
87
+ ): ReadonlySet<string> {
88
+ const tracking_epics = [...tracking]
89
+ .filter(([child]) => running.has(epic_graph.key_of({ repo, number: child })))
90
+ .flatMap(([, epics]) => epics.map((number) => epic_graph.key_of({ repo, number })))
91
+ const grown = new Set([...running, ...tracking_epics])
92
+
93
+ return grown.size === running.size ? running : with_tracking_epics(grown, tracking, repo)
94
+ }
95
+
96
+ // The epics re-derived from the members alone, so an epic whose last running child was just taken out
97
+ // leaves with it rather than lingering from an earlier pass.
98
+ function rooted(
99
+ running: ReadonlySet<string>,
100
+ tracking: TrackingIndex,
101
+ repo: string,
102
+ ): ReadonlySet<string> {
103
+ const epics = epic_keys_of(tracking, repo)
104
+ const members = new Set([...running].filter((key) => !epics.has(key)))
105
+
106
+ return with_tracking_epics(members, tracking, repo)
107
+ }
108
+
109
+ function is_stuck(issue: OpenIssueData, running: ReadonlySet<string>, repo: string): boolean {
110
+ return has_any_label(issue.labels, DECISION_LABELS) || waits_outside(issue, running, repo)
111
+ }
112
+
72
113
  // The running set with every standalone row a person has to resolve taken out, repeated until a pass
73
114
  // removes nothing — a row waiting on such a row waits on that person too, however long the chain.
74
115
  function settle_standalone(
75
116
  running: ReadonlySet<string>,
76
117
  issues: ReadonlyArray<OpenIssueData>,
77
118
  repo: string,
119
+ tracking: TrackingIndex,
78
120
  ): ReadonlySet<string> {
79
121
  const settled = new Set(running)
80
122
 
81
- // An epic row is never in the set, so deleting its key changes nothing and it needs no filter.
123
+ // An epic row is never a standalone row, so deleting its key here never happens; `rooted` decides it.
82
124
  for (const issue of issues) {
83
- const is_stuck =
84
- has_any_label(issue.labels, DECISION_LABELS) || waits_outside(issue, running, repo)
85
-
86
- if (is_stuck) settled.delete(epic_graph.key_of({ repo, number: issue.number }))
125
+ if (is_stuck(issue, running, repo)) {
126
+ settled.delete(epic_graph.key_of({ repo, number: issue.number }))
127
+ }
87
128
  }
88
129
 
89
- return settled.size === running.size ? running : settle_standalone(settled, issues, repo)
130
+ const next = rooted(settled, tracking, repo)
131
+
132
+ return next.size === running.size ? next : settle_standalone(next, issues, repo, tracking)
90
133
  }
91
134
 
92
135
  // An opted-in row as the graph's node type. Both halves of the pool are then the same shape, so one
@@ -182,18 +225,21 @@ function classify_standalone(
182
225
  // (joshuafolkken/kit#1943). A child is opted in through its epic's `auto-ok` even where it carries none
183
226
  // of its own, which is why the set is built from the graphs that were read rather than from labels. A
184
227
  // standalone row a person has to resolve is left out, so a row waiting on it waits for that person too;
185
- // an epic child in the same state is taken out by `epic_next_views.settle_views`.
228
+ // an epic child in the same state is taken out by `epic_next_views.settle_views`. An open epic with a
229
+ // child in the set is in it too, so a row blocked by that epic waits rather than needs a person. A
230
+ // closed child is left out: it runs nothing, and kept in the set it would hold its epic there.
186
231
  function running_set(
187
232
  graphs: ReadonlyArray<ReadonlyArray<EpicChild>>,
188
233
  issues: ReadonlyArray<OpenIssueData>,
189
234
  repo: string,
235
+ tracking: TrackingIndex,
190
236
  ): ReadonlySet<string> {
191
237
  const running = epic_outside_blocker.running_keys([
192
- ...graphs.flat(),
238
+ ...graphs.flat().filter((child) => child.state === 'OPEN'),
193
239
  ...to_children(standalone_rows(issues), repo),
194
240
  ])
195
241
 
196
- return settle_standalone(running, issues, repo)
242
+ return settle_standalone(rooted(running, tracking, repo), issues, repo, tracking)
197
243
  }
198
244
 
199
245
  // A cycle no single epic can see, because its links cross from one graph into another. Each epic's own
@@ -336,4 +382,4 @@ const backlog_pool = {
336
382
  }
337
383
 
338
384
  export { backlog_pool }
339
- export type { ConsideredContext, StandaloneContext }
385
+ export type { ConsideredContext, StandaloneContext, TrackingIndex }
@@ -3,7 +3,7 @@ import { issue_cite } from '#scripts/issue/issue-cite'
3
3
  import { josh_command, type JoshResult } from '#scripts/josh/josh-run'
4
4
  import { lane_capacity } from '#scripts/lane/lane-capacity'
5
5
  import { lane_registry } from '#scripts/lane/lane-registry'
6
- import type { RunCarry } from '#scripts/run/run-carry'
6
+ import type { RunCarry } from '#scripts/run/carry/run-carry'
7
7
  import { run_headless } from '#scripts/run/run-headless'
8
8
  import { run_invocation } from '#scripts/run/run-invocation'
9
9
  import { backlog_stalled } from './backlog-stalled'
@@ -1,5 +1,5 @@
1
1
  import type { EpicNextResult } from '#scripts/epic/epic-report'
2
- import type { OpenIssueData } from '#scripts/git/schemas'
2
+ import type { OpenIssueData } from '#scripts/git/git-schemas'
3
3
  import { AUTO_OK_LABEL, EPIC_LABEL, has_any_label } from '#scripts/issue/issue-labels'
4
4
 
5
5
  // Which open issues the backlog will not run, and why (joshuafolkken/kit#1652).
@@ -1,6 +1,6 @@
1
1
  import { telegram_notify } from '#scripts/notify/telegram-notify'
2
- import { run_event_stream, type RunEvent } from '#scripts/run/run-event-stream'
3
- import { run_event_stream_emit } from '#scripts/run/run-event-stream-emit'
2
+ import { run_event_stream, type RunEvent } from '#scripts/run/event/run-event-stream'
3
+ import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
4
4
  import { backlog_ready, type ReadyPorts } from './backlog-ready'
5
5
  import { backlog_stalled, type StallReading, type StallVerdict } from './backlog-stalled'
6
6
 
@@ -1,5 +1,5 @@
1
1
  import { epic_triage } from '#scripts/epic/epic-triage'
2
- import { run_event_stream, type RunEvent } from '#scripts/run/run-event-stream'
2
+ import { run_event_stream, type RunEvent } from '#scripts/run/event/run-event-stream'
3
3
 
4
4
  // When ready backlog work sits undispatched while lanes are free, nobody notices until a person asks
5
5
  // (joshuafolkken/kit#2359). This is the mechanical judge of that state: three facts read, never
@@ -10,7 +10,9 @@ const CODEX_HOOKS = path.join(REPO_ROOT, '.codex', 'hooks.json')
10
10
 
11
11
  // Regenerate `.codex/hooks.json` from `.claude/settings.json` (joshuafolkken/kit#2997). The output is
12
12
  // committed rather than gitignored: Codex reads it straight from a fresh clone of kit, before any
13
- // build has run, and `josh init` / `josh sync` copy it to consumers from the package.
13
+ // build has run, and `josh init` / `josh sync` copy it to consumers from the package. It is run by
14
+ // hand, never from `pnpm build`, so a build never rewrites a committed file (joshuafolkken/kit#3324):
15
+ // `codex-project-config.test.ts` fails the gate when the committed copy has drifted.
14
16
  function build_codex_hooks(): string {
15
17
  writeFileSync(CODEX_HOOKS, codex_hooks.codex_hooks_text(readFileSync(CLAUDE_SETTINGS, 'utf8')))
16
18
 
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env tsx
2
+ import { rmSync } from 'node:fs'
3
+ import path from 'node:path'
4
+ import { fileURLToPath } from 'node:url'
5
+ import { COMMAND_MAP } from '#scripts/josh/josh-command-map'
6
+ import { BUNDLED_COMMAND_DIRECTORY, josh_in_process } from '#scripts/josh/josh-in-process'
7
+ import { error_text } from '#scripts/lib/error-message'
8
+ import { build } from 'esbuild'
9
+
10
+ const PACKAGE_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..')
11
+ const OUT_DIR = path.join(PACKAGE_DIR, BUNDLED_COMMAND_DIRECTORY)
12
+
13
+ // Each `is_bundled` command is pre-built to its own `dist/commands/<script basename>.js`, so a
14
+ // consumer's `dist/josh.js` imports it under plain node instead of spawning tsx for its `.ts`
15
+ // (joshuafolkken/kit#3328, `docs/maintainers/runtime-bundling.md`).
16
+ //
17
+ // **No code splitting, and that is why the import closure is checked.** Every entry is one
18
+ // self-contained file, so every module it imports shares the entry's `import.meta.url`; a second
19
+ // `process.argv[1] === fileURLToPath(import.meta.url)` guard inside the closure would fire with the
20
+ // entry's own. `build-commands.test.ts` refuses a bundled command whose closure carries one.
21
+ //
22
+ // The bundle sits two levels under the package root, exactly as its source does under `scripts/`,
23
+ // so a module that finds the package from its own `import.meta.url` resolves the same directory.
24
+ function bundled_scripts(): Array<string> {
25
+ return Object.values(COMMAND_MAP)
26
+ .filter((entry) => entry.is_bundled === true)
27
+ .map((entry) => entry.script ?? '')
28
+ }
29
+
30
+ function entry_point(script: string): { in: string; out: string } {
31
+ const out = path.basename(josh_in_process.bundled_script_path(PACKAGE_DIR, script), '.js')
32
+
33
+ return { in: path.join(PACKAGE_DIR, script), out }
34
+ }
35
+
36
+ // Nothing in this checkout launches `dist/commands/` (kit's own `pnpm josh` runs the source), so the
37
+ // directory is emptied first rather than pruned after, which drops the output of a command no longer
38
+ // bundled.
39
+ async function build_commands(out_directory: string = OUT_DIR): Promise<string> {
40
+ rmSync(out_directory, { recursive: true, force: true })
41
+ await build({
42
+ absWorkingDir: PACKAGE_DIR,
43
+ entryPoints: bundled_scripts().map((script) => entry_point(script)),
44
+ outdir: out_directory,
45
+ bundle: true,
46
+ platform: 'node',
47
+ format: 'esm',
48
+ target: 'node22',
49
+ packages: 'external',
50
+ })
51
+
52
+ return out_directory
53
+ }
54
+
55
+ async function main(): Promise<void> {
56
+ try {
57
+ console.info(` ✔ ${await build_commands()} built`)
58
+ } catch (error) {
59
+ console.error(error_text.message_of(error))
60
+ process.exit(1)
61
+ }
62
+ }
63
+
64
+ if (process.argv[1] === fileURLToPath(import.meta.url)) await main()
65
+
66
+ export { build_commands, bundled_scripts, OUT_DIR }
@@ -49,7 +49,7 @@ interface HookBundle {
49
49
  out: string
50
50
  }
51
51
 
52
- // The three settings.json hooks, the Codex input adapter, and the three guards `pretool-guard`
52
+ // The settings.json hooks (the session-start audit provisioner among them), the Codex input adapter, and the three guards `pretool-guard`
53
53
  // composes: `batch-guard`, `investigation-guard` and `duplicate-read-guard` each self-invoke, so they
54
54
  // must be their own entries to keep their `import.meta.url` out of `pretool-guard`'s file.
55
55
  // `delivered-rules` (the fourth guard) has no self-invoke, so it stays inlined.
@@ -59,6 +59,7 @@ const HOOK_BUNDLES: ReadonlyArray<HookBundle> = [
59
59
  { source: 'scripts/hooks/stop-guard.ts', out: 'stop-guard' },
60
60
  { source: 'scripts/hooks/format-edited-cli.ts', out: 'format-edited' },
61
61
  { source: 'scripts/josh/session-language-cli.ts', out: 'session-lang' },
62
+ { source: 'scripts/security/security-audit-provision.ts', out: 'audit-provision' },
62
63
  { source: 'scripts/hooks/batch-guard.ts', out: 'batch-guard' },
63
64
  { source: 'scripts/delegation/investigation-guard.ts', out: 'investigation-guard' },
64
65
  { source: 'scripts/delegation/duplicate-read-guard.ts', out: 'duplicate-read-guard' },
@@ -7,6 +7,13 @@ import { dts } from 'rollup-plugin-dts'
7
7
 
8
8
  const PACKAGE_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..')
9
9
  const SCRIPTS_IMPORT_PREFIX = '#scripts/'
10
+ // Every public library `pnpm build` bundles — each one a `./<name>` export in package.json.
11
+ const PUBLIC_LIBRARIES: ReadonlyArray<string> = [
12
+ 'version',
13
+ 'config-merge',
14
+ 'managed-marker',
15
+ 'self-sync-guard',
16
+ ]
10
17
 
11
18
  interface LibraryPaths {
12
19
  entry_point: string
@@ -73,11 +80,13 @@ async function build_library_dts(entry_point: string, dts_file: string): Promise
73
80
  async function build_library(name: string): Promise<LibraryPaths> {
74
81
  const paths = library_paths(name)
75
82
 
76
- await build_library_js(paths.entry_point, paths.outfile)
77
- await build_library_dts(paths.entry_point, paths.dts_file)
83
+ await Promise.all([
84
+ build_library_js(paths.entry_point, paths.outfile),
85
+ build_library_dts(paths.entry_point, paths.dts_file),
86
+ ])
78
87
 
79
88
  return paths
80
89
  }
81
90
 
82
91
  export type { LibraryPaths }
83
- export { build_library, library_paths }
92
+ export { build_library, library_paths, PUBLIC_LIBRARIES }
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env tsx
2
+ import { fileURLToPath } from 'node:url'
3
+ import { error_text } from '#scripts/lib/error-message'
4
+ import { OUTFILE as BIN_OUTFILE, build_bin } from './build-bin'
5
+ import { build_claude_md } from './build-claude-md'
6
+ import { build_commands } from './build-commands'
7
+ import { build_hooks, OUT_DIR as HOOKS_OUT_DIR } from './build-hooks'
8
+ import { build_library, PUBLIC_LIBRARIES } from './build-library'
9
+
10
+ interface BuildStep {
11
+ name: string
12
+ run: () => Promise<string>
13
+ }
14
+
15
+ async function bin_step(): Promise<string> {
16
+ await build_bin()
17
+
18
+ return BIN_OUTFILE
19
+ }
20
+
21
+ async function hooks_step(): Promise<string> {
22
+ await build_hooks()
23
+
24
+ return HOOKS_OUT_DIR
25
+ }
26
+
27
+ async function library_step(name: string): Promise<string> {
28
+ const { outfile } = await build_library(name)
29
+
30
+ return outfile
31
+ }
32
+
33
+ async function claude_md_step(): Promise<string> {
34
+ return build_claude_md()
35
+ }
36
+
37
+ // Every step `pnpm build` runs (joshuafolkken/kit#3324). The steps write disjoint paths under
38
+ // `dist/`, so they run concurrently from this one entry instead of eight serial `tsx` launches.
39
+ // Nothing here writes a git-tracked file: `.codex/hooks.json` is regenerated by hand with
40
+ // `tsx scripts/build/build-codex-hooks.ts`, and `codex-project-config.test.ts` fails the gate when
41
+ // the committed copy drifts from `.claude/settings.json`.
42
+ function build_steps(): ReadonlyArray<BuildStep> {
43
+ return [
44
+ { name: 'bin', run: bin_step },
45
+ { name: 'hooks', run: hooks_step },
46
+ { name: 'commands', run: async () => await build_commands() },
47
+ ...PUBLIC_LIBRARIES.map((name) => ({ name, run: async () => await library_step(name) })),
48
+ { name: 'claude-md', run: claude_md_step },
49
+ ]
50
+ }
51
+
52
+ async function build_all(): Promise<ReadonlyArray<string>> {
53
+ return await Promise.all(build_steps().map(async (step) => await step.run()))
54
+ }
55
+
56
+ async function main(): Promise<void> {
57
+ try {
58
+ const outputs = await build_all()
59
+
60
+ for (const output of outputs) console.info(` ✔ ${output} built`)
61
+ } catch (error) {
62
+ console.error(error_text.message_of(error))
63
+ process.exit(1)
64
+ }
65
+ }
66
+
67
+ if (process.argv[1] === fileURLToPath(import.meta.url)) await main()
68
+
69
+ export type { BuildStep }
70
+ export { build_all, build_steps }
@@ -1,6 +1,7 @@
1
1
  import { existsSync, readFileSync } from 'node:fs'
2
2
  import { createRequire } from 'node:module'
3
3
  import path from 'node:path'
4
+ import { ancestor_directories } from '#scripts/lib/ancestor-directories'
4
5
  import { package_bin_schema } from '#scripts/lib/schemas'
5
6
 
6
7
  const NODE_MODULES = 'node_modules'
@@ -27,20 +28,9 @@ function resolve_local_bin(project_root: string, bin_name: string): string {
27
28
  // in `src/lib` would miss the toolkit its sibling checks resolve fine (joshuafolkken/kit#934).
28
29
  // Ascending for the shim itself, rather than for a `package.json` first, is what keeps the two in
29
30
  // step: a nested manifest that owns no `node_modules` is not where pnpm would stop either.
30
- function ancestor_directories(start_directory: string): ReadonlyArray<string> {
31
- const directories: Array<string> = []
32
- let current = start_directory
33
-
34
- while (!directories.includes(current)) {
35
- directories.push(current)
36
- current = path.dirname(current)
37
- }
38
-
39
- return directories
40
- }
41
-
42
31
  function find_local_bin_upwards(start_directory: string, bin_name: string): string | undefined {
43
- return ancestor_directories(start_directory)
32
+ return ancestor_directories
33
+ .list(start_directory)
44
34
  .map((directory) => resolve_local_bin(directory, bin_name))
45
35
  .find((candidate) => existsSync(candidate))
46
36
  }
@@ -1,6 +1,7 @@
1
1
  import path from 'node:path'
2
2
  import { cost_blocks } from '#scripts/cost-runtime/cost-blocks'
3
3
  import { cost_transcript } from '#scripts/cost-runtime/cost-transcript'
4
+ import { capped_print_part } from '#scripts/document/capped-print-part'
4
5
  import { hook_decision, type GuardRun } from '#scripts/josh/hook-decision'
5
6
  import { time_batch_guard, type GuardedCall } from '#scripts/time-runtime/time-batch-guard'
6
7
  import { time_bundle_call } from '#scripts/time-runtime/time-bundle-call'
@@ -212,7 +213,8 @@ function is_session_artifact(target: string): boolean {
212
213
 
213
214
  return (
214
215
  segments.some((_segment, index) => has_state_root(segments, index)) ||
215
- is_harness_output(segments)
216
+ is_harness_output(segments) ||
217
+ capped_print_part.is_part_file(absolute)
216
218
  )
217
219
  }
218
220