@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
@@ -2,15 +2,23 @@
2
2
  import path from 'node:path'
3
3
  import { fileURLToPath } from 'node:url'
4
4
  import { agent_role_profile, type AgentProfile } from '#scripts/agent/agent-role-profile'
5
+ import { bash_output_cap_reader } from '#scripts/document/bash-output-cap'
5
6
  import { scoped_green } from '#scripts/gate/scoped-green'
6
7
  import { change_base } from '#scripts/git/change-base'
7
8
  import { changed_paths } from '#scripts/git/changed-paths'
8
9
  import { git_command } from '#scripts/git/git-command'
10
+ import { PROJECT_ROOT } from '#scripts/init/init-paths'
11
+ import type { FileMapStamp } from '#scripts/josh/file-map-stamp'
9
12
  import { find_package_directory } from '#scripts/josh/josh-logic'
10
13
  import { path_decision } from '#scripts/josh/path-decision'
14
+ import { stamp_file } from '#scripts/josh/stamp-file'
15
+ import { openai_review_broker } from '#scripts/lane/openai-review-broker'
16
+ import { run_ship_review } from '#scripts/run/run-ship-review'
11
17
  import { review_attest } from './review-attest'
12
18
  import { review_brief } from './review-brief'
13
19
  import { review_checkout, type ReviewCheckout } from './review-checkout'
20
+ import type { DiffParts } from './review-diff-parts'
21
+ import { review_diff_write } from './review-diff-write'
14
22
  import { review_level, type ReviewLevel } from './review-level'
15
23
  import { review_stamps } from './review-stamps'
16
24
  import { review_tree } from './review-tree'
