@joshuafolkken/kit 1.1455.0 → 1.1514.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 (374) hide show
  1. package/.claude/settings.json +6 -6
  2. package/.claude/skills/dependency-update/SKILL.md +26 -55
  3. package/.claude/skills/epic-commands/SKILL.md +83 -156
  4. package/.claude/skills/epic-commands/epic-bundle.md +51 -79
  5. package/.claude/skills/epic-commands/execution-waves.md +43 -81
  6. package/.claude/skills/verify-ui/SKILL.md +24 -50
  7. package/.claude/skills/workflow-commands/SKILL.md +7 -9
  8. package/.claude/skills/workflow-commands/background-commands.md +31 -46
  9. package/.claude/skills/workflow-commands/backlogrun-child.md +65 -85
  10. package/.claude/skills/workflow-commands/backlogrun-lanes.md +86 -125
  11. package/.claude/skills/workflow-commands/backlogrun-park.md +68 -118
  12. package/.claude/skills/workflow-commands/backlogrun-progress.md +17 -28
  13. package/.claude/skills/workflow-commands/backlogrun-recovery.md +17 -26
  14. package/.claude/skills/workflow-commands/backlogrun-steps.md +35 -52
  15. package/.claude/skills/workflow-commands/backlogrun.md +31 -50
  16. package/.claude/skills/workflow-commands/chain-rule.md +31 -40
  17. package/.claude/skills/workflow-commands/delegation.md +12 -8
  18. package/.claude/skills/workflow-commands/entry-sequence.md +1 -3
  19. package/.claude/skills/workflow-commands/followup.md +55 -77
  20. package/.claude/skills/workflow-commands/fullrun-steps.md +3 -5
  21. package/.claude/skills/workflow-commands/fullrun.md +4 -6
  22. package/.claude/skills/workflow-commands/halfrun.md +3 -7
  23. package/.claude/skills/workflow-commands/into-target.md +1 -2
  24. package/.claude/skills/workflow-commands/issue-comments.md +43 -60
  25. package/.claude/skills/workflow-commands/issue-scout.md +3 -2
  26. package/.claude/skills/workflow-commands/kickoff.md +65 -74
  27. package/.claude/skills/workflow-commands/latest-gate.md +2 -6
  28. package/.claude/skills/workflow-commands/needs-human-review.md +2 -5
  29. package/.claude/skills/workflow-commands/observation-filing.md +59 -118
  30. package/.claude/skills/workflow-commands/observation-ledger.md +52 -112
  31. package/.claude/skills/workflow-commands/pre-gate-cut.md +88 -142
  32. package/.claude/skills/workflow-commands/prerequisite.md +11 -17
  33. package/.claude/skills/workflow-commands/progress-watcher.md +23 -33
  34. package/.claude/skills/workflow-commands/prrun.md +3 -5
  35. package/.claude/skills/workflow-commands/retrospective.md +35 -54
  36. package/.claude/skills/workflow-commands/split-assessment.md +32 -58
  37. package/.claude/skills/workflow-commands/target-repository.md +1 -2
  38. package/.claude/skills/workflow-commands/working-tree-hold.md +54 -73
  39. package/.codex/hooks.json +6 -6
  40. package/.github/actions/setup-node/action.yml +1 -1
  41. package/.github/workflows/ci.yml +1 -1
  42. package/.github/workflows/publish.yml +2 -2
  43. package/CLAUDE.md +7 -6
  44. package/cspell/index.yaml +7 -0
  45. package/dist/CLAUDE.md +7 -6
  46. package/dist/commands/document-section-cli.js +67 -34
  47. package/dist/hooks/batch-guard.js +6 -6
  48. package/dist/hooks/chunk-4KKD2UTK.js +66 -0
  49. package/dist/hooks/{chunk-GPLGZ6IC.js → chunk-6TS2JD6D.js} +14 -3
  50. package/dist/hooks/chunk-7DSBJVFH.js +50 -0
  51. package/dist/hooks/{chunk-5H4SSDSD.js → chunk-A65Y4YOR.js} +3 -3
  52. package/dist/hooks/{chunk-3C4XRYG6.js → chunk-APUO6U4J.js} +102 -19
  53. package/dist/hooks/{chunk-IX6TTTI6.js → chunk-EFXE6C37.js} +8 -22
  54. package/dist/hooks/chunk-GP4IEC4O.js +20 -0
  55. package/dist/hooks/chunk-JP45SOCJ.js +56 -0
  56. package/dist/hooks/{chunk-OLMO72ON.js → chunk-LAOV7NLM.js} +1 -1
  57. package/dist/hooks/chunk-M4HGZV7U.js +83 -0
  58. package/dist/hooks/{chunk-TBJFTSUY.js → chunk-O6GDRNJB.js} +9 -7
  59. package/dist/hooks/{chunk-HFGWYGUV.js → chunk-PF2NZL2A.js} +5 -5
  60. package/dist/hooks/{chunk-WNLVGT7E.js → chunk-PTICX4OL.js} +4 -5
  61. package/dist/hooks/{chunk-HHI6FO3R.js → chunk-RT27QRJW.js} +763 -1515
  62. package/dist/hooks/{chunk-7WQBPLUN.js → chunk-SYOTDYCI.js} +1149 -1095
  63. package/dist/hooks/{chunk-LIAFCXL7.js → chunk-TNUMY6NL.js} +1519 -1332
  64. package/dist/hooks/chunk-UPUZF3AN.js +279 -0
  65. package/dist/hooks/{chunk-Z4XI7CZS.js → chunk-WK6SMBIC.js} +1932 -784
  66. package/dist/hooks/codex-hook-adapter.js +17 -14
  67. package/dist/hooks/duplicate-read-guard.js +7 -7
  68. package/dist/hooks/format-edited.js +5 -4
  69. package/dist/hooks/inputs.json +302 -247
  70. package/dist/hooks/investigation-guard.js +8 -11
  71. package/dist/hooks/pretool-guard.js +16 -13
  72. package/dist/hooks/session-lang.js +372 -26
  73. package/dist/hooks/stop-guard.js +2593 -189
  74. package/dist/josh.js +2128 -282
  75. package/dist/managed-marker/index.js +1 -2
  76. package/dist/version/index.js +15 -12
  77. package/eslint/base.js +2 -1
  78. package/eslint/rules/unicorn.js +16 -0
  79. package/lefthook/base.yml +5 -3
  80. package/package.json +14 -12
  81. package/prompts/coding-standards.md +12 -22
  82. package/prompts/collaboration-workflow/file-edits.md +25 -45
  83. package/prompts/collaboration-workflow/gh-rest.md +19 -36
  84. package/prompts/collaboration-workflow/glossary.md +5 -7
  85. package/prompts/collaboration-workflow/issue-citation.md +6 -14
  86. package/prompts/collaboration-workflow/issue-template.md +40 -32
  87. package/prompts/collaboration-workflow/lane-instructions.md +35 -0
  88. package/prompts/collaboration-workflow/operating-rules.md +33 -46
  89. package/prompts/collaboration-workflow/output-bounds.md +15 -15
  90. package/prompts/collaboration-workflow/overview.md +14 -19
  91. package/prompts/collaboration-workflow/plan-comment.md +13 -13
  92. package/prompts/collaboration-workflow/principles.md +57 -54
  93. package/prompts/collaboration-workflow/proposal-request.md +1 -9
  94. package/prompts/collaboration-workflow/report-format.md +41 -49
  95. package/prompts/collaboration-workflow/residency.md +15 -11
  96. package/prompts/collaboration-workflow/rule-delivery.md +7 -15
  97. package/prompts/collaboration-workflow/shell-body.md +10 -20
  98. package/prompts/collaboration-workflow/turn-batching.md +8 -14
  99. package/prompts/collaboration-workflow/upstream-interrupt.md +26 -34
  100. package/prompts/collaboration-workflow/wip-cap.md +26 -32
  101. package/prompts/collaboration-workflow.md +25 -25
  102. package/prompts/refactoring.md +33 -43
  103. package/prompts/review-rubric.md +84 -129
  104. package/prompts/review.md +110 -141
  105. package/prompts/sonar-hotspot-handling.md +22 -50
  106. package/prompts/testing-guide.md +48 -99
  107. package/scripts/adopt/adopt-toolkits.ts +2 -4
  108. package/scripts/agent/agent-argv.ts +20 -4
  109. package/scripts/agent/agent-exit-record.ts +23 -1
  110. package/scripts/agent/agent-role-profile.ts +101 -45
  111. package/scripts/agent/agent-safe-text.ts +60 -0
  112. package/scripts/agent/claude-agent-argv.ts +14 -0
  113. package/scripts/agent/codex-agent-argv.ts +9 -2
  114. package/scripts/agent/lane-instructions.ts +144 -0
  115. package/scripts/backlog/backlog-budget-cli.ts +1 -2
  116. package/scripts/backlog/backlog-budget.ts +4 -4
  117. package/scripts/backlog/backlog-drive-carried.ts +26 -0
  118. package/scripts/backlog/backlog-drive-cli.ts +10 -5
  119. package/scripts/backlog/backlog-drive-named.ts +3 -5
  120. package/scripts/backlog/backlog-drive-restore.ts +28 -2
  121. package/scripts/backlog/backlog-drive-seats.ts +27 -0
  122. package/scripts/backlog/backlog-drive.ts +11 -6
  123. package/scripts/backlog/backlog-occupied.ts +56 -0
  124. package/scripts/backlog/backlog-ready.ts +59 -15
  125. package/scripts/behavior/behavior-rules.ts +3 -2
  126. package/scripts/cost-runtime/codex-usage.ts +4 -2
  127. package/scripts/cost-runtime/cost-cli.ts +1 -2
  128. package/scripts/delegation/duplicate-read-guard.ts +2 -2
  129. package/scripts/delegation/investigation-guard.ts +15 -65
  130. package/scripts/delegation/investigation-reads.ts +1 -2
  131. package/scripts/discovery/repo-discovery.ts +4 -2
  132. package/scripts/discovery/repo-origin.ts +2 -4
  133. package/scripts/doctor/doctor-logic.ts +6 -3
  134. package/scripts/document/document-byte-budget.ts +28 -27
  135. package/scripts/document/document-byte-check.ts +1 -2
  136. package/scripts/document/document-section-cli.ts +17 -5
  137. package/scripts/document/entry-read-budget.ts +3 -3
  138. package/scripts/document/read-set-cli.ts +4 -1
  139. package/scripts/epic/epic-audit-orphans.ts +5 -8
  140. package/scripts/epic/epic-audit-rationale.ts +8 -2
  141. package/scripts/epic/epic-audit.ts +52 -1
  142. package/scripts/epic/epic-bundle-cli.ts +1 -2
  143. package/scripts/epic/epic-bundle-evidence.ts +49 -26
  144. package/scripts/epic/epic-bundle-referenced.ts +14 -3
  145. package/scripts/epic/epic-bundle.ts +17 -9
  146. package/scripts/epic/epic-chains.ts +6 -2
  147. package/scripts/epic/epic-close-comment.ts +1 -2
  148. package/scripts/followup/git-followup-workflow.ts +19 -1
  149. package/scripts/gate/check-inputs.ts +129 -0
  150. package/scripts/gate/check-reuse.ts +162 -0
  151. package/scripts/gate/core-budget.ts +93 -44
  152. package/scripts/gate/core-wait.ts +130 -0
  153. package/scripts/gate/free-cores.ts +49 -0
  154. package/scripts/gate/gate-ledger.ts +17 -3
  155. package/scripts/gate/gate-plan.ts +23 -1
  156. package/scripts/gate/gate-report.ts +15 -2
  157. package/scripts/gate/gate-run-steps.ts +150 -0
  158. package/scripts/gate/held-mark.ts +55 -0
  159. package/scripts/gate/machine-capacity.ts +70 -11
  160. package/scripts/gate/pre-commit-type-check.ts +14 -1
  161. package/scripts/gate/verification-gate.ts +65 -127
  162. package/scripts/gh/git-gh-issue-rest.ts +1 -0
  163. package/scripts/gh/git-gh-issue-write.ts +24 -2
  164. package/scripts/gh/git-pr.ts +19 -3
  165. package/scripts/git/git-common-directory.ts +3 -3
  166. package/scripts/git/git-diff-reads.ts +16 -9
  167. package/scripts/git/git-execa-error.ts +1 -2
  168. package/scripts/git/main-merge-regenerate.ts +78 -0
  169. package/scripts/git/main-merge.ts +14 -5
  170. package/scripts/hooks/batch-guard.ts +5 -8
  171. package/scripts/hooks/format-edited-file.ts +10 -4
  172. package/scripts/hooks/pre-commit-lint.ts +91 -0
  173. package/scripts/hooks/pre-push-unit.ts +15 -4
  174. package/scripts/hooks/pretool-guard.ts +48 -79
  175. package/scripts/hooks/reserved-run.ts +1 -0
  176. package/scripts/hooks/run-hook.sh +10 -12
  177. package/scripts/hooks/step-zero-notice.ts +3 -2
  178. package/scripts/hooks/stop-actions.ts +204 -0
  179. package/scripts/hooks/stop-guard.ts +62 -21
  180. package/scripts/init/hook-command-rewrite.ts +6 -2
  181. package/scripts/init/hook-launch.ts +12 -7
  182. package/scripts/init/init-logic-deploy-vps.ts +4 -2
  183. package/scripts/issue/behavior-change-lint.ts +12 -6
  184. package/scripts/issue/expected-effect-lint.ts +59 -0
  185. package/scripts/issue/issue-cite-cli.ts +35 -15
  186. package/scripts/issue/issue-classification.ts +1 -1
  187. package/scripts/issue/issue-lint-cli.ts +5 -3
  188. package/scripts/issue/issue-scout-cli.ts +22 -16
  189. package/scripts/issue/markdown-section.ts +19 -5
  190. package/scripts/josh/command-usage.ts +110 -0
  191. package/scripts/josh/file-map-stamp.ts +1 -3
  192. package/scripts/josh/hook-decision.ts +17 -2
  193. package/scripts/josh/josh-command-map.ts +2 -0
  194. package/scripts/josh/josh-command-types.ts +55 -9
  195. package/scripts/josh/josh-commands-ai.ts +13 -0
  196. package/scripts/josh/josh-commands-development.ts +1 -1
  197. package/scripts/josh/josh-commands-hooks.ts +6 -0
  198. package/scripts/josh/josh-commands-lane.ts +10 -1
  199. package/scripts/josh/josh-commands-workflow.ts +5 -0
  200. package/scripts/josh/josh-logic.ts +6 -15
  201. package/scripts/josh/josh-usage-automation.ts +121 -0
  202. package/scripts/josh/josh-usage-backlog.ts +180 -0
  203. package/scripts/josh/josh-usage-developer.ts +230 -0
  204. package/scripts/josh/josh-usage-hooks.ts +38 -0
  205. package/scripts/josh/josh-usage-issue.ts +205 -0
  206. package/scripts/josh/josh-usage-review.ts +101 -0
  207. package/scripts/josh/josh-usage-run.ts +252 -0
  208. package/scripts/josh/josh-usage-session.ts +238 -0
  209. package/scripts/josh/josh-usage-workflow.ts +212 -0
  210. package/scripts/josh/josh.ts +14 -5
  211. package/scripts/josh/package-directory.ts +20 -0
  212. package/scripts/lane/lane-await.ts +3 -2
  213. package/scripts/lane/lane-capacity.ts +8 -2
  214. package/scripts/lane/lane-check-stats.ts +56 -0
  215. package/scripts/lane/lane-child-invocation.ts +49 -5
  216. package/scripts/lane/lane-dispatch.ts +3 -3
  217. package/scripts/lane/lane-guard-policy.ts +5 -5
  218. package/scripts/lane/lane-handoff.ts +8 -1
  219. package/scripts/lane/lane-install.ts +12 -4
  220. package/scripts/lane/lane-ledger.ts +52 -1
  221. package/scripts/lane/lane-limit-cli.ts +8 -9
  222. package/scripts/lane/lane-load.ts +9 -2
  223. package/scripts/lane/lane-measure-cli.ts +4 -0
  224. package/scripts/lane/lane-parked.ts +18 -0
  225. package/scripts/lane/lane-preserve.ts +29 -1
  226. package/scripts/lane/lane-process-load.ts +125 -0
  227. package/scripts/lane/lane-process-stats.ts +93 -0
  228. package/scripts/lane/lane-registry.ts +17 -10
  229. package/scripts/lane/lane-restart.ts +5 -26
  230. package/scripts/lane/lane-session-action.ts +146 -0
  231. package/scripts/lane/lane-session-broker.ts +68 -125
  232. package/scripts/lane/lane-spent.ts +14 -3
  233. package/scripts/lane/lane-stats.ts +1 -0
  234. package/scripts/lane/lane-withdraw-cli.ts +71 -0
  235. package/scripts/lane/lane-withdraw.ts +182 -0
  236. package/scripts/lint/format.ts +4 -4
  237. package/scripts/lint/lint-parallel.ts +10 -3
  238. package/scripts/lint/lint-related-scope.ts +4 -1
  239. package/scripts/managed-marker/managed-marker-logic.ts +1 -2
  240. package/scripts/notify/telegram-test.ts +10 -5
  241. package/scripts/overrides/lockfile-overrides.ts +1 -3
  242. package/scripts/propagate/propagate.ts +1 -2
  243. package/scripts/release/release-progress.ts +3 -2
  244. package/scripts/report/report-format-reference.ts +2 -0
  245. package/scripts/report/report-lint.ts +7 -4
  246. package/scripts/review/acceptance-map-check.ts +61 -0
  247. package/scripts/review/acceptance-map.ts +205 -0
  248. package/scripts/review/review-brief-cli.ts +1 -1
  249. package/scripts/review/review-record-cli.ts +6 -2
  250. package/scripts/rules/agent-model.ts +59 -0
  251. package/scripts/rules/delivered-rules.ts +11 -2
  252. package/scripts/rules/destructive-command.ts +6 -9
  253. package/scripts/rules/direct-filing.ts +3 -7
  254. package/scripts/rules/early-heartbeat.ts +7 -18
  255. package/scripts/rules/file-body.ts +6 -13
  256. package/scripts/rules/filing-cap.ts +4 -6
  257. package/scripts/rules/firing-point.ts +6 -5
  258. package/scripts/rules/git-force.ts +5 -9
  259. package/scripts/rules/guard-remedy.ts +117 -0
  260. package/scripts/rules/implementation-cut.ts +37 -35
  261. package/scripts/rules/index-guard.ts +4 -7
  262. package/scripts/rules/issue-comments.ts +67 -16
  263. package/scripts/rules/josh-git-bare.ts +3 -6
  264. package/scripts/rules/lane-background.ts +10 -21
  265. package/scripts/rules/lane-carry-conflict.ts +7 -17
  266. package/scripts/rules/lane-interactive-ask.ts +6 -11
  267. package/scripts/rules/lane-park.ts +5 -13
  268. package/scripts/rules/lane-split-park.ts +2 -7
  269. package/scripts/rules/lane-switch-main.ts +9 -12
  270. package/scripts/rules/last-prompt.ts +50 -5
  271. package/scripts/rules/oracle-consulted.ts +4 -5
  272. package/scripts/rules/oracle-list-cli.ts +7 -0
  273. package/scripts/rules/piped-verification.ts +84 -32
  274. package/scripts/rules/poll-loop.ts +7 -17
  275. package/scripts/rules/pre-gate-cut.ts +7 -21
  276. package/scripts/rules/prior-comment-read.ts +7 -5
  277. package/scripts/rules/protected-files.ts +5 -9
  278. package/scripts/rules/raw-field-body.ts +3 -7
  279. package/scripts/rules/rule-body-guard.ts +4 -11
  280. package/scripts/rules/rule-list.ts +4 -1
  281. package/scripts/rules/rule-registry-rows.ts +10 -0
  282. package/scripts/rules/rule-registry.ts +7 -4
  283. package/scripts/rules/rule-rewrite.ts +114 -0
  284. package/scripts/rules/rule-value.ts +7 -1
  285. package/scripts/rules/run-tail-rule.ts +6 -22
  286. package/scripts/rules/shell-body-trigger.ts +4 -6
  287. package/scripts/rules/shell-segments.ts +22 -0
  288. package/scripts/rules/stop-decision.ts +77 -0
  289. package/scripts/rules/stop-rules.ts +164 -77
  290. package/scripts/rules/tail-commands.ts +15 -1
  291. package/scripts/rules/test-declared-commit.ts +4 -10
  292. package/scripts/rules/third-party-write.ts +5 -10
  293. package/scripts/rules/worktree-guard.ts +5 -12
  294. package/scripts/run/board/run-board-cli.ts +2 -0
  295. package/scripts/run/board/run-board-closed.ts +8 -2
  296. package/scripts/run/board/run-board-github.ts +19 -3
  297. package/scripts/run/board/run-board-header.ts +4 -1
  298. package/scripts/run/board/run-board-idle.ts +31 -0
  299. package/scripts/run/board/run-board-labels.ts +2 -0
  300. package/scripts/run/board/run-board-layout.ts +1 -1
  301. package/scripts/run/board/run-board-read.ts +25 -12
  302. package/scripts/run/board/run-board-reason.ts +17 -4
  303. package/scripts/run/board/run-board-render-legend.ts +1 -0
  304. package/scripts/run/board/run-board-render-slot.ts +1 -1
  305. package/scripts/run/board/run-board-render-waits.ts +41 -0
  306. package/scripts/run/board/run-board-render.ts +6 -1
  307. package/scripts/run/board/run-board-row-yield.ts +1 -0
  308. package/scripts/run/board/run-board-state.ts +9 -0
  309. package/scripts/run/board/run-board-status.ts +89 -23
  310. package/scripts/run/board/run-board-thanks.ts +7 -2
  311. package/scripts/run/board/run-board-tick.ts +37 -8
  312. package/scripts/run/carry/run-carry-args.ts +1 -3
  313. package/scripts/run/carry/run-carry-conversation.ts +7 -2
  314. package/scripts/run/cut/run-cut-cli.ts +18 -22
  315. package/scripts/run/cut/run-cut-decline.ts +72 -0
  316. package/scripts/run/cut/run-cut-ready.ts +74 -0
  317. package/scripts/run/cut/run-cut-report.ts +29 -0
  318. package/scripts/run/cut/run-cut.ts +10 -1
  319. package/scripts/run/detached-launch.ts +23 -4
  320. package/scripts/run/entry/run-entry-cli.ts +8 -1
  321. package/scripts/run/event/run-event-render.ts +1 -0
  322. package/scripts/run/event/run-event-scope.ts +19 -1
  323. package/scripts/run/event/run-event-stream-emit.ts +13 -6
  324. package/scripts/run/event/run-event-stream.ts +4 -0
  325. package/scripts/run/hold/run-hold-cli.ts +14 -3
  326. package/scripts/run/hold/run-hold-session.ts +46 -0
  327. package/scripts/run/hold/run-hold.ts +13 -4
  328. package/scripts/run/launch-priority.ts +32 -0
  329. package/scripts/run/merge/run-merge-cli.ts +16 -42
  330. package/scripts/run/merge/run-merge-ship.ts +59 -1
  331. package/scripts/run/merge/run-merge-signals.ts +99 -0
  332. package/scripts/run/merge/run-merge-steps.ts +11 -1
  333. package/scripts/run/merge/run-merge.ts +22 -9
  334. package/scripts/run/run-ending.ts +31 -3
  335. package/scripts/run/run-liveness.ts +1 -1
  336. package/scripts/run/run-parent-cut-hook.ts +5 -10
  337. package/scripts/run/run-poll-hook.ts +157 -0
  338. package/scripts/run/run-preflight.ts +1 -2
  339. package/scripts/run/run-step-cli.ts +22 -15
  340. package/scripts/run/run-step-section.ts +85 -0
  341. package/scripts/run/run-stop-notify.ts +1 -2
  342. package/scripts/run/run-watcher-guard.ts +6 -3
  343. package/scripts/run/ship/run-ship-cli.ts +5 -12
  344. package/scripts/run/ship/run-ship-detach.ts +9 -0
  345. package/scripts/run/ship/run-ship-next.ts +10 -2
  346. package/scripts/run/ship/run-ship-overlap.ts +195 -0
  347. package/scripts/run/ship/run-ship-pre-detach.ts +33 -15
  348. package/scripts/run/ship/run-ship-preflight.ts +28 -2
  349. package/scripts/run/ship/run-ship-return.ts +31 -7
  350. package/scripts/run/ship/run-ship-review-steps.ts +25 -14
  351. package/scripts/run/ship/run-ship-review.ts +15 -2
  352. package/scripts/run/ship/run-ship-steps.ts +1 -1
  353. package/scripts/run/ship/run-ship-stop-context.ts +206 -0
  354. package/scripts/run/ship/run-ship-sync.ts +14 -6
  355. package/scripts/run/tidy/run-tidy-cli.ts +3 -3
  356. package/scripts/run/tidy/run-tidy-lanes.ts +3 -2
  357. package/scripts/safe-chain/project-config.ts +7 -2
  358. package/scripts/sync/sync-hook-safety.ts +8 -2
  359. package/scripts/test/test-e2e-guard.ts +30 -5
  360. package/scripts/test/test-unit-guard.ts +16 -1
  361. package/scripts/test/unit-worker-share.ts +26 -3
  362. package/scripts/time-runtime/time-batch-guard.ts +3 -3
  363. package/scripts/time-runtime/time-hook-transcript.ts +3 -2
  364. package/scripts/time-runtime/time-shell.ts +39 -4
  365. package/scripts/time-runtime/time-spans.ts +1 -0
  366. package/scripts/time-runtime/time-tool-call.ts +7 -0
  367. package/scripts/version/effective-upstream.ts +3 -4
  368. package/scripts/version/kit-version-config.ts +8 -2
  369. package/scripts/version/latest-corepack.ts +1 -2
  370. package/scripts/version/release-hold.ts +11 -4
  371. package/scripts/version/version-commands.ts +12 -4
  372. package/templates/gitignore +6 -2
  373. package/dist/hooks/chunk-D5QBTOCZ.js +0 -68
  374. package/dist/hooks/chunk-UT7YC3N2.js +0 -56
