@joshuafolkken/kit 1.1514.0 → 1.1784.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 (858) hide show
  1. package/.claude/agents/investigator.md +1 -1
  2. package/.claude/settings.json +5 -5
  3. package/.claude/skills/epic-commands/SKILL.md +26 -65
  4. package/.claude/skills/epic-commands/epic-bundle.md +3 -1
  5. package/.claude/skills/workflow-commands/SKILL.md +5 -5
  6. package/.claude/skills/workflow-commands/background-commands.md +5 -5
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +10 -8
  8. package/.claude/skills/workflow-commands/backlogrun-handoff-report.md +7 -25
  9. package/.claude/skills/workflow-commands/backlogrun-lanes.md +17 -13
  10. package/.claude/skills/workflow-commands/backlogrun-park.md +14 -23
  11. package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -2
  12. package/.claude/skills/workflow-commands/backlogrun-recovery.md +5 -5
  13. package/.claude/skills/workflow-commands/backlogrun-steps.md +10 -10
  14. package/.claude/skills/workflow-commands/backlogrun.md +1 -1
  15. package/.claude/skills/workflow-commands/chain-rule.md +13 -7
  16. package/.claude/skills/workflow-commands/delegation.md +6 -5
  17. package/.claude/skills/workflow-commands/entry-sequence.md +9 -9
  18. package/.claude/skills/workflow-commands/followup.md +9 -31
  19. package/.claude/skills/workflow-commands/fullrun-steps.md +36 -45
  20. package/.claude/skills/workflow-commands/fullrun.md +2 -2
  21. package/.claude/skills/workflow-commands/halfrun.md +17 -25
  22. package/.claude/skills/workflow-commands/issue-comments.md +16 -12
  23. package/.claude/skills/workflow-commands/issue-scout.md +2 -2
  24. package/.claude/skills/workflow-commands/kickoff.md +24 -23
  25. package/.claude/skills/workflow-commands/latest-gate.md +7 -12
  26. package/.claude/skills/workflow-commands/needs-human-review.md +9 -14
  27. package/.claude/skills/workflow-commands/observation-filing.md +4 -36
  28. package/.claude/skills/workflow-commands/observation-ledger.md +1 -1
  29. package/.claude/skills/workflow-commands/pre-gate-cut.md +13 -30
  30. package/.claude/skills/workflow-commands/prerequisite.md +10 -16
  31. package/.claude/skills/workflow-commands/progress-watcher.md +1 -1
  32. package/.claude/skills/workflow-commands/prrun.md +3 -7
  33. package/.claude/skills/workflow-commands/retrospective.md +1 -1
  34. package/.claude/skills/workflow-commands/split-assessment.md +13 -1
  35. package/.claude/skills/workflow-commands/working-tree-hold.md +9 -9
  36. package/.codex/hooks.json +5 -5
  37. package/.github/actions/setup-node/action.yml +9 -0
  38. package/.github/actions/setup-pnpm/action.yml +1 -1
  39. package/.github/dependabot.yml +16 -0
  40. package/.github/release.yml +0 -2
  41. package/.github/workflows/ci.yml +120 -10
  42. package/.github/workflows/publish.yml +8 -1
  43. package/.github/workflows/sonar-qube.yml +1 -0
  44. package/.prettierignore +2 -0
  45. package/.vscode/tasks.json +1 -2
  46. package/CLAUDE.md +3 -7
  47. package/README.md +4 -2
  48. package/SECURITY.md +1 -1
  49. package/dist/CLAUDE.md +3 -7
  50. package/dist/commands/document-read-cli.js +882 -0
  51. package/dist/commands/{document-section-cli.js → document-section-main.js} +79 -37
  52. package/dist/commands/read-set-cli.js +1867 -0
  53. package/dist/commands/run-prep-main.js +21653 -0
  54. package/dist/commands/run-step-cli.js +23880 -0
  55. package/dist/config-merge/index.js +5 -1
  56. package/dist/hooks/audit-provision.js +20 -35
  57. package/dist/hooks/{chunk-DGT54IH5.js → chunk-AZX4FGQ3.js} +63 -17
  58. package/dist/hooks/chunk-CWMBGKYW.js +6483 -0
  59. package/dist/hooks/chunk-O2YBIDSI.js +4306 -0
  60. package/dist/hooks/{chunk-TNUMY6NL.js → chunk-PT5R6UJD.js} +4193 -1900
  61. package/dist/hooks/chunk-TUIFS5E7.js +72 -0
  62. package/dist/hooks/{chunk-723HKZO5.js → chunk-VWWCFGWK.js} +1 -1
  63. package/dist/hooks/{chunk-APUO6U4J.js → chunk-WR2KQAYZ.js} +1843 -440
  64. package/dist/hooks/{chunk-O6GDRNJB.js → chunk-XGBNSWEI.js} +248 -46
  65. package/dist/hooks/chunk-YCDOIR3I.js +3456 -0
  66. package/dist/hooks/codex-hook-adapter.js +10 -22
  67. package/dist/hooks/format-edited.js +5 -6
  68. package/dist/hooks/inputs.json +443 -317
  69. package/dist/hooks/pretool-guard.js +7 -25
  70. package/dist/hooks/session-lang.js +44 -51
  71. package/dist/hooks/stop-guard.js +7716 -2187
  72. package/dist/josh.js +6002 -3583
  73. package/dist/self-sync-guard/index.js +74 -10
  74. package/dist/version/index.js +115 -406
  75. package/eslint/base.js +1 -1
  76. package/lefthook/base.yml +3 -1
  77. package/package.json +10 -48
  78. package/pnpm-workspace.yaml +4 -2
  79. package/prompts/coding-standards.md +1 -1
  80. package/prompts/collaboration-workflow/file-edits.md +1 -7
  81. package/prompts/collaboration-workflow/issue-citation.md +1 -1
  82. package/prompts/collaboration-workflow/issue-template.md +33 -16
  83. package/prompts/collaboration-workflow/lane-instructions.md +1 -2
  84. package/prompts/collaboration-workflow/measurement.md +37 -0
  85. package/prompts/collaboration-workflow/operating-rules.md +4 -6
  86. package/prompts/collaboration-workflow/output-bounds.md +2 -7
  87. package/prompts/collaboration-workflow/plan-comment.md +3 -42
  88. package/prompts/collaboration-workflow/principles.md +5 -0
  89. package/prompts/collaboration-workflow/report-format.md +31 -60
  90. package/prompts/collaboration-workflow/residency.md +2 -2
  91. package/prompts/collaboration-workflow/shell-body.md +6 -16
  92. package/prompts/collaboration-workflow/turn-batching.md +0 -2
  93. package/prompts/collaboration-workflow/upstream-interrupt.md +14 -4
  94. package/prompts/collaboration-workflow/wip-cap.md +1 -1
  95. package/prompts/collaboration-workflow.md +3 -7
  96. package/prompts/refactoring.md +1 -1
  97. package/prompts/review-rubric.md +1 -2
  98. package/prompts/review.md +41 -21
  99. package/prompts/testing-guide.md +8 -43
  100. package/scripts/agent/agent-event.ts +15 -15
  101. package/scripts/agent/agent-exit-record.ts +13 -1
  102. package/scripts/agent/api-auth.ts +41 -0
  103. package/scripts/agent/api-outage.ts +1 -1
  104. package/scripts/auto-ok/auto-ok-cli.ts +14 -16
  105. package/scripts/auto-ok/auto-ok-judge-read.ts +12 -3
  106. package/scripts/auto-ok/auto-ok-judge-write.ts +46 -19
  107. package/scripts/auto-ok/auto-ok-judge.ts +13 -2
  108. package/scripts/auto-ok/auto-ok-main.ts +17 -0
  109. package/scripts/backlog/backlog-arrival.ts +14 -3
  110. package/scripts/backlog/backlog-budget-cli.ts +7 -33
  111. package/scripts/backlog/backlog-budget-main.ts +16 -0
  112. package/scripts/backlog/backlog-budget.ts +2 -3
  113. package/scripts/backlog/backlog-defect-priority.ts +4 -3
  114. package/scripts/backlog/backlog-drive-adopt.ts +67 -0
  115. package/scripts/backlog/backlog-drive-args.ts +4 -5
  116. package/scripts/backlog/backlog-drive-cli.ts +113 -28
  117. package/scripts/backlog/backlog-drive-hold.ts +162 -0
  118. package/scripts/backlog/backlog-drive-idle.ts +151 -0
  119. package/scripts/backlog/backlog-drive-judge.ts +25 -0
  120. package/scripts/backlog/backlog-drive-memory.ts +126 -0
  121. package/scripts/backlog/backlog-drive-named-offer.ts +5 -10
  122. package/scripts/backlog/backlog-drive-named.ts +53 -6
  123. package/scripts/backlog/backlog-drive-offer-argv.ts +3 -8
  124. package/scripts/backlog/backlog-drive-paused.ts +169 -0
  125. package/scripts/backlog/backlog-drive-restore.ts +30 -7
  126. package/scripts/backlog/backlog-drive-seats.ts +18 -8
  127. package/scripts/backlog/backlog-drive-token-handling.ts +38 -0
  128. package/scripts/backlog/backlog-drive.ts +79 -75
  129. package/scripts/backlog/backlog-next-main.ts +16 -0
  130. package/scripts/backlog/backlog-next-shared.ts +73 -0
  131. package/scripts/backlog/backlog-next.ts +48 -16
  132. package/scripts/backlog/backlog-occupied.ts +52 -39
  133. package/scripts/backlog/backlog-offer-cli.ts +6 -21
  134. package/scripts/backlog/backlog-offer-exclude.ts +15 -0
  135. package/scripts/backlog/backlog-offer-main.ts +12 -0
  136. package/scripts/backlog/backlog-offer.ts +36 -3
  137. package/scripts/backlog/backlog-overlap.ts +22 -4
  138. package/scripts/backlog/backlog-plan-read.ts +6 -2
  139. package/scripts/backlog/backlog-plan.ts +18 -4
  140. package/scripts/backlog/backlog-pool.ts +10 -10
  141. package/scripts/backlog/backlog-rank.ts +10 -2
  142. package/scripts/backlog/backlog-ready.ts +112 -30
  143. package/scripts/backlog/backlog-stalled-detect.ts +109 -36
  144. package/scripts/backlog/backlog-stalled.ts +52 -16
  145. package/scripts/backlog/backlog-wait-cause.ts +86 -0
  146. package/scripts/backlog/backlog-waves.ts +39 -13
  147. package/scripts/backlog/backlogrun-args.ts +19 -7
  148. package/scripts/backlog/backlogrun-cli.ts +19 -5
  149. package/scripts/backlog/backlogrun-launch.ts +6 -0
  150. package/scripts/backlog/backlogrun-restart.ts +97 -0
  151. package/scripts/backlog/backlogrun-stop.ts +79 -7
  152. package/scripts/behavior/behavior-cli.ts +2 -2
  153. package/scripts/behavior/behavior-rules.ts +47 -24
  154. package/scripts/build/build-bin.ts +2 -16
  155. package/scripts/build/build-claude-md.ts +0 -7
  156. package/scripts/build/build-commands.ts +0 -13
  157. package/scripts/build/build-hooks.ts +49 -48
  158. package/scripts/build/hook-bundle-stamp.ts +29 -11
  159. package/scripts/build/local-bin.ts +1 -1
  160. package/scripts/cases/cases-cli.ts +25 -13
  161. package/scripts/cases/cases-interaction-scan.ts +134 -0
  162. package/scripts/cases/cases-interaction.ts +183 -0
  163. package/scripts/cases/cases-logic.ts +39 -6
  164. package/scripts/ci/pr-classification-main.ts +18 -0
  165. package/scripts/ci/pr-classification.ts +10 -17
  166. package/scripts/clone/clone-scan.ts +1 -1
  167. package/scripts/cost-runtime/cost-blocks.ts +22 -37
  168. package/scripts/cost-runtime/cost-cli.ts +31 -14
  169. package/scripts/cost-runtime/cost-main.ts +12 -0
  170. package/scripts/cost-runtime/cost-transcript.ts +1 -0
  171. package/scripts/delegation/delegation-policy.ts +17 -4
  172. package/scripts/delegation/duplicate-read-guard.ts +0 -8
  173. package/scripts/delegation/investigation-guard.ts +0 -8
  174. package/scripts/delegation/investigation-reads.ts +3 -4
  175. package/scripts/dependabot/dependabot-cooldown.ts +194 -0
  176. package/scripts/discovery/repo-discovery.ts +24 -6
  177. package/scripts/doctor/doctor-consumer.ts +2 -5
  178. package/scripts/document/document-byte-budget.ts +8 -6
  179. package/scripts/document/document-scan.ts +1 -1
  180. package/scripts/document/document-section-cli.ts +0 -8
  181. package/scripts/document/document-section-main.ts +12 -0
  182. package/scripts/epic/epic-audit-cli.ts +12 -6
  183. package/scripts/epic/epic-bundle-apply.ts +137 -0
  184. package/scripts/epic/epic-bundle-cli.ts +32 -121
  185. package/scripts/epic/epic-bundle-format.ts +116 -0
  186. package/scripts/epic/epic-bundle-main.ts +17 -0
  187. package/scripts/epic/epic-busy.ts +5 -12
  188. package/scripts/epic/epic-classify.ts +24 -15
  189. package/scripts/epic/epic-cli-argv.ts +31 -0
  190. package/scripts/epic/epic-cli-decide.ts +42 -0
  191. package/scripts/epic/epic-cli.ts +6 -38
  192. package/scripts/epic/epic-close.ts +112 -55
  193. package/scripts/epic/epic-cross-repo.ts +4 -7
  194. package/scripts/epic/epic-decide.ts +119 -0
  195. package/scripts/epic/epic-decision.ts +9 -0
  196. package/scripts/epic/epic-fetch.ts +4 -0
  197. package/scripts/epic/epic-graph.ts +2 -0
  198. package/scripts/epic/epic-issue.ts +5 -1
  199. package/scripts/epic/epic-label-age.ts +1 -1
  200. package/scripts/epic/epic-lane-offer.ts +39 -4
  201. package/scripts/epic/epic-next-main.ts +24 -0
  202. package/scripts/epic/epic-next.ts +6 -24
  203. package/scripts/epic/epic-outside-blocker.ts +6 -2
  204. package/scripts/epic/epic-parse.ts +9 -3
  205. package/scripts/epic/epic-read.ts +1 -0
  206. package/scripts/epic/epic-reconcile.ts +39 -0
  207. package/scripts/epic/epic-run.ts +10 -1
  208. package/scripts/epic/epic-solo.ts +50 -14
  209. package/scripts/epic/epic.ts +41 -7
  210. package/scripts/exports/unused-members-cli.ts +2 -2
  211. package/scripts/followup/followup-checks-event.ts +8 -3
  212. package/scripts/followup/followup-coderabbit-wait.ts +82 -0
  213. package/scripts/followup/followup-review-gates.ts +81 -0
  214. package/scripts/followup/git-followup-stages.ts +13 -3
  215. package/scripts/followup/git-followup-workflow.ts +19 -66
  216. package/scripts/followup/git-pr-followup-wrapup.ts +9 -14
  217. package/scripts/followup/git-pr-followup.ts +36 -8
  218. package/scripts/fresh-machine/fresh-machine-cli.ts +1 -1
  219. package/scripts/fresh-machine/fresh-machine-run.ts +8 -8
  220. package/scripts/fresh-machine/specs/kit-test-backlogrun.json +1 -1
  221. package/scripts/gate/busy-average.ts +58 -0
  222. package/scripts/gate/check-cpu.ts +60 -0
  223. package/scripts/gate/check-inputs.ts +39 -95
  224. package/scripts/gate/check-reuse.ts +33 -54
  225. package/scripts/gate/command-memory.ts +192 -0
  226. package/scripts/gate/core-admission.ts +218 -28
  227. package/scripts/gate/core-budget-timing.ts +37 -0
  228. package/scripts/gate/core-budget.ts +80 -98
  229. package/scripts/gate/core-wait-record.ts +48 -0
  230. package/scripts/gate/core-wait.ts +37 -5
  231. package/scripts/gate/core-weights.ts +86 -0
  232. package/scripts/gate/free-cores.ts +27 -4
  233. package/scripts/gate/gate-ledger.ts +32 -4
  234. package/scripts/gate/gate-plan.ts +41 -34
  235. package/scripts/gate/gate-report.ts +14 -2
  236. package/scripts/gate/gate-run-steps.ts +53 -8
  237. package/scripts/gate/gate-skip.ts +12 -2
  238. package/scripts/gate/gate-steps.ts +12 -1
  239. package/scripts/gate/input-fingerprint.ts +42 -0
  240. package/scripts/gate/machine-capacity.ts +65 -31
  241. package/scripts/gate/moved-paths.ts +67 -0
  242. package/scripts/gate/project-checks.ts +5 -12
  243. package/scripts/gate/scoped-green.ts +12 -8
  244. package/scripts/gate/since-green.ts +62 -0
  245. package/scripts/gate/toolchain-inputs.ts +115 -0
  246. package/scripts/gate/verification-gate.ts +27 -24
  247. package/scripts/gate/verification-inputs.ts +250 -0
  248. package/scripts/gh/gh-author-association.ts +96 -9
  249. package/scripts/gh/git-ai-review-scan.ts +4 -2
  250. package/scripts/gh/git-gh-api-path.ts +15 -0
  251. package/scripts/gh/git-gh-branch-rules.ts +73 -0
  252. package/scripts/gh/git-gh-conditional.ts +5 -2
  253. package/scripts/gh/git-gh-issue-read.ts +5 -1
  254. package/scripts/gh/git-gh-issue-write.ts +67 -29
  255. package/scripts/gh/git-gh-issue.ts +7 -3
  256. package/scripts/gh/git-gh-poll-read.ts +89 -0
  257. package/scripts/gh/git-gh-pr-auto-merge.ts +8 -3
  258. package/scripts/gh/git-gh-pr-rest.ts +1 -1
  259. package/scripts/gh/git-gh-pr-snapshot.ts +33 -20
  260. package/scripts/gh/git-gh-pr.ts +27 -15
  261. package/scripts/gh/git-pr-checks-eval.ts +39 -7
  262. package/scripts/gh/git-pr-checks-parse.ts +39 -9
  263. package/scripts/gh/git-pr-merge-checked.ts +80 -0
  264. package/scripts/git/base-tree.ts +19 -2
  265. package/scripts/git/changed-file-scope.ts +6 -4
  266. package/scripts/git/changed-paths.ts +18 -1
  267. package/scripts/git/git-diff-reads.ts +27 -2
  268. package/scripts/git/git-grep-hits.ts +85 -0
  269. package/scripts/git/git-location-environment.ts +1 -1
  270. package/scripts/git/git-merge-conflicts.ts +83 -0
  271. package/scripts/git/git-preflight.ts +37 -12
  272. package/scripts/git/git-push-transport.ts +1 -2
  273. package/scripts/git/git-schemas.ts +17 -7
  274. package/scripts/git/git-spawn.ts +1 -2
  275. package/scripts/git/git-status.ts +4 -4
  276. package/scripts/git/main-merge-main.ts +12 -0
  277. package/scripts/git/main-merge-regenerate.ts +2 -2
  278. package/scripts/git/main-merge.ts +25 -9
  279. package/scripts/git/main-sync-main.ts +12 -0
  280. package/scripts/git/main-sync.ts +0 -9
  281. package/scripts/git/stash/git-stash.ts +27 -4
  282. package/scripts/git/stash/{stash-pop-args.ts → stash-args.ts} +13 -10
  283. package/scripts/git/stash/stash-pop-cli.ts +6 -12
  284. package/scripts/git/stash/stash-pop-main.ts +12 -0
  285. package/scripts/git/stash/stash-push-cli.ts +76 -0
  286. package/scripts/git/stash/stash-push-main.ts +12 -0
  287. package/scripts/hooks/batch-guard.ts +0 -8
  288. package/scripts/hooks/check-commit-message-main.ts +8 -0
  289. package/scripts/hooks/check-commit-message.ts +4 -7
  290. package/scripts/hooks/format-edited-file.ts +8 -24
  291. package/scripts/hooks/pre-commit-lint.ts +30 -3
  292. package/scripts/hooks/pre-push-unit.ts +4 -2
  293. package/scripts/hooks/pretool-guard-cli.ts +1 -8
  294. package/scripts/hooks/pretool-guard.ts +32 -19
  295. package/scripts/hooks/reserved-run.ts +67 -9
  296. package/scripts/hooks/run-hook.sh +13 -4
  297. package/scripts/hooks/shell-rules-notice.ts +37 -0
  298. package/scripts/hooks/stop-actions.ts +2 -21
  299. package/scripts/hooks/stop-guard.ts +13 -9
  300. package/scripts/init/hook-command-rewrite.ts +19 -5
  301. package/scripts/init/hook-launch.ts +15 -17
  302. package/scripts/init/init-actions.ts +0 -6
  303. package/scripts/init/init-ai-copy.ts +10 -36
  304. package/scripts/init/init-bootstrap.ts +9 -8
  305. package/scripts/init/init-dry-run-report.ts +1 -1
  306. package/scripts/init/init-dry-run.ts +1 -1
  307. package/scripts/init/init-file-action.ts +7 -9
  308. package/scripts/init/init-logic-json-merge.ts +2 -2
  309. package/scripts/init/init-logic-migrate.ts +9 -82
  310. package/scripts/init/init-logic.ts +3 -2
  311. package/scripts/init/init-main.ts +12 -0
  312. package/scripts/init/init.ts +5 -12
  313. package/scripts/init/kit-development-versions.ts +3 -7
  314. package/scripts/init/kit-written-paths.ts +2 -2
  315. package/scripts/init/project-profile.ts +5 -4
  316. package/scripts/init/tsconfig-preset-migration.ts +2 -1
  317. package/scripts/init/vscode-tasks.ts +1 -1
  318. package/scripts/issue/defect-origin-cli.ts +106 -0
  319. package/scripts/issue/defect-origin-line.ts +60 -0
  320. package/scripts/issue/defect-origin-main.ts +11 -0
  321. package/scripts/issue/defect-origin.ts +114 -0
  322. package/scripts/issue/defect-rate-cli.ts +34 -78
  323. package/scripts/issue/defect-rate.ts +0 -16
  324. package/scripts/issue/defect-report-cli.ts +128 -0
  325. package/scripts/issue/defect-report-format.ts +56 -0
  326. package/scripts/issue/defect-report-main.ts +11 -0
  327. package/scripts/issue/defect-report.ts +160 -0
  328. package/scripts/issue/expected-effect-lint.ts +1 -0
  329. package/scripts/issue/issue-already-done-cli.ts +62 -0
  330. package/scripts/issue/issue-body-or-comment.ts +40 -0
  331. package/scripts/issue/issue-cite-cli.ts +0 -9
  332. package/scripts/issue/issue-cite-main.ts +12 -0
  333. package/scripts/issue/issue-classification.ts +12 -7
  334. package/scripts/issue/issue-comment-cli.ts +10 -24
  335. package/scripts/issue/issue-comment-main.ts +12 -0
  336. package/scripts/issue/issue-evidence-exit.ts +100 -0
  337. package/scripts/issue/issue-file-cli.ts +29 -7
  338. package/scripts/issue/issue-file.ts +19 -19
  339. package/scripts/issue/issue-fold-cli.ts +2 -11
  340. package/scripts/issue/issue-fold-main.ts +12 -0
  341. package/scripts/issue/issue-labels.ts +81 -90
  342. package/scripts/issue/issue-lint-cli.ts +2 -10
  343. package/scripts/issue/issue-lint-main.ts +12 -0
  344. package/scripts/issue/issue-measured-cli.ts +56 -0
  345. package/scripts/issue/issue-merged.ts +19 -2
  346. package/scripts/issue/issue-not-before-label.ts +135 -0
  347. package/scripts/issue/issue-not-before.ts +111 -0
  348. package/scripts/issue/issue-number-shape.ts +15 -1
  349. package/scripts/issue/issue-park.ts +28 -0
  350. package/scripts/issue/issue-plan-cli.ts +151 -0
  351. package/scripts/issue/issue-priority.ts +151 -0
  352. package/scripts/issue/issue-rank.ts +7 -1
  353. package/scripts/issue/issue-read-cli.ts +3 -10
  354. package/scripts/issue/issue-read-main.ts +12 -0
  355. package/scripts/issue/issue-read.ts +29 -5
  356. package/scripts/issue/issue-release-cli.ts +0 -10
  357. package/scripts/issue/issue-release-main.ts +13 -0
  358. package/scripts/issue/issue-release.ts +7 -12
  359. package/scripts/issue/issue-sample-gate.ts +192 -0
  360. package/scripts/issue/issue-sample-source.ts +76 -0
  361. package/scripts/issue/issue-scout-cli.ts +0 -11
  362. package/scripts/issue/issue-scout-main.ts +14 -0
  363. package/scripts/issue/issue-state-cli.ts +0 -10
  364. package/scripts/issue/issue-state-main.ts +12 -0
  365. package/scripts/issue/issue-watch-diff.ts +56 -15
  366. package/scripts/issue/issue-watch.ts +2 -1
  367. package/scripts/issue/issue-wip.ts +2 -7
  368. package/scripts/issue/measure-rerun-cli.ts +13 -8
  369. package/scripts/issue/plan-consumers-cli.ts +39 -0
  370. package/scripts/issue/plan-consumers-main.ts +11 -0
  371. package/scripts/issue/plan-consumers-section.ts +55 -0
  372. package/scripts/issue/plan-consumers.ts +127 -0
  373. package/scripts/josh/agent-session-environment.ts +1 -1
  374. package/scripts/josh/command-usage.ts +15 -43
  375. package/scripts/josh/file-map-stamp.ts +49 -16
  376. package/scripts/josh/hook-decision.ts +32 -20
  377. package/scripts/josh/josh-command-map.ts +4 -1
  378. package/scripts/josh/josh-command-types.ts +12 -6
  379. package/scripts/josh/josh-commands-agent-hooks.ts +83 -0
  380. package/scripts/josh/josh-commands-ai.ts +157 -158
  381. package/scripts/josh/josh-commands-backlog.ts +82 -16
  382. package/scripts/josh/josh-commands-clone.ts +1 -0
  383. package/scripts/josh/josh-commands-development.ts +111 -71
  384. package/scripts/josh/josh-commands-document.ts +43 -1
  385. package/scripts/josh/josh-commands-epic.ts +171 -0
  386. package/scripts/josh/josh-commands-hooks.ts +25 -2
  387. package/scripts/josh/josh-commands-issue-write.ts +181 -0
  388. package/scripts/josh/josh-commands-issue.ts +124 -24
  389. package/scripts/josh/josh-commands-lane.ts +103 -2
  390. package/scripts/josh/josh-commands-lint.ts +19 -8
  391. package/scripts/josh/josh-commands-maintenance.ts +112 -4
  392. package/scripts/josh/josh-commands-pause.ts +29 -0
  393. package/scripts/josh/josh-commands-progress.ts +87 -0
  394. package/scripts/josh/josh-commands-project.ts +138 -9
  395. package/scripts/josh/josh-commands-review.ts +124 -0
  396. package/scripts/josh/josh-commands-run.ts +211 -23
  397. package/scripts/josh/josh-commands-ship.ts +169 -0
  398. package/scripts/josh/josh-commands-split.ts +9 -0
  399. package/scripts/josh/josh-commands-versioning.ts +49 -2
  400. package/scripts/josh/josh-commands-workflow.ts +144 -6
  401. package/scripts/josh/josh-logic.ts +6 -13
  402. package/scripts/josh/package-directory.ts +2 -4
  403. package/scripts/josh/process-identity.ts +13 -4
  404. package/scripts/josh/session-language-cli.ts +4 -8
  405. package/scripts/josh/session-language-main.ts +13 -0
  406. package/scripts/josh/session-language.ts +6 -1
  407. package/scripts/josh/shared-cache.ts +90 -0
  408. package/scripts/josh/stamp-file.ts +9 -15
  409. package/scripts/lane/lane-await.ts +51 -12
  410. package/scripts/lane/lane-cache.ts +5 -30
  411. package/scripts/lane/lane-capacity.ts +14 -23
  412. package/scripts/lane/lane-check-stats.ts +62 -21
  413. package/scripts/lane/lane-child-invocation.ts +8 -0
  414. package/scripts/lane/lane-cli.ts +15 -5
  415. package/scripts/lane/lane-close.ts +86 -18
  416. package/scripts/lane/lane-core-wait-stats.ts +66 -0
  417. package/scripts/lane/lane-dispatch.ts +24 -3
  418. package/scripts/lane/lane-gap-stats.ts +156 -0
  419. package/scripts/lane/lane-handoff.ts +69 -1
  420. package/scripts/lane/lane-held-stats.ts +129 -0
  421. package/scripts/lane/lane-install.ts +4 -11
  422. package/scripts/lane/lane-launch-cli.ts +0 -9
  423. package/scripts/lane/lane-launch-main.ts +12 -0
  424. package/scripts/lane/lane-ledger-schema.ts +266 -0
  425. package/scripts/lane/lane-ledger.ts +92 -123
  426. package/scripts/lane/lane-limit-cli.ts +12 -1
  427. package/scripts/lane/lane-measure-cli.ts +57 -11
  428. package/scripts/lane/lane-open.ts +9 -1
  429. package/scripts/lane/lane-parked.ts +3 -3
  430. package/scripts/lane/lane-pause-cli.ts +130 -0
  431. package/scripts/lane/lane-pause.ts +158 -0
  432. package/scripts/lane/lane-process-table.ts +166 -0
  433. package/scripts/lane/lane-reap-settle.ts +124 -0
  434. package/scripts/lane/lane-reap.ts +50 -15
  435. package/scripts/lane/lane-registry.ts +24 -3
  436. package/scripts/lane/lane-residents.ts +162 -0
  437. package/scripts/lane/lane-restart.ts +22 -2
  438. package/scripts/lane/lane-round-two-stats.ts +49 -0
  439. package/scripts/lane/lane-sampler.ts +4 -0
  440. package/scripts/lane/lane-session-action.ts +19 -5
  441. package/scripts/lane/lane-session-broker.ts +102 -21
  442. package/scripts/lane/lane-snapshot-trace.ts +84 -0
  443. package/scripts/lane/lane-spans.ts +51 -0
  444. package/scripts/lane/lane-spent.ts +6 -3
  445. package/scripts/lane/lane-stage-stats.ts +7 -2
  446. package/scripts/lane/lane-state.ts +302 -0
  447. package/scripts/lane/lane-stats.ts +58 -4
  448. package/scripts/lane/lane-stop-stats.ts +113 -37
  449. package/scripts/lane/lane-test-related-stats.ts +127 -0
  450. package/scripts/lane/lane-transcript-calls.ts +145 -0
  451. package/scripts/lane/lane-transcript-stats.ts +168 -0
  452. package/scripts/lane/lane-vacant.ts +13 -3
  453. package/scripts/lane/lane-withdraw-cli.ts +5 -4
  454. package/scripts/lane/lane-withdraw.ts +50 -49
  455. package/scripts/lane/process-directories.ts +70 -0
  456. package/scripts/lane/process-lane-marks.ts +94 -0
  457. package/scripts/lib/atomic-write.ts +62 -0
  458. package/scripts/lib/buffered-process.ts +12 -5
  459. package/scripts/lib/cli-flags.ts +53 -0
  460. package/scripts/lib/figure-format.ts +63 -0
  461. package/scripts/lib/json-value.ts +9 -1
  462. package/scripts/lib/package-manifest.ts +35 -0
  463. package/scripts/lib/read-file.ts +3 -1
  464. package/scripts/lib/stamped-memo.ts +63 -0
  465. package/scripts/lib/stdout-on-stderr.ts +24 -0
  466. package/scripts/lib/timeouts.ts +9 -0
  467. package/scripts/lib/transcript-record.ts +91 -0
  468. package/scripts/lines/effective-limit.ts +1 -1
  469. package/scripts/lint/eslint-cache-dependencies.ts +145 -0
  470. package/scripts/lint/eslint-daemon.ts +265 -0
  471. package/scripts/lint/format.ts +11 -2
  472. package/scripts/lint/import-graph.ts +279 -0
  473. package/scripts/lint/lint-gate-scope.ts +102 -0
  474. package/scripts/lint/lint-parallel-main.ts +19 -0
  475. package/scripts/lint/lint-parallel.ts +62 -30
  476. package/scripts/lint/lint-related-scope.ts +30 -24
  477. package/scripts/lint/lint-related.ts +38 -6
  478. package/scripts/notify/confirmation-options.ts +1 -2
  479. package/scripts/notify/telegram-notify.ts +20 -20
  480. package/scripts/notify/telegram-test-logic.ts +0 -1
  481. package/scripts/notify/telegram-test-main.ts +8 -0
  482. package/scripts/notify/telegram-test.ts +2 -6
  483. package/scripts/observations/observation-ledger.ts +13 -0
  484. package/scripts/observations/observations-flush-landing.ts +5 -3
  485. package/scripts/observations/observations-flush.ts +6 -1
  486. package/scripts/overrides/overrides-check.ts +2 -5
  487. package/scripts/overrides/overrides-files.ts +2 -1
  488. package/scripts/overrides/overrides-logic.ts +3 -6
  489. package/scripts/package/verify-optional-eslint-install.ts +8 -6
  490. package/scripts/propagate/propagate-publish.ts +2 -7
  491. package/scripts/propagate/propagate-targets.ts +4 -12
  492. package/scripts/refactor/import-graph.ts +9 -7
  493. package/scripts/release/github-release-runs.ts +17 -6
  494. package/scripts/release/release-approval-prune.ts +18 -0
  495. package/scripts/release/release-history.ts +1 -3
  496. package/scripts/release/release-progress.ts +42 -22
  497. package/scripts/release/release-publish-run.ts +39 -0
  498. package/scripts/release/release-publish.ts +6 -6
  499. package/scripts/release/release-scope-cli.ts +0 -10
  500. package/scripts/release/release-scope-main.ts +12 -0
  501. package/scripts/repo/repo-setting.ts +3 -6
  502. package/scripts/repo/required-checks-logic.ts +6 -15
  503. package/scripts/report/report-format-reference.ts +2 -0
  504. package/scripts/report/report-labels.ts +155 -0
  505. package/scripts/report/report-lint-cli.ts +3 -0
  506. package/scripts/report/report-lint.ts +85 -110
  507. package/scripts/report/report-template-cli.ts +59 -0
  508. package/scripts/report/report-template.ts +112 -0
  509. package/scripts/review/acceptance-map.ts +1 -0
  510. package/scripts/review/removed-tests-check.ts +86 -0
  511. package/scripts/review/removed-tests.ts +149 -0
  512. package/scripts/review/review-brief-cli.ts +81 -15
  513. package/scripts/review/review-brief-main.ts +12 -0
  514. package/scripts/review/review-brief.ts +31 -3
  515. package/scripts/review/review-code-tree.ts +10 -6
  516. package/scripts/review/review-comment-round.ts +26 -8
  517. package/scripts/review/review-finding-ledger.ts +30 -15
  518. package/scripts/review/review-interaction.ts +94 -0
  519. package/scripts/review/review-readers-scan.ts +163 -0
  520. package/scripts/review/review-record-cli.ts +69 -30
  521. package/scripts/review/review-record-main.ts +12 -0
  522. package/scripts/review/review-round-one-blobs.ts +221 -0
  523. package/scripts/review/review-round2-cli.ts +49 -12
  524. package/scripts/review/review-round2.ts +80 -12
  525. package/scripts/review/review-stamps.ts +19 -1
  526. package/scripts/review/review-stop-log.ts +96 -0
  527. package/scripts/review/review-stops-cli.ts +85 -0
  528. package/scripts/review/review-tree.ts +6 -17
  529. package/scripts/review/review-untouched-readers.ts +146 -0
  530. package/scripts/review/test-titles.ts +118 -0
  531. package/scripts/rules/agent-model.ts +8 -0
  532. package/scripts/rules/bash-triggers.ts +46 -3
  533. package/scripts/rules/decision-oracle-batch.ts +9 -1
  534. package/scripts/rules/decision-oracle.ts +2 -2
  535. package/scripts/rules/delivered-rules.ts +80 -2
  536. package/scripts/rules/destructive-command.ts +8 -1
  537. package/scripts/rules/direct-filing.ts +10 -2
  538. package/scripts/rules/direct-issue-comment.ts +117 -0
  539. package/scripts/rules/direct-pr-create.ts +69 -3
  540. package/scripts/rules/early-heartbeat.ts +2 -1
  541. package/scripts/rules/file-body.ts +7 -0
  542. package/scripts/rules/filing-cap.ts +7 -0
  543. package/scripts/rules/git-argv.ts +72 -14
  544. package/scripts/rules/git-force.ts +12 -2
  545. package/scripts/rules/guard-remedy.ts +4 -0
  546. package/scripts/rules/implementation-cut-verdict.ts +1 -1
  547. package/scripts/rules/implementation-cut.ts +11 -3
  548. package/scripts/rules/index-guard.ts +8 -1
  549. package/scripts/rules/issue-comments.ts +9 -1
  550. package/scripts/rules/josh-git-bare.ts +7 -0
  551. package/scripts/rules/lane-background.ts +67 -25
  552. package/scripts/rules/lane-carry-conflict.ts +6 -0
  553. package/scripts/rules/lane-direct-tool.ts +74 -0
  554. package/scripts/rules/lane-interactive-ask.ts +9 -2
  555. package/scripts/rules/lane-park.ts +45 -23
  556. package/scripts/rules/lane-split-park.ts +10 -2
  557. package/scripts/rules/lane-switch-main.ts +7 -0
  558. package/scripts/rules/oracle-consulted.ts +10 -0
  559. package/scripts/rules/oracle-firing.ts +1 -0
  560. package/scripts/rules/permission-guards.ts +3 -0
  561. package/scripts/rules/piped-verification.ts +1 -1
  562. package/scripts/rules/poll-loop.ts +7 -0
  563. package/scripts/rules/pr-merge.ts +123 -0
  564. package/scripts/rules/protected-files.ts +32 -5
  565. package/scripts/rules/raw-field-body.ts +6 -0
  566. package/scripts/rules/rule-body-guard.ts +8 -0
  567. package/scripts/rules/rule-list.ts +9 -28
  568. package/scripts/rules/rule-value-cache.ts +4 -9
  569. package/scripts/rules/rule-value-cli.ts +51 -32
  570. package/scripts/rules/rule-value.ts +1 -1
  571. package/scripts/rules/shell-segments.ts +35 -0
  572. package/scripts/rules/stop-rule-rows.ts +64 -0
  573. package/scripts/rules/stop-rules.ts +3 -4
  574. package/scripts/rules/test-declared-commit.ts +11 -1
  575. package/scripts/rules/third-party-write.ts +7 -0
  576. package/scripts/rules/timed-rerun.ts +69 -0
  577. package/scripts/rules/worktree-guard.ts +13 -3
  578. package/scripts/run/board/run-board-app-name.ts +23 -0
  579. package/scripts/run/board/run-board-cli.ts +65 -32
  580. package/scripts/run/board/run-board-earlier.ts +94 -0
  581. package/scripts/run/board/run-board-ending-reason.ts +67 -0
  582. package/scripts/run/board/run-board-estimate-schedule.ts +103 -0
  583. package/scripts/run/board/run-board-estimate.ts +98 -0
  584. package/scripts/run/board/run-board-fit.ts +153 -36
  585. package/scripts/run/board/run-board-fold.ts +123 -0
  586. package/scripts/run/board/run-board-fresh.ts +2 -2
  587. package/scripts/run/board/run-board-gather-live.ts +29 -0
  588. package/scripts/run/board/run-board-gather-thread.ts +189 -0
  589. package/scripts/run/board/run-board-gather-worker.ts +29 -0
  590. package/scripts/run/board/run-board-gather.ts +187 -0
  591. package/scripts/run/board/run-board-github.ts +118 -38
  592. package/scripts/run/board/run-board-header.ts +82 -20
  593. package/scripts/run/board/run-board-keys.ts +58 -0
  594. package/scripts/run/board/run-board-kind.ts +20 -6
  595. package/scripts/run/board/run-board-labels.ts +116 -71
  596. package/scripts/run/board/run-board-lane-state.ts +109 -0
  597. package/scripts/run/board/run-board-lane-time.ts +122 -0
  598. package/scripts/run/board/run-board-layout.ts +239 -60
  599. package/scripts/run/board/run-board-length.ts +52 -0
  600. package/scripts/run/board/run-board-machine.ts +8 -4
  601. package/scripts/run/board/run-board-main.ts +12 -0
  602. package/scripts/run/board/run-board-notes.ts +52 -31
  603. package/scripts/run/board/run-board-now.ts +1 -1
  604. package/scripts/run/board/run-board-operation.ts +15 -33
  605. package/scripts/run/board/run-board-phase.ts +1 -1
  606. package/scripts/run/board/run-board-plan-shared.ts +115 -0
  607. package/scripts/run/board/run-board-plan.ts +55 -3
  608. package/scripts/run/board/run-board-planning.ts +45 -0
  609. package/scripts/run/board/run-board-priority.ts +44 -0
  610. package/scripts/run/board/run-board-process-groups.ts +195 -0
  611. package/scripts/run/board/run-board-read.ts +151 -27
  612. package/scripts/run/board/run-board-reason.ts +235 -51
  613. package/scripts/run/board/run-board-released.ts +35 -0
  614. package/scripts/run/board/run-board-render-checks.ts +39 -5
  615. package/scripts/run/board/run-board-render-condition.ts +96 -0
  616. package/scripts/run/board/run-board-render-drawn.ts +67 -0
  617. package/scripts/run/board/run-board-render-foot.ts +59 -0
  618. package/scripts/run/board/run-board-render-icon.ts +35 -0
  619. package/scripts/run/board/run-board-render-lanes.ts +145 -0
  620. package/scripts/run/board/run-board-render-lead.ts +80 -0
  621. package/scripts/run/board/run-board-render-legend.ts +117 -48
  622. package/scripts/run/board/run-board-render-notes.ts +156 -29
  623. package/scripts/run/board/run-board-render-processes.ts +196 -0
  624. package/scripts/run/board/run-board-render-section.ts +119 -0
  625. package/scripts/run/board/run-board-render-slot.ts +3 -36
  626. package/scripts/run/board/run-board-render-tail.ts +115 -48
  627. package/scripts/run/board/run-board-render-time.ts +56 -0
  628. package/scripts/run/board/run-board-render-title.ts +117 -24
  629. package/scripts/run/board/run-board-render-waits.ts +104 -20
  630. package/scripts/run/board/run-board-render.ts +207 -265
  631. package/scripts/run/board/run-board-roots.ts +54 -0
  632. package/scripts/run/board/run-board-row-yield.ts +9 -4
  633. package/scripts/run/board/run-board-setup.ts +1 -12
  634. package/scripts/run/board/run-board-snapshot.ts +111 -0
  635. package/scripts/run/board/run-board-spin.ts +2 -2
  636. package/scripts/run/board/run-board-state.ts +22 -33
  637. package/scripts/run/board/run-board-status.ts +147 -71
  638. package/scripts/run/board/run-board-thanks-read.ts +2 -2
  639. package/scripts/run/board/run-board-tick.ts +122 -107
  640. package/scripts/run/board/run-board-usage-board.ts +78 -0
  641. package/scripts/run/board/run-board-usage-lanes.ts +113 -0
  642. package/scripts/run/board/run-board-usage-listing.ts +93 -0
  643. package/scripts/run/board/run-board-usage-read.ts +120 -150
  644. package/scripts/run/board/run-board-usage-rusage.ts +19 -7
  645. package/scripts/run/board/run-board-usage-text.ts +139 -51
  646. package/scripts/run/board/run-board-usage-top.ts +102 -0
  647. package/scripts/run/board/run-board-usage.ts +89 -72
  648. package/scripts/run/board/run-board-usual.ts +20 -9
  649. package/scripts/run/carry/run-carry-args.ts +4 -7
  650. package/scripts/run/carry/run-carry-conversation.ts +1 -1
  651. package/scripts/run/carry/run-carry.ts +9 -4
  652. package/scripts/run/cut/run-cut-handoff.ts +2 -2
  653. package/scripts/run/event/run-event-cli.ts +1 -5
  654. package/scripts/run/event/run-event-filed.ts +12 -6
  655. package/scripts/run/event/run-event-follow.ts +2 -3
  656. package/scripts/run/event/run-event-render.ts +6 -10
  657. package/scripts/run/event/run-event-scope.ts +2 -2
  658. package/scripts/run/event/run-event-stream-emit.ts +82 -22
  659. package/scripts/run/event/run-event-stream.ts +34 -8
  660. package/scripts/run/hold/run-hold-adopt.ts +65 -0
  661. package/scripts/run/hold/run-hold-cli.ts +93 -22
  662. package/scripts/run/hold/run-hold-main.ts +12 -0
  663. package/scripts/run/hold/run-hold-member.ts +37 -0
  664. package/scripts/run/hold/run-stop-notify.ts +183 -0
  665. package/scripts/run/merge/run-merge-auth.ts +31 -0
  666. package/scripts/run/merge/run-merge-cli.ts +62 -48
  667. package/scripts/run/merge/run-merge-close.ts +74 -0
  668. package/scripts/run/merge/run-merge-collect.ts +6 -13
  669. package/scripts/run/merge/run-merge-driver.ts +71 -0
  670. package/scripts/run/merge/run-merge-main.ts +12 -0
  671. package/scripts/run/merge/run-merge-outcome.ts +23 -0
  672. package/scripts/run/merge/run-merge-restart.ts +39 -0
  673. package/scripts/run/merge/run-merge-ship.ts +20 -4
  674. package/scripts/run/merge/run-merge-signals.ts +33 -9
  675. package/scripts/run/merge/run-merge-steps.ts +120 -85
  676. package/scripts/run/merge/run-merge.ts +38 -37
  677. package/scripts/run/park/run-park-cli.ts +91 -0
  678. package/scripts/run/park/run-park.ts +88 -0
  679. package/scripts/run/park/run-stalled.ts +68 -0
  680. package/scripts/run/pause/run-pause-cli.ts +73 -0
  681. package/scripts/run/pause/run-pause.ts +251 -0
  682. package/scripts/run/progress/run-progress-cli.ts +4 -12
  683. package/scripts/run/progress/run-progress-clock.ts +1 -1
  684. package/scripts/run/progress/run-progress-config.ts +6 -14
  685. package/scripts/run/progress/run-progress-main.ts +12 -0
  686. package/scripts/run/progress/run-progress.ts +1 -4
  687. package/scripts/run/review/run-review.ts +2 -1
  688. package/scripts/run/run-ending.ts +1 -0
  689. package/scripts/run/run-invocation.ts +5 -6
  690. package/scripts/run/run-liveness-cli.ts +6 -8
  691. package/scripts/run/run-liveness.ts +60 -29
  692. package/scripts/run/run-next.ts +1 -1
  693. package/scripts/run/run-parent-cut-hook.ts +2 -2
  694. package/scripts/run/run-preflight.ts +18 -3
  695. package/scripts/run/run-prep-cli.ts +1 -10
  696. package/scripts/run/run-prep-locate.ts +7 -50
  697. package/scripts/run/run-prep-main.ts +12 -0
  698. package/scripts/run/run-prep.ts +6 -0
  699. package/scripts/run/run-report-cli.ts +101 -13
  700. package/scripts/run/run-report-handoff.ts +114 -0
  701. package/scripts/run/run-step.ts +1 -1
  702. package/scripts/run/run-stranded-detect.ts +13 -0
  703. package/scripts/run/run-watcher-guard-cli.ts +1 -1
  704. package/scripts/run/run-watcher-guard.ts +1 -1
  705. package/scripts/run/ship/run-ship-args.ts +121 -0
  706. package/scripts/run/ship/run-ship-body-draft.ts +110 -0
  707. package/scripts/run/ship/run-ship-cli.ts +63 -140
  708. package/scripts/run/ship/run-ship-detach.ts +19 -8
  709. package/scripts/run/ship/run-ship-infra-retry.ts +59 -0
  710. package/scripts/run/ship/run-ship-next.ts +18 -2
  711. package/scripts/run/ship/run-ship-overlap.ts +42 -5
  712. package/scripts/run/ship/run-ship-place.ts +96 -0
  713. package/scripts/run/ship/run-ship-pre-detach-timed.ts +43 -0
  714. package/scripts/run/ship/run-ship-pre-detach.ts +81 -24
  715. package/scripts/run/ship/run-ship-preflight.ts +137 -32
  716. package/scripts/run/ship/run-ship-probe.ts +11 -3
  717. package/scripts/run/ship/run-ship-relaunch-cap.ts +70 -0
  718. package/scripts/run/ship/run-ship-removed-rows.ts +61 -0
  719. package/scripts/run/ship/run-ship-return.ts +107 -23
  720. package/scripts/run/ship/run-ship-review-steps.ts +105 -151
  721. package/scripts/run/ship/run-ship-review.ts +73 -6
  722. package/scripts/run/ship/run-ship-reviewer.ts +207 -0
  723. package/scripts/run/ship/run-ship-stage.ts +55 -6
  724. package/scripts/run/ship/run-ship-steps.ts +46 -15
  725. package/scripts/run/ship/run-ship-stop-cause.ts +135 -0
  726. package/scripts/run/ship/run-ship-stop-text.ts +11 -6
  727. package/scripts/run/ship/run-ship-sync.ts +43 -6
  728. package/scripts/run/ship/run-ship.ts +30 -2
  729. package/scripts/run/tidy/run-tidy-cli.ts +0 -4
  730. package/scripts/run/tidy/run-tidy-lanes.ts +3 -0
  731. package/scripts/run/tidy/run-tidy-main.ts +8 -0
  732. package/scripts/run/wake/run-wake-cli.ts +119 -100
  733. package/scripts/run/wake/run-wake-code.ts +83 -0
  734. package/scripts/run/wake/run-wake-driver.ts +19 -8
  735. package/scripts/run/wake/run-wake-loop.ts +34 -3
  736. package/scripts/run/wake/run-wake-main.ts +13 -0
  737. package/scripts/run/wake/run-wake-ports.ts +90 -0
  738. package/scripts/run/wake/run-wake-takeover.ts +66 -0
  739. package/scripts/run/wake/run-wake.ts +2 -1
  740. package/scripts/safe-chain/pack-hook.ts +2 -2
  741. package/scripts/safe-chain/preinstall-command.ts +2 -1
  742. package/scripts/safe-chain/project-config.ts +3 -9
  743. package/scripts/security/security-audit-main.ts +8 -0
  744. package/scripts/security/security-audit-provision-logic.ts +0 -11
  745. package/scripts/security/security-audit-provision-main.ts +12 -0
  746. package/scripts/security/security-audit-provision.ts +11 -26
  747. package/scripts/security/security-audit.ts +6 -7
  748. package/scripts/self-sync-guard/self-sync-guard-logic.ts +6 -13
  749. package/scripts/split/split-assess-cli.ts +2 -2
  750. package/scripts/split/split-assess.ts +15 -0
  751. package/scripts/split/split-measure.ts +65 -0
  752. package/scripts/sync/claude-settings-merge.ts +8 -15
  753. package/scripts/sync/directory-copy-guard.ts +4 -9
  754. package/scripts/sync/file-content.ts +78 -8
  755. package/scripts/sync/sync-ai-files.ts +3 -5
  756. package/scripts/sync/sync-configs.ts +11 -23
  757. package/scripts/sync/sync-hook-safety.ts +4 -10
  758. package/scripts/sync/sync-main.ts +11 -0
  759. package/scripts/sync/sync.ts +25 -37
  760. package/scripts/test/test-declared-changed.ts +2 -2
  761. package/scripts/test/test-declared.ts +1 -1
  762. package/scripts/test/test-e2e-guard.ts +25 -1
  763. package/scripts/test/test-e2e-stamp.ts +38 -0
  764. package/scripts/test/test-pinned-logic.ts +145 -0
  765. package/scripts/test/test-pinned-main.ts +78 -0
  766. package/scripts/test/test-pinned.ts +100 -0
  767. package/scripts/test/test-read-map.ts +264 -0
  768. package/scripts/test/test-read-recording.ts +91 -0
  769. package/scripts/test/test-read-trace.ts +148 -0
  770. package/scripts/test/test-red-main.ts +12 -0
  771. package/scripts/test/test-red.ts +12 -30
  772. package/scripts/test/test-related-main.ts +18 -0
  773. package/scripts/test/test-related-record.ts +119 -0
  774. package/scripts/test/test-related-scope.ts +229 -43
  775. package/scripts/test/test-related.ts +300 -22
  776. package/scripts/test/test-unit-guard-main.ts +15 -0
  777. package/scripts/test/test-unit-guard.ts +42 -24
  778. package/scripts/test/unit-count-file.ts +37 -0
  779. package/scripts/test/unit-run-marker.ts +162 -0
  780. package/scripts/test/unit-setup-files.ts +51 -0
  781. package/scripts/test/unit-worker-share.ts +61 -149
  782. package/scripts/test/whole-suite-files.ts +63 -0
  783. package/scripts/time-runtime/time-background.ts +20 -2
  784. package/scripts/time-runtime/time-bundles.ts +4 -3
  785. package/scripts/time-runtime/time-density-hook.ts +8 -6
  786. package/scripts/time-runtime/time-followup-stage.ts +1 -3
  787. package/scripts/time-runtime/time-format.ts +5 -28
  788. package/scripts/time-runtime/time-markers.ts +10 -1
  789. package/scripts/time-runtime/time-shell.ts +97 -10
  790. package/scripts/time-runtime/time-transcript-line.ts +49 -62
  791. package/scripts/uninstall/uninstall.ts +1 -1
  792. package/scripts/version/bump-version-main.ts +12 -0
  793. package/scripts/version/bump-version.ts +25 -25
  794. package/scripts/version/effective-upstream.ts +6 -12
  795. package/scripts/version/latest-corepack.ts +17 -32
  796. package/scripts/version/latest-if-required-cli.ts +93 -0
  797. package/scripts/version/latest-lane-guard-main.ts +8 -0
  798. package/scripts/version/latest-lane-guard.ts +0 -4
  799. package/scripts/version/latest-scope-cli.ts +0 -9
  800. package/scripts/version/latest-scope-main.ts +12 -0
  801. package/scripts/version/latest-update.ts +5 -5
  802. package/scripts/version/npm-registry.ts +44 -6
  803. package/scripts/version/publishable-range-check.ts +5 -16
  804. package/scripts/version/release-age.ts +1 -1
  805. package/scripts/version/release-hold.ts +1 -1
  806. package/scripts/version/release-window.ts +38 -0
  807. package/scripts/version/running-binary.ts +1 -1
  808. package/scripts/version/safe-chain-version-update.ts +3 -8
  809. package/scripts/version/version-targets.ts +6 -28
  810. package/templates/dependabot.yml +29 -0
  811. package/templates/gitignore +4 -1
  812. package/templates/pnpm-workspace.basic.yaml +1 -1
  813. package/templates/sonar-project.properties +3 -2
  814. package/templates/workflows/ci.yml +12 -4
  815. package/templates/workflows/github-release.yml +4 -0
  816. package/tsconfig.sonar.json +1 -1
  817. package/.ncurc.json +0 -3
  818. package/dist/hooks/batch-guard.js +0 -29
  819. package/dist/hooks/chunk-4KKD2UTK.js +0 -66
  820. package/dist/hooks/chunk-6TS2JD6D.js +0 -237
  821. package/dist/hooks/chunk-7DSBJVFH.js +0 -50
  822. package/dist/hooks/chunk-A65Y4YOR.js +0 -79
  823. package/dist/hooks/chunk-CDY4NFQG.js +0 -15
  824. package/dist/hooks/chunk-EFXE6C37.js +0 -81
  825. package/dist/hooks/chunk-GP4IEC4O.js +0 -20
  826. package/dist/hooks/chunk-JP45SOCJ.js +0 -56
  827. package/dist/hooks/chunk-LAOV7NLM.js +0 -45
  828. package/dist/hooks/chunk-M4HGZV7U.js +0 -83
  829. package/dist/hooks/chunk-PF2NZL2A.js +0 -131
  830. package/dist/hooks/chunk-PTICX4OL.js +0 -358
  831. package/dist/hooks/chunk-RT27QRJW.js +0 -6247
  832. package/dist/hooks/chunk-SYOTDYCI.js +0 -3533
  833. package/dist/hooks/chunk-UPUZF3AN.js +0 -279
  834. package/dist/hooks/chunk-WK6SMBIC.js +0 -3180
  835. package/dist/hooks/duplicate-read-guard.js +0 -30
  836. package/dist/hooks/investigation-guard.js +0 -29
  837. package/scripts/backlog/backlog-stalled-cli.ts +0 -30
  838. package/scripts/cost-runtime/cost-format.ts +0 -29
  839. package/scripts/init/basic-path-migration.ts +0 -24
  840. package/scripts/issue/issue-backlinks-cli.ts +0 -93
  841. package/scripts/josh/josh-commands-guard.ts +0 -38
  842. package/scripts/josh/josh-usage-automation.ts +0 -121
  843. package/scripts/josh/josh-usage-backlog.ts +0 -180
  844. package/scripts/josh/josh-usage-developer.ts +0 -230
  845. package/scripts/josh/josh-usage-hooks.ts +0 -38
  846. package/scripts/josh/josh-usage-issue.ts +0 -205
  847. package/scripts/josh/josh-usage-review.ts +0 -101
  848. package/scripts/josh/josh-usage-run.ts +0 -252
  849. package/scripts/josh/josh-usage-session.ts +0 -238
  850. package/scripts/josh/josh-usage-workflow.ts +0 -212
  851. package/scripts/lint/cross-file-recheck.ts +0 -155
  852. package/scripts/registry-migration/migrate-logic.ts +0 -237
  853. package/scripts/registry-migration/migrate.ts +0 -292
  854. package/scripts/registry-migration/user-npmrc.ts +0 -15
  855. package/scripts/rules/rule-guard.ts +0 -23
  856. package/scripts/rules/rule-registry-rows.ts +0 -292
  857. package/scripts/rules/rule-registry.ts +0 -112
  858. package/scripts/run/run-stranded-cli.ts +0 -27
