@joshuafolkken/kit 1.1035.0 → 1.1094.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 (605) hide show
  1. package/.claude/settings.json +9 -8
  2. package/.claude/skills/epic-commands/SKILL.md +5 -7
  3. package/.claude/skills/verify-ui/SKILL.md +1 -1
  4. package/.claude/skills/workflow-commands/SKILL.md +21 -13
  5. package/.claude/skills/workflow-commands/background-commands.md +5 -4
  6. package/.claude/skills/workflow-commands/backlogrun-child.md +3 -3
  7. package/.claude/skills/workflow-commands/backlogrun-lanes.md +9 -7
  8. package/.claude/skills/workflow-commands/backlogrun-park.md +6 -0
  9. package/.claude/skills/workflow-commands/backlogrun-progress.md +31 -37
  10. package/.claude/skills/workflow-commands/backlogrun-steps.md +25 -25
  11. package/.claude/skills/workflow-commands/backlogrun.md +2 -2
  12. package/.claude/skills/workflow-commands/chain-rule.md +6 -4
  13. package/.claude/skills/workflow-commands/delegation.md +3 -3
  14. package/.claude/skills/workflow-commands/followup-reference.md +3 -3
  15. package/.claude/skills/workflow-commands/followup.md +7 -3
  16. package/.claude/skills/workflow-commands/fullrun-steps.md +3 -2
  17. package/.claude/skills/workflow-commands/fullrun.md +3 -2
  18. package/.claude/skills/workflow-commands/halfrun.md +16 -19
  19. package/.claude/skills/workflow-commands/issue-comments.md +2 -2
  20. package/.claude/skills/workflow-commands/issue-fold-existing.md +10 -10
  21. package/.claude/skills/workflow-commands/issue-scout.md +1 -1
  22. package/.claude/skills/workflow-commands/kickoff.md +9 -4
  23. package/.claude/skills/workflow-commands/latest-gate.md +1 -1
  24. package/.claude/skills/workflow-commands/needs-human-review.md +1 -1
  25. package/.claude/skills/workflow-commands/observation-filing.md +44 -89
  26. package/.claude/skills/workflow-commands/pre-gate-cut.md +33 -36
  27. package/.claude/skills/workflow-commands/prerequisite.md +1 -1
  28. package/.claude/skills/workflow-commands/prrun.md +36 -0
  29. package/.claude/skills/workflow-commands/retrospective.md +1 -1
  30. package/.claude/skills/workflow-commands/working-tree-hold.md +24 -4
  31. package/.codex/hooks.json +16 -20
  32. package/.github/actions/setup-pnpm/action.yml +93 -0
  33. package/.github/dependabot.yml +5 -1
  34. package/.github/workflows/auto-tag.yml +21 -0
  35. package/.github/workflows/ci.yml +26 -128
  36. package/.github/workflows/pr-classification.yml +5 -41
  37. package/.github/workflows/publish.yml +42 -48
  38. package/.github/workflows/sonar-qube.yml +37 -4
  39. package/AGENTS.md +12 -2
  40. package/CLAUDE.md +15 -16
  41. package/GEMINI.md +14 -2
  42. package/README.md +59 -18
  43. package/SECURITY.md +36 -6
  44. package/cspell/index.yaml +2 -1
  45. package/dist/CLAUDE.md +15 -16
  46. package/dist/config-merge/index.js +15 -3
  47. package/dist/hooks/batch-guard.js +4 -4
  48. package/dist/hooks/{chunk-Y27M6A7X.js → chunk-3C4YCCEF.js} +5 -13
  49. package/dist/hooks/{chunk-D67KVGGY.js → chunk-7ZPFAVR7.js} +17 -88
  50. package/dist/hooks/{chunk-HOYJU5RM.js → chunk-E54KGFEQ.js} +11 -4
  51. package/dist/hooks/{chunk-KG6PZD72.js → chunk-IL27YTPH.js} +2 -2
  52. package/dist/hooks/{chunk-GJT4BNVE.js → chunk-KHWHKJOM.js} +3 -3
  53. package/dist/hooks/{chunk-HU66PWWL.js → chunk-M2XDCUKD.js} +1076 -509
  54. package/dist/hooks/{chunk-GLBDBJOK.js → chunk-NKOG3XAV.js} +199 -304
  55. package/dist/hooks/{chunk-ZXNE6NY3.js → chunk-O4LL4HTI.js} +2 -7
  56. package/dist/hooks/{chunk-XPLP27WA.js → chunk-OIZUHPJI.js} +5 -27
  57. package/dist/hooks/{chunk-EIFCAJRB.js → chunk-UD24EAIL.js} +2546 -1636
  58. package/dist/hooks/codex-hook-adapter.js +10 -11
  59. package/dist/hooks/duplicate-read-guard.js +5 -5
  60. package/dist/hooks/format-edited.js +15 -34
  61. package/dist/hooks/inputs.json +279 -0
  62. package/dist/hooks/investigation-guard.js +5 -5
  63. package/dist/hooks/pretool-guard.js +23 -16
  64. package/dist/hooks/session-lang.js +0 -1
  65. package/dist/hooks/stop-guard.js +188 -509
  66. package/dist/josh.js +166 -225
  67. package/dist/managed-marker/index.js +2 -1
  68. package/dist/version/index.js +412 -64
  69. package/eslint/rules/promise.js +5 -0
  70. package/package.json +13 -8
  71. package/prompts/collaboration-workflow/file-edits.md +6 -53
  72. package/prompts/collaboration-workflow/issue-citation.md +5 -5
  73. package/prompts/collaboration-workflow/operating-rules.md +4 -4
  74. package/prompts/collaboration-workflow/overview.md +13 -1
  75. package/prompts/collaboration-workflow/report-format.md +1 -1
  76. package/prompts/collaboration-workflow/residency.md +4 -4
  77. package/prompts/collaboration-workflow/rule-delivery.md +5 -36
  78. package/prompts/collaboration-workflow/shell-body.md +7 -9
  79. package/prompts/collaboration-workflow/turn-batching.md +21 -37
  80. package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
  81. package/prompts/collaboration-workflow/wip-cap.md +36 -36
  82. package/prompts/collaboration-workflow.md +5 -8
  83. package/prompts/review-rubric.md +1 -1
  84. package/prompts/review.md +3 -3
  85. package/prompts/sonar-hotspot-handling.md +12 -4
  86. package/prompts/testing-guide.md +3 -3
  87. package/scripts/adopt/adopt-toolkits.ts +2 -2
  88. package/scripts/adopt/adopt.ts +0 -2
  89. package/scripts/agent/agent-argv.ts +0 -2
  90. package/scripts/agent/agent-diagnostics.ts +1 -1
  91. package/scripts/agent/agent-role-profile.ts +0 -7
  92. package/scripts/agent/claude-agent-argv.ts +0 -2
  93. package/scripts/agent/codex-agent-argv.ts +1 -1
  94. package/scripts/agent/codex-hooks.ts +92 -0
  95. package/scripts/agent/interactive-ask.ts +1 -1
  96. package/scripts/auto-ok/auto-ok-cli.ts +15 -25
  97. package/scripts/backlog/backlog-budget.ts +0 -2
  98. package/scripts/backlog/backlog-defect-priority.ts +2 -2
  99. package/scripts/backlog/backlog-drive-cli.ts +10 -8
  100. package/scripts/backlog/backlog-drive-named-offer.ts +16 -3
  101. package/scripts/backlog/backlog-drive-named.ts +2 -1
  102. package/scripts/backlog/backlog-drive.ts +76 -16
  103. package/scripts/backlog/backlog-named.ts +0 -3
  104. package/scripts/backlog/backlog-next.ts +32 -22
  105. package/scripts/backlog/backlog-offer-cli.ts +0 -5
  106. package/scripts/backlog/backlog-plan-cli.ts +6 -8
  107. package/scripts/backlog/backlog-plan.ts +1 -1
  108. package/scripts/backlog/backlog-pool.ts +34 -17
  109. package/scripts/backlog/backlog-rank.ts +106 -0
  110. package/scripts/backlog/backlog-ready.ts +19 -3
  111. package/scripts/backlog/backlog-scope.ts +1 -3
  112. package/scripts/backlog/backlog-stalled-detect.ts +2 -2
  113. package/scripts/backlog/backlog-stalled.ts +0 -1
  114. package/scripts/backlog/backlog-waves.ts +47 -31
  115. package/scripts/behavior/behavior-cli.ts +1 -1
  116. package/scripts/build/build-codex-hooks.ts +26 -0
  117. package/scripts/build/build-hooks.ts +92 -11
  118. package/scripts/build/hook-bundle-stamp.ts +111 -0
  119. package/scripts/cases/cases-cli.ts +1 -1
  120. package/scripts/cases/cases-logic.ts +1 -1
  121. package/scripts/ci/composite-actions.ts +30 -0
  122. package/scripts/ci/pr-classification.ts +3 -3
  123. package/scripts/claude/workflow-destination.ts +10 -1
  124. package/scripts/clone/clone-fingerprint.ts +0 -1
  125. package/scripts/clone/clone-scan-cli.ts +1 -1
  126. package/scripts/clone/clone-scan.ts +1 -1
  127. package/scripts/config-merge/json-format.ts +0 -1
  128. package/scripts/config-merge/patch-yaml-list.ts +1 -1
  129. package/scripts/cost-runtime/codex-usage.ts +2 -9
  130. package/scripts/cost-runtime/cost-attribute.ts +0 -1
  131. package/scripts/cost-runtime/cost-cli.ts +0 -3
  132. package/scripts/cost-runtime/cost-corpus.ts +0 -2
  133. package/scripts/cost-runtime/cost-format.ts +0 -3
  134. package/scripts/cost-runtime/cost-pricing.ts +0 -1
  135. package/scripts/cost-runtime/cost-tokens.ts +0 -1
  136. package/scripts/delegation/delegation-cli.ts +1 -1
  137. package/scripts/delegation/delegation-policy.ts +11 -1
  138. package/scripts/delegation/duplicate-read-guard.ts +0 -8
  139. package/scripts/delegation/fanout-cli.ts +1 -1
  140. package/scripts/delegation/fanout.ts +0 -2
  141. package/scripts/delegation/investigation-reads.ts +1 -164
  142. package/scripts/discovery/repo-map-logic.ts +0 -1
  143. package/scripts/discovery/repo-party-cli.ts +1 -1
  144. package/scripts/doctor/doctor-consumer.ts +4 -6
  145. package/scripts/doctor/doctor-logic.ts +0 -4
  146. package/scripts/doctor/doctor.ts +14 -9
  147. package/scripts/document/document-byte-budget.ts +8 -9
  148. package/scripts/document/document-byte-check.ts +0 -1
  149. package/scripts/document/document-read-cli.ts +0 -2
  150. package/scripts/document/document-section-cli.ts +1 -1
  151. package/scripts/document/document-section.ts +0 -3
  152. package/scripts/document/edit-files-cli.ts +0 -1
  153. package/scripts/document/entry-read-budget.ts +13 -4
  154. package/scripts/document/lane-child-read-set.ts +1 -6
  155. package/scripts/document/read-files-cli.ts +0 -4
  156. package/scripts/document/read-set-cli.ts +0 -2
  157. package/scripts/document/read-set-point-of-use.ts +1 -0
  158. package/scripts/document/read-set-pricing.ts +0 -1
  159. package/scripts/document/read-set-trim.ts +1 -1
  160. package/scripts/epic/epic-add.ts +1 -1
  161. package/scripts/epic/epic-audit-cli.ts +1 -4
  162. package/scripts/epic/epic-audit-orphans.ts +1 -3
  163. package/scripts/epic/epic-audit-rationale.ts +0 -1
  164. package/scripts/epic/epic-audit-report.ts +0 -2
  165. package/scripts/epic/epic-audit.ts +5 -4
  166. package/scripts/epic/epic-bundle-cli.ts +1 -1
  167. package/scripts/epic/epic-bundle-evidence.ts +0 -1
  168. package/scripts/epic/epic-bundle-referenced.ts +1 -5
  169. package/scripts/epic/epic-bundle.ts +0 -4
  170. package/scripts/epic/epic-busy.ts +4 -5
  171. package/scripts/epic/epic-candidate-confirm.ts +0 -5
  172. package/scripts/epic/epic-classify.ts +2 -2
  173. package/scripts/epic/epic-cli-argv.ts +0 -1
  174. package/scripts/epic/epic-close-comment.ts +1 -1
  175. package/scripts/epic/epic-close.ts +5 -2
  176. package/scripts/epic/epic-cross-repo.ts +2 -4
  177. package/scripts/epic/epic-decision.ts +0 -1
  178. package/scripts/epic/epic-fetch.ts +2 -2
  179. package/scripts/epic/epic-index.ts +2 -3
  180. package/scripts/epic/epic-issue.ts +1 -15
  181. package/scripts/epic/epic-lane-offer.ts +20 -30
  182. package/scripts/epic/epic-nested.ts +1 -1
  183. package/scripts/epic/epic-next-read.ts +1 -3
  184. package/scripts/epic/epic-next-views.ts +0 -1
  185. package/scripts/epic/epic-next.ts +1 -10
  186. package/scripts/epic/epic-parse.ts +0 -1
  187. package/scripts/epic/epic-promote.ts +0 -9
  188. package/scripts/epic/epic-rank.ts +37 -0
  189. package/scripts/epic/epic-read.ts +1 -2
  190. package/scripts/epic/epic-reconcile.ts +1 -1
  191. package/scripts/epic/epic-reference.ts +1 -13
  192. package/scripts/epic/epic-relation-recheck.ts +1 -1
  193. package/scripts/epic/epic-relations.ts +1 -1
  194. package/scripts/epic/epic-remove.ts +1 -1
  195. package/scripts/epic/epic-report.ts +0 -1
  196. package/scripts/epic/epic-run.ts +2 -3
  197. package/scripts/epic/epic-shape.ts +1 -1
  198. package/scripts/epic/epic-solo-stale.ts +107 -0
  199. package/scripts/epic/epic-solo.ts +32 -30
  200. package/scripts/epic/epic-triage.ts +1 -1
  201. package/scripts/epic/epic-validate.ts +1 -1
  202. package/scripts/epic/epic.ts +1 -1
  203. package/scripts/exports/unused-members-cli.ts +53 -0
  204. package/scripts/{git → followup}/followup-issue-number.ts +1 -6
  205. package/scripts/{git → followup}/git-followup-cleanup.ts +2 -1
  206. package/scripts/{git → followup}/git-followup-finish.ts +1 -3
  207. package/scripts/{git → followup}/git-followup-flush.ts +2 -2
  208. package/scripts/{git → followup}/git-followup-issue-close.ts +2 -2
  209. package/scripts/{git → followup}/git-followup-label.ts +4 -4
  210. package/scripts/followup/git-followup-merged.ts +112 -0
  211. package/scripts/{git → followup}/git-followup-pending.ts +1 -1
  212. package/scripts/{git → followup}/git-followup-workflow.ts +19 -11
  213. package/scripts/{git → followup}/git-pr-followup-wrapup.ts +9 -3
  214. package/scripts/{git → followup}/git-pr-followup.ts +53 -16
  215. package/scripts/gate/core-budget.ts +3 -9
  216. package/scripts/gate/gate-plan.ts +7 -4
  217. package/scripts/gate/gate-report.ts +0 -6
  218. package/scripts/gate/gate-tree.ts +1 -1
  219. package/scripts/gate/pre-commit-type-check.ts +0 -6
  220. package/scripts/gate/project-checks.ts +7 -8
  221. package/scripts/gate/scoped-green.ts +0 -1
  222. package/scripts/gate/type-check-step.ts +1 -1
  223. package/scripts/gate/verification-gate.ts +0 -2
  224. package/scripts/gh/fix-gh-packages.ts +15 -12
  225. package/scripts/gh/gh-spawn.ts +2 -2
  226. package/scripts/{git → gh}/git-ai-review-scan.ts +1 -5
  227. package/scripts/{git → gh}/git-gh-check.ts +2 -1
  228. package/scripts/{git → gh}/git-gh-exec.ts +1 -1
  229. package/scripts/{git → gh}/git-gh-failure.ts +1 -1
  230. package/scripts/{git → gh}/git-gh-helpers.ts +0 -1
  231. package/scripts/{git → gh}/git-gh-issue-list.ts +2 -0
  232. package/scripts/{git → gh}/git-gh-issue-read.ts +1 -1
  233. package/scripts/{git → gh}/git-gh-issue-rest.ts +6 -3
  234. package/scripts/{git → gh}/git-gh-pr-read.ts +24 -0
  235. package/scripts/{git → gh}/git-gh-pr-rest.ts +5 -2
  236. package/scripts/{git → gh}/git-gh-pr-review.ts +2 -2
  237. package/scripts/{git → gh}/git-gh-pr-rollup.ts +1 -3
  238. package/scripts/{git → gh}/git-gh-pr.ts +3 -1
  239. package/scripts/{git → gh}/git-pr-ai-review.ts +2 -5
  240. package/scripts/{git → gh}/git-pr-checks-eval.ts +0 -10
  241. package/scripts/{git → gh}/git-pr-checks-parse.ts +4 -20
  242. package/scripts/{git → gh}/git-pr-checks.ts +2 -1
  243. package/scripts/{git → gh}/git-pr-coderabbit.ts +2 -5
  244. package/scripts/{git → gh}/git-pr-confirmation.ts +1 -3
  245. package/scripts/{git → gh}/git-pr-managed-config.ts +2 -3
  246. package/scripts/{git → gh}/git-pr.ts +3 -3
  247. package/scripts/git/changed-file-scope.ts +0 -1
  248. package/scripts/git/git-branch.ts +3 -6
  249. package/scripts/git/git-command.ts +1 -1
  250. package/scripts/git/git-commit.ts +1 -1
  251. package/scripts/git/git-common-directory.ts +80 -24
  252. package/scripts/git/git-error.ts +66 -9
  253. package/scripts/git/git-execa-error.ts +6 -1
  254. package/scripts/git/git-issue.ts +1 -1
  255. package/scripts/git/git-preflight.ts +24 -6
  256. package/scripts/git/git-prompt.ts +6 -31
  257. package/scripts/git/git-push-transport.ts +12 -69
  258. package/scripts/git/git-push.ts +1 -1
  259. package/scripts/git/git-spawn.ts +79 -3
  260. package/scripts/git/git-ssh-keepalive.ts +74 -0
  261. package/scripts/git/git-staging.ts +1 -0
  262. package/scripts/git/git-status.ts +1 -1
  263. package/scripts/git/git-workflow.ts +1 -1
  264. package/scripts/git/gone-branch.ts +4 -2
  265. package/scripts/git/listing-cutoff.ts +1 -1
  266. package/scripts/git/main-merge.ts +1 -1
  267. package/scripts/git/main-sync.ts +19 -1
  268. package/scripts/git/parse-json-array.ts +0 -3
  269. package/scripts/git/repository-lock.ts +16 -16
  270. package/scripts/git/{git-stash.ts → stash/git-stash.ts} +1 -1
  271. package/scripts/git/{stash-pop-args.ts → stash/stash-pop-args.ts} +1 -1
  272. package/scripts/git/{stash-pop-cli.ts → stash/stash-pop-cli.ts} +0 -1
  273. package/scripts/git/{stash-sweep-lock.ts → stash/stash-sweep-lock.ts} +3 -3
  274. package/scripts/hooks/codex-hook-adapter.ts +0 -1
  275. package/scripts/hooks/edited-cspell.ts +1 -1
  276. package/scripts/hooks/format-edited-cli.ts +15 -0
  277. package/scripts/hooks/format-edited-file.ts +4 -9
  278. package/scripts/hooks/pre-push-unit.ts +0 -4
  279. package/scripts/hooks/pretool-guard-cli.ts +21 -0
  280. package/scripts/hooks/pretool-guard.ts +36 -19
  281. package/scripts/hooks/reserved-run.ts +1 -1
  282. package/scripts/hooks/step-zero-notice.ts +76 -0
  283. package/scripts/hooks/stop-guard.ts +47 -21
  284. package/scripts/init/claude-plugin-config.ts +4 -5
  285. package/scripts/init/hook-command-rewrite.ts +16 -8
  286. package/scripts/init/hook-launch.ts +41 -15
  287. package/scripts/init/init-basic.ts +2 -5
  288. package/scripts/init/init-logic.ts +7 -0
  289. package/scripts/init/init.ts +0 -3
  290. package/scripts/init/project-profile.ts +6 -11
  291. package/scripts/init/start-exec.ts +8 -2
  292. package/scripts/init/start-plan.ts +18 -5
  293. package/scripts/init/start-setup-pr.ts +52 -25
  294. package/scripts/init/start-steps.ts +42 -9
  295. package/scripts/init/start.ts +40 -10
  296. package/scripts/issue/behavior-change-lint.ts +0 -1
  297. package/scripts/issue/defect-rate-cli.ts +3 -3
  298. package/scripts/issue/defect-rate.ts +1 -2
  299. package/scripts/{git → issue}/git-next-issues.ts +37 -8
  300. package/scripts/issue/issue-backlinks-cli.ts +1 -5
  301. package/scripts/issue/issue-cite-cli.ts +2 -6
  302. package/scripts/issue/issue-cite.ts +19 -3
  303. package/scripts/issue/issue-classification.ts +1 -9
  304. package/scripts/issue/issue-closing-pr.ts +4 -4
  305. package/scripts/issue/issue-comment-cli.ts +2 -2
  306. package/scripts/issue/issue-file-cli.ts +5 -5
  307. package/scripts/issue/issue-file.ts +2 -2
  308. package/scripts/issue/issue-fold-cli.ts +1 -1
  309. package/scripts/issue/issue-fold-existing-cli.ts +1 -1
  310. package/scripts/{git → issue}/issue-labels.ts +20 -0
  311. package/scripts/issue/issue-lint-cli.ts +1 -1
  312. package/scripts/issue/issue-merged.ts +2 -2
  313. package/scripts/issue/issue-rank.ts +89 -0
  314. package/scripts/issue/issue-read-cli.ts +8 -47
  315. package/scripts/issue/issue-read.ts +0 -2
  316. package/scripts/issue/issue-report-failures.ts +80 -0
  317. package/scripts/issue/issue-scout-cli.ts +1 -7
  318. package/scripts/issue/issue-scout-closed.ts +2 -2
  319. package/scripts/issue/issue-scout.ts +0 -2
  320. package/scripts/issue/issue-state-cli.ts +5 -46
  321. package/scripts/issue/issue-state.ts +1 -5
  322. package/scripts/issue/markdown-section.ts +1 -1
  323. package/scripts/issue/measure-rerun-cli.ts +1 -1
  324. package/scripts/issue/reproduction-measure.ts +1 -1
  325. package/scripts/josh/cli-body.ts +1 -1
  326. package/scripts/josh/file-map-stamp.ts +0 -3
  327. package/scripts/josh/josh-command-map.ts +2 -102
  328. package/scripts/josh/josh-commands-ai.ts +9 -102
  329. package/scripts/josh/josh-commands-backlog.ts +5 -1
  330. package/scripts/josh/josh-commands-development.ts +10 -3
  331. package/scripts/josh/josh-commands-issue.ts +2 -2
  332. package/scripts/josh/josh-commands-maintenance.ts +7 -0
  333. package/scripts/josh/josh-commands-project.ts +7 -1
  334. package/scripts/josh/josh-commands-run.ts +114 -0
  335. package/scripts/josh/josh-commands-versioning.ts +8 -0
  336. package/scripts/josh/josh-commands-workflow.ts +2 -2
  337. package/scripts/josh/path-decision.ts +0 -3
  338. package/scripts/josh/process-owner.ts +16 -0
  339. package/scripts/josh/session-language-cli.ts +0 -1
  340. package/scripts/lane/lane-await.ts +3 -6
  341. package/scripts/lane/lane-capacity.ts +6 -3
  342. package/scripts/lane/lane-child-invocation.ts +20 -7
  343. package/scripts/lane/lane-child-marker.ts +16 -2
  344. package/scripts/lane/lane-cli.ts +33 -18
  345. package/scripts/lane/lane-close.ts +1 -3
  346. package/scripts/lane/lane-dispatch.ts +3 -4
  347. package/scripts/lane/lane-environment.ts +0 -9
  348. package/scripts/lane/lane-handoff.ts +38 -0
  349. package/scripts/lane/lane-launch-cli.ts +21 -11
  350. package/scripts/lane/lane-open.ts +0 -3
  351. package/scripts/lane/lane-output.ts +0 -1
  352. package/scripts/lane/lane-registry.ts +9 -0
  353. package/scripts/lane/lane-report.ts +10 -4
  354. package/scripts/lane/openai-lane-ship.ts +2 -0
  355. package/scripts/lane/openai-lane-supervisor-decision.ts +2 -1
  356. package/scripts/lane/openai-lane-supervisor.ts +6 -4
  357. package/scripts/lane/openai-review-broker.ts +3 -0
  358. package/scripts/lib/bounded-pool.ts +1 -0
  359. package/scripts/lib/json-value.ts +5 -4
  360. package/scripts/lib/poll.ts +3 -1
  361. package/scripts/lib/timed-fetch.ts +15 -0
  362. package/scripts/lib/timeouts.ts +13 -0
  363. package/scripts/{yaml → lib}/yaml-document.ts +3 -1
  364. package/scripts/{bytes → lines}/bytes-command.ts +0 -2
  365. package/scripts/lines/lines-command.ts +0 -1
  366. package/scripts/lint/lint-related-scope.ts +0 -1
  367. package/scripts/lint/lint-related.ts +1 -1
  368. package/scripts/{git → notify}/telegram-notify.ts +2 -2
  369. package/scripts/{git → notify}/telegram-test.ts +4 -4
  370. package/scripts/observations/observation-ledger-home.ts +0 -1
  371. package/scripts/observations/observation-ledger-line.ts +0 -1
  372. package/scripts/observations/observation-ledger-migrate.ts +1 -1
  373. package/scripts/observations/observations-flush-landing.ts +3 -3
  374. package/scripts/observations/observations-flush.ts +2 -2
  375. package/scripts/overrides/lockfile-overrides.ts +1 -1
  376. package/scripts/overrides/overrides-logic.ts +1 -1
  377. package/scripts/package/package-scout-cli.ts +2 -7
  378. package/scripts/package/package-scout.ts +0 -2
  379. package/scripts/propagate/propagate-git-failure.ts +0 -1
  380. package/scripts/propagate/propagate-git.ts +0 -2
  381. package/scripts/propagate/propagate-plan.ts +185 -0
  382. package/scripts/propagate/propagate-publish.ts +2 -3
  383. package/scripts/propagate/propagate-run.ts +5 -3
  384. package/scripts/propagate/propagate-steps.ts +19 -6
  385. package/scripts/propagate/propagate-targets.ts +13 -6
  386. package/scripts/propagate/propagate.ts +60 -46
  387. package/scripts/refactor/import-graph.ts +0 -1
  388. package/scripts/refactor/refactor-lint.ts +0 -2
  389. package/scripts/refactor/refactor-scan.ts +0 -1
  390. package/scripts/refactor/refactor-targets.ts +0 -1
  391. package/scripts/registry-migration/migrate-logic.ts +1 -2
  392. package/scripts/registry-migration/migrate.ts +19 -9
  393. package/scripts/release/github-release-cli.ts +8 -6
  394. package/scripts/release/github-release-environment.ts +46 -0
  395. package/scripts/release/github-release.ts +151 -94
  396. package/scripts/release/release-history.ts +0 -1
  397. package/scripts/release/release-plan.ts +0 -1
  398. package/scripts/release/release-publish.ts +2 -3
  399. package/scripts/release/release-scope-cli.ts +1 -2
  400. package/scripts/release/release-tag.ts +2 -4
  401. package/scripts/repo/auto-merge-setting-logic.ts +1 -4
  402. package/scripts/repo/repo-setting.ts +1 -1
  403. package/scripts/repo/repository-labels.ts +3 -3
  404. package/scripts/repo/required-checks-logic.ts +206 -0
  405. package/scripts/repo/required-checks-report.ts +71 -0
  406. package/scripts/repo/ruleset-check-cli.ts +53 -0
  407. package/scripts/repo/ruleset-check.ts +147 -0
  408. package/scripts/report/report-lint-cli.ts +0 -4
  409. package/scripts/review/disposition-cli.ts +1 -1
  410. package/scripts/review/live-evidence.ts +1 -1
  411. package/scripts/review/review-attest-cli.ts +0 -6
  412. package/scripts/review/review-attest.ts +48 -16
  413. package/scripts/review/review-brief-cli.ts +72 -8
  414. package/scripts/review/review-brief.ts +67 -9
  415. package/scripts/review/review-diff-parts.ts +89 -0
  416. package/scripts/review/review-diff-write.ts +97 -0
  417. package/scripts/review/review-finding-ledger.ts +0 -1
  418. package/scripts/review/review-record-cli.ts +1 -1
  419. package/scripts/review/review-record.ts +0 -1
  420. package/scripts/review/review-round2-cli.ts +1 -1
  421. package/scripts/review/review-stamps.ts +6 -2
  422. package/scripts/review/review-tree.ts +14 -2
  423. package/scripts/rules/decision-oracle-stage.ts +18 -0
  424. package/scripts/rules/decision-oracle.ts +10 -7
  425. package/scripts/rules/delivered-rules.ts +9 -1
  426. package/scripts/rules/destructive-command.ts +119 -0
  427. package/scripts/rules/direct-filing.ts +1 -1
  428. package/scripts/rules/file-body.ts +0 -3
  429. package/scripts/rules/filing-cap.ts +0 -2
  430. package/scripts/rules/gh-api.ts +7 -2
  431. package/scripts/rules/git-argv.ts +18 -7
  432. package/scripts/rules/git-force.ts +0 -2
  433. package/scripts/rules/implementation-cut.ts +1 -2
  434. package/scripts/rules/index-guard.ts +71 -0
  435. package/scripts/rules/issue-citation.ts +50 -25
  436. package/scripts/rules/issue-fold.ts +1 -2
  437. package/scripts/rules/lane-background.ts +15 -7
  438. package/scripts/rules/lane-carry-conflict.ts +1 -2
  439. package/scripts/rules/lane-park.ts +14 -8
  440. package/scripts/rules/last-prompt.ts +1 -0
  441. package/scripts/rules/oracle-consulted.ts +1 -1
  442. package/scripts/rules/oracle-firing.ts +1 -0
  443. package/scripts/rules/oracle-list-cli.ts +0 -3
  444. package/scripts/rules/permission-guards.ts +14 -0
  445. package/scripts/rules/pre-gate-cut.ts +2 -2
  446. package/scripts/rules/protected-files.ts +74 -0
  447. package/scripts/rules/reply-language.ts +1 -1
  448. package/scripts/rules/rule-body-guard.ts +0 -3
  449. package/scripts/rules/rule-value-cli.ts +0 -1
  450. package/scripts/rules/shell-body-trigger.ts +0 -1
  451. package/scripts/rules/shell-segments.ts +0 -1
  452. package/scripts/rules/stop-rules.ts +13 -5
  453. package/scripts/rules/tail-commands.ts +1 -1
  454. package/scripts/rules/test-declared-commit.ts +1 -1
  455. package/scripts/rules/third-party-write.ts +0 -1
  456. package/scripts/rules/worktree-guard.ts +26 -9
  457. package/scripts/run/run-carry-cli.ts +0 -2
  458. package/scripts/run/run-carry-stash.ts +2 -2
  459. package/scripts/run/run-carry-streak.ts +1 -1
  460. package/scripts/run/run-cut-cli.ts +0 -7
  461. package/scripts/run/run-cut.ts +8 -54
  462. package/scripts/run/run-ending-cli.ts +1 -1
  463. package/scripts/run/run-ending.ts +1 -4
  464. package/scripts/run/run-entry-cli.ts +101 -24
  465. package/scripts/run/run-entry.ts +0 -1
  466. package/scripts/run/run-event-cli.ts +0 -2
  467. package/scripts/run/run-event-follow.ts +1 -0
  468. package/scripts/run/run-event-render.ts +1 -1
  469. package/scripts/run/run-event-scope.ts +53 -4
  470. package/scripts/run/run-event-stream.ts +0 -3
  471. package/scripts/run/run-event-watch.ts +1 -0
  472. package/scripts/run/run-halfrun-resume.ts +20 -7
  473. package/scripts/run/run-headless.ts +24 -8
  474. package/scripts/run/run-hold-cli.ts +33 -10
  475. package/scripts/run/run-hold.ts +25 -5
  476. package/scripts/run/run-issue-number.ts +1 -1
  477. package/scripts/run/run-liveness-cli.ts +1 -1
  478. package/scripts/run/run-liveness.ts +2 -3
  479. package/scripts/run/run-merge-cli.ts +5 -13
  480. package/scripts/run/run-merge-steps.ts +5 -5
  481. package/scripts/run/run-merge.ts +1 -1
  482. package/scripts/run/run-next-cli.ts +1 -1
  483. package/scripts/run/run-parent-cut-hook.ts +143 -0
  484. package/scripts/run/run-preflight.ts +2 -9
  485. package/scripts/run/run-prep-cli.ts +2 -2
  486. package/scripts/run/run-prep-locate.ts +1 -1
  487. package/scripts/run/run-progress-cli.ts +4 -7
  488. package/scripts/run/run-progress-clock.ts +6 -34
  489. package/scripts/run/run-progress-config.ts +0 -4
  490. package/scripts/run/run-progress-read.ts +3 -3
  491. package/scripts/run/run-progress.ts +22 -10
  492. package/scripts/run/run-prrun-resume.ts +117 -0
  493. package/scripts/run/run-report-cli.ts +1 -2
  494. package/scripts/run/run-report.ts +0 -1
  495. package/scripts/run/run-retrospective.ts +1 -1
  496. package/scripts/run/run-review-cli.ts +0 -3
  497. package/scripts/run/run-review-steps.ts +2 -0
  498. package/scripts/run/run-review.ts +0 -2
  499. package/scripts/run/run-ship-cli.ts +27 -77
  500. package/scripts/run/run-ship-detach.ts +1 -0
  501. package/scripts/run/run-ship-next.ts +106 -0
  502. package/scripts/run/run-ship-preflight.ts +87 -0
  503. package/scripts/run/run-ship-return.ts +8 -3
  504. package/scripts/run/run-ship-review-steps.ts +23 -30
  505. package/scripts/run/run-ship-review.ts +20 -0
  506. package/scripts/run/run-ship-scoped.ts +45 -0
  507. package/scripts/run/run-ship-stage.ts +5 -1
  508. package/scripts/run/run-ship-steps.ts +105 -0
  509. package/scripts/run/run-ship.ts +2 -1
  510. package/scripts/run/run-stage-read.ts +62 -0
  511. package/scripts/run/run-stage.ts +160 -0
  512. package/scripts/run/run-status-cli.ts +1 -1
  513. package/scripts/run/run-step-cli.ts +21 -14
  514. package/scripts/run/run-step.ts +1 -1
  515. package/scripts/run/run-stop-notify.ts +1 -3
  516. package/scripts/run/run-stranded-cli.ts +0 -4
  517. package/scripts/run/run-stranded-detect.ts +2 -2
  518. package/scripts/run/run-tail-cli.ts +17 -11
  519. package/scripts/run/run-tail.ts +2 -0
  520. package/scripts/run/run-tidy-lanes.ts +2 -1
  521. package/scripts/run/run-tidy-stashes.ts +12 -12
  522. package/scripts/run/run-wake-cli.ts +4 -5
  523. package/scripts/run/run-wake-describe.ts +19 -1
  524. package/scripts/run/run-wake-loop.ts +2 -2
  525. package/scripts/run/run-wake.ts +2 -4
  526. package/scripts/run/run-watcher-guard-cli.ts +0 -4
  527. package/scripts/run/run-watcher-guard.ts +9 -7
  528. package/scripts/run/run-watcher-hook.ts +1 -1
  529. package/scripts/safe-chain/ci-installer-pin.ts +11 -5
  530. package/scripts/safe-chain/project-config.ts +1 -1
  531. package/scripts/security/security-audit-provision-logic.ts +0 -1
  532. package/scripts/security/security-audit-provision.ts +3 -2
  533. package/scripts/security/security-audit.ts +0 -1
  534. package/scripts/security/security-updates-logic.ts +0 -1
  535. package/scripts/sonar/sonar-hotspots-cli.ts +10 -52
  536. package/scripts/sonar/sonar-hotspots.ts +0 -1
  537. package/scripts/sonar/sonar-new-code-cli.ts +150 -0
  538. package/scripts/sonar/sonar-new-code.ts +79 -0
  539. package/scripts/sonar/sonar-project.ts +97 -0
  540. package/scripts/split/split-assess-cli.ts +1 -1
  541. package/scripts/split/split-assess.ts +2 -5
  542. package/scripts/sync/managed-config-scope-cli.ts +1 -1
  543. package/scripts/sync/skill-migration.ts +0 -1
  544. package/scripts/sync/sync-hook-safety.ts +2 -3
  545. package/scripts/sync/sync.ts +1 -8
  546. package/scripts/sync/template-source-logic.ts +0 -1
  547. package/scripts/sync/workflow-pin-logic.ts +16 -28
  548. package/scripts/test/test-declared-logic.ts +0 -1
  549. package/scripts/test/test-declared.ts +0 -2
  550. package/scripts/test/test-red-commit.ts +2 -2
  551. package/scripts/test/test-red.ts +14 -7
  552. package/scripts/test/test-type-logic.ts +1 -1
  553. package/scripts/test/unit-worker-share.ts +7 -16
  554. package/scripts/time-runtime/time-batch-guard.ts +1 -2
  555. package/scripts/time-runtime/time-bundle-call.ts +2 -3
  556. package/scripts/time-runtime/time-bundles.ts +0 -4
  557. package/scripts/time-runtime/time-density-hook.ts +0 -2
  558. package/scripts/time-runtime/time-followup-stage.ts +1 -1
  559. package/scripts/time-runtime/time-format.ts +0 -73
  560. package/scripts/time-runtime/time-round-trips.ts +0 -4
  561. package/scripts/time-runtime/time-single-check.ts +1 -1
  562. package/scripts/time-runtime/time-spans.ts +1 -1
  563. package/scripts/time-runtime/time-transcript-line.ts +1 -2
  564. package/scripts/ui/ui-routes-cli.ts +0 -5
  565. package/scripts/ui/ui-routes.ts +0 -5
  566. package/scripts/version/effective-upstream.ts +2 -2
  567. package/scripts/version/latest-corepack.ts +7 -9
  568. package/scripts/version/latest-scope-cli.ts +0 -2
  569. package/scripts/version/latest-update.ts +0 -2
  570. package/scripts/version/npm-registry.ts +97 -0
  571. package/scripts/version/publishable-range-check.ts +1 -1
  572. package/scripts/version/release-hold.ts +0 -4
  573. package/scripts/version/running-binary.ts +2 -2
  574. package/scripts/version/version-check-logic.ts +0 -2
  575. package/scripts/version/version-commands.ts +5 -4
  576. package/scripts/version/version-remote.ts +28 -14
  577. package/scripts/version/version-targets.ts +4 -4
  578. package/templates/sonar-project.properties +28 -1
  579. package/templates/workflows/dependabot-auto-merge.yml +5 -3
  580. package/templates/workflows/github-release.yml +81 -0
  581. package/prompts/collaboration-workflow/cross-repo-epic.md +0 -5
  582. package/prompts/collaboration-workflow/epic-audit.md +0 -5
  583. package/prompts/collaboration-workflow/epic-bundle.md +0 -5
  584. package/scripts/init/plugin-install-hint.ts +0 -47
  585. package/scripts/version/parse-json.ts +0 -13
  586. /package/scripts/{git → followup}/git-followup-stages.ts +0 -0
  587. /package/scripts/{git → gh}/git-gh-api-path.ts +0 -0
  588. /package/scripts/{git → gh}/git-gh-command.ts +0 -0
  589. /package/scripts/{git → gh}/git-gh-issue-write.ts +0 -0
  590. /package/scripts/{git → gh}/git-gh-issue.ts +0 -0
  591. /package/scripts/{git → gh}/git-gh-pr-auto-merge.ts +0 -0
  592. /package/scripts/{git → gh}/git-gh-pr-snapshot.ts +0 -0
  593. /package/scripts/{git → gh}/git-gh-reachability.ts +0 -0
  594. /package/scripts/{git → gh}/git-gh-repo.ts +0 -0
  595. /package/scripts/{git → gh}/git-gh-rest-state.ts +0 -0
  596. /package/scripts/{git → gh}/git-pr-checks-watch.ts +0 -0
  597. /package/scripts/{git → gh}/git-pr-error.ts +0 -0
  598. /package/scripts/{git → gh}/git-pr-messages.ts +0 -0
  599. /package/scripts/{git → gh}/github-issue-url.ts +0 -0
  600. /package/scripts/git/{stash-orphans.ts → stash/stash-orphans.ts} +0 -0
  601. /package/scripts/{git → issue}/issue-reference.ts +0 -0
  602. /package/scripts/{git → lib}/animation-helpers.ts +0 -0
  603. /package/scripts/{git → lib}/git-animation.ts +0 -0
  604. /package/scripts/{git → notify}/git-notify.ts +0 -0
  605. /package/scripts/{git → notify}/telegram-test-logic.ts +0 -0
