@joshuafolkken/kit 1.1784.0 → 1.2116.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 (690) hide show
  1. package/.claude/agents/reviewer-verification.md +19 -0
  2. package/.claude/agents/reviewer.md +19 -0
  3. package/.claude/settings.json +5 -6
  4. package/.claude/skills/dependency-update/SKILL.md +9 -10
  5. package/.claude/skills/workflow-commands/SKILL.md +6 -6
  6. package/.claude/skills/workflow-commands/background-commands.md +8 -5
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +3 -1
  8. package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +5 -2
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -3
  11. package/.claude/skills/workflow-commands/backlogrun-recovery.md +1 -1
  12. package/.claude/skills/workflow-commands/backlogrun-steps.md +3 -2
  13. package/.claude/skills/workflow-commands/backlogrun.md +1 -1
  14. package/.claude/skills/workflow-commands/chain-rule.md +41 -32
  15. package/.claude/skills/workflow-commands/delegation.md +6 -6
  16. package/.claude/skills/workflow-commands/entry-sequence.md +2 -2
  17. package/.claude/skills/workflow-commands/followup.md +7 -5
  18. package/.claude/skills/workflow-commands/fullrun-steps.md +6 -6
  19. package/.claude/skills/workflow-commands/fullrun.md +1 -1
  20. package/.claude/skills/workflow-commands/issue-comments.md +9 -4
  21. package/.claude/skills/workflow-commands/issue-fold-existing.md +2 -1
  22. package/.claude/skills/workflow-commands/kickoff.md +2 -2
  23. package/.claude/skills/workflow-commands/observation-filing.md +1 -1
  24. package/.claude/skills/workflow-commands/observation-ledger.md +6 -4
  25. package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -7
  26. package/.claude/skills/workflow-commands/prerequisite.md +3 -2
  27. package/.claude/skills/workflow-commands/retrospective.md +2 -2
  28. package/.claude/skills/workflow-commands/split-assessment.md +7 -5
  29. package/.codex/hooks.json +5 -5
  30. package/.github/actions/setup-pnpm/action.yml +9 -16
  31. package/.github/dependabot.yml +16 -0
  32. package/.github/workflows/auto-tag.yml +45 -0
  33. package/.github/workflows/ci.yml +155 -15
  34. package/.github/workflows/dependabot-auto-merge.yml +63 -4
  35. package/.github/workflows/production.yml +8 -0
  36. package/.github/workflows/publish.yml +60 -45
  37. package/.vscode/settings.json +19 -0
  38. package/CLAUDE.md +5 -12
  39. package/SECURITY.md +2 -2
  40. package/dist/CLAUDE.md +5 -12
  41. package/dist/commands/document-read-cli.js +2 -1
  42. package/dist/commands/document-section-main.js +2 -1
  43. package/dist/commands/read-set-cli.js +194 -134
  44. package/dist/commands/run-prep-main.js +9694 -10173
  45. package/dist/commands/run-step-cli.js +22138 -18285
  46. package/dist/hooks/audit-provision.js +23 -5
  47. package/dist/hooks/chunk-3GKE653K.js +6204 -0
  48. package/dist/hooks/chunk-45CJJOO7.js +1243 -0
  49. package/dist/hooks/{chunk-CWMBGKYW.js → chunk-5PM2JRGV.js} +2153 -856
  50. package/dist/hooks/{chunk-WR2KQAYZ.js → chunk-7SIUNQXK.js} +1207 -1470
  51. package/dist/hooks/{chunk-O2YBIDSI.js → chunk-CQD4LJE6.js} +1682 -1130
  52. package/dist/hooks/{chunk-VWWCFGWK.js → chunk-OPSRGWFU.js} +1 -1
  53. package/dist/hooks/{chunk-XGBNSWEI.js → chunk-UJ3FPMMM.js} +132 -49
  54. package/dist/hooks/chunk-VVNYJWEI.js +30 -0
  55. package/dist/hooks/chunk-Z6DQJKH3.js +2806 -0
  56. package/dist/hooks/codex-hook-adapter.js +8 -8
  57. package/dist/hooks/format-edited.js +4 -5
  58. package/dist/hooks/inputs.json +386 -360
  59. package/dist/hooks/pretool-guard.js +7 -6
  60. package/dist/hooks/session-lang.js +101 -258
  61. package/dist/hooks/stop-guard.js +1744 -2576
  62. package/dist/josh.js +7133 -6368
  63. package/dist/version/index.js +161 -1
  64. package/eslint/rules/comment-why-only.js +108 -0
  65. package/package.json +16 -9
  66. package/prompts/coding-standards.md +1 -1
  67. package/prompts/collaboration-workflow/file-edits.md +14 -11
  68. package/prompts/collaboration-workflow/issue-citation.md +0 -4
  69. package/prompts/collaboration-workflow/issue-template.md +40 -21
  70. package/prompts/collaboration-workflow/lane-instructions.md +3 -1
  71. package/prompts/collaboration-workflow/measurement.md +8 -1
  72. package/prompts/collaboration-workflow/operating-rules.md +11 -2
  73. package/prompts/collaboration-workflow/output-bounds.md +6 -2
  74. package/prompts/collaboration-workflow/plan-comment.md +1 -1
  75. package/prompts/collaboration-workflow/principles.md +9 -0
  76. package/prompts/collaboration-workflow/residency.md +3 -2
  77. package/prompts/collaboration-workflow/rule-delivery.md +13 -1
  78. package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
  79. package/prompts/collaboration-workflow/wip-cap.md +3 -1
  80. package/prompts/review-rubric.md +8 -0
  81. package/prompts/review.md +31 -22
  82. package/prompts/testing-guide.md +1 -0
  83. package/scripts/agent/agent-argv.ts +14 -16
  84. package/scripts/agent/agent-provider.ts +138 -0
  85. package/scripts/agent/agent-role-profile.ts +108 -156
  86. package/scripts/agent/agent-safe-text.ts +20 -5
  87. package/scripts/agent/api-usage-limit.ts +65 -0
  88. package/scripts/agent/claude-agent-argv.ts +19 -9
  89. package/scripts/agent/codex-agent-argv.ts +118 -22
  90. package/scripts/agent/usage-limit-reset.ts +179 -0
  91. package/scripts/auth/claude-token-output.ts +2 -2
  92. package/scripts/auto-ok/auto-ok-author.ts +53 -0
  93. package/scripts/auto-ok/auto-ok-cli.ts +20 -9
  94. package/scripts/backlog/backlog-defect-priority.ts +1 -1
  95. package/scripts/backlog/backlog-drive-cli.ts +6 -1
  96. package/scripts/backlog/backlog-drive-hold.ts +3 -3
  97. package/scripts/backlog/backlog-drive-idle.ts +10 -0
  98. package/scripts/backlog/backlog-drive-launch-pass.ts +90 -0
  99. package/scripts/backlog/backlog-drive-launch.ts +8 -2
  100. package/scripts/backlog/backlog-drive-named-offer.ts +73 -30
  101. package/scripts/backlog/backlog-drive-named.ts +28 -7
  102. package/scripts/backlog/backlog-drive-paused.ts +5 -4
  103. package/scripts/backlog/backlog-drive-restore.ts +11 -3
  104. package/scripts/backlog/backlog-drive.ts +21 -60
  105. package/scripts/backlog/backlog-gate-scope.ts +61 -0
  106. package/scripts/backlog/backlog-measure-close.ts +112 -0
  107. package/scripts/backlog/backlog-next.ts +39 -49
  108. package/scripts/backlog/backlog-occupied.ts +2 -2
  109. package/scripts/backlog/backlog-overlap.ts +42 -8
  110. package/scripts/backlog/backlog-plan-cli.ts +4 -1
  111. package/scripts/backlog/backlog-plan-comment.ts +81 -0
  112. package/scripts/backlog/backlog-plan-read.ts +19 -6
  113. package/scripts/backlog/backlog-pool.ts +50 -12
  114. package/scripts/backlog/backlog-rank.ts +60 -13
  115. package/scripts/backlog/backlog-stalled-detect.ts +2 -1
  116. package/scripts/backlog/backlog-waves.ts +17 -2
  117. package/scripts/backlog/backlogrun-launch.ts +7 -4
  118. package/scripts/cost-runtime/context-cut-payback.ts +27 -25
  119. package/scripts/cost-runtime/cost-cli.ts +37 -16
  120. package/scripts/cost-runtime/cost-pricing.ts +9 -0
  121. package/scripts/cost-runtime/cost-verdict.ts +4 -1
  122. package/scripts/delegation/delegation-policy.ts +2 -2
  123. package/scripts/delegation/duplicate-read-guard.ts +1 -0
  124. package/scripts/delegation/investigation-guard.ts +14 -2
  125. package/scripts/delegation/investigation-reads.ts +45 -23
  126. package/scripts/dependabot/dependabot-cooldown.ts +3 -2
  127. package/scripts/discovery/repo-party.ts +80 -20
  128. package/scripts/discovery/session-owner-pin.ts +51 -0
  129. package/scripts/document/capped-print.ts +1 -1
  130. package/scripts/document/command-reference-line-budget.ts +42 -0
  131. package/scripts/document/document-byte-budget.ts +17 -7
  132. package/scripts/document/document-checks.ts +20 -0
  133. package/scripts/document/document-ratchet-check.ts +101 -0
  134. package/scripts/document/document-section.ts +1 -0
  135. package/scripts/document/entry-read-budget.ts +7 -3
  136. package/scripts/document/issue-citation-budget.ts +94 -0
  137. package/scripts/epic/epic-cli-argv.ts +2 -2
  138. package/scripts/epic/epic-fetch.ts +4 -2
  139. package/scripts/epic/epic-graph.ts +7 -2
  140. package/scripts/epic/epic-issue.ts +3 -1
  141. package/scripts/epic/epic-rank.ts +5 -0
  142. package/scripts/exports/unused-members-check.ts +62 -0
  143. package/scripts/exports/unused-members-cli.ts +6 -51
  144. package/scripts/followup/followup-ci-path.ts +67 -0
  145. package/scripts/followup/followup-coderabbit-retrigger.ts +261 -0
  146. package/scripts/followup/followup-coderabbit-wait.ts +13 -10
  147. package/scripts/followup/followup-failed-tests.ts +160 -0
  148. package/scripts/followup/followup-job-needs.ts +100 -0
  149. package/scripts/followup/followup-job-rerun.ts +303 -0
  150. package/scripts/followup/followup-main-move.ts +113 -0
  151. package/scripts/followup/git-followup-finish.ts +43 -11
  152. package/scripts/followup/git-followup-pending.ts +3 -3
  153. package/scripts/followup/git-followup-stages.ts +41 -11
  154. package/scripts/followup/git-pr-followup-checks.ts +55 -16
  155. package/scripts/followup/git-pr-followup-wrapup.ts +24 -5
  156. package/scripts/followup/git-pr-followup.ts +62 -27
  157. package/scripts/fresh-machine/fresh-machine-script.ts +5 -9
  158. package/scripts/fresh-machine/specs/kit-test-backlogrun-python.json +2 -2
  159. package/scripts/fresh-machine/specs/kit-test-backlogrun.json +2 -2
  160. package/scripts/gate/busy-average.ts +34 -2
  161. package/scripts/gate/check-related-pinned.ts +43 -0
  162. package/scripts/gate/check-related-reuse.ts +64 -0
  163. package/scripts/gate/check-related-section.ts +57 -0
  164. package/scripts/gate/check-related-unplanned.ts +34 -0
  165. package/scripts/gate/check-related.ts +265 -0
  166. package/scripts/gate/command-memory.ts +1 -1
  167. package/scripts/gate/core-admission.ts +24 -6
  168. package/scripts/gate/core-budget-timing.ts +20 -6
  169. package/scripts/gate/core-budget.ts +40 -11
  170. package/scripts/gate/core-wait-record.ts +3 -2
  171. package/scripts/gate/core-wait.ts +25 -2
  172. package/scripts/gate/core-weights.ts +15 -7
  173. package/scripts/gate/gate-labels.ts +46 -0
  174. package/scripts/gate/gate-ledger.ts +14 -6
  175. package/scripts/gate/gate-plan.ts +103 -58
  176. package/scripts/gate/gate-report.ts +9 -7
  177. package/scripts/gate/gate-run-steps.ts +26 -3
  178. package/scripts/gate/gate-skip.ts +45 -6
  179. package/scripts/gate/gate-static-group.ts +60 -0
  180. package/scripts/gate/gate-steps.ts +2 -1
  181. package/scripts/gate/gate-tree.ts +4 -2
  182. package/scripts/gate/hook-gate-reuse.ts +19 -2
  183. package/scripts/gate/metrics-totals.ts +59 -0
  184. package/scripts/gate/scoped-green.ts +68 -15
  185. package/scripts/gate/since-green.ts +14 -6
  186. package/scripts/gate/structural-checks.ts +96 -0
  187. package/scripts/gate/verification-gate.ts +51 -16
  188. package/scripts/gate/verification-inputs.ts +21 -6
  189. package/scripts/gate/verification-tail.ts +52 -0
  190. package/scripts/gh/gh-author-association.ts +23 -2
  191. package/scripts/gh/git-ai-review-scan.ts +1 -1
  192. package/scripts/gh/git-gh-api-path.ts +12 -3
  193. package/scripts/gh/git-gh-comments-unreadable.ts +36 -0
  194. package/scripts/gh/git-gh-exec.ts +32 -2
  195. package/scripts/gh/git-gh-issue-read.ts +4 -2
  196. package/scripts/gh/git-gh-issue-rest.ts +1 -0
  197. package/scripts/gh/git-gh-issue-write.ts +8 -2
  198. package/scripts/gh/git-gh-issue.ts +12 -5
  199. package/scripts/gh/git-gh-pr-auto-merge.ts +13 -6
  200. package/scripts/gh/git-gh-pr-graphql-state.ts +56 -0
  201. package/scripts/gh/git-gh-pr-read.ts +74 -13
  202. package/scripts/gh/git-gh-pr-rest.ts +3 -1
  203. package/scripts/gh/git-gh-pr-snapshot.ts +22 -7
  204. package/scripts/gh/git-gh-pr-too-large.ts +20 -0
  205. package/scripts/gh/git-gh-pr.ts +21 -7
  206. package/scripts/gh/git-gh-retry.ts +141 -0
  207. package/scripts/gh/git-pr-ai-review.ts +15 -6
  208. package/scripts/gh/git-pr-checks-eval.ts +3 -0
  209. package/scripts/gh/git-pr-checks.ts +5 -5
  210. package/scripts/git/base-tree.ts +30 -0
  211. package/scripts/git/change-base.ts +4 -10
  212. package/scripts/git/changed-paths-sync.ts +63 -0
  213. package/scripts/git/changed-paths.ts +16 -1
  214. package/scripts/git/git-common-directory.ts +11 -1
  215. package/scripts/git/git-diff-reads.ts +66 -20
  216. package/scripts/git/git-error.ts +9 -2
  217. package/scripts/git/git-schemas.ts +13 -0
  218. package/scripts/git/git-worktree.ts +13 -0
  219. package/scripts/git/gone-branch.ts +4 -1
  220. package/scripts/git/main-merge-budget-conflict.ts +89 -0
  221. package/scripts/git/main-merge-guard.ts +55 -18
  222. package/scripts/git/main-merge-regenerate.ts +59 -25
  223. package/scripts/git/main-merge.ts +53 -5
  224. package/scripts/git/no-base-checkout.ts +127 -0
  225. package/scripts/git/stash/git-stash.ts +11 -2
  226. package/scripts/git/stash/stash-push-cli.ts +10 -0
  227. package/scripts/hooks/batch-guard.ts +40 -21
  228. package/scripts/hooks/edited-cspell.ts +37 -11
  229. package/scripts/hooks/format-edited-file.ts +22 -2
  230. package/scripts/hooks/lane-plan-guard.ts +50 -0
  231. package/scripts/hooks/pre-commit-lint-switch.ts +9 -0
  232. package/scripts/hooks/pre-commit-lint.ts +14 -1
  233. package/scripts/hooks/pre-push-related-switch.ts +10 -0
  234. package/scripts/hooks/pre-push-unit.ts +76 -10
  235. package/scripts/hooks/pretool-guard.ts +2 -0
  236. package/scripts/hooks/reserved-run.ts +14 -1
  237. package/scripts/hooks/run-hook.sh +23 -8
  238. package/scripts/hooks/step-zero-notice.ts +6 -1
  239. package/scripts/hooks/stop-actions.ts +3 -15
  240. package/scripts/hooks/stop-guard.ts +7 -6
  241. package/scripts/init/distributed-paths.ts +1 -0
  242. package/scripts/init/hook-command-rewrite.ts +5 -1
  243. package/scripts/init/hook-launch.ts +4 -2
  244. package/scripts/issue/aggregation-split.ts +52 -0
  245. package/scripts/issue/defect-origin-line.ts +19 -1
  246. package/scripts/issue/defect-rate-cli.ts +5 -102
  247. package/scripts/issue/defect-report.ts +4 -4
  248. package/scripts/issue/effect-audit-cli.ts +178 -0
  249. package/scripts/issue/effect-audit.ts +185 -0
  250. package/scripts/issue/expected-effect-lint.ts +64 -9
  251. package/scripts/issue/git-next-issues.ts +5 -0
  252. package/scripts/issue/issue-body-or-comment.ts +38 -4
  253. package/scripts/issue/issue-cite-cli.ts +1 -3
  254. package/scripts/issue/issue-classification.ts +1 -0
  255. package/scripts/issue/issue-closing-pr.ts +8 -1
  256. package/scripts/issue/issue-evidence-exit.ts +4 -2
  257. package/scripts/issue/issue-file-cap.ts +58 -0
  258. package/scripts/issue/issue-file-cli.ts +111 -38
  259. package/scripts/issue/issue-file-deferral.ts +52 -0
  260. package/scripts/issue/issue-file-fold.ts +29 -10
  261. package/scripts/issue/issue-file-interrupt.ts +85 -0
  262. package/scripts/issue/issue-file-lane-hint.ts +30 -0
  263. package/scripts/issue/issue-file.ts +43 -6
  264. package/scripts/issue/issue-labels.ts +19 -2
  265. package/scripts/issue/issue-lint-cli.ts +27 -2
  266. package/scripts/issue/issue-measured-cli.ts +13 -35
  267. package/scripts/issue/issue-measured-close.ts +58 -0
  268. package/scripts/issue/issue-not-before-label.ts +2 -2
  269. package/scripts/issue/issue-not-before.ts +4 -1
  270. package/scripts/issue/issue-priority-cli.ts +60 -0
  271. package/scripts/issue/issue-priority-raise.ts +55 -0
  272. package/scripts/issue/issue-priority.ts +174 -43
  273. package/scripts/issue/issue-rank.ts +21 -4
  274. package/scripts/issue/issue-read-cli.ts +32 -6
  275. package/scripts/issue/issue-read.ts +37 -12
  276. package/scripts/issue/issue-sample-gate.ts +95 -74
  277. package/scripts/issue/issue-sample-prime.ts +127 -0
  278. package/scripts/issue/issue-sample-required.ts +57 -0
  279. package/scripts/issue/issue-sample-source.ts +12 -11
  280. package/scripts/issue/issue-search.ts +124 -0
  281. package/scripts/issue/issue-state.ts +13 -1
  282. package/scripts/issue/issue-template-section.ts +43 -0
  283. package/scripts/issue/issue-watch-diff.ts +31 -1
  284. package/scripts/issue/issue-watch-hook.ts +11 -2
  285. package/scripts/issue/issue-watch.ts +55 -12
  286. package/scripts/issue/markdown-section.ts +1 -0
  287. package/scripts/issue/measure-declaration.ts +121 -0
  288. package/scripts/issue/measure-rerun-cli.ts +7 -70
  289. package/scripts/issue/plan-consumers-section.ts +22 -1
  290. package/scripts/issue/reproduction-measure.ts +3 -1
  291. package/scripts/issue/size-estimate.ts +90 -0
  292. package/scripts/issue/trusted-measure.ts +84 -0
  293. package/scripts/josh/command-usage.ts +3 -2
  294. package/scripts/josh/durable-state-migrate.ts +105 -0
  295. package/scripts/josh/durable-state.ts +112 -0
  296. package/scripts/josh/josh-aliases.ts +95 -0
  297. package/scripts/josh/josh-command-map.ts +1 -82
  298. package/scripts/josh/josh-commands-agent-hooks.ts +6 -6
  299. package/scripts/josh/josh-commands-ai.ts +5 -5
  300. package/scripts/josh/josh-commands-development.ts +59 -58
  301. package/scripts/josh/josh-commands-issue-write.ts +23 -4
  302. package/scripts/josh/josh-commands-issue.ts +32 -0
  303. package/scripts/josh/josh-commands-lane.ts +87 -4
  304. package/scripts/josh/josh-commands-lint.ts +16 -3
  305. package/scripts/josh/josh-commands-maintenance.ts +15 -0
  306. package/scripts/josh/josh-commands-review.ts +41 -6
  307. package/scripts/josh/josh-commands-ship.ts +56 -8
  308. package/scripts/josh/josh-commands-test-check.ts +80 -0
  309. package/scripts/josh/josh-commands-workflow.ts +1 -1
  310. package/scripts/josh/josh-environment-file.ts +43 -3
  311. package/scripts/josh/josh-in-process.ts +2 -2
  312. package/scripts/josh/josh-logic.ts +5 -3
  313. package/scripts/josh/josh-run.ts +19 -1
  314. package/scripts/josh/run-record-path.ts +15 -0
  315. package/scripts/josh/stamp-file.ts +11 -2
  316. package/scripts/lane/lane-adopt-cli.ts +98 -0
  317. package/scripts/lane/lane-adopt.ts +208 -0
  318. package/scripts/lane/lane-await.ts +5 -8
  319. package/scripts/lane/lane-baseline.ts +123 -0
  320. package/scripts/lane/lane-breakdown-cli.ts +64 -0
  321. package/scripts/lane/lane-breakdown-implement.ts +170 -0
  322. package/scripts/lane/lane-breakdown-laps.ts +107 -0
  323. package/scripts/lane/lane-breakdown-pinned.ts +76 -0
  324. package/scripts/lane/lane-breakdown-text.ts +145 -0
  325. package/scripts/lane/lane-breakdown.ts +239 -0
  326. package/scripts/lane/lane-check-stats.ts +29 -8
  327. package/scripts/lane/lane-child-invocation.ts +9 -2
  328. package/scripts/lane/lane-child-mark-keys.ts +12 -0
  329. package/scripts/lane/lane-child-marker.ts +20 -1
  330. package/scripts/lane/lane-ci-path-stats.ts +73 -0
  331. package/scripts/lane/lane-claim-stats.ts +84 -0
  332. package/scripts/lane/lane-close.ts +8 -3
  333. package/scripts/lane/lane-dispatch-log.ts +3 -3
  334. package/scripts/lane/lane-dispatch.ts +2 -2
  335. package/scripts/lane/lane-gap-stats.ts +7 -6
  336. package/scripts/lane/lane-guard-policy.ts +7 -1
  337. package/scripts/lane/lane-implement-stats.ts +207 -0
  338. package/scripts/lane/lane-implement-subagents.ts +90 -0
  339. package/scripts/lane/lane-investigation-switch.ts +16 -0
  340. package/scripts/lane/lane-ledger-kind.ts +31 -0
  341. package/scripts/lane/lane-ledger-schema-ship.ts +49 -0
  342. package/scripts/lane/lane-ledger-schema.ts +119 -36
  343. package/scripts/lane/lane-ledger-write.ts +257 -0
  344. package/scripts/lane/lane-ledger.ts +31 -177
  345. package/scripts/lane/lane-load.ts +1 -1
  346. package/scripts/lane/lane-measure-cli.ts +176 -59
  347. package/scripts/lane/lane-net-read.ts +44 -0
  348. package/scripts/lane/lane-net-time.ts +212 -0
  349. package/scripts/lane/lane-open.ts +16 -7
  350. package/scripts/lane/lane-output.ts +2 -4
  351. package/scripts/lane/lane-overrun-prompt.ts +147 -0
  352. package/scripts/lane/lane-overrun.ts +274 -0
  353. package/scripts/lane/lane-paths.ts +24 -1
  354. package/scripts/lane/lane-pause-cli.ts +4 -1
  355. package/scripts/lane/lane-paused-spans.ts +97 -0
  356. package/scripts/lane/lane-plan-check.ts +207 -0
  357. package/scripts/lane/lane-plan-cli.ts +41 -0
  358. package/scripts/lane/lane-plan.ts +144 -0
  359. package/scripts/lane/lane-registry.ts +14 -1
  360. package/scripts/lane/lane-relaunch.ts +1 -1
  361. package/scripts/lane/lane-round-one-stats.ts +51 -0
  362. package/scripts/lane/lane-sampler.ts +23 -4
  363. package/scripts/lane/lane-session-action.ts +93 -18
  364. package/scripts/lane/lane-session-broker.ts +49 -21
  365. package/scripts/lane/lane-session-reread-main.ts +14 -0
  366. package/scripts/lane/lane-session-reread.ts +51 -0
  367. package/scripts/lane/lane-ship-lap-stats.ts +74 -0
  368. package/scripts/lane/lane-sleep.ts +58 -0
  369. package/scripts/lane/lane-spent.ts +1 -1
  370. package/scripts/lane/lane-split-stats.ts +28 -0
  371. package/scripts/lane/lane-stage-stats.ts +13 -1
  372. package/scripts/lane/lane-state.ts +41 -9
  373. package/scripts/lane/lane-stats-tables.ts +58 -0
  374. package/scripts/lane/lane-stats.ts +21 -5
  375. package/scripts/lane/lane-stop-stats.ts +51 -19
  376. package/scripts/lane/lane-tail-stats.ts +32 -0
  377. package/scripts/lane/lane-transcript-calls.ts +67 -10
  378. package/scripts/lane/lane-transcript-stats.ts +44 -12
  379. package/scripts/lane/lane-value-cell.ts +72 -0
  380. package/scripts/lane/lane-value.ts +118 -0
  381. package/scripts/lane/lane-withdraw-closed.ts +124 -0
  382. package/scripts/lane/lane-withdraw.ts +108 -31
  383. package/scripts/lane/lane-yield.ts +85 -0
  384. package/scripts/lane/openai-lane-ship.ts +12 -11
  385. package/scripts/lane/openai-lane-supervisor-decision.ts +6 -8
  386. package/scripts/lane/openai-lane-supervisor-owner.ts +5 -8
  387. package/scripts/lane/openai-lane-supervisor.ts +5 -4
  388. package/scripts/lib/poll.ts +38 -9
  389. package/scripts/lib/settled-together.ts +10 -0
  390. package/scripts/lib/shell-quote.ts +21 -0
  391. package/scripts/lib/token-shape.ts +111 -0
  392. package/scripts/lint/eslint-daemon-sources.ts +79 -0
  393. package/scripts/lint/eslint-daemon.ts +45 -6
  394. package/scripts/lint/eslint-warm-cli.ts +7 -0
  395. package/scripts/lint/eslint-warm.ts +66 -0
  396. package/scripts/lint/import-graph.ts +141 -11
  397. package/scripts/lint/lint-gate-scope.ts +2 -2
  398. package/scripts/lint/lint-parallel.ts +54 -6
  399. package/scripts/lint/lint-related.ts +154 -33
  400. package/scripts/lint/rename-cli.ts +179 -0
  401. package/scripts/lint/rename-identifier.ts +192 -0
  402. package/scripts/lint/type-only-imports.ts +58 -0
  403. package/scripts/notify/telegram-notify.ts +12 -3
  404. package/scripts/observations/observation-record.ts +42 -16
  405. package/scripts/observations/observations-flush.ts +32 -9
  406. package/scripts/overrides/overrides-check.ts +9 -1
  407. package/scripts/release/release-approval-prune.ts +7 -1
  408. package/scripts/repo/required-checks-logic.ts +4 -1
  409. package/scripts/repo/ruleset-check.ts +4 -3
  410. package/scripts/report/markdown-shape.ts +28 -0
  411. package/scripts/report/report-format-reference.ts +15 -1
  412. package/scripts/report/report-labels.ts +12 -1
  413. package/scripts/report/report-lint-child-summary.ts +94 -0
  414. package/scripts/report/report-lint-cli.ts +26 -7
  415. package/scripts/report/report-lint.ts +2 -20
  416. package/scripts/review/prose-stale-cli.ts +88 -0
  417. package/scripts/review/prose-stale-scan.ts +152 -0
  418. package/scripts/review/review-attest.ts +73 -23
  419. package/scripts/review/review-brief-cli.ts +68 -19
  420. package/scripts/review/review-brief-paths.ts +22 -0
  421. package/scripts/review/review-brief.ts +14 -7
  422. package/scripts/review/review-comment-carry.ts +47 -0
  423. package/scripts/review/review-comment-round.ts +85 -22
  424. package/scripts/review/review-finding-ledger.ts +109 -7
  425. package/scripts/review/review-finding-text.ts +43 -0
  426. package/scripts/review/review-interaction.ts +11 -0
  427. package/scripts/review/review-lane-handover.ts +68 -0
  428. package/scripts/review/review-lint-cli.ts +57 -0
  429. package/scripts/review/review-lint-findings.ts +92 -0
  430. package/scripts/review/review-lint-sections.ts +80 -0
  431. package/scripts/review/review-lint.ts +221 -0
  432. package/scripts/review/review-prior-findings.ts +102 -0
  433. package/scripts/review/review-readers-scan.ts +4 -2
  434. package/scripts/review/review-record-cli.ts +177 -54
  435. package/scripts/review/review-record-code-round.ts +55 -0
  436. package/scripts/review/review-record-comment.ts +60 -0
  437. package/scripts/review/review-record-interaction.ts +35 -0
  438. package/scripts/review/review-record-pinned.ts +108 -0
  439. package/scripts/review/review-record.ts +25 -1
  440. package/scripts/review/review-reviewed-tree.ts +307 -0
  441. package/scripts/review/review-round-one-closure.ts +62 -0
  442. package/scripts/review/review-round-reuse.ts +106 -0
  443. package/scripts/review/review-round2-cli.ts +91 -29
  444. package/scripts/review/review-round2-skip-comment.ts +55 -0
  445. package/scripts/review/review-round2.ts +24 -8
  446. package/scripts/review/review-stamps.ts +7 -3
  447. package/scripts/review/review-stop-log.ts +20 -6
  448. package/scripts/review/review-stops-cli.ts +2 -1
  449. package/scripts/review/review-submit-cli.ts +101 -0
  450. package/scripts/rules/agent-model.ts +1 -1
  451. package/scripts/rules/bash-triggers.ts +3 -3
  452. package/scripts/rules/concise-reply.ts +88 -0
  453. package/scripts/rules/credential-body.ts +77 -0
  454. package/scripts/rules/decision-oracle.ts +1 -1
  455. package/scripts/rules/delivered-rules.ts +36 -17
  456. package/scripts/rules/destructive-command.ts +3 -11
  457. package/scripts/rules/direct-issue-comment.ts +34 -12
  458. package/scripts/rules/direct-issue-read.ts +191 -0
  459. package/scripts/rules/direct-pr-create.ts +4 -24
  460. package/scripts/rules/early-heartbeat.ts +2 -0
  461. package/scripts/rules/edit-tool.ts +27 -0
  462. package/scripts/rules/file-edit-rows.ts +17 -0
  463. package/scripts/rules/file-rewrite.ts +146 -0
  464. package/scripts/rules/firing-point.ts +3 -2
  465. package/scripts/rules/gh-api.ts +128 -7
  466. package/scripts/rules/gh-repo-selector.ts +84 -0
  467. package/scripts/rules/git-force.ts +2 -2
  468. package/scripts/rules/guard-remedy.ts +14 -5
  469. package/scripts/rules/implementation-cut.ts +61 -28
  470. package/scripts/rules/investigator-foreground.ts +231 -0
  471. package/scripts/rules/issue-citation.ts +15 -60
  472. package/scripts/rules/issue-comments.ts +9 -4
  473. package/scripts/rules/josh-git-bare.ts +1 -1
  474. package/scripts/rules/lane-background.ts +41 -13
  475. package/scripts/rules/lane-direct-tool.ts +107 -9
  476. package/scripts/rules/lane-interactive-ask.ts +4 -1
  477. package/scripts/rules/lane-park.ts +4 -2
  478. package/scripts/rules/lane-spilled-read.ts +90 -0
  479. package/scripts/rules/lane-split-park.ts +1 -1
  480. package/scripts/rules/lane-switch-main.ts +4 -4
  481. package/scripts/rules/last-prompt.ts +20 -47
  482. package/scripts/rules/oracle-consulted.ts +1 -1
  483. package/scripts/rules/permission-guards.ts +5 -1
  484. package/scripts/rules/piped-verification-shapes.ts +110 -0
  485. package/scripts/rules/piped-verification.ts +67 -17
  486. package/scripts/rules/poll-loop.ts +72 -9
  487. package/scripts/rules/pr-merge.ts +5 -5
  488. package/scripts/rules/pre-gate-cut.ts +3 -3
  489. package/scripts/rules/protected-files.ts +88 -24
  490. package/scripts/rules/reply-language.ts +3 -17
  491. package/scripts/rules/reply-prose.ts +34 -0
  492. package/scripts/rules/repo-admin.ts +132 -0
  493. package/scripts/rules/reviewer-foreground.ts +88 -0
  494. package/scripts/rules/round-one-check-related.ts +120 -0
  495. package/scripts/rules/rule-body-guard.ts +5 -15
  496. package/scripts/rules/rule-value-cache.ts +53 -5
  497. package/scripts/rules/rule-value-candidates.ts +84 -0
  498. package/scripts/rules/rule-value-cli.ts +59 -11
  499. package/scripts/rules/rule-value.ts +17 -4
  500. package/scripts/rules/run-tail-rule.ts +1 -1
  501. package/scripts/rules/sed-in-place.ts +196 -0
  502. package/scripts/rules/shell-segments.ts +10 -2
  503. package/scripts/rules/stop-rule-rows.ts +1 -13
  504. package/scripts/rules/stop-rules.ts +33 -58
  505. package/scripts/rules/test-declared-commit.ts +1 -1
  506. package/scripts/rules/third-party-write.ts +110 -23
  507. package/scripts/rules/timed-rerun.ts +1 -1
  508. package/scripts/rules/turn-filings.ts +90 -0
  509. package/scripts/rules/worktree-guard.ts +22 -7
  510. package/scripts/run/board/run-board-ending-reason.ts +6 -2
  511. package/scripts/run/board/run-board-fit.ts +24 -1
  512. package/scripts/run/board/run-board-found.ts +134 -0
  513. package/scripts/run/board/run-board-header.ts +8 -0
  514. package/scripts/run/board/run-board-labels.ts +11 -1
  515. package/scripts/run/board/run-board-lane-time.ts +1 -0
  516. package/scripts/run/board/run-board-link.ts +15 -2
  517. package/scripts/run/board/run-board-notes.ts +7 -1
  518. package/scripts/run/board/run-board-operation.ts +4 -2
  519. package/scripts/run/board/run-board-phase.ts +2 -5
  520. package/scripts/run/board/run-board-plan.ts +1 -1
  521. package/scripts/run/board/run-board-read.ts +46 -1
  522. package/scripts/run/board/run-board-reason.ts +20 -8
  523. package/scripts/run/board/run-board-render-checks.ts +3 -2
  524. package/scripts/run/board/run-board-render-drawn.ts +11 -0
  525. package/scripts/run/board/run-board-render-found.ts +157 -0
  526. package/scripts/run/board/run-board-render-lead.ts +9 -0
  527. package/scripts/run/board/run-board-render-legend.ts +19 -0
  528. package/scripts/run/board/run-board-render-tail.ts +1 -1
  529. package/scripts/run/board/run-board-render.ts +82 -18
  530. package/scripts/run/board/run-board-spin.ts +1 -3
  531. package/scripts/run/board/run-board-status.ts +2 -0
  532. package/scripts/run/board/run-board-tick.ts +39 -10
  533. package/scripts/run/carry/run-carry-ended.ts +3 -2
  534. package/scripts/run/carry/run-carry.ts +3 -2
  535. package/scripts/run/cut/run-cut-cli.ts +33 -133
  536. package/scripts/run/cut/run-cut-digest.ts +152 -0
  537. package/scripts/run/cut/run-cut-handoff.ts +52 -8
  538. package/scripts/run/cut/run-cut-report.ts +24 -3
  539. package/scripts/run/cut/run-cut-resume.ts +129 -0
  540. package/scripts/run/cut/run-cut-review.ts +105 -0
  541. package/scripts/run/cut/run-cut.ts +18 -7
  542. package/scripts/run/detached-launch.ts +1 -1
  543. package/scripts/run/entry/run-entry-cli.ts +88 -19
  544. package/scripts/run/entry/run-entry-spill.ts +83 -0
  545. package/scripts/run/entry/run-entry-stop.ts +5 -1
  546. package/scripts/run/entry/run-entry-trust.ts +91 -0
  547. package/scripts/run/event/run-event-baseline.ts +56 -0
  548. package/scripts/run/event/run-event-filed.ts +9 -3
  549. package/scripts/run/event/run-event-overrun.ts +197 -0
  550. package/scripts/run/event/run-event-render.ts +4 -0
  551. package/scripts/run/event/run-event-stream.ts +25 -3
  552. package/scripts/run/hold/run-stop-notify.ts +3 -8
  553. package/scripts/run/merge/run-merge-cap.ts +57 -0
  554. package/scripts/run/merge/run-merge-cli.ts +66 -23
  555. package/scripts/run/merge/run-merge-outcome.ts +2 -0
  556. package/scripts/run/merge/run-merge-ship.ts +13 -3
  557. package/scripts/run/merge/run-merge-signals.ts +40 -23
  558. package/scripts/run/merge/run-merge-steps.ts +56 -36
  559. package/scripts/run/merge/run-merge-usage-limit.ts +53 -0
  560. package/scripts/run/merge/run-merge-withdrawn.ts +53 -0
  561. package/scripts/run/merge/run-merge.ts +41 -14
  562. package/scripts/run/review/run-review-cli.ts +306 -20
  563. package/scripts/run/review/run-review-early-push.ts +121 -0
  564. package/scripts/run/review/run-review-join-read.ts +94 -0
  565. package/scripts/run/review/run-review-pinned-accepted.ts +126 -0
  566. package/scripts/run/review/run-review-pinned-join.ts +216 -0
  567. package/scripts/run/review/run-review-pinned-steps.ts +383 -0
  568. package/scripts/run/review/run-review-pinned-tree.ts +37 -0
  569. package/scripts/run/review/run-review-pinned.ts +53 -0
  570. package/scripts/run/review/run-review-steps.ts +70 -34
  571. package/scripts/run/review/run-review.ts +26 -6
  572. package/scripts/run/run-parent-cut-hook.ts +3 -4
  573. package/scripts/run/run-prep.ts +1 -0
  574. package/scripts/run/run-stage-read.ts +2 -6
  575. package/scripts/run/run-step-cli.ts +17 -5
  576. package/scripts/run/run-step-lane-plan.ts +27 -0
  577. package/scripts/run/run-step-section.ts +26 -7
  578. package/scripts/run/run-step.ts +5 -2
  579. package/scripts/run/ship/run-ship-args.ts +19 -0
  580. package/scripts/run/ship/run-ship-brokered-review.ts +106 -0
  581. package/scripts/run/ship/run-ship-cli.ts +131 -39
  582. package/scripts/run/ship/run-ship-conflict-probe.ts +59 -0
  583. package/scripts/run/ship/run-ship-detach.ts +10 -4
  584. package/scripts/run/ship/run-ship-handover.ts +106 -0
  585. package/scripts/run/ship/run-ship-infra-retry.ts +16 -1
  586. package/scripts/run/ship/run-ship-lap.ts +63 -0
  587. package/scripts/run/ship/run-ship-next.ts +27 -26
  588. package/scripts/run/ship/run-ship-overlap.ts +8 -3
  589. package/scripts/run/ship/run-ship-place.ts +9 -2
  590. package/scripts/run/ship/run-ship-planned.ts +92 -0
  591. package/scripts/run/ship/run-ship-pre-detach-pinned.ts +197 -0
  592. package/scripts/run/ship/run-ship-pre-detach-timed.ts +7 -8
  593. package/scripts/run/ship/run-ship-pre-detach.ts +77 -23
  594. package/scripts/run/ship/run-ship-preflight.ts +16 -4
  595. package/scripts/run/ship/run-ship-probe.ts +23 -9
  596. package/scripts/run/ship/run-ship-relaunch-cap.ts +43 -7
  597. package/scripts/run/ship/run-ship-relaunch.ts +51 -0
  598. package/scripts/run/ship/run-ship-return.ts +103 -29
  599. package/scripts/run/ship/run-ship-review-reason.ts +24 -0
  600. package/scripts/run/ship/run-ship-review-steps.ts +230 -59
  601. package/scripts/run/ship/run-ship-review.ts +171 -51
  602. package/scripts/run/ship/run-ship-reviewer.ts +138 -42
  603. package/scripts/run/ship/run-ship-scoped.ts +39 -10
  604. package/scripts/run/ship/run-ship-stage.ts +49 -13
  605. package/scripts/run/ship/run-ship-steps.ts +24 -4
  606. package/scripts/run/ship/run-ship-stop-cause.ts +43 -2
  607. package/scripts/run/ship/run-ship-stop-context.ts +50 -13
  608. package/scripts/run/ship/run-ship-sync.ts +171 -30
  609. package/scripts/run/ship/run-ship-synced-scope.ts +178 -0
  610. package/scripts/run/ship/run-ship-wait-cli.ts +145 -0
  611. package/scripts/run/ship/run-ship-waiter.ts +114 -0
  612. package/scripts/run/ship/run-ship.ts +16 -2
  613. package/scripts/run/wake/run-wake-caffeinate.ts +48 -0
  614. package/scripts/run/wake/run-wake-cli.ts +6 -113
  615. package/scripts/run/wake/run-wake-code.ts +53 -11
  616. package/scripts/run/wake/run-wake-driver.ts +5 -3
  617. package/scripts/run/wake/run-wake-finish.ts +137 -0
  618. package/scripts/run/wake/run-wake-loop.ts +5 -3
  619. package/scripts/run/wake/run-wake-ports.ts +11 -3
  620. package/scripts/run/wake/run-wake-session.ts +2 -0
  621. package/scripts/run/wake/run-wake.ts +3 -2
  622. package/scripts/safe-chain/ci-installer-pin.ts +49 -8
  623. package/scripts/safe-chain/project-config.ts +3 -2
  624. package/scripts/security/secretlint-scan.ts +42 -9
  625. package/scripts/security/security-audit-provision-main.ts +9 -1
  626. package/scripts/security/security-audit-provision.ts +1 -1
  627. package/scripts/security/security-audit.ts +21 -1
  628. package/scripts/security/sonar-file.ts +10 -5
  629. package/scripts/split/split-assess.ts +12 -3
  630. package/scripts/split/split-early-notice.ts +116 -0
  631. package/scripts/split/split-measure.ts +20 -2
  632. package/scripts/split/split-resolution.ts +107 -0
  633. package/scripts/test/direct-importers.ts +185 -0
  634. package/scripts/test/pure-files-entries.ts +83 -0
  635. package/scripts/test/related-heavy-tests.ts +81 -0
  636. package/scripts/test/test-no-base.ts +88 -0
  637. package/scripts/test/test-pinned-cache-logic.ts +363 -0
  638. package/scripts/test/test-pinned-cache.ts +337 -0
  639. package/scripts/test/test-pinned-emit.ts +49 -0
  640. package/scripts/test/test-pinned-functions.ts +116 -0
  641. package/scripts/test/test-pinned-ledger.ts +80 -0
  642. package/scripts/test/test-pinned-logic.ts +208 -20
  643. package/scripts/test/test-pinned-main.ts +84 -18
  644. package/scripts/test/test-pinned-pool.ts +73 -0
  645. package/scripts/test/test-pinned-probe.ts +254 -0
  646. package/scripts/test/test-pinned-prune-logic.ts +118 -0
  647. package/scripts/test/test-pinned-reach.ts +194 -0
  648. package/scripts/test/test-pinned-record.ts +196 -0
  649. package/scripts/test/test-pinned-rewire.ts +148 -0
  650. package/scripts/test/test-pinned-spawn.ts +81 -0
  651. package/scripts/test/test-pinned-stage.ts +70 -0
  652. package/scripts/test/test-pinned.ts +258 -47
  653. package/scripts/test/test-reach-cli.ts +61 -0
  654. package/scripts/test/test-read-map.ts +35 -11
  655. package/scripts/test/test-read-recording.ts +17 -5
  656. package/scripts/test/test-read-trace.ts +26 -8
  657. package/scripts/test/test-red-logic.ts +46 -7
  658. package/scripts/test/test-red.ts +34 -14
  659. package/scripts/test/test-related-claim.ts +37 -0
  660. package/scripts/test/test-related-main.ts +4 -1
  661. package/scripts/test/test-related-moved.ts +91 -0
  662. package/scripts/test/test-related-record.ts +43 -23
  663. package/scripts/test/test-related-scope.ts +99 -34
  664. package/scripts/test/test-related-synced.ts +135 -0
  665. package/scripts/test/test-related-touched.ts +84 -0
  666. package/scripts/test/test-related.ts +167 -83
  667. package/scripts/test/test-unit-guard.ts +28 -5
  668. package/scripts/test/unit-durations.ts +41 -0
  669. package/scripts/test/unit-worker-share.ts +5 -4
  670. package/scripts/test/vitest-cache-directory.ts +19 -0
  671. package/scripts/test/vitest-cli-excludes.ts +14 -0
  672. package/scripts/test/vitest-failure-summary.ts +111 -0
  673. package/scripts/test/whole-suite-files.ts +12 -1
  674. package/scripts/time-runtime/time-batch-guard.ts +42 -4
  675. package/scripts/time-runtime/time-bundle-call.ts +1 -1
  676. package/scripts/time-runtime/time-bundles.ts +36 -5
  677. package/scripts/time-runtime/time-markers.ts +2 -2
  678. package/scripts/time-runtime/time-search-call.ts +38 -0
  679. package/scripts/time-runtime/time-shell.ts +1 -1
  680. package/scripts/time-runtime/time-transcript-line.ts +17 -5
  681. package/scripts/version/development-engines-verdict.ts +124 -0
  682. package/scripts/version/latest-corepack.ts +2 -0
  683. package/templates/gitignore +2 -0
  684. package/templates/workflows/ci.yml +41 -0
  685. package/dist/hooks/chunk-AZX4FGQ3.js +0 -207
  686. package/dist/hooks/chunk-PT5R6UJD.js +0 -7131
  687. package/dist/hooks/chunk-TUIFS5E7.js +0 -72
  688. package/dist/hooks/chunk-YCDOIR3I.js +0 -3456
  689. package/scripts/cost-runtime/context-cut-threshold.ts +0 -11
  690. package/scripts/rules/filing-cap.ts +0 -139