@@ -0,0 +1,212 @@
1
+ import type { CommandUsage } from './josh-command-types'
2
+
3
+ // The usage of the commands `docs/josh-commands-automation.md` documents under "Workflow",
4
+ // "Versioning", "Maintenance" and "Git hooks", keyed by command name. The page's usage blocks are
5
+ // generated from this table and `josh help <command>` prints it, so an example or a flag is written
6
+ // once, here (#3939).
7
+ const PR_TITLE = '"PR title #N"'
8
+ const ISSUE_URL = '--issue-url "https://..."'
9
+ const REVIEW_ISSUE = '--issue 2325'
10
+ const CHECK = '--check'
11
+ const JSON_FLAG = '--json'
12
+ const BODY_FILE_NOTE =
13
+ '(`-` reads stdin); use this whenever the body carries a backtick or `$`. Passing both forms is refused.'
14
+
15
+ /* eslint-disable @typescript-eslint/naming-convention */
16
+ const WORKFLOW_USAGE: Readonly<Record<string, CommandUsage>> = {
17
+ followup: {
18
+ examples: [
19
+ { arguments: PR_TITLE, note: 'merges (default)' },
20
+ { arguments: String.raw`${PR_TITLE} --notify-message "Implemented X:\n- change 1"` },
21
+ { arguments: `${PR_TITLE} --notify-message-file completion.md` },
22
+ { arguments: `${PR_TITLE} --ai-review-ignore-reason "false positive"` },
23
+ { arguments: `${PR_TITLE} --no-merge`, note: 'do the work, leave the PR open' },
24
+ ],
25
+ flags: [
26
+ {
27
+ names: ['--no-merge'],
28
+ description:
29
+ 'do the follow-up work but do not merge; leaves the PR open (the only flag that stops the merge). `--merge` is a deprecated no-op. A PR already merged by hand skips the CI wait, the AI-review scan and the merge and runs only the post-merge tail; a completion report already on the Issue is not posted again.',
30
+ },
31
+ {
32
+ names: ['--notify-message'],
33
+ description: 'inline completion body; `\\n` expands to newlines.',
34
+ },
35
+ {
36
+ names: ['--notify-message-file'],
37
+ description: `read the completion body from a file ${BODY_FILE_NOTE}`,
38
+ },
39
+ {
40
+ names: ['--ai-review-ignore-reason'],
41
+ description: 'reason to dismiss an AI-review finding.',
42
+ },
43
+ ],
44
+ },
45
+ notify: {
46
+ examples: [
47
+ { arguments: String.raw`--task-type planning ${ISSUE_URL} --body="- bullet 1\n- bullet 2"` },
48
+ {
49
+ arguments: `--task-type confirmation ${ISSUE_URL} --body-file r.md --recommended "Go" --alternative "Wait"`,
50
+ },
51
+ ],
52
+ flags: [
53
+ {
54
+ names: ['--task-type'],
55
+ description:
56
+ 'one of `planning` 📋, `completion` ✅, `failure` ❌, `warning` ⚠️, `kickoff_retry` 🔄, `confirmation` ⏸️. Do not send `completion` or `warning` by hand — `josh followup` sends them.',
57
+ },
58
+ {
59
+ names: ['--body', "--body=$'…'"],
60
+ description: "inline body; use `--body=$'…'` when it starts with `-`.",
61
+ },
62
+ { names: ['--body-file'], description: `read the body from a file ${BODY_FILE_NOTE}` },
63
+ {
64
+ names: ['--repo-name', '--issue-url', '--pr-url'],
65
+ description:
66
+ 'header repository, resolved in that order, then the working directory. The issue title is read from `--issue-url`.',
67
+ },
68
+ {
69
+ names: ['--recommended', '--alternative'],
70
+ description:
71
+ 'the choices appended under `JOSH_SESSION_LANG` headings; `--recommended` is required for `confirmation`, `--alternative` is repeatable.',
72
+ },
73
+ ],
74
+ },
75
+ 'observations:flush': { examples: [{ arguments: '' }] },
76
+ 'measure:rerun': { examples: [{ arguments: '2212' }] },
77
+ 'review:record': {
78
+ examples: [
79
+ { arguments: `${REVIEW_ISSUE} bug-risks:medium:src/foo.ts:42 tests:low:a.test.ts` },
80
+ { arguments: REVIEW_ISSUE, note: 'a zero-finding round — records one `none` line' },
81
+ {
82
+ arguments: `${REVIEW_ISSUE} --comment`,
83
+ note: 'a round that passed after the PR opened — an Issue comment, no append',
84
+ },
85
+ { arguments: `${CHECK} ${REVIEW_ISSUE}`, note: 'the merge gate: was it recorded?' },
86
+ ],
87
+ },
88
+ bump: { examples: [{ arguments: 'major' }, { arguments: 'minor' }, { arguments: 'patch' }] },
89
+ release: {
90
+ examples: [
91
+ { arguments: '' },
92
+ { arguments: '--dry-run', note: 'count and report, write nothing' },
93
+ ],
94
+ flags: [
95
+ {
96
+ names: ['--dry-run'],
97
+ description:
98
+ 'count and report only; writes nothing, fetches nothing, and creates no work tree.',
99
+ },
100
+ {
101
+ names: ['--help', '-h'],
102
+ description:
103
+ 'print the usage line and exit 0 without fetching or releasing. Any other argument is refused with the usage line and a non-zero exit, before anything is fetched.',
104
+ },
105
+ ],
106
+ },
107
+ 'release:scope': {
108
+ examples: [
109
+ { arguments: '', note: '→ required | skip | unknown' },
110
+ { arguments: '--json', note: '{"scope":"…","reason":"…"} on one line' },
111
+ ],
112
+ },
113
+ 'ruleset:check': {
114
+ examples: [
115
+ { arguments: '', note: 'report only' },
116
+ { arguments: '--apply', note: 'add the missing checks to the existing rule' },
117
+ ],
118
+ flags: [
119
+ {
120
+ names: ['--apply'],
121
+ description:
122
+ "append the missing checks to the ruleset's required-checks rule (or to the branch protection's contexts). It never creates a ruleset: with none, create one under Settings → Rules → Rulesets, then rerun. Writing a repository setting needs admin access, so only this flag writes — `josh sync` and `josh doctor` never do.",
123
+ },
124
+ ],
125
+ },
126
+ 'audit:provision': {
127
+ examples: [
128
+ { arguments: '', note: 'no-op if a scanner is already present' },
129
+ { arguments: '--force', note: 'ignore backoff, allow a longer download' },
130
+ ],
131
+ flags: [
132
+ {
133
+ names: ['--force'],
134
+ description:
135
+ 'ignore the 6-hour failure backoff and allow a longer download window; the command to run after fixing a network problem.',
136
+ },
137
+ ],
138
+ },
139
+ 'reconcile-templates': {
140
+ examples: [
141
+ { arguments: '', note: 'regenerate copy templates + record tripwire hashes' },
142
+ { arguments: CHECK, note: 'verify templates are in sync; non-zero on drift' },
143
+ ],
144
+ flags: [
145
+ {
146
+ names: [CHECK],
147
+ description:
148
+ 'verify only; exits non-zero on drift. A pre-commit hook runs this when a tracked source or copy template is staged.',
149
+ },
150
+ ],
151
+ },
152
+ 'pre-push-unit': { examples: [{ arguments: '' }] },
153
+ 'reserved-run': {
154
+ examples: [
155
+ { arguments: '2 -- pnpm install', note: 'hold 2 cores while installing' },
156
+ { arguments: '1 -- pnpm josh audit', note: 'hold 1 core while scanning' },
157
+ ],
158
+ },
159
+ 'pre-commit-type-check': { examples: [{ arguments: '' }] },
160
+ 'pr:classification': {
161
+ examples: [{ arguments: '', note: 'run by CI on a pull request; fails without one label' }],
162
+ },
163
+ 'observation:record': {
164
+ examples: [
165
+ { arguments: "flaky-e2e d1 'tests/e2e/login.test.ts' 'times out on CI only'" },
166
+ {
167
+ arguments: "flaky-e2e d1 'src/app.ts' 'fails there too' --checkout ~/Development/app",
168
+ note: "another repository's ledger",
169
+ },
170
+ ],
171
+ flags: [
172
+ {
173
+ names: ['--checkout <path>'],
174
+ description: "count and append in that repository's `.josh/observations/` instead.",
175
+ },
176
+ ],
177
+ },
178
+ 'release:github': {
179
+ examples: [
180
+ { arguments: '', note: 'run by CI with GH_TOKEN, RELEASE_TAG and GITHUB_REPOSITORY set' },
181
+ ],
182
+ },
183
+ 'latest:scope': {
184
+ examples: [
185
+ { arguments: '', note: 'required or skip, the reason on stderr' },
186
+ { arguments: '--record', note: 'note a finished josh latest run' },
187
+ { arguments: JSON_FLAG, note: 'the verdict and the reason as JSON' },
188
+ ],
189
+ flags: [
190
+ { names: ['--record'], description: 'write the completion record `josh latest` ends with.' },
191
+ { names: [JSON_FLAG], description: 'emit the verdict and its reason as JSON.' },
192
+ ],
193
+ },
194
+ 'latest:guard': { examples: [{ arguments: '', note: 'refuses inside a lane' }] },
195
+ 'prevent-main-commit': { examples: [{ arguments: '', note: 'run by the pre-commit hook' }] },
196
+ 'check-commit-message': {
197
+ examples: [{ arguments: '.git/COMMIT_EDITMSG', note: 'run by the commit-msg hook' }],
198
+ },
199
+ 'secretlint-scan': {
200
+ examples: [{ arguments: 'src/app.ts .env.example', note: 'the staged paths' }],
201
+ },
202
+ 'pre-commit-lint': {
203
+ examples: [
204
+ { arguments: 'cspell src/app.ts' },
205
+ { arguments: 'prettier src/app.ts' },
206
+ { arguments: 'eslint src/app.ts' },
207
+ ],
208
+ },
209
+ }
210
+ /* eslint-enable @typescript-eslint/naming-convention */
211
+
212
+ export { WORKFLOW_USAGE }
@@ -1,4 +1,5 @@
1
1
  import { doctor_consumer } from '#scripts/doctor/doctor-consumer'