@@ -0,0 +1,92 @@
1
+ import { hook_launch } from '#scripts/init/hook-launch'
2
+
3
+ // `.codex/hooks.json` is derived from `.claude/settings.json`, never written by hand
4
+ // (joshuafolkken/kit#2997). The hand copy carried every hook command twice, so a change to one side
5
+ // left the other silently stale. Codex differs from Claude Code in three places only, and each is a
6
+ // rule applied here rather than a line maintained in the copy:
7
+ //
8
+ // 1. The pretool and posttool handlers run through the Codex input adapter, which translates the
9
+ // `apply_patch` payload into the Edit/Write shape the Claude-side guards read.
10
+ // 2. The PreToolUse and PostToolUse matchers also select `apply_patch`, Codex's edit tool.
11
+ // 3. UserPromptSubmit carries no matcher — Codex documents that the event ignores it.
12
+
13
+ interface HookHandler {
14
+ type: string
15
+ command: string
16
+ timeout?: number
17
+ }
18
+
19
+ interface MatcherGroup {
20
+ matcher?: string
21
+ hooks: Array<HookHandler>
22
+ }
23
+
24
+ type HookEvents = Record<string, Array<MatcherGroup>>
25
+
26
+ interface HookConfig {
27
+ hooks: HookEvents
28
+ }
29
+
30
+ const CODEX_EDIT_TOOL = 'apply_patch'
31
+ const TOOL_EVENTS: ReadonlySet<string> = new Set(['PreToolUse', 'PostToolUse'])
32
+ const UNMATCHED_EVENTS: ReadonlySet<string> = new Set(['UserPromptSubmit'])
33
+ const JSON_INDENT = '\t'
34
+
35
+ function adapter_command(mode: string): string {
36
+ return hook_launch.bundle_launch_command(
37
+ `codex-hook-adapter.js ${mode}`,
38
+ `pnpm exec tsx scripts/hooks/codex-hook-adapter.ts ${mode}`,
39
+ )
40
+ }
41
+
42
+ // Each Claude-side guard command the adapter stands in for, keyed by that command verbatim.
43
+ const ADAPTED_COMMANDS: ReadonlyMap<string, string> = new Map([
44
+ [
45
+ hook_launch.hook_launch_command('pretool-guard.js', 'pretool:guard'),
46
+ adapter_command('pretool'),
47
+ ],
48
+ [
49
+ hook_launch.hook_launch_command('format-edited.js', 'format:edited'),
50
+ adapter_command('posttool'),
51
+ ],
52
+ ])
53
+
54
+ function codex_handler(handler: HookHandler): HookHandler {
55
+ return { ...handler, command: ADAPTED_COMMANDS.get(handler.command) ?? handler.command }
56
+ }
57
+
58
+ function codex_matcher(event: string, matcher: string | undefined): string | undefined {
59
+ if (UNMATCHED_EVENTS.has(event)) return undefined
60
+ if (matcher !== undefined && TOOL_EVENTS.has(event)) return `${matcher}|${CODEX_EDIT_TOOL}`
61
+
62
+ return matcher
63
+ }
64
+
65
+ function codex_group(event: string, group: MatcherGroup): MatcherGroup {
66
+ const matcher = codex_matcher(event, group.matcher)
67
+ const hooks = group.hooks.map((handler) => codex_handler(handler))
68
+
69
+ return matcher === undefined ? { hooks } : { matcher, hooks }
70
+ }
71
+
72
+ function codex_hook_config(claude: HookConfig): HookConfig {
73
+ const events = Object.entries(claude.hooks).map(([event, groups]) => [
74
+ event,
75
+ groups.map((group) => codex_group(event, group)),
76
+ ])
77
+
78
+ return { hooks: Object.fromEntries(events) as HookEvents }
79
+ }
80
+
81
+ // The file text `.codex/hooks.json` holds — the formatter's own output for this JSON, so a write
82
+ // followed by `pnpm josh format:edited` leaves it byte-identical.
83
+ function codex_hooks_text(claude_settings_text: string): string {
84
+ const claude = JSON.parse(claude_settings_text) as HookConfig
85
+
86
+ return `${JSON.stringify(codex_hook_config(claude), undefined, JSON_INDENT)}\n`
87
+ }
88
+
89
+ const codex_hooks = { adapter_command, codex_hook_config, codex_hooks_text }
90
+
91
+ export { codex_hooks }
92
+ export type { HookConfig }
@@ -86,6 +86,6 @@ function refused_ask_of(permission_denials: unknown): string | undefined {
86
86
  return questions.map((question) => render_question(question)).join(QUESTION_SEPARATOR)
87
87
  }
