@joshuafolkken/kit 1.1050.0 → 1.1128.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 (630) hide show
  1. package/.claude/settings.json +9 -8
  2. package/.claude/skills/epic-commands/SKILL.md +5 -7
  3. package/.claude/skills/workflow-commands/SKILL.md +20 -12
  4. package/.claude/skills/workflow-commands/background-commands.md +36 -84
  5. package/.claude/skills/workflow-commands/backlogrun-child.md +1 -1
  6. package/.claude/skills/workflow-commands/backlogrun-lanes.md +8 -6
  7. package/.claude/skills/workflow-commands/backlogrun-progress.md +30 -33
  8. package/.claude/skills/workflow-commands/backlogrun-steps.md +12 -12
  9. package/.claude/skills/workflow-commands/backlogrun.md +2 -2
  10. package/.claude/skills/workflow-commands/chain-rule.md +4 -2
  11. package/.claude/skills/workflow-commands/delegation.md +3 -3
  12. package/.claude/skills/workflow-commands/followup-reference.md +1 -1
  13. package/.claude/skills/workflow-commands/followup.md +7 -3
  14. package/.claude/skills/workflow-commands/fullrun-steps.md +3 -2
  15. package/.claude/skills/workflow-commands/fullrun.md +8 -6
  16. package/.claude/skills/workflow-commands/halfrun.md +19 -21
  17. package/.claude/skills/workflow-commands/issue-comments.md +1 -1
  18. package/.claude/skills/workflow-commands/issue-fold-existing.md +10 -10
  19. package/.claude/skills/workflow-commands/issue-scout.md +1 -1
  20. package/.claude/skills/workflow-commands/kickoff.md +9 -4
  21. package/.claude/skills/workflow-commands/latest-gate.md +8 -16
  22. package/.claude/skills/workflow-commands/needs-human-review.md +1 -1
  23. package/.claude/skills/workflow-commands/observation-filing.md +3 -3
  24. package/.claude/skills/workflow-commands/pre-gate-cut.md +4 -8
  25. package/.claude/skills/workflow-commands/prerequisite.md +1 -1
  26. package/.claude/skills/workflow-commands/prrun.md +36 -0
  27. package/.claude/skills/workflow-commands/retrospective.md +1 -1
  28. package/.claude/skills/workflow-commands/split-assessment.md +4 -18
  29. package/.claude/skills/workflow-commands/working-tree-hold.md +22 -2
  30. package/.codex/hooks.json +16 -20
  31. package/.github/actions/setup-node/action.yml +33 -0
  32. package/.github/actions/setup-pnpm/action.yml +93 -0
  33. package/.github/dependabot.yml +5 -1
  34. package/.github/workflows/auto-tag.yml +2 -3
  35. package/.github/workflows/ci.yml +31 -134
  36. package/.github/workflows/dependabot-auto-merge.yml +1 -0
  37. package/.github/workflows/pr-classification.yml +6 -44
  38. package/.github/workflows/production.yml +1 -0
  39. package/.github/workflows/publish.yml +43 -47
  40. package/.github/workflows/sonar-qube.yml +41 -4
  41. package/.pnpmfile.mjs +29 -0
  42. package/AGENTS.md +5 -2
  43. package/CLAUDE.md +33 -27
  44. package/GEMINI.md +5 -2
  45. package/README.md +66 -20
  46. package/SECURITY.md +37 -6
  47. package/cspell/index.yaml +6 -1
  48. package/dist/CLAUDE.basic.md +6 -6
  49. package/dist/CLAUDE.md +33 -27
  50. package/dist/CLAUDE.static.md +6 -6
  51. package/dist/config-merge/index.js +48 -12
  52. package/dist/hooks/batch-guard.js +4 -4
  53. package/dist/hooks/{chunk-7VPDUBRN.js → chunk-4JZDP5X5.js} +152 -155
  54. package/dist/hooks/{chunk-HJIISEAC.js → chunk-5SD2YM7Z.js} +5 -13
  55. package/dist/hooks/{chunk-NAS4C7GP.js → chunk-77J7IEQM.js} +2 -2
  56. package/dist/hooks/{chunk-DMQN45FN.js → chunk-7HVB7SZG.js} +3 -3
  57. package/dist/hooks/{chunk-RLDX5SOC.js → chunk-AIOIOMPX.js} +4413 -1970
  58. package/dist/hooks/{chunk-5BK3K7V4.js → chunk-M7QKEKWO.js} +873 -2049
  59. package/dist/hooks/{chunk-WQ4OSBSS.js → chunk-MKVGBQPA.js} +2 -2
  60. package/dist/hooks/{chunk-EJDX2TOB.js → chunk-NXYMNPUQ.js} +7 -88
  61. package/dist/hooks/{chunk-NJQOBE6L.js → chunk-QVLT52OV.js} +2 -7
  62. package/dist/hooks/{chunk-GQ7KP45M.js → chunk-XYUIQOW3.js} +2 -2
  63. package/dist/hooks/codex-hook-adapter.js +12 -48
  64. package/dist/hooks/duplicate-read-guard.js +5 -5
  65. package/dist/hooks/format-edited.js +2 -2
  66. package/dist/hooks/inputs.json +280 -0
  67. package/dist/hooks/investigation-guard.js +5 -5
  68. package/dist/hooks/pretool-guard.js +9 -9
  69. package/dist/hooks/session-lang.js +0 -1
  70. package/dist/hooks/stop-guard.js +192 -333
  71. package/dist/josh.js +240 -148
  72. package/dist/managed-marker/index.js +2 -1
  73. package/dist/version/index.js +70 -78
  74. package/eslint/rules/promise.js +5 -0
  75. package/eslint/rules/unicorn.js +3 -2
  76. package/package.json +26 -5
  77. package/pnpm-workspace.yaml +5 -7
  78. package/prompts/collaboration-workflow/glossary.md +17 -0
  79. package/prompts/collaboration-workflow/issue-citation.md +5 -5
  80. package/prompts/collaboration-workflow/issue-template.md +1 -1
  81. package/prompts/collaboration-workflow/operating-rules.md +5 -5
  82. package/prompts/collaboration-workflow/overview.md +13 -1
  83. package/prompts/collaboration-workflow/principles.md +9 -0
  84. package/prompts/collaboration-workflow/report-format.md +1 -1
  85. package/prompts/collaboration-workflow/residency.md +3 -3
  86. package/prompts/collaboration-workflow/rule-delivery.md +1 -1
  87. package/prompts/collaboration-workflow/turn-batching.md +3 -3
  88. package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
  89. package/prompts/collaboration-workflow/wip-cap.md +25 -22
  90. package/prompts/collaboration-workflow.md +6 -8
  91. package/prompts/review-rubric.md +1 -1
  92. package/prompts/review.md +3 -3
  93. package/prompts/sonar-hotspot-handling.md +11 -3
  94. package/prompts/testing-guide.md +3 -3
  95. package/scripts/adopt/adopt-toolkits.ts +0 -2
  96. package/scripts/adopt/adopt.ts +0 -2
  97. package/scripts/agent/agent-argv.ts +0 -2
  98. package/scripts/agent/agent-diagnostics.ts +1 -1
  99. package/scripts/agent/agent-role-profile.ts +0 -7
  100. package/scripts/agent/claude-agent-argv.ts +0 -2
  101. package/scripts/agent/codex-agent-argv.ts +1 -1
  102. package/scripts/agent/codex-hooks.ts +92 -0
  103. package/scripts/agent/interactive-ask.ts +1 -1
  104. package/scripts/auto-ok/auto-ok-cli.ts +6 -16
  105. package/scripts/backlog/backlog-arrival.ts +30 -10
  106. package/scripts/backlog/backlog-budget-cli.ts +15 -16
  107. package/scripts/backlog/backlog-budget.ts +0 -2
  108. package/scripts/backlog/backlog-defect-priority.ts +2 -2
  109. package/scripts/backlog/backlog-drive-cli.ts +10 -8
  110. package/scripts/backlog/backlog-drive-named-offer.ts +16 -3
  111. package/scripts/backlog/backlog-drive-named.ts +2 -1
  112. package/scripts/backlog/backlog-drive.ts +76 -16
  113. package/scripts/backlog/backlog-named.ts +0 -3
  114. package/scripts/backlog/backlog-next.ts +9 -15
  115. package/scripts/backlog/backlog-offer-cli.ts +6 -19
  116. package/scripts/backlog/backlog-plan-cli.ts +1 -7
  117. package/scripts/backlog/backlog-plan.ts +30 -19
  118. package/scripts/backlog/backlog-pool.ts +3 -6
  119. package/scripts/backlog/backlog-rank.ts +2 -2
  120. package/scripts/backlog/backlog-ready.ts +39 -10
  121. package/scripts/backlog/backlog-scope.ts +1 -3
  122. package/scripts/backlog/backlog-stalled-detect.ts +2 -2
  123. package/scripts/backlog/backlog-stalled.ts +0 -1
  124. package/scripts/backlog/backlog-waves.ts +5 -2
  125. package/scripts/behavior/behavior-cli.ts +1 -1
  126. package/scripts/build/build-codex-hooks.ts +26 -0
  127. package/scripts/build/build-hooks.ts +85 -9
  128. package/scripts/build/hook-bundle-stamp.ts +111 -0
  129. package/scripts/cases/cases-cli.ts +1 -1
  130. package/scripts/cases/cases-logic.ts +1 -1
  131. package/scripts/ci/composite-actions.ts +30 -0
  132. package/scripts/ci/pr-classification.ts +3 -3
  133. package/scripts/claude/workflow-destination.ts +10 -1
  134. package/scripts/clone/clone-fingerprint.ts +0 -1
  135. package/scripts/clone/clone-scan-cli.ts +1 -1
  136. package/scripts/clone/clone-scan.ts +1 -1
  137. package/scripts/config-merge/json-format.ts +0 -1
  138. package/scripts/config-merge/parse-jsonc.ts +33 -3
  139. package/scripts/config-merge/patch-json-key.ts +13 -6
  140. package/scripts/config-merge/patch-yaml-list.ts +1 -1
  141. package/scripts/cost-runtime/codex-usage.ts +2 -9
  142. package/scripts/cost-runtime/cost-attribute.ts +0 -1
  143. package/scripts/cost-runtime/cost-cli.ts +3 -10
  144. package/scripts/cost-runtime/cost-corpus.ts +0 -2
  145. package/scripts/cost-runtime/cost-format.ts +0 -3
  146. package/scripts/cost-runtime/cost-pricing.ts +0 -1
  147. package/scripts/cost-runtime/cost-tokens.ts +0 -1
  148. package/scripts/delegation/delegation-cli.ts +1 -1
  149. package/scripts/delegation/delegation-policy.ts +0 -1
  150. package/scripts/delegation/duplicate-read-guard.ts +0 -8
  151. package/scripts/delegation/fanout-cli.ts +1 -1
  152. package/scripts/delegation/fanout.ts +0 -2
  153. package/scripts/delegation/investigation-reads.ts +1 -164
  154. package/scripts/discovery/repo-map-logic.ts +0 -1
  155. package/scripts/discovery/repo-party-cli.ts +1 -1
  156. package/scripts/doctor/doctor-consumer.ts +6 -10
  157. package/scripts/doctor/doctor-io.ts +9 -13
  158. package/scripts/doctor/doctor-logic.ts +0 -4
  159. package/scripts/doctor/doctor.ts +14 -9
  160. package/scripts/document/backlogrun-parent-read-set.ts +12 -1
  161. package/scripts/document/document-byte-budget.ts +5 -5
  162. package/scripts/document/document-byte-check.ts +0 -1
  163. package/scripts/document/document-read-cli.ts +0 -2
  164. package/scripts/document/document-section-cli.ts +1 -1
  165. package/scripts/document/document-section.ts +0 -3
  166. package/scripts/document/edit-files-cli.ts +0 -1
  167. package/scripts/document/entry-read-budget.ts +21 -7
  168. package/scripts/document/entry-read-set.ts +32 -8
  169. package/scripts/document/lane-child-read-set.ts +8 -6
  170. package/scripts/document/read-files-cli.ts +0 -4
  171. package/scripts/document/read-set-cli.ts +0 -2
  172. package/scripts/document/read-set-point-of-use.ts +9 -3
  173. package/scripts/document/read-set-pricing.ts +0 -1
  174. package/scripts/document/read-set-trim.ts +4 -2
  175. package/scripts/epic/epic-add.ts +1 -1
  176. package/scripts/epic/epic-audit-cli.ts +1 -4
  177. package/scripts/epic/epic-audit-orphans.ts +1 -3
  178. package/scripts/epic/epic-audit-rationale.ts +0 -1
  179. package/scripts/epic/epic-audit-report.ts +0 -2
  180. package/scripts/epic/epic-audit.ts +8 -22
  181. package/scripts/epic/epic-bundle-cli.ts +1 -1
  182. package/scripts/epic/epic-bundle-evidence.ts +0 -1
  183. package/scripts/epic/epic-bundle-referenced.ts +1 -5
  184. package/scripts/epic/epic-bundle.ts +0 -4
  185. package/scripts/epic/epic-busy.ts +4 -5
  186. package/scripts/epic/epic-candidate-confirm.ts +0 -5
  187. package/scripts/epic/epic-classify.ts +2 -2
  188. package/scripts/epic/epic-cli-argv.ts +0 -1
  189. package/scripts/epic/epic-close-comment.ts +1 -1
  190. package/scripts/epic/epic-close.ts +5 -2
  191. package/scripts/epic/epic-cross-repo.ts +2 -4
  192. package/scripts/epic/epic-decision.ts +0 -1
  193. package/scripts/epic/epic-fetch.ts +2 -2
  194. package/scripts/epic/epic-index.ts +2 -3
  195. package/scripts/epic/epic-issue.ts +1 -15
  196. package/scripts/epic/epic-lane-offer.ts +9 -8
  197. package/scripts/epic/epic-nested.ts +1 -1
  198. package/scripts/epic/epic-next-read.ts +1 -3
  199. package/scripts/epic/epic-next-views.ts +0 -1
  200. package/scripts/epic/epic-next.ts +1 -10
  201. package/scripts/epic/epic-parse.ts +0 -1
  202. package/scripts/epic/epic-promote.ts +0 -9
  203. package/scripts/epic/epic-rank.ts +2 -2
  204. package/scripts/epic/epic-read.ts +1 -2
  205. package/scripts/epic/epic-reconcile.ts +1 -1
  206. package/scripts/epic/epic-reference.ts +1 -13
  207. package/scripts/epic/epic-relation-recheck.ts +1 -1
  208. package/scripts/epic/epic-relations.ts +1 -1
  209. package/scripts/epic/epic-remove.ts +1 -1
  210. package/scripts/epic/epic-report.ts +0 -1
  211. package/scripts/epic/epic-run.ts +2 -3
  212. package/scripts/epic/epic-shape.ts +1 -1
  213. package/scripts/epic/epic-solo-stale.ts +107 -0
  214. package/scripts/epic/epic-solo.ts +3 -2
  215. package/scripts/epic/epic-triage.ts +1 -1
  216. package/scripts/epic/epic-validate.ts +1 -1
  217. package/scripts/epic/epic.ts +1 -1
  218. package/scripts/exports/unused-members-cli.ts +53 -0
  219. package/scripts/{git → followup}/followup-issue-number.ts +1 -6
  220. package/scripts/{git → followup}/git-followup-cleanup.ts +2 -1
  221. package/scripts/{git → followup}/git-followup-finish.ts +1 -3
  222. package/scripts/{git → followup}/git-followup-flush.ts +2 -2
  223. package/scripts/{git → followup}/git-followup-issue-close.ts +2 -2
  224. package/scripts/{git → followup}/git-followup-label.ts +4 -4
  225. package/scripts/followup/git-followup-merged.ts +112 -0
  226. package/scripts/{git → followup}/git-followup-pending.ts +1 -1
  227. package/scripts/{git → followup}/git-followup-workflow.ts +19 -11
  228. package/scripts/{git → followup}/git-pr-followup-wrapup.ts +9 -3
  229. package/scripts/{git → followup}/git-pr-followup.ts +53 -16
  230. package/scripts/gate/core-budget.ts +3 -9
  231. package/scripts/gate/gate-plan.ts +7 -4
  232. package/scripts/gate/gate-report.ts +0 -6
  233. package/scripts/gate/gate-tree.ts +1 -1
  234. package/scripts/gate/pre-commit-type-check.ts +0 -6
  235. package/scripts/gate/project-checks.ts +7 -8
  236. package/scripts/gate/scoped-green.ts +0 -1
  237. package/scripts/gate/type-check-step.ts +1 -1
  238. package/scripts/gate/verification-gate.ts +0 -2
  239. package/scripts/gh/fix-gh-packages.ts +15 -12
  240. package/scripts/gh/gh-spawn.ts +2 -2
  241. package/scripts/{git → gh}/git-ai-review-scan.ts +1 -5
  242. package/scripts/{git → gh}/git-gh-check.ts +2 -1
  243. package/scripts/{git → gh}/git-gh-exec.ts +1 -1
  244. package/scripts/{git → gh}/git-gh-failure.ts +1 -1
  245. package/scripts/{git → gh}/git-gh-helpers.ts +0 -1
  246. package/scripts/{git → gh}/git-gh-issue-list.ts +13 -10
  247. package/scripts/{git → gh}/git-gh-issue-read.ts +1 -1
  248. package/scripts/{git → gh}/git-gh-issue-rest.ts +6 -3
  249. package/scripts/{git → gh}/git-gh-issue-write.ts +4 -1
  250. package/scripts/{git → gh}/git-gh-pr-auto-merge.ts +4 -1
  251. package/scripts/{git → gh}/git-gh-pr-read.ts +24 -0
  252. package/scripts/{git → gh}/git-gh-pr-rest.ts +5 -2
  253. package/scripts/{git → gh}/git-gh-pr-review.ts +2 -2
  254. package/scripts/{git → gh}/git-gh-pr-rollup.ts +1 -3
  255. package/scripts/{git → gh}/git-gh-pr.ts +3 -1
  256. package/scripts/{git → gh}/git-pr-ai-review.ts +2 -5
  257. package/scripts/{git → gh}/git-pr-checks-eval.ts +0 -10
  258. package/scripts/{git → gh}/git-pr-checks-parse.ts +4 -20
  259. package/scripts/{git → gh}/git-pr-checks.ts +2 -1
  260. package/scripts/{git → gh}/git-pr-coderabbit.ts +2 -5
  261. package/scripts/{git → gh}/git-pr-confirmation.ts +1 -3
  262. package/scripts/{git → gh}/git-pr-managed-config.ts +2 -3
  263. package/scripts/{git → gh}/git-pr.ts +3 -3
  264. package/scripts/git/changed-file-scope.ts +0 -1
  265. package/scripts/git/git-branch.ts +3 -6
  266. package/scripts/git/git-command.ts +6 -1
  267. package/scripts/git/git-commit.ts +1 -1
  268. package/scripts/git/git-common-directory.ts +80 -24
  269. package/scripts/git/git-error.ts +66 -9
  270. package/scripts/git/git-issue.ts +1 -1
  271. package/scripts/git/git-preflight.ts +2 -2
  272. package/scripts/git/git-prompt.ts +6 -31
  273. package/scripts/git/git-push.ts +1 -1
  274. package/scripts/git/git-spawn-sync.ts +65 -0
  275. package/scripts/git/git-spawn.ts +5 -4
  276. package/scripts/git/git-staging.ts +1 -0
  277. package/scripts/git/git-status.ts +1 -1
  278. package/scripts/git/git-workflow.ts +1 -1
  279. package/scripts/git/gone-branch.ts +1 -0
  280. package/scripts/git/listing-cutoff.ts +1 -1
  281. package/scripts/git/main-merge.ts +1 -1
  282. package/scripts/git/main-sync.ts +19 -1
  283. package/scripts/git/parse-json-array.ts +0 -3
  284. package/scripts/git/repository-lock.ts +16 -16
  285. package/scripts/git/{git-stash.ts → stash/git-stash.ts} +1 -1
  286. package/scripts/git/{stash-pop-args.ts → stash/stash-pop-args.ts} +2 -7
  287. package/scripts/git/{stash-pop-cli.ts → stash/stash-pop-cli.ts} +0 -1
  288. package/scripts/git/{stash-sweep-lock.ts → stash/stash-sweep-lock.ts} +3 -3
  289. package/scripts/hooks/codex-hook-adapter.ts +0 -1
  290. package/scripts/hooks/edited-cspell.ts +1 -1
  291. package/scripts/hooks/format-edited-file.ts +2 -0
  292. package/scripts/hooks/pre-push-unit.ts +0 -4
  293. package/scripts/hooks/pretool-guard.ts +22 -4
  294. package/scripts/hooks/reserved-run.ts +1 -1
  295. package/scripts/hooks/step-zero-notice.ts +76 -0
  296. package/scripts/hooks/stop-guard.ts +47 -21
  297. package/scripts/init/claude-plugin-config.ts +4 -5
  298. package/scripts/init/hook-command-rewrite.ts +16 -8
  299. package/scripts/init/hook-launch.ts +41 -15
  300. package/scripts/init/init-basic.ts +2 -5
  301. package/scripts/init/init-file-action.ts +54 -0
  302. package/scripts/init/init-logic-migrate.ts +35 -17
  303. package/scripts/init/init-logic-secretlint.ts +1 -1
  304. package/scripts/init/init-logic.ts +10 -19
  305. package/scripts/init/init.ts +11 -71
  306. package/scripts/init/kit-written-paths.ts +2 -0
  307. package/scripts/init/project-profile.ts +9 -17
  308. package/scripts/init/start-exec.ts +1 -1
  309. package/scripts/init/start-setup-pr.ts +6 -6
  310. package/scripts/init/start-steps.ts +3 -1
  311. package/scripts/issue/behavior-change-lint.ts +0 -1
  312. package/scripts/issue/defect-rate-cli.ts +64 -23
  313. package/scripts/issue/defect-rate.ts +1 -2
  314. package/scripts/{git → issue}/git-next-issues.ts +3 -3
  315. package/scripts/issue/issue-backlinks-cli.ts +1 -5
  316. package/scripts/issue/issue-backlinks.ts +7 -14
  317. package/scripts/issue/issue-cite-cli.ts +2 -6
  318. package/scripts/issue/issue-cite.ts +12 -8
  319. package/scripts/issue/issue-classification.ts +1 -9
  320. package/scripts/issue/issue-closing-pr.ts +4 -4
  321. package/scripts/issue/issue-comment-cli.ts +2 -2
  322. package/scripts/issue/issue-file-cli.ts +5 -5
  323. package/scripts/issue/issue-file.ts +7 -14
  324. package/scripts/issue/issue-fold-cli.ts +1 -1
  325. package/scripts/issue/issue-fold-existing-cli.ts +1 -1
  326. package/scripts/{git → issue}/issue-labels.ts +8 -0
  327. package/scripts/issue/issue-lint-cli.ts +1 -1
  328. package/scripts/issue/issue-merged.ts +2 -2
  329. package/scripts/{git → issue}/issue-rank.ts +1 -1
  330. package/scripts/issue/issue-read-cli.ts +8 -47
  331. package/scripts/issue/issue-read.ts +0 -2
  332. package/scripts/issue/issue-report-failures.ts +80 -0
  333. package/scripts/issue/issue-scout-cli.ts +1 -7
  334. package/scripts/issue/issue-scout-closed.ts +2 -2
  335. package/scripts/issue/issue-scout.ts +0 -2
  336. package/scripts/issue/issue-state-cli.ts +5 -46
  337. package/scripts/issue/issue-state.ts +1 -5
  338. package/scripts/issue/markdown-section.ts +21 -6
  339. package/scripts/issue/measure-rerun-cli.ts +74 -15
  340. package/scripts/issue/reproduction-measure.ts +1 -1
  341. package/scripts/josh/cli-body.ts +1 -1
  342. package/scripts/josh/file-map-stamp.ts +0 -3
  343. package/scripts/josh/josh-command-map.ts +2 -0
  344. package/scripts/josh/josh-commands-ai.ts +9 -102
  345. package/scripts/josh/josh-commands-backlog.ts +5 -1
  346. package/scripts/josh/josh-commands-development.ts +8 -1
  347. package/scripts/josh/josh-commands-issue.ts +2 -2
  348. package/scripts/josh/josh-commands-maintenance.ts +7 -0
  349. package/scripts/josh/josh-commands-project.ts +7 -1
  350. package/scripts/josh/josh-commands-run.ts +114 -0
  351. package/scripts/josh/josh-commands-versioning.ts +8 -0
  352. package/scripts/josh/josh-commands-workflow.ts +3 -3
  353. package/scripts/josh/path-decision.ts +0 -3
  354. package/scripts/josh/process-owner.ts +16 -0
  355. package/scripts/josh/run-github-prerequisite.ts +3 -6
  356. package/scripts/josh/session-language-cli.ts +0 -1
  357. package/scripts/lane/lane-await.ts +46 -19
  358. package/scripts/lane/lane-capacity.ts +6 -3
  359. package/scripts/lane/lane-child-invocation.ts +20 -7
  360. package/scripts/lane/lane-cli.ts +1 -4
  361. package/scripts/lane/lane-close.ts +5 -4
  362. package/scripts/lane/lane-dispatch.ts +3 -4
  363. package/scripts/lane/lane-environment.ts +0 -9
  364. package/scripts/lane/lane-handoff.ts +38 -0
  365. package/scripts/lane/lane-launch-cli.ts +31 -27
  366. package/scripts/lane/lane-open.ts +0 -3
  367. package/scripts/lane/lane-output.ts +0 -1
  368. package/scripts/lane/lane-registry.ts +9 -0
  369. package/scripts/lane/openai-lane-ship.ts +2 -0
  370. package/scripts/lane/openai-lane-supervisor-decision.ts +2 -1
  371. package/scripts/lane/openai-lane-supervisor.ts +6 -4
  372. package/scripts/lane/openai-review-broker.ts +7 -1
  373. package/scripts/lib/bounded-pool.ts +1 -0
  374. package/scripts/lib/cli-flags.ts +31 -2
  375. package/scripts/lib/error-message.ts +12 -1
  376. package/scripts/lib/json-value.ts +5 -4
  377. package/scripts/lib/poll.ts +3 -1
  378. package/scripts/lib/timed-fetch.ts +15 -0
  379. package/scripts/lib/timeouts.ts +13 -0
  380. package/scripts/{yaml → lib}/yaml-document.ts +3 -1
  381. package/scripts/{bytes → lines}/bytes-command.ts +0 -2
  382. package/scripts/lines/line-targets.ts +0 -11
  383. package/scripts/lines/lines-command.ts +5 -4
  384. package/scripts/lint/lint-related-scope.ts +0 -1
  385. package/scripts/lint/lint-related.ts +1 -1
  386. package/scripts/{git → notify}/telegram-notify.ts +2 -2
  387. package/scripts/{git → notify}/telegram-test.ts +4 -4
  388. package/scripts/observations/observation-ledger-home.ts +0 -1
  389. package/scripts/observations/observation-ledger-line.ts +0 -1
  390. package/scripts/observations/observation-ledger-migrate.ts +1 -1
  391. package/scripts/observations/observations-flush-landing.ts +3 -3
  392. package/scripts/observations/observations-flush.ts +2 -2
  393. package/scripts/overrides/lockfile-overrides.ts +1 -1
  394. package/scripts/overrides/overrides-logic.ts +1 -1
  395. package/scripts/package/package-scout-cli.ts +2 -7
  396. package/scripts/package/package-scout.ts +0 -2
  397. package/scripts/propagate/propagate-git-failure.ts +0 -1
  398. package/scripts/propagate/propagate-git.ts +3 -10
  399. package/scripts/propagate/propagate-publish.ts +2 -3
  400. package/scripts/propagate/propagate-run.ts +0 -2
  401. package/scripts/propagate/propagate-steps.ts +3 -5
  402. package/scripts/propagate/propagate-targets.ts +0 -4
  403. package/scripts/propagate/propagate.ts +0 -4
  404. package/scripts/refactor/import-graph.ts +0 -1
  405. package/scripts/refactor/refactor-lint.ts +0 -2
  406. package/scripts/refactor/refactor-scan.ts +2 -2
  407. package/scripts/refactor/refactor-targets.ts +0 -1
  408. package/scripts/registry-migration/migrate-logic.ts +28 -21
  409. package/scripts/registry-migration/migrate.ts +25 -14
  410. package/scripts/release/github-release-cli.ts +19 -6
  411. package/scripts/release/github-release-environment.ts +46 -0
  412. package/scripts/release/github-release.ts +151 -94
  413. package/scripts/release/release-history.ts +0 -1
  414. package/scripts/release/release-plan.ts +0 -1
  415. package/scripts/release/release-publish.ts +38 -5
  416. package/scripts/release/release-scope-cli.ts +1 -2
  417. package/scripts/release/release-tag.ts +2 -4
  418. package/scripts/release/release-worktree.ts +97 -2
  419. package/scripts/repo/auto-merge-setting-logic.ts +1 -4
  420. package/scripts/repo/repo-setting.ts +1 -1
  421. package/scripts/repo/repository-labels.ts +3 -3
  422. package/scripts/repo/required-checks-logic.ts +206 -0
  423. package/scripts/repo/required-checks-report.ts +71 -0
  424. package/scripts/repo/ruleset-check-cli.ts +53 -0
  425. package/scripts/repo/ruleset-check.ts +147 -0
  426. package/scripts/report/report-lint-cli.ts +0 -4
  427. package/scripts/review/disposition-cli.ts +1 -1
  428. package/scripts/review/live-evidence.ts +1 -1
  429. package/scripts/review/review-attest-cli.ts +0 -6
  430. package/scripts/review/review-attest.ts +4 -16
  431. package/scripts/review/review-brief-cli.ts +23 -6
  432. package/scripts/review/review-brief.ts +21 -8
  433. package/scripts/review/review-checkout.ts +3 -2
  434. package/scripts/review/review-diff-parts.ts +89 -0
  435. package/scripts/review/review-diff-write.ts +97 -0
  436. package/scripts/review/review-finding-ledger.ts +0 -1
  437. package/scripts/review/review-record-cli.ts +10 -17
  438. package/scripts/review/review-record.ts +0 -1
  439. package/scripts/review/review-round2-cli.ts +1 -1
  440. package/scripts/review/review-stamps.ts +0 -3
  441. package/scripts/review/review-tree.ts +14 -2
  442. package/scripts/rules/decision-oracle-stage.ts +18 -0
  443. package/scripts/rules/decision-oracle.ts +10 -7
  444. package/scripts/rules/delivered-rules.ts +9 -1
  445. package/scripts/rules/destructive-command.ts +119 -0
  446. package/scripts/rules/direct-filing.ts +1 -1
  447. package/scripts/rules/early-heartbeat.ts +4 -3
  448. package/scripts/rules/file-body.ts +0 -3
  449. package/scripts/rules/filing-cap.ts +0 -2
  450. package/scripts/rules/gh-api.ts +7 -2
  451. package/scripts/rules/git-argv.ts +18 -7
  452. package/scripts/rules/git-force.ts +0 -2
  453. package/scripts/rules/implementation-cut.ts +0 -1
  454. package/scripts/rules/index-guard.ts +71 -0
  455. package/scripts/rules/issue-citation.ts +50 -25
  456. package/scripts/rules/lane-background.ts +15 -7
  457. package/scripts/rules/lane-park.ts +22 -6
  458. package/scripts/rules/last-prompt.ts +1 -0
  459. package/scripts/rules/oracle-consulted.ts +1 -1
  460. package/scripts/rules/oracle-firing.ts +1 -0
  461. package/scripts/rules/oracle-list-cli.ts +0 -3
  462. package/scripts/rules/permission-guards.ts +14 -0
  463. package/scripts/rules/protected-files.ts +74 -0
  464. package/scripts/rules/reply-language.ts +1 -1
  465. package/scripts/rules/rule-body-guard.ts +0 -3
  466. package/scripts/rules/rule-value-cli.ts +0 -1
  467. package/scripts/rules/shell-body-trigger.ts +0 -1
  468. package/scripts/rules/shell-segments.ts +0 -1
  469. package/scripts/rules/stop-rules.ts +20 -9
  470. package/scripts/rules/tail-commands.ts +1 -1
  471. package/scripts/rules/test-declared-commit.ts +1 -1
  472. package/scripts/rules/third-party-write.ts +0 -1
  473. package/scripts/rules/worktree-guard.ts +26 -9
  474. package/scripts/run/run-carry-args.ts +8 -12
  475. package/scripts/run/run-carry-cli.ts +0 -2
  476. package/scripts/run/run-carry-stash.ts +2 -2
  477. package/scripts/run/run-carry-streak.ts +1 -1
  478. package/scripts/run/run-cut-args.ts +1 -6
  479. package/scripts/run/run-cut-cli.ts +0 -7
  480. package/scripts/run/run-cut.ts +8 -54
  481. package/scripts/run/run-ending-cli.ts +2 -6
  482. package/scripts/run/run-ending.ts +1 -4
  483. package/scripts/run/run-entry-cli.ts +133 -25
  484. package/scripts/run/run-entry-stop.ts +104 -0
  485. package/scripts/run/run-entry.ts +0 -1
  486. package/scripts/run/run-event-cli.ts +0 -2
  487. package/scripts/run/run-event-follow.ts +1 -0
  488. package/scripts/run/run-event-render.ts +1 -1
  489. package/scripts/run/run-event-scope.ts +53 -4
  490. package/scripts/run/run-event-stream-emit.ts +7 -2
  491. package/scripts/run/run-event-stream.ts +0 -3
  492. package/scripts/run/run-event-watch.ts +1 -0
  493. package/scripts/run/run-halfrun-resume.ts +20 -7
  494. package/scripts/run/run-headless.ts +2 -2
  495. package/scripts/run/run-hold-cli.ts +33 -10
  496. package/scripts/run/run-hold.ts +29 -6
  497. package/scripts/run/run-issue-number.ts +1 -1
  498. package/scripts/run/run-liveness-cli.ts +2 -6
  499. package/scripts/run/run-liveness.ts +2 -3
  500. package/scripts/run/run-merge-cli.ts +7 -23
  501. package/scripts/run/run-merge-steps.ts +5 -5
  502. package/scripts/run/run-merge.ts +1 -1
  503. package/scripts/run/run-next-cli.ts +1 -1
  504. package/scripts/run/run-parent-cut-hook.ts +4 -2
  505. package/scripts/run/run-preflight.ts +2 -9
  506. package/scripts/run/run-prep-cli.ts +6 -3
  507. package/scripts/run/run-prep-locate.ts +1 -1
  508. package/scripts/run/run-progress-args.ts +20 -4
  509. package/scripts/run/run-progress-cli.ts +35 -36
  510. package/scripts/run/run-progress-clock.ts +10 -35
  511. package/scripts/run/run-progress-config.ts +0 -4
  512. package/scripts/run/run-progress-read.ts +1 -2
  513. package/scripts/run/run-progress.ts +1 -2
  514. package/scripts/run/run-prrun-resume.ts +117 -0
  515. package/scripts/run/run-report-cli.ts +1 -2
  516. package/scripts/run/run-report.ts +0 -1
  517. package/scripts/run/run-retrospective.ts +1 -1
  518. package/scripts/run/run-review-cli.ts +0 -3
  519. package/scripts/run/run-review-steps.ts +2 -0
  520. package/scripts/run/run-review.ts +0 -2
  521. package/scripts/run/run-ship-cli.ts +29 -19
  522. package/scripts/run/run-ship-detach.ts +1 -0
  523. package/scripts/run/run-ship-next.ts +106 -0
  524. package/scripts/run/run-ship-preflight.ts +1 -1
  525. package/scripts/run/run-ship-probe.ts +4 -1
  526. package/scripts/run/run-ship-return.ts +8 -3
  527. package/scripts/run/run-ship-review-steps.ts +18 -4
  528. package/scripts/run/run-ship-review.ts +11 -0
  529. package/scripts/run/run-ship-scoped.ts +1 -0
  530. package/scripts/run/run-ship-steps.ts +1 -1
  531. package/scripts/run/run-ship.ts +0 -1
  532. package/scripts/run/run-stage-read.ts +62 -0
  533. package/scripts/run/run-stage.ts +160 -0
  534. package/scripts/run/run-status-cli.ts +3 -16
  535. package/scripts/run/run-step-cli.ts +21 -14
  536. package/scripts/run/run-step.ts +1 -1
  537. package/scripts/run/run-stop-notify.ts +1 -3
  538. package/scripts/run/run-stranded-cli.ts +0 -4
  539. package/scripts/run/run-stranded-detect.ts +2 -2
  540. package/scripts/run/run-tail-cli.ts +17 -11
  541. package/scripts/run/run-tail.ts +2 -0
  542. package/scripts/run/run-tidy-lanes.ts +6 -2
  543. package/scripts/run/run-tidy-stashes.ts +12 -12
  544. package/scripts/run/run-wake-cli.ts +4 -13
  545. package/scripts/run/run-wake-loop.ts +2 -2
  546. package/scripts/run/run-wake.ts +2 -4
  547. package/scripts/run/run-watcher-guard-cli.ts +0 -4
  548. package/scripts/run/run-watcher-guard.ts +18 -12
  549. package/scripts/run/run-watcher-hook.ts +1 -1
  550. package/scripts/safe-chain/ci-installer-pin.ts +11 -5
  551. package/scripts/safe-chain/pack-hook.ts +92 -0
  552. package/scripts/safe-chain/project-config.ts +1 -1
  553. package/scripts/security/security-audit-provision-logic.ts +0 -1
  554. package/scripts/security/security-audit-provision.ts +3 -2
  555. package/scripts/security/security-audit.ts +0 -1
  556. package/scripts/security/security-updates-logic.ts +0 -1
  557. package/scripts/sonar/sonar-hotspots-cli.ts +10 -52
  558. package/scripts/sonar/sonar-hotspots.ts +0 -1
  559. package/scripts/sonar/sonar-new-code-cli.ts +150 -0
  560. package/scripts/sonar/sonar-new-code.ts +79 -0
  561. package/scripts/sonar/sonar-project.ts +97 -0
  562. package/scripts/split/split-assess-cli.ts +1 -1
  563. package/scripts/split/split-assess.ts +2 -5
  564. package/scripts/sync/managed-config-scope-cli.ts +1 -1
  565. package/scripts/sync/skill-migration.ts +0 -1
  566. package/scripts/sync/sync-ai-files.ts +4 -0
  567. package/scripts/sync/sync-hook-safety.ts +2 -3
  568. package/scripts/sync/sync.ts +1 -8
  569. package/scripts/sync/template-source-logic.ts +0 -1
  570. package/scripts/sync/workflow-pin-logic.ts +16 -28
  571. package/scripts/test/test-declared-changed.ts +13 -16
  572. package/scripts/test/test-declared-logic.ts +0 -1
  573. package/scripts/test/test-declared.ts +3 -9
  574. package/scripts/test/test-red-commit.ts +2 -2
  575. package/scripts/test/test-red.ts +14 -7
  576. package/scripts/test/test-type-logic.ts +1 -1
  577. package/scripts/test/unit-worker-share.ts +7 -16
  578. package/scripts/time-runtime/time-batch-guard.ts +1 -2
  579. package/scripts/time-runtime/time-bundle-call.ts +0 -1
  580. package/scripts/time-runtime/time-bundles.ts +0 -4
  581. package/scripts/time-runtime/time-density-hook.ts +0 -2
  582. package/scripts/time-runtime/time-followup-stage.ts +1 -1
  583. package/scripts/time-runtime/time-format.ts +0 -73
  584. package/scripts/time-runtime/time-round-trips.ts +0 -4
  585. package/scripts/time-runtime/time-single-check.ts +1 -1
  586. package/scripts/time-runtime/time-spans.ts +1 -1
  587. package/scripts/time-runtime/time-transcript-line.ts +1 -2
  588. package/scripts/ui/ui-routes-cli.ts +0 -5
  589. package/scripts/ui/ui-routes.ts +0 -5
  590. package/scripts/version/effective-upstream.ts +2 -2
  591. package/scripts/version/latest-corepack.ts +7 -9
  592. package/scripts/version/latest-scope-cli.ts +0 -2
  593. package/scripts/version/latest-update.ts +0 -2
  594. package/scripts/version/npm-registry.ts +2 -2
  595. package/scripts/version/publishable-range-check.ts +1 -1
  596. package/scripts/version/release-hold.ts +0 -4
  597. package/scripts/version/running-binary.ts +2 -2
  598. package/scripts/version/version-check-logic.ts +0 -2
  599. package/scripts/version/version-commands.ts +11 -1
  600. package/scripts/version/version-remote.ts +3 -3
  601. package/scripts/version/version-targets.ts +4 -4
  602. package/templates/CLAUDE.basic.md +6 -6
  603. package/templates/sonar-project.properties +28 -1
  604. package/templates/workflows/ci.yml +16 -82
  605. package/templates/workflows/dependabot-auto-merge.yml +6 -3
  606. package/templates/workflows/github-release.yml +79 -0
  607. package/tsconfig.sonar.json +4 -22
  608. package/prompts/collaboration-workflow/cross-repo-epic.md +0 -5
  609. package/prompts/collaboration-workflow/epic-audit.md +0 -5
  610. package/prompts/collaboration-workflow/epic-bundle.md +0 -5
  611. package/scripts/init/plugin-install-hint.ts +0 -47
  612. package/scripts/version/parse-json.ts +0 -13
  613. /package/scripts/{git → followup}/git-followup-stages.ts +0 -0
  614. /package/scripts/{git → gh}/git-gh-api-path.ts +0 -0
  615. /package/scripts/{git → gh}/git-gh-command.ts +0 -0
  616. /package/scripts/{git → gh}/git-gh-issue.ts +0 -0
  617. /package/scripts/{git → gh}/git-gh-pr-snapshot.ts +0 -0
  618. /package/scripts/{git → gh}/git-gh-reachability.ts +0 -0
  619. /package/scripts/{git → gh}/git-gh-repo.ts +0 -0
  620. /package/scripts/{git → gh}/git-gh-rest-state.ts +0 -0
  621. /package/scripts/{git → gh}/git-pr-checks-watch.ts +0 -0
  622. /package/scripts/{git → gh}/git-pr-error.ts +0 -0
  623. /package/scripts/{git → gh}/git-pr-messages.ts +0 -0
  624. /package/scripts/{git → gh}/github-issue-url.ts +0 -0
  625. /package/scripts/git/{stash-orphans.ts → stash/stash-orphans.ts} +0 -0
  626. /package/scripts/{git → issue}/issue-reference.ts +0 -0
  627. /package/scripts/{git → lib}/animation-helpers.ts +0 -0
  628. /package/scripts/{git → lib}/git-animation.ts +0 -0
  629. /package/scripts/{git → notify}/git-notify.ts +0 -0
  630. /package/scripts/{git → notify}/telegram-test-logic.ts +0 -0
