@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,14 +1,22 @@
1
1
  import { git_gh_command } from '#scripts/gh/git-gh-command'
2
2
  import { issue_cite } from '#scripts/issue/issue-cite'
3
- import { josh_command, type JoshResult } from '#scripts/josh/josh-run'
3
+ import type { JoshResult } from '#scripts/josh/josh-run'
4
4
  import { lane_capacity } from '#scripts/lane/lane-capacity'
5
+ import { lane_process_table, type TableRead } from '#scripts/lane/lane-process-table'
5
6
  import { lane_registry, type LaneInfo } from '#scripts/lane/lane-registry'
7
+ import { lane_snapshot_trace } from '#scripts/lane/lane-snapshot-trace'
6
8
  import { lane_spent } from '#scripts/lane/lane-spent'
9
+ import { lane_state } from '#scripts/lane/lane-state'
7
10
  import type { RunCarry } from '#scripts/run/carry/run-carry'
11
+ import { run_event_scope } from '#scripts/run/event/run-event-scope'
12
+ import { run_event_stream } from '#scripts/run/event/run-event-stream'
8
13
  import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
9
14
  import { run_headless } from '#scripts/run/run-headless'
10
15
  import { run_invocation } from '#scripts/run/run-invocation'
11
- import { backlog_occupied, type OccupiedRead } from './backlog-occupied'
16
+ import { backlog_drive_restore } from './backlog-drive-restore'
17
+ import { backlog_next_shared } from './backlog-next-shared'
18
+ import { backlog_occupied } from './backlog-occupied'
19
+ import { backlog_offer_exclude } from './backlog-offer-exclude'
12
20
  import { backlog_stalled } from './backlog-stalled'
13
21
 
14
22
  // The ready line reports runnable work to the driving backlogrun parent on a watcher wake.
@@ -21,10 +29,27 @@ interface ReadyReading {
21
29
  free_lanes: number
22
30
  }
23
31
 
24
- // How many open lanes hold a place under the limit, and how many hold a port seat.
32
+ // How many open lanes hold a place under the limit, how many hold a port seat, and the ones with no
33
+ // lane state record.
25
34
  interface LaneUse {
26
35
  occupied: number
27
36
  seated: number
37
+ unknown: ReadonlyArray<string>
38
+ }
39
+
40
+ // The lanes that hold a place under the limit, read once for every count drawn from them.
41
+ interface LaneRoom {
42
+ occupied: ReadonlyArray<LaneInfo>
43
+ // The open lanes no child is working in, read from the same snapshot.
44
+ idle: ReadonlyArray<string>
45
+ // The open lanes with no lane state record, counted as holding a place until one is written.
46
+ unknown: ReadonlyArray<string>
47
+ use: LaneUse
48
+ }
49
+
50
+ interface LaneCount {
51
+ limit: number
52
+ free: number
28
53
  }
29
54
 