88
88
 
89
- const interactive_ask = { INTERACTIVE_TOOLS, is_interactive_tool, refused_ask_of }
89
+ const interactive_ask = { is_interactive_tool, refused_ask_of }
90
90
 
91
91
  export { interactive_ask }
@@ -3,19 +3,19 @@ import { fileURLToPath } from 'node:url'
3
3
  import { epic_bundle_gaps } from '#scripts/epic/epic-bundle-gaps'
4
4
  import { epic_index, type FetchedEpics } from '#scripts/epic/epic-index'
5
5
  import { epic_issue } from '#scripts/epic/epic-issue'
6
- import { git_gh_command } from '#scripts/git/git-gh-command'
7
- import { SUMMARY_FIELDS } from '#scripts/git/git-gh-issue'
8
- import { git_next_issues } from '#scripts/git/git-next-issues'
9
- import { AUTO_OK_LABEL } from '#scripts/git/issue-labels'
6
+ import { git_gh_command } from '#scripts/gh/git-gh-command'
7
+ import { SUMMARY_FIELDS } from '#scripts/gh/git-gh-issue'
10
8
  import { cutoff_cause, cutoff_of, type ScanCutoff } from '#scripts/git/listing-cutoff'
11
9
  import { read_json_listing } from '#scripts/git/parse-json-array'