@@ -1,17 +1,17 @@
1
+ import path from 'node:path'
1
2
  import { agent_session_role } from '#scripts/agent/agent-session-role'
2
- import { CONTEXT_CUT_THRESHOLD } from '#scripts/cost-runtime/context-cut-threshold'
3
3
  import { cost_cli, type CostVerdict } from '#scripts/cost-runtime/cost-cli'
4
4
  import { cost_verdict } from '#scripts/cost-runtime/cost-verdict'
5
5
  import type { GuardRun } from '#scripts/josh/hook-decision'
6
6
  import { lane_child_marker, type MarkerSource } from '#scripts/lane/lane-child-marker'
7
7
  import { lane_paths } from '#scripts/lane/lane-paths'
8
- import { figure_format } from '#scripts/lib/figure-format'
8
+ import { json_value } from '#scripts/lib/json-value'
9
9
  import { run_cut, type RunCut } from '#scripts/run/cut/run-cut'
10
10
  import { run_cut_decline } from '#scripts/run/cut/run-cut-decline'
11
11
  import { run_cut_handoff } from '#scripts/run/cut/run-cut-handoff'
12
12
  import { run_cut_ready } from '#scripts/run/cut/run-cut-ready'
13
13
  import type { GuardedCall } from '#scripts/time-runtime/time-batch-guard'
