@joshuafolkken/kit 1.1178.0 → 1.1229.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 (425) hide show
  1. package/.claude/.claude-plugin/plugin.json +1 -1
  2. package/.claude/settings.json +2 -2
  3. package/.claude/skills/dependency-update/SKILL.md +4 -8
  4. package/.claude/skills/epic-commands/SKILL.md +2 -2
  5. package/.claude/skills/epic-commands/epic-bundle.md +1 -1
  6. package/.claude/skills/workflow-commands/SKILL.md +2 -4
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +6 -4
  8. package/.claude/skills/workflow-commands/backlogrun-lanes.md +6 -2
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +23 -2
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +7 -2
  11. package/.claude/skills/workflow-commands/backlogrun-recovery.md +4 -3
  12. package/.claude/skills/workflow-commands/backlogrun-steps.md +21 -13
  13. package/.claude/skills/workflow-commands/chain-rule.md +1 -1
  14. package/.claude/skills/workflow-commands/delegation.md +2 -2
  15. package/.claude/skills/workflow-commands/followup.md +5 -0
  16. package/.claude/skills/workflow-commands/fullrun-steps.md +1 -1
  17. package/.claude/skills/workflow-commands/halfrun.md +1 -1
  18. package/.claude/skills/workflow-commands/issue-scout.md +1 -1
  19. package/.claude/skills/workflow-commands/kickoff.md +1 -1
  20. package/.claude/skills/workflow-commands/observation-ledger.md +3 -3
  21. package/.claude/skills/workflow-commands/pre-gate-cut.md +6 -1
  22. package/.claude/skills/workflow-commands/prerequisite.md +2 -2
  23. package/.claude/skills/workflow-commands/progress-watcher.md +1 -1
  24. package/.claude/skills/workflow-commands/working-tree-hold.md +1 -1
  25. package/.codex/hooks.json +2 -2
  26. package/.cursorrules +6 -41
  27. package/.github/actions/setup-node/action.yml +1 -1
  28. package/.github/workflows/auto-tag.yml +3 -4
  29. package/.github/workflows/ci.yml +32 -31
  30. package/.github/workflows/dependabot-auto-merge.yml +13 -6
  31. package/.github/workflows/publish.yml +48 -4
  32. package/.github/workflows/sonar-qube.yml +3 -0
  33. package/.pnpmfile.mjs +4 -3
  34. package/.prettierignore +8 -2
  35. package/CLAUDE.md +18 -20
  36. package/README.md +26 -19
  37. package/SECURITY.md +15 -1
  38. package/dist/CLAUDE.md +18 -20
  39. package/dist/commands/document-section-cli.js +734 -0
  40. package/dist/hooks/audit-provision.js +346 -0
  41. package/dist/hooks/batch-guard.js +5 -4
  42. package/dist/hooks/{chunk-S6X6WYKR.js → chunk-55HHG5PX.js} +1210 -711
  43. package/dist/hooks/{chunk-ZAL3NRGL.js → chunk-5VMKCCC4.js} +25 -10
  44. package/dist/hooks/chunk-5VNDSNG3.js +12 -0
  45. package/dist/hooks/{chunk-32GQTL4F.js → chunk-6HJJXRBX.js} +4 -2
  46. package/dist/hooks/chunk-CDY4NFQG.js +15 -0
  47. package/dist/hooks/chunk-ELCN5LCH.js +135 -0
  48. package/dist/hooks/{chunk-VESKRQOF.js → chunk-F56MFS4B.js} +3 -3
  49. package/dist/hooks/{chunk-UAGLLIGZ.js → chunk-FIVDHQGT.js} +7 -6
  50. package/dist/hooks/{chunk-3V37IID6.js → chunk-JBBMAPC4.js} +23 -14
  51. package/dist/hooks/{chunk-G6KRCKEC.js → chunk-JUDKDCDP.js} +496 -378
  52. package/dist/hooks/{chunk-GDS5N2KB.js → chunk-NV2JRZZO.js} +718 -681
  53. package/dist/hooks/{chunk-VQLLNFNT.js → chunk-RNWHN5BP.js} +3 -3
  54. package/dist/hooks/{chunk-DO6NWWHU.js → chunk-TQNPDZNH.js} +4 -4
  55. package/dist/hooks/{chunk-I4XSL4TT.js → chunk-VC3PZPZO.js} +1 -1
  56. package/dist/hooks/codex-hook-adapter.js +14 -12
  57. package/dist/hooks/duplicate-read-guard.js +6 -5
  58. package/dist/hooks/format-edited.js +4 -3
  59. package/dist/hooks/inputs.json +217 -195
  60. package/dist/hooks/investigation-guard.js +6 -5
  61. package/dist/hooks/pretool-guard.js +12 -10
  62. package/dist/hooks/session-lang.js +2 -4
  63. package/dist/hooks/stop-guard.js +66 -58
  64. package/dist/josh.js +868 -74
  65. package/dist/version/index.d.ts +7 -2
  66. package/dist/version/index.js +152 -75
  67. package/eslint/base.js +23 -1
  68. package/eslint/rules/code-quality.js +3 -0
  69. package/eslint/rules/early-return-one-liner.js +98 -0
  70. package/eslint/rules/unicorn.js +16 -1
  71. package/package.json +7 -6
  72. package/pnpm-workspace.yaml +9 -4
  73. package/prettier/basic.d.ts +3 -1
  74. package/prettier/index.d.ts +3 -1
  75. package/prettier/static.d.ts +3 -1
  76. package/prompts/coding-standards.md +1 -1
  77. package/prompts/collaboration-workflow/file-edits.md +4 -4
  78. package/prompts/collaboration-workflow/glossary.md +1 -1
  79. package/prompts/collaboration-workflow/operating-rules.md +17 -9
  80. package/prompts/collaboration-workflow/overview.md +2 -2
  81. package/prompts/collaboration-workflow/principles.md +14 -12
  82. package/prompts/collaboration-workflow/report-format.md +1 -1
  83. package/prompts/collaboration-workflow/residency.md +1 -1
  84. package/prompts/collaboration-workflow/rule-delivery.md +6 -6
  85. package/prompts/collaboration-workflow/shell-body.md +6 -6
  86. package/prompts/collaboration-workflow/turn-batching.md +1 -1
  87. package/prompts/collaboration-workflow/upstream-interrupt.md +12 -2
  88. package/prompts/collaboration-workflow/wip-cap.md +10 -10
  89. package/prompts/review-rubric.md +1 -2
  90. package/prompts/review.md +1 -1
  91. package/scripts/agent/agent-headless.ts +29 -0
  92. package/scripts/agent/agent-launch-environment.ts +6 -2
  93. package/scripts/agent/codex-agent-argv.ts +2 -1
  94. package/scripts/auto-ok/auto-ok-cli.ts +1 -1
  95. package/scripts/backlog/backlog-arrival.ts +3 -3
  96. package/scripts/backlog/backlog-budget.ts +1 -1
  97. package/scripts/backlog/backlog-drive-args.ts +135 -0
  98. package/scripts/backlog/backlog-drive-cli.ts +11 -137
  99. package/scripts/backlog/backlog-drive-launch.ts +39 -0
  100. package/scripts/backlog/backlog-drive-named-offer.ts +3 -5
  101. package/scripts/backlog/backlog-drive-named.ts +3 -3
  102. package/scripts/backlog/backlog-drive-offer-argv.ts +1 -1
  103. package/scripts/backlog/backlog-drive-owner.ts +1 -1
  104. package/scripts/backlog/backlog-drive-restore.ts +1 -1
  105. package/scripts/backlog/backlog-drive-retrospective.ts +1 -1
  106. package/scripts/backlog/backlog-drive.ts +1 -1
  107. package/scripts/backlog/backlog-next.ts +16 -5
  108. package/scripts/backlog/backlog-offer-cli.ts +6 -6
  109. package/scripts/backlog/backlog-offer.ts +1 -1
  110. package/scripts/backlog/backlog-plan-cli.ts +1 -1
  111. package/scripts/backlog/backlog-pool.ts +57 -11
  112. package/scripts/backlog/backlog-ready.ts +1 -1
  113. package/scripts/backlog/backlog-scope.ts +1 -1
  114. package/scripts/backlog/backlog-stalled-detect.ts +2 -2
  115. package/scripts/backlog/backlog-stalled.ts +1 -1
  116. package/scripts/build/build-codex-hooks.ts +3 -1
  117. package/scripts/build/build-commands.ts +66 -0
  118. package/scripts/build/build-hooks.ts +2 -1
  119. package/scripts/build/build-library.ts +12 -3
  120. package/scripts/build/build.ts +70 -0
  121. package/scripts/build/local-bin.ts +3 -13
  122. package/scripts/delegation/investigation-reads.ts +3 -1
  123. package/scripts/discovery/repo-origin.ts +5 -5
  124. package/scripts/doctor/doctor-consumer.ts +2 -2
  125. package/scripts/doctor/doctor-io.ts +2 -3
  126. package/scripts/document/capped-print-part.ts +30 -0
  127. package/scripts/document/capped-print.ts +3 -4
  128. package/scripts/document/document-byte-budget.ts +11 -2
  129. package/scripts/document/document-scan.ts +117 -0
  130. package/scripts/document/document-section.ts +143 -16
  131. package/scripts/document/entry-read-budget.ts +5 -3
  132. package/scripts/document/entry-read-set.ts +10 -89
  133. package/scripts/document/read-set-cost.ts +98 -0
  134. package/scripts/epic/epic-add-body.ts +1 -0
  135. package/scripts/epic/epic-audit-checks.ts +1 -1
  136. package/scripts/epic/epic-audit-rationale.ts +4 -3
  137. package/scripts/epic/epic-bundle-cli.ts +14 -3
  138. package/scripts/epic/epic-bundle-poll.ts +41 -0
  139. package/scripts/epic/epic-busy.ts +1 -1
  140. package/scripts/epic/epic-candidate-confirm.ts +3 -2
  141. package/scripts/epic/epic-classify.ts +1 -1
  142. package/scripts/epic/epic-cli-argv.ts +78 -46
  143. package/scripts/epic/epic-cli-remove.ts +11 -19
  144. package/scripts/epic/epic-cli.ts +74 -73
  145. package/scripts/epic/epic-close-comment.ts +1 -1
  146. package/scripts/epic/epic-close.ts +1 -1
  147. package/scripts/epic/epic-cross-repo.ts +5 -5
  148. package/scripts/epic/epic-graph.ts +1 -1
  149. package/scripts/epic/epic-index.ts +1 -1
  150. package/scripts/epic/epic-issue.ts +2 -6
  151. package/scripts/epic/epic-lane-offer.ts +2 -2
  152. package/scripts/epic/epic-next.ts +29 -42
  153. package/scripts/epic/epic-solo-stale.ts +1 -1
  154. package/scripts/epic/epic-triage.ts +8 -4
  155. package/scripts/epic/epic-validate.ts +1 -1
  156. package/scripts/followup/git-followup-finish.ts +2 -2
  157. package/scripts/followup/git-followup-label.ts +2 -2
  158. package/scripts/followup/git-followup-merged.ts +2 -2
  159. package/scripts/followup/git-pr-followup-checks.ts +142 -0
  160. package/scripts/followup/git-pr-followup.ts +4 -129
  161. package/scripts/gate/core-budget.ts +69 -1
  162. package/scripts/gate/gate-plan.ts +47 -7
  163. package/scripts/gate/gate-skip.ts +38 -7
  164. package/scripts/gate/hook-gate-reuse.ts +12 -10
  165. package/scripts/gate/pre-commit-type-check.ts +4 -1
  166. package/scripts/gate/project-checks.ts +6 -9
  167. package/scripts/gate/type-check-step.ts +2 -3
  168. package/scripts/gate/verification-gate.ts +27 -8
  169. package/scripts/gh/git-gh-api-path.ts +2 -2
  170. package/scripts/gh/git-gh-issue-rest.ts +3 -3
  171. package/scripts/gh/git-gh-issue-write.ts +53 -7
  172. package/scripts/gh/git-gh-pr-read.ts +64 -19
  173. package/scripts/gh/git-gh-pr-rest.ts +1 -1
  174. package/scripts/gh/git-gh-pr.ts +5 -1
  175. package/scripts/gh/git-pr-ai-review.ts +1 -1
  176. package/scripts/gh/git-pr-checks-eval.ts +1 -3
  177. package/scripts/gh/git-pr-checks-parse.ts +1 -1
  178. package/scripts/gh/git-pr-checks-watch.ts +6 -5
  179. package/scripts/gh/git-pr-checks.ts +7 -5
  180. package/scripts/gh/git-pr-coderabbit.ts +1 -1
  181. package/scripts/gh/git-pr-error.ts +1 -3
  182. package/scripts/gh/git-pr.ts +9 -13
  183. package/scripts/gh/github-issue-url.ts +2 -2
  184. package/scripts/git/constants.ts +2 -6
  185. package/scripts/git/git-command.ts +20 -218
  186. package/scripts/git/git-diff-reads.ts +225 -0
  187. package/scripts/git/git-error.ts +4 -12
  188. package/scripts/git/git-pre-push-hook.ts +139 -0
  189. package/scripts/git/git-prompt.ts +2 -6
  190. package/scripts/git/git-spawn-sync.ts +3 -1
  191. package/scripts/git/git-spawn.ts +1 -1
  192. package/scripts/git/git-staging.ts +4 -6
  193. package/scripts/git/git-status.ts +3 -9
  194. package/scripts/hooks/codex-hook-adapter.ts +1 -1
  195. package/scripts/hooks/edited-cspell.ts +2 -4
  196. package/scripts/hooks/format-edited-file.ts +3 -12
  197. package/scripts/hooks/pre-push-unit.ts +31 -9
  198. package/scripts/hooks/reserved-run.ts +2 -2
  199. package/scripts/hooks/run-hook.sh +5 -4
  200. package/scripts/hooks/stop-guard.ts +5 -3
  201. package/scripts/init/init-actions.ts +0 -5
  202. package/scripts/init/init-ai-copy.ts +13 -2
  203. package/scripts/init/init-logic-json-merge.ts +19 -0
  204. package/scripts/init/init-logic-secretlint.ts +7 -7
  205. package/scripts/init/init-logic-workspace.ts +41 -2
  206. package/scripts/init/init-logic.ts +16 -26
  207. package/scripts/init/init.ts +5 -15
  208. package/scripts/init/initial-commit.ts +4 -4
  209. package/scripts/init/kit-development-versions.ts +40 -0
  210. package/scripts/init/kit-setup-state.ts +2 -2
  211. package/scripts/init/start-exec.ts +68 -19
  212. package/scripts/init/start-setup-pr.ts +9 -9
  213. package/scripts/init/start-steps.ts +6 -10
  214. package/scripts/issue/defect-rate-cli.ts +1 -1
  215. package/scripts/issue/git-next-issues.ts +1 -1
  216. package/scripts/issue/issue-auto-ok.ts +1 -1
  217. package/scripts/issue/issue-backlinks-cli.ts +2 -2
  218. package/scripts/issue/issue-backlinks.ts +9 -9
  219. package/scripts/issue/issue-comment-cli.ts +19 -13
  220. package/scripts/issue/issue-file-cli.ts +45 -18
  221. package/scripts/issue/issue-file.ts +24 -1
  222. package/scripts/issue/issue-scout-closed.ts +1 -1
  223. package/scripts/issue/issue-state-cli.ts +30 -74
  224. package/scripts/josh/josh-command-map.ts +2 -0
  225. package/scripts/josh/josh-command-types.ts +11 -0
  226. package/scripts/josh/josh-commands-ai.ts +4 -4
  227. package/scripts/josh/josh-commands-backlog.ts +4 -1
  228. package/scripts/josh/josh-commands-development.ts +10 -0
  229. package/scripts/josh/josh-commands-document.ts +1 -0
  230. package/scripts/josh/josh-commands-lane.ts +22 -0
  231. package/scripts/josh/josh-commands-maintenance.ts +4 -4
  232. package/scripts/josh/josh-commands-run.ts +12 -7
  233. package/scripts/josh/josh-in-process.ts +28 -9
  234. package/scripts/josh/josh-logic.ts +33 -15
  235. package/scripts/josh/process-identity.ts +1 -3
  236. package/scripts/josh/session-language-cli.ts +3 -4
  237. package/scripts/lane/lane-await.ts +5 -1
  238. package/scripts/lane/lane-child-invocation.ts +2 -2
  239. package/scripts/lane/lane-cli.ts +3 -3
  240. package/scripts/lane/lane-dispatch.ts +14 -10
  241. package/scripts/lane/lane-environment.ts +5 -1
  242. package/scripts/lane/lane-handoff.ts +1 -1
  243. package/scripts/lane/lane-install.ts +2 -13
  244. package/scripts/lane/lane-launch-cli.ts +15 -1
  245. package/scripts/lane/lane-ledger.ts +145 -0
  246. package/scripts/lane/lane-leftover.ts +1 -1
  247. package/scripts/lane/lane-load.ts +108 -0
  248. package/scripts/lane/lane-measure-cli.ts +149 -0
  249. package/scripts/lane/lane-occupancy.ts +3 -0
  250. package/scripts/lane/lane-reap.ts +1 -3
  251. package/scripts/lane/lane-relaunch.ts +1 -1
  252. package/scripts/lane/lane-stats.ts +224 -0
  253. package/scripts/lane/lane-vacant.ts +36 -0
  254. package/scripts/lane/openai-lane-ship.ts +2 -2
  255. package/scripts/lane/openai-lane-supervisor-owner.ts +180 -0
  256. package/scripts/lane/openai-lane-supervisor.ts +7 -165
  257. package/scripts/lane/openai-review-broker.ts +2 -4
  258. package/scripts/lib/ancestor-directories.ts +35 -0
  259. package/scripts/lib/animation-helpers.ts +2 -2
  260. package/scripts/lib/buffered-process.ts +3 -7
  261. package/scripts/lib/cli-flags.ts +71 -1
  262. package/scripts/lib/spawn-exit.ts +2 -2
  263. package/scripts/lib/timeouts.ts +35 -2
  264. package/scripts/lines/line-budget.ts +4 -6
  265. package/scripts/notify/telegram-test.ts +6 -0
  266. package/scripts/observations/observation-ledger-line.ts +6 -6
  267. package/scripts/observations/observation-ledger-migrate.ts +55 -4
  268. package/scripts/observations/observation-ledger.ts +26 -7
  269. package/scripts/overrides/lockfile-overrides.ts +1 -1
  270. package/scripts/overrides/overrides-logic.ts +1 -1
  271. package/scripts/propagate/propagate-git.ts +1 -1
  272. package/scripts/propagate/propagate-publish.ts +2 -2
  273. package/scripts/propagate/propagate-steps.ts +20 -15
  274. package/scripts/propagate/propagate.ts +36 -27
  275. package/scripts/refactor/import-graph.ts +18 -1
  276. package/scripts/refactor/refactor-lint.ts +4 -4
  277. package/scripts/repo/repository-labels.ts +2 -2
  278. package/scripts/repo/required-checks-logic.ts +1 -3
  279. package/scripts/review/live-evidence.ts +2 -4
  280. package/scripts/review/review-brief-cli.ts +1 -1
  281. package/scripts/review/review-finding-ledger.ts +1 -1
  282. package/scripts/review/review-findings-cli.ts +1 -3
  283. package/scripts/rules/decision-oracle-batch.ts +128 -0
  284. package/scripts/rules/decision-oracle-tokens.ts +21 -0
  285. package/scripts/rules/decision-oracle.ts +8 -120
  286. package/scripts/rules/delivered-rules.ts +26 -182
  287. package/scripts/rules/direct-filing.ts +1 -1
  288. package/scripts/rules/early-heartbeat.ts +3 -3
  289. package/scripts/rules/git-argv.ts +1 -1
  290. package/scripts/rules/git-force.ts +1 -1
  291. package/scripts/rules/implementation-cut.ts +2 -2
  292. package/scripts/rules/index-guard.ts +1 -1
  293. package/scripts/rules/issue-comments.ts +118 -0
  294. package/scripts/rules/{issue-fold.ts → issue-fold-rule.ts} +2 -2
  295. package/scripts/rules/lane-background.ts +2 -2
  296. package/scripts/rules/lane-park.ts +18 -0
  297. package/scripts/rules/lane-split-park.ts +128 -0
  298. package/scripts/rules/oracle-firing.ts +1 -1
  299. package/scripts/rules/poll-loop.ts +1 -1
  300. package/scripts/rules/pre-gate-cut.ts +1 -1
  301. package/scripts/rules/protected-files.ts +59 -4
  302. package/scripts/rules/{run-tail.ts → run-tail-rule.ts} +2 -2
  303. package/scripts/rules/shell-body-trigger.ts +1 -1
  304. package/scripts/rules/stop-rules.ts +18 -7
  305. package/scripts/rules/test-declared-commit.ts +4 -4
  306. package/scripts/rules/wip-cap.ts +63 -0
  307. package/scripts/run/{run-carry-args.ts → carry/run-carry-args.ts} +37 -13
  308. package/scripts/run/{run-carry-change.ts → carry/run-carry-change.ts} +29 -7
  309. package/scripts/run/{run-carry-cli.ts → carry/run-carry-cli.ts} +4 -6
  310. package/scripts/run/{run-carry.ts → carry/run-carry.ts} +1 -1
  311. package/scripts/run/{run-cut-args.ts → cut/run-cut-args.ts} +1 -1
  312. package/scripts/run/{run-cut-cli.ts → cut/run-cut-cli.ts} +2 -2
  313. package/scripts/run/{run-cut.ts → cut/run-cut.ts} +1 -1
  314. package/scripts/run/{run-entry-cli.ts → entry/run-entry-cli.ts} +11 -11
  315. package/scripts/run/{run-entry.ts → entry/run-entry.ts} +2 -2
  316. package/scripts/run/{run-event-scope.ts → event/run-event-scope.ts} +1 -1
  317. package/scripts/run/{run-event-stream-emit.ts → event/run-event-stream-emit.ts} +1 -1
  318. package/scripts/run/{run-event-stream.ts → event/run-event-stream.ts} +16 -2
  319. package/scripts/run/{run-hold-cli.ts → hold/run-hold-cli.ts} +5 -5
  320. package/scripts/run/{run-merge-cli.ts → merge/run-merge-cli.ts} +10 -5
  321. package/scripts/run/{run-merge-steps.ts → merge/run-merge-steps.ts} +53 -5
  322. package/scripts/run/{run-merge.ts → merge/run-merge.ts} +1 -1
  323. package/scripts/run/{run-progress-cli.ts → progress/run-progress-cli.ts} +1 -1
  324. package/scripts/run/{run-progress-config.ts → progress/run-progress-config.ts} +2 -17
  325. package/scripts/run/{run-progress-read.ts → progress/run-progress-read.ts} +5 -5
  326. package/scripts/run/{run-progress.ts → progress/run-progress.ts} +1 -1
  327. package/scripts/run/{run-review-steps.ts → review/run-review-steps.ts} +2 -3
  328. package/scripts/run/run-ending.ts +2 -2
  329. package/scripts/run/run-halfrun-resume.ts +6 -1
  330. package/scripts/run/run-headless.ts +1 -1
  331. package/scripts/run/run-invocation.ts +85 -84
  332. package/scripts/run/run-liveness.ts +1 -1
  333. package/scripts/run/run-parent-cut-hook.ts +1 -1
  334. package/scripts/run/run-preflight.ts +6 -6
  335. package/scripts/run/run-prep-cli.ts +1 -1
  336. package/scripts/run/run-prrun-resume.ts +1 -1
  337. package/scripts/run/run-report-cli.ts +4 -4
  338. package/scripts/run/run-report.ts +2 -2
  339. package/scripts/run/run-status-cli.ts +1 -1
  340. package/scripts/run/run-step-cli.ts +3 -3
  341. package/scripts/run/run-step.ts +2 -2
  342. package/scripts/run/run-stop-notify.ts +1 -1
  343. package/scripts/run/run-stranded-detect.ts +4 -4
  344. package/scripts/run/run-stranded.ts +2 -2
  345. package/scripts/run/run-watcher-guard-cli.ts +1 -1
  346. package/scripts/run/run-watcher-guard.ts +5 -3
  347. package/scripts/run/run-watcher-hook.ts +1 -1
  348. package/scripts/run/{run-ship-cli.ts → ship/run-ship-cli.ts} +2 -2
  349. package/scripts/run/{run-ship-detach.ts → ship/run-ship-detach.ts} +3 -3
  350. package/scripts/run/ship/run-ship-lock.ts +50 -0
  351. package/scripts/run/{run-ship-preflight.ts → ship/run-ship-preflight.ts} +6 -2
  352. package/scripts/run/{run-ship-probe.ts → ship/run-ship-probe.ts} +2 -2
  353. package/scripts/run/{run-ship-return.ts → ship/run-ship-return.ts} +4 -3
  354. package/scripts/run/{run-ship-review-steps.ts → ship/run-ship-review-steps.ts} +3 -3
  355. package/scripts/run/{run-ship-scoped.ts → ship/run-ship-scoped.ts} +10 -1
  356. package/scripts/run/{run-ship-steps.ts → ship/run-ship-steps.ts} +11 -12
  357. package/scripts/run/ship/run-ship-stop-text.ts +13 -0
  358. package/scripts/run/{run-ship-sync.ts → ship/run-ship-sync.ts} +25 -11
  359. package/scripts/run/{run-tidy-lanes.ts → tidy/run-tidy-lanes.ts} +1 -1
  360. package/scripts/run/{run-wake-cli.ts → wake/run-wake-cli.ts} +23 -8
  361. package/scripts/run/{run-wake-describe.ts → wake/run-wake-describe.ts} +3 -3
  362. package/scripts/run/{run-wake-driver.ts → wake/run-wake-driver.ts} +59 -8
  363. package/scripts/run/{run-wake-handoff.ts → wake/run-wake-handoff.ts} +1 -1
  364. package/scripts/run/{run-wake-loop.ts → wake/run-wake-loop.ts} +8 -2
  365. package/scripts/run/wake/run-wake-restart.ts +58 -0
  366. package/scripts/run/{run-wake-session.ts → wake/run-wake-session.ts} +3 -3
  367. package/scripts/run/{run-wake.ts → wake/run-wake.ts} +1 -1
  368. package/scripts/safe-chain/preinstall-command.ts +20 -21
  369. package/scripts/safe-chain/project-config.ts +19 -15
  370. package/scripts/sync/sync-ai-files.ts +1 -1
  371. package/scripts/sync/sync-configs.ts +2 -1
  372. package/scripts/sync/sync.ts +15 -2
  373. package/scripts/test/unit-worker-share.ts +1 -0
  374. package/scripts/time-runtime/time-background.ts +5 -1
  375. package/scripts/time-runtime/time-instant.ts +3 -1
  376. package/scripts/time-runtime/time-spans.ts +6 -139
  377. package/scripts/time-runtime/time-tool-call.ts +160 -0
  378. package/scripts/version/effective-upstream.ts +2 -20
  379. package/scripts/version/latest-corepack.ts +17 -17
  380. package/scripts/version/latest-regression.ts +1 -1
  381. package/scripts/version/latest-update.ts +4 -4
  382. package/scripts/version/npm-registry.ts +20 -5
  383. package/scripts/version/publishable-range-check.ts +2 -2
  384. package/scripts/version/publishable-range.ts +1 -1
  385. package/scripts/version/release-age.ts +48 -38
  386. package/scripts/version/release-hold.ts +1 -1
  387. package/scripts/version/safe-chain-version-update.ts +40 -0
  388. package/scripts/version/upgrade-shell-command.ts +48 -8
  389. package/scripts/version/version-check-logic.ts +23 -14
  390. package/scripts/version/version-commands.ts +23 -11
  391. package/scripts/version/version-remote.ts +28 -13
  392. package/templates/pnpm-workspace.basic.yaml +4 -0
  393. package/templates/workflows/dependabot-auto-merge.yml +5 -5
  394. package/templates/workflows/github-release.yml +2 -0
  395. package/scripts/build/build-config-merge.ts +0 -27
  396. package/scripts/build/build-managed-marker.ts +0 -27
  397. package/scripts/build/build-self-sync-guard.ts +0 -27
  398. package/scripts/build/build-version.ts +0 -26
  399. package/scripts/version/preinstall-version-update.ts +0 -86
  400. /package/scripts/git/{schemas.ts → git-schemas.ts} +0 -0
  401. /package/scripts/overrides/{schemas.ts → overrides-schemas.ts} +0 -0
  402. /package/scripts/run/{run-carry-conversation.ts → carry/run-carry-conversation.ts} +0 -0
  403. /package/scripts/run/{run-carry-reclaim.ts → carry/run-carry-reclaim.ts} +0 -0
  404. /package/scripts/run/{run-carry-stash.ts → carry/run-carry-stash.ts} +0 -0
  405. /package/scripts/run/{run-carry-streak.ts → carry/run-carry-streak.ts} +0 -0
  406. /package/scripts/run/{run-cut-handoff.ts → cut/run-cut-handoff.ts} +0 -0
  407. /package/scripts/run/{run-cut-report.ts → cut/run-cut-report.ts} +0 -0
  408. /package/scripts/run/{run-entry-stop.ts → entry/run-entry-stop.ts} +0 -0
  409. /package/scripts/run/{run-event-cli.ts → event/run-event-cli.ts} +0 -0
  410. /package/scripts/run/{run-event-follow.ts → event/run-event-follow.ts} +0 -0
  411. /package/scripts/run/{run-event-render.ts → event/run-event-render.ts} +0 -0
  412. /package/scripts/run/{run-event-watch.ts → event/run-event-watch.ts} +0 -0
  413. /package/scripts/run/{run-hold.ts → hold/run-hold.ts} +0 -0
  414. /package/scripts/run/{run-progress-args.ts → progress/run-progress-args.ts} +0 -0
  415. /package/scripts/run/{run-progress-clock.ts → progress/run-progress-clock.ts} +0 -0
  416. /package/scripts/run/{run-review-cli.ts → review/run-review-cli.ts} +0 -0
  417. /package/scripts/run/{run-review.ts → review/run-review.ts} +0 -0
  418. /package/scripts/run/{run-ship-next.ts → ship/run-ship-next.ts} +0 -0
  419. /package/scripts/run/{run-ship-pre-detach.ts → ship/run-ship-pre-detach.ts} +0 -0
  420. /package/scripts/run/{run-ship-review.ts → ship/run-ship-review.ts} +0 -0
  421. /package/scripts/run/{run-ship-stage.ts → ship/run-ship-stage.ts} +0 -0
  422. /package/scripts/run/{run-ship.ts → ship/run-ship.ts} +0 -0
  423. /package/scripts/run/{run-tidy-cli.ts → tidy/run-tidy-cli.ts} +0 -0
  424. /package/scripts/run/{run-tidy-stashes.ts → tidy/run-tidy-stashes.ts} +0 -0
  425. /package/scripts/run/{run-tidy.ts → tidy/run-tidy.ts} +0 -0