12
10
  import { open_issue_schema, type OpenIssueData } from '#scripts/git/schemas'
11
+ import { git_next_issues } from '#scripts/issue/git-next-issues'
12
+ import { AUTO_OK_LABEL } from '#scripts/issue/issue-labels'
13
13
 
14
14
  // `josh auto-ok:next` — which issue outside the epic an unattended run picks up next
15
15
  // (joshuafolkken/kit#906).
16
16
  //
17
17
  // A command rather than a documented `gh` invocation, for the reason the label constant exists: the
18
- // name `auto-ok` is single-sourced in `scripts/git/issue-labels.ts`, and a procedure that told an
18
+ // name `auto-ok` is single-sourced in `scripts/issue/issue-labels.ts`, and a procedure that told an
19
19
  // agent to type `gh issue list --label auto-ok` would put a second copy of it in prose, where
20
20
  // nothing checks it. The contract is `epic:next`'s: one token on standard output, every explanation
21
21
  // on standard error, so `answer=$(pnpm josh auto-ok:next)` reads it.
@@ -48,7 +48,7 @@ const LISTING_LIMIT = 200
48
48
  // CLI's version cannot be what changed the row shape — the same misdirection the message below
49
49
  // already refuses to repeat for the blocker relations, left standing one constant above it.
