@joshuafolkken/kit 1.1229.0 → 1.1370.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 (939) hide show
  1. package/.claude/agents/investigator.md +1 -0
  2. package/.claude/settings.json +4 -0
  3. package/.claude/skills/dependency-update/SKILL.md +5 -3
  4. package/.claude/skills/epic-commands/SKILL.md +82 -113
  5. package/.claude/skills/epic-commands/epic-bundle.md +38 -63
  6. package/.claude/skills/epic-commands/execution-waves.md +30 -51
  7. package/.claude/skills/verify-ui/SKILL.md +13 -20
  8. package/.claude/skills/workflow-commands/SKILL.md +10 -10
  9. package/.claude/skills/workflow-commands/background-commands.md +4 -4
  10. package/.claude/skills/workflow-commands/backlogrun-child.md +30 -105
  11. package/.claude/skills/workflow-commands/backlogrun-handoff-report.md +29 -0
  12. package/.claude/skills/workflow-commands/backlogrun-lanes.md +45 -131
  13. package/.claude/skills/workflow-commands/backlogrun-park.md +36 -53
  14. package/.claude/skills/workflow-commands/backlogrun-progress.md +81 -331
  15. package/.claude/skills/workflow-commands/backlogrun-recovery.md +29 -83
  16. package/.claude/skills/workflow-commands/backlogrun-steps.md +105 -424
  17. package/.claude/skills/workflow-commands/backlogrun.md +50 -61
  18. package/.claude/skills/workflow-commands/chain-rule.md +36 -40
  19. package/.claude/skills/workflow-commands/entry-sequence.md +6 -6
  20. package/.claude/skills/workflow-commands/followup.md +24 -20
  21. package/.claude/skills/workflow-commands/fullrun-steps.md +23 -27
  22. package/.claude/skills/workflow-commands/fullrun.md +10 -10
  23. package/.claude/skills/workflow-commands/halfrun.md +9 -8
  24. package/.claude/skills/workflow-commands/into-target.md +12 -18
  25. package/.claude/skills/workflow-commands/issue-comments.md +11 -26
  26. package/.claude/skills/workflow-commands/kickoff.md +27 -16
  27. package/.claude/skills/workflow-commands/latest-gate.md +18 -29
  28. package/.claude/skills/workflow-commands/needs-human-review.md +13 -24
  29. package/.claude/skills/workflow-commands/observation-filing.md +37 -28
  30. package/.claude/skills/workflow-commands/observation-ledger.md +48 -38
  31. package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -9
  32. package/.claude/skills/workflow-commands/prerequisite.md +23 -15
  33. package/.claude/skills/workflow-commands/progress-watcher.md +17 -11
  34. package/.claude/skills/workflow-commands/prrun.md +3 -3
  35. package/.claude/skills/workflow-commands/retrospective.md +13 -18
  36. package/.claude/skills/workflow-commands/split-assessment.md +6 -4
  37. package/.claude/skills/workflow-commands/target-repository.md +25 -28
  38. package/.claude/skills/workflow-commands/working-tree-hold.md +11 -17
  39. package/.gitattributes +2 -1
  40. package/.github/workflows/ci.yml +14 -0
  41. package/.github/workflows/publish.yml +2 -0
  42. package/.vscode/tasks.json +14 -0
  43. package/CLAUDE.md +10 -61
  44. package/README.md +38 -57
  45. package/SECURITY.md +1 -1
  46. package/dist/CLAUDE.md +10 -61
  47. package/dist/commands/document-section-cli.js +42 -10
  48. package/dist/config-merge/index.js +11 -2
  49. package/dist/hooks/audit-provision.js +2 -2
  50. package/dist/hooks/batch-guard.js +7 -7
  51. package/dist/hooks/{chunk-FIVDHQGT.js → chunk-43G45XJF.js} +18 -20
  52. package/dist/hooks/{chunk-JUDKDCDP.js → chunk-4TW4MQUL.js} +284 -362
  53. package/dist/hooks/{chunk-5VMKCCC4.js → chunk-76RK6E3H.js} +13 -11
  54. package/dist/hooks/{chunk-RNWHN5BP.js → chunk-DZWZ3DKY.js} +4 -4
  55. package/dist/hooks/{chunk-5VNDSNG3.js → chunk-FZ6FUSBM.js} +1 -1
  56. package/dist/hooks/{chunk-VC3PZPZO.js → chunk-GG72ANKI.js} +1 -1
  57. package/dist/hooks/{chunk-6HJJXRBX.js → chunk-KPM4YIIX.js} +8 -44
  58. package/dist/hooks/chunk-MXVQMLDP.js +3705 -0
  59. package/dist/hooks/{chunk-ELCN5LCH.js → chunk-NEC4AT4Z.js} +34 -12
  60. package/dist/hooks/{chunk-TQNPDZNH.js → chunk-NZBHG6FW.js} +7 -5
  61. package/dist/hooks/chunk-NZN2UFI6.js +2409 -0
  62. package/dist/hooks/{chunk-F56MFS4B.js → chunk-R6CRQEAL.js} +4 -4
  63. package/dist/hooks/chunk-SYSRHRWU.js +1589 -0
  64. package/dist/hooks/{chunk-55HHG5PX.js → chunk-TLJYAGZK.js} +799 -903
  65. package/dist/hooks/chunk-Z5TMJIPW.js +45 -0
  66. package/dist/hooks/codex-hook-adapter.js +26 -21
  67. package/dist/hooks/duplicate-read-guard.js +8 -8
  68. package/dist/hooks/format-edited.js +4 -4
  69. package/dist/hooks/inputs.json +213 -197
  70. package/dist/hooks/investigation-guard.js +8 -8
  71. package/dist/hooks/pretool-guard.js +15 -15
  72. package/dist/hooks/session-lang.js +406 -8
  73. package/dist/hooks/stop-guard.js +122 -201
  74. package/dist/josh.js +540 -137
  75. package/dist/version/index.js +15 -13
  76. package/eslint/base.js +43 -5
  77. package/eslint/rules/english-only-prose.js +3 -3
  78. package/eslint/rules/import.js +12 -0
  79. package/eslint/rules/namespace-object-export.js +2 -2
  80. package/package.json +16 -10
  81. package/pnpm-workspace.yaml +2 -4
  82. package/prompts/coding-standards.md +14 -48
  83. package/prompts/collaboration-workflow/file-edits.md +1 -1
  84. package/prompts/collaboration-workflow/issue-citation.md +1 -1
  85. package/prompts/collaboration-workflow/issue-template.md +4 -10
  86. package/prompts/collaboration-workflow/operating-rules.md +7 -8
  87. package/prompts/collaboration-workflow/output-bounds.md +1 -1
  88. package/prompts/collaboration-workflow/overview.md +1 -1
  89. package/prompts/collaboration-workflow/plan-comment.md +2 -1
  90. package/prompts/collaboration-workflow/principles.md +21 -3
  91. package/prompts/collaboration-workflow/report-format.md +16 -29
  92. package/prompts/collaboration-workflow/residency.md +1 -1
  93. package/prompts/collaboration-workflow/rule-delivery.md +7 -95
  94. package/prompts/collaboration-workflow/shell-body.md +3 -23
  95. package/prompts/collaboration-workflow/turn-batching.md +4 -13
  96. package/prompts/collaboration-workflow/wip-cap.md +5 -11
  97. package/prompts/refactoring.md +1 -1
  98. package/prompts/review-rubric.md +3 -22
  99. package/prompts/review.md +15 -38
  100. package/prompts/testing-guide.md +2 -4
  101. package/scripts/adopt/adopt-logic.ts +5 -5
  102. package/scripts/adopt/adopt-toolkits.ts +4 -5
  103. package/scripts/adopt/adopt.ts +2 -3
  104. package/scripts/agent/agent-argv.ts +7 -7
  105. package/scripts/agent/agent-diagnostics.ts +2 -2
  106. package/scripts/agent/agent-exit-record.ts +1 -1
  107. package/scripts/agent/agent-headless.ts +1 -1
  108. package/scripts/agent/agent-launch-environment.ts +6 -1
  109. package/scripts/agent/agent-role-profile.ts +49 -22
  110. package/scripts/agent/agent-session-role.ts +32 -0
  111. package/scripts/agent/api-outage.ts +1 -1
  112. package/scripts/agent/claude-agent-argv.ts +4 -4
  113. package/scripts/agent/claude-result-event.ts +4 -4
  114. package/scripts/agent/codex-hooks.ts +2 -2
  115. package/scripts/agent/interactive-ask.ts +3 -6
  116. package/scripts/auto-ok/auto-ok-cli.ts +46 -60
  117. package/scripts/backlog/backlog-arrival-added.ts +34 -0
  118. package/scripts/backlog/backlog-arrival.ts +54 -17
  119. package/scripts/backlog/backlog-budget-cli.ts +34 -6
  120. package/scripts/backlog/backlog-budget.ts +17 -24
  121. package/scripts/backlog/backlog-defect-priority.ts +1 -1
  122. package/scripts/backlog/backlog-drive-args.ts +5 -4
  123. package/scripts/backlog/backlog-drive-cli.ts +14 -10
  124. package/scripts/backlog/backlog-drive-epic.ts +85 -0
  125. package/scripts/backlog/backlog-drive-launch.ts +1 -1
  126. package/scripts/backlog/backlog-drive-named-offer.ts +60 -9
  127. package/scripts/backlog/backlog-drive-named.ts +39 -9
  128. package/scripts/backlog/backlog-drive-offer-argv.ts +1 -1
  129. package/scripts/backlog/backlog-drive-restore.ts +1 -1
  130. package/scripts/backlog/backlog-drive-retrospective.ts +2 -2
  131. package/scripts/backlog/backlog-drive.ts +43 -28
  132. package/scripts/backlog/backlog-idle.ts +88 -0
  133. package/scripts/backlog/backlog-named.ts +11 -15
  134. package/scripts/backlog/backlog-next.ts +26 -30
  135. package/scripts/backlog/backlog-offer-cli.ts +28 -23
  136. package/scripts/backlog/backlog-offer.ts +7 -7
  137. package/scripts/backlog/backlog-overlap.ts +178 -0
  138. package/scripts/backlog/backlog-plan-cli.ts +14 -90
  139. package/scripts/backlog/backlog-plan-read.ts +111 -0
  140. package/scripts/backlog/backlog-plan.ts +11 -10
  141. package/scripts/backlog/backlog-pool.ts +13 -14
  142. package/scripts/backlog/backlog-rank.ts +11 -11
  143. package/scripts/backlog/backlog-ready.ts +15 -10
  144. package/scripts/backlog/backlog-scope.ts +14 -15
  145. package/scripts/backlog/backlog-stalled-cli.ts +2 -2
  146. package/scripts/backlog/backlog-stalled-detect.ts +4 -4
  147. package/scripts/backlog/backlog-stalled.ts +5 -6
  148. package/scripts/backlog/backlog-waves.ts +4 -4
  149. package/scripts/backlog/backlogrun-args.ts +74 -0
  150. package/scripts/backlog/backlogrun-cli.ts +113 -0
  151. package/scripts/backlog/backlogrun-launch.ts +178 -0
  152. package/scripts/behavior/behavior-assertion.ts +6 -8
  153. package/scripts/behavior/behavior-cli.ts +1 -1
  154. package/scripts/behavior/behavior-rules.ts +3 -3
  155. package/scripts/build/build-claude-md.ts +4 -4
  156. package/scripts/build/build-codex-hooks.ts +2 -2
  157. package/scripts/build/build-commands.ts +1 -1
  158. package/scripts/build/build-hooks.ts +5 -5
  159. package/scripts/build/build.ts +1 -1
  160. package/scripts/build/hook-bundle-stamp.ts +109 -7
  161. package/scripts/build/local-bin.ts +2 -2
  162. package/scripts/cases/cases-cli.ts +1 -1
  163. package/scripts/cases/cases-logic.ts +2 -2
  164. package/scripts/ci/composite-actions.ts +1 -2
  165. package/scripts/ci/pr-classification.ts +2 -2
  166. package/scripts/claude/workflow-destination.ts +1 -1
  167. package/scripts/clone/clone-aggregate.ts +1 -1
  168. package/scripts/clone/clone-fingerprint.ts +1 -1
  169. package/scripts/clone/clone-scan-cli.ts +1 -1
  170. package/scripts/clone/clone-scan.ts +1 -1
  171. package/scripts/config-merge/index.ts +1 -1
  172. package/scripts/config-merge/json-format.ts +1 -3
  173. package/scripts/config-merge/patch-json-array.ts +90 -0
  174. package/scripts/config-merge/patch-json-key.ts +6 -3
  175. package/scripts/config-merge/patch-json-list.ts +1 -1
  176. package/scripts/cost-runtime/codex-usage.ts +1 -1
  177. package/scripts/cost-runtime/context-cut-payback.ts +4 -5
  178. package/scripts/cost-runtime/context-cut-threshold.ts +4 -6
  179. package/scripts/cost-runtime/cost-attribute.ts +3 -3
  180. package/scripts/cost-runtime/cost-blocks.ts +3 -4
  181. package/scripts/cost-runtime/cost-cli.ts +14 -11
  182. package/scripts/cost-runtime/cost-corpus.ts +11 -11
  183. package/scripts/cost-runtime/cost-pricing.ts +4 -4
  184. package/scripts/cost-runtime/cost-tokens.ts +1 -2
  185. package/scripts/cost-runtime/cost-transcript.ts +29 -29
  186. package/scripts/cost-runtime/cost-usage.ts +6 -7
  187. package/scripts/cost-runtime/cost-verdict.ts +10 -11
  188. package/scripts/cost-runtime/own-session.ts +1 -1
  189. package/scripts/cost-runtime/transcript-cwd.ts +2 -2
  190. package/scripts/delegation/delegation-cli.ts +4 -4
  191. package/scripts/delegation/delegation-policy.ts +13 -15
  192. package/scripts/delegation/duplicate-read-guard.ts +9 -10
  193. package/scripts/delegation/fanout-cli.ts +1 -1
  194. package/scripts/delegation/fanout.ts +1 -1
  195. package/scripts/delegation/investigation-guard.ts +18 -22
  196. package/scripts/delegation/investigation-reads.ts +48 -238
  197. package/scripts/discovery/repo-discovery.ts +1 -1
  198. package/scripts/discovery/repo-map-logic.ts +1 -2
  199. package/scripts/discovery/repo-origin.ts +3 -3
  200. package/scripts/discovery/repo-party-cli.ts +2 -2
  201. package/scripts/discovery/repo-party.ts +2 -2
  202. package/scripts/doctor/doctor-consumer.ts +1 -1
  203. package/scripts/doctor/doctor-io.ts +6 -7
  204. package/scripts/doctor/doctor-logic.ts +1 -1
  205. package/scripts/doctor/doctor-ports.ts +1 -1
  206. package/scripts/doctor/doctor.ts +8 -9
  207. package/scripts/document/backlogrun-parent-read-set.ts +5 -6
  208. package/scripts/document/bash-output-cap.ts +5 -7
  209. package/scripts/document/capped-print-part.ts +1 -1
  210. package/scripts/document/capped-print.ts +1 -1
  211. package/scripts/document/document-byte-budget.ts +33 -64
  212. package/scripts/document/document-byte-check.ts +4 -4
  213. package/scripts/document/document-reachability.ts +7 -8
  214. package/scripts/document/document-read-cli.ts +2 -2
  215. package/scripts/document/document-scan.ts +26 -2
  216. package/scripts/document/document-section-cli.ts +6 -8
  217. package/scripts/document/document-section.ts +8 -12
  218. package/scripts/document/edit-files-cli.ts +3 -4
  219. package/scripts/document/entry-read-budget.ts +8 -70
  220. package/scripts/document/entry-read-set.ts +51 -34
  221. package/scripts/document/lane-child-read-set.ts +9 -9
  222. package/scripts/document/read-files-cli.ts +1 -2
  223. package/scripts/document/read-set-cli.ts +16 -19
  224. package/scripts/document/read-set-cost.ts +4 -4
  225. package/scripts/document/read-set-point-of-use.ts +28 -38
  226. package/scripts/document/read-set-pricing.ts +1 -1
  227. package/scripts/document/read-set-trim.ts +3 -3
  228. package/scripts/document/resident-budget.ts +8 -10
  229. package/scripts/epic/epic-add-body.ts +15 -18
  230. package/scripts/epic/epic-add-plan.ts +26 -28
  231. package/scripts/epic/epic-add.ts +32 -25
  232. package/scripts/epic/epic-audit-checks.ts +27 -37
  233. package/scripts/epic/epic-audit-cli.ts +21 -22
  234. package/scripts/epic/epic-audit-orphans.ts +16 -17
  235. package/scripts/epic/epic-audit-rationale.ts +10 -15
  236. package/scripts/epic/epic-audit-report.ts +2 -5
  237. package/scripts/epic/epic-audit.ts +18 -14
  238. package/scripts/epic/epic-body.ts +10 -10
  239. package/scripts/epic/epic-bundle-cli.ts +36 -34
  240. package/scripts/epic/epic-bundle-evidence.ts +5 -5
  241. package/scripts/epic/epic-bundle-gaps.ts +6 -9
  242. package/scripts/epic/epic-bundle-poll.ts +1 -1
  243. package/scripts/epic/epic-bundle-referenced.ts +11 -14
  244. package/scripts/epic/epic-bundle.ts +19 -20
  245. package/scripts/epic/epic-busy.ts +44 -21
  246. package/scripts/epic/epic-candidate-confirm.ts +15 -18
  247. package/scripts/epic/epic-chains.ts +18 -23
  248. package/scripts/epic/epic-classify.ts +11 -12
  249. package/scripts/epic/epic-cli-argv.ts +5 -6
  250. package/scripts/epic/epic-cli-remove.ts +9 -4
  251. package/scripts/epic/epic-cli.ts +38 -26
  252. package/scripts/epic/epic-close-comment.ts +14 -15
  253. package/scripts/epic/epic-close.ts +25 -29
  254. package/scripts/epic/epic-cross-repo.ts +18 -21
  255. package/scripts/epic/epic-decision.ts +14 -18
  256. package/scripts/epic/epic-fetch.ts +25 -31
  257. package/scripts/epic/epic-graph.ts +15 -17
  258. package/scripts/epic/epic-index.ts +14 -16
  259. package/scripts/epic/epic-issue.ts +9 -11
  260. package/scripts/epic/epic-label-age.ts +74 -0
  261. package/scripts/epic/epic-lane-offer.ts +35 -24
  262. package/scripts/epic/epic-nested.ts +1 -1
  263. package/scripts/epic/epic-next-read.ts +8 -8
  264. package/scripts/epic/epic-next-views.ts +12 -12
  265. package/scripts/epic/epic-next.ts +29 -33
  266. package/scripts/epic/epic-outside-blocker.ts +11 -10
  267. package/scripts/epic/epic-parse.ts +22 -24
  268. package/scripts/epic/epic-promote.ts +3 -2
  269. package/scripts/epic/epic-rank.ts +1 -1
  270. package/scripts/epic/epic-read.ts +10 -8
  271. package/scripts/epic/epic-reconcile.ts +8 -6
  272. package/scripts/epic/epic-reference.ts +5 -4
  273. package/scripts/epic/epic-relation-recheck.ts +10 -11
  274. package/scripts/epic/epic-relations.ts +9 -8
  275. package/scripts/epic/epic-remove-plan.ts +4 -5
  276. package/scripts/epic/epic-remove.ts +7 -5
  277. package/scripts/epic/epic-report.ts +18 -20
  278. package/scripts/epic/epic-run.ts +6 -5
  279. package/scripts/epic/epic-sections.ts +2 -2
  280. package/scripts/epic/epic-shape.ts +3 -3
  281. package/scripts/epic/epic-solo-stale.ts +3 -2
  282. package/scripts/epic/epic-solo.ts +8 -8
  283. package/scripts/epic/epic-triage.ts +5 -4
  284. package/scripts/epic/epic-validate.ts +8 -7
  285. package/scripts/epic/epic.ts +5 -5
  286. package/scripts/exports/unused-members-cli.ts +1 -1
  287. package/scripts/followup/followup-issue-number.ts +1 -2
  288. package/scripts/followup/git-followup-cleanup.ts +6 -7
  289. package/scripts/followup/git-followup-finish.ts +11 -13
  290. package/scripts/followup/git-followup-flush.ts +11 -7
  291. package/scripts/followup/git-followup-issue-close.ts +16 -13
  292. package/scripts/followup/git-followup-label.ts +9 -6
  293. package/scripts/followup/git-followup-merged.ts +1 -1
  294. package/scripts/followup/git-followup-pending.ts +7 -9
  295. package/scripts/followup/git-followup-stages.ts +28 -17
  296. package/scripts/followup/git-followup-workflow.ts +19 -21
  297. package/scripts/followup/git-pr-followup-checks.ts +13 -20
  298. package/scripts/followup/git-pr-followup-wrapup.ts +7 -7
  299. package/scripts/followup/git-pr-followup.ts +18 -17
  300. package/scripts/gate/core-admission.ts +162 -0
  301. package/scripts/gate/core-budget.ts +134 -91
  302. package/scripts/gate/gate-ledger.ts +114 -0
  303. package/scripts/gate/gate-log.ts +7 -9
  304. package/scripts/gate/gate-plan.ts +103 -35
  305. package/scripts/gate/gate-report.ts +39 -21
  306. package/scripts/gate/gate-skip.ts +11 -13
  307. package/scripts/gate/gate-steps.ts +5 -1
  308. package/scripts/gate/gate-tree.ts +3 -4
  309. package/scripts/gate/hook-gate-reuse.ts +9 -9
  310. package/scripts/gate/machine-capacity.ts +313 -0
  311. package/scripts/gate/pre-commit-type-check.ts +4 -4
  312. package/scripts/gate/project-checks.ts +12 -4
  313. package/scripts/gate/scoped-green.ts +11 -18
  314. package/scripts/gate/type-check-command.ts +2 -2
  315. package/scripts/gate/type-check-step.ts +4 -4
  316. package/scripts/gate/verification-gate.ts +60 -53
  317. package/scripts/gh/gh-spawn.ts +2 -2
  318. package/scripts/gh/git-ai-review-scan.ts +3 -2
  319. package/scripts/gh/git-gh-api-path.ts +10 -11
  320. package/scripts/gh/git-gh-exec.ts +43 -48
  321. package/scripts/gh/git-gh-failure.ts +6 -9
  322. package/scripts/gh/git-gh-helpers.ts +1 -1
  323. package/scripts/gh/git-gh-issue-list.ts +15 -19
  324. package/scripts/gh/git-gh-issue-read.ts +43 -60
  325. package/scripts/gh/git-gh-issue-rest.ts +14 -15
  326. package/scripts/gh/git-gh-issue-write.ts +52 -40
  327. package/scripts/gh/git-gh-issue.ts +23 -24
  328. package/scripts/gh/git-gh-pr-auto-merge.ts +3 -3
  329. package/scripts/gh/git-gh-pr-read.ts +46 -50
  330. package/scripts/gh/git-gh-pr-rest.ts +23 -26
  331. package/scripts/gh/git-gh-pr-review.ts +2 -2
  332. package/scripts/gh/git-gh-pr-rollup.ts +4 -4
  333. package/scripts/gh/git-gh-pr-snapshot.ts +8 -10
  334. package/scripts/gh/git-gh-pr.ts +16 -16
  335. package/scripts/gh/git-gh-reachability.ts +11 -12
  336. package/scripts/gh/git-gh-repo.ts +2 -3
  337. package/scripts/gh/git-gh-rest-state.ts +1 -1
  338. package/scripts/gh/git-pr-ai-review.ts +6 -5
  339. package/scripts/gh/git-pr-checks-eval.ts +28 -30
  340. package/scripts/gh/git-pr-checks-parse.ts +14 -16
  341. package/scripts/gh/git-pr-checks-watch.ts +17 -17
  342. package/scripts/gh/git-pr-checks.ts +20 -23
  343. package/scripts/gh/git-pr-coderabbit.ts +8 -6
  344. package/scripts/gh/git-pr-confirmation.ts +5 -5
  345. package/scripts/gh/git-pr-managed-config.ts +7 -9
  346. package/scripts/gh/git-pr-messages.ts +1 -1
  347. package/scripts/gh/git-pr.ts +15 -16
  348. package/scripts/gh/github-issue-url.ts +8 -9
  349. package/scripts/git/base-tree.ts +66 -0
  350. package/scripts/git/change-base.ts +42 -2
  351. package/scripts/git/changed-file-scope.ts +5 -5
  352. package/scripts/git/changed-paths.ts +1 -2
  353. package/scripts/git/constants.ts +2 -2
  354. package/scripts/git/git-branch.ts +1 -1
  355. package/scripts/git/git-closes-keyword.ts +3 -3
  356. package/scripts/git/git-command.ts +53 -41
  357. package/scripts/git/git-common-directory.ts +3 -3
  358. package/scripts/git/git-diff-reads.ts +14 -15
  359. package/scripts/git/git-error.ts +1 -1
  360. package/scripts/git/git-execa-error.ts +1 -2
  361. package/scripts/git/git-issue.ts +10 -8
  362. package/scripts/git/git-location-environment.ts +3 -4
  363. package/scripts/git/git-ls-remote.ts +6 -8
  364. package/scripts/git/git-pre-push-hook.ts +11 -10
  365. package/scripts/git/git-preflight.ts +5 -5
  366. package/scripts/git/git-push-transport.ts +2 -2
  367. package/scripts/git/git-remote-branch.ts +1 -2
  368. package/scripts/git/git-schemas.ts +16 -23
  369. package/scripts/git/git-spawn-sync.ts +1 -1
  370. package/scripts/git/git-spawn.ts +37 -14
  371. package/scripts/git/git-ssh-keepalive.ts +12 -5
  372. package/scripts/git/git-staging.ts +7 -8
  373. package/scripts/git/git-workflow.ts +1 -1
  374. package/scripts/git/git-worktree.ts +35 -27
  375. package/scripts/git/gone-branch.ts +2 -2
  376. package/scripts/git/listing-cutoff.ts +1 -2
  377. package/scripts/git/lockfile-sync.ts +65 -0
  378. package/scripts/git/main-merge-guard.ts +1 -2
  379. package/scripts/git/main-merge.ts +7 -7
  380. package/scripts/git/main-sync.ts +23 -8
  381. package/scripts/git/parse-json-array.ts +18 -23
  382. package/scripts/git/repository-lock.ts +34 -2
  383. package/scripts/git/stash/git-stash.ts +4 -5
  384. package/scripts/git/stash/stash-orphans.ts +5 -3
  385. package/scripts/git/stash/stash-pop-args.ts +1 -1
  386. package/scripts/git/stash/stash-pop-cli.ts +3 -3
  387. package/scripts/git/stash/stash-sweep-lock.ts +2 -2
  388. package/scripts/hooks/batch-guard.ts +11 -13
  389. package/scripts/hooks/check-commit-message.ts +12 -9
  390. package/scripts/hooks/codex-hook-adapter.ts +16 -10
  391. package/scripts/hooks/edited-cspell.ts +3 -4
  392. package/scripts/hooks/format-edited-cli.ts +1 -1
  393. package/scripts/hooks/format-edited-file.ts +11 -17
  394. package/scripts/hooks/format-rewrite-notice.ts +19 -17
  395. package/scripts/hooks/pre-push-unit.ts +10 -14
  396. package/scripts/hooks/pretool-guard-cli.ts +4 -4
  397. package/scripts/hooks/pretool-guard.ts +93 -18
  398. package/scripts/hooks/reserved-run.ts +2 -2
  399. package/scripts/hooks/step-zero-notice.ts +1 -1
  400. package/scripts/hooks/stop-guard.ts +21 -10
  401. package/scripts/init/basic-path-migration.ts +2 -2
  402. package/scripts/init/claude-kit-only-settings.ts +2 -2
  403. package/scripts/init/claude-plugin-config.ts +2 -2
  404. package/scripts/init/distributed-paths.ts +4 -4
  405. package/scripts/init/hook-command-rewrite.ts +3 -3
  406. package/scripts/init/hook-launch.ts +5 -5
  407. package/scripts/init/init-actions.ts +13 -0
  408. package/scripts/init/init-ai-copy.ts +11 -11
  409. package/scripts/init/init-bootstrap.ts +3 -3
  410. package/scripts/init/init-copy-content.ts +4 -4
  411. package/scripts/init/init-logic-json-merge.ts +7 -9
  412. package/scripts/init/init-logic-migrate.ts +1 -1
  413. package/scripts/init/init-logic-templates.ts +1 -1
  414. package/scripts/init/init-logic-workspace.ts +4 -4
  415. package/scripts/init/init-logic-yaml-merge.ts +2 -2
  416. package/scripts/init/init-logic.ts +19 -22
  417. package/scripts/init/init.ts +12 -8
  418. package/scripts/init/kit-base-preset.ts +1 -1
  419. package/scripts/init/kit-setup-state.ts +1 -1
  420. package/scripts/init/kit-written-paths.ts +1 -2
  421. package/scripts/init/package-manager-pin.ts +35 -0
  422. package/scripts/init/project-profile-cli.ts +1 -1
  423. package/scripts/init/project-profile.ts +3 -3
  424. package/scripts/init/session-language-environment.ts +1 -1
  425. package/scripts/init/start-exec.ts +3 -4
  426. package/scripts/init/start-plan.ts +2 -2
  427. package/scripts/init/start-setup-pr.ts +3 -2
  428. package/scripts/init/start-steps.ts +2 -2
  429. package/scripts/init/tsconfig-preset-migration.ts +1 -1
  430. package/scripts/init/vscode-tasks.ts +62 -0
  431. package/scripts/issue/baseline-measure.ts +2 -2
  432. package/scripts/issue/behavior-change-lint.ts +2 -2
  433. package/scripts/issue/defect-rate-cli.ts +6 -7
  434. package/scripts/issue/defect-rate.ts +37 -27
  435. package/scripts/issue/git-next-issues.ts +9 -8
  436. package/scripts/issue/issue-auto-ok.ts +49 -11
  437. package/scripts/issue/issue-backlinks-cli.ts +5 -5
  438. package/scripts/issue/issue-backlinks.ts +6 -6
  439. package/scripts/issue/issue-cite-cli.ts +20 -18
  440. package/scripts/issue/issue-cite.ts +18 -8
  441. package/scripts/issue/issue-closing-pr.ts +4 -4
  442. package/scripts/issue/issue-comment-cli.ts +6 -4
  443. package/scripts/issue/issue-file-cli.ts +75 -15
  444. package/scripts/issue/issue-file-fold.ts +155 -0
  445. package/scripts/issue/issue-file.ts +14 -6
  446. package/scripts/issue/issue-fold-cli.ts +14 -9
  447. package/scripts/issue/issue-fold.ts +23 -8
  448. package/scripts/issue/issue-labels.ts +46 -37
  449. package/scripts/issue/issue-lint-cli.ts +2 -2
  450. package/scripts/issue/issue-lint.ts +1 -1
  451. package/scripts/issue/issue-merged.ts +10 -4
  452. package/scripts/issue/issue-number-shape.ts +27 -0
  453. package/scripts/issue/issue-rank.ts +1 -1
  454. package/scripts/issue/issue-read-cli.ts +4 -5
  455. package/scripts/issue/issue-read.ts +4 -5
  456. package/scripts/issue/issue-reference.ts +5 -5
  457. package/scripts/issue/issue-release-cli.ts +165 -0
  458. package/scripts/issue/issue-release.ts +58 -0
  459. package/scripts/issue/issue-report-failures.ts +7 -4
  460. package/scripts/issue/issue-scout-cli.ts +11 -11
  461. package/scripts/issue/issue-scout-closed.ts +4 -4
  462. package/scripts/issue/issue-scout.ts +4 -5
  463. package/scripts/issue/issue-state-cli.ts +17 -10
  464. package/scripts/issue/issue-state.ts +12 -13
  465. package/scripts/issue/issue-wip.ts +7 -7
  466. package/scripts/issue/markdown-section.ts +3 -3
  467. package/scripts/issue/measure-rerun-cli.ts +10 -9
  468. package/scripts/issue/reproduction-measure.ts +3 -3
  469. package/scripts/issue/session-cite.ts +56 -0
  470. package/scripts/josh/agent-session-environment.ts +10 -8
  471. package/scripts/josh/cli-body.ts +2 -2
  472. package/scripts/josh/command-suggest.ts +1 -1
  473. package/scripts/josh/file-map-stamp.ts +20 -23
  474. package/scripts/josh/hook-decision.ts +24 -28
  475. package/scripts/josh/josh-command-map.ts +4 -1
  476. package/scripts/josh/josh-command-types.ts +32 -34
  477. package/scripts/josh/josh-commands-ai.ts +6 -6
  478. package/scripts/josh/josh-commands-backlog.ts +15 -3
  479. package/scripts/josh/josh-commands-clone.ts +1 -1
  480. package/scripts/josh/josh-commands-development.ts +33 -4
  481. package/scripts/josh/josh-commands-document.ts +3 -3
  482. package/scripts/josh/josh-commands-guard.ts +3 -3
  483. package/scripts/josh/josh-commands-issue.ts +11 -5
  484. package/scripts/josh/josh-commands-lane.ts +16 -5
  485. package/scripts/josh/josh-commands-lint.ts +1 -1
  486. package/scripts/josh/josh-commands-maintenance.ts +2 -2
  487. package/scripts/josh/josh-commands-run.ts +20 -6
  488. package/scripts/josh/josh-commands-split.ts +1 -2
  489. package/scripts/josh/josh-commands-versioning.ts +5 -5
  490. package/scripts/josh/josh-commands-workflow.ts +30 -22
  491. package/scripts/josh/josh-environment-file.ts +1 -1
  492. package/scripts/josh/josh-in-process.ts +3 -3
  493. package/scripts/josh/josh-logic.ts +10 -10
  494. package/scripts/josh/josh-run.ts +3 -3
  495. package/scripts/josh/josh-verdict.ts +9 -12
  496. package/scripts/josh/josh.ts +3 -3
  497. package/scripts/josh/kit-only.ts +2 -2
  498. package/scripts/josh/path-decision.ts +3 -3
  499. package/scripts/josh/platform-temporary.ts +7 -5
  500. package/scripts/josh/process-identity.ts +24 -6
  501. package/scripts/josh/process-owner.ts +4 -4
  502. package/scripts/josh/session-language-cli.ts +53 -11
  503. package/scripts/josh/session-language.ts +1 -1
  504. package/scripts/josh/stamp-file.ts +48 -29
  505. package/scripts/josh/stamp-record.ts +57 -0
  506. package/scripts/lane/lane-await.ts +35 -11
  507. package/scripts/lane/lane-cache.ts +6 -6
  508. package/scripts/lane/lane-capacity.ts +32 -17
  509. package/scripts/lane/lane-child-invocation.ts +17 -15
  510. package/scripts/lane/lane-child-marker.ts +12 -12
  511. package/scripts/lane/lane-cli.ts +20 -13
  512. package/scripts/lane/lane-close.ts +6 -6
  513. package/scripts/lane/lane-dispatch.ts +61 -72
  514. package/scripts/lane/lane-environment.ts +5 -5
  515. package/scripts/lane/lane-guard-policy.ts +7 -21
  516. package/scripts/lane/lane-handoff.ts +2 -2
  517. package/scripts/lane/lane-install.ts +9 -10
  518. package/scripts/lane/lane-launch-cli.ts +13 -8
  519. package/scripts/lane/lane-ledger.ts +73 -11
  520. package/scripts/lane/lane-leftover.ts +44 -30
  521. package/scripts/lane/lane-limit-cli.ts +160 -0
  522. package/scripts/lane/lane-limit-override.ts +74 -0
  523. package/scripts/lane/lane-load.ts +19 -68
  524. package/scripts/lane/lane-measure-cli.ts +15 -25
  525. package/scripts/lane/lane-occupancy.ts +6 -4
  526. package/scripts/lane/lane-open.ts +25 -24
  527. package/scripts/lane/lane-output.ts +4 -3
  528. package/scripts/lane/lane-paths.ts +22 -8
  529. package/scripts/lane/lane-phase.ts +33 -0
  530. package/scripts/lane/lane-reap.ts +2 -2
  531. package/scripts/lane/lane-registry.ts +27 -15
  532. package/scripts/lane/lane-relaunch.ts +9 -9
  533. package/scripts/lane/lane-report.ts +5 -4
  534. package/scripts/lane/lane-resume.ts +2 -2
  535. package/scripts/lane/lane-sampler.ts +55 -0
  536. package/scripts/lane/lane-seed.ts +7 -7
  537. package/scripts/lane/lane-stage-stats.ts +135 -0
  538. package/scripts/lane/lane-start-point.ts +8 -11
  539. package/scripts/lane/lane-stats.ts +60 -15
  540. package/scripts/lane/lane-stray.ts +140 -0
  541. package/scripts/lane/lane-vacant.ts +1 -1
  542. package/scripts/lane/openai-lane-supervisor-decision.ts +3 -7
  543. package/scripts/lane/openai-lane-supervisor-owner.ts +3 -9
  544. package/scripts/lane/openai-review-broker.ts +2 -4
  545. package/scripts/lib/ancestor-directories.ts +1 -1
  546. package/scripts/lib/bounded-pool.ts +2 -2
  547. package/scripts/lib/buffered-process.ts +4 -6
  548. package/scripts/lib/caddy-logs.sh +0 -0
  549. package/scripts/lib/cli-flags.ts +39 -6
  550. package/scripts/lib/error-message.ts +1 -1
  551. package/scripts/lib/json-value.ts +17 -3
  552. package/scripts/lib/poll.ts +1 -1
  553. package/scripts/lib/status-icons.ts +3 -3
  554. package/scripts/lib/timed-fetch.ts +1 -1
  555. package/scripts/lib/timeouts.ts +1 -1
  556. package/scripts/lines/bytes-command.ts +3 -4
  557. package/scripts/lines/effective-limit.ts +25 -12
  558. package/scripts/lines/line-budget.ts +47 -55
  559. package/scripts/lines/line-targets.ts +6 -2
  560. package/scripts/lines/lines-command.ts +3 -3
  561. package/scripts/lint/cspell-cached.ts +1 -1
  562. package/scripts/lint/cycle-recheck.ts +122 -0
  563. package/scripts/lint/format.ts +1 -2
  564. package/scripts/lint/lint-parallel.ts +34 -19
  565. package/scripts/lint/lint-related-scope.ts +25 -15
  566. package/scripts/lint/lint-related.ts +6 -7
  567. package/scripts/managed-marker/index.ts +1 -1
  568. package/scripts/managed-marker/managed-marker-logic.ts +1 -2
  569. package/scripts/notify/git-notify.ts +9 -7
  570. package/scripts/notify/telegram-notify.ts +53 -37
  571. package/scripts/notify/telegram-test-logic.ts +3 -3
  572. package/scripts/notify/telegram-test.ts +45 -30
  573. package/scripts/observations/observation-ledger-home.ts +14 -8
  574. package/scripts/observations/observation-ledger-line.ts +3 -2
  575. package/scripts/observations/observation-ledger-migrate.ts +3 -4
  576. package/scripts/observations/observation-ledger-prepare.ts +4 -4
  577. package/scripts/observations/observation-ledger.ts +14 -15
  578. package/scripts/observations/observation-record-cli.ts +83 -0
  579. package/scripts/observations/observation-record.ts +91 -0
  580. package/scripts/observations/observations-flush-cli.ts +1 -1
  581. package/scripts/observations/observations-flush-landing.ts +7 -6
  582. package/scripts/observations/observations-flush.ts +26 -27
  583. package/scripts/overrides/overrides-check.ts +18 -8
  584. package/scripts/package/package-scout-cli.ts +1 -1
  585. package/scripts/package/package-scout-format.ts +2 -2
  586. package/scripts/package/package-scout.ts +1 -1
  587. package/scripts/propagate/propagate-git-failure.ts +1 -1
  588. package/scripts/propagate/propagate-git.ts +7 -7
  589. package/scripts/propagate/propagate-plan.ts +2 -2
  590. package/scripts/propagate/propagate-publish.ts +2 -3
  591. package/scripts/propagate/propagate-run.ts +5 -7
  592. package/scripts/propagate/propagate-select.ts +1 -1
  593. package/scripts/propagate/propagate-steps.ts +19 -20
  594. package/scripts/propagate/propagate-targets.ts +6 -10
  595. package/scripts/propagate/propagate.ts +5 -5
  596. package/scripts/refactor/import-graph.ts +1 -1
  597. package/scripts/refactor/refactor-lint.ts +4 -10
  598. package/scripts/refactor/refactor-scan-cli.ts +1 -1
  599. package/scripts/refactor/refactor-scan.ts +2 -2
  600. package/scripts/refactor/refactor-targets.ts +1 -1
  601. package/scripts/release/github-release-cli.ts +25 -3
  602. package/scripts/release/github-release-environment.ts +1 -0
  603. package/scripts/release/github-release-runs.ts +115 -0
  604. package/scripts/release/github-release.ts +13 -67
  605. package/scripts/release/release-cli.ts +21 -4
  606. package/scripts/release/release-history.ts +6 -10
  607. package/scripts/release/release-plan.ts +3 -3
  608. package/scripts/release/release-progress.ts +3 -4
  609. package/scripts/release/release-publish.ts +8 -9
  610. package/scripts/release/release-scope-cli.ts +8 -10
  611. package/scripts/release/release-tag.ts +6 -8
  612. package/scripts/release/release-worktree.ts +5 -5
  613. package/scripts/repo/auto-merge-setting-logic.ts +7 -9
  614. package/scripts/repo/auto-merge-setting.ts +1 -1
  615. package/scripts/repo/repo-setting.ts +4 -4
  616. package/scripts/repo/repository-labels.ts +1 -1
  617. package/scripts/repo/required-checks-logic.ts +3 -3
  618. package/scripts/repo/required-checks-report.ts +1 -1
  619. package/scripts/repo/ruleset-check-cli.ts +1 -1
  620. package/scripts/repo/ruleset-check.ts +1 -1
  621. package/scripts/report/report-format-reference.ts +26 -0
  622. package/scripts/report/report-lint-cli.ts +2 -2
  623. package/scripts/report/report-lint.ts +16 -2
  624. package/scripts/review/disposition-cli.ts +2 -2
  625. package/scripts/review/disposition-logic.ts +1 -1
  626. package/scripts/review/live-evidence.ts +9 -6
  627. package/scripts/review/review-attest-cli.ts +1 -2
  628. package/scripts/review/review-attest.ts +3 -3
  629. package/scripts/review/review-brief-cli.ts +19 -20
  630. package/scripts/review/review-brief.ts +29 -32
  631. package/scripts/review/review-checkout.ts +2 -2
  632. package/scripts/review/review-diff-parts.ts +3 -5
  633. package/scripts/review/review-diff-write.ts +1 -1
  634. package/scripts/review/review-finding-ledger.ts +7 -4
  635. package/scripts/review/review-findings-cli.ts +2 -2
  636. package/scripts/review/review-level.ts +4 -7
  637. package/scripts/review/review-record-cli.ts +73 -16
  638. package/scripts/review/review-record.ts +5 -4
  639. package/scripts/review/review-round2-cli.ts +2 -3
  640. package/scripts/review/review-round2.ts +13 -21
  641. package/scripts/review/review-stamps.ts +9 -71
  642. package/scripts/review/review-tree.ts +4 -5
  643. package/scripts/rules/bash-triggers.ts +4 -4
  644. package/scripts/rules/decision-oracle-batch.ts +5 -6
  645. package/scripts/rules/decision-oracle-stage.ts +1 -1
  646. package/scripts/rules/decision-oracle-tokens.ts +1 -2
  647. package/scripts/rules/decision-oracle.ts +2 -2
  648. package/scripts/rules/delivered-rules.ts +61 -406
  649. package/scripts/rules/destructive-command.ts +2 -2
  650. package/scripts/rules/direct-filing.ts +4 -4
  651. package/scripts/rules/direct-pr-create.ts +2 -2
  652. package/scripts/rules/early-heartbeat.ts +15 -19
  653. package/scripts/rules/file-body.ts +5 -6
  654. package/scripts/rules/filing-cap.ts +6 -7
  655. package/scripts/rules/filing-offer.ts +1 -1
  656. package/scripts/rules/firing-point.ts +6 -6
  657. package/scripts/rules/gh-api.ts +2 -2
  658. package/scripts/rules/git-argv.ts +3 -3
  659. package/scripts/rules/git-force.ts +2 -2
  660. package/scripts/rules/hook-context-line.ts +31 -0
  661. package/scripts/rules/implementation-cut-verdict.ts +5 -8
  662. package/scripts/rules/implementation-cut.ts +35 -32
  663. package/scripts/rules/index-guard.ts +2 -2
  664. package/scripts/rules/issue-citation.ts +7 -7
  665. package/scripts/rules/issue-comments.ts +21 -13
  666. package/scripts/rules/josh-git-bare.ts +2 -2
  667. package/scripts/rules/lane-background.ts +14 -16
  668. package/scripts/rules/lane-carry-conflict.ts +41 -5
  669. package/scripts/rules/lane-interactive-ask.ts +6 -9
  670. package/scripts/rules/lane-park.ts +12 -16
  671. package/scripts/rules/lane-split-park.ts +1 -2
  672. package/scripts/rules/lane-switch-main.ts +10 -13
  673. package/scripts/rules/last-prompt.ts +1 -1
  674. package/scripts/rules/oracle-consulted.ts +5 -5
  675. package/scripts/rules/oracle-firing.ts +6 -9
  676. package/scripts/rules/oracle-list-cli.ts +2 -2
  677. package/scripts/rules/permission-guards.ts +2 -2
  678. package/scripts/rules/piped-verification.ts +79 -9
  679. package/scripts/rules/poll-loop.ts +9 -11
  680. package/scripts/rules/pre-gate-cut.ts +33 -30
  681. package/scripts/rules/prior-comment-read.ts +3 -3
  682. package/scripts/rules/protected-files.ts +25 -13
  683. package/scripts/rules/raw-field-body.ts +3 -4
  684. package/scripts/rules/reply-language.ts +1 -1
  685. package/scripts/rules/rule-body-guard.ts +10 -12
  686. package/scripts/rules/rule-guard.ts +1 -1
  687. package/scripts/rules/rule-list.ts +51 -0
  688. package/scripts/rules/rule-registry-rows.ts +282 -0
  689. package/scripts/rules/rule-registry.ts +109 -0
  690. package/scripts/rules/rule-value-cache.ts +2 -2
  691. package/scripts/rules/rule-value-cli.ts +6 -4
  692. package/scripts/rules/rule-value.ts +61 -22
  693. package/scripts/rules/run-tail-rule.ts +11 -15
  694. package/scripts/rules/shell-body-trigger.ts +7 -7
  695. package/scripts/rules/shell-segments.ts +2 -4
  696. package/scripts/rules/stop-rules.ts +54 -41
  697. package/scripts/rules/tail-commands.ts +1 -1
  698. package/scripts/rules/test-declared-commit.ts +2 -2
  699. package/scripts/rules/third-party-write.ts +3 -3
  700. package/scripts/rules/worktree-guard.ts +12 -5
  701. package/scripts/run/add/run-add-cli.ts +165 -0
  702. package/scripts/run/add/run-add.ts +124 -0
  703. package/scripts/run/board/run-board-cli.ts +207 -0
  704. package/scripts/run/board/run-board-closed.ts +95 -0
  705. package/scripts/run/board/run-board-every.ts +60 -0
  706. package/scripts/run/board/run-board-fetch.ts +38 -0
  707. package/scripts/run/board/run-board-fit.ts +219 -0
  708. package/scripts/run/board/run-board-github.ts +162 -0
  709. package/scripts/run/board/run-board-header.ts +275 -0
  710. package/scripts/run/board/run-board-kind.ts +35 -0
  711. package/scripts/run/board/run-board-labels.ts +299 -0
  712. package/scripts/run/board/run-board-layout.ts +222 -0
  713. package/scripts/run/board/run-board-link.ts +31 -0
  714. package/scripts/run/board/run-board-machine.ts +198 -0
  715. package/scripts/run/board/run-board-notes.ts +103 -0
  716. package/scripts/run/board/run-board-phase.ts +136 -0
  717. package/scripts/run/board/run-board-plan.ts +129 -0
  718. package/scripts/run/board/run-board-read.ts +62 -0
  719. package/scripts/run/board/run-board-render-legend.ts +82 -0
  720. package/scripts/run/board/run-board-render-notes.ts +77 -0
  721. package/scripts/run/board/run-board-render-slot.ts +50 -0
  722. package/scripts/run/board/run-board-render.ts +407 -0
  723. package/scripts/run/board/run-board-scope.ts +17 -0
  724. package/scripts/run/board/run-board-screen.ts +43 -0
  725. package/scripts/run/board/run-board-span.ts +66 -0
  726. package/scripts/run/board/run-board-spin.ts +115 -0
  727. package/scripts/run/board/run-board-state.ts +113 -0
  728. package/scripts/run/board/run-board-status.ts +279 -0
  729. package/scripts/run/board/run-board-tick.ts +210 -0
  730. package/scripts/run/board/run-board-track.ts +22 -0
  731. package/scripts/run/board/run-board-usage-read.ts +255 -0
  732. package/scripts/run/board/run-board-usage-rusage.ts +124 -0
  733. package/scripts/run/board/run-board-usage-text.ts +80 -0
  734. package/scripts/run/board/run-board-usage.ts +165 -0
  735. package/scripts/run/carry/run-carry-added.ts +62 -0
  736. package/scripts/run/carry/run-carry-args.ts +25 -22
  737. package/scripts/run/carry/run-carry-change.ts +1 -1
  738. package/scripts/run/carry/run-carry-cli.ts +71 -48
  739. package/scripts/run/carry/run-carry-conversation.ts +6 -7
  740. package/scripts/run/carry/run-carry-ended.ts +85 -0
  741. package/scripts/run/carry/run-carry-reclaim.ts +1 -1
  742. package/scripts/run/carry/run-carry-stash.ts +3 -2
  743. package/scripts/run/carry/run-carry-streak.ts +8 -10
  744. package/scripts/run/carry/run-carry.ts +85 -89
  745. package/scripts/run/cut/run-cut-args.ts +7 -7
  746. package/scripts/run/cut/run-cut-cli.ts +68 -37
  747. package/scripts/run/cut/run-cut-handoff.ts +15 -15
  748. package/scripts/run/cut/run-cut-report.ts +37 -16
  749. package/scripts/run/cut/run-cut.ts +63 -77
  750. package/scripts/run/detached-launch.ts +35 -50
  751. package/scripts/run/entry/run-entry-cli.ts +48 -27
  752. package/scripts/run/entry/run-entry-stop.ts +7 -9
  753. package/scripts/run/entry/run-entry.ts +5 -6
  754. package/scripts/run/event/run-event-cli.ts +5 -6
  755. package/scripts/run/event/run-event-filed.ts +69 -0
  756. package/scripts/run/event/run-event-follow.ts +3 -3
  757. package/scripts/run/event/run-event-plan.ts +38 -0
  758. package/scripts/run/event/run-event-render.ts +10 -4
  759. package/scripts/run/event/run-event-scope.ts +47 -18
  760. package/scripts/run/event/run-event-stream-emit.ts +64 -11
  761. package/scripts/run/event/run-event-stream.ts +172 -43
  762. package/scripts/run/event/run-event-watch.ts +4 -6
  763. package/scripts/run/hold/run-hold-cli.ts +65 -62
  764. package/scripts/run/hold/run-hold.ts +88 -46
  765. package/scripts/run/merge/run-merge-cli.ts +116 -77
  766. package/scripts/run/merge/run-merge-collect.ts +107 -0
  767. package/scripts/run/merge/run-merge-steps.ts +112 -65
  768. package/scripts/run/merge/run-merge-token.ts +30 -0
  769. package/scripts/run/merge/run-merge.ts +31 -22
  770. package/scripts/run/progress/run-progress-args.ts +4 -4
  771. package/scripts/run/progress/run-progress-cli.ts +39 -50
  772. package/scripts/run/progress/run-progress-clock.ts +25 -32
  773. package/scripts/run/progress/run-progress-config.ts +6 -9
  774. package/scripts/run/progress/run-progress-read.ts +9 -10
  775. package/scripts/run/progress/run-progress.ts +48 -53
  776. package/scripts/run/review/run-review-cli.ts +6 -6
  777. package/scripts/run/review/run-review-steps.ts +6 -6
  778. package/scripts/run/review/run-review.ts +9 -11
  779. package/scripts/run/run-cli-fault.ts +29 -0
  780. package/scripts/run/run-ending-cli.ts +3 -3
  781. package/scripts/run/run-ending.ts +10 -14
  782. package/scripts/run/run-halfrun-resume.ts +6 -8
  783. package/scripts/run/run-headless.ts +25 -12
  784. package/scripts/run/run-invocation.ts +17 -22
  785. package/scripts/run/run-label.ts +7 -5
  786. package/scripts/run/run-liveness-cli.ts +19 -6
  787. package/scripts/run/run-liveness.ts +27 -38
  788. package/scripts/run/run-next-cli.ts +5 -9
  789. package/scripts/run/run-next.ts +4 -5
  790. package/scripts/run/run-parent-cut-hook.ts +10 -12
  791. package/scripts/run/run-preflight.ts +25 -29
  792. package/scripts/run/run-prep-cli.ts +17 -13
  793. package/scripts/run/run-prep-locate.ts +4 -5
  794. package/scripts/run/run-prep.ts +7 -10
  795. package/scripts/run/run-prrun-resume.ts +2 -2
  796. package/scripts/run/run-report-cli.ts +4 -4
  797. package/scripts/run/run-report.ts +9 -14
  798. package/scripts/run/run-retrospective.ts +3 -3
  799. package/scripts/run/run-section.ts +42 -0
  800. package/scripts/run/run-stage-read.ts +2 -2
  801. package/scripts/run/run-stage.ts +6 -4
  802. package/scripts/run/run-status-cli.ts +7 -5
  803. package/scripts/run/run-status.ts +6 -7
  804. package/scripts/run/run-step-cli.ts +13 -15
  805. package/scripts/run/run-step.ts +62 -48
  806. package/scripts/run/run-stop-notify.ts +7 -8
  807. package/scripts/run/run-stranded-cli.ts +1 -1
  808. package/scripts/run/run-stranded-detect.ts +4 -4
  809. package/scripts/run/run-stranded.ts +11 -13
  810. package/scripts/run/run-tail-cli.ts +15 -16
  811. package/scripts/run/run-tail.ts +14 -33
  812. package/scripts/run/run-watcher-guard-cli.ts +3 -4
  813. package/scripts/run/run-watcher-guard.ts +11 -12
  814. package/scripts/run/run-watcher-hook.ts +6 -12
  815. package/scripts/run/ship/run-ship-cli.ts +67 -33
  816. package/scripts/run/ship/run-ship-detach.ts +15 -13
  817. package/scripts/run/ship/run-ship-lock.ts +1 -1
  818. package/scripts/run/ship/run-ship-next.ts +7 -8
  819. package/scripts/run/ship/run-ship-pre-detach.ts +27 -11
  820. package/scripts/run/ship/run-ship-preflight.ts +10 -11
  821. package/scripts/run/ship/run-ship-probe.ts +4 -4
  822. package/scripts/run/ship/run-ship-return.ts +1 -1
  823. package/scripts/run/ship/run-ship-review-steps.ts +43 -24
  824. package/scripts/run/ship/run-ship-review.ts +12 -14
  825. package/scripts/run/ship/run-ship-scoped.ts +15 -6
  826. package/scripts/run/ship/run-ship-stage.ts +80 -26
  827. package/scripts/run/ship/run-ship-steps.ts +26 -16
  828. package/scripts/run/ship/run-ship-stop-text.ts +4 -2
  829. package/scripts/run/ship/run-ship-sync.ts +9 -8
  830. package/scripts/run/ship/run-ship.ts +17 -32
  831. package/scripts/run/tidy/run-tidy-cli.ts +9 -5
  832. package/scripts/run/tidy/run-tidy-lanes.ts +18 -7
  833. package/scripts/run/tidy/run-tidy-stashes.ts +8 -8
  834. package/scripts/run/tidy/run-tidy.ts +4 -3
  835. package/scripts/run/wake/run-wake-cli.ts +27 -33
  836. package/scripts/run/wake/run-wake-describe.ts +76 -29
  837. package/scripts/run/wake/run-wake-driver.ts +14 -14
  838. package/scripts/run/wake/run-wake-handoff.ts +6 -6
  839. package/scripts/run/wake/run-wake-loop.ts +13 -21
  840. package/scripts/run/wake/run-wake-restart.ts +4 -5
  841. package/scripts/run/wake/run-wake-session.ts +23 -27
  842. package/scripts/run/wake/run-wake.ts +57 -328
  843. package/scripts/safe-chain/ci-installer-pin.ts +3 -3
  844. package/scripts/safe-chain/pack-hook.ts +2 -2
  845. package/scripts/safe-chain/preinstall-command.ts +2 -2
  846. package/scripts/security/security-audit-logic.ts +1 -1
  847. package/scripts/security/security-audit-provision-logic.ts +1 -1
  848. package/scripts/security/security-audit-provision.ts +2 -2
  849. package/scripts/security/security-audit.ts +5 -5
  850. package/scripts/security/security-updates-logic.ts +2 -3
  851. package/scripts/security/security-updates.ts +2 -4
  852. package/scripts/self-sync-guard/index.ts +1 -1
  853. package/scripts/self-sync-guard/self-sync-guard-logic.ts +2 -2
  854. package/scripts/self-sync-guard/self-sync-refusal.ts +1 -1
  855. package/scripts/sonar/sonar-hotspots-cli.ts +1 -1
  856. package/scripts/sonar/sonar-hotspots.ts +1 -1
  857. package/scripts/sonar/sonar-new-code-cli.ts +1 -1
  858. package/scripts/sonar/sonar-new-code.ts +1 -1
  859. package/scripts/sonar/sonar-project.ts +1 -1
  860. package/scripts/split/split-assess-cli.ts +1 -1
  861. package/scripts/split/split-assess.ts +3 -3
  862. package/scripts/sync/directory-copy-guard.ts +2 -3
  863. package/scripts/sync/managed-config-scope-cli.ts +1 -2
  864. package/scripts/sync/managed-config-scope.ts +4 -4
  865. package/scripts/sync/plugin-skill-directories.ts +2 -2
  866. package/scripts/sync/reconcile-templates.ts +17 -8
  867. package/scripts/sync/removed-skill-manifest.ts +2 -3
  868. package/scripts/sync/sync-ai-files.ts +7 -7
  869. package/scripts/sync/sync-configs.ts +30 -3
  870. package/scripts/sync/sync-hook-safety.ts +2 -2
  871. package/scripts/sync/sync.ts +23 -10
  872. package/scripts/sync/synced-paths.ts +2 -1
  873. package/scripts/sync/workflow-pin-logic.ts +1 -1
  874. package/scripts/test/test-declared-changed.ts +4 -4
  875. package/scripts/test/test-declared-logic.ts +2 -3
  876. package/scripts/test/test-declared-match.ts +25 -4
  877. package/scripts/test/test-declared.ts +26 -9
  878. package/scripts/test/test-red-commit.ts +3 -2
  879. package/scripts/test/test-red-logic.ts +7 -14
  880. package/scripts/test/test-red.ts +12 -47
  881. package/scripts/test/test-related-scope.ts +2 -3
  882. package/scripts/test/test-related.ts +3 -3
  883. package/scripts/test/test-type-logic.ts +1 -2
  884. package/scripts/test/test-unit-guard.ts +13 -17
  885. package/scripts/test/unit-worker-share.ts +7 -8
  886. package/scripts/time-runtime/time-agent-bundles.ts +2 -4
  887. package/scripts/time-runtime/time-background.ts +17 -21
  888. package/scripts/time-runtime/time-batch-guard.ts +67 -342
  889. package/scripts/time-runtime/time-bundle-call.ts +26 -28
  890. package/scripts/time-runtime/time-bundles.ts +11 -12
  891. package/scripts/time-runtime/time-call-identity.ts +1 -1
  892. package/scripts/time-runtime/time-command-key.ts +2 -2
  893. package/scripts/time-runtime/time-density-hook.ts +8 -11
  894. package/scripts/time-runtime/time-density.ts +5 -5
  895. package/scripts/time-runtime/time-followup-stage.ts +7 -7
  896. package/scripts/time-runtime/time-format.ts +5 -5
  897. package/scripts/time-runtime/time-hook-transcript.ts +3 -3
  898. package/scripts/time-runtime/time-instant.ts +1 -1
  899. package/scripts/time-runtime/time-markers.ts +15 -19
  900. package/scripts/time-runtime/time-phase-names.ts +3 -3
  901. package/scripts/time-runtime/time-reported-failure.ts +15 -19
  902. package/scripts/time-runtime/time-round-trips.ts +20 -23
  903. package/scripts/time-runtime/time-shell.ts +8 -8
  904. package/scripts/time-runtime/time-single-check.ts +1 -2
  905. package/scripts/time-runtime/time-spans.ts +35 -40
  906. package/scripts/time-runtime/time-tool-call.ts +15 -16
  907. package/scripts/time-runtime/time-transcript-line.ts +53 -34
  908. package/scripts/time-runtime/time-writes.ts +5 -5
  909. package/scripts/ui/ui-routes-cli.ts +1 -2
  910. package/scripts/ui/ui-routes.ts +1 -2
  911. package/scripts/version/bump-version.ts +1 -1
  912. package/scripts/version/fresh-metadata-cache.ts +2 -2
  913. package/scripts/version/latest-corepack.ts +129 -98
  914. package/scripts/version/latest-lane-guard.ts +1 -1
  915. package/scripts/version/latest-scope-cli.ts +2 -2
  916. package/scripts/version/latest-stamp.ts +1 -2
  917. package/scripts/version/latest-update.ts +2 -2
  918. package/scripts/version/npm-registry.ts +2 -2
  919. package/scripts/version/package-manager-version.ts +18 -0
  920. package/scripts/version/publishable-range-check.ts +2 -1
  921. package/scripts/version/publishable-range.ts +1 -1
  922. package/scripts/version/release-age.ts +11 -11
  923. package/scripts/version/release-hold.ts +2 -2
  924. package/scripts/version/safe-chain-version-update.ts +3 -3
  925. package/scripts/version/version-check-logic.ts +2 -3
  926. package/scripts/version/version-check.ts +1 -2
  927. package/scripts/version/version-command-config.ts +2 -2
  928. package/scripts/version/version-commands.ts +3 -3
  929. package/scripts/version/version-remote.ts +4 -4
  930. package/scripts/version/version-targets.ts +2 -2
  931. package/templates/gitignore +7 -0
  932. package/templates/workflows/github-release.yml +4 -0
  933. package/dist/hooks/chunk-NV2JRZZO.js +0 -6385
  934. package/dist/hooks/chunk-RKUAD3I6.js +0 -90
  935. package/dist/hooks/chunk-WPALEIRX.js +0 -18
  936. package/scripts/backlog/backlog-restructure.ts +0 -152
  937. package/scripts/rules/issue-fold-rule.ts +0 -72
  938. package/scripts/rules/wip-cap.ts +0 -63
  939. package/scripts/run/run-issue-number.ts +0 -19