@@ -1,11 +1,17 @@
1
- #!/usr/bin/env tsx
2
- import { existsSync } from 'node:fs'
3
- import { fileURLToPath } from 'node:url'
1
+ import { existsSync, readFileSync } from 'node:fs'
2
+ import path from 'node:path'
3
+ import { gate_plan } from '#scripts/gate/gate-plan'
4
4
  import type { GateTree } from '#scripts/gate/gate-tree'
5
+ import { input_fingerprint } from '#scripts/gate/input-fingerprint'
6
+ import { moved_paths } from '#scripts/gate/moved-paths'
5
7
  import { scoped_green } from '#scripts/gate/scoped-green'
8
+ import { since_green } from '#scripts/gate/since-green'
6
9
  import { changed_file_scope } from '#scripts/git/changed-file-scope'
10
+ import { changed_paths } from '#scripts/git/changed-paths'
7
11
  import { review_stamps } from '#scripts/review/review-stamps'
8
- import { related_scope } from './test-related-scope'
12
+ import { test_read_map, type ReadMap } from './test-read-map'
13
+ import { test_related_record, type RunInput } from './test-related-record'
14
+ import { related_scope, type RelatedScope, type ScopeRequest } from './test-related-scope'
9
15
  import { test_unit_guard } from './test-unit-guard'