50
50
  const UNREADABLE_MESSAGE = `Could not read the \`${AUTO_OK_LABEL}\` listing. That is not "nothing is opted in" — check \`gh auth status\` and ask again.`
51
- const UNEXPECTED_SHAPE_MESSAGE = `Read the \`${AUTO_OK_LABEL}\` listing but could not parse it. That is not "nothing is opted in" — the rows came back in a shape this command does not recognize, so check the fields it asks for and the REST field mapping in \`scripts/git/git-gh-issue-rest.ts\` rather than your authentication.`
51
+ const UNEXPECTED_SHAPE_MESSAGE = `Read the \`${AUTO_OK_LABEL}\` listing but could not parse it. That is not "nothing is opted in" — the rows came back in a shape this command does not recognize, so check the fields it asks for and the REST field mapping in \`scripts/gh/git-gh-issue-rest.ts\` rather than your authentication.`
52
52
  // The blocker relations failing takes the whole listing with them, and `issue_list` swallows
53
53
  // the error — so the read looks exactly like an access failure and sends the reader to
54
54
  // `gh auth status`, which is green. That is the misdirection joshuafolkken/kit#996 added the message
@@ -310,9 +310,8 @@ async function fetch_tracking(count: number): Promise<TrackingRead> {
310
310
  }