2
+ import { command_usage } from './command-usage'
2
3
  import { find_package_directory, josh_logic, UNKNOWN_COMMAND_EXIT_CODE } from './josh-logic'
3
4
 
4
5
  const ARGV_OFFSET = 2
@@ -12,10 +13,6 @@ const HELP_COMMANDS: ReadonlySet<string> = new Set(['help', '--help', '-h'])
12
13
  // A bare `--all` in the command slot is a help request, not a command.
13
14
  const ALL_FLAG = '--all'
14
15
 
15
- function print_help(is_all: boolean, is_consumer: boolean): void {
16
- console.info(josh_logic.format_help(is_all, is_consumer))
17
- }
18
-
19
16
  // Both halves go to stderr. The help listing is a diagnosis here, not the answer, and a shell
20
17
  // wiring `--port $(josh port dev)` reads stdout alone, so a command name this kit cannot resolve
21
18
  // has to leave that stream empty rather than substitute the whole toolkit index (#825).
@@ -24,6 +21,18 @@ function handle_unknown(cmd: string): never {
24
21
  process.exit(1)
25
22
  }
26
23
 
24
+ // `josh help <command>` prints that one command's usage — the text its reference page renders
25
+ // (#3932); a flag in the topic slot is still a listing request (`josh --help --all`).
26
+ function print_help(is_all: boolean, is_consumer: boolean, topic: string | undefined): void {
27
+ if (topic === undefined || topic.startsWith('-')) {
28
+ console.info(josh_logic.format_help(is_all, is_consumer))
29
+
30
+ return
31
+ }
32
+
33
+ console.info(command_usage.format_command_help(topic) ?? handle_unknown(topic))
34
+ }
35
+
27
36
  // `process.exit` truncates a piped stdout at its buffer size, and the output at risk is the script's