@@ -134,13 +142,54 @@ function record_round_one(
134
142
  // failed to record would hand the review a command that cannot succeed and the run a check that
135
143
  // answers `not-required` — the guard gone, silently, which is the shape this whole record exists to
136
144
  // remove.
137
- async function open_contract(): Promise<{ checkout: ReviewCheckout; nonce: string }> {
145
+ //
146
+ // **Whether this is a resume is read first** (joshuafolkken/kit#2945): `record_target` drops the
147
+ // previous nonce's records, so asked afterwards the finished review would always read as absent. The
148
+ // findings file is the ship's, keyed on `PROJECT_ROOT` as the ship keys it; a review run outside the
149
+ // ship writes none, so it never reads as a resume and keeps the whole change.
150
+ //
151
+ // **The narrowing is measured from the tree that review was briefed on**, and only when that record
152
+ // was written by the brief the pointer names: one left by an earlier brief is not the tree the
153
+ // finished review read, so the resume reads the whole change instead.
154
+ function attested_tree(checkout: ReviewCheckout): FileMapStamp | undefined {
155
+ const { findings } = openai_review_broker.review_paths(PROJECT_ROOT)
156
+ const briefed = review_stamps.briefed_stamp.read()
157
+
158
+ if (briefed === undefined || !review_attest.is_briefed_since(briefed.taken_at, checkout.root)) {
159
+ return undefined
160
+ }
161
+
162
+ const is_clean =
163
+ review_attest.is_reviewed_on(checkout, findings, checkout.root) &&
164
+ run_ship_review.is_clean_round_one(stamp_file.read_stamp_text(findings))
165
+
166
+ return is_clean ? briefed : undefined
167
+ }
168
+
169
+ async function open_contract(): Promise<{
170
+ checkout: ReviewCheckout
171
+ nonce: string
172
+ resumed_from: FileMapStamp | undefined
173
+ }> {
138
174
  const checkout = await review_checkout.read_checkout()
175
+ const resumed_from = attested_tree(checkout)
139
176
 
140
177
  // Keyed on the root git just answered with, never on `process.cwd()`: the check made before the
141
178
  // merge asks git the same question, and the two hash different keys the moment one of them runs
142
179
  // from a subdirectory — a mismatch that would drop the guard with nothing printed.
143
- return { checkout, nonce: review_attest.record_target(checkout, checkout.root) }
180
+ return { checkout, nonce: review_attest.record_target(checkout, checkout.root), resumed_from }
181
+ }
182
+
183
+ // Retaken on every round-1 brief, after the pointer it pairs with (joshuafolkken/kit#2945). Swallowed:
184
+ // a record that failed to write predates the next pointer, so the resume widens rather than narrows.
185
+ function record_briefed(round: number, tree: Record<string, string>, base?: string): void {
186
+ if (round !== FIRST_ROUND) return
187
+
188
+ try {
189
+ review_stamps.briefed_stamp.write(tree, undefined, base)
190
+ } catch {
191
+ /* no record widens the resume rather than narrowing it */
192
+ }
144
193
  }
145
194
 
146
195
  interface ComposeRequest {
@@ -151,8 +200,26 @@ interface ComposeRequest {
151
200
  profile: AgentProfile
152
201
  }
153
202
 
203
+ // **Swallowed, and the brief keeps its target line** (joshuafolkken/kit#2963): parts that could not be
204
+ // written leave the reviewer the whole `git diff` to read, which costs truncated output rather than
205
+ // scope — the direction every failure here falls.
206
+ async function read_diff(
207
+ root: string,
208
+ base: string,
209
+ paths: ReadonlyArray<string>,
210
+ ): Promise<{ parts: DiffParts; cap: number } | undefined> {
211
+ const cap = bash_output_cap_reader.bash_output_cap(root)
212
+
213
+ try {
214
+ return { parts: await review_diff_write.write_parts({ root, base, paths, cap }), cap }
215
+ } catch {
216
+ return undefined
217
+ }
218
+ }
219
+
154
220
  async function compose_brief(request: ComposeRequest): Promise<string> {
155
221
  const { round, paths, tree, base, profile } = request
222
+ const contract = await open_contract()
156
223
  const stamps = {
157
224
  gate: review_stamps.gate_stamp.read(),
158
225
  in_flight: review_stamps.in_flight_stamp.read(),
@@ -172,7 +239,8 @@ async function compose_brief(request: ComposeRequest): Promise<string> {
172
239
  // the map is stored against is the same one the brief printed (joshuafolkken/kit#1537).
173
240
  base,
174
241
  rubric_path: RUBRIC_PATH,
175
- ...(await open_contract()),
242
+ ...contract,
243
+ diff: await read_diff(contract.checkout.root, base, paths),
176
244
  })
177
245
  }
178
246
 
@@ -252,6 +320,7 @@ async function run_review(round: number, reading: ChangeReading): Promise<number
252
320
  if (resolved.kind === 'rejected') return report_error(resolved.note)
253
321
  console.info(await compose_brief({ round, paths, tree, base, profile: resolved.profile }))
254
322
  record_round_one(round, tree, commit)
323
+ record_briefed(round, tree, commit)
255
324
 
256
325
  return 0
257
326
  }
@@ -274,15 +343,10 @@ const review_brief_cli = {
274
343
  FIRST_ROUND,
275
344
  format_reason,
276
345
  KEPT_NOTE_PREFIX,
277
- kept_note,
278
- LEVEL_ONLY_FLAG,
279
- main,
280
346
  parse_round,
281
347
  record_round_one,
282
348
  report_error,
283
349
  run,
284
- run_level,
285
- USAGE,
286
350
  }
287
351
 
288
352
  if (process.argv[1] === fileURLToPath(import.meta.url)) await main(process.argv.slice(ARGV_OFFSET))
@@ -1,6 +1,7 @@
1
1
  import { agent_role_profile, type AgentProfile } from '#scripts/agent/agent-role-profile'
2
2
  import { file_map_stamp, type FileMapStamp } from '#scripts/josh/file-map-stamp'
3
3
  import { review_checkout, type ReviewCheckout } from './review-checkout'
4
+ import { review_diff_parts, type DiffParts } from './review-diff-parts'
4
5
 
5
6
  // The text `josh review:brief` prints — the `/code-review` invocation, composed from what the run
6
7
  // already knows (joshuafolkken/kit#1241).
@@ -56,7 +57,7 @@ function attest_line(nonce: string): string {
56
57
  const RUBRIC_RELATIVE_PATH = 'prompts/review-rubric.md'
57
58
 
58
59
  function rubric_line(rubric_path: string): string {
59
- return `Rubric: read \`${rubric_path}\` first and apply it — it is the severity tests, the round output format, the nine categories and the stop conditions this review is scored against. You do not carry them otherwise, so a review that skips it is scored on the wrong rules.`
60
+ return `Rubric: read \`${rubric_path}\` first, with the Read tool rather than \`cat\` — it is larger than the Bash output cap, so a Bash print comes back truncated (joshuafolkken/kit#2963) — and apply it: it is the severity tests, the round output format, the nine categories and the stop conditions this review is scored against. You do not carry them otherwise, so a review that skips it is scored on the wrong rules.`
60
61
  }
61
62
 
62
63
  function checkout_block(checkout: ReviewCheckout, nonce: string): string {
@@ -357,6 +358,39 @@ function round_two_block(
357
358
  return narrow_block(scope.recorded_at, scope, root, base)
358
359
  }
359
360
 
361
+ // **A resumed round 1 reads what changed since the attested review, reusing round 2's reconciliation**
362
+ // (joshuafolkken/kit#2945). A ship that stopped and was re-issued briefed the whole change again, so
363
+ // the reviewer re-read every file the attested review had just read. The scope is the comparison round
364
+ // 2 makes, measured from the tree that review was briefed on. Every reading that cannot narrow falls back to the whole
365
+ // change: no record, a moved base, or an empty target. An empty target is included because a resumed
366
+ // review that read nothing would report a clean verdict over the one already recorded.
367
+ const RESUMED_HEADING =
368
+ 'Resumed round 1 — a review of this branch was already attested, so this pass reads only what changed since the tree it read.'
369
+
370
+ const RESUMED_QUESTION =
371
+ 'Review these files in full against the rubric — they are the only code this pass has not already read.'
372
+
373
+ function resumed_target(
374
+ snapshot: FileMapStamp | undefined,
375
+ tree: Record<string, string>,
376
+ root: string,
377
+ base: string,
378
+ ): string {
379
+ const scope = round_two_scope(snapshot, tree, base)
380
+
381
+ if (scope.recorded_at === undefined || scope.target.length === 0) {
382
+ return whole_change_target(root, base)
383
+ }
384
+
385
+ return [
386
+ RESUMED_HEADING,
387
+ `The attested review read the tree recorded at ${scope.recorded_at}.`,
388
+ `Target: only these files, which changed since that tree:\n${format_paths(root, scope.target)}`,
389
+ ...reconciliation(root, base, scope),
390
+ RESUMED_QUESTION,
391
+ ].join('\n')
392
+ }
393
+
360
394
  interface BriefStamps {
361
395
  gate: FileMapStamp | undefined
362
396
  in_flight: FileMapStamp | undefined
@@ -377,20 +411,48 @@ interface BriefInput {
377
411
  // The rubric's absolute path, resolved by the caller against the kit package rather than the review
378
412
  // checkout, so it resolves in a consumer that ships no `prompts/` of its own (joshuafolkken/kit#2402).
379
413
  rubric_path: string
414
+ // The tree a finished, clean review of this branch was briefed on, so round 1 is a resume
415
+ // (joshuafolkken/kit#2945). Absent, round 1 reads the whole change.
416
+ resumed_from?: FileMapStamp | undefined
417
+ // The change written as parts under the Bash output cap (joshuafolkken/kit#2963). Absent when the
418
+ // write failed, and the target line alone then names the change.
419
+ diff?: { parts: DiffParts; cap: number } | undefined
380
420
  }
381
421
 
382
422
  const SECOND_ROUND = 2
383
423
 
424
+ function round_one_target(input: BriefInput): string {
425
+ const { root } = input.checkout
426
+
427
+ if (input.resumed_from === undefined) return whole_change_target(root, input.base)
428
+
429
+ return resumed_target(input.resumed_from, input.tree, root, input.base)
430
+ }
431
+
384
432
  function target_block(input: BriefInput): string {
385
- if (input.round < SECOND_ROUND) return whole_change_target(input.checkout.root, input.base)
433
+ if (input.round < SECOND_ROUND) return round_one_target(input)
386
434
 
387
435
  return round_two_block(input.stamps.round_one, input.tree, input.checkout.root, input.base)
388
436
  }
389
437
 
438
+ // **Only beside a whole-change target** (joshuafolkken/kit#2963): each part is a path's diff against
439
+ // the base, so beside a narrowed round 2 or a resumed round 1 the list would hand the reviewer the
440
+ // code that narrowing exists to keep out of scope. Decided by the target actually printed, not by
441
+ // the round: every round that cannot narrow widens through `whole_change_target`, and that round
442
+ // needs the parts as much as a first one does.
443
+ function diff_block(input: BriefInput, target: string): ReadonlyArray<string> {
444
+ const is_whole_change = target.includes(whole_change_target(input.checkout.root, input.base))
445
+
446
+ if (!is_whole_change || input.diff === undefined) return []
447
+
448
+ return ['', review_diff_parts.reading_block(input.diff.parts, input.diff.cap)]
449
+ }
450
+
390
451
  // The level alone on the first line, because the level-only mode's contract — a caller reading the
391
452
  // answer with `$(...)` — is the one thing a brief must not break.
392
453
  function compose(input: BriefInput): string {
393
454
  const profile = input.profile ?? agent_role_profile.DEFAULT_PROFILES.reviewer
455
+ const target = target_block(input)
394
456
 
395
457
  return [
396
458
  input.level,
@@ -404,28 +466,24 @@ function compose(input: BriefInput): string {
404
466
  gate_line(input.stamps, input.tree, input.base),
405
467
  TEST_COMMAND_LINE,
406
468
  '',
407
- target_block(input),
469
+ target,
470
+ ...diff_block(input, target),
408
471
  ].join('\n')
409
472
  }
410
473
 
411
474
  const review_brief = {
412
475
  attest_line,
413
476
  BASE_MOVED_PREFIX,
414
- base_moved_line,
415
477
  carried_line,
416
- checkout_block,
417
478
  checkout_warning,
418
479
  compose,
419
480
  dropped_line,
420
481
  EMPTY_DELTA_LINE,
421
482
  gate_line,
422
- green_stamp,
423
- in_flight_line,
424
- live_marker,
483
+ RESUMED_HEADING,
425
484
  matching_stamp,
426
485
  no_snapshot_line,
427
486
  NOTHING_LEFT_LINE,
428
- NOT_VERIFIED_LINE,
429
487
  rubric_line,
430
488
  RUBRIC_RELATIVE_PATH,
431
489
  ROUND_TWO_HEADING,
@@ -0,0 +1,89 @@
1
+ // The change handed to the reviewer as files no larger than the Bash output cap
2
+ // (joshuafolkken/kit#2963). The brief used to name the whole change as one `git diff` and the rubric
3
+ // as one path, and the forked reviewer printed both through Bash: every print past
4
+ // `BASH_MAX_OUTPUT_LENGTH` came back as a truncated preview plus a saved file it then re-read, and both
5
+ // stayed in the cached prefix of every later request — 120 overflows and 68 re-reads in one review.
6
+ //
7
+ // **The diff is split, not shortened.** Each changed path gets its own parts, every part fits under the
8
+ // cap, and the parts of one path concatenate back to exactly its diff — so the scope a review covers
9
+ // is the one `git diff` lists, and only the size of a single read changes.
10
+
11
+ // A map from each changed path to the absolute part files that carry its diff, in order.
12
+ type DiffParts = Readonly<Record<string, ReadonlyArray<string>>>
13
+
14
+ const LINE_BREAK = '\n'
15
+
16
+ // A line longer than the budget is cut by characters: a minified file or a lockfile line would
17
+ // otherwise produce one part past the cap, which is the read this module exists to remove.
18
+ function cut_line(line: string, budget: number): Array<string> {
19
+ const pieces: Array<string> = []
20
+
21
+ for (let start = 0; start < line.length; start += budget) {
22
+ pieces.push(line.slice(start, start + budget))
23
+ }
24
+
25
+ return pieces
26
+ }
27
+
28
+ function pieces_of(text: string, budget: number): Array<string> {
29
+ return text.split(/(?<=\n)/u).flatMap((line) => cut_line(line, budget))
30
+ }
31
+
32
+ // Line-preserving where a line fits, so a part ends on a line boundary and a reader never sees a hunk
33
+ // cut mid-line unless that one line is itself over the budget.
34
+ function is_full(current: string, piece: string, budget: number): boolean {
35
+ return current.length > 0 && current.length + piece.length > budget
36
+ }
37
+
38
+ function split_text(text: string, budget: number): Array<string> {
39
+ const parts: Array<string> = []
40
+ let current = ''
41
+
42
+ for (const piece of pieces_of(text, budget)) {
43
+ if (is_full(current, piece, budget)) {
44
+ parts.push(current)
45
+ current = ''
46
+ }
47
+
48
+ current += piece
49
+ }
50
+
51
+ return current.length > 0 ? [...parts, current] : parts
52
+ }
53
+
54
+ function part_header(relative: string, index: number, count: number): string {
55
+ return `# ${relative} — part ${String(index + 1)} of ${String(count)}${LINE_BREAK}`
56
+ }
57
+
58
+ // The header is counted inside the cap, so the file a reader opens — header included — is what fits.
59
+ // The count in the header is the final one, so it is sized against the widest header it can carry.
60
+ function part_texts(relative: string, diff: string, cap: number): Array<string> {
61
+ const budget = Math.max(1, cap - part_header(relative, diff.length, diff.length).length)
62
+ const bodies = split_text(diff, budget)
63
+
64
+ return bodies.map((body, index) => `${part_header(relative, index, bodies.length)}${body}`)
65
+ }
66
+
67
+ function body_of(part: string): string {
68
+ return part.slice(part.indexOf(LINE_BREAK) + 1)
69
+ }
70
+
71
+ function part_list(parts: DiffParts): string {
72
+ return Object.entries(parts)
73
+ .flatMap(([relative, files]) => [` ${relative}`, ...files.map((file) => ` ${file}`)])
74
+ .join(LINE_BREAK)
75
+ }
76
+
77
+ // **The read instruction names the tool as well as the files.** A part under the cap would survive a
78
+ // `cat`, but the Read tool is the one read that is never truncated, and naming it keeps the reviewer
79
+ // from reaching back for the whole `git diff` the target line defines the change by.
80
+ function reading_block(parts: DiffParts, cap: number): string {
81
+ return [
82
+ `Reading the diff: Bash output is cut at ${String(cap)} characters, so the change is written below as one or more parts per path, each under that cap, and together exactly the diff. Read the parts of every path you review with the Read tool. Do not print the diff, or any file this brief names, through Bash (\`git diff\`, \`cat\`).`,
83
+ part_list(parts),
84
+ ].join(LINE_BREAK)
85
+ }
86
+
87
+ const review_diff_parts = { body_of, part_texts, reading_block, split_text }
88
+
89
+ export { review_diff_parts, type DiffParts }
@@ -0,0 +1,97 @@
1
+ import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
2
+ import path from 'node:path'
3
+ import { git_spawn } from '#scripts/git/git-spawn'
4
+ import { stamp_file } from '#scripts/josh/stamp-file'
5
+ import { review_diff_parts, type DiffParts } from './review-diff-parts'
6
+
7
+ // Writes the change as the parts `review-diff-parts.ts` cuts it into (joshuafolkken/kit#2963).
8
+ //
9
+ // **One diff per path, read the way the target line defines the change** — `git -C <root> diff
10
+ // <base> -- <path>` for a tracked path, and the file's own content for an untracked one, which no
11
+ // `git diff` lists. The parts are written to the temp directory keyed per checkout, the same place the
12
+ // brief's other records live, and the directory is replaced on every brief so a part from an earlier
13
+ // tree is never offered beside this one's.
14
+
15
+ const DIRECTORY_PREFIX = 'josh-review-diff-'
16
+ const DIRECTORY_MODE = 0o700
17
+ const FILE_MODE = 0o600
18
+ const PART_SUFFIX = '.diff'
19
+ const INDEX_WIDTH = 3
20
+ const NUL = '\0'
21
+ const SLUG_SEPARATOR = '__'
22
+
23
+ function untracked_text(root: string, relative: string): string {
24
+ try {
25
+ const content = readFileSync(path.join(root, relative), 'utf8')
26
+
27
+ if (content.includes(NUL)) return `untracked binary file ${relative}, not shown\n`
28
+
29
+ return `untracked file ${relative}, shown whole:\n${content}`
30
+ } catch {
31
+ return `${relative} is listed by the change but holds no diff and no file\n`
32
+ }
33
+ }
34
+
35
+ async function path_diff(root: string, base: string, relative: string): Promise<string> {
36
+ const diff = await git_spawn.read(['-C', root, 'diff', '--no-color', base, '--', relative])
37
+
38
+ return diff.length > 0 ? diff : untracked_text(root, relative)
39
+ }
40
+
41
+ function part_name(position: number, relative: string, index: number): string {
42
+ const prefix = String(position).padStart(INDEX_WIDTH, '0')
43
+
44
+ return `${prefix}-${relative.split('/').join(SLUG_SEPARATOR)}-${String(index + 1)}${PART_SUFFIX}`
45
+ }
46
+
47
+ interface PathText {
48
+ relative: string
49
+ text: string
50
+ }
51
+
52
+ function write_path(
53
+ directory: string,
54
+ position: number,
55
+ entry: PathText,
56
+ cap: number,
57
+ ): Array<string> {
58
+ return review_diff_parts.part_texts(entry.relative, entry.text, cap).map((part, index) => {
59
+ const file = path.join(directory, part_name(position, entry.relative, index))
60
+
61
+ writeFileSync(file, part, { flag: 'wx', mode: FILE_MODE })
62
+
63
+ return file
64
+ })
65
+ }
66
+
67
+ function fresh_directory(root: string): string {
68
+ const directory = stamp_file.stamp_path(DIRECTORY_PREFIX, root, '')
69
+
70
+ rmSync(directory, { recursive: true, force: true })
71
+ mkdirSync(directory, { mode: DIRECTORY_MODE })
72
+
73
+ return directory
74
+ }
75
+
76
+ interface DiffRequest {
77
+ root: string
78
+ base: string
79
+ paths: ReadonlyArray<string>
80
+ cap: number
81
+ }
82
+
83
+ async function write_parts(request: DiffRequest, directory?: string): Promise<DiffParts> {
84
+ const { root, base, paths, cap } = request
85
+ const texts = await Promise.all(
86
+ paths.map(async (relative) => ({ relative, text: await path_diff(root, base, relative) })),
87
+ )
88
+ const target = directory ?? fresh_directory(root)
89
+
90
+ return Object.fromEntries(
91
+ texts.map((entry, position) => [entry.relative, write_path(target, position, entry, cap)]),
92
+ )
93
+ }
94
+
95
+ const review_diff_write = { path_diff, write_parts }
96
+
97
+ export { review_diff_write }
@@ -151,7 +151,6 @@ function has_issue_record(content: string, issue: number): boolean {
151
151
 
152
152
  const review_finding_ledger = {
153
153
  CATEGORIES,
154
- SEVERITIES,
155
154
  category_counts,
156
155
  finding_line,
157
156
  has_issue_record,
@@ -186,7 +186,7 @@ async function main(argv: ReadonlyArray<string>): Promise<void> {
186
186
  process.exitCode = await run(argv, new Date())
187
187
  }
188
188
 
189
- const review_record_cli = { USAGE, build_lines, parse_finding, run }
189
+ const review_record_cli = { build_lines, parse_finding, run }
190
190
 
191
191
  if (process.argv[1] === fileURLToPath(import.meta.url)) await main(process.argv.slice(ARGV_OFFSET))
192
192
 
@@ -55,7 +55,6 @@ function refusal_message(issue: number): string {
55
55
  }
56
56
 
57
57
  const review_record = {
58
- MISSING_REASON,
59
58
  check,
60
59
  refusal_message,
61
60
  }
@@ -77,7 +77,7 @@ async function main(argv: ReadonlyArray<string>): Promise<void> {
77
77
  process.exitCode = await run(argv)
78
78
  }
79
79
 
80
- const review_round2_cli = { CLOSED_FLAG, JSON_KEY, KNOWN_FLAGS, main, parse_options, run, USAGE }
80
+ const review_round2_cli = { CLOSED_FLAG, parse_options, run }
81
81
 
82
82
  if (process.argv[1] === fileURLToPath(import.meta.url)) await main(process.argv.slice(ARGV_OFFSET))
83
83
 
@@ -59,10 +59,15 @@ const TEST_RELATED_PREFIX = 'josh-test-related-stamp-'
59
59
  const GATE_PREFIX = 'josh-gate-stamp-'
60
60
  const IN_FLIGHT_PREFIX = 'josh-gate-running-'
61
61
  const ROUND_ONE_PREFIX = 'josh-review-round1-'
62
+ const BRIEFED_PREFIX = 'josh-review-briefed-'
62
63
 
63
64
  const gate_stamp: FileMapStampAccess = file_map_stamp.create(GATE_PREFIX, PROJECT_ROOT)
64
65
  const in_flight_stamp: FileMapStampAccess = file_map_stamp.create(IN_FLIGHT_PREFIX, PROJECT_ROOT)
65
66
  const round_one_stamp: FileMapStampAccess = file_map_stamp.create(ROUND_ONE_PREFIX, PROJECT_ROOT)
67
+ // **The tree the latest round-1 brief handed out, retaken on every brief** (joshuafolkken/kit#2945).
68
+ // The round-1 snapshot is kept from the first brief of a run, so it is not the tree a later review
69
+ // read — a resume narrowed against it would skip a file put back to that older content.
70
+ const briefed_stamp: FileMapStampAccess = file_map_stamp.create(BRIEFED_PREFIX, PROJECT_ROOT)
66
71
  const lint_related_stamp: FileMapStampAccess = file_map_stamp.create(
67
72
  LINT_RELATED_PREFIX,
68
73
  PROJECT_ROOT,
@@ -97,16 +102,15 @@ function clear_round_one(target?: string): void {
97
102
  }
98
103
 
99
104
  const review_stamps = {
105
+ briefed_stamp,
100
106
  clear_round_one,
101
107
  GATE_PREFIX,
102
108
  gate_stamp,
103
109
  IN_FLIGHT_PREFIX,
104
110
  in_flight_stamp,
105
- LINT_RELATED_PREFIX,
106
111
  lint_related_stamp,
107
112
  ROUND_ONE_PREFIX,
108
113
  round_one_stamp,
109
- TEST_RELATED_PREFIX,
110
114
  test_related_stamp,
111
115
  }
112
116
 
@@ -3,6 +3,7 @@ import path from 'node:path'
3
3
  import { changed_paths } from '#scripts/git/changed-paths'
4
4
  import { git_command } from '#scripts/git/git-command'
5
5
  import { stamp_file } from '#scripts/josh/stamp-file'
6
+ import { observation_ledger } from '#scripts/observations/observation-ledger'
6
7
 
7
8
  // The tree `josh review:brief` records: every path the change touches, and the digest of its content
8
9
  // (joshuafolkken/kit#1241).
@@ -30,8 +31,18 @@ function digest_of(root: string, relative: string): string {
30
31
 
31
32
  // Sorted so two readings of one tree produce the same record byte for byte, which is what lets a
32
33
  // stored stamp be compared against a fresh reading without a normalization step in between.
34
+ //
35
+ // **The observation ledger is left out of the map**, for the reason `hook-gate-reuse.ts` drops it from
36
+ // the status it reads: it is no code any check runs (joshuafolkken/kit#1756). Kept in, a review's line
37
+ // appended after the gate moved the map, so the ledger commit `pnpm josh followup` pushes carried a
38
+ // tree the record no longer matched — the pre-push hook re-ran the whole unit suite inside the push's
39
+ // 120-second budget, the timed-out push was retried over the still-running suite, and the commit's
40
+ // undo then moved the tree under both (joshuafolkken/kit#2998). Filtered here, every reader of the map
41
+ // — the gate's record, both hooks, the brief and the round-2 fix delta — agrees on it.
33
42
  function tree_of(root: string, paths: ReadonlyArray<string>): Record<string, string> {
34
- const sorted = [...paths].toSorted((left, right) => left.localeCompare(right))
43
+ const sorted = paths
44
+ .filter((relative) => !observation_ledger.is_ledger_path(relative))
45
+ .toSorted((left, right) => left.localeCompare(right))
35
46
 
36
47
  return Object.fromEntries(sorted.map((relative) => [relative, digest_of(root, relative)]))
37
48
  }
@@ -43,6 +54,7 @@ function tree_of(root: string, paths: ReadonlyArray<string>): Record<string, str
43
54
  // say the gate had verified an arbitrarily edited tree, and `--round 2` would report an empty fix
44
55
  // delta. **A defect that answers "all clear" is the one shape this record cannot take**, which is why
45
56
  // the root is resolved rather than assumed (measured from `scripts/`: 18 of 25 entries `absent`).
57
+ // The observation ledger is dropped inside `tree_of`, above (joshuafolkken/kit#3017).
46
58
  async function read_changed_tree(
47
59
  paths?: ReadonlyArray<string>,
48
60
  root?: string,
@@ -53,6 +65,6 @@ async function read_changed_tree(
53
65
  )
54
66
  }
55
67
 
56
- const review_tree = { ABSENT_DIGEST, digest_of, read_changed_tree, tree_of }
68
+ const review_tree = { ABSENT_DIGEST, read_changed_tree, tree_of }
57
69
 
58
70
  export { review_tree }
@@ -0,0 +1,18 @@
1
+ import { run_stage } from '#scripts/run/run-stage'
2
+ import type { DecisionOracle } from './decision-oracle'
3
+
4
+ // The stage-ladder oracle (joshuafolkken/kit#3042), kept beside the enumeration rather than inside it
5
+ // because `decision-oracle.ts` sits at its file-size limit. Where a run on an issue starts — and whether
6
+ // the command typed has already been reached — is computed by `run:entry` from the issue and the tree's
7
+ // hold, so the skill's stage table points at the command rather than re-deciding it in prose. The
8
+ // vocabulary is `run_stage`'s own start tokens, never a second copy.
9
+ const RUN_ENTRY_ORACLE: DecisionOracle = {
10
+ name: 'run:entry',
11
+ decision:
12
+ 'Where a run on an issue starts, and whether the typed command has already been reached',
13
+ args: '<N> [--to kickoff|halfrun|prrun|fullrun]',
14
+ vocabulary: run_stage.START_TOKENS,
15
+ single_source: '.claude/skills/workflow-commands/SKILL.md → §2k',
16
+ }
17
+
18
+ export { RUN_ENTRY_ORACLE }
@@ -6,6 +6,7 @@
6
6
  // not by prose. Single source: `prompts/collaboration-workflow/residency.md` → question 0.
7
7
  //
8
8
  // Anything not on this list is answered by prose or by a hook-delivered rule, never by a command.
9
+ import { RUN_ENTRY_ORACLE } from './decision-oracle-stage'
9
10
 
10
11
  // Paths that appear in more than one entry's `single_source` field.
11
12
  const CHAIN_RULE_MD = '.claude/skills/workflow-commands/chain-rule.md'
@@ -22,11 +23,11 @@ const BACKLOGRUN_MD = '.claude/skills/workflow-commands/backlogrun.md'
22
23
  // now has its verdict contract only in this reference. That makes it the single source and the section
23
24
  // a reader is routed to, in the same `file.md → \`josh <command>\`` form the `epic:reconcile` and
24
25
  // `lane:list` entries already use. joshuafolkken/kit#2254.
25
- const RUN_MERGE_REFERENCE = 'docs/josh-commands.md → `josh run:merge`'
26
- const EPIC_NEXT_REFERENCE = 'docs/josh-commands.md → `josh epic:next`'
27
- const BACKLOG_BUDGET_REFERENCE = 'docs/josh-commands.md → `josh backlog:budget`'
28
- const RUN_LIVENESS_REFERENCE = 'docs/josh-commands.md → `josh run:liveness`'
29
- const AUTO_OK_NEXT_REFERENCE = 'docs/josh-commands.md → `josh auto-ok:next`'
26
+ const RUN_MERGE_REFERENCE = 'docs/josh-commands-automation.md → `josh run:merge`'
27
+ const EPIC_NEXT_REFERENCE = 'docs/josh-commands-automation.md → `josh epic:next`'
28
+ const BACKLOG_BUDGET_REFERENCE = 'docs/josh-commands-automation.md → `josh backlog:budget`'
29
+ const RUN_LIVENESS_REFERENCE = 'docs/josh-commands-automation.md → `josh run:liveness`'
30
+ const AUTO_OK_NEXT_REFERENCE = 'docs/josh-commands-automation.md → `josh auto-ok:next`'
30
31
 
31
32
  // Command used by two separate oracle entries (run:cut:resume and run:cut:gate).
32
33
  const RUN_CUT_CMD = 'run:cut'
@@ -311,7 +312,7 @@ const DECISION_ORACLES: ReadonlyArray<DecisionOracle> = [
311
312
  "Whether an epic's declaration matches its recorded relations, and the repair when it does not",
312
313
  args: '--reconcile <E>',
313
314
  vocabulary: [RECONCILED, NOTHING_TO_RECONCILE],
314
- single_source: 'docs/josh-commands.md → `josh epic --reconcile`',
315
+ single_source: 'docs/josh-commands-automation.md → `josh epic --reconcile`',
315
316
  },
316
317
  {
317
318
  name: 'lane:list',
@@ -319,8 +320,9 @@ const DECISION_ORACLES: ReadonlyArray<DecisionOracle> = [
319
320
  'Whether each in-progress issue holds a live lane, and the two-directional difference',
320
321
  args: '',
321
322
  vocabulary: [LIVE, STOPPED, UNKNOWN],
322
- single_source: 'docs/josh-commands.md → The `in-progress` / lane difference',
323
+ single_source: 'docs/josh-commands-automation.md → The `in-progress` / lane difference',
323
324
  },
325
+ RUN_ENTRY_ORACLE,
324
326
  ]
325
327
 
326
328
  // Returns the command name for an oracle entry. When `command` is omitted from the entry,
@@ -339,4 +341,5 @@ const decision_oracle = {
339
341
  get_command,
340
342
  }
341
343
 
344
+ export type { DecisionOracle }
342
345
  export { decision_oracle }