10
16
 
11
17
  // `josh test:related` — the unit check an implementation loop runs between edits.
@@ -30,27 +36,303 @@ function conclusive_tree(before: GateTree | undefined): GateTree | undefined {
30
36
  return test_unit_guard.is_running(process.cwd()) ? before : undefined
31
37
  }
32
38
 
33
- async function run_related_tests(command_arguments: ReadonlyArray<string>): Promise<number> {
34
- const root = await changed_file_scope.repository_root_or_cwd()
35
- const scope = await changed_file_scope.resolve_command_scope({
36
- command_arguments,
39
+ // The change a narrowing reads, and the map it reads it against. `is_unmoved` is the since-green
40
+ // reading's positive fact that nothing moved since this command was last green on this checkout.
41
+ // `synced` is the part of the change a main sync brought in, kept for the run's ledger record, and
42
+ // `since_map` the part the change since the map's tree joined to what this change moved.
43
+ type ChangeReading = Pick<ScopeRequest, 'changed' | 'map' | 'since_map'> & {
44
+ is_unmoved?: true
45
+ synced?: ReadonlyArray<string>
46
+ }
47
+
48
+ // A failure answers `undefined` rather than an empty list: the two are opposite inputs to
49
+ // `resolve_scope`, and only one of them means "could not tell".
50
+ async function read_or_undefined(
51
+ read: () => Promise<ReadonlyArray<string>>,
52
+ ): Promise<ReadonlyArray<string> | undefined> {
53
+ try {
54
+ return await read()
55
+ } catch {
56
+ return undefined
57
+ }
58
+ }
59
+
60
+ async function branch_change(): Promise<ReadonlyArray<string> | undefined> {
61
+ return await read_or_undefined(async () => await changed_paths.read_changed_paths(false))
62
+ }
63
+
64
+ // **The change a map answers for is the change since the tree it was recorded on** — its commit and
65
+ // the content its dirty files held then (`test_read_map.changed_since_tree`). A commit git can no
66
+ // longer resolve — a pruned or foreign map — leaves the branch change with no map, which runs the
67
+ // whole suite on any non-code file.
68
+ async function change_since(
69
+ root: string,
70
+ map: ReadMap,
71
+ ): Promise<ReadonlyArray<string> | undefined> {
72
+ const since = await read_or_undefined(
73
+ async () => await changed_paths.read_changed_since(map.commit),
74
+ )
75
+
76
+ if (since === undefined) return undefined
77
+
78
+ return test_read_map.changed_since_tree(
79
+ map,
80
+ since,
81
+ input_fingerprint.of_files(root, Object.keys(map.dirty)),
82
+ )
83
+ }
84
+
85
+ // **The map's tree is whichever lane last ran the whole suite green**, so the change since it holds that
86
+ // lane's own branch change too (joshuafolkken/kit#4527). What this branch did not change is marked
87
+ // `since_map`: it still reaches its readers — a source file only when it names what moved — but only
88
+ // this branch's change can send the run to the whole suite. A branch change git cannot read marks nothing.
89
+ async function map_change(root: string, map: ReadMap): Promise<ChangeReading> {
90
+ const changed = await change_since(root, map)
91
+
92
+ if (changed === undefined) return { changed: await branch_change(), map: undefined }
93
+
94
+ const branch = await branch_change()
95
+
96
+ if (branch === undefined) return { changed, map }
97
+
98
+ return { changed, map, since_map: changed.filter((file) => !branch.includes(file)) }
99
+ }
100
+
101
+ // Explicit file arguments win over the git reading, which is what makes the narrowing testable by
102
+ // hand and usable from a hook that already knows which file it just wrote. **The map still answers
103
+ // only for the change since its tree**, so that change joins the arguments: a test added since the
104
+ // map was recorded is in no entry, and only its own appearance in the change runs it — a source file
105
+ // there only when it names a file the arguments moved (`naming_moved`).
106
+ async function explicit_change(
107
+ root: string,
108
+ explicit: ReadonlyArray<string>,
109
+ map: ReadMap | undefined,
110
+ ): Promise<ChangeReading> {
111
+ const since = map === undefined ? undefined : await change_since(root, map)
112
+
113
+ if (since === undefined) return { changed: explicit, map: undefined }
114
+
115
+ const named = new Set(explicit)
116
+ const since_map = since.filter((file) => !named.has(file))
117
+
118
+ return { changed: [...named, ...since_map], map, since_map }
119
+ }
120
+
121
+ // **A non-code file a main sync brought in is not this branch's change** (joshuafolkken/kit#4572), so it
122
+ // joins `since_map`: it still reaches the tests reading it, but never sends the run to the whole suite —
123
+ // main's CI verified it. A synced module stays a moved file, so `vitest related` still walks to the
124
+ // tests importing it, a branch-only one among them. A branch change git cannot read marks nothing.
125
+ async function synced_data(synced: ReadonlyArray<string>): Promise<ReadonlyArray<string>> {
126
+ const data = synced.filter((file) => !related_scope.is_relatable(file))
127
+
128
+ if (data.length === 0) return []
129
+
130
+ const branch = (await branch_change()) ?? data
131
+
132
+ return data.filter((file) => !branch.includes(file))
133
+ }
134
+
135
+ // **What moved since this command's last green run** (`since-green.ts`), read as explicit arguments
136
+ // are. A moved file — code or not — reaches the tests reading it as data through the map, whose
137
+ // entries hold no module that started reading it after the map's tree; the change since that tree
138
+ // joins the list — its test files, and a source file only when it names a moved file
139
+ // (`naming_moved`) — so such a module runs the tests importing it. Nothing moved runs nothing; no map,
140
+ // or one git can no longer diff against, answers `undefined`, which reads the whole branch change.
141
+ async function since_green_change(
142
+ root: string,
143
+ map: ReadMap | undefined,
144
+ ): Promise<ChangeReading | undefined> {
145
+ const parts = await since_green.read_moved_parts(
146
+ review_stamps.test_related_stamp,
147
+ gate_plan.UNIT_LABEL,
148
+ )
149
+
150
+ if (parts === undefined) return undefined
151
+
152
+ const moved = moved_paths.union_of(parts)
153
+
154
+ if (moved.length === 0) return { changed: [], map, is_unmoved: true }
155
+
156
+ const change = await explicit_change(root, moved, map)
157
+
158
+ if (change.map === undefined) return undefined
159
+
160
+ process.stdout.write(`${since_green.describe(related_scope.COMMAND_LABEL, moved)}\n`)
161
+
162
+ const since_map = [...(change.since_map ?? []), ...(await synced_data(parts.synced))]
163
+
164
+ return { ...change, since_map, synced: parts.synced }
165
+ }
166
+
167
+ async function whole_change(root: string, map: ReadMap | undefined): Promise<ChangeReading> {
168
+ const since = await since_green_change(root, map)
169
+
170
+ if (since !== undefined) return since
171
+
172
+ return map === undefined ? { changed: await branch_change(), map } : await map_change(root, map)
173
+ }
174
+
175
+ async function read_change(
176
+ root: string,
177
+ command_arguments: ReadonlyArray<string>,
178
+ ): Promise<ChangeReading> {
179
+ const map = test_read_map.read_map(root)
180
+ const explicit = command_arguments
181
+ .filter((argument) => !changed_file_scope.is_flag(argument))
182
+ .map((file) => path.relative(root, path.resolve(file)))
183
+
184
+ return explicit.length > 0
185
+ ? await explicit_change(root, explicit, map)
186
+ : await whole_change(root, map)
187
+ }
188
+
189
+ // **The changed non-code files the map's tree held and that did not already differ from it** — the
190
+ // ones whose having no reader in the map means no test reads them. A file that was dirty when the
191
+ // map was recorded is left out, since the tree the tests read then was not the commit's. A git
192
+ // failure holds none, which runs the whole suite on any of them.
193
+ async function recorded_files(change: ChangeReading): Promise<ReadonlySet<string>> {
194
+ const { changed, map } = change
195
+
196
+ if (changed === undefined || map === undefined) return new Set()
197
+
198
+ const dirty = new Set(Object.keys(map.dirty))
199
+ const candidates = changed.filter((file) => !related_scope.is_relatable(file) && !dirty.has(file))
200
+
201
+ return new Set(
202
+ await read_or_undefined(async () => await changed_paths.read_held_at(map.commit, candidates)),
203
+ )
204
+ }
205
+
206
+ function text_of(file_path: string): string {
207
+ try {
208
+ return readFileSync(file_path, 'utf8')
209
+ } catch {
210
+ return ''
211
+ }
212
+ }
213
+
214
+ // Each file's text is read once, however many names it is checked for.
215
+ function names_any(text: string, names: ReadonlyArray<string>): boolean {
216
+ return names.some((name) => text.includes(name))
217
+ }
218
+
219
+ // **The code files of the change since the map that name a file this change moved** — read off their
220
+ // text, the one place a file-system read added since the map's tree shows (`is_code_input` in
221
+ // `test-related-scope.ts`, joshuafolkken/kit#4532). A file the tree no longer holds names nothing.
222
+ function naming_moved(root: string, change: ChangeReading): ReadonlySet<string> {
223
+ const { changed = [], since_map = [] } = change
224
+ const names = changed
225
+ .filter((file) => !since_map.includes(file))
226
+ .map((file) => path.basename(file))
227
+ const code = since_map.filter((file) => related_scope.is_relatable(file))
228
+
229
+ return new Set(code.filter((file) => names_any(text_of(path.join(root, file)), names)))
230
+ }
231
+
232
+ async function scope_of(root: string, change: ChangeReading): Promise<RelatedScope> {
233
+ const recorded = await recorded_files(change)
234
+ const naming = naming_moved(root, change)
235
+
236
+ return related_scope.resolve_scope({
37
237
  root,
38
- inputs: related_scope.scope_inputs(existsSync),
238
+ ...change,
239
+ recorded,
240
+ naming_moved: naming,
241
+ is_present: existsSync,
39
242
  })
243
+ }
40
244
 
41
- changed_file_scope.report_unusable_arguments(
42
- command_arguments,
43
- scope,
44
- related_scope.COMMAND_LABEL,
45
- )
245
+ // **Whether a set of changed files can reach any test**, answered by the decision this command
246
+ // narrows with, so the gate's reuse of a green unit step (`check-inputs.ts`) can never trust a change
247
+ // this command would have run tests for. Unknown reaches: no map, or one recorded on a tree git can
248
+ // no longer diff against. The change since the map joins the paths as it does for explicit
249
+ // arguments, so a test added or edited after the map was recorded still reaches.
250
+ async function reaches_tests(root: string, paths: ReadonlyArray<string>): Promise<boolean> {
251
+ if (paths.length === 0) return false
46
252
 
47
- const before = await scoped_green.read_before(command_arguments)
48
- const exit_code = await test_unit_guard.run_guarded_vitest(
253
+ const change = await explicit_change(root, paths, test_read_map.read_map(root))
254
+
255
+ if (change.map === undefined) return true
256
+
257
+ const scope = await scope_of(root, change)
258
+
259
+ return scope.mode !== 'none'
260
+ }
261
+
262
+ // A change known to reach no test succeeds without starting vitest, and says why.
263
+ async function run_scope(
264
+ scope: RelatedScope,
265
+ root: string,
266
+ command_arguments: ReadonlyArray<string>,
267
+ ): Promise<number> {
268
+ const description = related_scope.describe_scope(scope, root)
269
+
270
+ if (scope.mode === 'none') {
271
+ process.stdout.write(`${description}\n`)
272
+
273
+ return 0
274
+ }
275
+
276
+ return await test_unit_guard.run_guarded_vitest(
49
277
  process.cwd(),
50
278
  related_scope.vitest_arguments(scope, changed_file_scope.flags_of(command_arguments)),
51
279
  related_scope.COMMAND_NAME,
52
- related_scope.describe_scope(scope, root),
280
+ description,
53
281
  )
282
+ }
283
+
284
+ async function resolve_change(root: string, change: ChangeReading): Promise<RelatedScope> {
285
+ const { UNMOVED_REASON } = related_scope
286
+
287
+ if (change.is_unmoved === true) return { mode: 'none', files: [], reason: UNMOVED_REASON }
288
+
289
+ return await scope_of(root, change)
290
+ }
291
+
292
+ async function read_run_input(
293
+ root: string,
294
+ command_arguments: ReadonlyArray<string>,
295
+ ): Promise<RunInput> {
296
+ const change = await read_change(root, command_arguments)
297
+ const scope = await resolve_change(root, change)
298
+
299
+ const { changed, synced = [], since_map = [] } = change
300
+
301
+ return { scope, root, changed, synced, since_map }
302
+ }
303
+
304
+ // Every run is timed and counted into the lane ledger (joshuafolkken/kit#4465).
305
+ async function run_and_record(
306
+ input: RunInput,
307
+ command_arguments: ReadonlyArray<string>,
308
+ ): Promise<number> {
309
+ const started = performance.now()
310
+ const { exit_code, test_files } = await test_related_record.with_test_count(
311
+ async () => await run_scope(input.scope, input.root, command_arguments),
312
+ )
313
+
314
+ await test_related_record.record_run(input, {
315
+ elapsed_ms: performance.now() - started,
316
+ test_files,
317
+ })
318
+
319
+ return exit_code
320
+ }
321
+
322
+ async function run_related_tests(command_arguments: ReadonlyArray<string>): Promise<number> {
323
+ const root = await changed_file_scope.repository_root_or_cwd()
324
+ const input = await read_run_input(root, command_arguments)
325
+
326
+ // A non-code argument is resolved through the map rather than handed to vitest, so only the
327
+ // code arguments can be ones vitest was not given.
328
+ changed_file_scope.report_unusable_arguments(
329
+ command_arguments.filter((argument) => related_scope.is_relatable(argument)),
330
+ input.scope,
331
+ related_scope.COMMAND_LABEL,
332
+ )
333
+
334
+ const before = await scoped_green.read_before(command_arguments)
335
+ const exit_code = await run_and_record(input, command_arguments)
54
336
 
55
337
  await scoped_green.record_if_green(review_stamps.test_related_stamp, {
56
338
  before: conclusive_tree(before),
@@ -60,10 +342,6 @@ async function run_related_tests(command_arguments: ReadonlyArray<string>): Prom
60
342
  return exit_code
61
343
  }
62
344
 
63
- if (process.argv[1] === fileURLToPath(import.meta.url)) {
64
- process.exitCode = await run_related_tests(process.argv.slice(changed_file_scope.ARGV_START))
65
- }
66
-
67
- const test_related = { run_related_tests }
345
+ const test_related = { reaches_tests, run_related_tests }
68
346
 
69
347
  export { test_related }
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env tsx
2
+ import { fileURLToPath } from 'node:url'
3
+ import { test_unit_guard } from './test-unit-guard'
4
+
5
+ // The `josh test:unit` entry, kept apart from `test-unit-guard.ts` because the gate and the pre-push
6
+ // hook import that one: a bundle is one file, so a main guard there would fire for every command that
7
+ // carries it (joshuafolkken/kit#4186).
8
+ if (process.argv[1] === fileURLToPath(import.meta.url)) {
9
+ const ARGV_OFFSET = 2
10
+
11
+ process.exitCode = await test_unit_guard.run_guarded_unit(
12
+ process.cwd(),
13
+ process.argv.slice(ARGV_OFFSET),
14
+ )
15
+ }
@@ -1,19 +1,19 @@
1
- #!/usr/bin/env tsx
2
1
  import { existsSync, globSync } from 'node:fs'
3
2
  import { availableParallelism } from 'node:os'
4
3
  import path from 'node:path'
5
- import { fileURLToPath } from 'node:url'
6
4
  import { PROJECT_ENVIRONMENT_KEYS } from '#ports'
5
+ import { core_budget } from '#scripts/gate/core-budget'
7
6
  import { free_cores } from '#scripts/gate/free-cores'
8
7
  import { project_checks } from '#scripts/gate/project-checks'
8
+ import { changed_file_scope } from '#scripts/git/changed-file-scope'
9
9
  import { execa } from 'execa'
10
10
  import { project_test_script, type ProjectScriptState } from './project-test-script'
11
11
  import { SKIP_MARKER } from './skip-marker'
12
+ import { test_read_recording, type RecordingEnvironment } from './test-read-recording'
12
13
  import { unit_worker_share } from './unit-worker-share'
13
14
 
14
15
  const PNPM = 'pnpm'
15
16
  const FAIL_EXIT_CODE = 1
16
- const ARGV_START = 2
17
17
  const VITEST_PACKAGE = path.join('node_modules', 'vitest')
18
18
  const UNIT_GLOB = '**/*.{test,spec}.{ts,js}'
19
19
  const NODE_MODULES = 'node_modules'
@@ -178,32 +178,56 @@ function isolated_unit_environment(
178
178
  // both count "alone" and both run uncapped. Inside the marker the number is identical — this run's own
179
179
  // record is now on disk and `is_nested_run` therefore contributes nothing — and the window is gone.
180
180
  //
181
+ // **The share is bounded by the claim the run was admitted on** (`unit_worker_share.cap_to_claim`), so
182
+ // a share read after admission never opens more workers than the ledger holds for it
183
+ // (joshuafolkken/kit#4235).
184
+ //
181
185
  // **The machine is read only when no count was typed.** The reading waits out a sample window, and a
182
- // caller's `--maxWorkers` — the gate's cap among them, already bounded by the same reading — wins
183
- // whatever it says.
186
+ // caller's `--maxWorkers` wins whatever it says. The gate's cap is one: its admission narrows it to the
187
+ // free cores, and its unit step bounds it by the free memory once admitted (`gate-run-steps.ts`).
184
188
  async function vitest_share(vitest_arguments: ReadonlyArray<string>): Promise<number | undefined> {
185
189
  if (unit_worker_share.has_worker_flag(vitest_arguments)) return undefined
186
190
 
187
191
  const available_cores = availableParallelism()
192
+ // The cores and the memory free right now (joshuafolkken/kit#4528), from one reading.
188
193
  const free = await free_cores.read({ available_cores })
194
+ const share = unit_worker_share.current_share(
195
+ available_cores,
196
+ unit_worker_share.live_run_count(),
197
+ free,
198
+ )
189
199
 
190
- return unit_worker_share.current_share(available_cores, unit_worker_share.live_run_count(), free)
200
+ return unit_worker_share.cap_to_claim(share, core_budget.held_unit_claim())
191
201
  }
192
202
 
203
+ async function execute_vitest(
204
+ vitest_arguments: ReadonlyArray<string>,
205
+ recording: RecordingEnvironment,
206
+ ): Promise<number> {
207
+ const result = await execa(PNPM, ['exec', 'vitest', ...vitest_arguments], {
208
+ env: { ...isolated_unit_environment(), ...recording },
209
+ extendEnv: false,
210
+ stdio: 'inherit',
211
+ reject: false,
212
+ })
213
+
214
+ return result.exitCode ?? FAIL_EXIT_CODE
215
+ }
216
+
217
+ // A whole-suite run also records the test-read map `josh test:related` narrows by.
193
218
  async function run_vitest(vitest_arguments: ReadonlyArray<string>): Promise<number> {
194
219
  return await unit_worker_share.with_run_marker(async () => {
195
- const sized = unit_worker_share.worker_arguments(
196
- vitest_arguments,
197
- await vitest_share(vitest_arguments),
220
+ const sized = [
221
+ ...vitest_arguments,
222
+ ...unit_worker_share.worker_arguments(vitest_arguments, await vitest_share(vitest_arguments)),
223
+ ]
224
+ const root = await changed_file_scope.repository_root_or_cwd()
225
+
226
+ return await test_read_recording.with_read_recording(
227
+ root,
228
+ sized,
229
+ async (recording) => await execute_vitest(sized, recording),
198
230
  )
199
- const result = await execa(PNPM, ['exec', 'vitest', ...vitest_arguments, ...sized], {
200
- env: isolated_unit_environment(),
201
- extendEnv: false,
202
- stdio: 'inherit',
203
- reject: false,
204
- })
205
-
206
- return result.exitCode ?? FAIL_EXIT_CODE
207
231
  })
208
232
  }
209
233
 
@@ -262,13 +286,6 @@ async function run_guarded_unit(
262
286
  return await run_guarded_vitest(project_directory, ['run', ...extra_arguments])
263
287
  }
264
288
 
265
- if (process.argv[1] === fileURLToPath(import.meta.url)) {
266
- const extra_arguments = process.argv.slice(ARGV_START)
267
- const exit_code = await run_guarded_unit(process.cwd(), extra_arguments)
268
-
269
- process.exit(exit_code)
270
- }
271
-
272
289
  const test_unit_guard = {
273
290
  SKIP_MARKER,
274
291
  guard_action,
@@ -280,6 +297,7 @@ const test_unit_guard = {
280
297
  isolated_unit_environment,
281
298
  run_guarded_unit,
282
299
  run_guarded_vitest,
300
+ vitest_share,
283
301
  }
284
302
 
285
303
  export type { GuardAction }
@@ -0,0 +1,37 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import { writeFile } from 'node:fs/promises'
3
+
4
+ // How many test files a unit run ran, handed from the unit reporter to the caller that named a file to
5
+ // receive it — `josh test:related`, which records it beside the scope it handed vitest
6
+ // (joshuafolkken/kit#4465). Its own shipped module: the reporter is kit-only and the setup-file list
7
+ // names files only, so neither can own a protocol a shipped reader shares.
8
+
9
+ // Names the file the run's test-file count is written to.
10
+ const COUNT_FILE_ENVIRONMENT = 'JOSH_UNIT_COUNT_FILE'
11
+
12
+ // Best-effort like the ledger: a run is never failed by the file it reports into.
13
+ async function write_count(count: number, target: string | undefined): Promise<void> {
14
+ if (target === undefined || target === '') return
15
+
16
+ try {
17
+ await writeFile(target, String(count))
18
+ } catch {
19
+ // The caller reads a missing count as unknown.
20
+ }
21
+ }
22
+
23
+ // A missing, empty or non-integer file is an unknown count, never zero.
24
+ function read_count(file: string): number | undefined {
25
+ try {
26
+ const text = readFileSync(file, 'utf8').trim()
27
+ const count = Number(text)
28
+
29
+ return text !== '' && Number.isSafeInteger(count) ? count : undefined
30
+ } catch {
31
+ return undefined
32
+ }
33
+ }
34
+
35
+ const unit_count_file = { COUNT_FILE_ENVIRONMENT, read_count, write_count }
36
+
37
+ export { unit_count_file }
@@ -0,0 +1,162 @@
1
+ import { readdirSync } from 'node:fs'
2
+ import path from 'node:path'
3
+ import { PLATFORM_TEMP_ROOT } from '#scripts/josh/platform-temporary'
4
+ import { process_identity } from '#scripts/josh/process-identity'
5
+ import { process_owner_schema, type ProcessOwner } from '#scripts/josh/process-owner'
6
+ import { stamp_file } from '#scripts/josh/stamp-file'
7
+ import { json_value } from '#scripts/lib/json-value'
8
+
9
+ // The run markers that count the unit runs in flight, and the division of the machine by that count —
10
+ // the part of the worker share `vitest.config.ts` reads (`vitest-config-workers.ts`).
11
+ //
12
+ // **Kept apart from `unit-worker-share.ts` because the config imports it** (joshuafolkken/kit#4572).
13
+ // Every module the vitest config imports is a whole-suite file (`whole-suite-files.ts`), and the
14
+ // capacity and claim bounds of the share change often; held here, only this stable part is one.
15
+
16
+ // A record that means something only while it exists, in the shape `stamp-file.ts` already keeps for
17
+ // the in-flight gate marker. Keyed by pid rather than by checkout: `josh gate`'s unit step and a
18
+ // `josh test:related` can be in flight in one checkout at once, and both of them are load.
19
+ const RUN_PREFIX = 'josh-unit-running-'
20
+ // Never below one: a share of zero would run no test at all and report the suite green.
21
+ const MIN_WORKERS = 1
22
+ // One run in flight is this run alone, which is the case that changes nothing.
23
+ const SOLO_RUNS = 1
24
+
25
+ // A marker is the writing process's identity and nothing else; a pid-only marker has an answer of its
26
+ // own below (`is_running`) rather than being rejected here.
27
+ type RunMarker = ProcessOwner
28
+
29
+ function marker_path(pid: number = process.pid): string {
30
+ return stamp_file.stamp_path(RUN_PREFIX, String(pid))
31
+ }
32
+
33
+ // **A marker is evidence, and the process behind it is the test.** A run killed outright leaves its
34
+ // file behind, and a count that trusted the file alone would hold every later run down to one worker
35
+ // for good — the failure mode `run-hold.ts` answers with an expiry, which cannot be sized here because
36
+ // a unit suite under six-way load already takes minutes. The process that writes this marker is the
37
+ // long-lived one, so unlike a `run:hold` record its identity is a liveness test rather than a note for
38
+ // the reader.
39
+ //
40
+ // **The pid alone was not that identity**. The section below already named
41
+ // what goes wrong — a reissued pid turns a leaked marker into a permanent phantom — and answered it by
42
+ // sweeping, which only ever collected the markers whose pid had *not* yet been reissued. Since the
43
+ // record now carries the writing process's start time beside its pid, a reissued pid is recognized as
44
+ // a different process and swept like any other dead one. A pid that is not positive is caught by the
45
+ // same check, inside `process_identity`: `process.kill(0, …)` addresses the caller's own process group
46
+ // rather than a process, so a truncated or hand-edited marker would otherwise answer "alive" forever.
47
+ //
48
+ // **"Cannot tell" counts as live here, which is the opposite of what the in-flight gate marker's
49
+ // readers do with it, and deliberately so.** A marker with no recorded start time — written before the
50
+ // field existed, or on a platform where it cannot be read — resolves toward *more* sharing: being
51
+ // wrong that way costs this run a narrower share of the machine, while being wrong the other way puts
52
+ // six unit suites on eleven cores, an oversubscription measured at a load
53
+ // average of 209.
54
+ function is_running(marker: RunMarker): boolean {
55
+ return process_identity.is_same_process(marker.pid, marker.process_start) !== false
56
+ }
57
+
58
+ function read_marker(source: string): RunMarker | undefined {
59
+ const raw = stamp_file.read_stamp_text(source)
60
+
61
+ if (raw === undefined) return undefined
62
+
63
+ const parsed = process_owner_schema.safeParse(json_value.parse_or_undefined(raw))
64
+
65
+ return parsed.success ? parsed.data : undefined
66
+ }
67
+
68
+ // An unreadable temp directory answers "no other run", which is the direction that leaves behavior
69
+ // as it was rather than throttling a run on a guess. Unlike the network guard, being wrong here costs
70
+ // wall time and never a false result.
71
+ function marker_files(directory: string = PLATFORM_TEMP_ROOT): Array<string> {
72
+ try {
73
+ return readdirSync(directory).filter((name) => name.startsWith(RUN_PREFIX))
74
+ } catch {
75
+ return []
76
+ }
77
+ }
78
+
79
+ // **A marker whose process is gone is removed, not merely skipped.** Skipping it is correct only until
80
+ // the operating system reissues that pid to something else, which on a machine left running for days
81
+ // it will — and from then on the phantom is counted as a live run for good, with every solo run held
82
+ // at one worker and `josh gate` announcing lanes that do not exist. `finally` in `with_run_marker`
83
+ // cannot prevent the leak, because the interrupt that produces it (Ctrl-C reaching the whole foreground
84
+ // group) does not unwind. Sweeping on read is what bounds it: the first later run collects it.
85
+ function sweep_marker(source: string): void {
86
+ try {
87
+ stamp_file.remove_stamp(source)
88
+ } catch {
89
+ /* not ours to remove; counting it out is the whole requirement */
90
+ }
91
+ }
92
+
93
+ // **Only a marker that parsed to a dead pid is swept, and the unlink still cannot throw.** A marker
94
+ // this account may not read — another user's file on a sticky `/tmp` — is `undefined` here, and
95
+ // deleting on that answer would raise `EPERM` from a path with no `catch` between it and
96
+ // `announce_gate_plan`: an unreadable file belonging to somebody else would abort the gate outright,
97
+ // which is worse than the leak this sweep exists for. Unreadable therefore counts as not-live and is
98
+ // left alone, exactly as it was before the sweep existed.
99
+ function is_marker_live(source: string): boolean {
100
+ const marker = read_marker(source)
101
+
102
+ if (marker === undefined) return false
103
+ if (is_running(marker)) return true
104
+
105
+ sweep_marker(source)
106
+
107
+ return false
108
+ }
109
+
110
+ // Every marker in the temp directory whose process is still alive. This run's own is deliberately not
111
+ // among them: both callers count *before* writing theirs, so the `+ 1` at the call site adds it.
112
+ function live_run_count(directory: string = PLATFORM_TEMP_ROOT): number {
113
+ return marker_files(directory).filter((name) => is_marker_live(path.join(directory, name))).length
114
+ }
115
+
116
+ // **The gate claims its place before its unit step exists, and the child must not claim a second
117
+ // one.** `josh gate` counts the runs in flight and then spawns `josh test:unit`, so without this the
118
+ // marker appears a second or so after the count that needed it — and two lanes launched together, the
119
+ // shape `epicrun` produces, both read "nothing else is running" and both take the whole machine. The
120
+ // gate therefore marks itself around the whole run and passes this down through the environment; the
121
+ // guard inside the child sees it and marks nothing, because the two processes are one run.
122
+ const NESTED_KEY = 'JOSH_UNIT_RUN_MARKED'
123
+ const NESTED_VALUE = '1'
124
+
125
+ function is_nested_run(): boolean {
126
+ return process.env[NESTED_KEY] === NESTED_VALUE
127
+ }
128
+
129
+ // **`undefined` at one run means "leave the choice where it was".** The gate then applies its own
130
+ // core reservation and the hook passes no flag at all, which is what both did before this existed.
131
+ function resolve_unit_workers(available_cores: number, runs: number): number | undefined {
132
+ if (runs <= SOLO_RUNS) return undefined
133
+
134
+ return Math.max(MIN_WORKERS, Math.floor(available_cores / runs))
135
+ }
136
+
137
+ // **The write failing is not a reason to fail the run.** A marker that could not be written costs the
138
+ // next run a wider share than it should have — the behavior that was there before — while a thrown
139
+ // error here would fail a unit suite over bookkeeping.
140
+ function mark_run_started(target: string): void {
141
+ try {
142
+ stamp_file.write_stamp(target, process_identity.own_fields())
143
+ } catch {
144
+ /* a missing marker costs a wide share, never a wrong result */
145
+ }
146
+ }
147
+
148
+ const unit_run_marker = {
149
+ MIN_WORKERS,
150
+ NESTED_KEY,
151
+ NESTED_VALUE,
152
+ RUN_PREFIX,
153
+ SOLO_RUNS,
154
+ is_nested_run,
155
+ live_run_count,
156
+ mark_run_started,
157
+ marker_path,
158
+ read_marker,
159
+ resolve_unit_workers,
160
+ }
161
+
162
+ export { unit_run_marker }