28
37
  // own — `scripts/gate/verification-gate.ts` writes its per-check blocks
29
38
  // and its failure summary through this process, and sets `process.exitCode` rather than exiting for
@@ -44,7 +53,7 @@ async function main(): Promise<void> {
44
53
  const is_consumer = doctor_consumer.is_kit_consumer(find_package_directory(process.cwd()))
45
54
 
46
55
  if (!cmd || cmd === ALL_FLAG || HELP_COMMANDS.has(cmd)) {
47
- print_help(is_all, is_consumer)
56
+ print_help(is_all, is_consumer, process.argv[ARGV_OFFSET + 1])
48
57
 
49
58
  return
50
59
  }
@@ -0,0 +1,20 @@
1
+ import { existsSync } from 'node:fs'
2
+ import path from 'node:path'
3
+ import { ancestor_directories } from '#scripts/lib/ancestor-directories'
4
+
5
+ const PACKAGE_JSON = 'package.json'
6
+
7
+ // Resolve the kit package root by ascending to the nearest package.json. This works both
8
+ // from the bundled dist/josh.js (one level under the root) and from the tsx source at
9
+ // scripts/josh/ (two levels), so this file's depth no longer has to be hard-coded.
10
+ // A leaf apart from `josh-logic`, so a bundled command can import it without pulling the
11
+ // dispatcher's main-guarded closure into its single-file bundle.
12
+ function find_package_directory(start_directory: string): string {
13
+ return (
14
+ ancestor_directories.nearest(start_directory, (directory) =>
15
+ existsSync(path.join(directory, PACKAGE_JSON)),
16
+ ) ?? start_directory
17
+ )
18
+ }
19
+
20
+ export { find_package_directory }
@@ -89,8 +89,9 @@ function process_trace_default(issue: string): ProcessTrace {
89
89
 
90
90
  process_tools.throw_if_missing(PGREP_COMMAND, result.error)
91
91
 
92
- if (result.status === PROCESS_FOUND) return PROCESS_ALIVE
93
- if (lane_handoff.is_ship_running(issue, process.cwd())) return PROCESS_ALIVE
92
+ if (result.status === PROCESS_FOUND || lane_handoff.is_ship_running(issue, process.cwd())) {
93
+ return PROCESS_ALIVE
94
+ }
94
95
 
95
96
  return result.status === PROCESS_NOT_FOUND ? PROCESS_NONE : PROCESS_UNKNOWN
96
97
  }
@@ -73,8 +73,14 @@ function seated_limit(limit: number): number {
73
73
  // Never negative: a repository holding more `in-progress` issues than the limit allows — the limit
74
74
  // was lowered, or a stale label outlived its run — has no free lane, and a negative count read as
75
75
  // "how many to offer" would be a slice nobody meant.
76
- function free_lanes(limit: number, occupied: number): number {
77
- return Math.max(NO_LANES, seated_limit(limit) - occupied)
76
+ //
77
+ // **A lane that holds no place under the limit still holds its port seat** (joshuafolkken/kit#3967):
78
+ // `seated` counts every open lane, so the free count never offers more launches than seats are left.
79
+ function free_lanes(limit: number, occupied: number, seated = occupied): number {
80
+ const by_limit = seated_limit(limit) - occupied
81
+ const by_seats = lane_seed_policy.LAST_LANE_SEAT - seated
82
+
83
+ return Math.max(NO_LANES, Math.min(by_limit, by_seats))
78
84
  }
79
85
 
80
86
  const lane_capacity = {
@@ -0,0 +1,56 @@
1
+ import { lane_ledger, type GateCheckRecord, type GateEntry, type LedgerEntry } from './lane-ledger'
2
+ import { lane_stage_stats } from './lane-stage-stats'
3
+ import { lane_stats, type StatsWindow } from './lane-stats'
4
+
5
+ // Which check a gate waited on: the ledger's per-check rows of one period reduced to one row per check
6
+ // — median, maximum, how many runs and how many were reused — printed last by `josh lane:stats`. The
7
+ // rows are in the order the checks first appear.
8
+ //
9
+ // **A reused check is counted, never timed.** It started no process, so its zero would pull the median
10
+ // toward a check that never ran; a check with only reused rows prints `not measured`.
11
+
12
+ const MS_PER_SECOND = 1000
13
+ const DECIMALS = 1
14
+ const COLUMNS = ['check', 'median (s)', 'max (s)', 'runs', 'reused'] as const
15
+
16
+ function is_gate(entry: LedgerEntry): entry is GateEntry {
17
+ return entry.kind === lane_ledger.KIND.GATE
18
+ }
19
+
20
+ function cell(milliseconds: number | undefined): string {
21
+ return milliseconds === undefined
22
+ ? lane_stage_stats.NOT_MEASURED
23
+ : (milliseconds / MS_PER_SECOND).toFixed(DECIMALS)
24
+ }
25
+
26
+ function check_row(label: string, checks: ReadonlyArray<GateCheckRecord>): string {
27
+ const runs = checks.filter((check) => check.label === label)
28
+ const timed = runs.filter((check) => check.is_reused !== true).map((check) => check.elapsed_ms)
29
+
30
+ return lane_stats.to_row([
31
+ label,
32
+ cell(lane_stats.median(timed)),
33
+ cell(lane_stats.peak(timed)),
34
+ String(runs.length),
35
+ String(runs.length - timed.length),
36
+ ])
37
+ }
38
+
39
+ // The period's table: `entries` is the whole ledger, filtered here to `window`.
40
+ function table(entries: ReadonlyArray<LedgerEntry>, window: StatsWindow): string {
41
+ const checks = lane_stats
42
+ .in_window(entries, window)
43
+ .filter(is_gate)
44
+ .flatMap((gate) => gate.checks ?? [])
45
+ const labels = [...new Set(checks.map((check) => check.label))]
46
+
47
+ return [
48
+ lane_stats.to_row(COLUMNS),
49
+ lane_stats.to_row(COLUMNS.map(() => '---')),
50
+ ...labels.map((label) => check_row(label, checks)),
51
+ ].join('\n')
52
+ }
53
+
54
+ const lane_check_stats = { table }
55
+
56
+ export { lane_check_stats }
@@ -1,13 +1,19 @@
1
+ import { agent_role_profile } from '#scripts/agent/agent-role-profile'
1
2
  import { issue_cite } from '#scripts/issue/issue-cite'
2
3
  import { issue_number_shape } from '#scripts/issue/issue-number-shape'
3
4
  import { run_ship_next, type ShipResume } from '#scripts/run/ship/run-ship-next'
4
5
  import type { Stage } from '#scripts/run/ship/run-ship-stage'
6
+ import { run_ship_stop_context, type StopContext } from '#scripts/run/ship/run-ship-stop-context'
5
7
 
6
8
  interface ShipStop extends ShipResume {
7
9
  stage: Stage
10
+ context?: StopContext
8
11
  }
9
12
 
10
13
  const CHILD_INVOCATION = 'fullrun'
14
+ const LINE_BREAK = '\n'
15
+ // What a brokered reviewer's prompt ends with, so the one pattern below finds it too.
16
+ const REVIEW_INVOCATION = 'the reviewer of lane'
11
17
  const RESUME_GUIDE = '.claude/skills/workflow-commands/pre-gate-cut.md'
12
18
  // What a detached `josh ship --detach` supervisor's command line carries. It ends
13
19
  // with the `"<title> #<N>"` title on purpose, so the liveness pattern below finds it by the same trailing
@@ -31,10 +37,20 @@ function child_invocation(issue: string): string {
31
37
  // pattern stopped matching as finished — parking an issue that was still shipping. The supervisor's
32
38
  // command line ends with its `#<N>` title, so the one extended pattern covers both, and the wait, the
33
39
  // liveness read and the reaper keep searching with a single pattern.
40
+ //
41
+ // **A brokered reviewer counts as the child too** (joshuafolkken/kit#3878). The lane's broker starts it
42
+ // for a ship and it outlives a ship that stopped waiting: unmatched, the lane read as finished, the
43
+ // run parked the issue under it, and the reap left it running checks in the parked lane.
34
44
  function process_pattern(issue: string): string {
35
45
  issue_number_shape.require_issue_number(issue)
36
46
 
37
- return `(${CHILD_INVOCATION}|${SHIP_PROCESS} .*) ${issue_cite.plain(issue)}$`
47
+ return `(${CHILD_INVOCATION}|${REVIEW_INVOCATION}|${SHIP_PROCESS} .*) ${issue_cite.plain(issue)}$`
48
+ }
49
+
50
+ function review_invocation(issue: string): string {
51
+ issue_number_shape.require_issue_number(issue)
52
+
53
+ return `${REVIEW_INVOCATION} ${issue_cite.plain(issue)}`
38
54
  }
39
55
 
40
56
  function resume_invocation(issue: string): string {
@@ -67,14 +83,41 @@ function outage_resume_invocation(issue: string): string {
67
83
  // **A known stage puts the next command in the prompt**, so the relaunched
68
84
  // session runs it rather than re-deriving it from `chain-rule.md`. An OpenAI lane's supervisor sees only
69
85
  // that the ship failed, not where, so without a stage the prompt points at `run:step` as before.
86
+ //
87
+ // **A stop that carries its context puts it in the prompt too** — the failed output's
88
+ // tail and the changed files (`run-ship-stop-context.ts`), so the session starts at the fix rather than
89
+ // at `josh ship --log` and `git diff` (joshuafolkken/kit#3923).
90
+ //
91
+ // The context gets what the rest of the prompt leaves of the one argv element's cap, so the whole
92
+ // prompt still launches (joshuafolkken/kit#3964).
93
+ function known_stop_lines(
94
+ issue: string,
95
+ stop: ShipStop,
96
+ frame: ReadonlyArray<string>,
97
+ ): ReadonlyArray<string> {
98
+ const { context } = stop
99
+ const is_excerpted = run_ship_stop_context.has_excerpt(context)
100
+ const next = run_ship_next.next_step(issue, stop.stage, stop, is_excerpted)
101
+
102
+ if (context === undefined) return [next]
103
+
104
+ const fixed = [...frame, next].join(LINE_BREAK).length + LINE_BREAK.length
105
+ const budget = agent_role_profile.MAX_VALUE_LENGTH - fixed
106
+
107
+ return [next, run_ship_stop_context.describe(issue, context, budget)]
108
+ }
109
+
70
110
  function ship_stop_invocation(issue: string, stop?: ShipStop): string {
71
111
  const opening = `Resuming the lane child for issue ${issue_cite.plain(issue)} after its detached ship supervisor stopped at a failed stage — do not re-read the workflow-commands entry documents (SKILL.md, fullrun.md).`
72
- const next =
112
+ const closing = `Do not re-plan or re-implement what is already on the branch. ${child_invocation(issue)}`
113
+ const middle =
73
114
  stop === undefined
74
- ? `Run \`pnpm josh run:step ${issue}\` and read the stopped report it names, fix what stopped the ship, then hand the region back per chain-rule.md.`
75
- : run_ship_next.next_step(issue, stop.stage, stop)
115
+ ? [
116
+ `Run \`pnpm josh run:step ${issue}\` and read the stopped report it names, fix what stopped the ship, then hand the region back per chain-rule.md.`,
117
+ ]
118
+ : known_stop_lines(issue, stop, [opening, closing])
76
119
 
77
- return `${opening} ${next} Do not re-plan or re-implement what is already on the branch. ${child_invocation(issue)}`
120
+ return [opening, ...middle, closing].join(LINE_BREAK)
78
121
  }
79
122
 
80
123
  const lane_child_invocation = {
@@ -82,6 +125,7 @@ const lane_child_invocation = {
82
125
  outage_resume_invocation,
83
126
  process_pattern,
84
127
  resume_invocation,
128
+ review_invocation,
85
129
  ship_stop_invocation,
86
130
  }
87
131
 
@@ -7,7 +7,7 @@ import { IN_PROGRESS_LABEL } from '#scripts/issue/issue-labels'
7
7
  import { issue_number_shape } from '#scripts/issue/issue-number-shape'
8
8
  import { session_cite } from '#scripts/issue/session-cite'
9
9
  import { telegram_notify } from '#scripts/notify/telegram-notify'
10
- import { detached_launch } from '#scripts/run/detached-launch'
10
+ import { detached_launch, type LaunchArgv } from '#scripts/run/detached-launch'
11
11
  import { run_event_stream } from '#scripts/run/event/run-event-stream'
12
12
  import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
13
13
  import { run_ending } from '#scripts/run/run-ending'
@@ -197,7 +197,7 @@ function existing_dispatch(request: StartRequest): DispatchOutcome | undefined {
197
197
  return dispatched_of(request, active.pid, [])
198
198
  }
199
199
 
200
- function launch_argv(request: StartRequest, nonce: string | undefined): AgentArgv {
200
+ function launch_argv(request: StartRequest, nonce: string | undefined): LaunchArgv {
201
201
  if (request.profile.provider !== 'openai') return request.argv
202
202
  if (nonce === undefined) throw new Error('OpenAI supervisor nonce is missing')
203
203
 
@@ -404,7 +404,7 @@ function log_sentence(outcome: Dispatched, issue: string): string {
404
404
  return ` Its output is NOT being kept — ${outcome.notes.join(NOTE_SEPARATOR)} — so ${outcome.log_path} will not grow and the process trace is the only answer: ${poll}.`
405
405
  }
406
406
 
407
- return ` It writes to ${outcome.log_path}. To poll it, ${poll}.`
407
+ return ` It writes to ${outcome.log_path}. Wait on it with \`pnpm josh lane:await ${issue} --owner "$PPID"\` in the background and end the turn; once that output falls silent, ${poll}.`
408
408
  }
409
409
 
410
410
  // Whether this dispatch resumed the disconnected child's session or started fresh — the report the
@@ -45,27 +45,27 @@ interface LaneGuardEntry {
45
45
  const LANE_GUARD_POLICY: ReadonlyArray<LaneGuardEntry> = [
46
46
  {
47
47
  id: 'investigation',
48
- mode_in_lane_child: 'notice',
48
+ mode_in_lane_child: 'refuse',
49
49
  because:
50
- 'a refusal ends a child turn so it cannot fire as one (kit#2138), which is why it was `off` from #2138 to #2382. The exemption reason — "the child is itself the delegated unit, so it cannot dispatch a sub-unit to read its own edit targets" — did not hold in measurement: kit#2382 re-measured the six lane children after #2347 (#2366 #2370 #2371 #2372 #2374 #2375) and every one dispatched sub-agents (10 launches, 2 of them investigation fan-outs) and read 4–17 files it never edited, all six over the threshold of 3. So the reading the guard exists to send out was there to send. It takes `notice`, not `off`: the child is nudged to delegate rather than killed, on the `additionalContext` path batching and duplicate-read already use, and the notice names the concrete unedited files this run read (the #2276 precedent) rather than the generic "delegate" #2164 → #2178 measured not to move the number. The density is a genuine experiment — re-measured on the next backlogrun, and a notice that still does not move it is redesigned rather than kept',
50
+ 'the notice was measured not to move the reading — 52% of lane cost stayed in main-line exploration — and the refusal fires once per accumulation, a round trip the child survives as it survives the rule row, so the child is refused like the main line',
51
51
  },
52
52
  {
53
53
  id: 'batching',
54
54
  mode_in_lane_child: 'off',
55
55
  because:
56
- 'a refusal ends a child turn so it cannot fire as one (kit#2138); kit#2164 replaced it with a notice, kit#2178 took that notice off after it did not move the density, and kit#2276 restored it — naming the concrete recent calls and recurring every single-call turn — as a genuine experiment to be redesigned rather than kept if the next backlogrun still missed 1.40. kit#2405 is that re-measurement, and it cuts the notice off (`off`). `josh time:density` read 1.13 calls per round trip over the ten most recent lanes (1.04 in the Issue’s per-message frame), short of the 1.40 target as every advisory attempt before it was (kit#1304/#1329/#1337/#1390/#2164/#2276). The cause is structural rather than wording: a `PreToolUse` hook cannot see the turn it is in — a turn’s later `tool_use` lines arrive 1.4–15s after its first — so it judges only closed turns, and a notice at turn close still asks for the parallel `tool_use` blocks the model resists. The one lever measured to move the density is a composite command the model emits in a single call (`read:files`/`edit:files`, kit#2202/#2311), which needs no notice. So per the issue’s instruction to discontinue advisory means when the target is missed, the notice is cut off rather than rewritten a seventh time; the density stays readable through `josh time:density`',
56
+ 'a refusal ends a child turn and every advisory notice was measured not to move the call density, so the guard is off and the density stays readable through `josh time:density`',
57
57
  },
58
58
  {
59
59
  id: 'duplicate-read',
60
60
  mode_in_lane_child: 'notice',
61
61
  because:
62
- 'a refusal ends a child turn so it cannot fire as one (kit#2138), and the unchanged re-reads the guard catches are measured in lane children above all (kit#2298 baseline: 8.0 per lane run) — so silencing it there (`off`) would neuter it exactly where the count lives. It takes `notice` instead: the child is nudged to scroll up to the earlier read rather than killed. The mode is a genuine experiment, as the batching notice is — a notice that does not reduce the duplicate reads on the next backlogrun is redesigned rather than kept',
62
+ 'a refusal ends a child turn, yet unchanged re-reads are measured in lane children above all, so the child is nudged to scroll up to the earlier read by a notice rather than killed',
63
63
  },
64
64
  {
65
65
  id: 'rule',
66
66
  mode_in_lane_child: 'refuse',
67
67
  because:
68
- "it carries the lane-only rules a child depends on (`pre-gate-cut`, `implementation-cut`, `lane-park`) and the safety rules a child must still obey (`shell-body`, `piped-verification`); a blanket suppression would disarm exactly the guards written for the child. `implementation-cut` (joshuafolkken/kit#2310) needs `refuse` for the same reason the pre-gate cut does — kit#1864 and kit#2310 both measured a cut carried as prose firing 0 times, so a notice, being prose in front of the run, would drop enforcement without a procedural replacement. The pre-gate-cut refusal does collateral a sibling call batched in the same turn — a `PreToolUse` deny cancels the turn's other parallel calls, which is the harness behavior kit#2177 measured on #2160 (gate refused, its batched `review:brief` cancelled) — and that collateral is not avoidable at the guard level. `notice` was considered for the pre-gate-cut point and rejected: kit#1864 measured the cut taken 0 times while it was carried as prose, and a notice is prose in front of the run (kit#2178 measured a lane-child notice not moving the number), so a notice would drop enforcement without a procedural replacement. kit#2177 supplies that replacement in the procedure instead — the chain orders the cut before the gate, so the cut is issued on its own (its `cut` verdict ends the turn, batching with nothing) and the gate runs in the fresh process where the carried cut keeps this guard silent; the refusal therefore stays `refuse` as insurance and the collateral is gone from the default path rather than from the guard",
68
+ 'it carries the lane-only rules a child depends on (`pre-gate-cut`, `implementation-cut`, `lane-park`) and the safety rules it must still obey, and a notice was rejected despite the collateral a refusal costs a batched sibling, because a cut carried as prose was measured never to fire',
69
69
  },
70
70
  ]
71
71
 
@@ -24,6 +24,13 @@ function is_ship_running(issue: string, directory: string): boolean {
24
24
  )
25
25
  }
26
26
 
27
+ // When the detached ship for `issue` that is still live was launched, or `undefined` where none is.
28
+ function ship_running_since(issue: string, directory: string): number | undefined {
29
+ const repository = git_common_directory.repository(directory)
30
+
31
+ return repository === undefined ? undefined : run_ship_detach.running_since(repository, issue)
32
+ }
33
+
27
34
  // This session is the dispatched lane child for `directory` and its own ship is running.
28
35
  function is_handed_off(directory: string, source: MarkerSource = process.env): boolean {
29
36
  const issue = lane_child_marker.marked_issue(source)
@@ -33,6 +40,6 @@ function is_handed_off(directory: string, source: MarkerSource = process.env): b
33
40
  return is_ship_running(issue, directory)
34
41
  }
35
42
 
36
- const lane_handoff = { is_handed_off, is_ship_running }
43
+ const lane_handoff = { is_handed_off, is_ship_running, ship_running_since }
37
44
 
38
45
  export { lane_handoff }
@@ -1,5 +1,6 @@
1
1
  import { existsSync } from 'node:fs'
2
2
  import path from 'node:path'
3
+ import { core_budget } from '#scripts/gate/core-budget'
3
4
  import { buffered_process } from '#scripts/lib/buffered-process'
4
5
  import { INSTALL_TIMEOUT_MS } from '#scripts/lib/timeouts'
5
6
 
@@ -68,10 +69,17 @@ function has_manifest(directory: string): boolean {
68
69
  async function install_dependencies(directory: string): Promise<InstallResult> {
69
70
  if (!has_manifest(directory)) return { is_installed: true, output: NO_MANIFEST_OUTPUT }
70
71
 
71
- const result = await buffered_process.run_buffered_process(INSTALL_ARGUMENTS, {
72
- cwd: directory,
73
- timeout_ms: INSTALL_TIMEOUT_MS,
74
- })
72
+ // The install claims its place in the core budget (joshuafolkken/kit#3944): a batch opens its lanes
73
+ // together, and each install ran beside the other lanes' gates off the ledger.
74
+ const result = await core_budget.with_command_reservation(
75
+ core_budget.CORE_WEIGHTS.install,
76
+ async () =>
77
+ await buffered_process.run_buffered_process(INSTALL_ARGUMENTS, {
78
+ cwd: directory,
79
+ timeout_ms: INSTALL_TIMEOUT_MS,
80
+ }),
81
+ { memory_mb: core_budget.MEMORY_MB.install, command: 'lane install' },
82
+ )
75
83
 
76
84
  return { is_installed: !buffered_process.is_process_failed(result), output: result.output }
77
85
  }