@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
@@ -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
 
@@ -111,12 +111,12 @@ function origin_section_lines(lines: ReadonlyArray<string>): Array<string> {
111
111
  return end === NOT_FOUND ? rest : rest.slice(0, end)
112
112
  }
113
113
 
114
- // The value of a `key = value` entry, or nothing when the line declares a different key. Split on
114
+ // The value of a `url = value` entry, or nothing when the line declares a different key. Split on
115
115
  // the first separator rather than matched, for the reason `parse_scp_like` is split by hand.
116
- function entry_value(line: string, key: string): string | undefined {
116
+ function url_value(line: string): string | undefined {
117
117
  const separator = line.indexOf('=')
118
118
  if (separator === NOT_FOUND) return undefined
119
- if (line.slice(0, separator).trim() !== key) return undefined
119
+ if (line.slice(0, separator).trim() !== URL_KEY) return undefined
120
120
 
121
121
  return line.slice(separator + 1).trim()
122
122
  }
@@ -129,7 +129,7 @@ function parse_origin_from_config(content: string): string | undefined {
129
129
  const lines = content.split('\n').map((line) => line.trim())
130
130
 
131
131
  return origin_section_lines(lines)
132
- .map((line) => entry_value(line, URL_KEY))
132
+ .map((line) => url_value(line))
133
133
  .find((url) => url !== undefined)
134
134
  }
135
135
 
@@ -153,7 +153,7 @@ function parse_remote_urls_from_config(content: string): Array<string> {
153
153
 
154
154
  return section_groups(lines)
155
155
  .filter((group) => REMOTE_SECTION.test(group[0] ?? ''))
156
- .flatMap((group) => group.map((line) => entry_value(line, URL_KEY)))
156
+ .flatMap((group) => group.map((line) => url_value(line)))
157
157
  .filter((url) => url !== undefined)
158
158
  }
159
159
 
@@ -3,6 +3,7 @@ import path from 'node:path'
3
3
  import { git_spawn_sync } from '#scripts/git/git-spawn-sync'
4
4
  import { json_value } from '#scripts/lib/json-value'
5
5
  import { file_reader } from '#scripts/lib/read-file'
6
+ import { PROBE_TIMEOUT_MS } from '#scripts/lib/timeouts'
6
7
  import { KIT_PACKAGE_NAME } from '#scripts/version/kit-descriptor'
7
8
  import { z } from 'zod'
8
9
 
@@ -20,7 +21,6 @@ const PLUGIN_ID = 'kit@kit'
20
21
  // full document, so this pointer is also what tells a consumer repository apart from kit itself.
21
22
  const CLAUDE_MD_POINTER = `@${NODE_MODULES}/${KIT_PACKAGE_NAME}/dist/${CLAUDE_MD}`
22
23
  const SECRETLINT_BIN = path.join(NODE_MODULES, '.bin', 'secretlint')
23
- const GIT_TIMEOUT_MS = 2000
24
24
 
25
25
  const manifest_schema = z.object({
26
26
  name: z.string().optional(),
@@ -77,7 +77,7 @@ function is_plugin_declared(root: string): boolean {
77
77
  // from installing kit's git hooks — the failure is silent but for one stderr line.
78
78
  function configured_hooks_path(root: string): string | undefined {
79
79
  const value = git_spawn_sync.read(['-C', root, 'config', '--get', 'core.hooksPath'], {
80
- timeout: GIT_TIMEOUT_MS,
80
+ timeout: PROBE_TIMEOUT_MS,
81
81
  })
82
82
 
83
83
  return value === '' ? undefined : value
@@ -2,11 +2,11 @@ import { existsSync, readFileSync } from 'node:fs'
2
2
  import path from 'node:path'
3
3
  import { git_spawn_sync } from '#scripts/git/git-spawn-sync'
4
4
  import { read_spawn_stdout } from '#scripts/lib/spawn-exit'
5
+ import { PROBE_TIMEOUT_MS } from '#scripts/lib/timeouts'
5
6
  import { execaSync } from 'execa'
6
7
  import { doctor_logic } from './doctor-logic'
7
8
 
8
9
  const JOSH_BIN = 'josh'
9
- const GIT_TIMEOUT_MS = 2000
10
10
  const NOT_A_REPOSITORY_MESSAGE = 'not a git repository'
11
11
  const NPM_VERSION_UPDATES_DISABLED = 'open-pull-requests-limit: 0'
12
12
  const DEPENDABOT_CONFIG_PATH = '.github/dependabot.yml'
@@ -72,7 +72,7 @@ function classify_git_failure(exit_code: number | undefined, stderr: string): Gi
72
72
  function resolve_git_top_level(): GitTopLevel {
73
73
  // The C locale `toplevel` asks under is what keeps the stderr match below from failing on a
74
74
  // translated message and bringing the spurious warning back.
75
- const result = git_spawn_sync.toplevel(GIT_TIMEOUT_MS)
75
+ const result = git_spawn_sync.toplevel(PROBE_TIMEOUT_MS)
76
76
 
77
77
  if (result.exit_code === 0) return classify_top_level(result.stdout.trim())
78
78
 
@@ -194,7 +194,6 @@ type GitTopLevel =
194
194
  { state: 'inside'; top_level: string } | { state: 'outside' } | { state: 'undetermined' }
195
195
 
196
196
  const doctor_io = {
197
- GIT_TIMEOUT_MS,
198
197
  resolve_path_josh,
199
198
  resolve_pnpm_global_josh,
200
199
  has_distributed_dependabot_config,
@@ -0,0 +1,30 @@
1
+ import path from 'node:path'
2
+
3
+ // Where `capped-print.ts` writes the parts of an over-cap output, and how a path is recognized as one
4
+ // of them (joshuafolkken/kit#3332). Both halves live here so the writer and the investigation guard,
5
+ // which must not count a read of a part as reading the Issue's subject, share one spelling of the
6
+ // shape — kept free of the writer's own imports, since the guard runs as a hook on every tool call.
7
+
8
+ const DIRECTORY_PREFIX = 'josh-capped-print-'
9
+ const PART_PREFIX = 'part-'
10
+ const PART_SUFFIX = '.md'
11
+ // A part is `part-<N>.md` and nothing else, so a run's own file that happens to sit beside one is not
12
+ // mistaken for it.
13
+ const PART_PATTERN = /^part-[1-9]\d*\.md$/u
14
+
15
+ function part_name(index: number): string {
16
+ return `${PART_PREFIX}${String(index + 1)}${PART_SUFFIX}`
17
+ }
18
+
19
+ // **The file's own parent, and the file's own name, both have to match.** A directory prefix alone
20
+ // would exempt anything a run unpacked under a similarly named directory; the caller also requires the
21
+ // path to lie outside the checkout, so no repository file is ever exempted by its name.
22
+ function is_part_file(absolute: string): boolean {
23
+ const parent = path.basename(path.dirname(absolute))
24
+
25
+ return parent.startsWith(DIRECTORY_PREFIX) && PART_PATTERN.test(path.basename(absolute))
26
+ }
27
+
28
+ const capped_print_part = { DIRECTORY_PREFIX, part_name, is_part_file }
29
+
30
+ export { capped_print_part }
@@ -3,6 +3,7 @@ import path from 'node:path'
3
3
  import { PLATFORM_TEMP_ROOT } from '#scripts/josh/platform-temporary'
4
4
  import { review_diff_parts } from '#scripts/review/review-diff-parts'
5
5
  import { bash_output_cap_reader } from './bash-output-cap'
6
+ import { capped_print_part } from './capped-print-part'
6
7
 
7
8
  // Prints a command's output whole when it fits under the Bash output cap, and as part files when it
8
9
  // does not (joshuafolkken/kit#3143). Past `BASH_MAX_OUTPUT_LENGTH` Claude Code saves the output and
@@ -17,9 +18,7 @@ import { bash_output_cap_reader } from './bash-output-cap'
17
18
  // in one turn, and a shared directory replaced on every call would delete one call's parts while
18
19
  // another call's listing still names them.
19
20
 
20
- const DIRECTORY_PREFIX = 'josh-capped-print-'
21
21
  const FILE_MODE = 0o600
22
- const PART_SUFFIX = '.md'
23
22
  const LINE_BREAK = '\n'
24
23
  // What else shares the Bash result with this output: the launcher line, a script banner, a few
25
24
  // stderr lines. Measured at about 80 characters for `pnpm josh doc:section` in kit, so 512 holds the
@@ -27,10 +26,10 @@ const LINE_BREAK = '\n'
27
26
  const HEADROOM_CHARS = 512
28
27
 
29
28
  function write_parts(label: string, text: string, cap: number): Array<string> {
30
- const directory = mkdtempSync(path.join(PLATFORM_TEMP_ROOT, DIRECTORY_PREFIX))
29
+ const directory = mkdtempSync(path.join(PLATFORM_TEMP_ROOT, capped_print_part.DIRECTORY_PREFIX))
31
30
 
32
31
  return review_diff_parts.part_texts(label, text, cap).map((part, index) => {
33
- const file = path.join(directory, `part-${String(index + 1)}${PART_SUFFIX}`)
32
+ const file = path.join(directory, capped_print_part.part_name(index))
34
33
 
35
34
  writeFileSync(file, part, { flag: 'wx', mode: FILE_MODE })
36
35
 
@@ -88,8 +88,17 @@ const DOCUMENT_BYTE_BUDGET: ReadonlyArray<DocumentBudget> = [
88
88
  // joshuafolkken/kit#2998 split the reference: the developer commands stay, the rest moved out.
89
89
  // joshuafolkken/kit#3175 raised it: the supervisor, provider-table and answer-to-budget prose moved
90
90
  // here out of `backlogrun-steps.md`, so a run reads it only when it asks about those commands.
91
- { path: 'docs/josh-commands-automation.md', bytes: 159_744 },
92
- { path: 'docs/josh-commands.md', bytes: 36_864 },
91
+ // joshuafolkken/kit#3277 moved the run, lane and session commands to `docs/josh-commands-run.md`.
92
+ // joshuafolkken/kit#3280 moved the issue, epic, backlog and review commands to
93
+ // `docs/josh-commands-backlog.md`.
94
+ // joshuafolkken/kit#3278 moved `josh latest` and `josh overrides` — commands a person types — from
95
+ // the automation page to `docs/josh-commands.md`, which grew one block and the automation page shrank one.
96
+ { path: 'docs/josh-commands-automation.md', bytes: 49_152 },
97
+ { path: 'docs/josh-commands-run.md', bytes: 57_344 },
98
+ { path: 'docs/josh-commands-backlog.md', bytes: 57_344 },
99
+ { path: 'docs/josh-commands.md', bytes: 40_960 },
100
+ // joshuafolkken/kit#3279 moved the label sections here out of `docs/josh-commands-backlog.md`.
101
+ { path: 'docs/labels-and-run-states.md', bytes: 8192 },
93
102
  { path: 'prompts/coding-standards.md', bytes: 8192 },
94
103
  { path: 'prompts/collaboration-workflow.md', bytes: 8192 },
95
104
  { path: 'prompts/collaboration-workflow/file-edits.md', bytes: 12_288 },
@@ -0,0 +1,117 @@
1
+ // Pulling machine-checkable references out of the distributed documents, so a few structural scans
2
+ // can replace the ~140 per-phrase marker suites the documents used to carry (joshuafolkken/kit#1923).
3
+ // Every function here is a pure string extractor: it takes document text and returns the references
4
+ // it names, which is what lets the scans that call it be checked on a synthetic string with a
5
+ // deliberately broken reference in it.
6
+
7
+ // A command reference, only inside a code span. `` `pnpm josh gate` `` and `` `josh review:brief` ``
8
+ // are the copy-and-paste form; the leading backtick keeps prose like "josh will decide" out, which
9
+ // would otherwise read "will" as a command name.
10
+ const COMMAND_PATTERN = /`(?:pnpm )?josh ([a-z][a-z0-9:-]+)/gu
11
+
12
+ // A label the documents operate on — applied (`labels[]=…`), removed (`…/labels/<name>`) or created
13
+ // (`labels -f name=…`). Prose that merely names a label is not scanned; a mistyped name only breaks
14
+ // where a command carries it.
15
+ const LABEL_PATTERN = /(?:labels\[\]=|\/labels\/|labels -f name=)([a-z][a-z0-9:_-]*)/gu
16
+
17
+ // A section reference: a markdown file, an arrow, and the cited heading in straight or Japanese
18
+ // quotes — `` `backlogrun-progress.md` → "The hand-off" ``. The code span is optional and a section
19
+ // number may sit between the arrow and the heading (`` `SKILL.md` → §1, "…" ``): both forms are in
20
+ // the documents, as is a name linked to its file (`` [`residency.md`](./residency.md) →「…」 ``), and a
21
+ // pattern that skipped them let a broken reference of each form through (joshuafolkken/kit#3076).
22
+ // The backreference pairs the code span's backticks, and the lookbehind keeps a bare name from
23
+ // starting mid-path — inside a URL or after an unpaired backtick.
24
+ const SECTION_PATTERN =
25
+ /(?<![\w./:`-])(?<tick>`?)(?<file>[\w./-]+\.md)\k<tick>\s*→\s*(?:§\w+,\s*)?["「](?<heading>[^"」]+)["」]/gu
26
+
27
+ // A markdown link's `(target)`, dropped before the section scan so a linked name sits right before its
28
+ // arrow — the link text already carries the file the reference names.
29
+ const LINK_TARGET_PATTERN = /\]\([^)\s]*\)/gu
30
+
31
+ // A relative markdown link target, with an optional `#anchor`. External `https://…` links carry no
32
+ // `.md`, so the pattern never matches them.
33
+ const LINK_PATTERN = /\]\(([\w./-]+\.md)(?:#[\w-]+)?\)/gu
34
+
35
+ // Filenames that appear in the documents as illustrations of the reference form itself, never as real
36
+ // targets — the doc-section explanation cites `` `path.md` → "Heading" `` and `` `X.md` → "Heading" ``.
37
+ const PLACEHOLDER_FILES: ReadonlySet<string> = new Set(['x.md', 'foo.md', 'file.md', 'path.md'])
38
+
39
+ function matches(text: string, pattern: RegExp): Array<RegExpMatchArray> {
40
+ return [...text.matchAll(pattern)]
41
+ }
42
+
43
+ // A trailing colon is a placeholder for the sub-command that follows — `` `josh epic:` `` stands for
44
+ // `epic:audit`, `epic:next` and the rest — so it names no command of its own.
45
+ function command_references(text: string): Array<string> {
46
+ return matches(text, COMMAND_PATTERN)
47
+ .map((match) => match[1] ?? '')
48
+ .filter((name) => !name.endsWith(':'))
49
+ }
50
+
51
+ // A `<placeholder>` inside a command, and `depth:<n>` after the char class stops at `<`, both leave a
52
+ // token that is not a real label. Real labels never end in a colon and never carry angle brackets.
53
+ function is_real_label(token: string): boolean {
54
+ return token.length > 0 && !token.endsWith(':') && !token.includes('<')
55
+ }
56
+
57
+ function label_references(text: string): Array<string> {
58
+ return matches(text, LABEL_PATTERN)
59
+ .map((match) => match[1] ?? '')
60
+ .filter((token) => is_real_label(token))
61
+ }
62
+
63
+ function base_name(path: string): string {
64
+ return path.split('/').at(-1) ?? path
65
+ }
66
+
67
+ function is_placeholder_file(name: string): boolean {
68
+ return name.includes('<') || PLACEHOLDER_FILES.has(base_name(name).toLowerCase())
69
+ }
70
+
71
+ interface SectionReference {
72
+ file: string
73
+ heading: string
74
+ }
75
+
76
+ function section_references(text: string): Array<SectionReference> {
77
+ return matches(text.replaceAll(LINK_TARGET_PATTERN, ''), SECTION_PATTERN)
78
+ .map(({ groups }) => ({ file: groups?.['file'] ?? '', heading: groups?.['heading'] ?? '' }))
79
+ .filter((reference) => !is_placeholder_file(reference.file))
80
+ }
81
+
82
+ function link_targets(text: string): Array<string> {
83
+ return matches(text, LINK_PATTERN)
84
+ .map((match) => match[1] ?? '')
85
+ .filter((file) => !is_placeholder_file(file))
86
+ }
87
+
88
+ // A cited heading and the heading it names are compared with backticks dropped and whitespace
89
+ // collapsed, because a reference wraps at the column the prose wraps at — sometimes across a
90
+ // blockquote `> ` continuation — while the heading it points at is one unbroken line.
91
+ function normalize_reference(heading: string): string {
92
+ return heading
93
+ .replaceAll('`', '')
94
+ .split(/\s+/u)
95
+ .filter((word) => word !== '>')
96
+ .join(' ')
97
+ }
98
+
99
+ // The two forms a heading can be cited by: with its leading number (`2b. Delegating…`) and without
100
+ // (`Delegating…`), since a document's own numbering is a prefix a reference may or may not carry.
101
+ function reference_forms(title: string): Array<string> {
102
+ const normalized = normalize_reference(title)
103
+
104
+ return [normalized, normalized.replace(/^\d+[a-z]?\. /u, '')]
105
+ }
106
+
107
+ const document_scan = {
108
+ command_references,
109
+ label_references,
110
+ link_targets,
111
+ normalize_reference,
112
+ reference_forms,
113
+ section_references,
114
+ }
115
+
116
+ export type { SectionReference }
117
+ export { document_scan }