14
- import { bash_triggers } from './bash-triggers'
14
+ import { edit_tool } from './edit-tool'
15
15
  import { implementation_cut_verdict } from './implementation-cut-verdict'
16
16
  import { shell_segments } from './shell-segments'
17
17
 
@@ -26,30 +26,34 @@ import { shell_segments } from './shell-segments'
26
26
  // rather than approximating it — the same statistic and the same threshold, never a second
27
27
  // measurement.
28
28
 
29
- // The two edit tools the `PreToolUse` matcher routes here, and the working-tree boundary the cut is
30
- // taken at. A `PreToolUse` refusal fires *before* the edit lands, so the tree is at the consistent
31
- // state the previous edit left it — the "between edit batches, never mid-edit" boundary
29
+ // The two edit tools the `PreToolUse` matcher routes here (`edit-tool.ts`), and the working-tree
30
+ // boundary the cut is taken at. A `PreToolUse` refusal fires *before* the edit lands, so the tree is at
31
+ // the consistent state the previous edit left it — the "between edit batches, never mid-edit" boundary
32
32
  // `pre-gate-cut.md` requires, reached without waiting for a check to go green.
33
- const EDIT_TOOLS: ReadonlySet<string> = new Set(['Edit', 'Write'])
34
-
35
- function is_edit_tool(name: string): boolean {
36
- return EDIT_TOOLS.has(name)
37
- }
33
+ const { is_edit_tool } = edit_tool
38
34
 