@@ -4,11 +4,15 @@ import { josh_command } from '#scripts/josh/josh-run'
4
4
  import { lane_child_marker } from '#scripts/lane/lane-child-marker'
5
5
  import { run_cut_report } from './run-cut-report'
6
6
  import { run_entry, type EntryParts } from './run-entry'
7
+ import { run_entry_stop } from './run-entry-stop'
7
8
  import { run_halfrun_resume } from './run-halfrun-resume'
8
9
  import { run_hold_cli } from './run-hold-cli'
9
10
  import { run_next } from './run-next'
10
11
  import { run_prep } from './run-prep'
11
12
  import { run_prep_cli } from './run-prep-cli'
13
+ import { run_prrun_resume } from './run-prrun-resume'
14
+ import { run_stage, type StageCommand, type StageDecision } from './run-stage'
15
+ import { run_stage_read, type StageRead } from './run-stage-read'
12
16
  import { run_step } from './run-step'
13
17
 
14
18
  // `josh run:entry <N>` — one call for the fixed entry sequence a lane opens on (joshuafolkken/kit#2372).
@@ -27,13 +31,17 @@ const ARGV_OFFSET = 2
27
31
  const SUCCESS_EXIT_CODE = 0
28
32
  const FAILURE_EXIT_CODE = 1
