@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
@@ -18,6 +18,7 @@ import { lane_interactive_ask } from './lane-interactive-ask'
18
18
  import { lane_park } from './lane-park'
19
19
  import { lane_switch_main } from './lane-switch-main'
20
20
  import { oracle_consulted } from './oracle-consulted'
21
+ import { permission_guards } from './permission-guards'
21
22
  import { piped_verification } from './piped-verification'
22
23
  import { poll_loop } from './poll-loop'
23
24
  import { pre_gate_cut } from './pre-gate-cut'
@@ -143,8 +144,10 @@ const { is_issue_filing, on_bash_command } = bash_triggers
143
144
  // exemptions and the three tests that decide the second one. The three tests are spelled out rather
144
145
  // than named, because a delivery that said only "an interrupt is exempt" would hand the deciding back
145
146
  // to judgement at exactly the moment nothing else is open to read (joshuafolkken/kit#1518).
147
+ // `WIP_CAP` is the number's single source; `wip-cap.md` states it once and a test pins the two equal.
148
+ const WIP_CAP = 30
146
149
  const WIP_CAP_REASON =
147
- "⛔ backlog WIP cap: count the target repository's open Issues before filing. With more than 30 " +
150
+ `⛔ backlog WIP cap: count the target repository's open Issues before filing. With more than ${String(WIP_CAP)} ` +
148
151
  'open, close one first; nothing honestly closable means do not file. Two filings are exempt and ' +
149
152
  'proceed while stating the overage — one the run is blocked by, and an interrupt, decided by ' +
150
153
  'three tests rather than judgement: a verification answers wrongly, a documented workflow cannot ' +