@@ -36,7 +36,7 @@
36
36
 
37
37
  ## 実装中の独立編集に効く合成コマンド(joshuafolkken/kit#2202)
38
38
 
39
- レーン子ではガードが `off` なので、`Read` → `Edit` の交互の並びは誰にも止められない。**Step 0 が対象ファイルを列挙した時点で、`pnpm josh read:files <path> …` で読み取りを 1 回に畳み、続く別ファイルへの編集を 1 ターンに載せる**(`report-format.md` が導く)。書き込みは `pnpm josh edit:files` で畳む(joshuafolkken/kit#2366) — プランを 1 呼び出しで適用し、`old` が 1 箇所に一致しなければ拒否する。形式は `docs/josh-commands-automation.md` →「`josh read:files`」と「`josh edit:files`」、経緯は `docs/maintainers/turn-batching-rationale.md` → "The composite commands"。
39
+ レーン子ではガードが `off` なので、`Read` → `Edit` の交互の並びは誰にも止められない。**Step 0 が対象ファイルを列挙した時点で、`pnpm josh read:files <path> …` で読み取りを 1 回に畳み、続く別ファイルへの編集を 1 ターンに載せる**(`report-format.md` が導く)。書き込みは `pnpm josh edit:files` で畳む(joshuafolkken/kit#2366) — プランを 1 呼び出しで適用し、`old` が 1 箇所に一致しなければ拒否する。形式は `docs/josh-commands-run.md` →「`josh read:files`」と「`josh edit:files`」、経緯は `docs/maintainers/turn-batching-rationale.md` → "The composite commands"。
40
40
 
41
41
  ## ガード発火時にも合成コマンドを手渡す(joshuafolkken/kit#2311)
42
42
 
@@ -9,13 +9,23 @@
9
9
  - **トリガーは「発見」であって「ブロックし始めたとき」ではない**
10
10
  - **起票は Tier A(確認なし)**。起票してよいか、どのリポジトリへ起票するか、いずれもユーザー確認を取らない。対象は first-party に限る(→「第三者リポジトリへの書き込みは Tier C(明示指示が必要)」)
11
11
  - **停止は無条件**。Issue が存在する状態にしてから停止する。上流の修正を待つか先送りするかは、Issue を目の前にしたユーザーが決める
12
- - **`backlogrun` の中では、停止の範囲がセッション全体ではなくその子 Issue に限定される**。起票と回避策の禁止は変わらない。該当の子に `needs-decision` を付けて park し、依存していない他の子へ進む(→ `.claude/skills/workflow-commands/backlogrun-park.md` → "park and continue")
12
+ - **`backlogrun` の中では、停止の範囲がセッション全体ではなくその子 Issue に限定される**。起票と回避策の禁止は変わらない。上流の修正を待つか先送りするかは人の判断なので、該当の子に `needs-decision` を付けて park し、依存していない他の子へ進む(→ `.claude/skills/workflow-commands/backlogrun-park.md` → "Only a person's judgement carries `needs-decision`")
13
+
14
+ ### 実行中のリポジトリ自身のラン機構の不具合
15
+
16
+ **この手順の対象は別パッケージであり、実行中のリポジトリ自身は含まない。** kit の中で kit のラン機構(`backlog:drive`、`run:wake`、`run:carry`、レーン、分類、カウンタ、ガードなど)の不具合を見つけた場合、それは上流の欠陥ではなく**このリポジトリの割り込み**である。上流 Issue を立てて停止する代わりに、次の手順を取る。この節がその単一ソースである。
17
+
18
+ 1. **起票する** — `pnpm josh issue:file "<title>" --body-file <path> --depth <n> --route interrupt --label priority:high`。上限は効かない(`wip-cap.md` →「割り込み起票 — 上限が効かない側」の条件 2)
19
+ 2. **止まらずに直す** — 壊れた機構を迂回しない(回避策の禁止と、検証ゲートを緩めない規則はここでも変わらない)。`backlogrun` の中では、その割り込みを次の子にし、修正が着地してから塞がれていた子へ戻る。プールから選ぶランでは `priority:high` が先頭に並べ、epic の下では `wip-cap.md` の手順 3 で挿入する。名前を指定したランのドライバーは指定された Issue しか出さないので、`pnpm josh lane:launch <N>` で自分で dispatch する。バッチの外では `wip-cap.md` の手順 4 が変わらず効く — 起票まで済ませ、打つべき `fullrun #<N>` を報告して止まる
20
+ 3. **再開できるなら自分で再開し、動くことを確かめる** — 修正のマージ後、再開の手段がある答えには人の打ち直しを求めない。手渡し済みの記録、所有者が死んだ記録、監督プロセスの停止(`warning` Telegram)には `pnpm josh run:wake --start`、`run:carry` の `standing` には `pnpm josh run:carry --resume "<invocation>" --owner "$PPID"` を自分で打つ。そのあと `pnpm josh run:wake --list` が監督プロセスを示し、そのログに次の子の dispatch が現れることを確かめて報告する
21
+ 4. **人に打ち直しを求めるのは再開の手段が無いときだけ** — `expired`(8 時間の上限を使い切った)、`mismatch`(別の起動の記録)、別の生きた所有者の `busy`。新しい承認を宣言するのは人だけ、という規則も変わらない
22
+ 5. **`needs-decision` を付けない** — ランが自分で直せる不具合は人の判断を要さない(`.claude/skills/workflow-commands/backlogrun-park.md` → "Only a person's judgement carries `needs-decision`")
13
23
 
14
24
  手順:
15
25
 
16
26
  1. **現在の作業を退避する**: `git stash push -u -m "upstream-interrupt: paused #<N>"`(WIP コミットでも可)。退避したことを忘れないよう、この時点で stash を作る。メッセージ付きで積むのは、復元をメッセージで特定するため(下記ステップ 5)
17
27
  2. **進行中の Issue に状況を明記する**: `pnpm josh issue:comment <N> --body-file <path>` で、(a) 作業を stash したこと、(b) 中断理由(どの別パッケージの・どんな問題で中断したか)、(c) 対象パッケージに作成した新 Issue へのリンクを `## Upstream issues` 見出しの下に `owner/repo#N` 形式で、を記載する。これにより「なぜこの Issue が一時停止しているか」と「何を待っているのか」が後から監査できる(→「起票元へのバックリンク」)
18
- 3. **対象パッケージのリポジトリに新しい Issue を作成する(確認なし)**: `pnpm josh issue:file "<root-cause title>" --body-file <body-file> --depth <n> --route tier-a --repo <owner>/<repo>`(`route:tier-a` は実装中の Tier A 起票を経路として集計するためのラベル — joshuafolkken/kit#1083)。本文の検査、本文が宣言する分類ラベルの付与、`## Origin` 節の確認、起票先での重複探し、`epic:bundle` はこのコマンドが実行する(`docs/josh-commands-automation.md` → `josh issue:file`)。分類の単一ソースは `prompts/collaboration-workflow/issue-template.md`。根本原因・再現・期待結果を Step 1 のテンプレに沿って記載し、**本文に `## Origin` 節を置いて起票元 Issue を `owner/repo#N` 形式で書く**(→「起票元へのバックリンク」)。ここで「起票してよいか」を尋ねて停止してはならない
28
+ 3. **対象パッケージのリポジトリに新しい Issue を作成する(確認なし)**: `pnpm josh issue:file "<root-cause title>" --body-file <body-file> --depth <n> --route tier-a --repo <owner>/<repo>`(`route:tier-a` は実装中の Tier A 起票を経路として集計するためのラベル — joshuafolkken/kit#1083)。本文の検査、本文が宣言する分類ラベルの付与、`## Origin` 節の確認、起票先での重複探し、`epic:bundle` はこのコマンドが実行する(`docs/josh-commands-backlog.md` → `josh issue:file`)。分類の単一ソースは `prompts/collaboration-workflow/issue-template.md`。根本原因・再現・期待結果を Step 1 のテンプレに沿って記載し、**本文に `## Origin` 節を置いて起票元 Issue を `owner/repo#N` 形式で書く**(→「起票元へのバックリンク」)。ここで「起票してよいか」を尋ねて停止してはならない
19
29
  4. **`confirmation` Telegram を送って停止する**: 上流 Issue の URL と、何が止まっているかを本文に書く(→ `CLAUDE.md` → "Mid-workflow stop notification (`confirmation`)")。無人実行でも画面外でユーザーが気付ける。停止は Issue が既に存在する状態で行うので、ユーザーは「待つ / 先送りする」を Issue を見ながら 1 語で答えられる
20
30
  5. **元の作業を再開する**: 上流の修正がマージされた、または**ユーザーが先送りを明示判断した**後に `pnpm josh stash:pop "upstream-interrupt: paused #<N>"`(位置指定や引数なしの `git stash pop` は使わない — stash は全 work tree が共有する 1 本のスタックで、別のレーンの stash を取り込む恐れがある)して、退避していた元タスクを続行する。上流 Issue を割り込みで実装するかどうかもユーザーの判断(上流パッケージの実装・PR・マージはそれぞれのワークフロー規則に従う)
21
31
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  **単一ソースはこのファイルである。**
4
4
 
5
- **この規則は常駐していない — 引き金つき配送に移った**(joshuafolkken/kit#1524)。`pnpm josh rule:guard` が Issue を作成する `Bash` 呼び出し(`pnpm josh issue:file`。`gh issue create` や `…/issues` への `title` 付き POST による直接起票は `direct-filing` が毎回拒否する)を拒否し、そこで数え方・拒否・2 つの免除・免除を決める 3 条件を突きつける。起票が無いターンでは何も起きず、それは上限に触れる行為が無いということである。配送は**ラン 1 回につき 1 度**なので、数えたうえで同じ呼び出しをもう一度出せばよい。機構と列挙表は `rule-delivery.md`、配送文の実体は `scripts/rules/delivered-rules.ts` の `WIP_CAP_REASON` にある(固定するテストは `docs/maintainers/wip-cap-rationale.md` →「文言を固定しているテスト」)。
5
+ **この規則は常駐していない — 引き金つき配送に移った**(joshuafolkken/kit#1524)。`pnpm josh rule:guard` が Issue を作成する `Bash` 呼び出し(`pnpm josh issue:file`。`gh issue create` や `…/issues` への `title` 付き POST による直接起票は `direct-filing` が毎回拒否する)を拒否し、そこで数え方・拒否・2 つの免除・免除を決める 3 条件を突きつける。起票が無いターンでは何も起きず、それは上限に触れる行為が無いということである。配送は**ラン 1 回につき 1 度**なので、数えたうえで同じ呼び出しをもう一度出せばよい。機構と列挙表は `rule-delivery.md`、配送文の実体は `scripts/rules/wip-cap.ts` の `WIP_CAP_REASON` にある(固定するテストは `docs/maintainers/wip-cap-rationale.md` → "Tests that pin the wording")。
6
6
 
7
7
  背景・測定・経緯は保守者向けの `docs/maintainers/wip-cap-rationale.md` にあり、ラン中に読む必要はない。
8
8
 
@@ -10,15 +10,15 @@
10
10
 
11
11
  **オープン Issue が上限を超えている状態で新しく起票するときは、先に 1 件閉じる。**
12
12
 
13
- **件数は `pnpm josh issue:file` が起票の前に数える**(joshuafolkken/kit#3181)。手で数えることも、見積もりや記憶で済ませることもない。数え方・印字・保留の詳細は `docs/josh-commands-automation.md` → "`josh issue:file`" にある。
13
+ **件数は `pnpm josh issue:file` が起票の前に数える**(joshuafolkken/kit#3181)。手で数えることも、見積もりや記憶で済ませることもない。数え方・印字・保留の詳細は `docs/josh-commands-backlog.md` → "`josh issue:file`" にある。
14
14
 
15
- - **上限は 30。** これを超える 1 件を作る前に 1 件閉じる。エージェントが読む文書(`CLAUDE.md`・`prompts/`・配布 skill)がこの数字を書くのはこの行だけで、一次情報は `scripts/rules/delivered-rules.ts` の `WIP_CAP` である(一致はテストが固定する)。
15
+ - **上限は 30。** これを超える 1 件を作る前に 1 件閉じる。エージェントが読む文書(`CLAUDE.md`・`prompts/`・配布 skill)がこの数字を書くのはこの行だけで、一次情報は `scripts/rules/wip-cap.ts` の `WIP_CAP` である(一致はテストが固定する)。
16
16
  - コマンドは起票先(`--repo` を付ければそのリポジトリ)のオープン Issue を epic も含めて数え、`wip:` 行に件数・上限・判定を印字する。上限を超えて免除が宣言されていなければ**何も送らずに保留し、免除の問いを印字する**。
17
17
  - **免除を宣言するのはこのファイルの判断である** — `--route interrupt`(下の 3 条件)、`--route split` / `--route tier-a`(実行が詰まる起票)はルートそのものが宣言になる。ルートの無い実行が詰まる起票(利用者が `new` と打った入口など)は `--over-cap` を付けて出し直す。裁量起票(`--route review-cap` を含む)に `--over-cap` を付けてはならない。
18
18
 
19
19
  ## なぜ上限が要るのか
20
20
 
21
- 測定は `docs/maintainers/wip-cap-rationale.md` →「なぜ上限が要るのか — 測定」。
21
+ 測定は `docs/maintainers/wip-cap-rationale.md` → "Why a cap is needed — the measurement"。
22
22
 
23
23
  **上限は、増加を見えるようにするための強制装置である。** 数を減らすこと自体が目的ではない。上限を超えた状態で起票しようとしたときに「本当にこれは 1 件増やす価値があるか」を必ず 1 回考えさせる、そこだけが役割である。
24
24
 
@@ -40,13 +40,13 @@
40
40
 
41
41
  前提 Issue(`prerequisite.md`)、別パッケージ起因の割り込み Issue、ユーザーが `new` と打った入口、`issue:scout` が重複無しと答えた新規作業、**そして分割判定が作る子 Issue と epic**。**これらは起票しないと実行が進まない。**
42
42
 
43
- - **上限を理由に止めない。** 理由は `docs/maintainers/wip-cap-rationale.md` →「実行が詰まる起票を止めない理由」。
43
+ - **上限を理由に止めない。** 理由は `docs/maintainers/wip-cap-rationale.md` → "Why a filing a run is blocked by is not stopped"。
44
44
  - **分割の子がここに入る理由**: 分割を検出した `fullrun` / `halfrun` は「子と epic を起票して **STOP**」と定められている(`fullrun.md` / `halfrun.md`)。**分割するかどうかを決めるのは分割判定の側**で、既定はもう「分割しない」に上がっている — 上限が二重に効く必要はない。
45
45
  - **超過した事実は完了報告に 1 行書く**(例: 「オープン 34 件で起票した」)。上限は可視化のための装置なので、超えたことが見えていれば役割は果たしている。
46
46
 
47
47
  ### 割り込み起票 — 上限が効かない側(3 条件で機械的に決める)
48
48
 
49
- **重大な欠陥の発見は、それが現在のランを止めていなくても捨ててはならない。** 上限の目的は増加を見えるようにすることであって、**発見を捨てることではない**(上の「なぜ上限が要るのか」)。由来は `docs/maintainers/wip-cap-rationale.md` →「割り込み区分の由来 — joshuafolkken/kit#1517」。
49
+ **重大な欠陥の発見は、それが現在のランを止めていなくても捨ててはならない。** 上限の目的は増加を見えるようにすることであって、**発見を捨てることではない**(上の「なぜ上限が要るのか」)。由来は `docs/maintainers/wip-cap-rationale.md` → "Where the interrupt category comes from"。
50
50
 
51
51
  **別パッケージ起因の割り込みとは別の区分である。** あちらは上流リポジトリへ起票して停止する手順(`upstream-interrupt.md`、`route:tier-a`)で、実行が詰まる側に属する。ここで言う割り込みは、**このリポジトリの欠陥で、発見したランをブロックしていないもの**を指す。
52
52
 
@@ -60,20 +60,20 @@
60
60
 
61
61
  **3 つのいずれにも当たらない発見は、従来どおり裁量側の出口を取る。** 改善案、設計上の好み、未検証の疑い、「あとで直したい」はここに入らない — レビュー指摘なら branch 3(PR 本文に 1 行残して落とす)であり、それは既定の出口であって上限に阻まれたときの代替ではない。
62
62
 
63
- **深刻さの自己申告は条件ではない。** 理由は `docs/maintainers/wip-cap-rationale.md` →「深刻さの自己申告を条件にしない理由」。
63
+ **深刻さの自己申告は条件ではない。** 理由は `docs/maintainers/wip-cap-rationale.md` → "Why self-reported severity is not a condition"。
64
64
 
65
65
  #### 該当したときの手順
66
66
 
67
- 1. **上限に関係なく起票する。** 1 件閉じることを条件にしない。起票は `pnpm josh issue:file` で行う。本文の検査、本文が宣言する分類ラベルの付与、重複探し、`epic:bundle` はこのコマンドが実行する(`docs/josh-commands-automation.md` → `josh issue:file`)。
67
+ 1. **上限に関係なく起票する。** 1 件閉じることを条件にしない。起票は `pnpm josh issue:file` で行う。本文の検査、本文が宣言する分類ラベルの付与、重複探し、`epic:bundle` はこのコマンドが実行する(`docs/josh-commands-backlog.md` → `josh issue:file`)。
68
68
 
69
69
  ```bash
70
70
  pnpm josh issue:file "<title>" --body-file <body-file> --depth <n> --route interrupt
71
71
  ```
72
72
 
73
73
  2. **超過している事実と、当たった条件の番号を本文に 1 行書く**(例:「オープン 37 件で起票。3 条件のうち 2(文書化された手順が完了できない)に該当」)。**どちらか一方では足りない** — 件数だけでは判定が再現できず、条件だけでは上限の可視化が効かない。
74
- 3. **次に実行されるものとして挿入する。** epic の下にあるなら `pnpm josh epic --add <E> <N>` で、**位置を指定せずに**追加する(`<E>` が epic、`<N>` が起票した割り込み)。**`--before` / `--after` を使ってはならない。** それらは `blocked-by` を書き込み、「発見したランをブロックしていない欠陥」という割り込みの定義と矛盾する**偽の依存関係**になる。**順序は実行側が持つ** — 先に提示させたいときは、行だけを動かす `--order-before <M>` を使う。仕組みと経緯は `docs/maintainers/wip-cap-rationale.md` →「位置を指定しない追加の経緯」。**epic の下に無いなら挿入先そのものが無い**ので、この手順は飛ばして 4 だけを行う。
74
+ 3. **次に実行されるものとして挿入する。** epic の下にあるなら `pnpm josh epic --add <E> <N>` で、**位置を指定せずに**追加する(`<E>` が epic、`<N>` が起票した割り込み)。**`--before` / `--after` を使ってはならない。** それらは `blocked-by` を書き込み、「発見したランをブロックしていない欠陥」という割り込みの定義と矛盾する**偽の依存関係**になる。**順序は実行側が持つ** — 先に提示させたいときは、行だけを動かす `--order-before <M>` を使う。仕組みと経緯は `docs/maintainers/wip-cap-rationale.md` → "Why an addition names no position"。**epic の下に無いなら挿入先そのものが無い**ので、この手順は飛ばして 4 だけを行う。
75
75
  4. **着手は、既にある承認の内側でのみ、指示を待たずに行う。** `backlogrun` の中なら、打たれたキーワードがバッチを承認しているので、割り込みは次の子として着手してよい。**バッチの外では `CLAUDE.md` →「Explicit invocation required」が変わらず効く** — 起票と挿入まで済ませたうえで、利用者に打つべきコマンド(`fullrun #<N>`)を報告して止まる。**割り込みは上限の例外であって、明示起動規則の例外ではない。**
76
76
 
77
77
  **起票と、実行されるようにするところまでが 1 つのまとまりである。** epic の下にある割り込みを起票だけして追加しなければ、`epic:next` はそれを候補にすら出さない — Issue は残るが実行されないという、コメントに埋もれるのと大差ない状態になる。**epic の外にある割り込みでは、まとまりの後半は 4 の報告そのもの**であり、打つべきコマンドを利用者に渡すまでが 1 回の行為である。上の「ひとまとまりで判定する」がここにも効く。
78
78
 
79
- **割り込みをバッチの中で単独で走らせるか、並列のレーンで走らせるか**は `.claude/skills/workflow-commands/backlogrun-lanes.md` → "Lanes — running more than one child at a time" が単一ソースである(理由は `docs/maintainers/wip-cap-rationale.md` →「単独実行の理由と由来」)。上限の数字の変え方は `docs/maintainers/wip-cap-rationale.md` →「上限そのものを変えるとき」、上限が分割判定・レビュー上限と一緒に動く理由は `docs/maintainers/wip-cap-rationale.md` →「3 つは一緒に動く」と `docs/maintainers/wip-cap-rationale.md` →「3 つを 1 コミットで着地させた経緯」にある。
79
+ **割り込みをバッチの中で単独で走らせるか、並列のレーンで走らせるか**は `.claude/skills/workflow-commands/backlogrun-lanes.md` → "Lanes — running more than one child at a time" が単一ソースである(理由は `docs/maintainers/wip-cap-rationale.md` → "Why a solo run")。上限の数字の変え方は `docs/maintainers/wip-cap-rationale.md` → "Changing the cap itself"、上限が分割判定・レビュー上限と一緒に動く理由は `docs/maintainers/wip-cap-rationale.md` → "The three move together"と `docs/maintainers/wip-cap-rationale.md` → "Why the three landed in one commit"にある。
@@ -212,8 +212,7 @@ allowed.
212
212
 
213
213
  ### 4. Project conventions (`CLAUDE.md`)
214
214
 
215
- **Do not re-check what lint enforces — the gate has already run; lint does not catch `function`
216
- syntax over an arrow const (outside named route handlers), the early-return one-liner, duplication
215
+ **Do not re-check what lint enforces — the gate has already run; lint does not catch duplication
217
216
  that is not identical, a name whose shape passes but whose meaning misleads, grouping and file layout,
218
217
  Svelte semantics, or test placement beyond the `*.spec.*` / top-level `tests/` bans, so check those.**
219
218
  A lint gap the change opens — a disabled rule, an ignored path, an added `eslint-disable`, a block
package/prompts/review.md CHANGED
@@ -167,7 +167,7 @@ Only branch 2 files an Issue. What follows applies to that branch.
167
167
  1. File the follow-up Issue referencing the current one, tagged `route:review-cap` — **before the current Issue closes.**
168
168
  `pnpm josh issue:file "<title>" --body-file <body-file> --depth <n> --route review-cap`.
169
169
  The command lints the body, applies the classification labels it declares, runs the duplicate scan
170
- and then `epic:bundle` on the new Issue (`docs/josh-commands-automation.md` → `josh issue:file`). The
170
+ and then `epic:bundle` on the new Issue (`docs/josh-commands-backlog.md` → `josh issue:file`). The
171
171
  `epic:bundle` candidate search reads open issues only, so once the parent has closed it answers
172
172
  `none` permanently.
173
173
  2. Act on the `epic:bundle` answer it prints. **`epic:bundle` recommends and writes nothing**, so acting means running the
@@ -0,0 +1,29 @@
1
+ // The mark every agent session kit launches itself carries — a lane child, a ship reviewer, a woken
2
+ // `run:wake` session (joshuafolkken/kit#3245).
3
+ //
4
+ // **Those sessions run under `claude -p`, and nobody reads their replies.** Their output goes to a
5
+ // stream-json log, and the only reader of the final text is the exit record's failure reason. So the
6
+ // stop rules that correct how a reply is written — the issue citation, the session language — refused
7
+ // replies no person would ever see, and each refusal cost a model turn: across one baseline run, 107
8
+ // of them in children and wake sessions.
9
+ //
10
+ // **It is set at the one place agent sessions are launched, never read from the prompt.** Every launch
11
+ // that passes an agent profile composes its environment in `agent_launch_environment.build`, so the
12
+ // mark is exactly "kit started this agent". A person's own session is never spawned there, so it never
13
+ // carries the mark; a process the headless session starts inherits it, and is headless too.
14
+ const KEY = 'JOSH_AGENT_HEADLESS'
15
+ const VALUE = '1'
16
+
17
+ type EnvironmentSource = Readonly<Record<string, string | undefined>>
18
+
19
+ function environment(): Record<string, string> {
20
+ return { [KEY]: VALUE }
21
+ }
22
+
23
+ function is_headless(source: EnvironmentSource = process.env): boolean {
24
+ return source[KEY] === VALUE
25
+ }
26
+
27
+ const agent_headless = { KEY, environment, is_headless }
28
+
29
+ export { agent_headless }
@@ -2,6 +2,7 @@ import { existsSync, lstatSync, mkdirSync, readlinkSync, symlinkSync, unlinkSync
2
2
  import path from 'node:path'
3
3
  import { gh_cli_token } from '#scripts/gh/gh-cli-token'
4
4
  import { PLATFORM_TEMP_ROOT } from '#scripts/josh/platform-temporary'
5
+ import { agent_headless } from './agent-headless'
5
6
  import { agent_role_profile, type AgentProfile } from './agent-role-profile'
6
7
  import { codex_home_source } from './codex-home-source'
7
8
 
@@ -57,9 +58,12 @@ function build(
57
58
  profile: AgentProfile | undefined,
58
59
  environment: LaunchEnvironment = {},
59
60
  ): LaunchEnvironment {
60
- if (profile?.provider !== OPENAI_PROVIDER) return environment
61
+ if (profile === undefined) return environment
61
62
 
62
- const base = { ...openai_environment(), ...environment }
63
+ const marked = { ...agent_headless.environment(), ...environment }
64
+ if (profile.provider !== OPENAI_PROVIDER) return marked
65
+
66
+ const base = { ...openai_environment(), ...marked }
63
67
 
64
68
  return profile.role === agent_role_profile.REVIEWER
65
69
  ? { ...base, CODEX_HOME: reviewer_home(cwd, environment) }
@@ -1,6 +1,7 @@
1
1
  import { lstatSync, mkdirSync } from 'node:fs'
2
2
  import path from 'node:path'
3
3
  import { git_common_directory } from '#scripts/git/git-common-directory'
4
+ import { OBSERVATION_LEDGER_DIRECTORY } from '#scripts/observations/observation-ledger'
4
5
  import { agent_role_profile, type AgentProfile } from './agent-role-profile'
5
6
 
6
7
  const AGENT_COMMAND = 'codex'
@@ -13,7 +14,7 @@ const SQLITE_CACHE_PATH = ['node_modules', '.cache', 'josh', 'openai']
13
14
  const EPHEMERAL_FLAG = '--ephemeral'
14
15
  const ADD_DIRECTORY_FLAG = '--add-dir'
15
16
  const GIT_DIRECTORY = '.git'
16
- const LEDGER_DIRECTORY = 'docs'
17
+ const LEDGER_DIRECTORY = path.dirname(OBSERVATION_LEDGER_DIRECTORY)
17
18
 
18
19
  interface CodexArgv {
19
20
  command: string
@@ -5,9 +5,9 @@ import { epic_index, type FetchedEpics } from '#scripts/epic/epic-index'
5
5
  import { epic_issue } from '#scripts/epic/epic-issue'
6
6
  import { git_gh_command } from '#scripts/gh/git-gh-command'
7
7
  import { SUMMARY_FIELDS } from '#scripts/gh/git-gh-issue'
8
+ import { open_issue_schema, type OpenIssueData } from '#scripts/git/git-schemas'
8
9
  import { cutoff_cause, cutoff_of, type ScanCutoff } from '#scripts/git/listing-cutoff'
9
10
  import { read_json_listing } from '#scripts/git/parse-json-array'
10
- import { open_issue_schema, type OpenIssueData } from '#scripts/git/schemas'
11
11
  import { git_next_issues } from '#scripts/issue/git-next-issues'
12
12
  import { AUTO_OK_LABEL } from '#scripts/issue/issue-labels'
13
13
 
@@ -1,5 +1,6 @@
1
1
  import { epic_triage } from '#scripts/epic/epic-triage'
2
2
  import type { JoshResult } from '#scripts/josh/josh-run'
3
+ import { COMMAND_TIMEOUT_MS } from '#scripts/lib/timeouts'
3
4
  import { run_headless } from '#scripts/run/run-headless'
4
5
  import { backlog_next } from './backlog-next'
5
6
  import { backlog_ready, type ReadyPorts, type ReadyReading } from './backlog-ready'
@@ -26,14 +27,13 @@ import { backlog_stalled } from './backlog-stalled'
26
27
  //
27
28
  // **Every read is bounded.** The probe is awaited inside the watcher's tick loop, so a `gh` call that
28
29
  // hangs would otherwise freeze the loop — its `--hours` bound, its liveness ping and the exit that is
29
- // the parent's wake. A read past `READ_TIMEOUT_MS` is killed and counts as a failed read.
30
+ // the parent's wake. A read past `COMMAND_TIMEOUT_MS` is killed and counts as a failed read.
30
31
  //
31
32
  // **And strict.** `backlog:next` exits 0 on a `retry` (a transport failure) or an `error` verdict, which
32
33
  // the lenient pick-up read takes as an empty pool — here that empty baseline is the whole-pool wake the
33
34
  // paragraph above rules out, so either verdict, like a non-zero exit, is a read that did not answer.
34
35
 
35
36
  const PROBE_INTERVAL_MS = 60_000
36
- const READ_TIMEOUT_MS = 30_000
37
37
  const SUCCESS_EXIT_CODE = 0
38
38
  const NO_FREE = 0
39
39
  const NONE = 0
@@ -61,7 +61,7 @@ function answered_issues(result: JoshResult | undefined): ReadonlyArray<string>
61
61
  }
62
62
 
63
63
  async function bounded_ready_issues(): Promise<ReadonlyArray<string>> {
64
- return answered_issues(await backlog_ready.read_backlog_next(READ_TIMEOUT_MS))
64
+ return answered_issues(await backlog_ready.read_backlog_next(COMMAND_TIMEOUT_MS))
65
65
  }
66
66
 
67
67
  const ARRIVAL_PORTS: ReadyPorts = {
@@ -59,7 +59,7 @@ type BudgetVerdict =
59
59
  typeof RUN_VERDICT | typeof WATCH_VERDICT | typeof STOP_VERDICT | typeof TRIAGE_VERDICT
60
60
 
61
61
  // What `backlog:next` answered, in the words this decision needs. The mapping is mechanical and is
62
- // written once, in `docs/josh-commands-automation.md` → "`josh backlog:offer`": numbers are `candidates`, `wait` is `blocked` while
62
+ // written once, in `docs/josh-commands-backlog.md` → "`josh backlog:offer`": numbers are `candidates`, `wait` is `blocked` while
63
63
  // this run has children in flight and `exhausted` when it does not, `none` is `exhausted`, `stop` is
64
64
  // `parked`, `triage` is `untriaged`, and `error` or a failed listing is `unreadable`.
65
65
  const ANSWERS = ['blocked', 'candidates', 'exhausted', 'parked', 'unreadable', 'untriaged'] as const
@@ -0,0 +1,135 @@
1
+ import { cli_flags } from '#scripts/lib/cli-flags'
2
+ import type { DriveState } from './backlog-drive'
3
+
4
+ // The `josh backlog:drive` flags — read into a `DriveContext`, and written back as the `resume:` line —
5
+ // split out of `backlog-drive-cli.ts` when it neared its line limit (joshuafolkken/kit#3264).
6
+ // `backlog_drive_cli` re-exports `parse` and `resume_line` under the names they always had, so the move
7
+ // changed no call site and no suite that reads them through `backlog_drive_cli`.
8
+
9
+ const MS_PER_MINUTE = 60_000
10
+ const LIST_SEPARATOR = ','
11
+ const COUNT_PATTERN = /^\d+$/u
12
+ const ISSUE_PATTERN = /^[1-9]\d*$/u
13
+ const USAGE =
14
+ 'Usage: josh backlog:drive --owner <pid> [--active <ISO-8601>] [--max <n>] [--idle <minutes>] [--only] [--exclude <n>[,<n>...]] [--await <n>[,<n>...]] [--window <minutes>] [--stopped <n>]'
15
+
16
+ const OPTIONS = {
17
+ active: { type: 'string' },
18
+ await: { type: 'string' },
19
+ exclude: { type: 'string' },
20
+ idle: { type: 'string' },
21
+ max: { type: 'string' },
22
+ only: { type: 'boolean' },
23
+ owner: { type: 'string' },
24
+ stopped: { type: 'string' },
25
+ window: { type: 'string' },
26
+ } as const
27
+
28
+ interface DriveContext {
29
+ owner: string
30
+ active: string | undefined
31
+ // Flags forwarded to `backlog:offer` unchanged — the declared budgets.
32
+ forwarded: ReadonlyArray<string>
33
+ exclude: ReadonlyArray<string>
34
+ awaited: ReadonlyArray<string>
35
+ window_ms: number | undefined
36
+ window: string | undefined
37
+ is_only: boolean
38
+ // The child whose merge answered `stop` before the hand-back: the resumed run starts already stopping.
39
+ stopped: string | undefined
40
+ }
41
+
42
+ type Values = Partial<Record<Exclude<keyof typeof OPTIONS, 'only'>, string>> & { only?: boolean }
43
+
44
+ function read_values(argv: ReadonlyArray<string>): Values | undefined {
45
+ return cli_flags.parse_or_undefined({ args: [...argv], options: OPTIONS, strict: true })?.values
46
+ }
47
+
48
+ // A comma list of issue numbers; one entry that is not an issue number refuses the whole list.
49
+ function to_issues(raw: string | undefined): ReadonlyArray<string> | undefined {
50
+ if (raw === undefined) return []
51
+
52
+ const issues = raw.split(LIST_SEPARATOR)
53
+
54
+ return issues.some((issue) => !ISSUE_PATTERN.test(issue)) ? undefined : issues
55
+ }
56
+
57
+ function forwarded_of(values: Values): ReadonlyArray<string> | undefined {
58
+ const pairs = (['max', 'idle'] as const).filter((name) => values[name] !== undefined)
59
+
60
+ if (pairs.some((name) => !COUNT_PATTERN.test(values[name] ?? ''))) return undefined
61
+
62
+ return pairs.flatMap((name) => [`--${name}`, values[name] ?? ''])
63
+ }
64
+
65
+ // An absent window is no bound; a present one must be a count, which `is_valid_window` checks first.
66
+ function window_of(raw: string | undefined): number | undefined {
67
+ return raw === undefined ? undefined : Number(raw) * MS_PER_MINUTE
68
+ }
69
+
70
+ function is_valid_window(raw: string | undefined): boolean {
71
+ return raw === undefined || COUNT_PATTERN.test(raw)
72
+ }
73
+
74
+ function is_valid_single(values: Values): boolean {
75
+ const is_valid_stopped = values.stopped === undefined || ISSUE_PATTERN.test(values.stopped)
76
+
77
+ return is_valid_stopped && is_valid_window(values.window)
78
+ }
79
+
80
+ function owner_of(values: Values | undefined): string | undefined {
81
+ const owner = values?.owner
82
+
83
+ return owner !== undefined && COUNT_PATTERN.test(owner) ? owner : undefined
84
+ }
85
+
86
+ function to_context(values: Values, owner: string): DriveContext | undefined {
87
+ if (!is_valid_single(values)) return undefined
88
+
89
+ const forwarded = forwarded_of(values)
90
+ const exclude = to_issues(values.exclude)
91
+ const awaited = to_issues(values.await)
92
+
93
+ if (forwarded === undefined || exclude === undefined || awaited === undefined) return undefined
94
+
95
+ const window_ms = window_of(values.window)
96
+
97
+ return {
98
+ owner,
99
+ active: values.active,
100
+ forwarded,
101
+ exclude,
102
+ awaited,
103
+ window_ms,
104
+ window: values.window,
105
+ is_only: values.only === true,
106
+ stopped: values.stopped,
107
+ }
108
+ }
109
+
110
+ function parse(argv: ReadonlyArray<string>): DriveContext | undefined {
111
+ const values = read_values(argv)
112
+ const owner = owner_of(values)
113
+
114
+ return values === undefined || owner === undefined ? undefined : to_context(values, owner)
115
+ }
116
+
117
+ function resume_line(state: DriveState, context: DriveContext): string {
118
+ const exclude = [...new Set([...context.exclude, ...state.exclude])]
119
+ const flags = ['--owner', context.owner, '--active', state.active, ...context.forwarded]
120
+
121
+ if (exclude.length > 0) flags.push('--exclude', exclude.join(LIST_SEPARATOR))
122
+ if (context.window !== undefined) flags.push('--window', context.window)
123
+ if (state.stopped_by !== undefined) flags.push('--stopped', state.stopped_by)
124
+
125
+ return `resume: ${flags.join(' ')}`
126
+ }
127
+
128
+ const backlog_drive_args = {
129
+ USAGE,
130
+ parse,
131
+ resume_line,
132
+ }
133
+
134
+ export { backlog_drive_args }
135
+ export type { DriveContext }
@@ -4,13 +4,11 @@ import { fileURLToPath } from 'node:url'
4
4
  import { hook_decision } from '#scripts/josh/hook-decision'
5
5
  import { josh_command } from '#scripts/josh/josh-run'
6
6
  import { lane_await, type AwaitState } from '#scripts/lane/lane-await'
7
- import { lane_launch_cli, type LaunchOutcome } from '#scripts/lane/lane-launch-cli'
8
7
  import { lane_registry } from '#scripts/lane/lane-registry'
9
- import { cli_flags } from '#scripts/lib/cli-flags'
10
8
  import { error_text } from '#scripts/lib/error-message'
11
- import { run_carry, type RunCarry } from '#scripts/run/run-carry'
12
- import { run_event_stream_emit } from '#scripts/run/run-event-stream-emit'
13
- import { run_merge_cli, type MergeResult } from '#scripts/run/run-merge-cli'
9
+ import { run_carry, type RunCarry } from '#scripts/run/carry/run-carry'
10
+ import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
11
+ import { run_merge_cli, type MergeResult } from '#scripts/run/merge/run-merge-cli'
14
12
  import { z } from 'zod'
15
13
  import {
16
14
  backlog_drive,
@@ -19,7 +17,9 @@ import {
19
17
  type LoopPorts,
20
18
  type OfferRead,
21
19
  } from './backlog-drive'
20
+ import { backlog_drive_args, type DriveContext } from './backlog-drive-args'
22
21
  import { backlog_drive_finish } from './backlog-drive-finish'
22
+ import { backlog_drive_launch } from './backlog-drive-launch'
23
23
  import { backlog_drive_named } from './backlog-drive-named'
24
24
  import { backlog_drive_named_offer } from './backlog-drive-named-offer'
25
25
  import { backlog_drive_offer_argv } from './backlog-drive-offer-argv'
@@ -44,114 +44,7 @@ const FAILURE_EXIT_CODE = 1
44
44
  const should_forward_stderr = true
45
45
  const POLL_MS = 5000
46
46
  const OFFER_MS = 60_000
47
- const MS_PER_MINUTE = 60_000
48
47
  const FIRST_LINE = 0
49
- const LIST_SEPARATOR = ','
50
- const COUNT_PATTERN = /^\d+$/u
51
- const ISSUE_PATTERN = /^[1-9]\d*$/u
52
- const USAGE =
53
- 'Usage: josh backlog:drive --owner <pid> [--active <ISO-8601>] [--max <n>] [--idle <minutes>] [--only] [--exclude <n>[,<n>...]] [--await <n>[,<n>...]] [--window <minutes>] [--stopped <n>]'
54
-
55
- const OPTIONS = {
56
- active: { type: 'string' },
57
- await: { type: 'string' },
58
- exclude: { type: 'string' },
59
- idle: { type: 'string' },
60
- max: { type: 'string' },
61
- only: { type: 'boolean' },
62
- owner: { type: 'string' },
63
- stopped: { type: 'string' },
64
- window: { type: 'string' },
65
- } as const
66
-
67
- interface DriveContext {
68
- owner: string
69
- active: string | undefined
70
- // Flags forwarded to `backlog:offer` unchanged — the declared budgets.
71
- forwarded: ReadonlyArray<string>
72
- exclude: ReadonlyArray<string>
73
- awaited: ReadonlyArray<string>
74
- window_ms: number | undefined
75
- window: string | undefined
76
- is_only: boolean
77
- // The child whose merge answered `stop` before the hand-back: the resumed run starts already stopping.
78
- stopped: string | undefined
79
- }
80
-
81
- type Values = Partial<Record<Exclude<keyof typeof OPTIONS, 'only'>, string>> & { only?: boolean }
82
-
83
- function read_values(argv: ReadonlyArray<string>): Values | undefined {
84
- return cli_flags.parse_or_undefined({ args: [...argv], options: OPTIONS, strict: true })?.values
85
- }
86
-
87
- // A comma list of issue numbers; one entry that is not an issue number refuses the whole list.
88
- function to_issues(raw: string | undefined): ReadonlyArray<string> | undefined {
89
- if (raw === undefined) return []
90
-
91
- const issues = raw.split(LIST_SEPARATOR)
92
-
93
- return issues.some((issue) => !ISSUE_PATTERN.test(issue)) ? undefined : issues
94
- }
95
-
96
- function forwarded_of(values: Values): ReadonlyArray<string> | undefined {
97
- const pairs = (['max', 'idle'] as const).filter((name) => values[name] !== undefined)
98
-
99
- if (pairs.some((name) => !COUNT_PATTERN.test(values[name] ?? ''))) return undefined
100
-
101
- return pairs.flatMap((name) => [`--${name}`, values[name] ?? ''])
102
- }
103
-
104
- // An absent window is no bound; a present one must be a count, which `is_valid_window` checks first.
105
- function window_of(raw: string | undefined): number | undefined {
106
- return raw === undefined ? undefined : Number(raw) * MS_PER_MINUTE
107
- }
108
-
109
- function is_valid_window(raw: string | undefined): boolean {
110
- return raw === undefined || COUNT_PATTERN.test(raw)
111
- }
112
-
113
- function is_valid_single(values: Values): boolean {
114
- const is_valid_stopped = values.stopped === undefined || ISSUE_PATTERN.test(values.stopped)
115
-
116
- return is_valid_stopped && is_valid_window(values.window)
117
- }
118
-
119
- function owner_of(values: Values | undefined): string | undefined {
120
- const owner = values?.owner
121
-
122
- return owner !== undefined && COUNT_PATTERN.test(owner) ? owner : undefined
123
- }
124
-
125
- function to_context(values: Values, owner: string): DriveContext | undefined {
126
- if (!is_valid_single(values)) return undefined
127
-
128
- const forwarded = forwarded_of(values)
129
- const exclude = to_issues(values.exclude)
130
- const awaited = to_issues(values.await)
131
-
132
- if (forwarded === undefined || exclude === undefined || awaited === undefined) return undefined
133
-
134
- const window_ms = window_of(values.window)
135
-
136
- return {
137
- owner,
138
- active: values.active,
139
- forwarded,
140
- exclude,
141
- awaited,
142
- window_ms,
143
- window: values.window,
144
- is_only: values.only === true,
145
- stopped: values.stopped,
146
- }
147
- }
148
-
149
- function parse(argv: ReadonlyArray<string>): DriveContext | undefined {
150
- const values = read_values(argv)
151
- const owner = owner_of(values)
152
-
153
- return values === undefined || owner === undefined ? undefined : to_context(values, owner)
154
- }
155
48
 
156
49
  // The `--json` object `backlog:offer` prints, keyed under its `JSON_KEY`.
157
50
  const offer_read_schema = z.object({
@@ -235,14 +128,6 @@ async function merge(issue: string, owner: string): Promise<MergeResult> {
235
128
  return result
236
129
  }
237
130
 
238
- async function launch(issue: string, owner: string): Promise<LaunchOutcome['kind']> {
239
- await backlog_drive_owner.assert_current(owner)
240
-
241
- const outcome = await lane_launch_cli.launch_lane({ issue, stash: undefined })
242
-
243
- return outcome.kind
244
- }
245
-
246
131
  // `lane:await`'s re-confirmed check, one state per child. A child already gone when the loop starts —
247
132
  // a restart after it ended — is read as having appeared, so it is collected after the re-confirm window
248
133
  // rather than waited on until the never-appeared timeout. One that never appeared is collected too:
@@ -278,17 +163,6 @@ async function open_lanes(): Promise<ReadonlyArray<string>> {
278
163
  return lanes.filter((lane) => !lane.is_stranded).map((lane) => lane.issue)
279
164
  }
280
165
 
281
- function resume_line(state: DriveState, context: DriveContext): string {
282
- const exclude = [...new Set([...context.exclude, ...state.exclude])]
283
- const flags = ['--owner', context.owner, '--active', state.active, ...context.forwarded]
284
-
285
- if (exclude.length > 0) flags.push('--exclude', exclude.join(LIST_SEPARATOR))
286
- if (context.window !== undefined) flags.push('--window', context.window)
287
- if (state.stopped_by !== undefined) flags.push('--stopped', state.stopped_by)
288
-
289
- return `resume: ${flags.join(' ')}`
290
- }
291
-
292
166
  function end_line(end: DriveEnd): string {
293
167
  const token = end.token === undefined || end.token === end.reason ? [] : [end.token]
294
168
  const issue = end.issue === undefined ? [] : [`#${end.issue}`]
@@ -306,7 +180,7 @@ function ports_of(
306
180
  is_finished: finished_checker(seeded),
307
181
  merge: async (issue) => await merge(issue, context.owner),
308
182
  offer: async (state) => await read_offer(state, context),
309
- launch: async (issue) => await launch(issue, context.owner),
183
+ launch: async (issue) => await backlog_drive_launch.launch(issue, context.owner),
310
184
  free_lanes: backlog_ready.drive_free_lane_count,
311
185
  now: () => new Date(),
312
186
  sleep: async (milliseconds) => {
@@ -345,7 +219,7 @@ async function drive(context: DriveContext): Promise<number> {
345
219
  const end = await backlog_drive.run_loop(last.state, config, ports_of(context, seeded, last))
346
220
 
347
221
  console.info(end_line(end))
348
- console.info(resume_line(last.state, context))
222
+ console.info(backlog_drive_args.resume_line(last.state, context))
349
223
 
350
224
  return SUCCESS_EXIT_CODE
351
225
  }
@@ -361,10 +235,10 @@ async function run_safe(context: DriveContext): Promise<number> {
361
235
  }
362
236
 
363
237
  async function run(argv: ReadonlyArray<string>): Promise<number> {
364
- const context = parse(argv)
238
+ const context = backlog_drive_args.parse(argv)
365
239
 
366
240
  if (context === undefined) {
367
- console.error(USAGE)
241
+ console.error(backlog_drive_args.USAGE)
368
242
 
369
243
  return FAILURE_EXIT_CODE
370
244
  }
@@ -384,8 +258,8 @@ const backlog_drive_cli = {
384
258
  merge,
385
259
  merge_token,
386
260
  offer_argv: backlog_drive_offer_argv.offer_argv,
387
- parse,
388
- resume_line,
261
+ parse: backlog_drive_args.parse,
262
+ resume_line: backlog_drive_args.resume_line,
389
263
  to_offer,
390
264
  }
391
265