29
33
  const ISSUE_NUMBER_PATTERN = /^[1-9]\d*$/u
30
- const USAGE = 'Usage: josh run:entry <issue-number>'
34
+ const USAGE = 'Usage: josh run:entry <issue-number> [--to kickoff|halfrun|prrun|fullrun]'
35
+ const TO_FLAG = '--to'
36
+ // The flag and its command.
37
+ const TO_ARGUMENT_COUNT = 2
31
38
  const should_forward_stderr = true
32
39
  const NEWLINE = '\n'
33
40
 
34
41
  const HOLD_STOP_NOTE =
35
42
  '(tree not held — see the reason above; clean up and retry, or release with `pnpm josh run:release`)'
36
43
  const COST_STOP_NOTE = '(session budget spent — see the figure above; resume in a fresh session)'
44
+ const { BUDGET_REASON, HOLD_REASON } = run_entry_stop
37
45
  const HALFRUN_RESUME_TOKEN = 'halfrun'
38
46
 
39
47
  // Exactly one issue number, or the call is refused — `run:entry` opens one run, and a second number
@@ -48,16 +56,42 @@ function parse_number(argv: ReadonlyArray<string>): string | undefined {
48
56
  return first
49
57
  }
50
58
 
59
+ interface EntryRequest {
60
+ issue_number: string
61
+ command: StageCommand
62
+ }
63
+
64
+ // `--to <command>` names how far the run goes (joshuafolkken/kit#3042); absent, it is `fullrun`.
65
+ // Anything else is refused.
66
+ function parse_command(rest: ReadonlyArray<string>): StageCommand | undefined {
67
+ if (rest.length === 0) return run_stage.DEFAULT_COMMAND
68
+
69
+ const [flag, value] = rest
70
+
71
+ if (flag !== TO_FLAG || rest.length !== TO_ARGUMENT_COUNT) return undefined
72
+
73
+ return run_stage.to_command(value)
74
+ }
75
+
76
+ function parse_request(argv: ReadonlyArray<string>): EntryRequest | undefined {
77
+ const issue_number = parse_number(argv.slice(0, 1))
78
+ const command = parse_command(argv.slice(1))
79
+
80
+ return issue_number === undefined || command === undefined ? undefined : { issue_number, command }
81
+ }
82
+
51
83
  function first_line(out: string): string {
52
84
  return out.split(NEWLINE)[0] ?? ''
53
85
  }