@@ -482,6 +485,10 @@ const DELIVERED_RULES: ReadonlyArray<DeliveredRule> = [
482
485
  git_force.ROW,
483
486
  worktree_guard.ROW,
484
487
  file_body.ROW,
488
+ // **The deny-list bypasses closed by argv and path rather than glob** (joshuafolkken/kit#2983) — an
489
+ // index mutation, a recursive forced `rm` or destructive `gh` call, and a protected file. Each
490
+ // claims a command or file no row above does and refuses every occurrence (`permission-guards.ts`).
491
+ ...permission_guards.ROWS,
485
492
  // **The hand-written wait loop a lane child improvises over a backgrounded command's output**
486
493
  // (joshuafolkken/kit#2371). `early-heartbeat` refuses a bare `sleep` and stands down on any loop
487
494
  // keyword; this is the loop it left — a `while`/`until` that sleeps between probes of an output
@@ -788,6 +795,7 @@ const delivered_rules = {
788
795
  SHELL_BODY_REASON,
789
796
  SWITCH_ENV_KEY,
790
797
  THIRD_PARTY_WRITE_REASON: third_party_write.THIRD_PARTY_WRITE_REASON,
798
+ WIP_CAP,
791
799
  WIP_CAP_REASON,
792
800
  WORKTREE_MUTATION_REASON: worktree_guard.WORKTREE_MUTATION_REASON,
793
801
  delivery,
@@ -0,0 +1,119 @@
1
+ import { bash_triggers } from './bash-triggers'
2
+ import { gh_api } from './gh-api'
3
+ import { git_argv } from './git-argv'
4
+ import { shell_segments } from './shell-segments'
5
+
6
+ // The trigger and the delivered text behind the `destructive-command` row of `delivered-rules.ts`
7
+ // (joshuafolkken/kit#2983): a recursive forced `rm`, and the `gh` calls that delete or close shared
8
+ // state — none of which the deny list stopped, or stopped only in one spelling (`Bash(rm -rf *)`
9
+ // misses `rm -fr`, `rm -r -f` and `rm --recursive --force`). The argv is read through `git-argv.ts`'s
10
+ // wrapper cut, so `sudo rm -fr` and `env gh pr close` are seen too.
11
+ //
12
+ // **What is refused is the decision recorded on the Issue, not every destructive act.** `gh issue
13
+ // close` passes — the WIP-cap procedure closes Issues legitimately — and so does removing a label from
14
+ // an Issue (`DELETE repos/<o>/<r>/issues/<N>/labels/<name>`), which the `in-progress` and
15
+ // `needs-decision` steps of the workflow documents issue. Every other `DELETE repos/…` is refused.
16
+ //
17
+ // **It fires on every occurrence**, for the reason `git-force.ts` does.
18
+
19
+ const RM_COMMAND = 'rm'
20
+ const RECURSIVE_LONG = '--recursive'
21
+ const RECURSIVE_LETTERS = 'rR'
22
+ const FORCE_LONG = '--force'
23
+ const FORCE_LETTER = 'f'
24
+
25
+ function has_flag(args: ReadonlyArray<string>, long: string, letters: string): boolean {
26
+ return args.some((argument) => argument === long || git_argv.short_cluster_has(argument, letters))
27
+ }
28
+
29
+ function is_recursive_forced_rm(segment: string): boolean {
30
+ const args = git_argv.arguments_of(segment, RM_COMMAND)
31
+
32
+ if (args === undefined) return false
33
+
34
+ return (
35
+ has_flag(args, RECURSIVE_LONG, RECURSIVE_LETTERS) && has_flag(args, FORCE_LONG, FORCE_LETTER)
36
+ )
37
+ }
38
+
39
+ const GH_COMMAND = 'gh'
40
+ const REPO_GROUP = 'repo'
41
+ const REPO_REMOVALS: ReadonlySet<string> = new Set(['delete', 'archive'])
42
+ const REPO_EDIT = 'edit'
43
+ const VISIBILITY_FLAG = '--visibility'
44
+ const PR_GROUP = 'pr'
45
+ const PR_CLOSE = 'close'
46
+
47
+ // `gh repo delete` / `archive`, and `gh repo edit --visibility …`.
48
+ function is_destructive_repo_action(action: string, args: ReadonlyArray<string>): boolean {
49
+ if (REPO_REMOVALS.has(action)) return true
50
+
51
+ return action === REPO_EDIT && args.some((argument) => argument.startsWith(VISIBILITY_FLAG))
52
+ }
53
+
54
+ function is_destructive_gh_command(args: ReadonlyArray<string>): boolean {
55
+ const [group, action = ''] = args
56
+
57
+ if (group === PR_GROUP) return action === PR_CLOSE
58
+
59
+ return group === REPO_GROUP && is_destructive_repo_action(action, args)
60
+ }
61
+
62
+ const DELETE_METHOD = 'DELETE'
63
+ const REPOSITORY_PATH = 'repos/'
64
+ // Removing one label from one Issue — the workflow's own `in-progress` / `needs-decision` step.
65
+ // Anchored on the whole argument, so a label path smuggled into a field value (`-f x=repos/…/labels/a`)
66
+ // does not exempt the real endpoint beside it.
67
+ const ISSUE_LABEL_PATH =
68
+ /^['"]?\/?repos\/[^/\s'"]+\/[^/\s'"]+\/issues\/\d+\/labels\/[^/\s'"]+['"]?$/u
69
+
70
+ // Judged on the call with its wrapper cut off, since `gh_api.is_gh_api` anchors on a leading `gh` and
71
+ // would otherwise miss `env gh api -X DELETE …` that the `gh pr close` branch already sees. Every
72
+ // argument naming a repository path must be a label removal for the call to pass.
73
+ function is_destructive_api_call(args: ReadonlyArray<string>): boolean {
74
+ const call = [GH_COMMAND, ...args].join(' ')
75
+
76
+ if (!gh_api.is_gh_api(call) || gh_api.method_of(call) !== DELETE_METHOD) return false
77
+
78
+ return args.some(
79
+ (argument) => argument.includes(REPOSITORY_PATH) && !ISSUE_LABEL_PATH.test(argument),
80
+ )
81
+ }
82
+
83
+ function is_destructive_gh(segment: string): boolean {
84
+ const args = git_argv.arguments_of(segment, GH_COMMAND)
85
+
86
+ if (args === undefined) return false
87
+
88
+ return is_destructive_gh_command(args) || is_destructive_api_call(args)
89
+ }
90
+
91
+ function is_destructive_segment(segment: string): boolean {
92
+ return is_recursive_forced_rm(segment) || is_destructive_gh(segment)
93
+ }
94
+
95
+ function is_destructive_command(command: string): boolean {
96
+ return shell_segments.segments_of(command).some((segment) => is_destructive_segment(segment))
97
+ }
98
+
99
+ const DESTRUCTIVE_COMMAND_REASON =
100
+ '⛔ destructive command: a recursive forced `rm` (`rm -rf`, `rm -fr`, `rm -r -f`, `rm --recursive ' +
101
+ '--force`), `gh repo delete` / `archive`, `gh repo edit --visibility`, `gh pr close`, or a `gh api ' +
102
+ '-X DELETE repos/…` call deletes or closes something that cannot be restored, which is Tier C and ' +
103
+ 'needs explicit current-turn user instruction (`prompts/collaboration-workflow/operating-rules.md`). ' +
104
+ 'The `.claude/settings.json` deny list matches prefix globs, so it misses these spellings; this row ' +
105
+ 'reads the argv instead. Remove a file or directory one path at a time without `-f`, or ask the user ' +
106
+ 'to run the command in their own terminal. `gh issue close` and removing a label from an Issue ' +
107
+ '(`DELETE repos/<o>/<r>/issues/<N>/labels/<name>`) are not refused. **This rule fires on every ' +
108
+ 'occurrence, not once per run.**'
109
+
110
+ const ROW = {
111
+ id: 'destructive-command',
112
+ is_trigger: bash_triggers.on_bash_command(is_destructive_command),
113
+ reason: DESTRUCTIVE_COMMAND_REASON,
114
+ decide: (): boolean => true,
115
+ }
116
+
117
+ const destructive_command = { DESTRUCTIVE_COMMAND_REASON, ROW, is_destructive_command }
118
+
119
+ export { destructive_command }
@@ -14,7 +14,7 @@ const DIRECT_FILING_REASON =
14
14
  'lint and its classification labels, the depth and `route:` labels, the `## Origin` check when filing ' +
15
15
  'into another repository, and `epic:bundle` after the create — so none of them is a step to remember. ' +
16
16
  'When the scout prints candidates it holds the filing: read each, then reissue with `--distinct <N,…>` ' +
17
- 'for the ones that are separate deliverables. Reference: `docs/josh-commands.md` → "`josh issue:file`". ' +
17
+ 'for the ones that are separate deliverables. Reference: `docs/josh-commands-automation.md` → "`josh issue:file`". ' +
18
18
  '**This rule fires on every occurrence, not once per run.**'
19
19
 
20
20
  function is_any_filing(command: string): boolean {
@@ -142,9 +142,6 @@ const file_body = {
142
142
  FILE_BODY_REASON,
143
143
  ROW,
144
144
  carries_a_file_body,
145
- is_in_place_perl,
146
- is_interpreter_write,
147
- writes_existing_file,
148
145
  }
149
146
 
150
147
  export { file_body }
@@ -127,8 +127,6 @@ const filing_cap = {
127
127
  FILING_CAP,
128
128
  FILING_CAP_REASON,
129
129
  ROW,
130
- current_turn,
131
- decide,
132
130
  is_prompt_line,
133
131
  prior_filing_count,
134
132
  turn_filing_count,
@@ -40,8 +40,13 @@ function is_gh_api(segment: string): boolean {
40
40
  }
41
41
 
42
42
  // A read is a `GET` — explicit via a method flag, or implicit when no field flag makes it a POST.
43
+ // The explicit `-X` / `--method` value, upper-cased, or `undefined` when the call names none.
44
+ function method_of(segment: string): string | undefined {
45
+ return API_METHOD.exec(segment)?.[1]?.toUpperCase()
46
+ }
47
+
43
48
  function is_read(segment: string): boolean {
44
- const method = API_METHOD.exec(segment)?.[1]
49
+ const method = method_of(segment)
45
50
 
46
51
  if (method !== undefined) return method.toUpperCase() === READ_METHOD
47
52
 
@@ -60,6 +65,6 @@ function repo_target(segment: string): RepoTarget | undefined {
60
65
  return { owner: match[OWNER_GROUP] ?? '', repo: match[REPO_GROUP] ?? '' }
61
66
  }
62
67
 
63
- const gh_api = { GH_API_COMMAND, GH_FLAGS, is_gh_api, is_read, is_write, repo_target }
68
+ const gh_api = { GH_FLAGS, is_gh_api, is_read, is_write, method_of, repo_target }
64
69
 
65
70
  export { gh_api }
@@ -12,8 +12,9 @@
12
12
  // arguments is what makes the judgement independent of the spelling.
13
13
 
14
14
  // The wrapper words that may stand in front of `git`, the same ones `run-tail.ts` skips in front of
15
- // `josh`: environment assignments, the package-manager launchers, `sudo`, and an opening subshell
16
- // parenthesis. Left in, `sudo git push --force` and `(git push -f)` are silently not a git command.
15
+ // `josh`: environment assignments, the package-manager launchers, `sudo`, `env`, and an opening
16
+ // subshell parenthesis. Left in, `sudo git push --force`, `env git commit` and `(git push -f)` are
17
+ // silently not a git command (joshuafolkken/kit#2983).
17
18
  const ENV_ASSIGNMENT = /^[A-Za-z_]\w*=/u
18
19
  const WRAPPER_WORDS: ReadonlySet<string> = new Set([
19
20
  'pnpm',
@@ -22,6 +23,7 @@ const WRAPPER_WORDS: ReadonlySet<string> = new Set([
22
23
  'run',
23
24
  'sudo',
24
25
  'command',
26
+ 'env',
25
27
  ])
26
28
  const SUBSHELL_OPEN = '('
27
29
 
@@ -92,17 +94,26 @@ function after_globals(words: ReadonlyArray<string>, start: number): number {
92
94
  return index
93
95
  }
94
96
 
97
+ // The words after `command` once the wrapper is skipped, or `undefined` when the segment does not
98
+ // invoke it. `gh` and `rm` are judged by the same wrapper cut as `git` (joshuafolkken/kit#2983), so
99
+ // `env gh pr close` and `sudo rm -rf` are read as the calls they are.
100
+ function arguments_of(segment: string, command: string): Array<string> | undefined {
101
+ const words = words_of(segment)
102
+ const command_index = after_wrapper(words)
103
+
104
+ return words[command_index] === command ? words.slice(command_index + NEXT) : undefined
105
+ }
106
+
95
107
  // The subcommand and the arguments after it, or `undefined` when the segment is not a git invocation.
96
108
  // **`pnpm josh git` is deliberately not one**: the word after the wrapper is `josh`, not `git`, so a
97
109
  // run's own authorized `pnpm josh git -y` push is invisible here — which is exactly what keeps this row
98
110
  // off the node route the deny list already leaves alone.
99
111
  function parse(segment: string): GitCall | undefined {
100
- const words = words_of(segment)
101
- const git_index = after_wrapper(words)
112
+ const words = arguments_of(segment, GIT_COMMAND)
102
113
 
103
- if (words[git_index] !== GIT_COMMAND) return undefined
114
+ if (words === undefined) return undefined
104
115
 
105
- const subcommand_index = after_globals(words, git_index + NEXT)
116
+ const subcommand_index = after_globals(words, 0)
106
117
 
107
118
  return { subcommand: words[subcommand_index], args: words.slice(subcommand_index + NEXT) }
108
119
  }
@@ -124,6 +135,6 @@ function short_cluster_has(token: string, letters: string): boolean {
124
135
  return false
125
136
  }
126
137
 
127
- const git_argv = { parse, short_cluster_has, words_of }
138
+ const git_argv = { arguments_of, parse, short_cluster_has }
128
139
 
129
140
  export { git_argv }
@@ -96,9 +96,7 @@ const ROW = {
96
96
  const git_force = {
97
97
  GIT_FORCE_REASON,
98
98
  ROW,
99
- is_branch_delete,
100
99
  is_force_or_delete,
101
- is_force_or_delete_push,
102
100
  }
103
101
 
104
102
  export { git_force }
@@ -50,7 +50,7 @@ function is_impl_cut_segment(segment: string): boolean {
50
50
  }
51
51
 
52
52
  // Whether this command takes the implementation-phase cut, segment-wise so a spelling quoted inside a
53
- // body is not read as the call, and alias-expanded so `pnpm josh rct --impl` is the same call.
53
+ // body is not read as the call.
54
54
  function takes_the_impl_cut(command: string): boolean {
55
55
  return shell_segments.segments_of(command).some((segment) => is_impl_cut_segment(segment))
56
56
  }
@@ -224,7 +224,6 @@ const implementation_cut = {
224
224
  REISSUE_WINDOW_MS,
225
225
  ROW,
226
226
  decide,
227
- is_edit_tool,
228
227
  is_over_threshold_edit,
229
228
  is_reissued_refusal,
230
229
  takes_the_impl_cut,
@@ -0,0 +1,71 @@
1
+ import { bash_triggers } from './bash-triggers'
2
+ import { git_argv } from './git-argv'
3
+ import { shell_segments } from './shell-segments'
4
+ import { worktree_guard } from './worktree-guard'
5
+
6
+ // The trigger and the delivered text behind the `index-mutation` row of `delivered-rules.ts`
7
+ // (joshuafolkken/kit#2983). `CLAUDE.md` → Git Rules forbids staging or otherwise mutating the git index
8
+ // on the run's own judgement, and `.claude/settings.json` backs it with `Bash(git add*)` /
9
+ // `Bash(git commit*)` and their siblings — but those are prefix globs, so `git -C . commit`,
10
+ // `git -c k=v commit` and `env git commit` all pass them. Reading the argv through `git-argv.ts`, the
11
+ // cut `git-force.ts` already uses, is what makes the judgement independent of the spelling.
12
+ //
13
+ // **The scope is accident prevention, not a sandbox.** Under `bypassPermissions` with `Bash(*)` a run
14
+ // that means to get round the guard can always do so through `python -c` or a script; the decision
15
+ // recorded on the Issue is to stop the variant spellings a run types by accident. The authorized
16
+ // commit flow is `pnpm josh git -y`, which spawns git in a child process this hook never sees.
17
+ //
18
+ // **It fires on every occurrence**, for the reason `git-force.ts` does: overwriting the user's
19
+ // staged snapshot is destructive each time it is issued.
20
+
21
+ // The subcommands that write the index outright. `stage` is `add`'s synonym; `rm` and `mv` stage the
22
+ // removal or rename they make.
23
+ const INDEX_SUBCOMMANDS: ReadonlySet<string> = new Set([
24
+ 'add',
25
+ 'commit',
26
+ 'mv',
27
+ 'reset',
28
+ 'rm',
29
+ 'stage',
30
+ ])
31
+ const RESTORE_SUBCOMMAND = 'restore'
32
+
33
+ // A `git restore` that touches only the index (`--staged` / `-S` without `--worktree` / `-W`). One that
34
+ // touches the working tree is the `worktree-mutation` row's, so the two rows never claim one command.
35
+ function is_index_restore(args: ReadonlyArray<string>): boolean {
36
+ return !worktree_guard.touches_worktree(args)
37
+ }
38
+
39
+ function is_index_segment(segment: string): boolean {
40
+ const call = git_argv.parse(segment)
41
+
42
+ if (call === undefined) return false
43
+ if (INDEX_SUBCOMMANDS.has(call.subcommand ?? '')) return true
44
+
45
+ return call.subcommand === RESTORE_SUBCOMMAND && is_index_restore(call.args)
46
+ }
47
+
48
+ function is_index_mutation(command: string): boolean {
49
+ return shell_segments.segments_of(command).some((segment) => is_index_segment(segment))
50
+ }
51
+
52
+ const INDEX_MUTATION_REASON =
53
+ '⛔ git index mutation: `git add` / `stage` / `commit` / `reset` / `rm` / `mv` and `git restore ' +
54
+ "--staged` overwrite the user's staged snapshot, which `CLAUDE.md` → Git Rules forbids on your own " +
55
+ 'judgement (`prompts/collaboration-workflow/operating-rules.md` → "git index を勝手に変更しない"). The ' +
56
+ '`.claude/settings.json` deny list matches prefix globs, so it misses `git -C . commit`, `git -c ' +
57
+ 'k=v commit` and `env git commit`; this row reads the argv instead, so the spelling does not matter. ' +
58
+ 'A commit goes through `pnpm josh git -y`; any other staging needs explicit current-turn user ' +
59
+ 'instruction, run by the user in their own terminal. **This rule fires on every occurrence, not once ' +
60
+ 'per run.**'
61
+
62
+ const ROW = {
63
+ id: 'index-mutation',
64
+ is_trigger: bash_triggers.on_bash_command(is_index_mutation),
65
+ reason: INDEX_MUTATION_REASON,
66
+ decide: (): boolean => true,
67
+ }
68
+
69
+ const index_guard = { INDEX_MUTATION_REASON, ROW, is_index_mutation }
70
+
71
+ export { index_guard }
@@ -34,10 +34,23 @@ const REFERENCE_BOUNDARY = /[\s#()[\]<>|]/u
34
34
  // `issue:cite`'s parser accepts. A path-like run (`src/lib`, `a/b/c`) is not one, so it is not emitted
35
35
  // as a prefix that would make the suggested `issue:cite` call refuse the very reference it names.
36
36
  const OWNER_REPO = /^[^\s/#]+\/[^\s/#]+$/u
37
- // A markdown link, with its text captured as group 1: `[text](target)`. Each class excludes *both*
38
- // of its delimiters — no `[`/`]` in the text, no `(`/`)` in the target — so neither star is ambiguous
39
- // against a nested bracket and there is nothing to backtrack.
40
- const MARKDOWN_LINK = /\[([^[\]]*)\]\([^()]*\)/gu
37
+ // A markdown link: `[text](target)`. Each class excludes *both* of its delimiters — no `[`/`]` in the
38
+ // text, no `(`/`)` in the target — so neither star is ambiguous against a nested bracket and there is
39
+ // nothing to backtrack.
40
+ const MARKDOWN_LINK = /\[[^[\]]*\]\([^()]*\)/gu
41
+ // What continues a `#N` into something longer, read off the two characters after its last digit: a
42
+ // word character (a hex color, `#1e90ff`) or a hyphen and a letter (a heading anchor, `#12-setup`) —
43
+ // never an Issue number (joshuafolkken/kit#2995). A hyphen before a digit or `#` is a range
44
+ // (`#12-#15`, `#3-5`), whose first number is still a citation.
45
+ const NUMBER_CONTINUATION = /^(?:\w|-[a-z])/iu
46
+ // The width of the window `NUMBER_CONTINUATION` reads: a hyphen and the letter after it.
47
+ const CONTINUATION_WIDTH = 2
48
+ // What, in the run of non-boundary characters before a `#N`, glues it into a longer token: the `&` of
49
+ // an HTML entity (`&#39;`), the `.` of a file fragment (`README.md#12`), the `/` of a path or URL
50
+ // fragment (`src/lib/x#5`, `example.com/#12`). Any other lead leaves it a citation — a repository
51
+ // without its owner (`kit#12`), a verb (`fixes#12`), prose in a non-Latin script or emphasis
52
+ // (`**#12**`) is a slip all the same. A well-formed `owner/repo#N` is read off `repo_prefix` first.
53
+ const GLUED_LEAD = /[&./]/u
41
54
  // A fenced-code delimiter line: three or more backticks or tildes after optional indentation — both
42
55
  // delimiters CommonMark allows. Toggling on each one brackets the fenced block, so a `closes #N` shown
43
56
  // in a `gh api` example never reads as a slip whichever fence the reply drew it with.
@@ -53,27 +66,34 @@ const PR_PREFIX = /\b(?:pr|pull request)\s*$/iu
53
66
  // sits inside a span.
54
67
  const BACKTICK_PAIR = 2
55
68
 
56
- // Whether a markdown link's *text* span — between the `[` and the `]`, never its `(target)` — covers
57
- // `index`. A `#N` inside the text is the approved `[#N](url)` citation; one in the target is not
58
- // reachable, since an issues URL carries no `#N`.
59
- function text_span_covers(link: RegExpMatchArray, index: number): boolean {
60
- const start = (link.index ?? 0) + 1
61
- const end = start + (link[1] ?? '').length
69
+ // Whether a markdown link covers `index`, text or target alike. A `#N` in the text is the approved
70
+ // `[#N](url)` citation; one in the target is a page fragment (`[setup](#12)`), not an Issue.
71
+ function link_covers(link: RegExpMatchArray, index: number): boolean {
72
+ const start = link.index ?? 0
62
73
 
63
- return index >= start && index < end
74
+ return index >= start && index < start + link[0].length
64
75
  }
65
76
 
66
- // The line is searched for a link whose text span covers this index, so `see [#12](url) and #34`
67
- // reads the first as linked and the second as bare. The scan is line-based (`is_bare_at` passes one
68
- // line), so a link and the `#N` it wraps must sit on the same line — which they always do.
77
+ // The line is searched for a link covering this index, so `see [#12](url) and #34` reads the first as
78
+ // linked and the second as bare. The scan is line-based (`is_bare_at` passes one line), so a link and
79
+ // the `#N` it wraps must sit on the same line — which they always do.
69
80
  function is_linked_at(line: string, index: number): boolean {
70
81
  for (const link of line.matchAll(MARKDOWN_LINK)) {
71
- if (text_span_covers(link, index)) return true
82
+ if (link_covers(link, index)) return true
72
83
  }
73
84
 
74
85
  return false
75
86
  }
76
87
 
88
+ // The run of non-boundary characters that ends at the `#` — what `repo_prefix` keeps when it is an
89
+ // `owner/repo` and `is_glued` weighs when it is not.
90
+ function lead_token(message: string, hash_index: number): string {
91
+ let start = hash_index
92
+ while (start > 0 && !REFERENCE_BOUNDARY.test(message.charAt(start - 1))) start -= 1
93
+
94
+ return message.slice(start, hash_index)
95
+ }
96
+
77
97
  // **The message text alone, never a GitHub-bound artifact.** An Issue body or comment is passed to
78
98
  // `gh` as a `Bash` argument, not spoken in `last_assistant_message`, so those never reach here — which
79
99
  // is exactly the "silent on GitHub-bound artifacts" behavior the issue asks for, obtained by what the
@@ -83,10 +103,7 @@ function is_linked_at(line: string, index: number): boolean {
83
103
  // non-boundary characters ending at the `#`, kept only when it holds a `/`. Read backwards a
84
104
  // character at a time so a repository name of any length costs its own length and no more.
85
105
  function repo_prefix(message: string, hash_index: number): string {
86
- let start = hash_index
87
- while (start > 0 && !REFERENCE_BOUNDARY.test(message.charAt(start - 1))) start -= 1
88
-
89
- const token = message.slice(start, hash_index)
106
+ const token = lead_token(message, hash_index)
90
107
 
91
108
  return OWNER_REPO.test(token) ? token : ''
92
109
  }
@@ -115,17 +132,25 @@ interface LineReference {
115
132
  text: string
116
133
  }
117
134
 
118
- // The bare references on one line, in order — the excluded mentions (linked, inline-code, PR) already
119
- // dropped by `is_bare_at`, so a caller acts on citations alone.
135
+ // Whether the `#N` is part of a longer token rather than an Issue number of its own — continued past
136
+ // its digits, or led by an entity, file or path run (`GLUED_LEAD`) that is not an `owner/repo`.
137
+ function is_glued(line: string, reference: LineReference): boolean {
138
+ const end = reference.index + reference.text.length
139
+
140
+ if (NUMBER_CONTINUATION.test(line.slice(end, end + CONTINUATION_WIDTH))) return true
141
+
142
+ return reference.prefix === '' && GLUED_LEAD.test(lead_token(line, reference.index))
143
+ }
144
+
145
+ // The bare references on one line, in order — the glued tokens (`is_glued`) and the excluded mentions
146
+ // (linked, inline-code, PR, `is_bare_at`) already dropped, so a caller acts on citations alone.
120
147
  function line_references(line: string): ReadonlyArray<LineReference> {
121
148
  const references: Array<LineReference> = []
122
149
 
123
150
  for (const match of line.matchAll(ISSUE_NUMBER)) {
124
- const { index } = match
151
+ const reference = { index: match.index, prefix: repo_prefix(line, match.index), text: match[0] }
125
152
 
126
- if (is_bare_at(line, index)) {
127
- references.push({ index, prefix: repo_prefix(line, index), text: match[0] })
128
- }
153
+ if (!is_glued(line, reference) && is_bare_at(line, match.index)) references.push(reference)
129
154
  }
130
155
 
131
156
  return references
@@ -21,8 +21,7 @@ import { tail_commands } from './tail-commands'
21
21
  // "fold first". **No new predicate**: the filing trigger is `bash_triggers.is_issue_filing`, and the
22
22
  // prior-filing count is `filing_cap.prior_filing_count`, both reused verbatim.
23
23
 
24
- // `pnpm josh issue:fold`, the one act the rule asks for. The alias `isf` is expanded where the command
25
- // is read, so the canonical name matches both spellings.
24
+ // `pnpm josh issue:fold`, the one act the rule asks for.
26
25
  const FOLD_NAMES: ReadonlySet<string> = new Set(['issue:fold'])
27
26
 
28
27
  // Keeping the rule: a call that runs the fold. Segment-wise, so a spelling quoted inside a filing's
@@ -20,7 +20,13 @@ import { run_tail } from './run-tail'
20
20
  //
21
21
  // **So the refusal is put at the launch, and it names the detached route.** The region from the gate to
22
22
  // the merge belongs to `pnpm josh ship --detach` in a child (`chain-rule.md` step 0), whose supervisor
23
- // outlives the turn. `ship` itself is not in the set: #2457 already detaches it implicitly in a child.
23
+ // outlives the turn.
24
+ //
25
+ // **`ship` is in the set too, `--detach` or not** (joshuafolkken/kit#3027). #2457 detaches it in a child,
26
+ // but only after its preflight — the scoped checks — has passed in the calling process, so a
27
+ // backgrounded `ship` is killed at the turn's end before any supervisor exists: the #3022 child did
28
+ // exactly that and was parked as a failure. Issued in the foreground it returns at `launched` within the
29
+ // tool timeout, and the supervisor carries the rest.
24
30
  //
25
31
  // **Its stop-time half reads the same fact from the other side.** A backgrounded task the transcript
26
32
  // launched but never saw finish is still running, and in a child the stop about to happen kills it —
@@ -30,7 +36,7 @@ import { run_tail } from './run-tail'
30
36
  // The josh subcommands that run long enough to be backgrounded, as `time_shell` names them — canonical,
31
37
  // so the `ga` / `g` / `fu` aliases are covered by the one spelling.
32
38
  const LONG_RUNNING_COMMANDS: ReadonlySet<string> = new Set(
33
- ['gate', 'git', 'followup'].map((name) => `${time_shell.JOSH_PREFIX}${name}`),
39
+ ['gate', 'git', 'followup', 'ship'].map((name) => `${time_shell.JOSH_PREFIX}${name}`),
34
40
  )
35
41
 
36
42
  const BACKGROUND_KEY = 'run_in_background'
@@ -92,11 +98,13 @@ function pending_agent_ids(tail: string): ReadonlyArray<string> {
92
98
  const LANE_BACKGROUND_REASON =
93
99
  '⛔ lane background: this session is a dispatched lane child (`JOSH_LANE_CHILD`), a headless ' +
94
100
  '`claude -p` process whose background Bash tasks are killed when the turn ends — so a backgrounded ' +
95
- '`josh gate` / `josh git` / `josh followup` never re-invokes you; it dies at `exit code 143` ' +
96
- '(joshuafolkken/kit#2704, measured on the #2606 child: implementation, review and live verification ' +
97
- 'done, the run parked instead of merged). Hand the gate-to-merge region to the detached supervisor ' +
98
- 'instead: `pnpm josh ship --detach --review "<title> #<N>"` (add `--cite <N>`), then end the turn on ' +
99
- '`launched` / `busy` — `.claude/skills/workflow-commands/chain-rule.md` step 0 is the single source. A ' +
101
+ '`josh gate` / `josh git` / `josh followup` / `josh ship` never re-invokes you; it dies at `exit code ' +
102
+ '143` (joshuafolkken/kit#2704, measured on the #2606 child: implementation, review and live ' +
103
+ 'verification done, the run parked instead of merged). Hand the gate-to-merge region to the detached ' +
104
+ 'supervisor instead: `pnpm josh ship --detach --review "<title> #<N>"` (add `--cite <N>`) issued in ' +
105
+ 'the foreground — its preflight runs in this process before the supervisor exists, so a backgrounded ' +
106
+ '`ship` dies with the turn (joshuafolkken/kit#3027) — then end the turn on `launched` / `busy`. ' +
107
+ '`.claude/skills/workflow-commands/chain-rule.md` step 0 is the single source. A ' +
100
108
  'single check you must read before continuing runs in the foreground within the tool timeout; the ' +
101
109
  'commit-push step does not — in a child it too belongs to the detached ship, in either spelling. This ' +
102
110
  'rule fires on every occurrence, not once per run.'
@@ -29,8 +29,7 @@ import { shell_segments } from './shell-segments'
29
29
 
30
30
  // The parent backlogrun budget/ownership commands. A child never runs either: `run:carry` begins and
31
31
  // advances the run budget the parent owns, and `run:merge` counts a returned child into it. Named in
32
- // canonical form only — `shell_segments.is_josh_command` canonicalizes an alias (`rc`, `rmg`) before
33
- // the match, so `pnpm josh rmg` arrives as `run:merge`.
32
+ // canonical form only — `shell_segments.is_josh_command` canonicalizes an alias before the match.
34
33
  const RUN_BUDGET_COMMANDS: ReadonlySet<string> = new Set(['run:merge', 'run:carry'])
35
34
 
36
35
  // A segment that invokes one of the parent's budget commands. Segment-wise and alias-expanded for the
@@ -1,5 +1,6 @@
1
- import { NEEDS_DECISION_LABEL } from '#scripts/git/issue-labels'
1
+ import { NEEDS_DECISION_LABEL } from '#scripts/issue/issue-labels'
2
2
  import { lane_child_marker } from '#scripts/lane/lane-child-marker'
3
+ import { lane_handoff } from '#scripts/lane/lane-handoff'
3
4
  import { shell_segments } from './shell-segments'
4
5
 
5
6
  // A dispatched lane child records its park before it stops, delivered at the call it binds on
@@ -30,8 +31,7 @@ import { shell_segments } from './shell-segments'
30
31
  // the stop, the reason is a checklist rather than an accusation, and a child that already parked simply
31
32
  // reissues. One wasted round trip on the compliant path is the safe direction; a missed park is not.
32
33
 
33
- // `josh notify`, in either spelling — the alias `nf` is expanded to `notify` before this sees it, the
34
- // same way `pre-gate-cut.ts` matches `gate` through `ga`.
34
+ // `josh notify`, named canonically — `shell_segments.is_josh_command` expands an alias before the match.
35
35
  const NOTIFY_COMMANDS: ReadonlySet<string> = new Set(['notify'])
36
36
  // The task type that marks a stop waiting on a person, taken quoted or bare so `--task-type
37
37
  // confirmation` and `--task-type=confirmation` read alike. A `progress` or `pr` notification is not a
@@ -71,13 +71,18 @@ function mentions_confirmation_notify(text: string): boolean {
71
71
  // confirmation stop, not on every `Bash` call in the run. `is_child_of` is the same mechanical
72
72
  // human-or-child fact the pre-gate cut reads: a person working in a lane carries no mark and sees no
73
73
  // refusal, and a mark that leaked in naming another issue is read as a person too.
74
- function is_unparked_stop(
75
- command: string,
76
- is_lane_child: boolean = lane_child_marker.is_child_of(process.cwd()),
77
- ): boolean {
74
+ //
75
+ // **A child that handed its region to the detached ship is not parking** (joshuafolkken/kit#2962): its
76
+ // stop waits on nobody, so the park checklist is the wrong advice. `lane_handoff.is_handed_off` is the
77
+ // reading the `Stop` hook stands its notify demand down on, so the two hooks cannot disagree.
78
+ function is_parking_child(directory: string = process.cwd()): boolean {
79
+ return lane_child_marker.is_child_of(directory) && !lane_handoff.is_handed_off(directory)
80
+ }
81
+
82
+ function is_unparked_stop(command: string, is_child: () => boolean = is_parking_child): boolean {
78
83
  if (!is_confirmation_notify(command)) return false
79
84
 
80
- return is_lane_child
85
+ return is_child()
81
86
  }
82
87
 
83
88
  // **Keeping this rule is applying `needs-decision`**, the one act the park asks for before the stop.
@@ -114,6 +119,7 @@ const LANE_PARK_REASON =
114
119
  const lane_park = {
115
120
  LANE_PARK_REASON,
116
121
  is_confirmation_notify,
122
+ is_parking_child,
117
123
  is_unparked_stop,
118
124
  mentions_confirmation_notify,
119
125
  records_the_park,
@@ -20,6 +20,7 @@ const WORKFLOW_KEYWORDS: ReadonlySet<string> = new Set([
20
20
  'kickoff',
21
21
  'fullrun',
22
22
  'halfrun',
23
+ 'prrun',
23
24
  'backlogrun',
24
25
  ])
25
26
  const NO_PROMPT = ''
@@ -76,6 +76,6 @@ const ROWS: ReadonlyArray<DeliveredRule> = oracle_firing
76
76
  .firing_oracles()
77
77
  .map(({ oracle, firing_point }) => row_for(oracle, firing_point))
78
78
 
79
- const oracle_consulted = { ROWS, command_line, reason_for, row_for, runs_the_oracle }
79
+ const oracle_consulted = { ROWS, reason_for }
80
80
 
81
81
  export { oracle_consulted }
@@ -99,6 +99,7 @@ const NOT_NAMED: ReadonlyMap<string, string> = new Map([
99
99
  ['epic:next', READ],
100
100
  ['run:merge', PHASE],
101
101
  ['run:step', SELF],
102
+ ['run:entry', SELF],
102
103
  ['refactor:scan', PHASE],
103
104
  ['split:assess', PHASE],
104
105
  ['sonar:hotspots', READ],