39
35
  // The one spelling that takes this cut rather than the pre-gate one: `--impl`. A bare `pnpm josh
40
36
  // run:cut <N>` is the pre-gate boundary and `--resume` / `--end` / `--json` ask about a cut rather than
41
- // take one, so the compliance test looks for the flag that makes it the implementation-phase cut.
37
+ // take one, so `cost-run-cut.ts` looks for the flag that makes it the implementation-phase cut.
42
38
  const CUT_COMMANDS: ReadonlySet<string> = new Set(['run:cut'])
43
39
  const IMPL_FLAG = /(?:^|\s)--impl(?:[=\s]|$)/u
40
+ const RESUME_FLAG = /(?:^|\s)--resume(?:[=\s]|$)/u
44
41
 
45
- function is_impl_cut_segment(segment: string): boolean {
46
- return shell_segments.is_josh_command(segment, CUT_COMMANDS) && IMPL_FLAG.test(segment)
42
+ // Segment-wise so a spelling quoted inside a body is not read as the call.
43
+ function calls_cut_with(command: string, flag: RegExp): boolean {
44
+ return shell_segments
45
+ .segments_of(command)
46
+ .some((segment) => shell_segments.is_josh_command(segment, CUT_COMMANDS) && flag.test(segment))
47
47
  }
48
48
 
49
- // Whether this command takes the implementation-phase cut, segment-wise so a spelling quoted inside a
50
- // body is not read as the call.
49
+ // Whether this command takes the implementation-phase cut.
51
50
  function takes_the_impl_cut(command: string): boolean {
52
- return shell_segments.segments_of(command).some((segment) => is_impl_cut_segment(segment))
51
+ return calls_cut_with(command, IMPL_FLAG)
52
+ }
53
+
54
+ // Whether this command asks for a cut's resume verdict — the call a relaunched lane child opens with.
55
+ function resumes_a_cut(command: string): boolean {
56
+ return calls_cut_with(command, RESUME_FLAG)
53
57
  }
54
58
 
55
59
  // What the trigger has to know about the world, passed in so the decision is testable without a lane on
@@ -133,6 +137,32 @@ function uncut_run_issue(state: LaneCostState): string | undefined {
133
137
  return state.carried()?.issue === issue ? undefined : issue
134
138
  }
135
139
 
140
+ function file_path_of(call: GuardedCall): string {
141
+ if (!json_value.is_record(call.input)) return ''
142
+
143
+ const value = call.input['file_path']
144
+
145
+ return typeof value === 'string' ? value : ''
146
+ }
147
+
148
+ // **The handoff the refusal asks for is never refused** (joshuafolkken/kit#4975). Only a reissue
149
+ // inside the window passed, so a run that ran a check between the refusal and the handoff `Write`
150
+ // could not write it, and `run:cut --impl` relaunched on the previous cut's stale handoff.
151
+ function is_handoff_write(call: GuardedCall, directory: string, issue: string): boolean {
152
+ const handoff = path.resolve(directory, run_cut_handoff.handoff_path_of(issue))
153
+
154
+ return path.resolve(directory, file_path_of(call)) === handoff
155
+ }
156
+
157
+ // The uncut run an edit would be refused for — none where the edit is that run's own handoff.
158
+ function refusable_issue(call: GuardedCall, state: LaneCostState): string | undefined {
159
+ const issue = uncut_run_issue(state)
160
+
161
+ if (issue === undefined) return undefined
162
+
163
+ return is_handoff_write(call, state.directory, issue) ? undefined : issue
164
+ }
165
+
136
166
  // **An unmeasurable session is cut in a lane and left alone outside one.** A lane child's safety net is
137
167
  // the pre-gate direction below; a held run outside a lane is a person's own session, so only a measured
138
168
  // `over` interrupts it — a provider with no transcript would otherwise refuse every edit it makes.
@@ -161,24 +191,24 @@ function is_over_threshold_edit(
161
191
  ): boolean {
162
192
  if (!is_edit_tool(call.name)) return false
163
193
 
164
- const issue = uncut_run_issue(state)
194
+ const issue = refusable_issue(call, state)
165
195
 
166
196
  if (issue === undefined) return false
167
197
 
168
198
  return warrants_the_cut(state) && state.can_cut(issue)
169
199
  }
170
200
 
171
- // **The threshold in the refusal text is assembled from the constant, never spelled**.
172
- // A spelled literal is left behind when the shared threshold moves, telling agents the wrong number;
173
- // building it from `CONTEXT_CUT_THRESHOLD` keeps the two from drifting. `figure_format.format_tokens` renders it the way every cost report does.
174
- const THRESHOLD_TEXT = `${figure_format.format_tokens(CONTEXT_CUT_THRESHOLD)}-token`
201
+ // **The threshold in the refusal text is named by its command, never spelled**. It is priced at the
202
+ // session's own model (`context-cut-payback.ts`), so no one number is right for every reader, and a
203
+ // spelled literal is left behind when the price list moves.
204
+ const THRESHOLD_TEXT = '`pnpm josh cost --cut`'
175
205
 
176
206
  // The instruction in the shape a refusal can carry: the handoff in the format the parser reads, the
177
207
  // cut, and the one verdict that ends the turn — `cut` is the only one, so a run told merely to "take
178
208
  // the cut" is not left to look it up.
179
209
  const IMPLEMENTATION_CUT_REASON =
180
- `⛔ implementation-phase cut: refused on every edit past the ${THRESHOLD_TEXT} line. ` +
181
- `Write \`${run_cut_handoff.HANDOFF_PATH}\` as ${run_cut_handoff.HANDOFF_FORMAT}, run ` +
210
+ `⛔ implementation-phase cut: refused on every edit over ${THRESHOLD_TEXT}. ` +
211
+ `Write \`${run_cut_handoff.HANDOFF_PATH}\`: ${run_cut_handoff.HANDOFF_FORMAT}, run ` +
182
212
  '`pnpm josh run:cut --impl <N> --handoff <path>`; `cut`: end the turn immediately, no Telegram ' +
183
213
  'is owed; else reissue the edit (`.claude/skills/workflow-commands/pre-gate-cut.md`).'
184
214
 
@@ -211,14 +241,15 @@ function decide(
211
241
  }
212
242
 
213
243
  // The row itself, so `delivered-rules.ts` spreads one entry. `decide` fires it per threshold crossing
214
- // in a run that can cut; `keeps` is the implementation cut command, read from a `Bash` call the same
215
- // way `pre-gate-cut`'s is.
244
+ // in a run that can cut. It declares no `keeps`: the trigger is a budget threshold the child cannot
245
+ // observe, so no run takes `run:cut --impl` before crossing it unaided, and the row is reported
246
+ // unmeasured rather than scored 0% on an act it cannot make (`rule-value.ts` → "A rule with no
247
+ // `keeps` predicate is reported as unmeasured").
216
248
  const ROW = {
217
249
  id: 'implementation-cut',
218
250
  is_trigger: is_over_threshold_edit,
219
251
  reason: IMPLEMENTATION_CUT_REASON,
220
252
  decide,
221
- keeps: bash_triggers.on_bash_command(takes_the_impl_cut),
222
253
  // The opening the reason carried before it was cut to the action and the next command.
223
254
  former_reasons: [
224
255
  '⛔ implementation-phase cut: this checkout is a lane dispatched',
@@ -230,7 +261,8 @@ const ROW = {
230
261
  '`.claude/skills/workflow-commands/pre-gate-cut.md` → "It is a guard, fired at the edit that crosses the threshold"',
231
262
  fires:
232
263
  'an `Edit` / `Write` by an uncut lane child whose recent context is over the `pnpm josh cost --cut` threshold; it hands over `pnpm josh run:cut --impl <N> --handoff <path>`. At each threshold crossing',
233
- quiet: 'not a lane child, a non-editing tool, already cut, or under the threshold',
264
+ quiet:
265
+ "not a lane child, a non-editing tool, the run's own handoff file, already cut, or under the threshold",
234
266
  },
235
267
  }
236
268
 
@@ -241,6 +273,7 @@ const implementation_cut = {
241
273
  decide,
242
274
  is_over_threshold_edit,
243
275
  is_reissued_refusal,
276
+ resumes_a_cut,
244
277
  takes_the_impl_cut,
245
278
  uncut_run_issue,
246
279
  }
@@ -0,0 +1,231 @@
1
+ import { delegation_policy } from '#scripts/delegation/delegation-policy'
2
+ import { hook_decision, type GuardRun } from '#scripts/josh/hook-decision'
3
+ import { json_value } from '#scripts/lib/json-value'
4
+ import type { GuardedCall } from '#scripts/time-runtime/time-batch-guard'
5
+ import {
6
+ time_transcript_line,
7
+ type Block,
8
+ type TranscriptLine,
9
+ } from '#scripts/time-runtime/time-transcript-line'
10
+ import { agent_model } from './agent-model'
11
+ import { implementation_cut } from './implementation-cut'
12
+
13
+ // An `investigator` dispatched without `run_in_background: false` is refused until it names it
14
+ // (joshuafolkken/kit#4721).
15
+ //
16
+ // **The background launch is the cost, not the dispatch.** The subagent tool launches in the
17
+ // background by default, so a main line with nothing else to do ends its turn on "waiting for the
18
+ // reply", and the finished result sits in the queue until a later turn — measured at 4 of 33 such
19
+ // dispatches over 7 days, 658 seconds idle, up to 287 in one plan. A foreground dispatch returns the
20
+ // result in the same turn; the edit-target reads that keep the main line busy go in the same message,
21
+ // where they run beside it.
22
+ //
23
+ // **It fires on every occurrence**: the remedy is one field on the same call.
24
+ //
25
+ // **A build whose subagent tool has no such field stands it down** (joshuafolkken/kit#4889). Claude
26
+ // Code 2.1.306 in VS Code declares no `run_in_background`: every dispatch there launched in the
27
+ // background (64 of 64), the model wrote the field as the string `"false"`, and the parsed hook input
28
+ // dropped it — so the refusal could never be met, and it blocked the very delegation the investigation
29
+ // guard demands. A string value is the tell: across 1,700 dispatches in builds that declare the field
30
+ // the model wrote a boolean every time. A first call written bare leaves no string anywhere, so the
31
+ // reissue it was refused into passes on the refused call's body instead (joshuafolkken/kit#4903).
32
+ //
33
+ // **The build is a fact of the session, not of the tail** (joshuafolkken/kit#4966). Each tell is
34
+ // recorded once against the transcript, so a stand-down outlives the 256 KiB window the tells are read
35
+ // from. A boolean `false` the parsed input dropped is a tell too: the transcript keeps what the model
36
+ // wrote, so a dispatch this row refused that wrote it there is one the field never reached.
37
+ //
38
+ // **This row's own refusal is the last tell** (joshuafolkken/kit#5148). The harness drops an undeclared
39
+ // argument before both the hook and the transcript see it, so a reissue rewritten after the refusal
40
+ // leaves no tell on the tail. A reissue that still carries no field passes, and is remembered for the
41
+ // session, when the last answered investigator dispatch on the tail is this row's refusal, alone in its
42
+ // message and inside the refusal-then-reissue window. A sibling of the refused call shares its message,
43
+ // a dispatch after an answered reissue follows a call that ran, and one past the window is a new one —
44
+ // each still refused where the build declares the field.
45
+
46
+ const INVESTIGATOR_FOREGROUND_REASON =
47
+ '⛔ investigator foreground: a background `investigator` leaves its result queued until a later turn. ' +
48
+ 'Reissue the call with `run_in_background: false`, and put the reads of files this run will edit in the same message. ' +
49
+ 'It fires on every occurrence (`.claude/skills/workflow-commands/delegation.md`).'
50
+
51
+ const BACKGROUND_FIELD = 'run_in_background'
52
+ // The fields that make a reissue the same dispatch as the call it repeats.
53
+ const BODY_FIELDS = ['description', 'prompt'] as const
54
+ const GUARD_LABEL = time_transcript_line.guard_from_refusal(INVESTIGATOR_FOREGROUND_REASON)
55
+ const NO_FIELD_STAMP = hook_decision.create_refusal_stamp('josh-investigator-no-field-')
56
+
57
+ // `kit:investigator` is the consumer's spelling of the same definition.
58
+ function is_investigator(call: GuardedCall): boolean {
59
+ if (!agent_model.SUBAGENT_TOOLS.has(call.name) || !json_value.is_record(call.input)) return false
60
+
61
+ const type = call.input['subagent_type']
62
+
63
+ return typeof type === 'string' && type.split(':').at(-1) === delegation_policy.INVESTIGATOR_AGENT
64
+ }
65
+
66
+ function field_of(input: unknown, key: string): unknown {
67
+ return json_value.is_record(input) ? input[key] : undefined
68
+ }
69
+
70
+ function is_foreground(call: GuardedCall): boolean {
71
+ return field_of(call.input, BACKGROUND_FIELD) === false
72
+ }
73
+
74
+ function is_background_investigator(call: GuardedCall): boolean {
75
+ return is_investigator(call) && !is_foreground(call)
76
+ }
77
+
78
+ function keeps_foreground(call: GuardedCall): boolean {
79
+ return is_investigator(call) && is_foreground(call)
80
+ }
81
+
82
+ function is_untyped_field(name: string, input: unknown): boolean {
83
+ if (!agent_model.SUBAGENT_TOOLS.has(name) || !json_value.is_record(input)) return false
84
+
85
+ return typeof input[BACKGROUND_FIELD] === 'string'
86
+ }
87
+
88
+ // The ids of the tail's calls that have a result, and of those this row refused with the refusal's
89
+ // instant.
90
+ interface TailResults {
91
+ answered: ReadonlySet<string>
92
+ refused: ReadonlyMap<string, number>
93
+ }
94
+
95
+ // A block with the message it was written in, or the instant its line was written.
96
+ interface Placed {
97
+ block: Block
98
+ message_id: string
99
+ at_ms: number
100
+ }
101
+
102
+ function placed_of(lines: ReadonlyArray<TranscriptLine>): Array<Placed> {
103
+ return lines.flatMap((line) =>
104
+ line.blocks.map((block) => ({ block, message_id: line.message_id, at_ms: line.timestamp_ms })),
105
+ )
106
+ }
107
+
108
+ function results_of(placed: ReadonlyArray<Placed>): TailResults {
109
+ const results = placed.filter(({ block }) => block.result_id !== '')
110
+ const refused = results.filter(({ block }) => block.refusal_guard === GUARD_LABEL)
111
+
112
+ return {
113
+ answered: new Set(results.map(({ block }) => block.result_id)),
114
+ refused: new Map(refused.map(({ block, at_ms }) => [block.result_id, at_ms])),
115
+ }
116
+ }
117
+
118
+ // The field written `false`, in either spelling.
119
+ function writes_foreground(block: Block): boolean {
120
+ return String(field_of(block.input, BACKGROUND_FIELD)) === 'false'
121
+ }
122
+
123
+ function has_same_body(block: Block, call: GuardedCall): boolean {
124
+ return BODY_FIELDS.every((key) => field_of(block.input, key) === field_of(call.input, key))
125
+ }
126
+
127
+ // The call in hand is not answered yet, and its `false` there is the one the parsed input dropped.
128
+ function is_pending_foreground(block: Block, results: TailResults): boolean {
129
+ return !results.answered.has(block.id) && writes_foreground(block)
130
+ }
131
+
132
+ // The call in hand on the tail, or a dispatch this row refused that it repeats. A same-body dispatch
133
+ // that ran is not a tell: a build that declares the field still refuses a bare repeat of it past the
134
+ // reissue window `refuses` reads.
135
+ function is_same_dispatch(block: Block, call: GuardedCall, results: TailResults): boolean {
136
+ if (!is_investigator(block) || !has_same_body(block, call)) return false
137
+
138
+ return results.refused.has(block.id) || is_pending_foreground(block, results)
139
+ }
140
+
141
+ // A dispatch this row refused although it wrote the field `false`.
142
+ function is_dropped_foreground(block: Block, results: TailResults): boolean {
143
+ return results.refused.has(block.id) && is_investigator(block) && writes_foreground(block)
144
+ }
145
+
146
+ function refused_at_ms(dispatch: Placed | undefined, results: TailResults): number {
147
+ return results.refused.get(dispatch?.block.id ?? '') ?? hook_decision.NEVER_MS
148
+ }
149
+
150
+ function is_alone(dispatch: Placed, dispatches: ReadonlyArray<Placed>): boolean {
151
+ return dispatches.filter(({ message_id }) => message_id === dispatch.message_id).length === 1
152
+ }
153
+
154
+ // The call in hand reissues this row's refusal: the last investigator dispatch with a result is one
155
+ // this row refused, alone in its message, within the reissue window. A sibling launched beside the
156
+ // refused call shares its message, and a dispatch after an answered reissue follows a call that ran.
157
+ function is_reissue(placed: ReadonlyArray<Placed>, results: TailResults, now_ms: number): boolean {
158
+ const dispatches = placed.filter(({ block }) => is_investigator(block))
159
+ const last = dispatches.findLast(({ block }) => results.answered.has(block.id))
160
+ const at_ms = refused_at_ms(last, results)
161
+
162
+ if (last === undefined || at_ms === hook_decision.NEVER_MS) return false
163
+
164
+ return is_alone(last, dispatches) && now_ms - at_ms < implementation_cut.REISSUE_WINDOW_MS
165
+ }
166
+
167
+ function tail_shows_no_field(tail: string, call: GuardedCall, now_ms: number): boolean {
168
+ const placed = placed_of(time_transcript_line.parse_text(tail))
169
+ const results = results_of(placed)
170
+ const has_block_tell = placed.some(
171
+ ({ block }) =>
172
+ is_untyped_field(block.name, block.input) ||
173
+ is_same_dispatch(block, call, results) ||
174
+ is_dropped_foreground(block, results),
175
+ )
176
+
177
+ return has_block_tell || is_reissue(placed, results, now_ms)
178
+ }
179
+
180
+ function remember_no_field(run: GuardRun): boolean {
181
+ NO_FIELD_STAMP.record(NO_FIELD_STAMP.path(run.transcript), run.now_ms)
182
+
183
+ return true
184
+ }
185
+
186
+ function is_remembered(run: GuardRun): boolean {
187
+ return NO_FIELD_STAMP.last_ms(NO_FIELD_STAMP.path(run.transcript)) !== hook_decision.NEVER_MS
188
+ }
189
+
190
+ // True when this session's subagent tool declares no `run_in_background`, so no dispatch in it can run
191
+ // in the foreground: the call in hand or a subagent call on the tail wrote the field as a string, the
192
+ // tail holds the call in hand (or the dispatch it reissues) with the field the parsed input dropped,
193
+ // or this row refused a dispatch that wrote it `false`. The first tell is recorded for the session. A
194
+ // call that names the background explicitly came through a build that declares the field.
195
+ function lacks_background_field(tail: string, call: GuardedCall, run: GuardRun): boolean {
196
+ if (field_of(call.input, BACKGROUND_FIELD) === true) return false
197
+ if (is_remembered(run)) return true
198
+
199
+ const has_tell =
200
+ is_untyped_field(call.name, call.input) || tail_shows_no_field(tail, call, run.now_ms)
201
+
202
+ return has_tell && remember_no_field(run)
203
+ }
204
+
205
+ const ROW = {
206
+ id: 'investigator-foreground',
207
+ is_trigger: is_background_investigator,
208
+ reason: INVESTIGATOR_FOREGROUND_REASON,
209
+ already_satisfied: lacks_background_field,
210
+ decide: (): boolean => true,
211
+ keeps: keeps_foreground,
212
+ reaches: is_investigator,
213
+ about: {
214
+ title: 'Investigator dispatched in the foreground',
215
+ topic:
216
+ '`.claude/skills/workflow-commands/delegation.md` → "The pre-implementation reading — what goes to a unit, and from which file"',
217
+ fires:
218
+ 'an `Agent` / `Task` call of the `investigator` type without `run_in_background: false`. Every occurrence',
219
+ quiet:
220
+ 'another agent type, `run_in_background: false` set, or a session whose subagent tool declares no `run_in_background` (the field written as a string, the tail holding the same description and prompt, a refused dispatch that wrote it `false`, or a reissue still without the field just after this row refused a lone dispatch) — remembered for the session',
221
+ },
222
+ }
223
+
224
+ const investigator_foreground = {
225
+ INVESTIGATOR_FOREGROUND_REASON,
226
+ ROW,
227
+ is_background_investigator,
228
+ lacks_background_field,
229
+ }
230
+
231
+ export { investigator_foreground }
@@ -1,24 +1,19 @@
1
- // The bare-`#N` predicate behind the `issue-citation` row of the stop guard,
2
- // and the printing-side formatter that keeps a bare `#N` out of session-facing output in the first
3
- // place.
1
+ // The printing-side formatter that keeps a bare `#N` out of session-facing output, and the bare-`#N`
2
+ // predicate it is checked against.
4
3
  //
5
4
  // **Session-facing output cites an Issue as a number-link, never a bare `#N`.** `CLAUDE.md` and
6
5
  // `prompts/collaboration-workflow/issue-citation.md` require `[#<N>](https://github.com/<owner>/<repo>/issues/<N>) — <short summary>`
7
6
  // in what the person reads: a bare `#123` is not clickable and does not say which repository's Issue
8
- // it is. The stop guard reads `last_assistant_message` — the turn's session-facing text — and this
9
- // predicate answers whether a bare number slipped into it.
7
+ // it is.
10
8
  //
11
- // **It blocks the stop, so a false positive costs a wasted turn**. The nudge
12
- // now reaches the model rather than the person, so the detection is tightened to what is genuinely a
13
- // bare citation: a `#N` inside a fenced code block, inside an inline-code span, on a quote line, or
14
- // right after `PR` / `pull request` is not a citation slip and is skipped. The scan is line-based so
15
- // each exclusion is decided from the one line the mention sits on.
9
+ // **The detection is what is genuinely a bare citation**: a `#N` inside a fenced code block, inside an
10
+ // inline-code span, on a quote line, or right after `PR` / `pull request` is not a citation slip and is
11
+ // skipped. The scan is line-based so each exclusion is decided from the one line the mention sits on.
16
12
  //
17
- // **`linkify` runs that same scan the other way**: a command whose stdout a
18
- // run copies into its reply passes the text through it, and every bare `#N` the predicate would flag
19
- // is rewritten to `[#N](url)` — which the predicate then reads as linked, so the material that fed the
20
- // duplicate reply is fixed where it is printed rather than scolded after it reaches the screen. The
21
- // same exclusions hold, so a `#N` in a fenced example or an already-linked reference is left untouched.
13
+ // **`linkify` runs that same scan the other way**: a command whose stdout a run copies into its reply
14
+ // passes the text through it, and every bare `#N` the predicate would flag is rewritten to `[#N](url)`
15
+ // — which the predicate then reads as linked, so the reference is fixed where it is printed. The same
16
+ // exclusions hold, so a `#N` in a fenced example or an already-linked reference is left untouched.
22
17
 
23
18
  import { issue_cite } from '#scripts/issue/issue-cite'
24
19
 
@@ -31,8 +26,8 @@ const ISSUE_NUMBER = /#\d+/gu
31
26
  // scan stays linear.
32
27
  const REFERENCE_BOUNDARY = /[\s#()[\]<>|]/u
33
28
  // A well-formed `owner/repo`: exactly one slash between two non-empty segments — the same shape
34
- // `issue:cite`'s parser accepts. A path-like run (`src/lib`, `a/b/c`) is not one, so it is not emitted
35
- // as a prefix that would make the suggested `issue:cite` call refuse the very reference it names.
29
+ // `issue:cite`'s parser accepts. A path-like run (`src/lib`, `a/b/c`) is not one, so it is not linked
30
+ // as a repository.
36
31
  const OWNER_REPO = /^[^\s/#]+\/[^\s/#]+$/u
37
32
  // A markdown link: `[text](target)`. Each class excludes *both* of its delimiters — no `[`/`]` in the
38
33
  // text, no `(`/`)` in the target — so neither star is ambiguous against a nested bracket and there is
@@ -94,11 +89,6 @@ function lead_token(message: string, hash_index: number): string {
94
89
  return message.slice(start, hash_index)
95
90
  }
96
91
 
97
- // **The message text alone, never a GitHub-bound artifact.** An Issue body or comment is passed to
98
- // `gh` as a `Bash` argument, not spoken in `last_assistant_message`, so those never reach here — which
99
- // is exactly the "silent on GitHub-bound artifacts" behavior the issue asks for, obtained by what the
100
- // stop guard reads rather than by a second exclusion here.
101
- //
102
92
  // The `owner/repo` written immediately before a `#N`, or '' when the mention is bare — the run of
103
93
  // non-boundary characters ending at the `#`, kept only when it holds a `/`. Read backwards a
104
94
  // character at a time so a repository name of any length costs its own length and no more.
@@ -184,10 +174,9 @@ function prose_lines(message: string): ReadonlyArray<string> {
184
174
  return lines_outside_fences(message).filter((line) => !QUOTE_LINE.test(line))
185
175
  }
186
176
 
187
- // The bare references in the message, in the order they appear and de-duplicated: the block reason
188
- // names them and turns them into `issue:cite` arguments, so a reference cited twice is not nudged
189
- // about twice. Fenced-code blocks and quote lines are skipped, so a `#N` shown in an example or quoted
190
- // from an Issue body is not read as the run's own citation.
177
+ // The bare references in the message, in the order they appear and de-duplicated. Fenced-code blocks
178
+ // and quote lines are skipped, so a `#N` shown in an example or quoted from an Issue body is not read
179
+ // as the run's own citation.
191
180
  function bare_references(message: string): ReadonlyArray<string> {
192
181
  const found: Array<string> = []
193
182
 
@@ -196,42 +185,10 @@ function bare_references(message: string): ReadonlyArray<string> {
196
185
  return [...new Set(found)]
197
186
  }
198
187
 
199
- // Every reference the prompt carries, each as written — `#N` or `owner/repo#N` — with none of the
200
- // citation exclusions applied: a number pasted inside a fence or a quote is still the person's.
201
- function prompt_references(prompt: string): ReadonlySet<string> {
202
- const found = new Set<string>()
203
-
204
- for (const match of prompt.matchAll(ISSUE_NUMBER)) {
205
- found.add(repo_prefix(prompt, match.index) + match[0])
206
- }
207
-
208
- return found
209
- }
210
-
211
- // **A number the person's prompt already carried is quoted, not cited**. A
212
- // pasted log from another repository holds its own `#1`…`#7`; `issue:cite` would link them to this
213
- // repository's unrelated Issues, so following the refusal would make the reply wrong. Only the exact
214
- // reference the prompt wrote is exempt, so a bare `#N` the run brought in itself is still refused.
215
- function unquoted_references(message: string, prompt: string): ReadonlyArray<string> {
216
- const quoted = prompt_references(prompt)
217
-
218
- return bare_references(message).filter((reference) => !quoted.has(reference))
219
- }
220
-
221
188
  function has_bare_reference(message: string): boolean {
222
189
  return bare_references(message).length > 0
223
190
  }
224
191
 
225
- // The token `issue:cite` takes for one reference: a qualified `owner/repo#N` is passed as-is, a bare
226
- // `#N` loses its `#` so the command reads `issue:cite 123` rather than `issue:cite #123`.
227
- function cite_argument(reference: string): string {
228
- return reference.startsWith('#') ? reference.slice(1) : reference
229
- }
230
-
231
- function cite_arguments(references: ReadonlyArray<string>): ReadonlyArray<string> {
232
- return references.map((reference) => cite_argument(reference))
233
- }
234
-
235
192
  // One bare reference rewritten as a number-link: `[#N](url)` for a same-repo mention, or
236
193
  // `[owner/repo#N](url)` for a qualified one — the label is the reference exactly as it was written, so
237
194
  // the reader sees the number they would have, now clickable. The URL is `issue-cite`'s own assembly,
@@ -286,11 +243,9 @@ function linkify(message: string, slug: string): string {
286
243
 
287
244
  const issue_citation = {
288
245
  bare_references,
289
- cite_arguments,
290
246
  has_bare_reference,
291
247
  linkify,
292
248
  prose_lines,
293
- unquoted_references,
294
249
  }
295
250
 
296
251
  export { issue_citation }
@@ -28,7 +28,7 @@ const ISSUE_BODY_PATH = /repos\/[^\s'"]*\/issues\/\d+(?=$|["'\s])/u
28
28
  // comments endpoint. The short `-c` is deliberately absent — it belongs to `wc`, `grep` and `sort`
29
29
  // far more often than to `gh`, and reading it as "comments included" silenced the rule on any line
30
30
  // that ended in a pipe. A run that types it pays one round trip instead.
31
- const FETCHES_COMMENTS = /--comments\b|--json\s[\w,]*\bcomments\b|\/comments\b/u
31
+ const FETCHES_COMMENTS = /--comments\b|--json[=\s]['"]?[\w,]*\bcomments\b|\/comments\b/u
32
32
  const ISSUES_PATH = /repos\/[^\s'"]*\/issues\//u
33
33
 
34
34
  // A field projection — `--jq` for `gh api`, `--json` for `gh issue view` — whose value never names the
@@ -38,11 +38,14 @@ const ISSUES_PATH = /repos\/[^\s'"]*\/issues\//u
38
38
  // comma list `--json state,labels` and the expression `'{state, labels}'` are read the same way.
39
39
  const FIELD_PROJECTION = /(?:--jq|--json)[= ]\s*('[^']*'|"[^"]*"|\S+)/u
40
40
  const NAMES_THE_BODY = /\bbody\b/u
41
+ // A projection that names no field at all — `--jq .`, `--jq '.[]'` — passes every field through,
42
+ // the body with them, so it is a body read however it is spelled.
43
+ const NAMES_A_FIELD = /(?:^|[.{,\s'"])[A-Za-z_]/u
41
44
 
42
45
  function projects_away_body(segment: string): boolean {
43
- const projection = FIELD_PROJECTION.exec(segment)
46
+ const value = FIELD_PROJECTION.exec(segment)?.[1]
44
47
 
45
- return projection !== null && !NAMES_THE_BODY.test(projection[1] ?? '')
48
+ return value !== undefined && NAMES_A_FIELD.test(value) && !NAMES_THE_BODY.test(value)
46
49
  }
47
50
 
48
51
  function is_body_read_segment(segment: string): boolean {
@@ -82,7 +85,7 @@ function reads_issue_comments(command: string): boolean {
82
85
  }
83
86
 
84
87
  const RULE_DOC = '`.claude/skills/workflow-commands/issue-comments.md`'
85
- const COMMENTS_FALLBACK = 'gh api repos/{owner}/{repo}/issues/<N>/comments'
88
+ const COMMENTS_FALLBACK = 'gh api repos/<owner>/<repo>/issues/<N>/comments'
86
89
 
87
90
  // **The refusal hands over the command that fixes it**, because reading is not the same as
88
91
  // obeying: a sentence saying "also read the comments" is prose that moves nothing, while a refused
@@ -179,7 +182,9 @@ const issue_comments = {
179
182
  ISSUE_COMMENTS_REASON,
180
183
  ROW,
181
184
  comments_input,
185
+ fetches_issue_comments,
182
186
  is_body_only_issue_read,
187
+ projects_away_body,
183
188
  }
184
189
 
185
190
  export { issue_comments }
@@ -68,7 +68,7 @@ const ROW = {
68
68
  decide: (): boolean => true,
69
69
  about: {
70
70
  title: 'Bare `pnpm josh git`',
71
- topic: '`CLAUDE.md` → Git Rules',
71
+ topic: '`operating-rules.md` → "git-rules"',
72
72
  fires:
73
73
  '`pnpm josh git` without `-y`, whose staging prompt cancels with no TTY. Every occurrence',
74
74
  quiet: '`pnpm josh git -y`',