@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
@@ -0,0 +1,145 @@
1
+ import { test_declared_logic } from './test-declared-logic'
2
+ import { related_scope } from './test-related-scope'
3
+
4
+ // The pure half of `josh test:pinned` (joshuafolkken/kit#4516): read a `git diff -U0` into hunks, put
5
+ // one hunk's old lines back into the changed file, and split the hunks at the run's cap. The run itself
6
+ // is `test-pinned.ts`.
7
+
8
+ const DEFAULT_MAX_HUNKS = 20
9
+ const HEADER = /^@@ -\d+(?:,\d+)? \+(?<start>\d+)(?:,(?<count>\d+))? @@/u
10
+ const FILE_HEADER = '+++ b/'
11
+ const SECTION_HEADER = 'diff --git '
12
+ const OLD_LINE = '-'
13
+ const OLD_FILE_HEADER = '--- '
14
+ const LINE_BREAK = '\n'
15
+ const GREEN_REASON = 'reverting it left every related test green'
16
+ const NO_TEST_REASON = 'no related test ran with it reverted'
17
+
18
+ interface Hunk {
19
+ file: string
20
+ // The first changed line of the working file; for a pure deletion, the line the removed ones sat after.
21
+ new_start: number
22
+ new_count: number
23
+ old_lines: Array<string>
24
+ }
25
+
26
+ interface HunkSplit {
27
+ checked: ReadonlyArray<Hunk>
28
+ unchecked: ReadonlyArray<Hunk>
29
+ }
30
+
31
+ // A reverted hunk nothing went red on: `is_green` when its related tests ran and passed, otherwise none
32
+ // ran at all — no related test, or a vitest that stopped before running one.
33
+ interface UnpinnedHunk extends Hunk {
34
+ is_green: boolean
35
+ }
36
+
37
+ interface PinnedReport {
38
+ unpinned: ReadonlyArray<UnpinnedHunk>
39
+ unchecked: ReadonlyArray<Hunk>
40
+ max_hunks: number
41
+ }
42
+
43
+ interface DiffWalk {
44
+ file: string
45
+ hunks: Array<Hunk>
46
+ }
47
+
48
+ // A test file is never reverted, and only a file vitest can walk an import graph back from has related
49
+ // tests to run.
50
+ function is_target(file: string): boolean {
51
+ return !test_declared_logic.is_test_file(file) && related_scope.is_relatable(file)
52
+ }
53
+
54
+ // An omitted count is one line (`@@ -3 +3 @@`).
55
+ function count_of(group: string | undefined): number {
56
+ return group === undefined ? 1 : Number(group)
57
+ }
58
+
59
+ function hunk_from(file: string, line: string): Hunk | undefined {
60
+ const groups = HEADER.exec(line)?.groups
61
+ if (groups === undefined) return undefined
62
+
63
+ return {
64
+ file,
65
+ new_start: Number(groups['start']),
66
+ new_count: count_of(groups['count']),
67
+ old_lines: [],
68
+ }
69
+ }
70
+
71
+ function is_old_line(line: string): boolean {
72
+ return line.startsWith(OLD_LINE) && !line.startsWith(OLD_FILE_HEADER)
73
+ }
74
+
75
+ // Each file section starts unnamed, so a `+++` line this does not read (a quoted path with a space)
76
+ // leaves its hunks on no file rather than on the previous one.
77
+ function file_after(file: string, line: string): string {
78
+ if (line.startsWith(FILE_HEADER)) return line.slice(FILE_HEADER.length)
79
+
80
+ return line.startsWith(SECTION_HEADER) ? '' : file
81
+ }
82
+
83
+ function step(walk: DiffWalk, line: string): void {
84
+ walk.file = file_after(walk.file, line)
85
+ const hunk = hunk_from(walk.file, line)
86
+
87
+ if (hunk !== undefined) walk.hunks.push(hunk)
88
+ else if (is_old_line(line)) walk.hunks.at(-1)?.old_lines.push(line.slice(OLD_LINE.length))
89
+ }
90
+
91
+ // One `-U0` diff into its hunks, in diff order. The `+` lines are not kept: the working file already
92
+ // holds them, at `new_start` for `new_count` lines.
93
+ function parse_hunks(diff: string): Array<Hunk> {
94
+ const walk: DiffWalk = { file: '', hunks: [] }
95
+
96
+ for (const line of diff.split(LINE_BREAK)) step(walk, line)
97
+
98
+ return walk.hunks.filter((hunk) => is_target(hunk.file))
99
+ }
100
+
101
+ // A pure deletion's `new_start` names the line before the gap, so the old lines go in after it.
102
+ function start_index(hunk: Hunk): number {
103
+ return hunk.new_count === 0 ? hunk.new_start : hunk.new_start - 1
104
+ }
105
+
106
+ // The working file's content with this one hunk put back to the base's lines.
107
+ function revert(content: string, hunk: Hunk): string {
108
+ const lines = content.split(LINE_BREAK)
109
+
110
+ lines.splice(start_index(hunk), hunk.new_count, ...hunk.old_lines)
111
+
112
+ return lines.join(LINE_BREAK)
113
+ }
114
+
115
+ function split(hunks: ReadonlyArray<Hunk>, max_hunks: number): HunkSplit {
116
+ return { checked: hunks.slice(0, max_hunks), unchecked: hunks.slice(max_hunks) }
117
+ }
118
+
119
+ function location(hunk: Hunk): string {
120
+ return `${hunk.file}:${String(Math.max(hunk.new_start, 1))}`
121
+ }
122
+
123
+ function format(report: PinnedReport): string {
124
+ const unpinned = report.unpinned.map(
125
+ (hunk) => `unpinned ${location(hunk)} — ${hunk.is_green ? GREEN_REASON : NO_TEST_REASON}`,
126
+ )
127
+ const unchecked = report.unchecked.map(
128
+ (hunk) => `unchecked ${location(hunk)} — over the ${String(report.max_hunks)}-hunk cap`,
129
+ )
130
+
131
+ return [...unpinned, ...unchecked].join(LINE_BREAK)
132
+ }
133
+
134
+ const test_pinned_logic = {
135
+ DEFAULT_MAX_HUNKS,
136
+ format,
137
+ is_target,
138
+ location,
139
+ parse_hunks,
140
+ revert,
141
+ split,
142
+ }
143
+
144
+ export type { Hunk, PinnedReport, UnpinnedHunk }
145
+ export { test_pinned_logic }
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env tsx
2
+ import { fileURLToPath } from 'node:url'
3
+ import { parseArgs } from 'node:util'
4
+ import { test_pinned } from './test-pinned'
5
+ import { test_pinned_logic, type PinnedReport } from './test-pinned-logic'
6
+
7
+ // The `josh test:pinned` entry: read `--max`, run, print one line per unpinned or unchecked hunk, and
8
+ // exit non-zero when any checked hunk is unpinned. An unchecked hunk alone does not fail the run — it
9
+ // was not asked about.
10
+
11
+ const CLEAN_EXIT = 0
12
+ const FAILED_EXIT = 1
13
+ const ARGV_OFFSET = 2
14
+ const USAGE = [
15
+ 'Usage: josh test:pinned [--max <n>] [--help]',
16
+ ' revert each changed hunk of a non-test code file and run its related tests;',
17
+ ' prints `unpinned <file>:<line>` for a hunk no test went red on, and',
18
+ ` \`unchecked <file>:<line>\` past the --max cap (default ${String(test_pinned_logic.DEFAULT_MAX_HUNKS)})`,
19
+ ].join('\n')
20
+
21
+ const PARSE_ARGS_OPTIONS = {
22
+ help: { type: 'boolean', short: 'h', default: false },
23
+ max: { type: 'string' },
24
+ } as const
25
+
26
+ const HELP_FLAGS: ReadonlySet<string> = new Set(['--help', '-h'])
27
+
28
+ // A `--max` that is not a whole number above zero is a refusal, not the default.
29
+ function valid_max(raw: string | undefined): number | undefined {
30
+ const max = Number(raw ?? test_pinned_logic.DEFAULT_MAX_HUNKS)
31
+
32
+ return Number.isSafeInteger(max) && max > 0 ? max : undefined
33
+ }
34
+
35
+ // `undefined` prints the usage: a help request, an unknown flag, or a missing or invalid `--max`.
36
+ function max_hunks_of(argv: ReadonlyArray<string>): number | undefined {
37
+ try {
38
+ const { values } = parseArgs({ args: [...argv], options: PARSE_ARGS_OPTIONS, strict: true })
39
+
40
+ return values.help ? undefined : valid_max(values.max)
41
+ } catch {
42
+ return undefined
43
+ }
44
+ }
45
+
46
+ // Clean for an explicit help request; a refusal for anything the parse did not understand.
47
+ function print_usage(argv: ReadonlyArray<string>): number {
48
+ process.stderr.write(`${USAGE}\n`)
49
+
50
+ return argv.some((argument) => HELP_FLAGS.has(argument)) ? CLEAN_EXIT : FAILED_EXIT
51
+ }
52
+
53
+ function output(report: PinnedReport): string {
54
+ const unpinned = String(report.unpinned.length)
55
+ const unchecked = String(report.unchecked.length)
56
+ const lines = [`unpinned ${unpinned} · unchecked ${unchecked}`, test_pinned_logic.format(report)]
57
+
58
+ return `${lines.filter((line) => line !== '').join('\n')}\n`
59
+ }
60
+
61
+ async function main(argv: ReadonlyArray<string>): Promise<number> {
62
+ const max_hunks = max_hunks_of(argv)
63
+ if (max_hunks === undefined) return print_usage(argv)
64
+
65
+ const report = await test_pinned.run(max_hunks)
66
+
67
+ process.stdout.write(output(report))
68
+
69
+ return report.unpinned.length === 0 ? CLEAN_EXIT : FAILED_EXIT
70
+ }
71
+
72
+ if (process.argv[1] === fileURLToPath(import.meta.url)) {
73
+ process.exitCode = await main(process.argv.slice(ARGV_OFFSET))
74
+ }
75
+
76
+ const test_pinned_main = { main }
77
+
78
+ export { test_pinned_main }
@@ -0,0 +1,100 @@
1
+ import { existsSync } from 'node:fs'
2
+ import { readFile, writeFile } from 'node:fs/promises'
3
+ import path from 'node:path'
4
+ import { base_tree, type BaseTree } from '#scripts/git/base-tree'
5
+ import { change_base } from '#scripts/git/change-base'
6
+ import { changed_paths } from '#scripts/git/changed-paths'
7
+ import { git_spawn } from '#scripts/git/git-spawn'
8
+ import {
9
+ test_pinned_logic,
10
+ type Hunk,
11
+ type PinnedReport,
12
+ type UnpinnedHunk,
13
+ } from './test-pinned-logic'
14
+ import { test_red } from './test-red'
15
+ import type { RedVerdict } from './test-red-logic'
16
+
17
+ // `josh test:pinned` (joshuafolkken/kit#4516) — put each changed hunk of a non-test code file back to
18
+ // the merge-base's lines, one at a time, run that file's related tests, and list the hunks no test went
19
+ // red on: the "reverting it stays green" finding a review used to stop a lane on.
20
+ //
21
+ // **The reverts happen in a detached worktree at HEAD, never the caller's checkout** (`base-tree.ts`).
22
+ // The changed files are copied in from the working tree first, so what is reverted is the change as it
23
+ // stands, committed or not, and each hunk's file is restored before the next one runs.
24
+
25
+ const TREE_PREFIX = 'josh-test-pinned-'
26
+ const HEAD = 'HEAD'
27
+
28
+ // `--diff-filter=M`: an added file's one hunk is the whole file, and reverting it is a missing module
29
+ // every importer fails on, which says nothing about the tests. The prefixes are pinned: a user's
30
+ // `diff.mnemonicPrefix` writes `+++ w/<file>`, which would read as no hunk at all.
31
+ async function read_hunks(base: string, files: ReadonlyArray<string>): Promise<Array<Hunk>> {
32
+ if (files.length === 0) return []
33
+ const diff_args = ['diff', '-U0', '--no-color', '--no-ext-diff', '--diff-filter=M']
34
+ const prefix_args = ['--src-prefix=a/', '--dst-prefix=b/', base, '--']
35
+
36
+ return test_pinned_logic.parse_hunks(
37
+ await git_spawn.read([...diff_args, ...prefix_args, ...files]),
38
+ )
39
+ }
40
+
41
+ // The verdict with this one hunk reverted. The file is put back before the next hunk runs, or that
42
+ // hunk's tests would also see this revert.
43
+ async function verdict_of(tree: BaseTree, hunk: Hunk): Promise<RedVerdict> {
44
+ const target = path.join(tree.tree, hunk.file)
45
+ const content = await readFile(target, 'utf8')
46
+
47
+ await writeFile(target, test_pinned_logic.revert(content, hunk))
48
+
49
+ try {
50
+ return await test_red.verdict_in(tree, ['related', hunk.file, '--run'])
51
+ } finally {
52
+ await writeFile(target, content)
53
+ }
54
+ }
55
+
56
+ // One hunk at a time: two reverts in flight would share the tree, and each run is already a whole vitest.
57
+ // Green and no-test both leave a hunk unpinned: either way nothing went red when it was reverted.
58
+ async function unpinned_in(
59
+ tree: BaseTree,
60
+ hunks: ReadonlyArray<Hunk>,
61
+ ): Promise<Array<UnpinnedHunk>> {
62
+ const unpinned: Array<UnpinnedHunk> = []
63
+
64
+ for (const hunk of hunks) {
65
+ // eslint-disable-next-line no-await-in-loop -- the hunks share one tree, so each revert waits for the last restore
66
+ const verdict = await verdict_of(tree, hunk)
67
+ if (verdict !== 'red') unpinned.push({ ...hunk, is_green: verdict === 'green' })
68
+ }
69
+
70
+ return unpinned
71
+ }
72
+
73
+ async function unpinned_on(
74
+ paths: ReadonlyArray<string>,
75
+ hunks: ReadonlyArray<Hunk>,
76
+ ): Promise<Array<UnpinnedHunk>> {
77
+ if (hunks.length === 0) return []
78
+
79
+ return await base_tree.with_tree(TREE_PREFIX, HEAD, async (tree) => {
80
+ await base_tree.copy_in(tree.tree, paths)
81
+
82
+ return await unpinned_in(tree, hunks)
83
+ })
84
+ }
85
+
86
+ // No merge-base (not a repository, no default branch) checks nothing, as `josh test:red` does.
87
+ async function run(max_hunks: number): Promise<PinnedReport> {
88
+ const base = await change_base.resolved()
89
+ const changed = await changed_paths.read_changed_paths(false)
90
+ const paths = changed.filter((file) => existsSync(file))
91
+ const targets = paths.filter((file) => test_pinned_logic.is_target(file))
92
+ const hunks = base === undefined ? [] : await read_hunks(base, targets)
93
+ const { checked, unchecked } = test_pinned_logic.split(hunks, max_hunks)
94
+
95
+ return { unpinned: await unpinned_on(paths, checked), unchecked, max_hunks }
96
+ }
97
+
98
+ const test_pinned = { run }
99
+
100
+ export { test_pinned }
@@ -0,0 +1,264 @@
1
+ import { readdirSync, readFileSync, rmSync, statSync } from 'node:fs'
2
+ import path from 'node:path'
3
+ import { git_common_directory } from '#scripts/git/git-common-directory'
4
+ import { atomic_write } from '#scripts/lib/atomic-write'
5
+ import { json_value } from '#scripts/lib/json-value'
6
+ import { test_read_trace, type ReadRecords } from './test-read-trace'
7
+
8
+ // The test-read map: for every repository path a full unit run read, the modules that read it.
9
+ // `josh test:related` resolves a changed non-code file through it to the code files `vitest related`
10
+ // can walk, so a changed document runs the tests that read it rather than the whole suite.
11
+ //
12
+ // **The map is valid against the tree it was recorded on, and only that tree.** It records the
13
+ // commit and the files that differed from it, so the change a narrowing reads is the change since
14
+ // then. A tree whose own code changed what it reads has changed that code, and `vitest related`
15
+ // runs the tests importing it. **It lives in the git common directory**, which every lane worktree of
16
+ // one clone shares along with the commits it names, so one lane's full run narrows the next lane's.
17
+ // **One file per version** (joshuafolkken/kit#4423): a lane on an older kit writing its map leaves a
18
+ // newer lane's map in place, so a version bump no longer sends either to the whole suite.
19
+
20
+ interface ReadMap {
21
+ version: number
22
+ commit: string
23
+ // The files that differed from `commit` when the map was recorded, each with the digest of its
24
+ // content then (`input_fingerprint.of_files`), so one whose content has not moved since does not count as changed
25
+ // (joshuafolkken/kit#4425).
26
+ dirty: Record<string, string>
27
+ // The directories `commit` holds, so a directory new since then is told apart from one no test
28
+ // read — the map's own keys cannot say which, since an unread directory has none.
29
+ directories: Array<string>
30
+ readers: ReadRecords
31
+ }
32
+
33
+ // Bumped whenever the shape, what a reader means or how `dirty` is digested changes, so a map an older
34
+ // kit wrote reads as no map at all and the next full run writes it afresh. 6: `dirty` is
35
+ // `input-fingerprint.ts`'s digest of every changed file (joshuafolkken/kit#4497).
36
+ const MAP_VERSION = 6
37
+
38
+ const MAP_DIRECTORY = 'josh'
39
+ const MAP_FILE_STEM = 'test-read-map'
40
+ const RECORD_EXTENSION = '.json'
41
+
42
+ // A map file of another version no lane has written for this long belongs to no kit still running,
43
+ // and is removed by the next write: one week.
44
+ const STALE_AFTER_MS = 604_800_000
45
+
46
+ type ReadPair = [string, string]
47
+
48
+ function record_pairs(record: ReadRecords): Array<ReadPair> {
49
+ return Object.entries(record).flatMap(([read_path, readers]) =>
50
+ readers.map((reader): ReadPair => [read_path, reader]),
51
+ )
52
+ }
53
+
54
+ function merge_records(records: ReadonlyArray<ReadRecords>): ReadRecords {
55
+ const merged = new Map<string, Set<string>>()
56
+ const pairs = records.flatMap((record) => record_pairs(record))
57
+
58
+ for (const [read_path, reader] of pairs) {
59
+ test_read_trace.add_reader(merged, read_path, reader)
60
+ }
61
+
62
+ return test_read_trace.to_records(merged)
63
+ }
64
+
65
+ function is_object(value: unknown): value is object {
66
+ return typeof value === 'object' && value !== null
67
+ }
68
+
69
+ function is_string_array(value: unknown): value is Array<string> {
70
+ return Array.isArray(value) && value.every((entry) => typeof entry === 'string')
71
+ }
72
+
73
+ function is_read_records(value: unknown): value is ReadRecords {
74
+ return is_object(value) && Object.values(value).every(is_string_array)
75
+ }
76
+
77
+ function is_digest_record(value: unknown): value is Record<string, string> {
78
+ if (!is_object(value) || Array.isArray(value)) return false
79
+
80
+ return Object.values(value).every((digest) => typeof digest === 'string')
81
+ }
82
+
83
+ const FIELD_CHECKS: ReadonlyArray<[keyof ReadMap, (field: unknown) => boolean]> = [
84
+ ['version', (field) => field === MAP_VERSION],
85
+ ['commit', (field) => typeof field === 'string'],
86
+ ['dirty', is_digest_record],
87
+ ['directories', is_string_array],
88
+ ['readers', is_read_records],
89
+ ]
90
+
91
+ function is_read_map(value: unknown): value is ReadMap {
92
+ if (!is_object(value)) return false
93
+
94
+ return FIELD_CHECKS.every(([field, is_valid]) => is_valid(Reflect.get(value, field)))
95
+ }
96
+
97
+ // **The files whose content differs from the tree the map was recorded on** (joshuafolkken/kit#4425).
98
+ // `since` is every path that differs from `map.commit` now, and `current` the digest of every path
99
+ // that was dirty then. A path dirty then is changed only when its digest moved: counted by name, a
100
+ // lane's own change the map was recorded over read as changed on every later run, so a gate reused
101
+ // no green unit step whenever the lane held any code.
102
+ function changed_since_tree(
103
+ map: ReadMap,
104
+ since: ReadonlyArray<string>,
105
+ current: Readonly<Record<string, string>>,
106
+ ): Array<string> {
107
+ const fresh = since.filter((file) => !Object.hasOwn(map.dirty, file))
108
+ const moved = Object.entries(map.dirty)
109
+ .filter(([file, digest]) => current[file] !== digest)
110
+ .map(([file]) => file)
111
+
112
+ return [...new Set([...fresh, ...moved])]
113
+ }
114
+
115
+ function parse_map(text: string): ReadMap | undefined {
116
+ const value = json_value.parse_or_undefined(text)
117
+
118
+ return is_read_map(value) ? value : undefined
119
+ }
120
+
121
+ function parse_records(text: string): ReadRecords {
122
+ const value = json_value.parse_or_undefined(text)
123
+
124
+ return is_read_records(value) ? value : {}
125
+ }
126
+
127
+ // Innermost first, ending at the root `.`.
128
+ function directories_above(relative: string): Array<string> {
129
+ const parent = path.dirname(relative)
130
+
131
+ if (parent === relative) return []
132
+
133
+ return [parent, ...directories_above(parent)]
134
+ }
135
+
136
+ // The directories on the file's path the recorded commit did not hold, innermost first. The root
137
+ // always existed.
138
+ function created_directories(
139
+ directories: ReadonlyArray<string>,
140
+ recorded: ReadonlySet<string>,
141
+ ): Array<string> {
142
+ return directories.filter(
143
+ (directory) => directory !== test_read_trace.ROOT_ENTRY && !recorded.has(directory),
144
+ )
145
+ }
146
+
147
+ // A changed file is read by whoever read it, listed its own directory or walked any directory above
148
+ // it. A directory new since the recording is also a new entry in the listing above it and a probe of
149
+ // it that now answers differently; a directory that already existed reads the same to both, whatever
150
+ // changed deeper down.
151
+ function lookup_keys(relative: string, recorded: ReadonlySet<string>): Array<string> {
152
+ const directories = directories_above(relative)
153
+ const created = created_directories(directories, recorded)
154
+ const listed = [
155
+ directories[0] ?? test_read_trace.ROOT_ENTRY,
156
+ ...created.map((directory) => path.dirname(directory)),
157
+ ]
158
+
159
+ return [
160
+ relative,
161
+ ...created,
162
+ ...listed.map((directory) => test_read_trace.read_key(directory, 'listing')),
163
+ ...directories.map((directory) => test_read_trace.read_key(directory, 'walk')),
164
+ ]
165
+ }
166
+
167
+ function readers_of(map: ReadMap, relative: string): Array<string> {
168
+ const keys = lookup_keys(relative, new Set(map.directories))
169
+
170
+ return [...new Set(keys.flatMap((key) => map.readers[key] ?? []))]
171
+ }
172
+
173
+ // **A directory the recorded tree held, inside which no recorded test listed, walked or read any
174
+ // entry** (joshuafolkken/kit#4303). A file added to it since is one no test reads, as surely as one
175
+ // the tree already held there: a test that builds a path into it reads some file there, and one that
176
+ // enumerates it lists it, both of which leave a key whose directory is this one.
177
+ function in_unread_directory(map: ReadMap, relative: string): boolean {
178
+ const directory = path.dirname(relative)
179
+
180
+ if (!map.directories.includes(directory)) return false
181
+
182
+ return Object.keys(map.readers).every((key) => path.dirname(key) !== directory)
183
+ }
184
+
185
+ function map_path(root: string, version: number = MAP_VERSION): string | undefined {
186
+ const common = git_common_directory.repository(root)
187
+ const name = `${MAP_FILE_STEM}.v${String(version)}${RECORD_EXTENSION}`
188
+
189
+ return common === undefined ? undefined : path.join(common, MAP_DIRECTORY, name)
190
+ }
191
+
192
+ // Every version's map, the unversioned one kits before joshuafolkken/kit#4423 wrote included; a
193
+ // staging file ends in `.tmp`, not the extension.
194
+ function is_map_file(name: string): boolean {
195
+ return name.startsWith(MAP_FILE_STEM) && name.endsWith(RECORD_EXTENSION)
196
+ }
197
+
198
+ // A file another lane's write pruned meanwhile has no stat, and is not this write's to remove.
199
+ function is_stale(file_path: string, now: number): boolean {
200
+ const modified = statSync(file_path, { throwIfNoEntry: false })?.mtimeMs ?? now
201
+
202
+ return now - modified > STALE_AFTER_MS
203
+ }
204
+
205
+ // The map just written is never stale, so it survives its own prune.
206
+ function prune_stale_maps(directory: string): void {
207
+ const now = Date.now()
208
+ const maps = readdirSync(directory)
209
+ .filter((name) => is_map_file(name))
210
+ .map((name) => path.join(directory, name))
211
+
212
+ for (const file_path of maps) {
213
+ if (is_stale(file_path, now)) rmSync(file_path, { force: true })
214
+ }
215
+ }
216
+
217
+ function read_text(file_path: string): string | undefined {
218
+ try {
219
+ return readFileSync(file_path, 'utf8')
220
+ } catch {
221
+ return undefined
222
+ }
223
+ }
224
+
225
+ function read_map(root: string): ReadMap | undefined {
226
+ const file_path = map_path(root)
227
+ const text = file_path === undefined ? undefined : read_text(file_path)
228
+
229
+ return text === undefined ? undefined : parse_map(text)
230
+ }
231
+
232
+ // Written beside the target and renamed over it, so a lane reading the map while another lane
233
+ // replaces it reads one whole map or the other. It lands in its own version's file.
234
+ function write_map(root: string, map: ReadMap): void {
235
+ const file_path = map_path(root, map.version)
236
+
237
+ if (file_path === undefined) return
238
+
239
+ atomic_write.replace_file(file_path, JSON.stringify(map))
240
+ prune_stale_maps(path.dirname(file_path))
241
+ }
242
+
243
+ // Every worker writes its own files into the run's directory; this reads them all back.
244
+ function collect_records(directory: string): Array<ReadRecords> {
245
+ return readdirSync(directory)
246
+ .filter((name) => name.endsWith(RECORD_EXTENSION))
247
+ .map((name) => parse_records(read_text(path.join(directory, name)) ?? ''))
248
+ }
249
+
250
+ const test_read_map = {
251
+ MAP_VERSION,
252
+ changed_since_tree,
253
+ collect_records,
254
+ in_unread_directory,
255
+ map_path,
256
+ merge_records,
257
+ parse_map,
258
+ read_map,
259
+ readers_of,
260
+ write_map,
261
+ }
262
+
263
+ export type { ReadMap }
264
+ export { test_read_map }
@@ -0,0 +1,91 @@
1
+ import { mkdtempSync, rmSync } from 'node:fs'
2
+ import { tmpdir } from 'node:os'
3
+ import path from 'node:path'
4
+ import { input_fingerprint } from '#scripts/gate/input-fingerprint'
5
+ import { changed_paths } from '#scripts/git/changed-paths'
6
+ import { git_command } from '#scripts/git/git-command'
7
+ import { git_spawn } from '#scripts/git/git-spawn'
8
+ import { test_read_map, type ReadMap } from './test-read-map'
9
+ import { test_read_trace } from './test-read-trace'
10
+
11
+ // When a unit run records the test-read map, and how the records become one. **Only a run of the
12
+ // whole suite records**: a map is read as "nothing else reads this file", which a narrowed, sharded
13
+ // or filtered run cannot vouch for. **Only a green run replaces the map**: a failed test may have
14
+ // stopped before the read it would have made.
15
+
16
+ type RecordingEnvironment = Record<string, string>
17
+
18
+ const RUN_SUBCOMMAND = 'run'
19
+
20
+ // The one flag a whole-suite run still carries — the gate's worker cap, which sizes the run without
21
+ // narrowing it.
22
+ const WORKER_FLAG_PREFIX = '--maxWorkers'
23
+
24
+ const RECORD_DIRECTORY_PREFIX = 'josh-test-reads-'
25
+
26
+ function is_recordable(vitest_arguments: ReadonlyArray<string>): boolean {
27
+ const [subcommand, ...flags] = vitest_arguments
28
+
29
+ return subcommand === RUN_SUBCOMMAND && flags.every((flag) => flag.startsWith(WORKER_FLAG_PREFIX))
30
+ }
31
+
32
+ // Every directory the commit holds, NUL-separated so a name git would quote reads as itself.
33
+ async function commit_directories(commit: string): Promise<Array<string>> {
34
+ const output = await git_spawn.read(['ls-tree', '-r', '-d', '--name-only', '-z', commit])
35
+
36
+ return output.split('\0').filter((listed) => listed.length > 0)
37
+ }
38
+
39
+ type TreeSnapshot = Pick<ReadMap, 'commit' | 'dirty' | 'directories'>
40
+
41
+ // The tree the run read: the commit, every file that differed from it with its content's digest, and
42
+ // the directories it holds. **Read before the run starts**: a digest taken after it would vouch for
43
+ // an edit made while the tests ran as content they read.
44
+ async function tree_snapshot(root: string): Promise<TreeSnapshot> {
45
+ const commit = await git_command.head_commit()
46
+ const dirty = input_fingerprint.of_files(root, await changed_paths.read_changed_since(commit))
47
+
48
+ return { commit, dirty, directories: await commit_directories(commit) }
49
+ }
50
+
51
+ // A map that cannot be written — no git, a read-only common directory — leaves the previous map in
52
+ // place, and a narrowing over a stale map is refused by the commit it names.
53
+ function save_map(root: string, directory: string, snapshot: TreeSnapshot): void {
54
+ try {
55
+ const readers = test_read_map.merge_records(test_read_map.collect_records(directory))
56
+
57
+ test_read_map.write_map(root, { version: test_read_map.MAP_VERSION, ...snapshot, readers })
58
+ } catch {
59
+ // The previous map stays; the run's own result is unaffected.
60
+ }
61
+ }
62
+
63
+ async function with_read_recording(
64
+ root: string,
65
+ vitest_arguments: ReadonlyArray<string>,
66
+ run: (environment: RecordingEnvironment) => Promise<number>,
67
+ ): Promise<number> {
68
+ if (!is_recordable(vitest_arguments)) return await run({})
69
+
70
+ const directory = mkdtempSync(path.join(tmpdir(), RECORD_DIRECTORY_PREFIX))
71
+
72
+ try {
73
+ // Settled rather than awaited, so a tree git cannot read records no map and fails no run.
74
+ const [tree] = await Promise.allSettled([tree_snapshot(root)])
75
+ const exit_code = await run({
76
+ [test_read_trace.RECORD_DIRECTORY_KEY]: directory,
77
+ [test_read_trace.ROOT_KEY]: root,
78
+ })
79
+
80
+ if (exit_code === 0 && tree.status === 'fulfilled') save_map(root, directory, tree.value)
81
+
82
+ return exit_code
83
+ } finally {
84
+ rmSync(directory, { recursive: true, force: true })
85
+ }
86
+ }
87
+
88
+ const test_read_recording = { is_recordable, with_read_recording }
89
+
90
+ export type { RecordingEnvironment }
91
+ export { test_read_recording }