@@ -1,24 +1,17 @@
1
1
  import {
2
- ENV_FILE_NAME
3
- } from "./chunk-RKUAD3I6.js";
2
+ ENV_FILE_NAME,
3
+ cost_transcript,
4
+ json_value,
5
+ process_identity,
6
+ process_owner_schema,
7
+ run_carry,
8
+ time_instant
9
+ } from "./chunk-NZN2UFI6.js";
4
10
  import {
5
11
  PLATFORM_TEMP_ROOT,
6
12
  PROBE_TIMEOUT_MS,
7
13
  stamp_file
8
- } from "./chunk-ELCN5LCH.js";
9
-
10
- // scripts/lib/json-value.ts
11
- function parse_or_undefined(text) {
12
- try {
13
- return JSON.parse(text);
14
- } catch {
15
- return void 0;
16
- }
17
- }
18
- function is_record(value) {
19
- return typeof value === "object" && value !== null && !Array.isArray(value);
20
- }
21
- var json_value = { parse_or_undefined, is_record };
14
+ } from "./chunk-NEC4AT4Z.js";
22
15
 
23
16
  // scripts/cost-runtime/cost-blocks.ts
24
17
  import { z } from "zod";
@@ -151,6 +144,17 @@ var CSPELL_CACHE_FLAGS = content_cache_flags(CSPELL_CACHE_FILE);
151
144
 
