@joshuafolkken/kit 1.1471.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 (267) hide show
  1. package/.claude/settings.json +6 -6
  2. package/.claude/skills/epic-commands/SKILL.md +2 -14
  3. package/.claude/skills/epic-commands/epic-bundle.md +9 -5
  4. package/.claude/skills/epic-commands/execution-waves.md +1 -2
  5. package/.claude/skills/verify-ui/SKILL.md +1 -2
  6. package/.claude/skills/workflow-commands/SKILL.md +7 -9
  7. package/.claude/skills/workflow-commands/background-commands.md +3 -7
  8. package/.claude/skills/workflow-commands/backlogrun-child.md +3 -10
  9. package/.claude/skills/workflow-commands/backlogrun-lanes.md +6 -15
  10. package/.claude/skills/workflow-commands/backlogrun-park.md +2 -8
  11. package/.claude/skills/workflow-commands/backlogrun-progress.md +10 -19
  12. package/.claude/skills/workflow-commands/backlogrun-recovery.md +8 -8
  13. package/.claude/skills/workflow-commands/backlogrun-steps.md +2 -10
  14. package/.claude/skills/workflow-commands/backlogrun.md +31 -50
  15. package/.claude/skills/workflow-commands/chain-rule.md +7 -6
  16. package/.claude/skills/workflow-commands/delegation.md +12 -8
  17. package/.claude/skills/workflow-commands/entry-sequence.md +1 -3
  18. package/.claude/skills/workflow-commands/followup.md +3 -6
  19. package/.claude/skills/workflow-commands/fullrun-steps.md +3 -5
  20. package/.claude/skills/workflow-commands/fullrun.md +4 -6
  21. package/.claude/skills/workflow-commands/halfrun.md +3 -7
  22. package/.claude/skills/workflow-commands/into-target.md +1 -2
  23. package/.claude/skills/workflow-commands/issue-comments.md +3 -3
  24. package/.claude/skills/workflow-commands/issue-scout.md +3 -2
  25. package/.claude/skills/workflow-commands/latest-gate.md +2 -6
  26. package/.claude/skills/workflow-commands/needs-human-review.md +2 -5
  27. package/.claude/skills/workflow-commands/observation-filing.md +0 -14
  28. package/.claude/skills/workflow-commands/observation-ledger.md +4 -9
  29. package/.claude/skills/workflow-commands/pre-gate-cut.md +11 -16
  30. package/.claude/skills/workflow-commands/prerequisite.md +1 -2
  31. package/.claude/skills/workflow-commands/progress-watcher.md +2 -7
  32. package/.claude/skills/workflow-commands/prrun.md +3 -5
  33. package/.claude/skills/workflow-commands/retrospective.md +4 -4
  34. package/.claude/skills/workflow-commands/split-assessment.md +1 -3
  35. package/.claude/skills/workflow-commands/target-repository.md +1 -2
  36. package/.claude/skills/workflow-commands/working-tree-hold.md +2 -4
  37. package/.codex/hooks.json +6 -6
  38. package/.github/actions/setup-node/action.yml +1 -1
  39. package/.github/workflows/ci.yml +1 -1
  40. package/.github/workflows/publish.yml +2 -2
  41. package/CLAUDE.md +1 -1
  42. package/cspell/index.yaml +7 -0
  43. package/dist/CLAUDE.md +1 -1
  44. package/dist/commands/document-section-cli.js +67 -34
  45. package/dist/hooks/batch-guard.js +6 -6
  46. package/dist/hooks/chunk-4KKD2UTK.js +66 -0
  47. package/dist/hooks/{chunk-J47HU5H5.js → chunk-6TS2JD6D.js} +3 -3
  48. package/dist/hooks/chunk-7DSBJVFH.js +50 -0
  49. package/dist/hooks/{chunk-YHBZAJSV.js → chunk-A65Y4YOR.js} +3 -3
  50. package/dist/hooks/{chunk-E7OIKX5Z.js → chunk-APUO6U4J.js} +85 -7
  51. package/dist/hooks/{chunk-IX6TTTI6.js → chunk-EFXE6C37.js} +8 -22
  52. package/dist/hooks/chunk-GP4IEC4O.js +20 -0
  53. package/dist/hooks/{chunk-SHGPANFB.js → chunk-JP45SOCJ.js} +3 -3
  54. package/dist/hooks/{chunk-K4EOONYM.js → chunk-LAOV7NLM.js} +1 -1
  55. package/dist/hooks/chunk-M4HGZV7U.js +83 -0
  56. package/dist/hooks/{chunk-KC5AK2GF.js → chunk-O6GDRNJB.js} +3 -3
  57. package/dist/hooks/{chunk-YYPI7SJZ.js → chunk-PF2NZL2A.js} +5 -5
  58. package/dist/hooks/{chunk-H5HVWYXK.js → chunk-PTICX4OL.js} +3 -4
  59. package/dist/hooks/{chunk-IIGFYXKC.js → chunk-RT27QRJW.js} +581 -1438
  60. package/dist/hooks/{chunk-43ZHT22P.js → chunk-SYOTDYCI.js} +1127 -1089
  61. package/dist/hooks/{chunk-AS74OU3D.js → chunk-TNUMY6NL.js} +1507 -1336
  62. package/dist/hooks/chunk-UPUZF3AN.js +279 -0
  63. package/dist/hooks/{chunk-EUMACUK2.js → chunk-WK6SMBIC.js} +1948 -806
  64. package/dist/hooks/codex-hook-adapter.js +17 -14
  65. package/dist/hooks/duplicate-read-guard.js +7 -7
  66. package/dist/hooks/format-edited.js +5 -4
  67. package/dist/hooks/inputs.json +317 -264
  68. package/dist/hooks/investigation-guard.js +8 -11
  69. package/dist/hooks/pretool-guard.js +16 -13
  70. package/dist/hooks/session-lang.js +370 -25
  71. package/dist/hooks/stop-guard.js +2576 -176
  72. package/dist/josh.js +2124 -277
  73. package/lefthook/base.yml +5 -3
  74. package/package.json +12 -10
  75. package/prompts/collaboration-workflow/file-edits.md +1 -3
  76. package/prompts/collaboration-workflow/gh-rest.md +1 -2
  77. package/prompts/collaboration-workflow/issue-citation.md +2 -4
  78. package/prompts/collaboration-workflow/issue-template.md +10 -2
  79. package/prompts/collaboration-workflow/lane-instructions.md +35 -0
  80. package/prompts/collaboration-workflow/operating-rules.md +2 -6
  81. package/prompts/collaboration-workflow/output-bounds.md +3 -3
  82. package/prompts/collaboration-workflow/overview.md +1 -1
  83. package/prompts/collaboration-workflow/principles.md +14 -8
  84. package/prompts/collaboration-workflow/report-format.md +9 -0
  85. package/prompts/collaboration-workflow/residency.md +12 -8
  86. package/prompts/collaboration-workflow/rule-delivery.md +3 -11
  87. package/prompts/collaboration-workflow/shell-body.md +6 -6
  88. package/prompts/collaboration-workflow/turn-batching.md +5 -5
  89. package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
  90. package/prompts/collaboration-workflow/wip-cap.md +6 -6
  91. package/prompts/collaboration-workflow.md +1 -0
  92. package/prompts/review.md +4 -5
  93. package/prompts/testing-guide.md +2 -2
  94. package/scripts/agent/agent-argv.ts +20 -4
  95. package/scripts/agent/agent-role-profile.ts +101 -45
  96. package/scripts/agent/agent-safe-text.ts +60 -0
  97. package/scripts/agent/claude-agent-argv.ts +14 -0
  98. package/scripts/agent/codex-agent-argv.ts +2 -0
  99. package/scripts/agent/lane-instructions.ts +144 -0
  100. package/scripts/backlog/backlog-budget.ts +4 -4
  101. package/scripts/backlog/backlog-drive-named.ts +1 -1
  102. package/scripts/backlog/backlog-drive-restore.ts +9 -1
  103. package/scripts/backlog/backlog-occupied.ts +56 -0
  104. package/scripts/backlog/backlog-ready.ts +47 -10
  105. package/scripts/delegation/duplicate-read-guard.ts +2 -2
  106. package/scripts/delegation/investigation-guard.ts +15 -65
  107. package/scripts/delegation/investigation-reads.ts +0 -1
  108. package/scripts/document/document-byte-budget.ts +6 -5
  109. package/scripts/document/document-section-cli.ts +17 -5
  110. package/scripts/document/entry-read-budget.ts +2 -2
  111. package/scripts/document/read-set-cli.ts +4 -1
  112. package/scripts/epic/epic-audit-orphans.ts +5 -8
  113. package/scripts/epic/epic-audit.ts +52 -1
  114. package/scripts/epic/epic-bundle-evidence.ts +49 -26
  115. package/scripts/epic/epic-bundle-referenced.ts +14 -3
  116. package/scripts/epic/epic-bundle.ts +17 -9
  117. package/scripts/followup/git-followup-workflow.ts +19 -1
  118. package/scripts/gate/check-inputs.ts +129 -0
  119. package/scripts/gate/check-reuse.ts +162 -0
  120. package/scripts/gate/core-budget.ts +93 -44
  121. package/scripts/gate/core-wait.ts +130 -0
  122. package/scripts/gate/free-cores.ts +49 -0
  123. package/scripts/gate/gate-ledger.ts +17 -3
  124. package/scripts/gate/gate-plan.ts +23 -1
  125. package/scripts/gate/gate-report.ts +15 -2
  126. package/scripts/gate/gate-run-steps.ts +150 -0
  127. package/scripts/gate/held-mark.ts +55 -0
  128. package/scripts/gate/machine-capacity.ts +70 -11
  129. package/scripts/gate/pre-commit-type-check.ts +14 -1
  130. package/scripts/gate/verification-gate.ts +58 -125
  131. package/scripts/gh/git-gh-issue-rest.ts +1 -0
  132. package/scripts/gh/git-gh-issue-write.ts +24 -2
  133. package/scripts/gh/git-pr.ts +13 -1
  134. package/scripts/git/main-merge-regenerate.ts +78 -0
  135. package/scripts/git/main-merge.ts +14 -5
  136. package/scripts/hooks/batch-guard.ts +5 -8
  137. package/scripts/hooks/pre-commit-lint.ts +91 -0
  138. package/scripts/hooks/pre-push-unit.ts +1 -1
  139. package/scripts/hooks/pretool-guard.ts +27 -52
  140. package/scripts/hooks/reserved-run.ts +1 -0
  141. package/scripts/hooks/run-hook.sh +10 -12
  142. package/scripts/hooks/stop-actions.ts +204 -0
  143. package/scripts/hooks/stop-guard.ts +62 -21
  144. package/scripts/init/hook-launch.ts +12 -7
  145. package/scripts/issue/expected-effect-lint.ts +59 -0
  146. package/scripts/issue/issue-cite-cli.ts +35 -15
  147. package/scripts/issue/issue-classification.ts +1 -1
  148. package/scripts/issue/issue-lint-cli.ts +5 -3
  149. package/scripts/issue/issue-scout-cli.ts +19 -14
  150. package/scripts/issue/markdown-section.ts +19 -5
  151. package/scripts/josh/command-usage.ts +110 -0
  152. package/scripts/josh/josh-command-map.ts +2 -0
  153. package/scripts/josh/josh-command-types.ts +55 -9
  154. package/scripts/josh/josh-commands-ai.ts +13 -0
  155. package/scripts/josh/josh-commands-development.ts +1 -1
  156. package/scripts/josh/josh-commands-hooks.ts +6 -0
  157. package/scripts/josh/josh-commands-lane.ts +10 -1
  158. package/scripts/josh/josh-commands-workflow.ts +5 -0
  159. package/scripts/josh/josh-logic.ts +6 -15
  160. package/scripts/josh/josh-usage-automation.ts +121 -0
  161. package/scripts/josh/josh-usage-backlog.ts +180 -0
  162. package/scripts/josh/josh-usage-developer.ts +230 -0
  163. package/scripts/josh/josh-usage-hooks.ts +38 -0
  164. package/scripts/josh/josh-usage-issue.ts +205 -0
  165. package/scripts/josh/josh-usage-review.ts +101 -0
  166. package/scripts/josh/josh-usage-run.ts +252 -0
  167. package/scripts/josh/josh-usage-session.ts +238 -0
  168. package/scripts/josh/josh-usage-workflow.ts +212 -0
  169. package/scripts/josh/josh.ts +14 -5
  170. package/scripts/josh/package-directory.ts +20 -0
  171. package/scripts/lane/lane-capacity.ts +8 -2
  172. package/scripts/lane/lane-check-stats.ts +56 -0
  173. package/scripts/lane/lane-child-invocation.ts +35 -4
  174. package/scripts/lane/lane-dispatch.ts +3 -3
  175. package/scripts/lane/lane-guard-policy.ts +2 -2
  176. package/scripts/lane/lane-handoff.ts +8 -1
  177. package/scripts/lane/lane-install.ts +12 -4
  178. package/scripts/lane/lane-ledger.ts +43 -1
  179. package/scripts/lane/lane-limit-cli.ts +8 -9
  180. package/scripts/lane/lane-measure-cli.ts +2 -0
  181. package/scripts/lane/lane-preserve.ts +29 -1
  182. package/scripts/lane/lane-registry.ts +9 -7
  183. package/scripts/lane/lane-restart.ts +5 -26
  184. package/scripts/lane/lane-session-action.ts +146 -0
  185. package/scripts/lane/lane-session-broker.ts +57 -138
  186. package/scripts/lane/lane-withdraw-cli.ts +71 -0
  187. package/scripts/lane/lane-withdraw.ts +182 -0
  188. package/scripts/lint/format.ts +4 -4
  189. package/scripts/lint/lint-parallel.ts +10 -3
  190. package/scripts/lint/lint-related-scope.ts +4 -1
  191. package/scripts/notify/telegram-test.ts +10 -5
  192. package/scripts/report/report-format-reference.ts +2 -0
  193. package/scripts/review/acceptance-map-check.ts +61 -0
  194. package/scripts/review/acceptance-map.ts +205 -0
  195. package/scripts/review/review-brief-cli.ts +1 -1
  196. package/scripts/rules/agent-model.ts +59 -0
  197. package/scripts/rules/delivered-rules.ts +11 -2
  198. package/scripts/rules/filing-cap.ts +1 -0
  199. package/scripts/rules/firing-point.ts +6 -5
  200. package/scripts/rules/guard-remedy.ts +117 -0
  201. package/scripts/rules/issue-comments.ts +67 -6
  202. package/scripts/rules/last-prompt.ts +50 -5
  203. package/scripts/rules/oracle-list-cli.ts +7 -0
  204. package/scripts/rules/piped-verification.ts +3 -1
  205. package/scripts/rules/rule-list.ts +4 -1
  206. package/scripts/rules/rule-registry-rows.ts +10 -0
  207. package/scripts/rules/rule-registry.ts +7 -4
  208. package/scripts/rules/rule-rewrite.ts +114 -0
  209. package/scripts/rules/rule-value.ts +7 -1
  210. package/scripts/rules/shell-segments.ts +15 -0
  211. package/scripts/rules/stop-decision.ts +77 -0
  212. package/scripts/rules/stop-rules.ts +147 -47
  213. package/scripts/rules/tail-commands.ts +15 -1
  214. package/scripts/run/board/run-board-cli.ts +2 -0
  215. package/scripts/run/board/run-board-closed.ts +8 -2
  216. package/scripts/run/board/run-board-github.ts +9 -1
  217. package/scripts/run/board/run-board-header.ts +4 -1
  218. package/scripts/run/board/run-board-labels.ts +2 -0
  219. package/scripts/run/board/run-board-layout.ts +1 -1
  220. package/scripts/run/board/run-board-read.ts +16 -0
  221. package/scripts/run/board/run-board-reason.ts +10 -1
  222. package/scripts/run/board/run-board-render-legend.ts +1 -0
  223. package/scripts/run/board/run-board-render-slot.ts +1 -1
  224. package/scripts/run/board/run-board-render-waits.ts +41 -0
  225. package/scripts/run/board/run-board-render.ts +6 -1
  226. package/scripts/run/board/run-board-row-yield.ts +1 -0
  227. package/scripts/run/board/run-board-state.ts +5 -0
  228. package/scripts/run/board/run-board-status.ts +72 -21
  229. package/scripts/run/board/run-board-tick.ts +5 -1
  230. package/scripts/run/cut/run-cut-cli.ts +3 -2
  231. package/scripts/run/cut/run-cut-report.ts +16 -0
  232. package/scripts/run/detached-launch.ts +23 -4
  233. package/scripts/run/entry/run-entry-cli.ts +8 -1
  234. package/scripts/run/event/run-event-render.ts +1 -0
  235. package/scripts/run/event/run-event-scope.ts +19 -1
  236. package/scripts/run/event/run-event-stream-emit.ts +13 -6
  237. package/scripts/run/event/run-event-stream.ts +4 -0
  238. package/scripts/run/hold/run-hold-session.ts +46 -0
  239. package/scripts/run/hold/run-hold.ts +7 -1
  240. package/scripts/run/launch-priority.ts +32 -0
  241. package/scripts/run/merge/run-merge-cli.ts +16 -65
  242. package/scripts/run/merge/run-merge-signals.ts +99 -0
  243. package/scripts/run/merge/run-merge-steps.ts +11 -1
  244. package/scripts/run/merge/run-merge.ts +21 -9
  245. package/scripts/run/run-liveness.ts +1 -1
  246. package/scripts/run/run-poll-hook.ts +157 -0
  247. package/scripts/run/run-step-cli.ts +22 -15
  248. package/scripts/run/run-step-section.ts +85 -0
  249. package/scripts/run/ship/run-ship-cli.ts +5 -12
  250. package/scripts/run/ship/run-ship-detach.ts +9 -0
  251. package/scripts/run/ship/run-ship-next.ts +10 -2
  252. package/scripts/run/ship/run-ship-overlap.ts +195 -0
  253. package/scripts/run/ship/run-ship-pre-detach.ts +33 -15
  254. package/scripts/run/ship/run-ship-preflight.ts +28 -2
  255. package/scripts/run/ship/run-ship-return.ts +31 -7
  256. package/scripts/run/ship/run-ship-review-steps.ts +12 -10
  257. package/scripts/run/ship/run-ship-steps.ts +1 -1
  258. package/scripts/run/ship/run-ship-stop-context.ts +206 -0
  259. package/scripts/run/ship/run-ship-sync.ts +14 -6
  260. package/scripts/test/test-e2e-guard.ts +30 -5
  261. package/scripts/test/test-unit-guard.ts +16 -1
  262. package/scripts/test/unit-worker-share.ts +26 -4
  263. package/scripts/time-runtime/time-shell.ts +29 -4
  264. package/scripts/time-runtime/time-spans.ts +1 -0
  265. package/scripts/time-runtime/time-tool-call.ts +7 -0
  266. package/templates/gitignore +6 -2
  267. package/dist/hooks/chunk-K4LMBQC2.js +0 -68