30
55
  interface ReadyPorts {
@@ -32,45 +57,69 @@ interface ReadyPorts {
32
57
  ready_issues: () => Promise<ReadonlyArray<string>>
33
58
  }
34
59
 
35
- // What decides which open lanes hold a place, read from this checkout's live run.
36
- async function occupied_read(): Promise<OccupiedRead> {
37
- const carry = await run_headless.current_carry()
38
-
39
- return {
40
- invocation: carry?.invocation,
41
- events: carry === undefined ? [] : await run_event_stream_emit.scoped_current_events(),
42
- idle: lane_spent.idle_lanes,
43
- }
60
+ // The lanes that hold a place under the limit (`backlog-occupied.ts`), the idle ones and the unknown
61
+ // ones. Paused is each lane's state record's answer; every lane's idle reading is drawn from one
62
+ // asynchronous process snapshot, so the count never blocks its caller's event loop
63
+ // (joshuafolkken/kit#4241, #4245); `run:board` passes the snapshot its redraw already read (#4246).
64
+ async function occupancy_of(
65
+ open: ReadonlyArray<LaneInfo>,
66
+ table: TableRead,
67
+ ): Promise<Omit<LaneRoom, 'use'>> {
68
+ const rows = await table()
69
+ const issues = open.map((lane) => lane.issue)
70
+ const trace = { process_trace: await lane_snapshot_trace.traces_of(issues, rows) }
71
+ const records = await lane_state.read_states(issues)
72
+ const is_merge_waiting = await lane_snapshot_trace.merge_waits_of(issues, rows)
73
+ const occupied = backlog_occupied.occupied_lanes(
74
+ open,
75
+ (live) => lane_spent.idle_lanes(live, trace),
76
+ records,
77
+ is_merge_waiting,
78
+ )
79
+ const unknown = backlog_occupied.unknown_lanes(open, records)
80
+
81
+ return { occupied, idle: lane_spent.idle_lanes(open, trace), unknown }
44
82
  }
45
83
 
46
- // The lanes that hold a place under the limit (`backlog-occupied.ts`).
47
- async function occupied_lanes(lanes?: ReadonlyArray<LaneInfo>): Promise<Array<LaneInfo>> {
84
+ // The open lanes as the free count reads them: those that hold a place under the limit, and every
85
+ // open one, since an uncounted lane still holds its port seat.
86
+ async function lane_room(
87
+ lanes?: ReadonlyArray<LaneInfo>,
88
+ table: TableRead = lane_process_table.read_table,
89
+ ): Promise<LaneRoom> {
48
90
  const open = lanes ?? (await lane_registry.list_lanes())
91
+ const occupancy = await occupancy_of(open, table)
92
+ const seated = open.filter((lane) => !lane.is_stranded).length
49
93
 
50
- return backlog_occupied.occupied_lanes(open, await occupied_read())
94
+ const use = { occupied: occupancy.occupied.length, seated, unknown: occupancy.unknown }
95
+
96
+ return { ...occupancy, use }
51
97
  }
52
98
 
53
- // The open lanes as the free count reads them: those that hold a place under the limit, and every
54
- // open one, since an uncounted lane still holds its port seat.
55
99
  async function lane_use(lanes?: ReadonlyArray<LaneInfo>): Promise<LaneUse> {
56
- const open = lanes ?? (await lane_registry.list_lanes())
57
- const occupied = await occupied_lanes(open)
100
+ const room = await lane_room(lanes)
58
101
 
59
- return { occupied: occupied.length, seated: open.filter((lane) => !lane.is_stranded).length }
102
+ return room.use
60
103
  }
61
104
 
62
105
  function free_of(limit: number, use: LaneUse): number {
63
106
  return lane_capacity.free_lanes(limit, use.occupied, use.seated)
64
107
  }
65
108
 
66
- // Free lanes beside `lanes`, `undefined` where the limit could not be read: the count `lane:limit`
67
- // prints, and the one `run:board` draws, so the two never answer apart.
68
- async function free_lanes_beside(lanes: ReadonlyArray<LaneInfo>): Promise<number | undefined> {
109
+ // The limit and the free lanes in `room`, `undefined` where the limit could not be read: the count
110
+ // `lane:limit` prints, and the one `run:board` draws, so the two never answer apart.
111
+ async function count_in(room: LaneRoom): Promise<LaneCount | undefined> {
69
112
  const limit = await lane_capacity.lane_limit()
70
113
 
71
114
  if (limit.kind !== 'limit') return undefined
72
115
 
73
- return free_of(limit.limit, await lane_use(lanes))
116
+ return { limit: limit.limit, free: free_of(limit.limit, room.use) }
117
+ }
118
+
119
+ async function free_lanes_beside(lanes: ReadonlyArray<LaneInfo>): Promise<number | undefined> {
120
+ const count = await count_in(await lane_room(lanes))
121
+
122
+ return count?.free
74
123
  }
75
124
 
76
125
  async function free_under(limit: number): Promise<number> {
@@ -94,12 +143,24 @@ async function free_lane_count(): Promise<number> {
94
143
  // **The drive's count throws on an unreadable limit**. The drive launches no
95
144
  // more than this count, so the safe-direction zero above would leave it launching nothing and reporting
96
145
  // nothing for good; a bad setting is the hard error `lane_capacity` says it is, ending the drive loudly.
97
- async function drive_free_lane_count(): Promise<number> {
146
+ async function drive_limit(): Promise<number> {
98
147
  const limit = await lane_capacity.lane_limit()
99
148
 
100
149
  if (limit.kind !== 'limit') throw new Error(limit.problem)
101
150
 
102
- return await free_under(limit.limit)
151
+ return limit.limit
152
+ }
153
+
154
+ async function drive_free_lane_count(): Promise<number> {
155
+ return await free_under(await drive_limit())
156
+ }
157
+
158
+ // The drive's room under the limit alone, for resuming a kept lane, which already holds its port seat.
159
+ async function drive_limit_room(): Promise<number> {
160
+ const limit = await drive_limit()
161
+ const use = await lane_use()
162
+
163
+ return lane_capacity.limit_room(limit, use.occupied)
103
164
  }
104
165
 
105
166
  // **A `--only` run has no pool to drain**. `backlog:next` lists the opted-in
@@ -110,13 +171,32 @@ function drains_pool(carry: RunCarry | undefined): boolean {
110
171
  return carry === undefined || !run_invocation.has_only(carry.invocation)
111
172
  }
112
173
 
174
+ // The offer's own exclusion, read off this run's stream: a merged child `backlog:next` still reads OPEN,
175
+ // or one in flight, is no ready work (joshuafolkken/kit#4349). Scoped to this invocation, as the drive's
176
+ // list is: the stream is the repository's log, so an earlier run's merge or unsettled launch would
177
+ // otherwise hide a reopened issue for good.
178
+ async function stream_exclude(carry: RunCarry | undefined): Promise<ReadonlyArray<string>> {
179
+ const target = await run_event_stream_emit.stream_target()
180
+
181
+ if (target === undefined || carry === undefined) return []
182
+
183
+ const scope = run_event_scope.scope_of({ kind: 'carried', carry })
184
+ const events = run_event_scope.scoped_events(run_event_stream.read_events(target), scope) ?? []
185
+
186
+ return backlog_drive_restore.offer_exclude(events)
187
+ }
188
+
113
189
  // The `backlog:next` read, or `undefined` for a `--only` run, which answers none before paying for the
114
190
  // network read. A bounded read keeps stderr piped: the arrival probe reads once
115
191
  // a minute, and a forwarded refusal would fill the watcher's output.
116
192
  async function read_backlog_next(timeout_ms?: number): Promise<JoshResult | undefined> {
117
- if (!drains_pool(await run_headless.current_carry())) return undefined
193
+ const carry = await run_headless.current_carry()
194
+
195
+ if (!drains_pool(carry)) return undefined
196
+
197
+ const argv = ['backlog:next', ...backlog_offer_exclude.exclude_argv(await stream_exclude(carry))]
118
198
 
119
- return await josh_command.josh_run(['backlog:next'], timeout_ms === undefined, timeout_ms)
199
+ return await backlog_next_shared.read(argv, timeout_ms === undefined, timeout_ms)
120
200
  }
121
201
 
122
202
  // The runnable issues for this checkout, read the way a loop reads them: `backlog:next`'s numeric lines.
@@ -208,9 +288,11 @@ const backlog_ready = {
208
288
  print_offer_hint,
209
289
  free_lane_count,
210
290
  free_lanes_beside,
291
+ count_in,
292
+ lane_room,
211
293
  lane_use,
212
- occupied_lanes,
213
294
  drive_free_lane_count,
295
+ drive_limit_room,
214
296
  drains_pool,
215
297
  print_ready_line,
216
298
  read_ready,
@@ -219,4 +301,4 @@ const backlog_ready = {
219
301
  }
220
302
 
221
303
  export { backlog_ready }
222
- export type { LaneUse, ReadyPorts, ReadyReading }
304
+ export type { LaneCount, LaneRoom, LaneUse, ReadyPorts, ReadyReading }
@@ -1,12 +1,14 @@
1
- import { telegram_notify } from '#scripts/notify/telegram-notify'
1
+ import { lane_ledger, type LedgerEntry } from '#scripts/lane/lane-ledger'
2
2
  import { run_event_stream, type RunEvent } from '#scripts/run/event/run-event-stream'
3
3
  import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
4
4
  import { backlog_ready, type ReadyPorts } from './backlog-ready'
5
5
  import { backlog_stalled, type StallReading, type StallVerdict } from './backlog-stalled'
6
6
 
7
7
  // The I/O half of the stall detector: it gathers the three counts the pure
8
- // judge in `backlog-stalled.ts` weighs, then — on a stall — leaves the marker and sends the one
9
- // notification. `stop-guard.ts` wires it into the Stop hook, so it runs at each loop boundary; the CLI
8
+ // judge in `backlog-stalled.ts` weighs, then — on a stall — leaves the marker `run:step` reads as
9
+ // `backlog:next`. It sends no Telegram (joshuafolkken/kit#4015): a stall resolves itself at the next
10
+ // dispatch, so the person it reached had nothing to do; the idle notification `backlog:drive` sends
11
+ // when nothing is left to dispatch is the one that wants a hand. `stop-guard.ts` wires it into the Stop hook, so it runs at each loop boundary; the CLI
10
12
  // exposes the same call for a person to run by hand.
11
13
  //
12
14
  // **Cheap first.** The costly read is `backlog:next`, a subprocess that hits the network. The two local
@@ -14,26 +16,39 @@ import { backlog_stalled, type StallReading, type StallVerdict } from './backlog
14
16
  // is one `git worktree list`. Neither the lane count nor the backlog read is made unless the cheaper
15
17
  // condition ahead of it already holds, so an ordinary stop — a run not idle, or with no free lane —
16
18
  // costs a single file read and nothing more.
19
+ //
20
+ // **A stall is aged from when work and a lane first met** (joshuafolkken/kit#4349). Each probe records,
21
+ // on the lane ledger, whether offerable work and a free lane coexist — only when that changes — and the
22
+ // wait runs from the observation that opened the current episode. The dispatch age stays the cheap
23
+ // gate: the wait can never exceed it.
17
24
 
18
25
  const NO_FREE = 0
19
26
  const NO_READY = 0
20
27
  const NO_AGE = 0
21
28
 
22
- // The recovery line names the command that resolves the stall — the same one `run:step` points a stalled
23
- // run at — so the person the notification reaches has the fix in hand.
24
- const STALL_RECOVERY = 'Dispatch the ready work with `pnpm josh backlog:next`.'
25
-
26
- // The seams a test replaces: the stream target and its events, the clock, the two counts, and the two
27
- // side effects. The defaults are the real readers; a test hands fakes so the gather and report logic run
28
- // without a git tree, a network or a wall clock.
29
+ // The seams a test replaces: the stream target and its events, the clock, the two counts, the ledger,
30
+ // and the marker. The defaults are the real readers; a test hands fakes so the gather and report logic
31
+ // run without a git tree, a network or a wall clock.
29
32
  interface DetectPorts {
30
33
  resolve_target: () => Promise<string | undefined>
31
34
  read_events: (target: string) => ReadonlyArray<RunEvent>
32
35
  now_ms: () => number
33
36
  free_lane_count: () => Promise<number>
34
37
  ready_count: () => Promise<number>
38
+ read_ledger: () => Promise<ReadonlyArray<LedgerEntry>>
39
+ mark_offerable: (is_offerable: boolean) => Promise<void>
35
40
  emit_stall: (text: string) => Promise<boolean>
36
- notify_stalled: (body: string) => Promise<boolean>
41
+ }
42
+
43
+ interface Counts {
44
+ ready_count: number
45
+ free_lanes: number
46
+ }
47
+
48
+ // The dispatch reference the episode is bounded by, and the probe's own time.
49
+ interface Clock {
50
+ reference_ms: number
51
+ now_ms: number
37
52
  }
38
53
 
39
54
  // The free-lane and runnable-issue reads are `backlog-ready.ts`'s — the watcher's ready line reads the
@@ -55,8 +70,15 @@ async function real_emit_stall(text: string): Promise<boolean> {
55
70
  return await run_event_stream_emit.emit_once_since(STALL, text, CHILD_LAUNCH)
56
71
  }
57
72
 
58
- async function real_notify_stalled(body: string): Promise<boolean> {
59
- return await telegram_notify.stalled({ body, recovery: STALL_RECOVERY })
73
+ // A test run has no ledger (`lane_ledger.target`), so it reads as empty there.
74
+ async function read_real_ledger(): Promise<ReadonlyArray<LedgerEntry>> {
75
+ const path = await lane_ledger.target()
76
+
77
+ return path === undefined ? [] : lane_ledger.read_entries(path)
78
+ }
79
+
80
+ async function real_mark_offerable(is_offerable: boolean): Promise<void> {
81
+ await lane_ledger.record_offerable(is_offerable)
60
82
  }
61
83
 
62
84
  function ports_over(ready: ReadyPorts): DetectPorts {
@@ -66,26 +88,64 @@ function ports_over(ready: ReadyPorts): DetectPorts {
66
88
  now_ms: () => Date.now(),
67
89
  free_lane_count: ready.free_lane_count,
68
90
  ready_count: ready_count_of(ready),
91
+ read_ledger: read_real_ledger,
92
+ mark_offerable: real_mark_offerable,
69
93
  emit_stall: real_emit_stall,
70
- notify_stalled: real_notify_stalled,
71
94
  }
72
95
  }
73
96
 
74
97
  const DEFAULT_PORTS: DetectPorts = ports_over(backlog_ready.DEFAULT_PORTS)
75
98
 
76
- function ok_reading(dispatch_age_ms: number): StallReading {
77
- return { ready_count: NO_READY, free_lanes: NO_FREE, dispatch_age_ms }
99
+ function ok_reading(): StallReading {
100
+ return { ready_count: NO_READY, free_lanes: NO_FREE, waiting_ms: NO_AGE }
78
101
  }
79
102
 
80
- // The idle-and-past-threshold branch, where the costly reads finally happen: count the free lanes, and
81
- // only if one is free read the backlog. A full pool short-circuits before the network call — a stall
82
- // needs a lane to go into.
83
- async function probe_reading(ports: DetectPorts, dispatch_age_ms: number): Promise<StallReading> {
103
+ // Count the free lanes, and only if one is free read the backlog. A full pool short-circuits before the
104
+ // network call — a stall needs a lane to go into.
105
+ async function read_counts(ports: DetectPorts): Promise<Counts> {
84
106
  const free_lanes = await ports.free_lane_count()
85
107
 
86
- if (free_lanes <= NO_FREE) return { ready_count: NO_READY, free_lanes, dispatch_age_ms }
108
+ if (free_lanes <= NO_FREE) return { ready_count: NO_READY, free_lanes }
109
+
110
+ return { ready_count: await ports.ready_count(), free_lanes }
111
+ }
112
+
113
+ function has_both(counts: Counts): boolean {
114
+ return counts.ready_count > NO_READY && counts.free_lanes > NO_FREE
115
+ }
116
+
117
+ // How long both have held: from the observation that opened the episode, or zero where this probe opens
118
+ // or closes one — and records that change.
119
+ async function waiting_ms(
120
+ ports: DetectPorts,
121
+ entries: ReadonlyArray<LedgerEntry>,
122
+ clock: Clock,
123
+ is_offerable: boolean,
124
+ ): Promise<number> {
125
+ const opened_ms = backlog_stalled.open_offerable_ms(entries, clock.reference_ms)
126
+
127
+ if (is_offerable === (opened_ms !== undefined)) return clock.now_ms - (opened_ms ?? clock.now_ms)
87
128
 
88
- return { ready_count: await ports.ready_count(), free_lanes, dispatch_age_ms }
129
+ await ports.mark_offerable(is_offerable)
130
+
131
+ return NO_AGE
132
+ }
133
+
134
+ // The idle-and-past-threshold branch, where the costly reads finally happen.
135
+ async function probe_reading(ports: DetectPorts, clock: Clock): Promise<StallReading> {
136
+ const counts = await read_counts(ports)
137
+ const entries = await ports.read_ledger()
138
+ const waited = await waiting_ms(ports, entries, clock, has_both(counts))
139
+
140
+ return { ...counts, waiting_ms: waited, hold: backlog_stalled.open_hold(entries) }
141
+ }
142
+
143
+ // The dispatch reference and the probe's time, or `undefined` when the stream has nothing to age against.
144
+ function clock_of(ports: DetectPorts, target: string): Clock | undefined {
145
+ const now_ms = ports.now_ms()
146
+ const age = backlog_stalled.dispatch_age_ms(ports.read_events(target), now_ms)
147
+
148
+ return age === undefined ? undefined : { reference_ms: now_ms - age, now_ms }
89
149
  }
90
150
 
91
151
  // The reading that decides the verdict, assembled cheap-condition-first. `undefined` is the unreadable
@@ -96,25 +156,38 @@ async function gather(ports: DetectPorts, threshold_ms: number): Promise<StallRe
96
156
 
97
157
  if (target === undefined) return undefined
98
158
 
99
- const age = backlog_stalled.dispatch_age_ms(ports.read_events(target), ports.now_ms())
159
+ const clock = clock_of(ports, target)
100
160
 
101
- if (age === undefined) return ok_reading(NO_AGE)
102
- if (age <= threshold_ms) return ok_reading(age)
161
+ if (clock === undefined || clock.now_ms - clock.reference_ms <= threshold_ms) return ok_reading()
103
162
 
104
- return await probe_reading(ports, age)
163
+ return await probe_reading(ports, clock)
105
164
  }
106
165
 
107
- // The marker and the notification, both once per stall episode. `emit_stall` refuses a second until a
108
- // dispatch has intervened, and its `false` is what holds the notification back too — so a stall
109
- // polled every stop reaches the person once, not once a turn.
110
- async function report(ports: DetectPorts, reading: StallReading): Promise<void> {
111
- const text = backlog_stalled.describe(reading)
166
+ // The watcher's once-a-minute arrival probe records the same observation from the reading it already
167
+ // made, so an episode opens within a probe interval of work meeting a lane — not at the first stop past
168
+ // the dispatch-age gate, which would hide up to one threshold of the wait. Best-effort, like the check.
169
+ async function observe_offerable(
170
+ is_offerable: boolean,
171
+ ports: DetectPorts = DEFAULT_PORTS,
172
+ ): Promise<void> {
173
+ try {
174
+ const target = await ports.resolve_target()
175
+ const clock = target === undefined ? undefined : clock_of(ports, target)
112
176
 
113
- if (await ports.emit_stall(text)) await ports.notify_stalled(text)
177
+ if (clock !== undefined) await waiting_ms(ports, await ports.read_ledger(), clock, is_offerable)
178
+ } catch {
179
+ // A failed observation is dropped: the next probe records it, and the watcher's loop must not break.
180
+ }
181
+ }
182
+
183
+ // The marker, once per stall episode: `emit_stall` refuses a second until a dispatch has intervened, so a
184
+ // stall polled every stop lands on the stream once, not once a turn.
185
+ async function report(ports: DetectPorts, reading: StallReading): Promise<void> {
186
+ await ports.emit_stall(backlog_stalled.describe(reading))
114
187
  }
115
188
 
116
- // Read the three conditions, print nothing, and on a stall leave the marker and notify. The verdict is
117
- // returned for the CLI to print; the side effects are the report's.
189
+ // Read the three conditions, print nothing, and on a stall leave the marker. The verdict is returned for
190
+ // the CLI to print; the side effect is the report's.
118
191
  async function detect_and_report(
119
192
  ports: DetectPorts = DEFAULT_PORTS,
120
193
  threshold_ms: number = backlog_stalled.STALL_THRESHOLD_MS,
@@ -127,7 +200,7 @@ async function detect_and_report(
127
200
  return verdict
128
201
  }
129
202
 
130
- // Best-effort for the Stop hook: the detector is a report, so a failure to gather or notify is dropped
203
+ // Best-effort for the Stop hook: the detector is a report, so a failure to gather or mark is dropped
131
204
  // rather than raised into the stop decision it rides alongside.
132
205
  async function run_stall_check(ready: ReadyPorts = backlog_ready.DEFAULT_PORTS): Promise<void> {
133
206
  try {
@@ -137,7 +210,7 @@ async function run_stall_check(ready: ReadyPorts = backlog_ready.DEFAULT_PORTS):
137
210
  }
138
211
  }
139
212
 
140
- const backlog_stalled_detect = { detect_and_report, run_stall_check }
213
+ const backlog_stalled_detect = { detect_and_report, observe_offerable, run_stall_check }
141
214
 
142
215
  export { backlog_stalled_detect }
143
216
  export type { DetectPorts }
@@ -1,11 +1,13 @@
1
1
  import { epic_triage } from '#scripts/epic/epic-triage'
2
2
  import { issue_number_shape } from '#scripts/issue/issue-number-shape'
3
+ import { lane_ledger, type LedgerEntry } from '#scripts/lane/lane-ledger'
4
+ import { MS_PER_MINUTE } from '#scripts/lib/timeouts'
3
5
  import { run_event_stream, type RunEvent } from '#scripts/run/event/run-event-stream'
4
6
 
5
7
  // When ready backlog work sits undispatched while lanes are free, nobody notices until a person asks.
6
8
  // This is the mechanical judge of that state: three facts read, never
7
9
  // weighed — is there runnable work, is there a free lane, and has nothing been dispatched for a while.
8
- // The verdict is a report, not a stop: a false positive costs one notification, never a halted run.
10
+ // The verdict is a report, not a stop: a false positive costs one stream marker, never a halted run.
9
11
  //
10
12
  // **Pure by design.** The clock and the counts are handed in, so the four acceptance cases — work with
11
13
  // a free lane, work with no free lane, no work, and an unreadable record — and the elapsed-time
@@ -13,7 +15,6 @@ import { run_event_stream, type RunEvent } from '#scripts/run/event/run-event-st
13
15
  // counts is `backlog-stalled-detect.ts`; this file only decides.
14
16
 
15
17
  const STALL_THRESHOLD_MINUTES = 10
16
- const MS_PER_MINUTE = 60_000
17
18
  const STALL_THRESHOLD_MS = STALL_THRESHOLD_MINUTES * MS_PER_MINUTE
18
19
  const NONE = 0
19
20
 
@@ -28,11 +29,14 @@ const OK: StallVerdict = 'ok'
28
29
  const UNREADABLE: StallVerdict = 'unreadable'
29
30
 
30
31
  // The three facts, read and never judged: how many issues could start now, how many lanes are free, and
31
- // how long since the last dispatch. Assembled by the detect layer; consumed only here.
32
+ // how long both have held together since the last dispatch — never the idle time before work arrived or
33
+ // a long child ran (joshuafolkken/kit#4349). `hold` is the driver's open hold reason (`memory`, …), so a
34
+ // deliberate hold reads apart from a slow dispatch. Assembled by the detect layer; consumed only here.
32
35
  interface StallReading {
33
36
  ready_count: number
34
37
  free_lanes: number
35
- dispatch_age_ms: number
38
+ waiting_ms: number
39
+ hold?: string | undefined
36
40
  }
37
41
 
38
42
  // All three together, and only together. Separated from `assess` so the short-circuit gate in the
@@ -40,9 +44,7 @@ interface StallReading {
40
44
  // same condition rather than a second copy of it.
41
45
  function is_stalled(reading: StallReading, threshold_ms: number): boolean {
42
46
  return (
43
- reading.ready_count > NONE &&
44
- reading.free_lanes > NONE &&
45
- reading.dispatch_age_ms > threshold_ms
47
+ reading.ready_count > NONE && reading.free_lanes > NONE && reading.waiting_ms > threshold_ms
46
48
  )
47
49
  }
48
50
 
@@ -68,23 +70,55 @@ function dispatch_reference_iso(events: ReadonlyArray<RunEvent>): string | undef
68
70
  return last_launch?.at ?? events[0]?.at
69
71
  }
70
72
 
71
- // Milliseconds since that reference, or `undefined` when there is no reference or the stamp is
72
- // unparseable — the caller reads either as "nothing to age against" and returns no stall.
73
- function dispatch_age_ms(events: ReadonlyArray<RunEvent>, now_ms: number): number | undefined {
73
+ // That reference as epoch milliseconds, or `undefined` when there is none or the stamp is unparseable.
74
+ function dispatch_reference_ms(events: ReadonlyArray<RunEvent>): number | undefined {
74
75
  const iso = dispatch_reference_iso(events)
76
+ const at = iso === undefined ? NaN : Date.parse(iso)
77
+
78
+ return Number.isNaN(at) ? undefined : at
79
+ }
75
80
 
76
- if (iso === undefined) return undefined
81
+ // Milliseconds since that reference, or `undefined` when there is no reference — the caller reads it as
82
+ // "nothing to age against" and returns no stall. A stall cannot be older than this, so it gates the
83
+ // costly reads.
84
+ function dispatch_age_ms(events: ReadonlyArray<RunEvent>, now_ms: number): number | undefined {
85
+ const at = dispatch_reference_ms(events)
86
+
87
+ return at === undefined ? undefined : now_ms - at
88
+ }
89
+
90
+ // When the current coexistence of offerable work and a free lane was first observed: the newest
91
+ // observation since the reference, if it saw both. `undefined` when it did not or none was made — an
92
+ // observation before the last dispatch belongs to an episode that dispatch ended.
93
+ function open_offerable_ms(
94
+ entries: ReadonlyArray<LedgerEntry>,
95
+ reference_ms: number,
96
+ ): number | undefined {
97
+ const newest = entries.findLast(
98
+ (entry) => entry.kind === lane_ledger.KIND.OFFERABLE && Date.parse(entry.at) >= reference_ms,
99
+ )
100
+
101
+ if (newest?.kind !== lane_ledger.KIND.OFFERABLE || !newest.is_offerable) return undefined
102
+
103
+ return Date.parse(newest.at)
104
+ }
77
105
 
78
- const at = Date.parse(iso)
106
+ // The driver's open hold reason: the newest of its hold, release and dispatch records, when a hold.
107
+ function open_hold(entries: ReadonlyArray<LedgerEntry>): string | undefined {
108
+ const { HELD, RELEASED, DISPATCH } = lane_ledger.KIND
109
+ const hold_kinds: ReadonlySet<string> = new Set([HELD, RELEASED, DISPATCH])
110
+ const newest = entries.findLast((entry) => hold_kinds.has(entry.kind))
79
111
 
80
- return Number.isNaN(at) ? undefined : now_ms - at
112
+ return newest?.kind === lane_ledger.KIND.HELD ? newest.reason : undefined
81
113
  }
82
114
 
83
- // The one line a person reads in the notification and on the stream: what is waiting and how long.
115
+ // The one line a person reads in the notification and on the stream: what is waiting, how long, and the
116
+ // driver's hold reason when it holds deliberately.
84
117
  function describe(reading: StallReading): string {
85
- const minutes = Math.floor(reading.dispatch_age_ms / MS_PER_MINUTE)
118
+ const minutes = Math.floor(reading.waiting_ms / MS_PER_MINUTE)
119
+ const held = reading.hold === undefined ? '' : ` (held: ${reading.hold})`
86
120
 
87
- return `${String(reading.ready_count)} ready, ${String(reading.free_lanes)} free lane(s), ${String(minutes)}m since the last dispatch`
121
+ return `${String(reading.ready_count)} ready, ${String(reading.free_lanes)} free lane(s), ${String(minutes)}m waiting with both${held}`
88
122
  }
89
123
 
90
124
  // The runnable issue numbers `backlog:next` printed: one token per line, a bare number per runnable
@@ -118,6 +152,8 @@ const backlog_stalled = {
118
152
  describe,
119
153
  dispatch_age_ms,
120
154
  needs_triage,
155
+ open_hold,
156
+ open_offerable_ms,
121
157
  ready_tokens,
122
158
  }
123
159