152
145
  // scripts/josh/josh-commands-backlog.ts
153
146
  var BACKLOG_COMMANDS = {
147
+ // Started from a terminal: the `backlogrun` keyword's launcher, and the board.
148
+ backlogrun: {
149
+ script: "scripts/backlog/backlogrun-cli.ts",
150
+ description: "Start a backlogrun in the background and show its board; with one already running, only show the board",
151
+ category: "AI tools",
152
+ reference: [
153
+ "[#<n>...] [--only] [--max <n>] [--idle <minutes>] [--agent claude|codex]",
154
+ "developer",
155
+ ["files", "network", "processes"]
156
+ ]
157
+ },
154
158
  "backlog:next": {
155
159
  script: "scripts/backlog/backlog-next.ts",
156
160
  description: "Order the whole opted-in backlog: auto-ok issues and the descendants of auto-ok epics, transitively through nested epics",
@@ -181,7 +185,7 @@ var BACKLOG_COMMANDS = {
181
185
  },
182
186
  "backlog:stalled": {
183
187
  script: "scripts/backlog/backlog-stalled-cli.ts",
184
- // A stall sends one Telegram warning (joshuafolkken/kit#3357). The `Stop` hook calls the detector
188
+ // A stall sends one Telegram warning. The `Stop` hook calls the detector
185
189
  // directly, so this flag costs only the manual command its in-process dispatch.
186
190
  tsx_arguments: OPTIONAL_ENV_FILE_FLAGS,
187
191
  description: "Report whether ready backlog work is sitting undispatched with a free lane and no recent dispatch",
@@ -276,7 +280,7 @@ var ISSUE_COMMANDS = {
276
280
  },
277
281
  "defect:rate": {
278
282
  script: "scripts/issue/defect-rate-cli.ts",
279
- description: "Print the defect rate of merged work: defects filed per behavior change completed",
283
+ description: "Print the defect rate of merged work: defects filed per enhancement completed",
280
284
  category: "AI tools",
281
285
  reference: ["[--days <n>]", "automation", ["network"]]
282
286
  },
@@ -306,13 +310,19 @@ var ISSUE_COMMANDS = {
306
310
  },
307
311
  "issue:file": {
308
312
  script: "scripts/issue/issue-file-cli.ts",
309
- description: "File an Issue with every filing step: lint, Origin, WIP cap, duplicate scout, labels, then epic:bundle",
313
+ description: "File an Issue with every filing step: lint, Origin, fold, WIP cap, duplicate scout, labels, then epic:bundle",
310
314
  category: "AI tools",
311
315
  reference: [
312
- "<title> --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>] [--distinct <N,\u2026>] [--over-cap] [--no-auto-ok]",
316
+ "<title> --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>] [--distinct <N,\u2026>] [--over-cap] [--no-auto-ok] [--requested] [--release]",
313
317
  "automation",
314
318
  ["network"]
315
319
  ]
320
+ },
321
+ "issue:release": {
322
+ script: "scripts/issue/issue-release-cli.ts",
323
+ description: "Link an Issue to the repository's open release Issue as its blocker, filing one when none is open",
324
+ category: "AI tools",
325
+ reference: ["<issue>", "automation", ["network"]]
316
326
  }
317
327
  };
318
328
 
@@ -348,7 +358,7 @@ var LANE_COMMANDS = {
348
358
  },
349
359
  "lane:prune": {
350
360
  ...LANE_ARGUMENTS,
351
- description: "Close every lane an interruption left without its work tree",
361
+ description: "Close every lane an interruption left without its work tree, then sweep unregistered leftovers under the lanes root",
352
362
  category: "AI tools",
353
363
  reference: ["", "automation", ["files", "git"]],
354
364
  default_script_arguments: ["prune"]
@@ -380,18 +390,27 @@ var LANE_COMMANDS = {
380
390
  category: "AI tools",
381
391
  reference: ["<issue> [--stash <message>]", "automation", ["files", "git", "processes"]]
382
392
  },
383
- // The lane-limit measurement (joshuafolkken/kit#3355): `.env` is read so `lane:stats` labels the row
393
+ // A live run's lane limit: `.env` is read so the bare form reports the
394
+ // `JOSH_LANE_LIMIT` a person set there when no override stands.
395
+ "lane:limit": {
396
+ script: "scripts/lane/lane-limit-cli.ts",
397
+ tsx_arguments: OPTIONAL_ENV_FILE_FLAGS,
398
+ description: "Change a live backlogrun\u2019s lane limit without stopping it, or print the limit, lanes in use and free lanes",
399
+ category: "AI tools",
400
+ reference: ["[<limit>] [--reset]", "developer", ["files"]]
401
+ },
402
+ // The lane-limit measurement: `.env` is read so `lane:stats` labels the row
384
403
  // with the `JOSH_LANE_LIMIT` a person set there.
385
404
  "lane:sample": {
386
405
  ...MEASURE_ARGUMENTS,
387
- description: "Record the machine load (load average, swap, free memory, working lanes) to the lane ledger",
406
+ description: "Record the machine load (load average, swap, free memory, working lanes) to the lane ledger \u2014 a backlogrun samples itself, this is for a reading outside one",
388
407
  category: "AI tools",
389
408
  reference: ["[--every <seconds>]", "maintainer", ["files"]],
390
409
  default_script_arguments: ["sample"]
391
410
  },
392
411
  "lane:stats": {
393
412
  ...MEASURE_ARGUMENTS,
394
- description: "Print one table row of lane throughput, gate duration and machine load over a period",
413
+ description: "Print one table row of lane throughput, gate duration and machine load over a period, and the per-stage durations of a lane under it",
395
414
  category: "AI tools",
396
415
  reference: ["--period <days> [--limit <lane-limit>]", "maintainer", ["none"]],
397
416
  default_script_arguments: ["stats"]
@@ -423,12 +442,18 @@ var RUN_COMMANDS = {
423
442
  "run:carry": {
424
443
  script: "scripts/run/carry/run-carry-cli.ts",
425
444
  // `--stopped` sends the stop confirmation, so the Telegram credentials come from `.env` as for
426
- // `run:wake` below (joshuafolkken/kit#3357).
445
+ // `run:wake` below.
427
446
  tsx_arguments: OPTIONAL_ENV_FILE_FLAGS,
428
447
  description: "Carry one invocation\u2019s budget across its own session cuts",
429
448
  category: "AI tools",
430
449
  reference: ["<operation> [arguments...]", "automation", ["files"]]
431
450
  },
451
+ "run:add": {
452
+ script: "scripts/run/add/run-add-cli.ts",
453
+ description: "Add issues to a live backlogrun, ahead of the queue unless --no-priority",
454
+ category: "AI tools",
455
+ reference: ["<issue...> [--no-priority]", "automation", ["network", "files"]]
456
+ },
432
457
  "run:wake": {
433
458
  script: "scripts/run/wake/run-wake-cli.ts",
434
459
  // `.env` rather than the ambient environment:
@@ -467,18 +492,26 @@ var RUN_COMMANDS = {
467
492
  ["files"]
468
493
  ]
469
494
  },
495
+ "run:board": {
496
+ script: "scripts/run/board/run-board-cli.ts",
497
+ // `--every` pushes its frame as a Telegram, so the credentials come from `.env` as for `run:carry`.
498
+ tsx_arguments: OPTIONAL_ENV_FILE_FLAGS,
499
+ description: "Draw a live board of the running backlogrun, redrawn every second",
500
+ category: "AI tools",
501
+ reference: ["[--once | --chat | --every <minutes>]", "automation", ["files", "network"]]
502
+ },
470
503
  "run:prep": {
471
504
  script: "scripts/run/run-prep-cli.ts",
472
505
  description: "Bundle a run\u2019s pre-edit reads: body, comments, state, dependency scope",
473
506
  category: "AI tools",
474
507
  reference: ["<issue>", "automation", ["network"]]
475
508
  },
476
- // The entry sequence a lane opened on, folded into one call (joshuafolkken/kit#2372): claim the tree,
509
+ // The entry sequence a lane opened on, folded into one call: claim the tree,
477
510
  // read the budget, gather the issue reads and decide the pre-implementation step. `run:hold`,
478
511
  // `cost --cut`, `run:prep` and `run:step` were four round trips re-billing a lane's full context each.
479
512
  "run:entry": {
480
513
  script: "scripts/run/entry/run-entry-cli.ts",
481
- // A `busy` hold or an `over` budget sends the stop confirmation (joshuafolkken/kit#3357).
514
+ // A `busy` hold or an `over` budget sends the stop confirmation.
482
515
  tsx_arguments: OPTIONAL_ENV_FILE_FLAGS,
483
516
  description: "Open a run in one call: claim the tree, read the budget, bundle the reads, decide the pre-implementation step",
484
517
  category: "AI tools",
@@ -581,12 +614,12 @@ var AI_COMMANDS = {
581
614
  reference: ["[options]", "maintainer", ["none"]],
582
615
  // Kit-only: it measures kit's own development runs and its report modules live under the
583
616
  // undistributed `scripts/time/`, so it means nothing in a consumer project and is dropped from a
584
- // consumer's help (joshuafolkken/kit#1997). The runtime analysis hooks and guards rely on stays
617
+ // consumer's help. The runtime analysis hooks and guards rely on stays
585
618
  // distributed under `scripts/time-runtime/`.
586
619
  is_kit_only: true
587
620
  },
588
621
  // The tool-calls-per-round-trip density the batching guard is measured on, aggregated across the
589
- // recent lane sessions (joshuafolkken/kit#2405). Kit-only for the same reason `time` is: it reads
622
+ // recent lane sessions. Kit-only for the same reason `time` is: it reads
590
623
  // kit's own lane transcripts and means nothing in a consumer project.
591
624
  "time:density": {
592
625
  script: "scripts/time/time-density-cli.ts",
@@ -602,7 +635,7 @@ var AI_COMMANDS = {
602
635
  reference: ["", "maintainer", ["none"]],
603
636
  // Kit-only: it reads kit's own development run — the transcript store, the review ledger and the
604
637
  // run event stream — so it means nothing in a consumer project and is dropped from a consumer's
605
- // help (joshuafolkken/kit#2328), through the same declaration `josh time` uses for the same reason.
638
+ // help, through the same declaration `josh time` uses for the same reason.
606
639
  is_kit_only: true
607
640
  },
608
641
  "review:brief": {
@@ -654,7 +687,7 @@ var AI_COMMANDS = {
654
687
  category: "AI tools",
655
688
  reference: ["[--join]", "automation", ["processes", "files"]]
656
689
  },
657
- // The post-merge sequence a run closed on, folded into one call (joshuafolkken/kit#2372): commit the
690
+ // The post-merge sequence a run closed on, folded into one call: commit the
658
691
  // observation ledger, read the completion citations and decide the release scope. `observations:flush`,
659
692
  // `issue:cite` and `release:scope` were three round trips re-billing the run's full context each.
660
693
  "run:tail": {
@@ -663,7 +696,7 @@ var AI_COMMANDS = {
663
696
  category: "AI tools",
664
697
  reference: ["[<issue> ...]", "automation", ["git", "network"]]
665
698
  },
666
- // The commit-to-report region a run ships a change on, folded into one call (joshuafolkken/kit#2398):
699
+ // The commit-to-report region a run ships a change on, folded into one call:
667
700
  // the gate, the commit/push/PR (`git -y`), the CI-wait merge (`followup`) and the report bookkeeping
668
701
  // (`run:tail`) were four round trips re-billing the run's full context each. It stops at the first
669
702
  // failed step and names it, so the run reads only the step to fix.
@@ -723,7 +756,7 @@ var AI_COMMANDS = {
723
756
  category: "AI tools",
724
757
  reference: ["[scenario...]", "maintainer", ["processes", "network"]],
725
758
  // Kit-only: it replays kit's own distributed rules against real Claude sessions, so it means
726
- // nothing in a consumer project and is dropped from a consumer's help (joshuafolkken/kit#1988).
759
+ // nothing in a consumer project and is dropped from a consumer's help.
727
760
  is_kit_only: true
728
761
  }
729
762
  };
@@ -739,186 +772,15 @@ var CLONE_COMMANDS = {
739
772
  };
740
773
 
741
774
  // scripts/gate/core-budget.ts
742
- import { randomUUID as randomUUID2 } from "node:crypto";
743
- import { readdirSync as readdirSync2 } from "node:fs";
744
- import { availableParallelism as availableParallelism2 } from "node:os";
745
- import path3 from "node:path";
746
-
747
- // scripts/josh/process-identity.ts
748
- import { execFileSync, spawnSync } from "node:child_process";
749
775
  import { randomUUID } from "node:crypto";
750
- import { readFileSync, rmSync } from "node:fs";
751
- import { createServer } from "node:net";
752
- import path from "node:path";
753
- var PS_COMMAND = "/bin/ps";
754
- var FORMAT_FLAG = "-o";
755
- var START_TIME_FORMAT = "lstart=";
756
- var PID_FLAG = "-p";
757
- var PROBE_ENVIRONMENT = { TZ: "UTC", LC_ALL: "C" };
758
- var LIVENESS_SIGNAL = 0;
759
- var LOWEST_REAL_PID = 1;
760
- var PROC_START_FIELD_INDEX = 19;
761
- var BEACON_SCHEME = "socket:";
762
- var BEACON_SUFFIX = ".sock";
763
- var BEACON_PREFIX = `josh-process-identity-${String(process.getuid?.() ?? "")}-`;
764
- var BEACON_ID_LENGTH = 36;
765
- var BEACON_ID_PATTERN = /^[\da-f-]+$/u;
766
- var WINDOWS_PLATFORM = "win32";
767
- var SOCKET_PROBE_SOURCE = "const net=require('node:net');const socket=net.createConnection(process.argv[1]);socket.once('connect',()=>process.exit(0));socket.once('error',()=>process.exit(1));socket.setTimeout(1000,()=>process.exit(1));";
768
- var beacons = /* @__PURE__ */ new Map();
769
- var exit_cleanup = { is_registered: false };
770
- function is_live_pid(pid) {
771
- if (pid < LOWEST_REAL_PID) return false;
772
- try {
773
- process.kill(pid, LIVENESS_SIGNAL);
774
- return true;
775
- } catch {
776
- return false;
777
- }
778
- }
779
- function read_proc_start(pid) {
780
- try {
781
- const stat = readFileSync(`/proc/${String(pid)}/stat`, "utf8");
782
- const fields = stat.slice(stat.lastIndexOf(")") + 1).trim().split(/\s+/u);
783
- const start = fields[PROC_START_FIELD_INDEX];
784
- return start === void 0 ? void 0 : `proc:${start}`;
785
- } catch {
786
- return void 0;
787
- }
788
- }
789
- function read_ps_start(pid) {
790
- try {
791
- const printed = execFileSync(
792
- PS_COMMAND,
793
- [FORMAT_FLAG, START_TIME_FORMAT, PID_FLAG, String(pid)],
794
- {
795
- encoding: "utf8",
796
- timeout: PROBE_TIMEOUT_MS,
797
- stdio: ["ignore", "pipe", "ignore"],
798
- env: PROBE_ENVIRONMENT
799
- }
800
- ).trim();
801
- return printed.length > 0 ? printed : void 0;
802
- } catch {
803
- return void 0;
804
- }
805
- }
806
- var START_PROBES = { read_proc_start, read_ps_start };
807
- function safe_probe(probe, pid) {
808
- try {
809
- return probe(pid);
810
- } catch {
811
- return void 0;
812
- }
813
- }
814
- function read_start(pid, probes = START_PROBES) {
815
- return safe_probe(probes.read_proc_start, pid) ?? safe_probe(probes.read_ps_start, pid);
816
- }
817
- function close_beacon(token) {
818
- const server = beacons.get(token);
819
- if (server === void 0) return;
820
- beacons.delete(token);
821
- server.close();
822
- rmSync(token.slice(BEACON_SCHEME.length), { force: true });
823
- }
824
- function close_beacons() {
825
- for (const token of beacons.keys()) close_beacon(token);
826
- }
827
- function ensure_exit_cleanup() {
828
- if (exit_cleanup.is_registered) return;
829
- exit_cleanup.is_registered = true;
830
- process.once("exit", close_beacons);
831
- }
832
- function ignore_beacon_error() {
833
- }
834
- function bind_beacon(target) {
835
- return createServer().on("error", ignore_beacon_error).listen(target);
836
- }
837
- function try_bind_beacon(bind, target) {
838
- try {
839
- const server = bind(target);
840
- return server.listening ? server : void 0;
841
- } catch {
842
- return void 0;
843
- }
844
- }
845
- function open_beacon(bind = bind_beacon) {
846
- const target = path.join(PLATFORM_TEMP_ROOT, `${BEACON_PREFIX}${randomUUID()}${BEACON_SUFFIX}`);
847
- const token = `${BEACON_SCHEME}${target}`;
848
- const server = try_bind_beacon(bind, target);
849
- if (server === void 0) return void 0;
850
- server.unref();
851
- beacons.set(token, server);
852
- ensure_exit_cleanup();
853
- return token;
854
- }
855
- function resolve_own_start(probes = START_PROBES, platform = process.platform) {
856
- const start = read_start(process.pid, probes);
857
- if (start !== void 0 || platform === WINDOWS_PLATFORM) return start;
858
- return open_beacon();
859
- }
860
- function is_valid_beacon_name(name) {
861
- if (!name.startsWith(BEACON_PREFIX) || !name.endsWith(BEACON_SUFFIX)) return false;
862
- const id = name.slice(BEACON_PREFIX.length, -BEACON_SUFFIX.length);
863
- return id.length === BEACON_ID_LENGTH && BEACON_ID_PATTERN.test(id);
864
- }
865
- function beacon_target(token) {
866
- if (!token.startsWith(BEACON_SCHEME)) return void 0;
867
- const target = token.slice(BEACON_SCHEME.length);
868
- if (path.dirname(target) !== PLATFORM_TEMP_ROOT) return void 0;
869
- return is_valid_beacon_name(path.basename(target)) ? target : void 0;
870
- }
871
- function is_live_beacon(target) {
872
- return spawnSync(process.execPath, ["-e", SOCKET_PROBE_SOURCE, target], {
873
- stdio: "ignore",
874
- timeout: PROBE_TIMEOUT_MS
875
- }).status === 0;
876
- }
877
- function has_matching_start(pid, recorded_start, read) {
878
- const observed = read(pid);
879
- return observed === void 0 ? void 0 : observed === recorded_start;
880
- }
881
- function matches_recorded_start(pid, recorded_start, read) {
882
- const target = beacon_target(recorded_start);
883
- return target === void 0 ? has_matching_start(pid, recorded_start, read) : is_live_beacon(target);
884
- }
885
- var own_probe = /* @__PURE__ */ new Map();
886
- function own_start() {
887
- if (!own_probe.has(process.pid)) own_probe.set(process.pid, resolve_own_start());
888
- return own_probe.get(process.pid);
889
- }
890
- function own_fields() {
891
- const start = own_start();
892
- return { pid: process.pid, ...start !== void 0 && { process_start: start } };
893
- }
894
- function is_same_process(pid, recorded_start, read = read_start) {
895
- if (pid === void 0 || !is_live_pid(pid)) return false;
896
- if (recorded_start === void 0) return void 0;
897
- return matches_recorded_start(pid, recorded_start, read);
898
- }
899
- function is_own_process(pid, recorded_start) {
900
- return pid === process.pid && recorded_start === own_start();
901
- }
902
- var process_identity = {
903
- close_beacon,
904
- is_live_pid,
905
- is_own_process,
906
- is_same_process,
907
- open_beacon,
908
- own_fields,
909
- own_start,
910
- read_start,
911
- resolve_own_start
912
- };
913
-
914
- // scripts/josh/process-owner.ts
915
- import { z as z2 } from "zod";
916
- var process_owner_schema = z2.object({ pid: z2.number(), process_start: z2.string().optional() });
776
+ import { readdirSync as readdirSync2 } from "node:fs";
777
+ import { availableParallelism as availableParallelism3 } from "node:os";
778
+ import path2 from "node:path";
917
779
 
918
780
  // scripts/test/unit-worker-share.ts
919
781
  import { readdirSync } from "node:fs";
920
782
  import { availableParallelism } from "node:os";
921
- import path2 from "node:path";
783
+ import path from "node:path";
922
784
  var RUN_PREFIX = "josh-unit-running-";
923
785
  var WORKER_FLAG = "--maxWorkers";
924
786
  var WORKER_FLAGS = [WORKER_FLAG, "--max-workers"];
@@ -957,7 +819,7 @@ function is_marker_live(source) {
957
819
  return false;
958
820
  }
959
821
  function live_run_count(directory = PLATFORM_TEMP_ROOT) {
960
- return marker_files(directory).filter((name) => is_marker_live(path2.join(directory, name))).length;
822
+ return marker_files(directory).filter((name) => is_marker_live(path.join(directory, name))).length;
961
823
  }
962
824
  var NESTED_KEY = "JOSH_UNIT_RUN_MARKED";
963
825
  var NESTED_VALUE = "1";
@@ -980,22 +842,22 @@ function worker_arguments(vitest_arguments, share) {
980
842
  if (vitest_arguments.some((argument) => is_worker_flag(argument))) return [];
981
843
  return [`${WORKER_FLAG}=${String(share)}`];
982
844
  }
983
- function mark_run_started(target) {
845
+ function mark_run_started(target2) {
984
846
  try {
985
- stamp_file.write_stamp(target, process_identity.own_fields());
847
+ stamp_file.write_stamp(target2, process_identity.own_fields());
986
848
  } catch {
987
849
  }
988
850
  }
989
851
  async function with_run_marker(run) {
990
852
  if (is_nested_run()) return await run();
991
- const target = marker_path();
992
- mark_run_started(target);
853
+ const target2 = marker_path();
854
+ mark_run_started(target2);
993
855
  process.env[NESTED_KEY] = NESTED_VALUE;
994
856
  try {
995
857
  return await run();
996
858
  } finally {
997
859
  process.env[NESTED_KEY] = "";
998
- stamp_file.remove_stamp(target);
860
+ stamp_file.remove_stamp(target2);
999
861
  }
1000
862
  }
1001
863
  var unit_worker_share = {
@@ -1015,7 +877,243 @@ var unit_worker_share = {
1015
877
  };
1016
878
 
1017
879
  // scripts/gate/core-budget.ts
1018
- import { z as z3 } from "zod";
880
+ import { z as z2 } from "zod";
881
+
882
+ // scripts/gate/core-admission.ts
883
+ var MS_PER_SECOND = 1e3;
884
+ var RAMP_UP_MS = 3e4;
885
+ function compare_claim(left, right) {
886
+ const by_time = left.reservation.claimed_at - right.reservation.claimed_at;
887
+ return by_time === 0 ? left.key.localeCompare(right.key) : by_time;
888
+ }
889
+ function add_load(totals, reservation) {
890
+ totals.cores += reservation.weight;
891
+ totals.memory_mb += reservation.memory_mb ?? 0;
892
+ }
893
+ function exceeds(totals, budget) {
894
+ return totals.cores > budget.cores || totals.memory_mb > budget.memory_mb;
895
+ }
896
+ function admitted_keys(reservations, budget, memory_budget = Infinity) {
897
+ const limit = { cores: budget, memory_mb: memory_budget };
898
+ const totals = { cores: 0, memory_mb: 0 };
899
+ const admitted = /* @__PURE__ */ new Set();
900
+ for (const [index, entry] of reservations.toSorted(compare_claim).entries()) {
901
+ add_load(totals, entry.reservation);
902
+ if (index !== 0 && exceeds(totals, limit)) break;
903
+ admitted.add(entry.key);
904
+ }
905
+ return admitted;
906
+ }
907
+ function is_admitted(key, reservations, budget) {
908
+ return admitted_keys(reservations, budget.cores, budget.memory_mb).has(key);
909
+ }
910
+ function sum_load(reservations) {
911
+ const load = { cores: 0, memory_mb: 0 };
912
+ for (const entry of reservations) add_load(load, entry.reservation);
913
+ return load;
914
+ }
915
+ function is_ramped(reservation, now) {
916
+ const { admitted_at } = reservation;
917
+ return admitted_at !== void 0 && now - admitted_at >= RAMP_UP_MS;
918
+ }
919
+ function ledger_load(reservations, now) {
920
+ const admitted = reservations.filter((entry) => entry.reservation.admitted_at !== void 0);
921
+ const ramped = admitted.filter((entry) => is_ramped(entry.reservation, now));
922
+ return { cores: sum_load(admitted).cores, memory_mb: sum_load(ramped).memory_mb };
923
+ }
924
+ function total_weight(reservations) {
925
+ return sum_load(reservations).cores;
926
+ }
927
+ function admitted_load(reservations, budget) {
928
+ const admitted = admitted_keys(reservations, budget);
929
+ return total_weight(reservations.filter((entry) => admitted.has(entry.key)));
930
+ }
931
+ function describe_memory(ledger, budget) {
932
+ if (!Number.isFinite(budget.memory_mb)) return "";
933
+ return ` and ${String(Math.round(ledger.memory_mb))} MB of memory against ${String(Math.round(budget.memory_mb))} MB`;
934
+ }
935
+ function describe_overflow(admission) {
936
+ const { overflow } = admission;
937
+ if (overflow === void 0) return void 0;
938
+ const { ledger, budget } = overflow;
939
+ const waited = String(Math.round(overflow.waited_ms / MS_PER_SECOND));
940
+ const cores = `the ledger held ${String(ledger.cores)} cores against a budget of ${String(budget.cores)}`;
941
+ return `started past the core budget after ${waited}s \u2014 ${cores}${describe_memory(ledger, budget)}`;
942
+ }
943
+ var core_admission = {
944
+ RAMP_UP_MS,
945
+ admitted_keys,
946
+ admitted_load,
947
+ describe_overflow,
948
+ is_admitted,
949
+ ledger_load,
950
+ sum_load
951
+ };
952
+
953
+ // scripts/gate/machine-capacity.ts
954
+ import { readFile } from "node:fs/promises";
955
+ import { availableParallelism as availableParallelism2, cpus, totalmem } from "node:os";
956
+ import { execa } from "execa";
957
+ var SAMPLE_WINDOW_MS = 250;
958
+ var BASELINE_CORES = 2;
959
+ var BYTES_PER_MB = 1048576;
960
+ var KB_PER_MB = 1024;
961
+ var PERCENT = 100;
962
+ var MEMINFO_PATH = "/proc/meminfo";
963
+ var VMSTAT_PATH = "/proc/vmstat";
964
+ var LINUX_AVAILABLE = /^MemAvailable:\s+(?<kb>\d+) kB/mu;
965
+ var LINUX_SWAP_IN = /^pswpin (?<pages>\d+)$/mu;
966
+ var LINUX_SWAP_OUT = /^pswpout (?<pages>\d+)$/mu;
967
+ var PAGE_SIZE_ARGUMENTS = ["PAGESIZE"];
968
+ var LEVEL_NAME = "kern.memorystatus_level";
969
+ var SWAP_IN_NAME = "vm.compressor.swapper.swapins_total";
970
+ var SWAP_OUT_NAME = "vm.compressor.swapper.swapouts_total";
971
+ var PAGE_SIZE_NAME = "hw.pagesize";
972
+ var PRESSURE_NAME = "kern.memorystatus_vm_pressure_level";
973
+ var SYSCTL_ARGUMENTS = [LEVEL_NAME, SWAP_IN_NAME, SWAP_OUT_NAME, PAGE_SIZE_NAME, PRESSURE_NAME];
974
+ var SYSCTL_LINE = /^(?<name>[\w.]+): (?<value>\d+)$/gmu;
975
+ function cpu_times() {
976
+ let busy = 0;
977
+ let idle = 0;
978
+ for (const { times } of cpus()) {
979
+ busy += times.user + times.nice + times.sys + times.irq;
980
+ idle += times.idle;
981
+ }
982
+ return { busy, total: busy + idle };
983
+ }
984
+ function busy_share_between(before, after) {
985
+ const total = after.total - before.total;
986
+ if (total <= 0) return void 0;
987
+ return (after.busy - before.busy) / total;
988
+ }
989
+ function busy_cores_between(before, after, cores) {
990
+ const share = busy_share_between(before, after);
991
+ return share === void 0 ? void 0 : share * cores;
992
+ }
993
+ function sysctl_values(output) {
994
+ const values = [...output.matchAll(SYSCTL_LINE)].map(
995
+ (match) => [match.groups?.["name"] ?? "", Number(match.groups?.["value"])]
996
+ );
997
+ return new Map(values);
998
+ }
999
+ function swapped_pages(pages_in, pages_out) {
1000
+ return pages_in === void 0 || pages_out === void 0 ? void 0 : pages_in + pages_out;
1001
+ }
1002
+ function swapped_mb(pages, page_bytes) {
1003
+ if (pages === void 0 || page_bytes === void 0) return void 0;
1004
+ return pages * page_bytes / BYTES_PER_MB;
1005
+ }
1006
+ function swapped_between(from, to) {
1007
+ if (from === void 0 || to === void 0) return void 0;
1008
+ return Math.max(0, to - from);
1009
+ }
1010
+ function parse_darwin_memory(output, total_bytes) {
1011
+ const values = sysctl_values(output);
1012
+ const level = values.get(LEVEL_NAME);
1013
+ return {
1014
+ available_mb: level === void 0 ? void 0 : level / PERCENT * (total_bytes / BYTES_PER_MB),
1015
+ swapped_mb: swapped_mb(
1016
+ swapped_pages(values.get(SWAP_IN_NAME), values.get(SWAP_OUT_NAME)),
1017
+ values.get(PAGE_SIZE_NAME)
1018
+ ),
1019
+ pressure_level: values.get(PRESSURE_NAME)
1020
+ };
1021
+ }
1022
+ function parse_linux_available(meminfo) {
1023
+ const kb = LINUX_AVAILABLE.exec(meminfo)?.groups?.["kb"];
1024
+ return kb === void 0 ? void 0 : Number(kb) / KB_PER_MB;
1025
+ }
1026
+ function pages_of(pattern, vmstat) {
1027
+ const pages = pattern.exec(vmstat)?.groups?.["pages"];
1028
+ return pages === void 0 ? void 0 : Number(pages);
1029
+ }
1030
+ function parse_linux_swapped(vmstat, page_bytes) {
1031
+ const pages = swapped_pages(pages_of(LINUX_SWAP_IN, vmstat), pages_of(LINUX_SWAP_OUT, vmstat));
1032
+ return swapped_mb(pages, page_bytes);
1033
+ }
1034
+ async function settled(read) {
1035
+ try {
1036
+ return await read();
1037
+ } catch {
1038
+ return void 0;
1039
+ }
1040
+ }
1041
+ async function read_darwin_memory() {
1042
+ const { stdout } = await execa("sysctl", SYSCTL_ARGUMENTS, {
1043
+ reject: false,
1044
+ timeout: PROBE_TIMEOUT_MS
1045
+ });
1046
+ return parse_darwin_memory(stdout, totalmem());
1047
+ }
1048
+ async function read_page_size() {
1049
+ const { stdout } = await execa("getconf", PAGE_SIZE_ARGUMENTS, { timeout: PROBE_TIMEOUT_MS });
1050
+ return stdout;
1051
+ }
1052
+ async function read_linux_memory() {
1053
+ const [meminfo, vmstat, page_size] = await Promise.all([
1054
+ settled(async () => await readFile(MEMINFO_PATH, "utf8")),
1055
+ settled(async () => await readFile(VMSTAT_PATH, "utf8")),
1056
+ settled(read_page_size)
1057
+ ]);
1058
+ const page_bytes = page_size === void 0 ? void 0 : Number(page_size);
1059
+ return {
1060
+ available_mb: meminfo === void 0 ? void 0 : parse_linux_available(meminfo),
1061
+ swapped_mb: vmstat === void 0 || page_bytes === void 0 ? void 0 : parse_linux_swapped(vmstat, page_bytes),
1062
+ pressure_level: void 0
1063
+ };
1064
+ }
1065
+ var UNREAD_MEMORY = {
1066
+ available_mb: void 0,
1067
+ swapped_mb: void 0,
1068
+ pressure_level: void 0
1069
+ };
1070
+ async function read_memory() {
1071
+ if (process.platform === "darwin") return await settled(read_darwin_memory) ?? UNREAD_MEMORY;
1072
+ return process.platform === "linux" ? await read_linux_memory() : UNREAD_MEMORY;
1073
+ }
1074
+ function is_unquoted() {
1075
+ return cpus().length > 0 && cpus().length === availableParallelism2();
1076
+ }
1077
+ async function default_sleep(ms) {
1078
+ await new Promise((resolve) => {
1079
+ setTimeout(resolve, ms);
1080
+ });
1081
+ }
1082
+ async function read_machine(sleep = default_sleep) {
1083
+ const before = cpu_times();
1084
+ const [memory] = await Promise.all([read_memory(), sleep(SAMPLE_WINDOW_MS)]);
1085
+ const busy_cores = is_unquoted() ? busy_cores_between(before, cpu_times(), cpus().length) : void 0;
1086
+ return { busy_cores, available_mb: memory.available_mb };
1087
+ }
1088
+ async function read_sample() {
1089
+ return { cpu: cpu_times(), memory: await read_memory(), total_mb: totalmem() / BYTES_PER_MB };
1090
+ }
1091
+ function external_cores(busy_cores, ledger_cores) {
1092
+ if (busy_cores === void 0) return 0;
1093
+ return Math.floor(Math.max(0, busy_cores - ledger_cores - BASELINE_CORES));
1094
+ }
1095
+ function machine_budget(cores, reading, ledger) {
1096
+ return {
1097
+ cores: cores - external_cores(reading.busy_cores, ledger.cores),
1098
+ memory_mb: reading.available_mb === void 0 ? Infinity : reading.available_mb + ledger.memory_mb
1099
+ };
1100
+ }
1101
+ var machine_capacity = {
1102
+ BASELINE_CORES,
1103
+ busy_cores_between,
1104
+ busy_share_between,
1105
+ external_cores,
1106
+ machine_budget,
1107
+ parse_darwin_memory,
1108
+ parse_linux_available,
1109
+ parse_linux_swapped,
1110
+ read_machine,
1111
+ read_memory,
1112
+ read_sample,
1113
+ swapped_between
1114
+ };
1115
+
1116
+ // scripts/gate/core-budget.ts
1019
1117
  var RESERVED_PREFIX = "josh-core-reserved-";
1020
1118
  var RESERVED_SUFFIX = ".json";
1021
1119
  var POLL_INTERVAL_MS = 50;
@@ -1027,11 +1125,20 @@ var CORE_WEIGHTS = {
1027
1125
  spell_check: 1,
1028
1126
  eslint_scan: 1
1029
1127
  };
1128
+ var MEMORY_MB = {
1129
+ lint: 2400,
1130
+ type_check: 1300,
1131
+ spell_check: 350,
1132
+ eslint_scan: 2400,
1133
+ unit_worker: 350
1134
+ };
1030
1135
  var HELD_KEY = "JOSH_CORE_RESERVED";
1031
1136
  var HELD_VALUE = "1";
1032
1137
  var reservation_schema = process_owner_schema.extend({
1033
- weight: z3.number(),
1034
- claimed_at: z3.number()
1138
+ weight: z2.number(),
1139
+ claimed_at: z2.number(),
1140
+ memory_mb: z2.number().optional(),
1141
+ admitted_at: z2.number().optional()
1035
1142
  });
1036
1143
  function marker_name(key) {
1037
1144
  return `${RESERVED_PREFIX}${key}${RESERVED_SUFFIX}`;
@@ -1042,12 +1149,7 @@ function is_running2(reservation) {
1042
1149
  function read_reservation(source) {
1043
1150
  const raw = stamp_file.read_stamp_text(source);
1044
1151
  if (raw === void 0) return void 0;
1045
- try {
1046
- const parsed = reservation_schema.safeParse(JSON.parse(raw));
1047
- return parsed.success ? parsed.data : void 0;
1048
- } catch {
1049
- return void 0;
1050
- }
1152
+ return json_value.parse_with(raw, reservation_schema);
1051
1153
  }
1052
1154
  function sweep_marker2(source) {
1053
1155
  try {
@@ -1064,78 +1166,92 @@ function live_reservation(source) {
1064
1166
  }
1065
1167
  function marker_files2(directory) {
1066
1168
  try {
1067
- return readdirSync2(directory).filter((name) => name.startsWith(RESERVED_PREFIX));
1169
+ return readdirSync2(directory).filter(
1170
+ (name) => name.startsWith(RESERVED_PREFIX) && name.endsWith(RESERVED_SUFFIX)
1171
+ );
1068
1172
  } catch {
1069
1173
  return [];
1070
1174
  }
1071
1175
  }
1072
1176
  function live_reservations(directory = PLATFORM_TEMP_ROOT) {
1073
1177
  return marker_files2(directory).flatMap((name) => {
1074
- const reservation = live_reservation(path3.join(directory, name));
1178
+ const reservation = live_reservation(path2.join(directory, name));
1075
1179
  return reservation === void 0 ? [] : { key: name, reservation };
1076
1180
  });
1077
1181
  }
1078
- function compare_claim(left, right) {
1079
- const by_time = left.reservation.claimed_at - right.reservation.claimed_at;
1080
- return by_time === 0 ? left.key.localeCompare(right.key) : by_time;
1081
- }
1082
- function admitted_keys(reservations, budget) {
1083
- const admitted = /* @__PURE__ */ new Set();
1084
- let cumulative = 0;
1085
- for (const [index, entry] of reservations.toSorted(compare_claim).entries()) {
1086
- cumulative += entry.reservation.weight;
1087
- if (index !== 0 && cumulative > budget) break;
1088
- admitted.add(entry.key);
1089
- }
1090
- return admitted;
1091
- }
1092
- function is_admitted(key, reservations, budget) {
1093
- return admitted_keys(reservations, budget).has(key);
1094
- }
1095
- function admitted_load(reservations, budget) {
1096
- const admitted = admitted_keys(reservations, budget);
1097
- return reservations.filter((entry) => admitted.has(entry.key)).reduce((total, entry) => total + entry.reservation.weight, 0);
1098
- }
1099
1182
  function normalize_budget(budget) {
1100
1183
  return Number.isFinite(budget) ? Math.max(MIN_BUDGET, Math.floor(budget)) : MIN_BUDGET;
1101
1184
  }
1102
- async function default_sleep(ms) {
1185
+ async function default_sleep2(ms) {
1103
1186
  await new Promise((resolve) => {
1104
1187
  setTimeout(resolve, ms);
1105
1188
  });
1106
1189
  }
1107
- function write_reservation(target, weight, claimed_at) {
1108
- stamp_file.write_stamp(target, { ...process_identity.own_fields(), weight, claimed_at });
1190
+ function write_reservation(target2, fields) {
1191
+ stamp_file.replace_stamp(target2, { ...process_identity.own_fields(), ...fields });
1109
1192
  }
1110
1193
  function resolve_timing(options) {
1111
1194
  return {
1112
1195
  now: options.now ?? Date.now,
1113
- sleep: options.sleep ?? default_sleep,
1114
- poll_interval_ms: options.poll_interval_ms ?? POLL_INTERVAL_MS
1196
+ sleep: options.sleep ?? default_sleep2,
1197
+ poll_interval_ms: options.poll_interval_ms ?? POLL_INTERVAL_MS,
1198
+ wait_cap_ms: options.wait_cap_ms ?? WAIT_CAP_MS
1199
+ };
1200
+ }
1201
+ async function current_budget(context, reservations) {
1202
+ if (reservations.length <= 1) return { cores: context.budget, memory_mb: Infinity };
1203
+ const reading = await context.read_machine();
1204
+ const ledger = core_admission.ledger_load(reservations, context.now());
1205
+ const budget = machine_capacity.machine_budget(context.budget, reading, ledger);
1206
+ return { ...budget, cores: normalize_budget(budget.cores) };
1207
+ }
1208
+ function admit(context, overflow) {
1209
+ write_reservation(context.target, { ...context.fields, admitted_at: context.now() });
1210
+ return { overflow };
1211
+ }
1212
+ function overflow_of(context, reservations, budget) {
1213
+ return {
1214
+ waited_ms: context.now() - context.fields.claimed_at,
1215
+ ledger: core_admission.sum_load(reservations),
1216
+ budget
1115
1217
  };
1116
1218
  }
1219
+ async function poll_admission(context) {
1220
+ const reservations = live_reservations(context.directory);
1221
+ const budget = await current_budget(context, reservations);
1222
+ if (core_admission.is_admitted(context.key, reservations, budget)) return admit(context);
1223
+ if (context.now() >= context.deadline) {
1224
+ return admit(context, overflow_of(context, reservations, budget));
1225
+ }
1226
+ return void 0;
1227
+ }
1117
1228
  async function await_admission(context) {
1118
- while (!is_admitted(context.key, live_reservations(context.directory), context.budget)) {
1119
- if (context.now() >= context.deadline) return;
1229
+ let admission = await poll_admission(context);
1230
+ while (admission === void 0) {
1120
1231
  await context.sleep(context.poll_interval_ms);
1232
+ admission = await poll_admission(context);
1121
1233
  }
1234
+ return admission;
1122
1235
  }
1123
1236
  async function reserve(weight, options = {}) {
1124
1237
  const timing = resolve_timing(options);
1125
1238
  const directory = options.directory ?? PLATFORM_TEMP_ROOT;
1126
- const budget = normalize_budget(options.budget ?? availableParallelism2());
1127
1239
  const claimed_at = timing.now();
1128
- const name = marker_name(randomUUID2());
1129
- const target = path3.join(directory, name);
1130
- write_reservation(target, weight, claimed_at);
1131
- await await_admission({
1240
+ const name = marker_name(randomUUID());
1241
+ const target2 = path2.join(directory, name);
1242
+ const fields = { weight, claimed_at, memory_mb: options.memory_mb };
1243
+ write_reservation(target2, fields);
1244
+ const admission = await await_admission({
1132
1245
  ...timing,
1133
1246
  key: name,
1247
+ target: target2,
1134
1248
  directory,
1135
- budget,
1136
- deadline: claimed_at + (options.wait_cap_ms ?? WAIT_CAP_MS)
1249
+ budget: normalize_budget(options.budget ?? availableParallelism3()),
1250
+ deadline: claimed_at + timing.wait_cap_ms,
1251
+ fields,
1252
+ read_machine: options.read_machine ?? machine_capacity.read_machine
1137
1253
  });
1138
- return { target };
1254
+ return { target: target2, admission };
1139
1255
  }
1140
1256
  function release(handle) {
1141
1257
  sweep_marker2(handle.target);
@@ -1143,7 +1259,7 @@ function release(handle) {
1143
1259
  async function with_core_reservation(weight, run, options = {}) {
1144
1260
  const handle = await reserve(weight, options);
1145
1261
  try {
1146
- return await run();
1262
+ return await run(handle.admission);
1147
1263
  } finally {
1148
1264
  release(handle);
1149
1265
  }
@@ -1171,9 +1287,11 @@ var core_budget = {
1171
1287
  CORE_WEIGHTS,
1172
1288
  HELD_KEY,
1173
1289
  HELD_VALUE,
1290
+ MEMORY_MB,
1174
1291
  RESERVED_PREFIX,
1175
- admitted_keys,
1176
- admitted_load,
1292
+ admitted_keys: core_admission.admitted_keys,
1293
+ admitted_load: core_admission.admitted_load,
1294
+ describe_overflow: core_admission.describe_overflow,
1177
1295
  is_held,
1178
1296
  live_reservations,
1179
1297
  release,
@@ -1184,7 +1302,7 @@ var core_budget = {
1184
1302
  };
1185
1303
 
1186
1304
  // scripts/gate/gate-plan.ts
1187
- import { availableParallelism as availableParallelism3 } from "node:os";
1305
+ import { availableParallelism as availableParallelism4 } from "node:os";
1188
1306
 
1189
1307
  // scripts/lib/status-icons.ts
1190
1308
  var FAIL_ICON = "\u2717";
@@ -1232,28 +1350,53 @@ var LINT_LABEL = "lint";
1232
1350
  var TYPE_CHECK_LABEL = "check";
1233
1351
  var UNIT_LABEL = "test:unit";
1234
1352
  var BEHAVIOR_LABEL = "behavior";
1353
+ var METRICS_LABEL = "metrics";
1235
1354
  var WARNING_CHECKER_LABELS = [LINT_LABEL, TYPE_CHECK_LABEL];
1236
1355
  var STATIC_CHECKS = [
1237
- { label: LINT_LABEL, target: "lint", reserved_cores: core_budget.CORE_WEIGHTS.lint },
1356
+ {
1357
+ label: LINT_LABEL,
1358
+ target: "lint",
1359
+ reserved_cores: core_budget.CORE_WEIGHTS.lint,
1360
+ memory_mb: core_budget.MEMORY_MB.lint
1361
+ },
1238
1362
  {
1239
1363
  label: TYPE_CHECK_LABEL,
1240
1364
  target: "check",
1241
- reserved_cores: core_budget.CORE_WEIGHTS.type_check
1365
+ reserved_cores: core_budget.CORE_WEIGHTS.type_check,
1366
+ memory_mb: core_budget.MEMORY_MB.type_check
1367
+ },
1368
+ {
1369
+ label: "cspell",
1370
+ target: "cspell:dot",
1371
+ reserved_cores: core_budget.CORE_WEIGHTS.spell_check,
1372
+ memory_mb: core_budget.MEMORY_MB.spell_check
1242
1373
  },
1243
- { label: "cspell", target: "cspell:dot", reserved_cores: core_budget.CORE_WEIGHTS.spell_check },
1244
1374
  { label: BEHAVIOR_LABEL, target: BEHAVIOR_LABEL, reserved_cores: 0 },
1245
- // **The unused-member check reserves no core** (joshuafolkken/kit#2987): it builds one TypeScript
1375
+ // **The unused-member check reserves no core**: it builds one TypeScript
1246
1376
  // program and walks it for about 5s, and it is over well before lint and the type check. A
1247
1377
  // reservation would only take a place from the four-core CI runner's fan-out and a worker from the
1248
1378
  // unit suite for the whole gate.
1249
- { label: "exports", target: "exports:unused", reserved_cores: 0 }
1379
+ { label: "exports", target: "exports:unused", reserved_cores: 0 },
1380
+ // **The metrics ratchet is kit's own**: it holds kit's repository-wide
1381
+ // totals to the merge-base's. It is one in-process eslint pass with only `max-lines` enabled, over
1382
+ // in a few seconds, so it reserves no core for the reason the unused-member check above does not.
1383
+ // It times no startup here: beside the unit suite that reads the load, not josh.
1384
+ {
1385
+ label: METRICS_LABEL,
1386
+ target: METRICS_LABEL,
1387
+ args: ["--no-startup"],
1388
+ reserved_cores: 0,
1389
+ memory_mb: core_budget.MEMORY_MB.eslint_scan,
1390
+ is_kit_only: true
1391
+ }
1250
1392
  ];
1251
1393
  var GATE_CHECKS = [
1252
1394
  ...STATIC_CHECKS,
1253
1395
  { label: UNIT_LABEL, target: UNIT_LABEL, reserved_cores: 0 }
1254
1396
  ];
1255
- function select_gate_checks(is_unit_included) {
1256
- return is_unit_included ? GATE_CHECKS : STATIC_CHECKS;
1397
+ function select_gate_checks(is_unit_included, is_kit_repository = true) {
1398
+ const checks = is_unit_included ? GATE_CHECKS : STATIC_CHECKS;
1399
+ return is_kit_repository ? checks : checks.filter((check) => check.is_kit_only !== true);
1257
1400
  }
1258
1401
  function has_unit_check(checks) {
1259
1402
  return checks.some((check) => check.label === UNIT_LABEL);
@@ -1293,19 +1436,33 @@ function check_weight(check, plan, available_cores) {
1293
1436
  if (check.label !== UNIT_LABEL) return check.reserved_cores;
1294
1437
  return plan.unit_worker_cap ?? solo_unit_weight(available_cores);
1295
1438
  }
1296
- function direct_unit_weight(available_cores = availableParallelism3(), live_runs = unit_worker_share.live_run_count()) {
1439
+ function unit_memory(workers) {
1440
+ return workers * core_budget.MEMORY_MB.unit_worker;
1441
+ }
1442
+ function check_memory(check, plan, available_cores) {
1443
+ if (check.label !== UNIT_LABEL) return check.memory_mb ?? 0;
1444
+ return unit_memory(check_weight(check, plan, available_cores));
1445
+ }
1446
+ function direct_unit_weight(available_cores = availableParallelism4(), live_runs = unit_worker_share.live_run_count()) {
1297
1447
  const weight = unit_worker_share.current_share(available_cores, live_runs) ?? solo_unit_weight(available_cores);
1298
1448
  return Math.max(unit_worker_share.MIN_WORKERS, weight);
1299
1449
  }
1450
+ function direct_unit_memory() {
1451
+ return unit_memory(direct_unit_weight());
1452
+ }
1453
+ function unit_cap_for(checks, available_cores, concurrent_runs) {
1454
+ if (!has_unit_check(checks)) return void 0;
1455
+ return resolve_unit_worker_cap(available_cores, concurrent_runs);
1456
+ }
1300
1457
  function plan_of(concurrency, unit_worker_cap, checks = GATE_CHECKS) {
1301
1458
  return { checks, concurrency, unit_worker_cap };
1302
1459
  }
1303
- function resolve_gate_plan(available_cores = availableParallelism3(), concurrent_runs = unit_worker_share.SOLO_RUNS, is_unit_included = true) {
1304
- const checks = select_gate_checks(is_unit_included);
1460
+ function resolve_gate_plan(available_cores = availableParallelism4(), concurrent_runs = unit_worker_share.SOLO_RUNS, is_unit_included = true, is_kit_repository = true) {
1461
+ const checks = select_gate_checks(is_unit_included, is_kit_repository);
1305
1462
  return {
1306
1463
  checks,
1307
1464
  concurrency: resolve_concurrency(available_cores, concurrent_runs, checks),
1308
- unit_worker_cap: is_unit_included ? resolve_unit_worker_cap(available_cores, concurrent_runs) : void 0
1465
+ unit_worker_cap: unit_cap_for(checks, available_cores, concurrent_runs)
1309
1466
  };
1310
1467
  }
1311
1468
  function format_machine(available_cores, concurrent_runs) {
@@ -1318,7 +1475,7 @@ function format_unit_cap(plan) {
1318
1475
  if (plan.unit_worker_cap === void 0) return `${UNIT_LABEL} unrestricted`;
1319
1476
  return `${UNIT_LABEL} at ${String(plan.unit_worker_cap)} workers`;
1320
1477
  }
1321
- function format_gate_plan(plan, available_cores = availableParallelism3(), concurrent_runs = unit_worker_share.SOLO_RUNS) {
1478
+ function format_gate_plan(plan, available_cores = availableParallelism4(), concurrent_runs = unit_worker_share.SOLO_RUNS) {
1322
1479
  const cap = format_unit_cap(plan);
1323
1480
  const count = `${String(plan.concurrency)} of ${String(plan.checks.length)}`;
1324
1481
  const width = `${count}${josh_verdict.GATE_OPENING_MARK}`;
@@ -1329,12 +1486,15 @@ var gate_plan = {
1329
1486
  GATE_CHECKS,
1330
1487
  LINT_LABEL,
1331
1488
  MEASURED_CORES,
1489
+ METRICS_LABEL,
1332
1490
  RESERVED_CORES,
1333
1491
  STATIC_CHECKS,
1334
1492
  TYPE_CHECK_LABEL,
1335
1493
  UNIT_LABEL,
1336
1494
  WARNING_CHECKER_LABELS,
1495
+ check_memory,
1337
1496
  check_weight,
1497
+ direct_unit_memory,
1338
1498
  direct_unit_weight,
1339
1499
  format_gate_plan,
1340
1500
  format_machine,
@@ -1370,28 +1530,45 @@ var DEV_COMMANDS = {
1370
1530
  description: "Check code with prettier and eslint (skips a tool a basic project lacks)",
1371
1531
  category: "Development",
1372
1532
  reference: ["", "developer", ["processes"]],
1373
- core_weight: core_budget.CORE_WEIGHTS.lint
1533
+ core_weight: core_budget.CORE_WEIGHTS.lint,
1534
+ memory_mb: core_budget.MEMORY_MB.lint
1374
1535
  },
1375
1536
  "lint:related": {
1376
1537
  script: "scripts/lint/lint-related.ts",
1377
1538
  description: "Check only the changed files with prettier and eslint (whole tree on fallback)",
1378
1539
  category: "Development",
1379
1540
  reference: [FILE_ARGUMENTS, "developer", ["processes"]],
1380
- core_weight: core_budget.CORE_WEIGHTS.lint
1541
+ core_weight: core_budget.CORE_WEIGHTS.lint,
1542
+ memory_mb: core_budget.MEMORY_MB.lint
1381
1543
  },
1382
1544
  lines: {
1383
1545
  script: "scripts/lines/lines-command.ts",
1384
1546
  description: "Print a file's code lines against the max-lines limit and the headroom left",
1385
1547
  category: "Development",
1386
1548
  reference: [REQUIRED_FILE_ARGUMENTS, "developer", ["none"]],
1387
- core_weight: core_budget.CORE_WEIGHTS.eslint_scan
1549
+ core_weight: core_budget.CORE_WEIGHTS.eslint_scan,
1550
+ memory_mb: core_budget.MEMORY_MB.eslint_scan
1551
+ },
1552
+ metrics: {
1553
+ script: "scripts/metrics/metrics-command.ts",
1554
+ description: "Print repository-wide quality totals and durations, and fail when a total grew past the merge-base or a duration past its baseline",
1555
+ category: "Development",
1556
+ reference: [
1557
+ '[--no-startup | --totals-only | --accept --reason "<why>"]',
1558
+ "developer",
1559
+ ["files"]
1560
+ ],
1561
+ core_weight: core_budget.CORE_WEIGHTS.eslint_scan,
1562
+ memory_mb: core_budget.MEMORY_MB.eslint_scan,
1563
+ is_kit_only: true
1388
1564
  },
1389
1565
  "refactor:scan": {
1390
1566
  script: "scripts/refactor/refactor-scan-cli.ts",
1391
1567
  description: "List refactoring candidates in the changed scope by category and answer clear/candidates",
1392
1568
  category: "Development",
1393
1569
  reference: ["", "automation", ["processes"]],
1394
- core_weight: core_budget.CORE_WEIGHTS.eslint_scan
1570
+ core_weight: core_budget.CORE_WEIGHTS.eslint_scan,
1571
+ memory_mb: core_budget.MEMORY_MB.eslint_scan
1395
1572
  },
1396
1573
  bytes: {
1397
1574
  script: "scripts/lines/bytes-command.ts",
@@ -1405,6 +1582,12 @@ var DEV_COMMANDS = {
1405
1582
  category: "AI tools",
1406
1583
  reference: ["[--refresh]", "developer", ["files"]]
1407
1584
  },
1585
+ "rule:list": {
1586
+ script: "scripts/rules/rule-list.ts",
1587
+ description: "Print the trigger-delivered rules \u2014 each one's source, firing call and silent turn \u2014 from the guard rows",
1588
+ category: "AI tools",
1589
+ reference: ["", "automation", ["none"]]
1590
+ },
1408
1591
  format: {
1409
1592
  script: "scripts/lint/format.ts",
1410
1593
  description: "Format code with prettier and eslint (skips a tool a basic project lacks)",
@@ -1425,8 +1608,8 @@ var DEV_COMMANDS = {
1425
1608
  // **No `tsx_arguments`, deliberately.** `JOSH_BATCH_GUARD` is a per-machine preference kept in
1426
1609
  // `.env`, which every other command reads through `OPTIONAL_ENV_FILE_FLAGS` — but declaring any
1427
1610
  // `tsx_arguments` disqualifies a command from in-process dispatch (`josh-in-process.ts`), and
1428
- // this one runs before every `Bash` call. That is the hot path joshuafolkken/kit#1342 took a
1429
- // second ~0.16 s tsx start off. The script calls `process.loadEnvFile` itself instead, which is
1611
+ // this one runs before every `Bash` call, where a second ~0.16 s tsx start is not affordable.
1612
+ // The script calls `process.loadEnvFile` itself instead, which is
1430
1613
  // node's own `--env-file` parser with node's own precedence.
1431
1614
  },
1432
1615
  "pretool:guard": {
@@ -1450,7 +1633,7 @@ var DEV_COMMANDS = {
1450
1633
  },
1451
1634
  "session:lang": {
1452
1635
  script: "scripts/josh/session-language-cli.ts",
1453
- description: "Claude Code hook: print the resolved JOSH_SESSION_LANG (defaults to ja) for the session context",
1636
+ description: "Claude Code hook: print a non-default JOSH_SESSION_LANG for the session context, and the run:board reply rule while a backlogrun is live (otherwise nothing)",
1454
1637
  category: "Development",
1455
1638
  reference: ["", "automation", ["none"]]
1456
1639
  // **No `tsx_arguments`, deliberately**, the same as `batch:guard` above: this runs on every
@@ -1463,7 +1646,7 @@ var DEV_COMMANDS = {
1463
1646
  category: "Development",
1464
1647
  reference: ["<pretool|posttool>", "automation", ["none"]]
1465
1648
  // The live-source fallback `scripts/hooks/run-hook.sh` derives from the `codex-hook-adapter`
1466
- // bundle name (joshuafolkken/kit#3184). **No `tsx_arguments`**, the same as `pretool:guard`
1649
+ // bundle name. **No `tsx_arguments`**, the same as `pretool:guard`
1467
1650
  // above: it runs before every guarded Codex call.
1468
1651
  },
1469
1652
  "cspell:dot": {
@@ -1471,7 +1654,8 @@ var DEV_COMMANDS = {
1471
1654
  description: "Run spell check including dotfiles",
1472
1655
  category: "Development",
1473
1656
  reference: ["", "developer", ["processes"]],
1474
- core_weight: core_budget.CORE_WEIGHTS.spell_check
1657
+ core_weight: core_budget.CORE_WEIGHTS.spell_check,
1658
+ memory_mb: core_budget.MEMORY_MB.spell_check
1475
1659
  },
1476
1660
  behavior: {
1477
1661
  script: "scripts/behavior/behavior-cli.ts",
@@ -1490,14 +1674,16 @@ var DEV_COMMANDS = {
1490
1674
  description: "Run unit tests with Vitest (skips when Vitest is absent; fails when it has no tests)",
1491
1675
  category: "Development",
1492
1676
  reference: [FILTER_ARGUMENTS, "developer", ["processes"]],
1493
- core_weight: gate_plan.direct_unit_weight
1677
+ core_weight: gate_plan.direct_unit_weight,
1678
+ memory_mb: gate_plan.direct_unit_memory
1494
1679
  },
1495
1680
  "test:related": {
1496
1681
  script: "scripts/test/test-related.ts",
1497
1682
  description: "Run only the unit tests related to the changed files (full suite on fallback)",
1498
1683
  category: "Development",
1499
1684
  reference: [FILE_ARGUMENTS, "developer", ["processes"]],
1500
- core_weight: gate_plan.direct_unit_weight
1685
+ core_weight: gate_plan.direct_unit_weight,
1686
+ memory_mb: gate_plan.direct_unit_memory
1501
1687
  },
1502
1688
  "test:declared": {
1503
1689
  script: "scripts/test/test-declared.ts",
@@ -1541,7 +1727,8 @@ var DEV_COMMANDS = {
1541
1727
  description: "Type-check with tsc (skips a basic project with no TypeScript to check)",
1542
1728
  category: "Development",
1543
1729
  reference: ["[arguments...]", "developer", ["processes"]],
1544
- core_weight: core_budget.CORE_WEIGHTS.type_check
1730
+ core_weight: core_budget.CORE_WEIGHTS.type_check,
1731
+ memory_mb: core_budget.MEMORY_MB.type_check
1545
1732
  },
1546
1733
  port: {
1547
1734
  script: "scripts/ports/port-command.ts",
@@ -1662,9 +1849,9 @@ var MAINTENANCE_COMMANDS = {
1662
1849
  shell: [
1663
1850
  "sh",
1664
1851
  "-c",
1665
- "export NODE_AUTH_TOKEN=$(gh auth token) && pnpm josh latest:guard && pnpm josh latest:corepack && pnpm josh latest:update && pnpm josh ranges && pnpm josh audit && pnpm josh latest:scope --record"
1852
+ "export NODE_AUTH_TOKEN=$(gh auth token) && pnpm josh latest:guard && pnpm josh latest:update && pnpm josh ranges && pnpm josh audit && pnpm josh latest:corepack && pnpm josh latest:scope --record"
1666
1853
  ],
1667
- description: "Update pnpm, dependencies, and run security audit",
1854
+ description: "Update dependencies, run security audit, then update pnpm",
1668
1855
  category: "Maintenance",
1669
1856
  reference: ["", "developer", ["files", "network", "processes"]],
1670
1857
  argument_targets: ["latest:corepack", "latest:update", "audit"]
@@ -1813,16 +2000,16 @@ var VERSIONING_COMMANDS = {
1813
2000
  category: "Versioning",
1814
2001
  reference: ["", "developer", ["network"]]
1815
2002
  },
1816
- // The one place that decides a version (joshuafolkken/kit#1169). A `script` entry for the same
2003
+ // The one place that decides a version. A `script` entry for the same
1817
2004
  // reason `ranges` is one: script paths resolve against the kit package root, so it keeps working
1818
2005
  // from a consumer repository where the file lives under node_modules.
1819
2006
  release: {
1820
2007
  script: "scripts/release/release-cli.ts",
1821
2008
  description: "Release the merges main has taken since the version last changed",
1822
2009
  category: "Versioning",
1823
- reference: ["[version]", "maintainer", ["git", "network", "release"]]
2010
+ reference: ["[--dry-run]", "maintainer", ["git", "network", "release"]]
1824
2011
  },
1825
- // The read-only half of the one above (joshuafolkken/kit#1582). `release --dry-run` cannot
2012
+ // The read-only half of the one above. `release --dry-run` cannot
1826
2013
  // answer this question: it refuses off the default branch and on a dirty tree, which is every
1827
2014
  // position a run asks it from. A `script` entry for the same reason `release` is one.
1828
2015
  "release:scope": {
@@ -1831,8 +2018,8 @@ var VERSIONING_COMMANDS = {
1831
2018
  category: "Versioning",
1832
2019
  reference: ["[--json]", "automation", ["none"]]
1833
2020
  },
1834
- // Run by the release workflows, kit's and the one sync distributes, after a tag has published
1835
- // (joshuafolkken/kit#3007). Settings come from the environment, so the workflow decides them.
2021
+ // Run by the release workflows, kit's and the one sync distributes, after a tag has published.
2022
+ // Settings come from the environment, so the workflow decides them.
1836
2023
  "release:github": {
1837
2024
  script: "scripts/release/github-release-cli.ts",
1838
2025
  description: "Create the GitHub Release for a published tag, with generated notes",
@@ -1860,20 +2047,17 @@ var WORKFLOW_COMMANDS = {
1860
2047
  reference: ["<message>", "developer", ["network"]],
1861
2048
  default_script_arguments: ["-y", "--skip-commit", "--skip-push"]
1862
2049
  },
1863
- // **The optional form, on both** (joshuafolkken/kit#1564). These two were the last commands
1864
- // passing the mandatory `--env-file=.env`, which node resolves before the script's first line: on
1865
- // a machine with no `.env` they died as `.env: not found` with exit code 9, even where
1866
- // `TELEGRAM_BOT_TOKEN` and `TELEGRAM_CHAT_ID` existed as real environment variables — a cloud
1867
- // session, and `followup` with them the merge step of every `fullrun` there. `doctor` was moved to
1868
- // this form for the same reason in joshuafolkken/kit#869.
2050
+ // **The optional form, on both**. The mandatory `--env-file=.env` is resolved by node before the
2051
+ // script's first line: on a machine with no `.env` it dies as `.env: not found` with exit code 9,
2052
+ // even where `TELEGRAM_BOT_TOKEN` and `TELEGRAM_CHAT_ID` exist as real environment variables — a
2053
+ // cloud session, and `followup` with them the merge step of every `fullrun` there.
1869
2054
  //
1870
2055
  // Nothing is lost by relaxing it: both scripts already load `.env` through `josh_environment_file`
1871
2056
  // themselves, so the file is read either way and node's precedence — an existing environment
1872
2057
  // variable wins over the file — is node's own in both spellings.
1873
2058
  //
1874
- // **What the mandatory flag was accidentally providing was noise**, and that is replaced rather
1875
- // than dropped: `telegram_notify.send` now throws on missing credentials and on a failed send, so
1876
- // `josh notify` exits non-zero instead of warning and answering 0.
2059
+ // **A missing credential still fails loudly**: `telegram_notify.send` throws on missing credentials
2060
+ // and on a failed send, so `josh notify` exits non-zero instead of warning and answering 0.
1877
2061
  followup: {
1878
2062
  script: "scripts/followup/git-followup-workflow.ts",
1879
2063
  description: "Follow-up git workflow",
@@ -1889,11 +2073,23 @@ var WORKFLOW_COMMANDS = {
1889
2073
  script: "scripts/notify/telegram-test.ts",
1890
2074
  description: "Send Telegram notification",
1891
2075
  category: "Workflow",
1892
- reference: ["--task-type <type> --body <text>", "automation", ["notifications"]],
2076
+ reference: [
2077
+ "[--task-type <type>] [--body <text> | --body-file <path>] [--issue-url <url>] [--pr-url <url>] [--issue-title <text>] [--repo-name <name>]",
2078
+ "automation",
2079
+ ["notifications"]
2080
+ ],
1893
2081
  tsx_arguments: OPTIONAL_ENV_FILE_FLAGS
1894
2082
  },
1895
- // The observation ledger's commit path for the lines no run's own commit carried
1896
- // (joshuafolkken/kit#1756, joshuafolkken/kit#2763): a lane's lines sit in the primary checkout, which
2083
+ // One observation-ledger sighting: the key's count, the append and the second-sighting verdict,
2084
+ // which a run used to type as a `cat | grep -c` and judge by hand.
2085
+ "observation:record": {
2086
+ script: "scripts/observations/observation-record-cli.ts",
2087
+ description: "Record an observation sighting and answer whether it is now filed",
2088
+ category: "Workflow",
2089
+ reference: ["<key> <depth> <where> <what> [--checkout <path>]", "automation", ["files"]]
2090
+ },
2091
+ // The observation ledger's commit path for the lines no run's own commit carried:
2092
+ // a lane's lines sit in the primary checkout, which
1897
2093
  // its commit cannot see, and the recurrence count the promotion rule reads is a count of main.
1898
2094
  "observations:flush": {
1899
2095
  script: "scripts/observations/observations-flush-cli.ts",
@@ -1901,8 +2097,8 @@ var WORKFLOW_COMMANDS = {
1901
2097
  category: "Workflow",
1902
2098
  reference: ["", "automation", ["git", "network"]]
1903
2099
  },
1904
- // The one write path for a `/code-review` round's findings (joshuafolkken/kit#2325), plus the
1905
- // `--check` gate `followup` runs before it merges (joshuafolkken/kit#2343). It appends a `- rf:`
2100
+ // The one write path for a `/code-review` round's findings, plus the
2101
+ // `--check` gate `followup` runs before it merges. It appends a `- rf:`
1906
2102
  // line per finding — or one zero-finding line for a clean round — to the observation ledger, so
1907
2103
  // `observations:flush` commits them and the recurrence count survives the run.
1908
2104
  "review:record": {
@@ -1910,12 +2106,12 @@ var WORKFLOW_COMMANDS = {
1910
2106
  description: "Record a review round\u2019s findings, or check a round was recorded",
1911
2107
  category: "Workflow",
1912
2108
  reference: [
1913
- "--issue <N> [<category>:<severity>:<file> ...] | --check --issue <N>",
2109
+ "--issue <N> [--comment] [<category>:<severity>:<file> ...] | --check --issue <N>",
1914
2110
  "automation",
1915
- ["files"]
2111
+ ["files", "network"]
1916
2112
  ]
1917
2113
  },
1918
- // The reader over what `review:record` wrote (joshuafolkken/kit#2325): each recurring category’s
2114
+ // The reader over what `review:record` wrote: each recurring category’s
1919
2115
  // count, and the number of zero-finding rounds that distinguishes a quiet category from an unwatched one.
1920
2116
  "review:findings": {
1921
2117
  script: "scripts/review/review-findings-cli.ts",
@@ -1924,7 +2120,7 @@ var WORKFLOW_COMMANDS = {
1924
2120
  reference: ["", "developer", ["files"]]
1925
2121
  },
1926
2122
  // After a behavior-change Issue merges, re-run its declared baseline and print before/after; a value
1927
- // that did not move appends a refuted-premise line to the observation ledger (joshuafolkken/kit#2212).
2123
+ // that did not move appends a refuted-premise line to the observation ledger.
1928
2124
  "measure:rerun": {
1929
2125
  script: "scripts/issue/measure-rerun-cli.ts",
1930
2126
  description: "Re-run a merged issue\u2019s baseline command and print the before/after pair",
@@ -1932,7 +2128,7 @@ var WORKFLOW_COMMANDS = {
1932
2128
  reference: ["<issue-number>", "automation", ["network", "processes", "files"]]
1933
2129
  },
1934
2130
  // A script rather than an `sh -c` chain, because it has a precondition to enforce: run inside a
1935
- // linked work tree it would hijack the default branch from every other one (joshuafolkken/kit#1535).
2131
+ // linked work tree it would hijack the default branch from every other one.
1936
2132
  "main:sync": {
1937
2133
  script: "scripts/git/main-sync.ts",
1938
2134
  description: "Checkout default branch, pull latest, and prune merged remote-gone branches (refuses inside a lane)",
@@ -1940,9 +2136,8 @@ var WORKFLOW_COMMANDS = {
1940
2136
  reference: ["", "developer", ["git", "network"]]
1941
2137
  },
1942
2138
  // A script rather than an `sh -c` chain, because the strategy has to be named rather than left to
1943
- // the caller's git configuration: the `git pull` this replaced aborted with `Need to specify how
1944
- // to reconcile divergent branches` on exactly the diverged branch the command exists for
1945
- // (joshuafolkken/kit#1659).
2139
+ // the caller's git configuration: a bare `git pull` aborts with `Need to specify how to reconcile
2140
+ // divergent branches` on exactly the diverged branch the command exists for.
1946
2141
  "main:merge": {
1947
2142
  script: "scripts/git/main-merge.ts",
1948
2143
  description: "Merge origin default branch into the current branch",
@@ -1969,6 +2164,7 @@ var ALIASES = {
1969
2164
  lr: "lint:related",
1970
2165
  ln: "lines",
1971
2166
  by: "bytes",
2167
+ mt: "metrics",
1972
2168
  f: "format",
1973
2169
  sd: "cspell:dot",
1974
2170
  bh: "behavior",
@@ -2011,7 +2207,9 @@ var ALIASES = {
2011
2207
  ruv: "rule:value",
2012
2208
  ev: "eval",
2013
2209
  lsm: "lane:sample",
2014
- lst: "lane:stats"
2210
+ lst: "lane:stats",
2211
+ lli: "lane:limit",
2212
+ blr: "backlogrun"
2015
2213
  };
2016
2214
  function canonical_command(name) {
2017
2215
  if (!Object.hasOwn(ALIASES, name)) return name;
@@ -2234,74 +2432,74 @@ var time_background = {
2234
2432
  };
2235
2433
 
2236
2434
  // scripts/git/git-schemas.ts
2237
- import { z as z4 } from "zod";
2238
- var package_name_schema = z4.object({ name: z4.string().min(1) });
2239
- var rollup_item_schema = z4.looseObject({
2435
+ import { z as z3 } from "zod";
2436
+ var package_name_schema = z3.object({ name: z3.string().min(1) });
2437
+ var rollup_item_schema = z3.looseObject({
2240
2438
  // eslint-disable-next-line @typescript-eslint/naming-convention -- GraphQL field name from GitHub API
2241
- __typename: z4.string().optional(),
2242
- state: z4.string().optional(),
2243
- status: z4.string().optional(),
2244
- conclusion: z4.string().optional(),
2245
- name: z4.string().optional(),
2246
- context: z4.string().optional()
2439
+ __typename: z3.string().optional(),
2440
+ state: z3.string().optional(),
2441
+ status: z3.string().optional(),
2442
+ conclusion: z3.string().optional(),
2443
+ name: z3.string().optional(),
2444
+ context: z3.string().optional()
2247
2445
  });
2248
- var pr_raw_schema = z4.object({
2249
- statusCheckRollup: z4.array(rollup_item_schema).optional(),
2250
- mergeStateStatus: z4.string().optional(),
2251
- reviewDecision: z4.string().optional()
2446
+ var pr_raw_schema = z3.object({
2447
+ statusCheckRollup: z3.array(rollup_item_schema).optional(),
2448
+ mergeStateStatus: z3.string().optional(),
2449
+ reviewDecision: z3.string().optional()
2252
2450
  });
2253
- var pull_comment_schema = z4.object({
2254
- body: z4.string().optional(),
2255
- html_url: z4.string().optional(),
2256
- user: z4.object({ login: z4.string().optional() }).optional()
2451
+ var pull_comment_schema = z3.object({
2452
+ body: z3.string().optional(),
2453
+ html_url: z3.string().optional(),
2454
+ user: z3.object({ login: z3.string().optional() }).optional()
2257
2455
  });
2258
- var ai_review_pull_comment_schema = z4.object({
2259
- body: z4.string().optional(),
2260
- url: z4.string().optional(),
2261
- author: z4.object({ login: z4.string().optional() }).optional()
2456
+ var ai_review_pull_comment_schema = z3.object({
2457
+ body: z3.string().optional(),
2458
+ url: z3.string().optional(),
2459
+ author: z3.object({ login: z3.string().optional() }).optional()
2262
2460
  });
2263
- var pr_info_schema = z4.object({
2264
- mergeable: z4.union([z4.boolean(), z4.string()]).nullable().optional(),
2265
- mergeStateStatus: z4.string().nullable().optional(),
2266
- state: z4.string().optional()
2461
+ var pr_info_schema = z3.object({
2462
+ mergeable: z3.union([z3.boolean(), z3.string()]).nullable().optional(),
2463
+ mergeStateStatus: z3.string().nullable().optional(),
2464
+ state: z3.string().optional()
2267
2465
  });
2268
- var epic_issue_schema = z4.object({
2269
- number: z4.number(),
2270
- body: z4.string().optional()
2466
+ var epic_issue_schema = z3.object({
2467
+ number: z3.number(),
2468
+ body: z3.string().optional()
2271
2469
  });
2272
- var blocking_issue_schema = z4.object({
2273
- number: z4.number(),
2274
- state: z4.string().optional(),
2275
- repository_url: z4.string().optional()
2470
+ var blocking_issue_schema = z3.object({
2471
+ number: z3.number(),
2472
+ state: z3.string().optional(),
2473
+ repository_url: z3.string().optional()
2276
2474
  });
2277
- var blocked_by_schema = z4.object({
2278
- nodes: z4.array(blocking_issue_schema).default([]),
2279
- totalCount: z4.number().optional()
2475
+ var blocked_by_schema = z3.object({
2476
+ nodes: z3.array(blocking_issue_schema).default([]),
2477
+ totalCount: z3.number().optional()
2280
2478
  }).optional();
2281
- var epic_child_schema = z4.object({
2282
- state: z4.string().optional(),
2479
+ var epic_child_schema = z3.object({
2480
+ state: z3.string().optional(),
2283
2481
  blockedBy: blocked_by_schema
2284
2482
  });
2285
- var rest_comment_schema = z4.looseObject({
2286
- body: z4.string().nullish(),
2287
- html_url: z4.string().optional(),
2288
- user: z4.looseObject({ login: z4.string().optional() }).nullish()
2483
+ var rest_comment_schema = z3.looseObject({
2484
+ body: z3.string().nullish(),
2485
+ html_url: z3.string().optional(),
2486
+ user: z3.looseObject({ login: z3.string().optional() }).nullish()
2289
2487
  });
2290
- var issue_label_schema = z4.object({ name: z4.string() });
2291
- var epic_subject_schema = z4.object({
2292
- number: z4.number(),
2293
- state: z4.string().optional(),
2294
- labels: z4.array(issue_label_schema).optional(),
2295
- body: z4.string().optional()
2488
+ var issue_label_schema = z3.object({ name: z3.string() });
2489
+ var epic_subject_schema = z3.object({
2490
+ number: z3.number(),
2491
+ state: z3.string().optional(),
2492
+ labels: z3.array(issue_label_schema).optional(),
2493
+ body: z3.string().optional()
2296
2494
  });
2297
- var open_issue_schema = z4.object({
2298
- number: z4.number(),
2299
- title: z4.string(),
2300
- labels: z4.array(issue_label_schema).optional(),
2301
- createdAt: z4.string(),
2495
+ var open_issue_schema = z3.object({
2496
+ number: z3.number(),
2497
+ title: z3.string(),
2498
+ labels: z3.array(issue_label_schema).optional(),
2499
+ createdAt: z3.string(),
2302
2500
  blockedBy: blocked_by_schema,
2303
- // Present only on the pickup listing, which reads it for the restructures each issue declares.
2304
- body: z4.string().optional()
2501
+ // Present only on the pickup listing, which reads it for the paths each issue declares.
2502
+ body: z3.string().optional()
2305
2503
  });
2306
2504
 
2307
2505
  // scripts/gh/git-pr-checks-parse.ts
@@ -2477,9 +2675,135 @@ var PrConflictError = class extends Error {
2477
2675
  name = "PrConflictError";
2478
2676
  };
2479
2677
 
2678
+ // scripts/lane/lane-ledger.ts
2679
+ import { closeSync, constants, openSync, writeSync } from "node:fs";
2680
+ import { z as z4 } from "zod";
2681
+ var LEDGER_PREFIX = "josh-lane-ledger-";
2682
+ var LEDGER_SUFFIX = ".jsonl";
2683
+ var LINE_SEPARATOR = "\n";
2684
+ var CI_WAIT_STAGE = "ci-wait";
2685
+ var LEDGER_FILE_MODE = 384;
2686
+ var { O_APPEND, O_CREAT, O_NOFOLLOW, O_WRONLY } = constants;
2687
+ var APPEND_FLAGS = O_WRONLY | O_APPEND | O_CREAT | O_NOFOLLOW;
2688
+ var KIND = {
2689
+ MERGE: "merge",
2690
+ GATE: "gate",
2691
+ LOAD: "load",
2692
+ DISPATCH: "dispatch",
2693
+ STAGE: "stage"
2694
+ };
2695
+ var merge_schema = z4.object({ kind: z4.literal(KIND.MERGE), at: z4.string(), issue: z4.number() });
2696
+ var gate_schema = z4.object({
2697
+ kind: z4.literal(KIND.GATE),
2698
+ at: z4.string(),
2699
+ elapsed_ms: z4.number(),
2700
+ is_passed: z4.boolean(),
2701
+ // The unit suite's own duration, present when this gate ran it — the one
2702
+ // record of a full vitest run `josh metrics` reads, so the suite is never timed twice.
2703
+ unit_ms: z4.number().optional(),
2704
+ // The whole cores busy outside this gate, beyond the machine's baseline, at its start or its end —
2705
+ // whichever was higher. Absent when the machine could not be read.
2706
+ external_cores: z4.number().optional()
2707
+ });
2708
+ var load_schema = z4.object({
2709
+ kind: z4.literal(KIND.LOAD),
2710
+ at: z4.string(),
2711
+ load: z4.number(),
2712
+ available_mb: z4.number().optional(),
2713
+ swapped_mb: z4.number().optional(),
2714
+ lanes: z4.number().optional()
2715
+ });
2716
+ var dispatch_schema = z4.object({
2717
+ kind: z4.literal(KIND.DISPATCH),
2718
+ at: z4.string(),
2719
+ issue: z4.number()
2720
+ });
2721
+ var stage_schema = z4.object({
2722
+ kind: z4.literal(KIND.STAGE),
2723
+ at: z4.string(),
2724
+ stage: z4.string(),
2725
+ elapsed_ms: z4.number(),
2726
+ issue: z4.number().optional()
2727
+ });
2728
+ var entry_schema = z4.discriminatedUnion("kind", [
2729
+ merge_schema,
2730
+ gate_schema,
2731
+ load_schema,
2732
+ dispatch_schema,
2733
+ stage_schema
2734
+ ]);
2735
+ function target_of(repository) {
2736
+ return stamp_file.stamp_path(LEDGER_PREFIX, repository, LEDGER_SUFFIX);
2737
+ }
2738
+ async function target() {
2739
+ if (process.env["VITEST"] !== void 0) return void 0;
2740
+ try {
2741
+ const repository = await run_carry.repository_directory();
2742
+ return repository === void 0 ? void 0 : target_of(repository);
2743
+ } catch {
2744
+ return void 0;
2745
+ }
2746
+ }
2747
+ function append(path4, entry) {
2748
+ const descriptor = openSync(path4, APPEND_FLAGS, LEDGER_FILE_MODE);
2749
+ try {
2750
+ if (stamp_file.is_own_regular_file(path4)) {
2751
+ writeSync(descriptor, `${JSON.stringify(entry)}${LINE_SEPARATOR}`);
2752
+ }
2753
+ } finally {
2754
+ closeSync(descriptor);
2755
+ }
2756
+ }
2757
+ async function record(entry, path4) {
2758
+ try {
2759
+ const destination = path4 ?? await target();
2760
+ if (destination !== void 0) append(destination, entry);
2761
+ } catch {
2762
+ }
2763
+ }
2764
+ function now_iso() {
2765
+ return (/* @__PURE__ */ new Date()).toISOString();
2766
+ }
2767
+ async function record_gate(path4, gate) {
2768
+ await record({ kind: KIND.GATE, at: now_iso(), ...gate }, path4);
2769
+ }
2770
+ async function record_merge(issue) {
2771
+ await record({ kind: KIND.MERGE, at: now_iso(), issue });
2772
+ }
2773
+ async function record_dispatch(issue, path4) {
2774
+ await record({ kind: KIND.DISPATCH, at: now_iso(), issue }, path4);
2775
+ }
2776
+ async function record_stage(stage, path4) {
2777
+ await record({ kind: KIND.STAGE, at: now_iso(), ...stage }, path4);
2778
+ }
2779
+ function parse_line2(line) {
2780
+ return entry_schema.safeParse(json_value.parse_or_undefined(line)).data;
2781
+ }
2782
+ function is_present(entry) {
2783
+ return entry !== void 0;
2784
+ }
2785
+ function read_entries(path4) {
2786
+ const raw = stamp_file.read_stamp_text(path4);
2787
+ if (raw === void 0) return [];
2788
+ return raw.split(LINE_SEPARATOR).map((line) => parse_line2(line.trim())).filter(is_present);
2789
+ }
2790
+ var lane_ledger = {
2791
+ CI_WAIT_STAGE,
2792
+ KIND,
2793
+ append,
2794
+ read_entries,
2795
+ record,
2796
+ record_dispatch,
2797
+ record_gate,
2798
+ record_merge,
2799
+ record_stage,
2800
+ target,
2801
+ target_of
2802
+ };
2803
+
2480
2804
  // scripts/time-runtime/time-format.ts
2481
2805
  var MS_PER_MINUTE = 6e4;
2482
- var MS_PER_SECOND = 1e3;
2806
+ var MS_PER_SECOND2 = 1e3;
2483
2807
  var MINUTE_DECIMALS = 1;
2484
2808
  var SECOND_DECIMALS = 1;
2485
2809
  var PERCENT_SCALE = 100;
@@ -2499,7 +2823,7 @@ function format_minutes(duration_ms) {
2499
2823
  return `${(duration_ms / MS_PER_MINUTE).toFixed(MINUTE_DECIMALS)} min`;
2500
2824
  }
2501
2825
  function format_seconds(duration_ms) {
2502
- return `${(duration_ms / MS_PER_SECOND).toFixed(SECOND_DECIMALS)} s`;
2826
+ return `${(duration_ms / MS_PER_SECOND2).toFixed(SECOND_DECIMALS)} s`;
2503
2827
  }
2504
2828
  function format_share(part, whole) {
2505
2829
  if (whole === 0) return "n/a";
@@ -2549,8 +2873,8 @@ var STAGE = {
2549
2873
  // blocker and on a red check, and those are the runs whose wait is longest — reporting nothing for
2550
2874
  // them would leave the measurement blind to exactly the invocations worth measuring.
2551
2875
  interrupted: "interrupted",
2552
- // The interrupted lap when the wait failed on a merge conflict (joshuafolkken/kit#3221), so the
2553
- // stage block names the cause a resumed session used to look up with `gh pr view`.
2876
+ // The interrupted lap when the wait failed on a merge conflict, so the
2877
+ // stage block names the cause a resumed session would otherwise look up with `gh pr view`.
2554
2878
  conflict: "conflict"
2555
2879
  };
2556
2880
  function stopped_lap(error) {
@@ -2580,6 +2904,14 @@ function format_stages(log) {
2580
2904
  function print_stages(log) {
2581
2905
  for (const line of format_stages(log)) console.info(line);
2582
2906
  }
2907
+ async function record_ci_wait(log) {
2908
+ const wait = log.stages.find((stage) => stage.name === STAGE.checks_wait);
2909
+ if (wait === void 0) return;
2910
+ await lane_ledger.record_stage({
2911
+ stage: lane_ledger.CI_WAIT_STAGE,
2912
+ elapsed_ms: wait.duration_ms
2913
+ });
2914
+ }
2583
2915
  var git_followup_stages = {
2584
2916
  STAGE,
2585
2917
  STAGE_LINE_PREFIX,
@@ -2589,14 +2921,15 @@ var git_followup_stages = {
2589
2921
  total_ms,
2590
2922
  format_stages,
2591
2923
  print_stages,
2924
+ record_ci_wait,
2592
2925
  stopped_lap
2593
2926
  };
2594
2927
 
2595
2928
  // scripts/time-runtime/time-followup-stage.ts
2596
- var LINE_SEPARATOR = "\n";
2929
+ var LINE_SEPARATOR2 = "\n";
2597
2930
  var SECONDS_SUFFIX = " s";
2598
2931
  var DIGIT_OR_POINT = /[\d.]/u;
2599
- var MS_PER_SECOND2 = 1e3;
2932
+ var MS_PER_SECOND3 = 1e3;
2600
2933
  var NO_STAGES = [];
2601
2934
  function stage_body(line) {
2602
2935
  const trimmed = line.trimStart();
@@ -2619,11 +2952,11 @@ function to_stage(body) {
2619
2952
  const name = head.slice(0, start).trim();
2620
2953
  const digits = head.slice(start);
2621
2954
  if (name === "" || !is_duration(digits)) return void 0;
2622
- return { name, duration_ms: Number(digits) * MS_PER_SECOND2 };
2955
+ return { name, duration_ms: Number(digits) * MS_PER_SECOND3 };
2623
2956
  }
2624
2957
  function read_stages(text) {
2625
2958
  if (!text.includes(git_followup_stages.STAGE_LINE_PREFIX)) return NO_STAGES;
2626
- return text.split(LINE_SEPARATOR).map((line) => stage_body(line)).filter((body) => body !== void 0).map((body) => to_stage(body)).filter((stage) => stage !== void 0);
2959
+ return text.split(LINE_SEPARATOR2).map((line) => stage_body(line)).filter((body) => body !== void 0).map((body) => to_stage(body)).filter((stage) => stage !== void 0);
2627
2960
  }
2628
2961
  var time_followup_stage = { NO_STAGES, read_stages };
2629
2962
 
@@ -2631,7 +2964,7 @@ var time_followup_stage = { NO_STAGES, read_stages };
2631
2964
  import { z as z5 } from "zod";
2632
2965
  var TEXT_BLOCK_SCHEMA = z5.object({ text: z5.string().nullish() });
2633
2966
  var CONTENT_SCHEMA = z5.union([z5.string(), z5.array(z5.unknown())]);
2634
- var LINE_SEPARATOR2 = "\n";
2967
+ var LINE_SEPARATOR3 = "\n";
2635
2968
  function block_text(block) {
2636
2969
  const parsed = TEXT_BLOCK_SCHEMA.safeParse(block);
2637
2970
  return parsed.success ? parsed.data.text ?? "" : "";
@@ -2640,7 +2973,7 @@ function result_text2(content) {
2640
2973
  const parsed = CONTENT_SCHEMA.safeParse(content);
2641
2974
  if (!parsed.success) return "";
2642
2975
  if (typeof parsed.data === "string") return parsed.data;
2643
- return parsed.data.map((block) => block_text(block)).join(LINE_SEPARATOR2);
2976
+ return parsed.data.map((block) => block_text(block)).join(LINE_SEPARATOR3);
2644
2977
  }
2645
2978
  function is_failure_line(line) {
2646
2979
  return line.trimStart().startsWith(status_icons.FAIL_ICON);
@@ -2692,7 +3025,7 @@ function did_scan_find(scan) {
2692
3025
  return scan.did_find || scan.has_failure_before_region || scan.has_failure_in_region;
2693
3026
  }
2694
3027
  function has_failure_line(content) {
2695
- const lines = result_text2(content).split(LINE_SEPARATOR2);
3028
+ const lines = result_text2(content).split(LINE_SEPARATOR3);
2696
3029
  if (lines.some((line) => is_failed_verdict(line))) return true;
2697
3030
  return did_scan_find(scan_body(lines));
2698
3031
  }
@@ -2913,8 +3246,8 @@ function field_targets(input) {
2913
3246
  }
2914
3247
  function tool_targets(input) {
2915
3248
  const scalar_targets = TARGET_FIELDS.map((field) => field_text(input, field));
2916
- const targets = [...scalar_targets, ...field_targets(input)].map((target) => normalize(target));
2917
- return [...new Set(targets)].filter((target) => target !== "");
3249
+ const targets = [...scalar_targets, ...field_targets(input)].map((target2) => normalize(target2));
3250
+ return [...new Set(targets)].filter((target2) => target2 !== "");
2918
3251
  }
2919
3252
  function prompt_references_prior(input) {
2920
3253
  const prompt = field_text(input, "prompt").toLowerCase();
@@ -2959,27 +3292,27 @@ var time_bundle_call = {
2959
3292
  bash_facts,
2960
3293
  call_facts,
2961
3294
  tool_facts,
2962
- // Exported for `time-agent-bundles.ts` (joshuafolkken/kit#1854), which asks the launch question of a
3295
+ // Exported for `time-agent-bundles.ts`, which asks the launch question of a
2963
3296
  // span's `label` — the tool name for a non-Bash call — so the set lives in one place.
2964
3297
  is_launch_tool,
2965
- // Exported for `time-writes.ts` (joshuafolkken/kit#1472), which asks what a call *wrote* rather
3298
+ // Exported for `time-writes.ts`, which asks what a call *wrote* rather
2966
3299
  // than what it named. The extraction is the same one either way — a second copy of it would let a
2967
3300
  // path be recognized as a target when read and missed when written.
2968
3301
  targets_in,
2969
3302
  tool_targets,
2970
- // Exported for the batching guard's own word scan (joshuafolkken/kit#1390), so the two scanners
3303
+ // Exported for the batching guard's own word scan, so the two scanners
2971
3304
  // cannot come to disagree about where one word of a shell line ends and the next begins.
2972
- // Exported for the read-fold notice (joshuafolkken/kit#2311), which offers `read:files <path>` only
3305
+ // Exported for the read-fold notice, which offers `read:files <path>` only
2973
3306
  // over file-shaped targets — a bare directory like `scripts/` is a target here but not something
2974
3307
  // `read:files` can read, so the notice reuses this test rather than keep a second copy that could
2975
3308
  // drift from what counts as a file path.
2976
3309
  has_extension,
2977
- // Exported for `time-writes.ts` (joshuafolkken/kit#1509), which needs the same two answers to say
3310
+ // Exported for `time-writes.ts`, which needs the same two answers to say
2978
3311
  // *which* files an in-place `sed` wrote. Two copies of this test disagreed in both directions at
2979
3312
  // once — one called a piped `grep -i` a write, the other missed a bundled `sed -ni`.
2980
3313
  write_segment,
2981
3314
  is_in_place_sed,
2982
- // Exported for the drift test in `time-bundle-call.test.ts` (joshuafolkken/kit#1875), which pins that
3315
+ // Exported for the drift test in `time-bundle-call.test.ts`, which pins that
2983
3316
  // every name here is a real `josh` command and none of them writes.
2984
3317
  READ_JOSH_SUBCOMMANDS
2985
3318
  };
@@ -2991,9 +3324,9 @@ function issue_from_branch(branch) {
2991
3324
  const matched = ISSUE_BRANCH_PATTERN.exec(branch);
2992
3325
  return matched?.[1] === void 0 ? UNATTRIBUTED_KEY : Number(matched[1]);
2993
3326
  }
2994
- function declared_issue(record) {
2995
- const declared = record.issue ?? UNATTRIBUTED_KEY;
2996
- return declared === UNATTRIBUTED_KEY ? issue_from_branch(record.branch) : declared;
3327
+ function declared_issue(record2) {
3328
+ const declared = record2.issue ?? UNATTRIBUTED_KEY;
3329
+ return declared === UNATTRIBUTED_KEY ? issue_from_branch(record2.branch) : declared;
2997
3330
  }
2998
3331
  function fill(declared, is_reverse) {
2999
3332
  const filled = Array.from({ length: declared.length }, () => UNATTRIBUTED_KEY);
@@ -3017,12 +3350,12 @@ function pick(own, carried, next, previous) {
3017
3350
  }
3018
3351
  function announcements(records) {
3019
3352
  return fill(
3020
- records.map((record) => record.issue ?? UNATTRIBUTED_KEY),
3353
+ records.map((record2) => record2.issue ?? UNATTRIBUTED_KEY),
3021
3354
  false
3022
3355
  );
3023
3356
  }
3024
3357
  function attribute(records) {
3025
- const declared = records.map((record) => declared_issue(record));
3358
+ const declared = records.map((record2) => declared_issue(record2));
3026
3359
  const carried = announcements(records);
3027
3360
  const next = fill(declared, true);
3028
3361
  const previous = fill(declared, false);
@@ -3033,9 +3366,9 @@ function attribute(records) {
3033
3366
  function group_by_issue(records) {
3034
3367
  const issues = attribute(records);
3035
3368
  const grouped = /* @__PURE__ */ new Map();
3036
- for (const [index, record] of records.entries()) {
3369
+ for (const [index, record2] of records.entries()) {
3037
3370
  const bucket = grouped.get(issues[index] ?? UNATTRIBUTED_KEY) ?? [];
3038
- bucket.push(record);
3371
+ bucket.push(record2);
3039
3372
  grouped.set(issues[index] ?? UNATTRIBUTED_KEY, bucket);
3040
3373
  }
3041
3374
  return [...grouped].toSorted(([left], [right]) => left - right).map(([issue, bucket]) => ({ issue, records: bucket }));
@@ -3164,28 +3497,18 @@ var time_single_check = { NO_CHECK, check_key };
3164
3497
 
3165
3498
  // scripts/time-runtime/time-transcript-line.ts
3166
3499
  import { z as z6 } from "zod";
3167
-
3168
- // scripts/time-runtime/time-instant.ts
3169
- function parse_instant(raw) {
3170
- if (raw === null || raw === void 0) return void 0;
3171
- const parsed = Date.parse(raw);
3172
- return Number.isNaN(parsed) ? void 0 : parsed;
3173
- }
3174
- var time_instant = { parse_instant };
3175
-
3176
- // scripts/time-runtime/time-transcript-line.ts
3177
3500
  var BLOCK_SCHEMA2 = z6.object({
3178
3501
  type: z6.string().nullish(),
3179
3502
  name: z6.string().nullish(),
3180
3503
  id: z6.string().nullish(),
3181
3504
  tool_use_id: z6.string().nullish(),
3182
3505
  input: z6.unknown().nullish(),
3183
- // Whether the harness wrote this result back as a failure (joshuafolkken/kit#1309). Present on a
3506
+ // Whether the harness wrote this result back as a failure. Present on a
3184
3507
  // `tool_result` block and on nothing else, and absent even there for the tools that never report
3185
3508
  // one — which is why it is read as three answers rather than as a boolean with a default.
3186
3509
  is_error: z6.boolean().nullish(),
3187
- // What the call printed. Read only to recover the outcome a pipeline threw away
3188
- // (joshuafolkken/kit#1361): it is kept as flattened text rather than as blocks, because that is
3510
+ // What the call printed. Read only to recover the outcome a pipeline threw away:
3511
+ // it is kept as flattened text rather than as blocks, because that is
3189
3512
  // the whole of what `time-reported-failure.ts` asks of it.
3190
3513
  content: z6.unknown().nullish()
3191
3514
  });
@@ -3196,10 +3519,10 @@ var LINE_SCHEMA = z6.object({
3196
3519
  timestamp: z6.string().nullish(),
3197
3520
  // The branch the line was written on, which is where the issue number lives — `josh git` names a
3198
3521
  // branch `<N>-<slug>`. Read here rather than re-parsed by a second reader so `josh time --issue`
3199
- // and `josh cost --issue` answer from the same field (joshuafolkken/kit#1268).
3522
+ // and `josh cost --issue` answer from the same field.
3200
3523
  gitBranch: z6.string().nullish(),
3201
- // The two fields outside `message` that the harness writes an end-of-task notice on
3202
- // (joshuafolkken/kit#1696). **Both are read as `unknown` rather than as strings**: a schema
3524
+ // The two fields outside `message` that the harness writes an end-of-task notice on.
3525
+ // **Both are read as `unknown` rather than as strings**: a schema
3203
3526
  // insisting on a string here would reject every line whose `content` is a list of blocks — which is
3204
3527
  // most of them — and a rejected line is dropped from the timeline entirely, so the shares would stop
3205
3528
  // reconstructing the elapsed time. The shape is checked at the read below instead.
@@ -3213,6 +3536,7 @@ var NO_MESSAGE_ID = "";
3213
3536
  var ERROR_TEXT_LIMIT = 256;
3214
3537
  var REFUSAL_MARKER = "\u26D4";
3215
3538
  var HOOK_ERROR_LABEL = /^PreToolUse:\S+ hook error: /u;
3539
+ var STOP_FEEDBACK_LABEL = /^Stop hook feedback:\s*/u;
3216
3540
  var TOKEN_LINE = /^[a-z][a-z-]*$/u;
3217
3541
  var TOKEN_LINE_LIMIT = 8;
3218
3542
  function block_names(raw) {
@@ -3230,6 +3554,11 @@ function guard_from_refusal(text) {
3230
3554
  const colon = headline.indexOf(":");
3231
3555
  return (colon === -1 ? headline : headline.slice(0, colon)).trim();
3232
3556
  }
3557
+ function stop_guard_of(data) {
3558
+ const content = data.message?.content;
3559
+ if (typeof content !== "string" || !STOP_FEEDBACK_LABEL.test(content)) return "";
3560
+ return guard_from_refusal(content.replace(STOP_FEEDBACK_LABEL, ""));
3561
+ }
3233
3562
  function token_lines_of(text) {
3234
3563
  return text.split("\n").map((line) => line.trim()).filter((line) => TOKEN_LINE.test(line)).slice(0, TOKEN_LINE_LIMIT);
3235
3564
  }
@@ -3268,19 +3597,24 @@ function to_line(data) {
3268
3597
  timestamp_ms,
3269
3598
  branch: data.gitBranch ?? UNKNOWN_BRANCH,
3270
3599
  finished_background: time_background.finished_id(notice_text(data)),
3600
+ stop_guard: stop_guard_of(data),
3271
3601
  ...message_fields(data.message)
3272
3602
  };
3273
3603
  }
3274
- function parse_line2(line) {
3604
+ function parse_line3(line) {
3275
3605
  const parsed = LINE_SCHEMA.safeParse(json_value.parse_or_undefined(line));
3276
3606
  return parsed.success ? to_line(parsed.data) : void 0;
3277
3607
  }
3608
+ function parse_text(text) {
3609
+ return text.split("\n").flatMap((line) => parse_line3(line) ?? []);
3610
+ }
3278
3611
  var time_transcript_line = {
3279
3612
  ERROR_TEXT_LIMIT,
3280
3613
  NO_MESSAGE_ID,
3281
3614
  TOKEN_LINE_LIMIT,
3282
3615
  guard_from_refusal,
3283
- parse_line: parse_line2
3616
+ parse_line: parse_line3,
3617
+ parse_text
3284
3618
  };
3285
3619
 
3286
3620
  // scripts/time-runtime/time-writes.ts
@@ -3369,7 +3703,7 @@ var time_tool_call = {
3369
3703
  };
3370
3704
 
3371
3705
  // scripts/time-runtime/time-spans.ts
3372
- var { NO_MESSAGE_ID: NO_MESSAGE_ID3, parse_line: parse_line3 } = time_transcript_line;
3706
+ var { NO_MESSAGE_ID: NO_MESSAGE_ID3, parse_line: parse_line4 } = time_transcript_line;
3373
3707
  var { NO_CALL: NO_CALL2, UNKNOWN_CALL: UNKNOWN_CALL2, UNKNOWN_TOOL: UNKNOWN_TOOL2, to_tool_call: to_tool_call2 } = time_tool_call;
3374
3708
  var ASSISTANT_TYPE = "assistant";
3375
3709
  var USER_TYPE = "user";
@@ -3489,12 +3823,12 @@ function to_spans(events, finished) {
3489
3823
  }));
3490
3824
  }
3491
3825
  function parse_timeline(text) {
3492
- const lines = text.split("\n").map((line) => parse_line3(line)).filter((line) => line !== void 0);
3826
+ const lines = text.split("\n").map((line) => parse_line4(line)).filter((line) => line !== void 0);
3493
3827
  const events = to_events(lines, collect_calls(lines));
3494
3828
  return {
3495
3829
  started_ms: events[0]?.timestamp_ms ?? 0,
3496
3830
  ended_ms: events.at(-1)?.timestamp_ms ?? 0,
3497
- // **The positioning happens here rather than in a caller** (joshuafolkken/kit#1662): a launch and
3831
+ // **The positioning happens here rather than in a caller**: a launch and
3498
3832
  // the call that reads its output are in one transcript, and by the time spans have been merged
3499
3833
  // across sessions and trimmed they are fragments rather than calls.
3500
3834
  spans: time_background.positioned(to_spans(events, time_background.finished_at(lines)))
@@ -3517,12 +3851,12 @@ var time_spans = {
3517
3851
  equal_durations,
3518
3852
  no_background,
3519
3853
  // Re-exported so the suites that measure how a command is read keep asking one namespace, and so
3520
- // `time-shell.ts` moving out of this file changed no call site (joshuafolkken/kit#1344).
3854
+ // `time-shell.ts` moving out of this file changed no call site.
3521
3855
  bash_label: time_shell.bash_label,
3522
3856
  josh_command_of: time_shell.josh_command_of,
3523
3857
  josh_commands_of: time_shell.josh_commands_of,
3524
3858
  to_tool_call: to_tool_call2,
3525
- parse_line: parse_line3,
3859
+ parse_line: parse_line4,
3526
3860
  parse_timeline
3527
3861
  };
3528
3862
 
@@ -3615,23 +3949,21 @@ var time_round_trips = {
3615
3949
  CALLS_PER_ROUND_TRIP_FLOOR,
3616
3950
  count_calls,
3617
3951
  count_round_trips,
3618
- // Exported since joshuafolkken/kit#1406, so a turn is defined in the one module that already
3619
- // defines a round trip rather than as a span filter in the report next door.
3952
+ // Exported so a turn is defined in the one module that already defines a round trip rather than
3953
+ // as a span filter in the report next door.
3620
3954
  count_turns,
3621
3955
  format_density,
3622
- // Exported since joshuafolkken/kit#1385, so the per-tool counts are read off the very groups this
3623
- // module counts rather than off a second grouping beside them.
3956
+ // Exported so the per-tool counts are read off the very groups this module counts rather than off
3957
+ // a second grouping beside them.
3624
3958
  group_round_trips,
3625
- // Exported since joshuafolkken/kit#1309, so the failure aggregation orders a run's spans through
3959
+ // Exported so the failure aggregation orders a run's spans through
3626
3960
  // the one function that already knows why they need it — a second `toSorted` beside it would be
3627
3961
  // the clone `CLAUDE.md` prohibits, and the seam it guards (a delegated unit's spans appended
3628
3962
  // after the parent's) is not one a second copy would keep remembering.
3629
3963
  in_time_order,
3630
3964
  is_below_floor,
3631
- // The four below are exported since joshuafolkken/kit#1406, when the model-gap walk moved to
3632
- // `time-model-gaps.ts` and needed the same predicates and the same opener test this walk uses. A
3633
- // private copy there would be the clone `CLAUDE.md` prohibits, in the one place a drift would have
3634
- // the distribution and the count disagreeing about what a round trip is.
3965
+ // Exported so callers price a round trip with the same divisor and guard rather than a private
3966
+ // copy — the clone `CLAUDE.md` prohibits.
3635
3967
  per_round_trip
3636
3968
  };
3637
3969
 
@@ -3771,9 +4103,9 @@ function tally_for(tallies, label) {
3771
4103
  return created;
3772
4104
  }
3773
4105
  function count_trip(tallies, counted, label) {
3774
- const tally2 = tally_for(tallies, label);
3775
- tally2.recoverable_round_trips += ONE_CALL;
3776
- if (!counted.has(label)) tally2.sequence_count += ONE_CALL;
4106
+ const tally = tally_for(tallies, label);
4107
+ tally.recoverable_round_trips += ONE_CALL;
4108
+ if (!counted.has(label)) tally.sequence_count += ONE_CALL;
3777
4109
  counted.add(label);
3778
4110
  }
3779
4111
  function tally_sequence(tallies, sequence) {
@@ -3791,7 +4123,7 @@ function by_weight(left, right) {
3791
4123
  function tool_rows(closed) {
3792
4124
  const tallies = /* @__PURE__ */ new Map();
3793
4125
  for (const sequence of closed) tally_sequence(tallies, sequence);
3794
- return [...tallies].map(([label, tally2]) => ({ label, ...tally2 })).toSorted(by_weight);
4126
+ return [...tallies].map(([label, tally]) => ({ label, ...tally })).toSorted(by_weight);
3795
4127
  }
3796
4128
  function attributed_of(rows) {
3797
4129
  return rows.reduce((sum, row) => sum + row.recoverable_round_trips, NONE3);
@@ -3925,9 +4257,11 @@ var NONE4 = 0;
3925
4257
  var NOTICE_REFIRE_EVERY = ONE_TURN;
3926
4258
  var NAMED_CANDIDATE_COUNT = 3;
3927
4259
  var SEQUENCE_BEFORE_LIMIT = CONSECUTIVE_LIMIT - ONE_TURN;
3928
- var REASON = `\u26D4 batching: the last ${String(SEQUENCE_BEFORE_LIMIT)} turns each issued a single tool call, so this one would make ${String(CONSECUTIVE_LIMIT)} in a row. Reissue it in one turn together with the calls meant to follow it that do not need its result. **The criterion is whether this call's input needs another call's result, not what kind of call it is** \u2014 edits are covered exactly as reads are, and it never authorizes weakening a verification gate or a review: fewer turns, never less work. The rule, and where its measured cost and rejected mechanisms are, is in \`prompts/collaboration-workflow/turn-batching.md\`. If this turn was already batching, or the call genuinely has nothing to go beside it, reissue it as it was: this fires once per run of single-call turns and cannot repeat on the call in hand.`;
3929
- var NOTICE = `\u{1F4A1} batching: the last ${String(SEQUENCE_BEFORE_LIMIT)} turns each issued a single tool call, so this Write makes ${String(CONSECUTIVE_LIMIT)} in a row. This is a notice, not a refusal \u2014 the write proceeds. Where the writes meant to follow it do not need its result, issue them in one turn together. **The criterion is whether a call's input needs another call's result, not what kind of call it is** \u2014 it never authorizes weakening a verification gate or a review: fewer turns, never less work. The rule, and where its measured cost and rejected mechanisms are, is in \`prompts/collaboration-workflow/turn-batching.md\`. If this run was already batching, or the write genuinely has nothing to go beside it, carry on: this recurs every ${String(NOTICE_REFIRE_EVERY)} further single-call turn(s).`;
3930
- var LANE_NOTICE = `\u{1F4A1} batching: the last ${String(SEQUENCE_BEFORE_LIMIT)} turns each issued a single tool call, so this one makes ${String(CONSECUTIVE_LIMIT)} in a row. This is a notice, not a refusal \u2014 the call proceeds, because a dispatched lane child ends its turn on a denial. Where the calls meant to follow it do not need its result, issue them in one turn together. **The criterion is whether a call's input needs another call's result, not what kind of call it is** \u2014 it never authorizes weakening a verification gate or a review: fewer turns, never less work. The rule, and where its measured cost and rejected mechanisms are, is in \`prompts/collaboration-workflow/turn-batching.md\`. If this run was already batching, or the call genuinely has nothing to go beside it, carry on: this recurs every ${String(NOTICE_REFIRE_EVERY)} further single-call turn(s).`;
4260
+ var RULE_POINTER = "`prompts/collaboration-workflow/turn-batching.md`";
4261
+ var STREAK = `${String(CONSECUTIVE_LIMIT)} single-call turns in a row`;
4262
+ var REASON = `\u26D4 batching: ${STREAK}. Reissue this with the calls that do not need its result \u2014 the test is whether a call's input needs another call's result, not what kind of call it is (edits are covered exactly as reads), and it never authorizes weakening a verification gate or a review. Already batching, or nothing to pair? Reissue it unchanged; this fires once per streak. ${RULE_POINTER}`;
4263
+ var NOTICE = `\u{1F4A1} batching: ${STREAK}; the Write proceeds. Issue the writes that do not need its result in one turn, never by weakening a gate or a review. ${RULE_POINTER}`;
4264
+ var LANE_NOTICE = `\u{1F4A1} batching: ${STREAK}; the call proceeds. Pair independent calls. ${RULE_POINTER}`;
3931
4265
  var WHOLE_FILE_WRITE_TOOL = "Write";
3932
4266
  var EDIT_TOOL = "Edit";
3933
4267
  function is_guarded_call(call) {
@@ -3984,13 +4318,13 @@ function should_notify(text, call, notified_at_ms) {
3984
4318
  return is_at_limit(spans, call, notified_at_ms, NOTICE_REFIRE_EVERY);
3985
4319
  }
3986
4320
  function describe_span(span) {
3987
- const target = span.targets[0] ?? "";
3988
- if (target === "" || span.label.includes(target)) return span.label;
3989
- return `${span.label} ${target}`;
4321
+ const target2 = span.targets[0] ?? "";
4322
+ if (target2 === "" || span.label.includes(target2)) return span.label;
4323
+ return `${span.label} ${target2}`;
3990
4324
  }
3991
4325
  var FOLD_MINIMUM = 2;
3992
4326
  function read_targets(sequence) {
3993
- const paths = sequence.filter((span) => span.is_bundleable && !span.is_writing).map((span) => span.targets[0] ?? "").filter((path7) => path7 !== "" && time_bundle_call.has_extension(path7));
4327
+ const paths = sequence.filter((span) => span.is_bundleable && !span.is_writing).map((span) => span.targets[0] ?? "").filter((path4) => path4 !== "" && time_bundle_call.has_extension(path4));
3994
4328
  return [...new Set(paths)];
3995
4329
  }
3996
4330
  function read_fold_directive(sequence) {
@@ -3999,7 +4333,7 @@ function read_fold_directive(sequence) {
3999
4333
  return ` Fold them into one call: \`pnpm josh read:files ${paths.join(" ")}\`.`;
4000
4334
  }
4001
4335
  function write_targets(sequence) {
4002
- const paths = sequence.filter((span) => span.label === EDIT_TOOL).map((span) => span.targets[0] ?? "").filter((path7) => path7 !== "" && time_bundle_call.has_extension(path7));
4336
+ const paths = sequence.filter((span) => span.label === EDIT_TOOL).map((span) => span.targets[0] ?? "").filter((path4) => path4 !== "" && time_bundle_call.has_extension(path4));
4003
4337
  return [...new Set(paths)];
4004
4338
  }
4005
4339
  function write_fold_directive(sequence) {
@@ -4051,449 +4385,22 @@ var time_batch_guard = {
4051
4385
  };
4052
4386
 
4053
4387
  // scripts/time-runtime/time-hook-transcript.ts
4054
- import path6 from "node:path";
4055
-
4056
- // scripts/cost-runtime/cost-transcript.ts
4057
- import { readdirSync as readdirSync3, readFileSync as readFileSync3, statSync } from "node:fs";
4058
- import { homedir } from "node:os";
4059
- import path5 from "node:path";
4060
-
4061
- // scripts/lane/lane-paths.ts
4062
- import path4 from "node:path";
4063
- var LANE_ROOT_KEY = "JOSH_LANE_ROOT";
4064
- var LANE_DIRECTORY_SUFFIX = "-lanes";
4065
- var LANE_BRANCH_SUFFIX = "-lane";
4066
- function default_lane_root(repository_root) {
4067
- const name = path4.basename(repository_root);
4068
- return path4.join(path4.dirname(repository_root), `.${name}${LANE_DIRECTORY_SUFFIX}`);
4069
- }
4070
- function lane_root(repository_root, environment = process.env) {
4071
- const configured = environment[LANE_ROOT_KEY]?.trim() ?? "";
4072
- return configured.length === 0 ? default_lane_root(repository_root) : path4.resolve(configured);
4073
- }
4074
- function lane_directory(root, issue) {
4075
- return path4.join(root, issue);
4076
- }
4077
- var LANE_ISSUE_PATTERN = /^\d+$/u;
4078
- var DEFAULT_LANE_ROOT_PATTERN = new RegExp(String.raw`^\..+${LANE_DIRECTORY_SUFFIX}$`, "u");
4079
- function is_lane_root(directory, environment) {
4080
- const configured = environment[LANE_ROOT_KEY]?.trim() ?? "";
4081
- if (configured.length > 0) return path4.resolve(configured) === directory;
4082
- return DEFAULT_LANE_ROOT_PATTERN.test(path4.basename(directory));
4083
- }
4084
- function lane_issue_of(directory, environment = process.env) {
4085
- const resolved = path4.resolve(directory);
4086
- const issue = path4.basename(resolved);
4087
- if (!LANE_ISSUE_PATTERN.test(issue)) return void 0;
4088
- return is_lane_root(path4.dirname(resolved), environment) ? issue : void 0;
4089
- }
4090
- function lane_branch(issue) {
4091
- return `${issue}${LANE_BRANCH_SUFFIX}`;
4092
- }
4093
- var lane_paths = {
4094
- LANE_BRANCH_SUFFIX,
4095
- LANE_ROOT_KEY,
4096
- default_lane_root,
4097
- lane_branch,
4098
- lane_directory,
4099
- lane_issue_of,
4100
- lane_root
4101
- };
4102
-
4103
- // scripts/lib/read-file.ts
4104
- import { readFileSync as readFileSync2 } from "node:fs";
4105
- var ABSENT_CODE = "ENOENT";
4106
- function is_absent(error) {
4107
- return error instanceof Error && "code" in error && error.code === ABSENT_CODE;
4108
- }
4109
- function read_optional(path7) {
4110
- try {
4111
- return readFileSync2(path7, "utf8");
4112
- } catch (error) {
4113
- if (is_absent(error)) return void 0;
4114
- throw error;
4115
- }
4116
- }
4117
- function read_file_or_empty(path7) {
4118
- return read_optional(path7) ?? "";
4119
- }
4120
- function read_if_readable(path7) {
4121
- try {
4122
- return readFileSync2(path7, "utf8");
4123
- } catch {
4124
- return void 0;
4125
- }
4126
- }
4127
- var file_reader = { read_optional, read_file_or_empty, read_if_readable };
4128
-
4129
- // scripts/cost-runtime/cost-usage.ts
4130
- import { z as z7 } from "zod";
4131
- var CACHE_CREATION_SCHEMA = z7.object({
4132
- ephemeral_1h_input_tokens: z7.number().nullish(),
4133
- ephemeral_5m_input_tokens: z7.number().nullish()
4134
- });
4135
- var USAGE_SCHEMA = z7.object({
4136
- input_tokens: z7.number(),
4137
- cache_creation_input_tokens: z7.number().nullish(),
4138
- cache_read_input_tokens: z7.number().nullish(),
4139
- output_tokens: z7.number(),
4140
- output_tokens_details: z7.object({ thinking_tokens: z7.number().nullish() }).nullish(),
4141
- cache_creation: CACHE_CREATION_SCHEMA.nullish()
4142
- });
4143
- var MESSAGE_SCHEMA3 = z7.object({
4144
- id: z7.string().nullish(),
4145
- model: z7.string().nullish(),
4146
- usage: USAGE_SCHEMA.nullish()
4147
- });
4148
- var LINE_SCHEMA2 = z7.object({
4149
- type: z7.string(),
4150
- requestId: z7.string().nullish(),
4151
- uuid: z7.string().nullish(),
4152
- gitBranch: z7.string().nullish(),
4153
- timestamp: z7.string().nullish(),
4154
- message: MESSAGE_SCHEMA3.nullish()
4155
- });
4156
- var SYNTHETIC_MODEL = "<synthetic>";
4157
- var EMPTY_TOTALS = {
4158
- input_tokens: 0,
4159
- cache_write_5m_tokens: 0,
4160
- cache_write_1h_tokens: 0,
4161
- cache_read_tokens: 0,
4162
- output_tokens: 0,
4163
- thinking_tokens: 0,
4164
- thinking_measured: false
4165
- };
4166
- var UNKNOWN_MODEL = "unknown";
4167
- var UNKNOWN_BRANCH2 = "";
4168
- function split_cache_write(usage) {
4169
- const total = usage.cache_creation_input_tokens ?? 0;
4170
- const detail = usage.cache_creation;
4171
- if (!detail) return { write_5m: total, write_1h: 0 };
4172
- const write_1h = detail.ephemeral_1h_input_tokens ?? 0;
4173
- return { write_5m: detail.ephemeral_5m_input_tokens ?? total - write_1h, write_1h };
4174
- }
4175
- function thinking_usage(usage) {
4176
- const raw = usage.output_tokens_details?.thinking_tokens;
4177
- return { tokens: raw ?? 0, measured: raw !== null && raw !== void 0 };
4178
- }
4179
- function to_totals(usage) {
4180
- const { write_5m, write_1h } = split_cache_write(usage);
4181
- const thinking = thinking_usage(usage);
4182
- return {
4183
- input_tokens: usage.input_tokens,
4184
- cache_write_5m_tokens: write_5m,
4185
- cache_write_1h_tokens: write_1h,
4186
- cache_read_tokens: usage.cache_read_input_tokens ?? 0,
4187
- output_tokens: usage.output_tokens,
4188
- thinking_tokens: thinking.tokens,
4189
- thinking_measured: thinking.measured
4190
- };
4191
- }
4192
- function declared_id(data) {
4193
- return data.requestId ?? data.message?.id ?? data.uuid ?? void 0;
4194
- }
4195
- function request_id_of(data, usage) {
4196
- const fallback = `${data.timestamp ?? ""}-${String(usage.output_tokens)}`;
4197
- return declared_id(data) ?? fallback;
4198
- }
4199
- function to_record(data, usage) {
4200
- return {
4201
- request_id: request_id_of(data, usage),
4202
- model: data.message?.model ?? UNKNOWN_MODEL,
4203
- branch: data.gitBranch ?? UNKNOWN_BRANCH2,
4204
- at_ms: time_instant.parse_instant(data.timestamp),
4205
- totals: to_totals(usage)
4206
- };
4207
- }
4208
- var ASSISTANT_TYPE2 = "assistant";
4209
- function is_priced_line(data) {
4210
- return data.type === ASSISTANT_TYPE2 && data.message?.model !== SYNTHETIC_MODEL;
4211
- }
4212
- function classify(data) {
4213
- if (!is_priced_line(data)) return { kind: "skipped" };
4214
- const usage = data.message?.usage;
4215
- return usage ? { kind: "record", record: to_record(data, usage) } : { kind: "no_usage" };
4216
- }
4217
- function parse_line4(line) {
4218
- if (line.trim() === "") return { kind: "skipped" };
4219
- const parsed = LINE_SCHEMA2.safeParse(json_value.parse_or_undefined(line));
4220
- return parsed.success ? classify(parsed.data) : { kind: "malformed" };
4221
- }
4222
- function later_instant(left, right) {
4223
- if (left === void 0) return right;
4224
- if (right === void 0) return left;
4225
- return Math.max(left, right);
4226
- }
4227
- function dedupe(records) {
4228
- const by_id = /* @__PURE__ */ new Map();
4229
- for (const record of records) {
4230
- const seen = by_id.get(record.request_id);
4231
- const at_ms = later_instant(seen?.at_ms, record.at_ms);
4232
- by_id.set(record.request_id, { ...seen ?? record, at_ms });
4233
- }
4234
- return [...by_id.values()];
4235
- }
4236
- function add_totals(left, right) {
4237
- return {
4238
- input_tokens: left.input_tokens + right.input_tokens,
4239
- cache_write_5m_tokens: left.cache_write_5m_tokens + right.cache_write_5m_tokens,
4240
- cache_write_1h_tokens: left.cache_write_1h_tokens + right.cache_write_1h_tokens,
4241
- cache_read_tokens: left.cache_read_tokens + right.cache_read_tokens,
4242
- output_tokens: left.output_tokens + right.output_tokens,
4243
- thinking_tokens: left.thinking_tokens + right.thinking_tokens,
4244
- thinking_measured: left.thinking_measured || right.thinking_measured
4245
- };
4246
- }
4247
- function sum_totals(records) {
4248
- let total = EMPTY_TOTALS;
4249
- for (const record of records) total = add_totals(total, record.totals);
4250
- return total;
4251
- }
4252
- function billed_input(totals) {
4253
- return totals.input_tokens + totals.cache_write_5m_tokens + totals.cache_write_1h_tokens + totals.cache_read_tokens;
4254
- }
4255
- var cost_usage = {
4256
- EMPTY_TOTALS,
4257
- UNKNOWN_MODEL,
4258
- SYNTHETIC_MODEL,
4259
- parse_line: parse_line4,
4260
- dedupe,
4261
- add_totals,
4262
- sum_totals,
4263
- billed_input
4264
- };
4265
-
4266
- // scripts/cost-runtime/cost-transcript.ts
4267
- var TRANSCRIPT_ROOT = path5.join(".claude", "projects");
4268
- var TRANSCRIPT_EXTENSION = ".jsonl";
4269
- var SLUG_PATTERN = /[^a-zA-Z0-9-]/gu;
4270
- var UNIT_DIRECTORY = "subagents";
4271
- var UNIT_ID_SEPARATOR = "/";
4272
- function project_slug(cwd) {
4273
- return cwd.replaceAll(SLUG_PATTERN, "-");
4274
- }
4275
- function transcript_directory(cwd, home = homedir()) {
4276
- return path5.join(home, TRANSCRIPT_ROOT, project_slug(cwd));
4277
- }
4278
- var GIT_ENTRY = ".git";
4279
- var GITDIR_PREFIX = "gitdir:";
4280
- var WORKTREE_SEGMENT = `/${GIT_ENTRY}/worktrees/`;
4281
- var NOT_FOUND = -1;
4282
- function linked_worktree_gitdir(cwd) {
4283
- try {
4284
- const contents = readFileSync3(path5.join(cwd, GIT_ENTRY), "utf8").trim();
4285
- return contents.startsWith(GITDIR_PREFIX) ? contents.slice(GITDIR_PREFIX.length).trim() : "";
4286
- } catch {
4287
- return "";
4288
- }
4289
- }
4290
- function session_cwd(cwd) {
4291
- const gitdir = linked_worktree_gitdir(cwd);
4292
- const absolute = gitdir === "" ? "" : path5.resolve(cwd, gitdir);
4293
- const segment = absolute.indexOf(WORKTREE_SEGMENT);
4294
- return segment === NOT_FOUND ? cwd : absolute.slice(0, segment);
4295
- }
4296
- function read_directory(directory) {
4297
- try {
4298
- return readdirSync3(directory);
4299
- } catch {
4300
- return [];
4301
- }
4302
- }
4303
- var LANE_ISSUE_SLUG = /^\d+$/u;
4304
- function lane_transcript_directories(main_cwd, home) {
4305
- const projects = path5.join(home, TRANSCRIPT_ROOT);
4306
- const prefix = `${project_slug(lane_paths.lane_root(main_cwd))}-`;
4307
- return read_directory(projects).filter((name) => name.startsWith(prefix) && LANE_ISSUE_SLUG.test(name.slice(prefix.length))).map((name) => path5.join(projects, name));
4308
- }
4309
- function transcript_directories(cwd, home = homedir()) {
4310
- const own = transcript_directory(cwd, home);
4311
- const lanes = session_cwd(cwd) === cwd ? lane_transcript_directories(cwd, home) : [];
4312
- return [.../* @__PURE__ */ new Set([own, ...lanes])];
4313
- }
4314
- var OWN_DEPTH = 0;
4315
- function home_directory() {
4316
- return homedir();
4317
- }
4318
- function to_session_file(full_path, session_id, depth) {
4319
- try {
4320
- return {
4321
- session_id,
4322
- path: full_path,
4323
- modified_ms: statSync(full_path).mtimeMs,
4324
- is_delegated: depth > OWN_DEPTH,
4325
- depth
4326
- };
4327
- } catch {
4328
- return void 0;
4329
- }
4330
- }
4331
- function is_transcript(name) {
4332
- return name.endsWith(TRANSCRIPT_EXTENSION);
4333
- }
4334
- function without_extension(name) {
4335
- return name.slice(0, -TRANSCRIPT_EXTENSION.length);
4336
- }
4337
- function own_files(directory, names) {
4338
- return names.filter((name) => is_transcript(name)).map((name) => to_session_file(path5.join(directory, name), without_extension(name), OWN_DEPTH)).filter((file) => file !== void 0);
4339
- }
4340
- function unit_directory(directory, session_id) {
4341
- return path5.join(directory, session_id, UNIT_DIRECTORY);
4342
- }
4343
- var UNIT_DEPTH = 1;
4344
- function level_units(subagents_directory, prefix, depth) {
4345
- return read_directory(subagents_directory).filter((name) => is_transcript(name)).map(
4346
- (name) => to_session_file(
4347
- path5.join(subagents_directory, name),
4348
- `${prefix}${UNIT_ID_SEPARATOR}${without_extension(name)}`,
4349
- depth
4350
- )
4351
- ).filter((file) => file !== void 0);
4352
- }
4353
- function collect_units(subagents_directory, prefix, depth) {
4354
- const nested = read_directory(subagents_directory).filter((name) => !is_transcript(name)).flatMap(
4355
- (name) => collect_units(
4356
- unit_directory(subagents_directory, name),
4357
- `${prefix}${UNIT_ID_SEPARATOR}${name}`,
4358
- depth + 1
4359
- )
4360
- );
4361
- return [...level_units(subagents_directory, prefix, depth), ...nested];
4362
- }
4363
- function unit_files(directory, session_name) {
4364
- return collect_units(unit_directory(directory, session_name), session_name, UNIT_DEPTH);
4365
- }
4366
- function list_sessions(directory) {
4367
- const names = read_directory(directory);
4368
- const units = names.filter((name) => !is_transcript(name)).flatMap((name) => unit_files(directory, name));
4369
- return [...own_files(directory, names), ...units].toSorted(
4370
- (left, right) => right.modified_ms - left.modified_ms
4371
- );
4372
- }
4373
- function list_sessions_across(directories) {
4374
- const seen = /* @__PURE__ */ new Set();
4375
- const merged = directories.flatMap((directory) => list_sessions(directory));
4376
- const newest_first = merged.toSorted((left, right) => right.modified_ms - left.modified_ms);
4377
- const kept = [];
4378
- for (const file of newest_first) {
4379
- if (seen.has(file.session_id)) continue;
4380
- seen.add(file.session_id);
4381
- kept.push(file);
4382
- }
4383
- return kept;
4384
- }
4385
- function owning_session_id(file) {
4386
- const [owner] = file.session_id.split(UNIT_ID_SEPARATOR);
4387
- return owner ?? file.session_id;
4388
- }
4389
- function parent_session_id(file) {
4390
- const separator = file.session_id.lastIndexOf(UNIT_ID_SEPARATOR);
4391
- return separator === NOT_FOUND ? file.session_id : file.session_id.slice(0, separator);
4392
- }
4393
- function latest_own_index(files) {
4394
- const index = files.findIndex((file) => !file.is_delegated);
4395
- return index === -1 ? 0 : index;
4396
- }
4397
- function empty_session() {
4398
- return {
4399
- records: [],
4400
- no_usage_lines: 0,
4401
- malformed_lines: 0,
4402
- is_readable: false,
4403
- baseline_tokens: 0
4404
- };
4405
- }
4406
- function tally(content) {
4407
- const outcomes = content.split("\n").map((line) => cost_usage.parse_line(line));
4408
- const records = outcomes.flatMap(
4409
- (outcome) => outcome.kind === "record" ? [outcome.record] : []
4410
- );
4411
- const unique = cost_usage.dedupe(records);
4412
- const [first] = unique;
4413
- return {
4414
- records: unique,
4415
- no_usage_lines: outcomes.filter((outcome) => outcome.kind === "no_usage").length,
4416
- malformed_lines: outcomes.filter((outcome) => outcome.kind === "malformed").length,
4417
- is_readable: true,
4418
- baseline_tokens: first === void 0 ? 0 : cost_usage.billed_input(first.totals)
4419
- };
4420
- }
4421
- function read_session(file) {
4422
- const content = file_reader.read_if_readable(file.path);
4423
- if (content === void 0) return { session_id: file.session_id, ...empty_session() };
4424
- return { session_id: file.session_id, ...tally(content) };
4425
- }
4426
- function read_raw(file) {
4427
- return file_reader.read_if_readable(file.path) ?? "";
4428
- }
4429
- function read_optional2(file) {
4430
- return file_reader.read_if_readable(file.path);
4431
- }
4432
- function directory_exists(directory) {
4433
- try {
4434
- return statSync(directory).isDirectory();
4435
- } catch {
4436
- return false;
4437
- }
4438
- }
4439
- function searched_directories(directories) {
4440
- return directories.map((directory) => ({
4441
- path: directory,
4442
- exists: directory_exists(directory)
4443
- }));
4444
- }
4445
- function describe_searched(directory) {
4446
- return ` ${directory.path} \u2014 ${directory.exists ? "no transcripts here" : "no such directory"}`;
4447
- }
4448
- function missing_message(searched, session_id) {
4449
- const lead = session_id === void 0 ? "No transcripts found. Searched:" : `No transcript named ${session_id}. Searched:`;
4450
- const listed = searched.map((directory) => describe_searched(directory));
4451
- if (session_id !== void 0) return [lead, ...listed];
4452
- return [
4453
- lead,
4454
- ...listed,
4455
- "Claude Code writes them per project; run this from the project it ran in."
4456
- ];
4457
- }
4458
- var cost_transcript = {
4459
- TRANSCRIPT_EXTENSION,
4460
- TRANSCRIPT_ROOT,
4461
- UNIT_DIRECTORY,
4462
- project_slug,
4463
- transcript_directory,
4464
- transcript_directories,
4465
- session_cwd,
4466
- unit_directory,
4467
- list_sessions,
4468
- list_sessions_across,
4469
- searched_directories,
4470
- owning_session_id,
4471
- parent_session_id,
4472
- latest_own_index,
4473
- tally,
4474
- read_session,
4475
- read_raw,
4476
- read_optional: read_optional2,
4477
- missing_message,
4478
- home_directory
4479
- };
4480
-
4481
- // scripts/time-runtime/time-hook-transcript.ts
4482
- var { TRANSCRIPT_EXTENSION: TRANSCRIPT_EXTENSION2 } = cost_transcript;
4388
+ import path3 from "node:path";
4389
+ var { TRANSCRIPT_EXTENSION } = cost_transcript;
4483
4390
  var AGENT_PREFIX = "agent-";
4484
4391
  var AGENT_ID_PATTERN = /^[\w-]+$/u;
4485
4392
  function is_agent_id(value) {
4486
4393
  return typeof value === "string" && AGENT_ID_PATTERN.test(value);
4487
4394
  }
4488
4395
  function fork_path(transcript_path, agent_id) {
4489
- const directory = path6.dirname(transcript_path);
4490
- const session_id = path6.basename(transcript_path, TRANSCRIPT_EXTENSION2);
4491
- const file_name = `${AGENT_PREFIX}${agent_id}${TRANSCRIPT_EXTENSION2}`;
4492
- return path6.join(cost_transcript.unit_directory(directory, session_id), file_name);
4396
+ const directory = path3.dirname(transcript_path);
4397
+ const session_id = path3.basename(transcript_path, TRANSCRIPT_EXTENSION);
4398
+ const file_name = `${AGENT_PREFIX}${agent_id}${TRANSCRIPT_EXTENSION}`;
4399
+ return path3.join(cost_transcript.unit_directory(directory, session_id), file_name);
4493
4400
  }
4494
4401
  function transcript_of(transcript_path, agent_id) {
4495
4402
  if (!is_agent_id(agent_id)) return transcript_path;
4496
- if (!transcript_path.endsWith(TRANSCRIPT_EXTENSION2)) return transcript_path;
4403
+ if (!transcript_path.endsWith(TRANSCRIPT_EXTENSION)) return transcript_path;
4497
4404
  return fork_path(transcript_path, agent_id);
4498
4405
  }
4499
4406
  var time_hook_transcript = {
@@ -4502,8 +4409,8 @@ var time_hook_transcript = {
4502
4409
  };
4503
4410
 
4504
4411
  // scripts/time-runtime/time-density-hook.ts
4505
- import { closeSync, fstatSync, openSync, readSync } from "node:fs";
4506
- import { z as z8 } from "zod";
4412
+ import { closeSync as closeSync2, fstatSync, openSync as openSync2, readSync } from "node:fs";
4413
+ import { z as z7 } from "zod";
4507
4414
 
4508
4415
  // scripts/time-runtime/time-density.ts
4509
4416
  var MIN_ROUND_TRIPS = 10;
@@ -4559,15 +4466,15 @@ var TAIL_BYTES = 262144;
4559
4466
  var FILE_START = 0;
4560
4467
  var NOTICE_PREFIX = "josh-density-notice-";
4561
4468
  var NEVER_MS = 0;
4562
- var payload_schema = z8.object({
4563
- transcript_path: z8.string().min(1).optional(),
4469
+ var payload_schema = z7.object({
4470
+ transcript_path: z7.string().min(1).optional(),
4564
4471
  // **`nullish`, not `optional`.** A payload spelling the absent agent as `null` has to read as "no
4565
4472
  // fork"; rejected, it would fail `safeParse` for the whole payload and silence the line for every
4566
4473
  // edit of the main line — the opposite of this module's stated failure direction.
4567
- agent_id: z8.string().nullish()
4474
+ agent_id: z7.string().nullish()
4568
4475
  });
4569
- var notice_schema = z8.object({ notified_at_ms: z8.number() });
4570
- var call_schema = z8.object({ tool_name: z8.string().min(1), tool_input: z8.unknown() });
4476
+ var notice_schema = z7.object({ notified_at_ms: z7.number() });
4477
+ var call_schema = z7.object({ tool_name: z7.string().min(1), tool_input: z7.unknown() });
4571
4478
  function parse_transcript_path(raw_payload) {
4572
4479
  const parsed = payload_schema.safeParse(JSON.parse(raw_payload));
4573
4480
  if (!parsed.success || parsed.data.transcript_path === void 0) return void 0;
@@ -4579,7 +4486,7 @@ function parse_call(raw_payload) {
4579
4486
  return { name: parsed.data.tool_name, input: parsed.data.tool_input };
4580
4487
  }
4581
4488
  function read_tail(file_path, max_bytes = TAIL_BYTES) {
4582
- const descriptor = openSync(file_path, "r");
4489
+ const descriptor = openSync2(file_path, "r");
4583
4490
  try {
4584
4491
  const { size } = fstatSync(descriptor);
4585
4492
  const length = Math.min(size, max_bytes);
@@ -4587,7 +4494,7 @@ function read_tail(file_path, max_bytes = TAIL_BYTES) {
4587
4494
  const read = readSync(descriptor, buffer, FILE_START, length, size - length);
4588
4495
  return buffer.subarray(FILE_START, read).toString("utf8");
4589
4496
  } finally {
4590
- closeSync(descriptor);
4497
+ closeSync2(descriptor);
4591
4498
  }
4592
4499
  }
4593
4500
  function notice_path(transcript_path) {
@@ -4596,15 +4503,11 @@ function notice_path(transcript_path) {
4596
4503
  function last_notice_ms(source) {
4597
4504
  const raw = stamp_file.read_stamp_text(source);
4598
4505
  if (raw === void 0) return NEVER_MS;
4599
- try {
4600
- return notice_schema.parse(JSON.parse(raw)).notified_at_ms;
4601
- } catch {
4602
- return NEVER_MS;
4603
- }
4506
+ return json_value.parse_with(raw, notice_schema)?.notified_at_ms ?? NEVER_MS;
4604
4507
  }
4605
- function arm_throttle(target, now_ms) {
4508
+ function arm_throttle(target2, now_ms) {
4606
4509
  try {
4607
- stamp_file.write_stamp(target, { notified_at_ms: now_ms });
4510
+ stamp_file.write_stamp(target2, { notified_at_ms: now_ms });
4608
4511
  } catch {
4609
4512
  }
4610
4513
  }
@@ -4613,11 +4516,11 @@ function notice_for(raw_payload, now_ms) {
4613
4516
  if (transcript_path === void 0) return void 0;
4614
4517
  const tail = read_tail(transcript_path);
4615
4518
  const reading = time_density.read_window(tail);
4616
- const target = notice_path(transcript_path);
4617
- if (!time_density.is_due(reading, now_ms - last_notice_ms(target))) return void 0;
4519
+ const target2 = notice_path(transcript_path);
4520
+ if (!time_density.is_due(reading, now_ms - last_notice_ms(target2))) return void 0;
4618
4521
  const candidates = time_batch_guard.pairing_candidates(tail, parse_call(raw_payload));
4619
4522
  if (candidates === "") return void 0;
4620
- arm_throttle(target, now_ms);
4523
+ arm_throttle(target2, now_ms);
4621
4524
  return time_density.format_notice(reading, candidates);
4622
4525
  }
4623
4526
  function density_notice(raw_payload, now_ms = Date.now()) {
@@ -4634,11 +4537,8 @@ var time_density_hook = {
4634
4537
  };
4635
4538
 
4636
4539
  export {
4637
- json_value,
4638
4540
  cost_blocks,
4639
4541
  ESLINT_EDIT_CACHE_FLAGS,
4640
- process_identity,
4641
- process_owner_schema,
4642
4542
  time_shell,
4643
4543
  time_bundle_call,
4644
4544
  blocking_issue_schema,
@@ -4660,10 +4560,6 @@ export {
4660
4560
  time_transcript_line,
4661
4561
  time_spans,
4662
4562
  time_batch_guard,
4663
- lane_paths,
4664
- file_reader,
4665
- cost_usage,
4666
- cost_transcript,
4667
4563
  time_hook_transcript,
4668
4564
  time_density_hook
4669
4565
  };