311
311
  }
312
312
 
313
- // The pickup *order* is `git_next_issues.prioritize` itself, not a copy of it: newest first, with the
314
- // `epic` / `in-progress` / `needs-decision` exclusions. Its display cap does not reach this caller,
315
- // which reads only the first row.
313
+ // The pickup *order* is `git_next_issues.order` itself, not a copy of it: the ranking `prioritize`
314
+ // shows, with the `epic` / `in-progress` / `needs-decision` exclusions, before its display cap.
316
315
  //
317
316
  // The two are no longer the same *set*, and deliberately so: since joshuafolkken/kit#996 the pickup
318
317
  // also drops a candidate whose prerequisite is still open, while `🗒 Next issues` shows every open
@@ -323,9 +322,12 @@ async function fetch_tracking(count: number): Promise<TrackingRead> {
323
322
  // Membership of the label is the *query's* job, not this function's: `--label` is what makes the
324
323
  // listing the opted-in set, so re-testing it here would be a second definition of opting in.
325
324
  //
326
- // The exclusions are applied **before** `prioritize`, not after: it keeps only its first few rows,
327
- // so filtering its output would answer `none` whenever those rows happen to be blocked while a
328
- // runnable issue sits below them.
325
+ // The exclusions are applied to `git_next_issues.order`'s **uncapped** ranking, never to
326
+ // `prioritize`'s capped one, which would answer `none` whenever its first rows happen to be blocked
327
+ // while a runnable issue sits below them. They are applied **after** the ranking, not before it: the
328
+ // dependents key counts the issues waiting on a row, and a waiting issue is by definition blocked —
329
+ // filtered first, every row would count zero and the key would never decide anything
330
+ // (joshuafolkken/kit#2928).
329
331
  //
330
332
  // The `🗒 Next issues` display is deliberately *not* filtered this way; `git-next-issues.ts` records
331
333
  // why, and the short version is that a person can see a blocked issue and choose to start it anyway
@@ -354,9 +356,7 @@ function pick_next(
354
356
  tracked: ReadonlyMap<number, number> = new Map(),
355
357
  exclude: ReadonlyArray<number> = [],
356
358
  ): OpenIssueData | undefined {
357
- const runnable = issues.filter((issue) => is_runnable(issue, tracked, exclude))
358
-
359
- return git_next_issues.prioritize(runnable)[0]
359
+ return git_next_issues.order(issues).find((issue) => is_runnable(issue, tracked, exclude))
360
360
  }
361
361
 
362
362
  // Why there is nothing to run. "No open issue carries the label" and "every opted-in issue is
@@ -491,23 +491,13 @@ const auto_ok_cli = {
491
491
  TRUNCATED_WITHOUT_ANSWER,
492
492
  NONE_OPTED_IN_MESSAGE,
493
493
  truncated_cause,
494
- parse_issue_number,
495
- parse_exclude,
496
- parse_pair,
497
494
  parse_options,
498
495
  fetch_opted_in,
499
- parse_listing,
500
- is_page_complete,
501
- is_closed,
502
- is_unblocked,
503
496
  fetch_tracking,
504
497
  is_runnable,
505
498
  pick_next,
506
499
  truncation_note,
507
- none_reason,
508
- report,
509
500
  run,
510
- main,
511
501
  }
512
502
 
513
503
  if (process.argv[1] === fileURLToPath(import.meta.url)) await main(process.argv.slice(ARGV_OFFSET))
@@ -268,7 +268,6 @@ function decide(input: BudgetInput): BudgetDecision {
268
268
 
269
269
  const backlog_budget = {
270
270
  ANSWERS,
271
- ANSWER_STOP_REASONS,
272
271
  BLOCKED_REASON,
273
272
  DEFAULT_IDLE_MINUTES,
274
273
  DEFAULT_IDLE_MS,
@@ -283,7 +282,6 @@ const backlog_budget = {
283
282
  UNREADABLE_REASON,
284
283
  WATCH_VERDICT,
285
284
  WHOLE_RUN_BUDGET_HOURS,
286
- WHOLE_RUN_BUDGET_MINUTES,
287
285
  WHOLE_RUN_BUDGET_MS,
288
286
  WHOLE_RUN_REASON,
289
287
  decide,
@@ -1,6 +1,6 @@
1
1
  import type { EpicChild } from '#scripts/epic/epic-graph'
2
2
  import type { EpicNextResult, RepoCandidates } from '#scripts/epic/epic-report'
3
- import { git_gh_command } from '#scripts/git/git-gh-command'
3
+ import { git_gh_command } from '#scripts/gh/git-gh-command'
4
4
  import { defect_rate, type DefectRate, type IssueKind } from '#scripts/issue/defect-rate'
5
5
  import { defect_rate_cli } from '#scripts/issue/defect-rate-cli'
6
6
 
@@ -72,6 +72,6 @@ async function prioritize(
72
72
  return await reorder(result, repo)
73
73
  }
74
74
 
75
- const backlog_defect_priority = { UNMEASURED_MESSAGE, KIND_RANK, prioritize }
75
+ const backlog_defect_priority = { UNMEASURED_MESSAGE, prioritize }
76
76
 
77
77
  export { backlog_defect_priority }
@@ -5,13 +5,13 @@ import { CONTEXT_CUT_THRESHOLD } from '#scripts/cost-runtime/context-cut-thresho
5
5
  import { hook_decision } from '#scripts/josh/hook-decision'
6
6
  import { josh_command } from '#scripts/josh/josh-run'
7
7
  import { lane_await, type AwaitState } from '#scripts/lane/lane-await'
8
- import { lane_launch_cli } from '#scripts/lane/lane-launch-cli'
8
+ import { lane_launch_cli, type LaunchOutcome } from '#scripts/lane/lane-launch-cli'
9
9
  import { lane_registry } from '#scripts/lane/lane-registry'
10
10
  import { cli_flags } from '#scripts/lib/cli-flags'
11
11
  import { error_text } from '#scripts/lib/error-message'
12
12
  import { run_carry, type RunCarry } from '#scripts/run/run-carry'
13
13
  import { run_event_stream_emit } from '#scripts/run/run-event-stream-emit'
14
- import { run_merge_cli } from '#scripts/run/run-merge-cli'
14
+ import { run_merge_cli, type MergeResult } from '#scripts/run/run-merge-cli'
15
15
  import { z } from 'zod'
16
16
  import {
17
17
  backlog_drive,
@@ -28,6 +28,7 @@ import { backlog_drive_owner } from './backlog-drive-owner'
28
28
  import { backlog_drive_restore } from './backlog-drive-restore'
29
29
  import { backlog_drive_retrospective } from './backlog-drive-retrospective'
30
30
  import { backlog_offer_cli } from './backlog-offer-cli'
31
+ import { backlog_ready } from './backlog-ready'
31
32
 
32
33
  // `josh backlog:drive` — the backlogrun parent's loop as one resident wait (joshuafolkken/kit#2499).
33
34
  // The parent issues it once, in the background, and is woken only when it exits — with a token the model
@@ -217,7 +218,7 @@ function merge_token(out: string, code: number): string {
217
218
 
218
219
  // The child's transcript, where its lane recorded one, so `run:merge` can tell an API outage from a
219
220
  // failure exactly as it does for the parent that passes `--output` by hand.
220
- async function merge(issue: string, owner: string): Promise<string> {
221
+ async function merge(issue: string, owner: string): Promise<MergeResult> {
221
222
  await backlog_drive_owner.assert_current(owner)
222
223
  const lane = await lane_registry.find_open_lane(issue)
223
224
  const result = await run_merge_cli.merge_child({
@@ -231,13 +232,15 @@ async function merge(issue: string, owner: string): Promise<string> {
231
232
 
232
233
  await backlog_drive_named.mark_done(issue, result, owner)
233
234
 
234
- return result.token
235
+ return result
235
236
  }
236
237
 
237
- async function launch(issue: string, owner: string): Promise<boolean> {
238
+ async function launch(issue: string, owner: string): Promise<LaunchOutcome['kind']> {
238
239
  await backlog_drive_owner.assert_current(owner)
239
240
 
240
- return (await lane_launch_cli.launch_lane({ issue, stash: undefined })) !== undefined
241
+ const outcome = await lane_launch_cli.launch_lane({ issue, stash: undefined })
242
+
243
+ return outcome.kind
241
244
  }
242
245
 
243
246
  // `lane:await`'s re-confirmed check, one state per child. A child already gone when the loop starts —
@@ -304,6 +307,7 @@ function ports_of(
304
307
  merge: async (issue) => await merge(issue, context.owner),
305
308
  offer: async (state) => await read_offer(state, context),
306
309
  launch: async (issue) => await launch(issue, context.owner),
310
+ free_lanes: backlog_ready.drive_free_lane_count,
307
311
  now: () => new Date(),
308
312
  sleep: async (milliseconds) => {
309
313
  await sleep(milliseconds)
@@ -375,14 +379,12 @@ async function main(argv: ReadonlyArray<string>): Promise<void> {
375
379
  }
376
380
 
377
381
  const backlog_drive_cli = {
378
- USAGE,
379
382
  end_line,
380
383
  finish: backlog_drive_finish.finish,
381
384
  merge_token,
382
385
  offer_argv: backlog_drive_offer_argv.offer_argv,
383
386
  parse,
384
387
  resume_line,
385
- run,
386
388
  to_offer,
387
389
  }
388
390
 
@@ -1,6 +1,8 @@
1
- import { EPIC_LABEL, has_label_name } from '#scripts/git/issue-labels'
1
+ import { EPIC_LABEL, has_label_name, NEEDS_DECISION_LABEL } from '#scripts/issue/issue-labels'
2
+ import type { IssueState } from '#scripts/issue/issue-state'
2
3
  import { issue_state_cli } from '#scripts/issue/issue-state-cli'
3
4
  import type { RunCarry } from '#scripts/run/run-carry'
5
+ import type { MergeResult } from '#scripts/run/run-merge-cli'
4
6
  import { backlog_budget } from './backlog-budget'
5
7
  import type { DriveState, OfferRead } from './backlog-drive'
6
8
  import { backlog_drive_named } from './backlog-drive-named'
@@ -44,6 +46,15 @@ function budget_offer(
44
46
  }
45
47
  }
46
48
 
49
+ // The outcome a named issue has already reached without this run dispatching it: closed is merged, and
50
+ // a `needs-decision` park waits on a person, so re-dispatching it only repeats the stop it parked on
51
+ // (joshuafolkken/kit#2965). Either is booked done rather than offered.
52
+ function settled_outcome(state: IssueState): MergeResult['outcome'] | undefined {
53
+ if (state.state.toUpperCase() === 'CLOSED') return 'merged'
54
+
55
+ return has_label_name(state.labels, NEEDS_DECISION_LABEL) ? 'parked' : undefined
56
+ }
57
+
47
58
  async function classify(issue: string, named: OfferRead, owner: string): Promise<OfferRead> {
48
59
  const result = await issue_state_cli.read_issue(issue)
49
60
 
@@ -51,8 +62,10 @@ async function classify(issue: string, named: OfferRead, owner: string): Promise
51
62
  return { verdict: 'issue-state', issues: [], retries: NO_RETRIES }
52
63
  }
53
64
 
54
- if (result.state.state.toUpperCase() === 'CLOSED') {
55
- await backlog_drive_named.mark_done(issue, { outcome: 'merged', code: 0, token: 'none' }, owner)
65
+ const outcome = settled_outcome(result.state)
66
+
67
+ if (outcome !== undefined) {
68
+ await backlog_drive_named.mark_done(issue, { outcome, code: 0, token: 'none' }, owner)
56
69
 
57
70
  return { verdict: 'wait', issues: [], retries: NO_RETRIES }
58
71
  }
@@ -1,4 +1,4 @@
1
- import { has_label_name, NEEDS_DECISION_LABEL } from '#scripts/git/issue-labels'
1
+ import { has_label_name, NEEDS_DECISION_LABEL } from '#scripts/issue/issue-labels'
2
2
  import { issue_state_cli } from '#scripts/issue/issue-state-cli'
3
3
  import { run_carry, type RunCarry } from '#scripts/run/run-carry'
4
4
  import type { RunEvent } from '#scripts/run/run-event-stream'
@@ -94,6 +94,7 @@ async function reconcile(
94
94
  for (const issue of completed) {
95
95
  const outcome = parked.has(issue) ? 'parked' : 'merged'
96
96
 
97
+ // eslint-disable-next-line no-await-in-loop -- each mark rewrites the same carry file
97
98
  await mark_done(String(issue), { outcome, code: 0, token: 'none' }, owner)
98
99
  }
99
100
  }
@@ -16,6 +16,9 @@
16
16
  // **Everything it touches is a port**, the pattern `run-wake-loop.ts` set, so the sequencing is pinned
17
17
  // without a process, a network or a clock.
18
18
 
19
+ import type { LaunchOutcome } from '#scripts/lane/lane-launch-cli'
20
+ import type { MergeResult } from '#scripts/run/run-merge-cli'
21
+
19
22
  const RUN_VERDICT = 'run'
20
23
  const STOP_VERDICT = 'stop'
21
24
  // The `run:merge` tokens that end the loop at once: a hand-off, a person's stop, the environment down,
@@ -32,6 +35,7 @@ const IMMEDIATE_TOKENS: ReadonlySet<string> = new Set([
32
35
  // and the children still in flight are collected before the loop ends (joshuafolkken/kit#2881).
33
36
  const HANDOFF_TOKENS: ReadonlySet<string> = new Set([...IMMEDIATE_TOKENS, STOP_VERDICT])
34
37
  const RESUMED_TOKEN = 'resumed'
38
+ const MERGED_OUTCOME = 'merged'
35
39
  const WATCH_VERDICT = 'watch'
36
40
  // The verdicts the loop acts on without the parent. Any other is handed back as it was printed.
37
41
  const KNOWN_VERDICTS: ReadonlySet<string> = new Set([
@@ -41,6 +45,9 @@ const KNOWN_VERDICTS: ReadonlySet<string> = new Set([
41
45
  'wait',
42
46
  ])
43
47
  const NO_RETRIES = 0
48
+ const NO_FREE_LANES = 0
49
+ const LAUNCHED = 'launched'
50
+ const UNOPENED = 'unopened'
44
51
 
45
52
  interface OfferRead {
46
53
  verdict: string
@@ -57,7 +64,9 @@ interface OfferRead {
57
64
  interface DriveState {
58
65
  // The children this run has in flight — seeded from the open lanes, so a restarted loop resumes them.
59
66
  in_flight: Array<string>
60
- // Every child collected, fed back to `backlog:offer` because GitHub closes a merged issue late.
67
+ // Every child merged, fed back to `backlog:offer` because GitHub closes a merged issue late. A parked
68
+ // child is left out: its labels classify it, so one a person released is offered again
69
+ // (joshuafolkken/kit#3041).
61
70
  exclude: Array<string>
62
71
  // When the run last did something, handed to `backlog:budget` as `--active`.
63
72
  active: string
@@ -80,14 +89,20 @@ interface DriveEnd {
80
89
  is_finish?: boolean | undefined
81
90
  }
82
91
 
92
+ type Collected = Pick<MergeResult, 'token' | 'outcome'>
93
+
83
94
  interface DrivePorts {
84
95
  // Whether a child's process has confirmed-ended — `lane:await`'s re-confirmed check in production.
85
96
  is_finished: (issue: string) => boolean
86
- // `run:merge <N>`'s first stdout token.
87
- merge: (issue: string) => Promise<string>
97
+ // `run:merge <N>`'s first stdout token and the outcome it handled the child as.
98
+ merge: (issue: string) => Promise<Collected>
88
99
  // `backlog:offer`'s answer for the state, or `undefined` when it exited non-zero.
89
100
  offer: (state: DriveState) => Promise<OfferRead | undefined>
90
- launch: (issue: string) => Promise<boolean>
101
+ // Where `lane:launch`'s chain ended — `launched`, `unopened` (no lane taken) or `failed` (one taken).
102
+ launch: (issue: string) => Promise<LaunchOutcome['kind']>
103
+ // The lanes free right now — `backlog_ready.drive_free_lane_count` in production, the limit less the
104
+ // open lanes.
105
+ free_lanes: () => Promise<number>
91
106
  now: () => Date
92
107
  }
93
108
 
@@ -150,29 +165,40 @@ function merge_stopped(issue: string, state: DriveState): DriveState {
150
165
  }
151
166
  }
152
167
 
153
- // The child collected and excluded, and — unless its cut was resumed in place — out of flight.
168
+ // Only a merged child is excluded: `backlog:next` may still read it OPEN. Any other is classified by
169
+ // its labels, so excluding it would hide a child a person released for the rest of the process.
170
+ function excluded(issue: string, outcome: Collected['outcome'], state: DriveState): Array<string> {
171
+ if (outcome !== MERGED_OUTCOME || state.exclude.includes(issue)) return state.exclude
172
+
173
+ return [...state.exclude, issue]
174
+ }
175
+
176
+ // The child collected, and — unless its cut was resumed in place — out of flight.
154
177
  function collected_state(
155
178
  issue: string,
156
- token: string,
179
+ collected: Collected,
157
180
  state: DriveState,
158
181
  active: string,
159
182
  ): DriveState {
160
183
  const in_flight =
161
- token === RESUMED_TOKEN ? state.in_flight : state.in_flight.filter((item) => item !== issue)
162
- const exclude = state.exclude.includes(issue) ? state.exclude : [...state.exclude, issue]
184
+ collected.token === RESUMED_TOKEN
185
+ ? state.in_flight
186
+ : state.in_flight.filter((item) => item !== issue)
187
+ const exclude = excluded(issue, collected.outcome, state)
163
188
 
164
189
  return { ...state, in_flight, exclude, active }
165
190
  }
166
191
 
167
192
  // One finished child: handed back on an immediate token, otherwise collected.
168
193
  async function collect(issue: string, state: DriveState, ports: DrivePorts): Promise<PassResult> {
169
- const token = await ports.merge(issue)
194
+ const collected = await ports.merge(issue)
195
+ const { token } = collected
170
196
 
171
197
  // An empty first line is a `run:merge` that failed before printing one: never read as a collection.
172
198
  if (token === '') return ended('merge', state, undefined, issue)
173
199
  if (IMMEDIATE_TOKENS.has(token)) return ended('merge', state, token, issue)
174
200
 
175
- const next = collected_state(issue, token, state, ports.now().toISOString())
201
+ const next = collected_state(issue, collected, state, ports.now().toISOString())
176
202
 
177
203
  return { kind: 'continue', state: token === STOP_VERDICT ? merge_stopped(issue, next) : next }
178
204
  }
@@ -182,6 +208,7 @@ async function collect_finished(state: DriveState, ports: DrivePorts): Promise<P
182
208
  let current = state
183
209
 
184
210
  for (const issue of finished) {
211
+ // eslint-disable-next-line no-await-in-loop -- each collect starts from the state the previous one returned
185
212
  const result = await collect(issue, current, ports)
186
213
 
187
214
  if (result.kind === 'end') return { ...result, state: current }
@@ -192,22 +219,55 @@ async function collect_finished(state: DriveState, ports: DrivePorts): Promise<P
192
219
  return { kind: 'continue', state: current }
193
220
  }
194
221
 
222
+ // A `lane:open` refused with every lane taken is a wait, not a judgement (joshuafolkken/kit#3027): the
223
+ // next offer after a lane frees retries it. A step failing after the lane opened is always handed back —
224
+ // that lane holds the last seat itself, so the free count would read the failure as a full pool.
225
+ async function refused(
226
+ issue: string,
227
+ outcome: LaunchOutcome['kind'],
228
+ state: DriveState,
229
+ ports: DrivePorts,
230
+ ): Promise<PassResult> {
231
+ if (outcome !== UNOPENED) return ended('launch', state, undefined, issue)
232
+ if ((await ports.free_lanes()) <= NO_FREE_LANES) return { kind: 'continue', state }
233
+
234
+ return ended('launch', state, undefined, issue)
235
+ }
236
+
237
+ // **No more launches than free lanes** (joshuafolkken/kit#3027). `backlog:offer` lists every ready issue
238
+ // without reading the lanes, so launching all of them overran `JOSH_LANE_LIMIT` until `lane:open` ran
239
+ // out of seats. The free count is read once, before the first launch, because every launch here opens
240
+ // a lane the count would otherwise have to be told about.
241
+ //
242
+ // **Only a launch is activity** (joshuafolkken/kit#3027): a pass that started nothing — every lane taken
243
+ // — keeps `active` where it was, or the once-a-minute offer would restart the idle budget for good.
244
+ function launched(state: DriveState, in_flight: Array<string>, ports: DrivePorts): DriveState {
245
+ if (in_flight.length === state.in_flight.length) return { ...state, in_flight }
246
+
247
+ return { ...state, in_flight, active: ports.now().toISOString() }
248
+ }
249
+
195
250
  async function launch_all(
196
251
  issues: ReadonlyArray<string>,
197
252
  state: DriveState,
198
253
  ports: DrivePorts,
199
254
  ): Promise<PassResult> {
200
255
  const in_flight = [...state.in_flight]
256
+ const free = await ports.free_lanes()
201
257
 
202
- for (const issue of issues) {
203
- const is_launched = await ports.launch(issue)
258
+ for (const issue of issues.slice(0, free)) {
259
+ // eslint-disable-next-line no-await-in-loop -- lanes launch in order and the first refusal ends the pass
260
+ const outcome = await ports.launch(issue)
204
261
 
205
- if (!is_launched) return ended('launch', { ...state, in_flight }, undefined, issue)
262
+ if (outcome !== LAUNCHED) {
263
+ // eslint-disable-next-line no-await-in-loop -- lanes launch in order and the first refusal ends the pass
264
+ return await refused(issue, outcome, launched(state, in_flight, ports), ports)
265
+ }
206
266
 
207
267
  in_flight.push(issue)
208
268
  }
209
269
 
210
- return { kind: 'continue', state: { ...state, in_flight, active: ports.now().toISOString() } }
270
+ return { kind: 'continue', state: launched(state, in_flight, ports) }
211
271
  }
212
272
 
213
273
  // A watch with nothing in flight is the drain: `run:step` owes the retrospective there, so it is the
@@ -337,7 +397,9 @@ async function run_loop(
337
397
  let step = await loop_step(first, config, ports)
338
398
 
339
399
  while (step.kind === 'next') {
400
+ // eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
340
401
  await ports.sleep(config.poll_ms)
402
+ // eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
341
403
  step = await loop_step(step.run, config, ports)
342
404
  }
343
405
 
@@ -348,10 +410,8 @@ async function run_loop(
348
410
 
349
411
  const backlog_drive = {
350
412
  HANDOFF_TOKENS,
351
- collect,
352
413
  initial_state,
353
414
  merge_stopped,
354
- on_verdict,
355
415
  run_loop,
356
416
  run_pass,
357
417
  }
@@ -141,9 +141,6 @@ function epic_item_outcome(
141
141
  }
142
142
 
143
143
  const backlog_named = {
144
- BACKLOG_KIND,
145
- END_KIND,
146
- NAMED_KIND,
147
144
  NOTHING_TO_RUN,
148
145
  after_failure,
149
146
  epic_item_outcome,