54
86
 
55
87
  // `run:hold <N>` prints one token — `hold`, `busy` or `unknown` — and forwards its explanation to
56
88
  // stderr, so the composite branches on the token and the reader still sees why. `--fullrun` marks the
57
- // hold as this entry's, since `run:entry` is `fullrun #N`'s alone (joshuafolkken/kit#2760).
58
- async function claim_hold(issue_number: string): Promise<string> {
89
+ // hold as a run whose implementation cut resumes as `fullrun #N` (joshuafolkken/kit#2760) — a
90
+ // `fullrun`'s, and a `prrun`'s, which runs `fullrun`'s steps; a `halfrun`'s hold is never marked.
91
+ async function claim_hold(issue_number: string, command: StageCommand): Promise<string> {
92
+ const mark = command === run_stage.HALFRUN ? [] : ['--fullrun']
59
93
  const held = await josh_command.josh_run(
60
- ['run:hold', issue_number, '--fullrun'],
94
+ ['run:hold', issue_number, ...mark],
61
95
  should_forward_stderr,
62
96
  )
63
97
 
@@ -103,6 +137,23 @@ function stop_report(issue_number: string, hold: string, cost: string, report: s
103
137
  return emit({ issue_number, hold, cost, verdict: run_entry.NO_VERDICT, report })
104
138
  }
105
139
 
140
+ // A stop this command decided carries its own chores (joshuafolkken/kit#3099): the `confirmation`
141
+ // Telegram always, and the release where this call claimed the hold — `run_entry_stop` says why.
142
+ interface StopCall {
143
+ parts: Pick<EntryParts, 'issue_number' | 'hold' | 'cost' | 'report'>
144
+ command: StageCommand
145
+ reason: string
146
+ should_release: boolean
147
+ }
148
+
149
+ async function stop_run({ parts, command, reason, should_release }: StopCall): Promise<number> {
150
+ const code = stop_report(parts.issue_number, parts.hold, parts.cost, parts.report)
151
+
152
+ await run_entry_stop.stop({ issue_number: parts.issue_number, command, reason, should_release })
153
+
154
+ return code
155
+ }
156
+
106
157
  interface Resume {
107
158
  token: string
108
159
  code: number
@@ -131,55 +182,116 @@ function resume_report(issue_number: string, resume: Resume): number {
131
182
  // **A `halfrun` stopped before its commit is resumed, not claimed** (joshuafolkken/kit#2796): its hold
132
183
  // is kept over the verified diff, so the claim below would answer `busy` against it. The budget is asked
133
184
  // first, as for any run; then the hold is adopted and the run goes to the gate, skipping everything up
134
- // to and including implementation.
135
- async function resume_halfrun(issue_number: string): Promise<number> {
185
+ // to and including implementation. **A `prrun` stopped before its merge is resumed the same way**
186
+ // (joshuafolkken/kit#3023), under the token that says what is left of it.
187
+ async function resume_stopped(
188
+ { issue_number, command }: EntryRequest,
189
+ token: string,
190
+ stopped_run: { adopt: (issue: string) => Promise<boolean> },
191
+ ): Promise<number> {
136
192
  const cost = await check_cost()
137
193
 
138
194
  if (cost === run_entry.COST_OVER) {
139
- return stop_report(issue_number, HALFRUN_RESUME_TOKEN, cost, COST_STOP_NOTE)
195
+ const parts = { issue_number, hold: token, cost, report: COST_STOP_NOTE }
196
+
197
+ return await stop_run({ parts, command, reason: BUDGET_REASON, should_release: false })
140
198
  }
141
199
 
142
- if (!(await run_halfrun_resume.adopt(issue_number))) {
143
- return stop_report(issue_number, run_hold_cli.BUSY_VERDICT, cost, HOLD_STOP_NOTE)
200
+ if (!(await stopped_run.adopt(issue_number))) {
201
+ const parts = { issue_number, hold: run_hold_cli.BUSY_VERDICT, cost, report: HOLD_STOP_NOTE }
202
+
203
+ return await stop_run({ parts, command, reason: HOLD_REASON, should_release: false })
144
204
  }
145
205
 
146
- console.info(`entry #${issue_number} — resume: ${HALFRUN_RESUME_TOKEN}`)
206
+ console.info(`entry #${issue_number} — resume: ${token}`)
147
207
 
148
208
  return SUCCESS_EXIT_CODE
149
209
  }
150
210
 
151
- async function open_run(issue_number: string): Promise<number> {
152
- const resume = await ask_resume(issue_number)
211
+ // The stopped run a decision picks up: a `halfrun` stop resumes at the gate, a `prrun` stop at
212
+ // `followup` under its own token. `undefined` for any other start, so the ordinary claim decides.
213
+ async function resume_any(
214
+ request: EntryRequest,
215
+ decision: StageDecision,
216
+ stage: StageRead,
217
+ ): Promise<number | undefined> {
218
+ if (decision.state === run_stage.HALFRUN_STOPPED) {
219
+ return await resume_stopped(request, HALFRUN_RESUME_TOKEN, run_halfrun_resume)
220
+ }
153
221
 
154
- if (resume.token !== run_cut_report.FRESH_VERDICT) return resume_report(issue_number, resume)
222
+ return stage.prrun_token === undefined
223
+ ? undefined
224
+ : await resume_stopped(request, stage.prrun_token, run_prrun_resume)
225
+ }
155
226
 
156
- if (await run_halfrun_resume.is_pending(issue_number)) return await resume_halfrun(issue_number)
227
+ // **A command whose stopping point the issue has already reached redoes nothing** (joshuafolkken/kit#3042)
228
+ // — the stage line is the whole report. A merged issue is the exception: the ordinary entry already
229
+ // answers it (`already-done`, or `keep-work` over a lane's uncommitted work), so it is left to that.
230
+ function is_settled(decision: StageDecision): boolean {
231
+ return decision.is_reached && decision.state !== run_stage.MERGED
232
+ }
157
233
 
158
- const hold = await claim_hold(issue_number)
234
+ async function claim_run({ issue_number, command }: EntryRequest): Promise<number> {
235
+ const hold = await claim_hold(issue_number, command)
159
236
 
160
237
  if (hold !== run_hold_cli.HOLD_VERDICT) {
161
- return stop_report(issue_number, hold, run_entry.COST_SKIPPED, HOLD_STOP_NOTE)
238
+ const parts = { issue_number, hold, cost: run_entry.COST_SKIPPED, report: HOLD_STOP_NOTE }
239
+
240
+ return await stop_run({ parts, command, reason: HOLD_REASON, should_release: false })
162
241
  }
163
242
 
164
243
  const cost = await check_cost()
165
244
 
166
- if (cost === run_entry.COST_OVER) return stop_report(issue_number, hold, cost, COST_STOP_NOTE)
245
+ if (cost === run_entry.COST_OVER) {
246
+ const parts = { issue_number, hold, cost, report: COST_STOP_NOTE }
247
+
248
+ return await stop_run({ parts, command, reason: BUDGET_REASON, should_release: true })
249
+ }
167
250
 
168
251
  const reads = await gather_reads(issue_number)
169
252
 
170
253
  return emit({ issue_number, hold, cost, verdict: reads.verdict, report: reads.report })
171
254
  }
172
255
 
256
+ // A carried cut is asked first, before anything is read (`run:cut --resume`); `kickoff` claims and cuts
257
+ // nothing, so it never asks. `undefined` when no cut is waiting.
258
+ async function resume_cut(request: EntryRequest): Promise<number | undefined> {
259
+ if (request.command === run_stage.KICKOFF) return undefined
260
+
261
+ const resume = await ask_resume(request.issue_number)
262
+
263
+ return resume.token === run_cut_report.FRESH_VERDICT
264
+ ? undefined
265
+ : resume_report(request.issue_number, resume)
266
+ }
267
+
268
+ // `kickoff` stops at the stage line whatever it says — it plans, and claims nothing.
269
+ async function open_run(request: EntryRequest): Promise<number> {
270
+ const { issue_number, command } = request
271
+ const cut = await resume_cut(request)
272
+
273
+ if (cut !== undefined) return cut
274
+
275
+ const stage = await run_stage_read.read_stage(issue_number)
276
+ const decision = run_stage.decide(stage.state, command)
277
+
278
+ console.info(run_stage.format_decision(issue_number, decision))
279
+
280
+ if (command === run_stage.KICKOFF || is_settled(decision)) return SUCCESS_EXIT_CODE
281
+
282
+ return (await resume_any(request, decision, stage)) ?? (await claim_run(request))
283
+ }
284
+
173
285
  async function run(argv: ReadonlyArray<string>): Promise<number> {
174
- const issue_number = parse_number(argv)
286
+ const request = parse_request(argv)
175
287
 
176
- if (issue_number === undefined) {
288
+ if (request === undefined) {
177
289
  console.error(USAGE)
178
290
 
179
291
  return FAILURE_EXIT_CODE
180
292
  }
181
293
 
182
- return await open_run(issue_number)
294
+ return await open_run(request)
183
295
  }
184
296
 
185
297
  async function main(argv: ReadonlyArray<string>): Promise<void> {
@@ -188,12 +300,8 @@ async function main(argv: ReadonlyArray<string>): Promise<void> {
188
300
 
189
301
  const run_entry_cli = {
190
302
  HALFRUN_RESUME_TOKEN,
191
- SUCCESS_EXIT_CODE,
192
- USAGE,
193
- check_cost,
194
- claim_hold,
195
- main,
196
303
  parse_number,
304
+ parse_request,
197
305
  run,
198
306
  }
199
307
 
@@ -0,0 +1,104 @@
1
+ import { josh_command } from '#scripts/josh/josh-run'
2
+ import { telegram_notify } from '#scripts/notify/telegram-notify'
3
+ import { lane_park } from '#scripts/rules/lane-park'
4
+
5
+ // What `run:entry` does on the way out of a stop it decided itself (joshuafolkken/kit#3099).
6
+ //
7
+ // **The stop's chores used to be the agent's to remember, and the `Stop` hook was what reminded it.**
8
+ // `fullrun.md` step 3 asked the agent, on an `over` budget, to send the `confirmation` Telegram and then
9
+ // run `pnpm josh run:release` — two calls after a command had already decided the run was over. Across
10
+ // eleven measured sessions the hook sent a reply back five times for exactly those two calls, each one a
11
+ // further turn re-reading the whole context. The command that decides the stop knows everything the
12
+ // chores need, so it does them, and the hook stays a safety net that a normal run never trips.
13
+ //
14
+ // **The release is the claim's own undo, and only where this call made the claim.** A resume over a
15
+ // stopped `halfrun` / `prrun` stops on the budget before adopting anything, and the hold there is the
16
+ // stopped run's — kept on purpose over its verified diff — so that stop notifies and releases nothing.
17
+ // A `busy` / `unknown` hold is another run's, or none at all, so it is never released here either.
18
+ //
19
+ // **A dispatched lane child sends no Telegram from here.** Its stop must park the Issue before it
20
+ // notifies, and `lane_park`'s guard delivers that rule at the `josh notify` call — a Telegram sent from
21
+ // inside this command would pass that guard by and satisfy the `Stop` hook with no park behind it.
22
+
23
+ interface StopNotice {
24
+ issue_number: string
25
+ command: string
26
+ reason: string
27
+ should_release: boolean
28
+ }
29
+
30
+ interface StopPorts {
31
+ notify: (input: { issue_title: string; body: string; recovery: string }) => Promise<boolean>
32
+ release: (issue_number: string) => Promise<boolean>
33
+ is_parking_child: () => boolean
34
+ }
35
+
36
+ const RECOVERY = 'If this did not arrive, the run:entry output in the session names the stop.'
37
+ const NOTIFY_FAILED_NOTE =
38
+ '(the confirmation Telegram could not be sent — send it with `pnpm josh notify --task-type confirmation` before stopping)'
39
+ const RELEASED_NOTE = '(hold released by run:entry — the tree is free for the resume)'
40
+ const RELEASE_FAILED_NOTE =
41
+ '(the hold could not be released — run `pnpm josh run:release` before stopping)'
42
+ const should_forward_stderr = true
43
+ const SUCCESS_EXIT_CODE = 0
44
+
45
+ const BUDGET_REASON = 'the session budget is spent'
46
+ const HOLD_REASON = 'the working tree is not held for this run — see the run:entry output'
47
+
48
+ async function release(issue_number: string): Promise<boolean> {
49
+ const released = await josh_command.josh_run(['run:release', issue_number], should_forward_stderr)
50
+
51
+ return released.code === SUCCESS_EXIT_CODE
52
+ }
53
+
54
+ function is_parking_child(): boolean {
55
+ return lane_park.is_parking_child()
56
+ }
57
+
58
+ const DEFAULT_PORTS: StopPorts = { notify: telegram_notify.confirm, release, is_parking_child }
59
+
60
+ function body_of(notice: StopNotice): string {
61
+ return `${notice.command} #${notice.issue_number} stopped at entry: ${notice.reason}.\nResume with \`${notice.command} #${notice.issue_number}\`.`
62
+ }
63
+
64
+ // The release runs first, so the resume the Telegram names finds the tree free when a person acts on it.
65
+ // The marker line is printed only for a Telegram that went out: the `Stop` hook reads it as the notify,
66
+ // and a failed send has to leave the hook still asking for one. The released note, likewise, is printed
67
+ // only for a release that succeeded, so a failed one leaves the agent still asked to release.
68
+ async function release_claim(notice: StopNotice, ports: StopPorts): Promise<void> {
69
+ if (!notice.should_release) return
70
+
71
+ const is_released = await ports.release(notice.issue_number)
72
+
73
+ console.info(is_released ? RELEASED_NOTE : RELEASE_FAILED_NOTE)
74
+ }
75
+
76
+ async function notify_stop(notice: StopNotice, ports: StopPorts): Promise<void> {
77
+ if (ports.is_parking_child()) return
78
+
79
+ const is_sent = await ports.notify({
80
+ issue_title: `${notice.command} #${notice.issue_number} stopped`,
81
+ body: body_of(notice),
82
+ recovery: RECOVERY,
83
+ })
84
+
85
+ console.info(is_sent ? lane_park.COMMAND_NOTIFY_MARKER : NOTIFY_FAILED_NOTE)
86
+ }
87
+
88
+ async function stop(notice: StopNotice, ports: StopPorts = DEFAULT_PORTS): Promise<void> {
89
+ await release_claim(notice, ports)
90
+ await notify_stop(notice, ports)
91
+ }
92
+
93
+ const run_entry_stop = {
94
+ BUDGET_REASON,
95
+ HOLD_REASON,
96
+ NOTIFY_FAILED_NOTE,
97
+ RELEASED_NOTE,
98
+ RELEASE_FAILED_NOTE,
99
+ body_of,
100
+ stop,
101
+ }
102
+
103
+ export { run_entry_stop }
104
+ export type { StopNotice, StopPorts }
@@ -84,7 +84,6 @@ const run_entry = {
84
84
  COST_SKIPPED,
85
85
  COST_UNDER,
86
86
  NO_VERDICT,
87
- SUMMARY_PREFIX,
88
87
  exit_code,
89
88
  format_report,
90
89
  can_proceed,
@@ -193,8 +193,6 @@ async function main(argv: ReadonlyArray<string>): Promise<void> {
193
193
  }
194
194
 
195
195
  const run_event_cli = {
196
- USAGE,
197
- main,
198
196
  run,
199
197
  watch_start,
200
198
  }
@@ -52,6 +52,7 @@ async function follow(
52
52
  let read = ports.read(position)
53
53
 
54
54
  while (read.events.length === 0 && ports.now() < deadline) {
55
+ // eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
55
56
  await ports.sleep(options.tick_ms)
56
57
  read = ports.read(position)
57
58
  }
@@ -69,7 +69,7 @@ function render(event: RunEvent, lang: string): string {
69
69
  return [clock_of(event.at), label_of(event.kind, lang), event.text].join(FIELD_SEPARATOR)
70
70
  }
71
71
 
72
- const run_event_render = { KIND_LABELS, clock_of, label_of, render }
72
+ const run_event_render = { clock_of, label_of, render }
73
73
 
74
74
  export type { KindLabel }
75
75
  export { run_event_render }
@@ -91,6 +91,22 @@ const SHIP_POSITION_KINDS: ReadonlySet<string> = new Set([
91
91
  run_event_stream.EVENT_KIND.SHIP_STOP,
92
92
  ])
93
93
 
94
+ const KIND = run_event_stream.EVENT_KIND
95
+
96
+ // The parent's record of the batch around a child — its dispatch, park and split, the retrospective
97
+ // whose summary may name an issue it filed, and the strand whose text carries the whole invocation
98
+ // (`backlogrun #<N1> #<N2> …`). Each can name the child, yet none is a position the child itself is at,
99
+ // so a lane child never reads one as its own.
100
+ const BATCH_RECORD_KINDS: ReadonlySet<string> = new Set([
101
+ KIND.CHILD_LAUNCH,
102
+ KIND.PARK,
103
+ KIND.SPLIT,
104
+ KIND.RETROSPECTIVE,
105
+ KIND.STRANDED,
106
+ ])
107
+
108
+ const ISSUE_REFERENCE = /#(\d+)/u
109
+
94
110
  function is_foreign_ship_event(event: RunEvent, issue: string): boolean {
95
111
  return SHIP_POSITION_KINDS.has(event.kind) && !event.text.startsWith(`#${issue} `)
96
112
  }
@@ -99,16 +115,49 @@ function is_own_ship_event(event: RunEvent, issue: string): boolean {
99
115
  return SHIP_POSITION_KINDS.has(event.kind) && !is_foreign_ship_event(event, issue)
100
116
  }
101
117
 
118
+ // **A lane child's position is read only from events that name its own issue** (joshuafolkken/kit#3039).
119
+ // The parent and every lane append to one stream under one carry scope, so anything else on it is another
120
+ // run's: another lane's merge told a planned child to stop, the parent's stall (which names no issue)
121
+ // pointed it at `backlog:next`, and another lane's cut at `run:cut --resume`. The child's own merge and
122
+ // outage stay, so the parent-only stop in `run-step.ts` still holds; the parent keeps reading everything.
123
+ function names_issue(event: RunEvent, issue: string): boolean {
124
+ return ISSUE_REFERENCE.exec(event.text)?.[1] === issue
125
+ }
126
+
127
+ function is_lane_position(event: RunEvent, issue: string): boolean {
128
+ return !BATCH_RECORD_KINDS.has(event.kind) && names_issue(event, issue)
129
+ }
130
+
131
+ // A lane child's attempt begins at its own newest launch. A child re-dispatched after an outage — or
132
+ // relaunched after a cut, whose resume `run:cut --resume` answers at the entry — shares the scope with
133
+ // its previous attempt, and that attempt's outage would otherwise stop the new one at its entry `run:step`.
134
+ function since_own_launch(events: ReadonlyArray<RunEvent>, issue: string): ReadonlyArray<RunEvent> {
135
+ const launch = events.findLastIndex(
136
+ (event) => event.kind === KIND.CHILD_LAUNCH && names_issue(event, issue),
137
+ )
138
+
139
+ return events.slice(launch + 1)
140
+ }
141
+
142
+ function is_foreign_event(event: RunEvent, issue: string, is_lane_child: boolean): boolean {
143
+ if (is_lane_child) return !is_lane_position(event, issue)
144
+
145
+ return is_foreign_ship_event(event, issue)
146
+ }
147
+
102
148
  // The newest position for one issue's run: the scoped last event with other issues' ship positions left
103
- // out, and — where no scope applies, as in an interactive `fullrun` with no carry record — the issue's own
104
- // newest ship position, which its issue number already scopes. A determined scope with nothing in it yet
105
- // reads nothing: an earlier invocation's stop for the same issue is not this invocation's position.
149
+ // out — and, for a lane child, every event not naming its issue — and, where no scope applies, as in
150
+ // an interactive `fullrun` with no carry record, the issue's own newest ship position, which its issue
151
+ // number already scopes. A determined scope with nothing in it yet reads nothing: an earlier invocation's
152
+ // stop for the same issue is not this invocation's position.
106
153
  function last_issue_event(
107
154
  events: ReadonlyArray<RunEvent>,
108
155
  scope: EventScope,
109
156
  issue: string,
157
+ is_lane_child: boolean,
110
158
  ): RunEvent | undefined {
111
- const own = events.filter((event) => !is_foreign_ship_event(event, issue))
159
+ const attempt = is_lane_child ? since_own_launch(events, issue) : events
160
+ const own = attempt.filter((event) => !is_foreign_event(event, issue, is_lane_child))
112
161
 
113
162
  if (scope.kind === SINCE_SCOPE) return last_scoped_event(own, scope)
114
163
 
@@ -1,3 +1,4 @@
1
+ import { error_text } from '#scripts/lib/error-message'
1
2
  import { run_carry } from './run-carry'
2
3
  import { run_event_scope } from './run-event-scope'
3
4
  import { run_event_stream, type RunEvent } from './run-event-stream'
@@ -62,8 +63,10 @@ async function emit_once(kind: string, text: string): Promise<boolean> {
62
63
  if (target === undefined || run_event_stream.read_last(target)?.kind === kind) return false
63
64
 
64
65
  return run_event_stream.append(target, kind, text, now_iso()).appended
65
- } catch {
66
+ } catch (error) {
66
67
  // Best-effort: a failed append is dropped rather than raised into the loop's work.
68
+ error_text.trace_swallowed('run_event_stream_emit.emit_once', error)
69
+
67
70
  return false
68
71
  }
69
72
  }
@@ -98,8 +101,10 @@ async function emit_once_since(kind: string, text: string, reset_kind: string):
98
101
  }
99
102
 
100
103
  return run_event_stream.append(target, kind, text, now_iso()).appended
101
- } catch {
104
+ } catch (error) {
102
105
  // Best-effort: a failed append is dropped rather than raised into the caller's work.
106
+ error_text.trace_swallowed('run_event_stream_emit.emit_once_since', error)
107
+
103
108
  return false
104
109
  }
105
110
  }
@@ -238,13 +238,10 @@ const run_event_stream = {
238
238
  EVENT_CAP,
239
239
  EVENT_KIND,
240
240
  EVENT_KINDS,
241
- EVENT_PREFIX,
242
- EVENT_SUFFIX,
243
241
  TRACE_KINDS,
244
242
  append,
245
243
  format_event,
246
244
  has_since,
247
- is_event_kind,
248
245
  read_events,
249
246
  read_from,
250
247
  read_last,
@@ -22,6 +22,7 @@ async function watch(ports: WatchPorts, position: number): Promise<number> {
22
22
  let next = position
23
23
 
24
24
  while (ports.should_continue()) {
25
+ // eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
25
26
  const read = await ports.pass(next)
26
27
 
27
28
  for (const event of read.events) ports.write(ports.render(event))
@@ -1,4 +1,4 @@
1
- import { run_hold, type HoldRead, type RunHold } from './run-hold'
1
+ import { run_hold, type HoldRead, type RunHold, type StopMarkFields } from './run-hold'
2
2
 
3
3
  // joshuafolkken/kit#2796: a `halfrun` stops before its commit and **keeps** its hold, because the
4
4
  // uncommitted, hand-verified work is exactly what a second run would trample. The person then types
@@ -38,7 +38,13 @@ function is_own_record(read: HoldRead, issue: string): boolean {
38
38
  return hold === undefined || hold.issue === issue || hold.issue === run_hold.UNNUMBERED_ISSUE
39
39
  }
40
40
 
41
- function mark_stop_at(target: string, issue: string): StopMark {
41
+ // `mark` is the `halfrun` stop's by default; a `prrun` stop passes its own (joshuafolkken/kit#3023), so
42
+ // the own-record check is one check whichever run is stopping.
43
+ function mark_stop_at(
44
+ target: string,
45
+ issue: string,
46
+ mark: StopMarkFields = run_hold.HALFRUN_STOP_FIELDS,
47
+ ): StopMark {
42
48
  const read = run_hold.read_hold(target)
43
49
 
44
50
  if (read.kind === 'unreadable') return UNREADABLE
@@ -47,7 +53,14 @@ function mark_stop_at(target: string, issue: string): StopMark {
47
53
 
48
54
  run_hold.release_hold(target)
49
55
 
50
- return run_hold.create_halfrun_stop_hold(target, issue) ? MARKED : FOREIGN
56
+ return run_hold.create_stop_hold(target, issue, mark) ? MARKED : FOREIGN
57
+ }
58
+
59
+ // The stopped run's record is replaced by this `fullrun`'s, shared with the `prrun` resume.
60
+ function take_over(target: string, issue: string): boolean {
61
+ run_hold.release_hold(target)
62
+
63
+ return run_hold.create_hold(target, issue, new Date(), true)
51
64
  }
52
65
 
53
66
  // `false` leaves the record untouched, so the ordinary claim that follows decides the tree exactly as
@@ -55,9 +68,7 @@ function mark_stop_at(target: string, issue: string): StopMark {
55
68
  function adopt_at(target: string, issue: string, is_dirty: boolean): boolean {
56
69
  if (!is_halfrun_stop(run_hold.read_hold(target), issue, is_dirty)) return false
57
70
 
58
- run_hold.release_hold(target)
59
-
60
- return run_hold.create_hold(target, issue, new Date(), true)
71
+ return take_over(target, issue)
61
72
  }
62
73
 
63
74
  // **An unreadable git directory is no resume**, never a crash: `run:entry` must still print its one
@@ -95,9 +106,11 @@ const run_halfrun_resume = {
95
106
  UNREADABLE,
96
107
  adopt,
97
108
  adopt_at,
98
- is_halfrun_stop,
109
+ hold_of,
110
+ hold_target,
99
111
  is_pending,
100
112
  mark_stop_at,
113
+ take_over,
101
114
  }
102
115
 
103
116
  export type { StopMark }
@@ -1,7 +1,7 @@
1
1
  import { lane_child_marker } from '#scripts/lane/lane-child-marker'
2
2
  import { lane_reap } from '#scripts/lane/lane-reap'
3
+ import { lane_registry } from '#scripts/lane/lane-registry'
3
4
  import { run_carry, type CarryRead, type RunCarry } from './run-carry'
4
- import { run_watcher_guard } from './run-watcher-guard'
5
5
 
6
6
  // The headless `backlogrun` parent (joshuafolkken/kit#2437). `run:wake` starts a cut's successor as
7
7
  // `claude -p`, and there a turn that ends is the process that ends: its background `lane:await` and
@@ -51,7 +51,7 @@ async function read_carry_here(): Promise<CarryRead | undefined> {
51
51
  async function must_keep_waiting(source: EnvironmentSource = process.env): Promise<boolean> {
52
52
  const is_candidate = is_headless(source) && lane_child_marker.marked_issue(source) === undefined
53
53
 
54
- if (!is_candidate || !(await run_watcher_guard.has_lanes_in_flight())) return false
54
+ if (!is_candidate || !(await lane_registry.has_lanes_in_flight())) return false
55
55
 
56
56
  return is_driving(await read_carry_here())
57
57
  }