@@ -0,0 +1,238 @@
1
+ import type { CommandUsage } from './josh-command-types'
2
+
3
+ // The usage of the commands `docs/josh-commands-run.md` documents from `run:progress` on — the run's
4
+ // watchers, the lanes, and the session-budget and document-reading commands — keyed by command name.
5
+ // The page's usage blocks are generated from this table and `josh help <command>` prints it, so an
6
+ // example or a flag is written once, here (#3937). The run lifecycle before it is `josh-usage-run.ts`.
7
+ const BARE = { arguments: '' }
8
+ const PATH_DIR = '--path <dir>'
9
+
10
+ /* eslint-disable @typescript-eslint/naming-convention */
11
+ const SESSION_USAGE: Readonly<Record<string, CommandUsage>> = {
12
+ 'run:progress': {
13
+ examples: [
14
+ { arguments: '--output <path>' },
15
+ { arguments: '--once', note: 'five labelled lines now, whatever the clock says' },
16
+ { arguments: '--interval 20 --repo joshuafolkken/app-kit --hours 4' },
17
+ ],
18
+ flags: [
19
+ {
20
+ names: ['--mark'],
21
+ description:
22
+ 'record that a real report happened without printing a line (keeps the last line for `run:wake --list`).',
23
+ },
24
+ {
25
+ names: ['--path'],
26
+ description:
27
+ 'print the ambient heartbeat log\'s path and exit. Every heartbeat line is mirrored there, so `tail -F "$(pnpm josh run:progress --path)"` follows the run across a `backlogrun` session cut. Reads no run state, so it answers in a lane child too.',
28
+ },
29
+ {
30
+ names: ['--interval <min>'],
31
+ description:
32
+ 'silence interval (default 20; also `JOSH_PROGRESS_INTERVAL_MINUTES`, then `josh.progress_interval_minutes`).',
33
+ },
34
+ {
35
+ names: ['--wait'],
36
+ description:
37
+ 'start once in the background: each report goes to the event stream and ambient log, never stdout; exits only on an arrival, `josh followup` ending the run, or `--hours`.',
38
+ },
39
+ {
40
+ names: ['--hours <n>'],
41
+ description: 'how long the watcher lives (default 8 with `--wait`, 1 otherwise).',
42
+ },
43
+ { names: ['--repo <owner/name>'], description: 'scopes the read.' },
44
+ ],
45
+ },
46
+ 'run:board': {
47
+ examples: [
48
+ { arguments: '', note: 'redraw until interrupted' },
49
+ { arguments: '--once', note: 'one frame, then exit' },
50
+ { arguments: '--chat', note: 'one frame for a chat, recorded as a progress report' },
51
+ {
52
+ arguments: '--every 5',
53
+ note: 'the --chat frame as a 📊 Progress Telegram every 5 minutes, until the run ends',
54
+ },
55
+ ],
56
+ flags: [
57
+ {
58
+ names: ['--chat'],
59
+ description:
60
+ 'answers a `backlogrun` progress question: the frame `--once` draws, with only `🧠` on the machine line and no escapes; it records the report as `run:progress --mark` does.',
61
+ },
62
+ {
63
+ names: ['--every <minutes>'],
64
+ description:
65
+ 'sends the `--chat` frame as a `📊 Progress` Telegram now and every `<minutes>` until the run ends — only when a person asks for it.',
66
+ },
67
+ ],
68
+ },
69
+ 'run:watcher:guard': { examples: [BARE] },
70
+ 'run:stranded': { examples: [BARE] },
71
+ 'lane:open': { examples: [{ arguments: '1490', note: 'prints the lane directory on stdout' }] },
72
+ 'lane:close': {
73
+ examples: [{ arguments: '1490' }, { arguments: '--all' }],
74
+ flags: [{ names: ['--all'], description: 'closes every lane.' }],
75
+ },
76
+ 'lane:list': { examples: [BARE] },
77
+ 'lane:prune': { examples: [BARE] },
78
+ 'lane:output': {
79
+ examples: [
80
+ { arguments: '1713 /abs/path/to/agent-7.jsonl', note: 'record it; prints the path back' },
81
+ { arguments: '1713', note: 'read it; prints the path, or `none`' },
82
+ ],
83
+ },
84
+ 'lane:dispatch': {
85
+ examples: [
86
+ {
87
+ arguments: '1749',
88
+ note: "prints the child's pid; a refusal is an empty capture and exit 1",
89
+ },
90
+ ],
91
+ flags: [
92
+ {
93
+ names: ['JOSH_{SCHEDULER,WORKER,REVIEWER}_MODEL'],
94
+ description:
95
+ 'Claude Code role overrides; Anthropic defaults are respectively `claude-opus-5-5`, `claude-opus-5-5`, and `claude-opus-5-5`. Codex keeps its provider-specific model.',
96
+ },
97
+ {
98
+ names: ['JOSH_{SCHEDULER,WORKER,REVIEWER}_EFFORT'],
99
+ description:
100
+ 'role effort overrides for either provider; defaults are `medium`, `medium`, and `high`.',
101
+ },
102
+ {
103
+ names: ['JOSH_REVIEWER_VERIFICATION_{MODEL,EFFORT}'],
104
+ description:
105
+ 'review round 2 and later (the verification pass); Anthropic defaults are `claude-sonnet-5-5` / `high`, falling back to `JOSH_REVIEWER_*`.',
106
+ },
107
+ ],
108
+ },
109
+ 'lane:await': {
110
+ examples: [
111
+ { arguments: '1749 1750', note: 'block until either lane completes' },
112
+ {
113
+ arguments: '1749 1750 --owner "$PPID"',
114
+ note: 'reclaim the carry record for a resumed conversation first',
115
+ },
116
+ ],
117
+ },
118
+ 'lane:launch': {
119
+ examples: [
120
+ { arguments: '1749', note: 'every lane after the first' },
121
+ {
122
+ arguments: '1749 --stash "backlogrun: josh latest before lanes"',
123
+ note: 'the first lane only',
124
+ },
125
+ ],
126
+ },
127
+ 'lane:sample': { examples: [{ arguments: '', note: 'one machine-load reading' }] },
128
+ 'lane:stats': {
129
+ examples: [{ arguments: '--period 7', note: "a 7-day period's stage medians and maxima" }],
130
+ },
131
+ cost: {
132
+ examples: [
133
+ {
134
+ arguments: '--cut',
135
+ note: 'compare billed input per request with the shared 135,000 context-cut threshold',
136
+ },
137
+ { arguments: '--over <tokens>', note: 'compare with an explicit limit' },
138
+ { arguments: `--cut ${PATH_DIR}`, note: 'Anthropic project or current OpenAI worktree' },
139
+ ],
140
+ flags: [
141
+ {
142
+ names: [PATH_DIR],
143
+ description:
144
+ 'selects another Anthropic project; OpenAI accepts only linked checkouts of the current project.',
145
+ },
146
+ ],
147
+ },
148
+ 'doc:section': {
149
+ examples: [
150
+ { arguments: '<file.md> "<heading>"' },
151
+ { arguments: 'backlogrun.md "The hand-off"' },
152
+ ],
153
+ },
154
+ 'read:set': {
155
+ examples: [
156
+ { arguments: '', note: 'every entry point' },
157
+ { arguments: 'backlogrun', note: 'one of them' },
158
+ { arguments: 'backlogrun --json' },
159
+ ],
160
+ },
161
+ 'doc:read': {
162
+ examples: [
163
+ { arguments: 'CLAUDE.md', note: 'under the cap: prints the document' },
164
+ { arguments: 'backlogrun.md', note: 'over the cap: prints a directive, no content' },
165
+ ],
166
+ },
167
+ 'read:files': {
168
+ examples: [
169
+ { arguments: 'a.ts b.ts c.ts', note: 'under the cap: prints each file under its own header' },
170
+ {
171
+ arguments: 'a.ts big.ts',
172
+ note: 'over the cap: prints a directive to Read them in one turn, no content',
173
+ },
174
+ ],
175
+ },
176
+ 'edit:files': {
177
+ examples: [
178
+ {
179
+ arguments: 'plan.txt',
180
+ note: 'applies every block in the plan, one line per edit reporting the outcome',
181
+ },
182
+ { arguments: "- <<'EDITS'", note: 'plan from stdin, then EDITS' },
183
+ ],
184
+ },
185
+ time: {
186
+ examples: [
187
+ { arguments: '', note: 'the last run tree, wall clock and cost by role' },
188
+ { arguments: '--run', note: 'the same run-tree scope, named explicitly' },
189
+ { arguments: '--json', note: 'the same figures, machine-readable' },
190
+ { arguments: PATH_DIR, note: "read another project's transcripts from this checkout" },
191
+ ],
192
+ flags: [
193
+ {
194
+ names: ['--run'],
195
+ description:
196
+ '(default) the whole run tree, wall clock led beside dollars. It is the only scope; any other flag is a usage error (exit 1). History: `docs/maintainers/josh-commands-run-rationale.md` → "`josh cost` and `josh time` lost their report scopes".',
197
+ },
198
+ {
199
+ names: [PATH_DIR],
200
+ description:
201
+ 'aim the read at another project (absolute path); keeps the `cwd` behavior when absent.',
202
+ },
203
+ { names: ['--json'], description: 'the run tree, machine-readable.' },
204
+ ],
205
+ },
206
+ 'cost:audit': {
207
+ examples: [
208
+ { arguments: '', note: 'the last 7 days against the 7 before' },
209
+ { arguments: '--period 30', note: 'the last 30 days against the 30 before' },
210
+ ],
211
+ flags: [
212
+ {
213
+ names: ['--period <days>'],
214
+ description: 'the length of each period, a positive whole number of days (default 7).',
215
+ },
216
+ ],
217
+ },
218
+ retrospective: {
219
+ examples: [{ arguments: '', note: 'the digest for the run this checkout carries' }],
220
+ },
221
+ eval: {
222
+ examples: [
223
+ { arguments: '', note: 'every scenario' },
224
+ { arguments: 'consult-not-execute', note: 'one scenario by name' },
225
+ ],
226
+ flags: [
227
+ { names: ['JOSH_EVAL_MODEL'], description: 'the model to run against (default `sonnet`).' },
228
+ {
229
+ names: ['JOSH_EVAL_CONCURRENCY'],
230
+ description:
231
+ 'how many sessions run at once (default `5`); a non-positive-integer value is refused.',
232
+ },
233
+ ],
234
+ },
235
+ }
236
+ /* eslint-enable @typescript-eslint/naming-convention */
237
+
238
+ export { SESSION_USAGE }
@@ -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 }
@@ -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,17 @@
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'
11
15
  // What a brokered reviewer's prompt ends with, so the one pattern below finds it too.
12
16
  const REVIEW_INVOCATION = 'the reviewer of lane'
13
17
  const RESUME_GUIDE = '.claude/skills/workflow-commands/pre-gate-cut.md'
@@ -79,14 +83,41 @@ function outage_resume_invocation(issue: string): string {
79
83
  // **A known stage puts the next command in the prompt**, so the relaunched
80
84
  // session runs it rather than re-deriving it from `chain-rule.md`. An OpenAI lane's supervisor sees only
81
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
+
82
110
  function ship_stop_invocation(issue: string, stop?: ShipStop): string {
83
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).`
84
- const next =
112
+ const closing = `Do not re-plan or re-implement what is already on the branch. ${child_invocation(issue)}`
113
+ const middle =
85
114
  stop === undefined
86
- ? `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.`
87
- : 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])
88
119
 
89
- 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)
90
121
  }
91
122
 
92
123
  const lane_child_invocation = {
@@ -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