@joshuafolkken/kit 1.1050.0 → 1.1128.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (630) hide show
  1. package/.claude/settings.json +9 -8
  2. package/.claude/skills/epic-commands/SKILL.md +5 -7
  3. package/.claude/skills/workflow-commands/SKILL.md +20 -12
  4. package/.claude/skills/workflow-commands/background-commands.md +36 -84
  5. package/.claude/skills/workflow-commands/backlogrun-child.md +1 -1
  6. package/.claude/skills/workflow-commands/backlogrun-lanes.md +8 -6
  7. package/.claude/skills/workflow-commands/backlogrun-progress.md +30 -33
  8. package/.claude/skills/workflow-commands/backlogrun-steps.md +12 -12
  9. package/.claude/skills/workflow-commands/backlogrun.md +2 -2
  10. package/.claude/skills/workflow-commands/chain-rule.md +4 -2
  11. package/.claude/skills/workflow-commands/delegation.md +3 -3
  12. package/.claude/skills/workflow-commands/followup-reference.md +1 -1
  13. package/.claude/skills/workflow-commands/followup.md +7 -3
  14. package/.claude/skills/workflow-commands/fullrun-steps.md +3 -2
  15. package/.claude/skills/workflow-commands/fullrun.md +8 -6
  16. package/.claude/skills/workflow-commands/halfrun.md +19 -21
  17. package/.claude/skills/workflow-commands/issue-comments.md +1 -1
  18. package/.claude/skills/workflow-commands/issue-fold-existing.md +10 -10
  19. package/.claude/skills/workflow-commands/issue-scout.md +1 -1
  20. package/.claude/skills/workflow-commands/kickoff.md +9 -4
  21. package/.claude/skills/workflow-commands/latest-gate.md +8 -16
  22. package/.claude/skills/workflow-commands/needs-human-review.md +1 -1
  23. package/.claude/skills/workflow-commands/observation-filing.md +3 -3
  24. package/.claude/skills/workflow-commands/pre-gate-cut.md +4 -8
  25. package/.claude/skills/workflow-commands/prerequisite.md +1 -1
  26. package/.claude/skills/workflow-commands/prrun.md +36 -0
  27. package/.claude/skills/workflow-commands/retrospective.md +1 -1
  28. package/.claude/skills/workflow-commands/split-assessment.md +4 -18
  29. package/.claude/skills/workflow-commands/working-tree-hold.md +22 -2
  30. package/.codex/hooks.json +16 -20
  31. package/.github/actions/setup-node/action.yml +33 -0
  32. package/.github/actions/setup-pnpm/action.yml +93 -0
  33. package/.github/dependabot.yml +5 -1
  34. package/.github/workflows/auto-tag.yml +2 -3
  35. package/.github/workflows/ci.yml +31 -134
  36. package/.github/workflows/dependabot-auto-merge.yml +1 -0
  37. package/.github/workflows/pr-classification.yml +6 -44
  38. package/.github/workflows/production.yml +1 -0
  39. package/.github/workflows/publish.yml +43 -47
  40. package/.github/workflows/sonar-qube.yml +41 -4
  41. package/.pnpmfile.mjs +29 -0
  42. package/AGENTS.md +5 -2
  43. package/CLAUDE.md +33 -27
  44. package/GEMINI.md +5 -2
  45. package/README.md +66 -20
  46. package/SECURITY.md +37 -6
  47. package/cspell/index.yaml +6 -1
  48. package/dist/CLAUDE.basic.md +6 -6
  49. package/dist/CLAUDE.md +33 -27
  50. package/dist/CLAUDE.static.md +6 -6
  51. package/dist/config-merge/index.js +48 -12
  52. package/dist/hooks/batch-guard.js +4 -4
  53. package/dist/hooks/{chunk-7VPDUBRN.js → chunk-4JZDP5X5.js} +152 -155
  54. package/dist/hooks/{chunk-HJIISEAC.js → chunk-5SD2YM7Z.js} +5 -13
  55. package/dist/hooks/{chunk-NAS4C7GP.js → chunk-77J7IEQM.js} +2 -2
  56. package/dist/hooks/{chunk-DMQN45FN.js → chunk-7HVB7SZG.js} +3 -3
  57. package/dist/hooks/{chunk-RLDX5SOC.js → chunk-AIOIOMPX.js} +4413 -1970
  58. package/dist/hooks/{chunk-5BK3K7V4.js → chunk-M7QKEKWO.js} +873 -2049
  59. package/dist/hooks/{chunk-WQ4OSBSS.js → chunk-MKVGBQPA.js} +2 -2
  60. package/dist/hooks/{chunk-EJDX2TOB.js → chunk-NXYMNPUQ.js} +7 -88
  61. package/dist/hooks/{chunk-NJQOBE6L.js → chunk-QVLT52OV.js} +2 -7
  62. package/dist/hooks/{chunk-GQ7KP45M.js → chunk-XYUIQOW3.js} +2 -2
  63. package/dist/hooks/codex-hook-adapter.js +12 -48
  64. package/dist/hooks/duplicate-read-guard.js +5 -5
  65. package/dist/hooks/format-edited.js +2 -2
  66. package/dist/hooks/inputs.json +280 -0
  67. package/dist/hooks/investigation-guard.js +5 -5
  68. package/dist/hooks/pretool-guard.js +9 -9
  69. package/dist/hooks/session-lang.js +0 -1
  70. package/dist/hooks/stop-guard.js +192 -333
  71. package/dist/josh.js +240 -148
  72. package/dist/managed-marker/index.js +2 -1
  73. package/dist/version/index.js +70 -78
  74. package/eslint/rules/promise.js +5 -0
  75. package/eslint/rules/unicorn.js +3 -2
  76. package/package.json +26 -5
  77. package/pnpm-workspace.yaml +5 -7
  78. package/prompts/collaboration-workflow/glossary.md +17 -0
  79. package/prompts/collaboration-workflow/issue-citation.md +5 -5
  80. package/prompts/collaboration-workflow/issue-template.md +1 -1
  81. package/prompts/collaboration-workflow/operating-rules.md +5 -5
  82. package/prompts/collaboration-workflow/overview.md +13 -1
  83. package/prompts/collaboration-workflow/principles.md +9 -0
  84. package/prompts/collaboration-workflow/report-format.md +1 -1
  85. package/prompts/collaboration-workflow/residency.md +3 -3
  86. package/prompts/collaboration-workflow/rule-delivery.md +1 -1
  87. package/prompts/collaboration-workflow/turn-batching.md +3 -3
  88. package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
  89. package/prompts/collaboration-workflow/wip-cap.md +25 -22
  90. package/prompts/collaboration-workflow.md +6 -8
  91. package/prompts/review-rubric.md +1 -1
  92. package/prompts/review.md +3 -3
  93. package/prompts/sonar-hotspot-handling.md +11 -3
  94. package/prompts/testing-guide.md +3 -3
  95. package/scripts/adopt/adopt-toolkits.ts +0 -2
  96. package/scripts/adopt/adopt.ts +0 -2
  97. package/scripts/agent/agent-argv.ts +0 -2
  98. package/scripts/agent/agent-diagnostics.ts +1 -1
  99. package/scripts/agent/agent-role-profile.ts +0 -7
  100. package/scripts/agent/claude-agent-argv.ts +0 -2
  101. package/scripts/agent/codex-agent-argv.ts +1 -1
  102. package/scripts/agent/codex-hooks.ts +92 -0
  103. package/scripts/agent/interactive-ask.ts +1 -1
  104. package/scripts/auto-ok/auto-ok-cli.ts +6 -16
  105. package/scripts/backlog/backlog-arrival.ts +30 -10
  106. package/scripts/backlog/backlog-budget-cli.ts +15 -16
  107. package/scripts/backlog/backlog-budget.ts +0 -2
  108. package/scripts/backlog/backlog-defect-priority.ts +2 -2
  109. package/scripts/backlog/backlog-drive-cli.ts +10 -8
  110. package/scripts/backlog/backlog-drive-named-offer.ts +16 -3
  111. package/scripts/backlog/backlog-drive-named.ts +2 -1
  112. package/scripts/backlog/backlog-drive.ts +76 -16
  113. package/scripts/backlog/backlog-named.ts +0 -3
  114. package/scripts/backlog/backlog-next.ts +9 -15
  115. package/scripts/backlog/backlog-offer-cli.ts +6 -19
  116. package/scripts/backlog/backlog-plan-cli.ts +1 -7
  117. package/scripts/backlog/backlog-plan.ts +30 -19
  118. package/scripts/backlog/backlog-pool.ts +3 -6
  119. package/scripts/backlog/backlog-rank.ts +2 -2
  120. package/scripts/backlog/backlog-ready.ts +39 -10
  121. package/scripts/backlog/backlog-scope.ts +1 -3
  122. package/scripts/backlog/backlog-stalled-detect.ts +2 -2
  123. package/scripts/backlog/backlog-stalled.ts +0 -1
  124. package/scripts/backlog/backlog-waves.ts +5 -2
  125. package/scripts/behavior/behavior-cli.ts +1 -1
  126. package/scripts/build/build-codex-hooks.ts +26 -0
  127. package/scripts/build/build-hooks.ts +85 -9
  128. package/scripts/build/hook-bundle-stamp.ts +111 -0
  129. package/scripts/cases/cases-cli.ts +1 -1
  130. package/scripts/cases/cases-logic.ts +1 -1
  131. package/scripts/ci/composite-actions.ts +30 -0
  132. package/scripts/ci/pr-classification.ts +3 -3
  133. package/scripts/claude/workflow-destination.ts +10 -1
  134. package/scripts/clone/clone-fingerprint.ts +0 -1
  135. package/scripts/clone/clone-scan-cli.ts +1 -1
  136. package/scripts/clone/clone-scan.ts +1 -1
  137. package/scripts/config-merge/json-format.ts +0 -1
  138. package/scripts/config-merge/parse-jsonc.ts +33 -3
  139. package/scripts/config-merge/patch-json-key.ts +13 -6
  140. package/scripts/config-merge/patch-yaml-list.ts +1 -1
  141. package/scripts/cost-runtime/codex-usage.ts +2 -9
  142. package/scripts/cost-runtime/cost-attribute.ts +0 -1
  143. package/scripts/cost-runtime/cost-cli.ts +3 -10
  144. package/scripts/cost-runtime/cost-corpus.ts +0 -2
  145. package/scripts/cost-runtime/cost-format.ts +0 -3
  146. package/scripts/cost-runtime/cost-pricing.ts +0 -1
  147. package/scripts/cost-runtime/cost-tokens.ts +0 -1
  148. package/scripts/delegation/delegation-cli.ts +1 -1
  149. package/scripts/delegation/delegation-policy.ts +0 -1
  150. package/scripts/delegation/duplicate-read-guard.ts +0 -8
  151. package/scripts/delegation/fanout-cli.ts +1 -1
  152. package/scripts/delegation/fanout.ts +0 -2
  153. package/scripts/delegation/investigation-reads.ts +1 -164
  154. package/scripts/discovery/repo-map-logic.ts +0 -1
  155. package/scripts/discovery/repo-party-cli.ts +1 -1
  156. package/scripts/doctor/doctor-consumer.ts +6 -10
  157. package/scripts/doctor/doctor-io.ts +9 -13
  158. package/scripts/doctor/doctor-logic.ts +0 -4
  159. package/scripts/doctor/doctor.ts +14 -9
  160. package/scripts/document/backlogrun-parent-read-set.ts +12 -1
  161. package/scripts/document/document-byte-budget.ts +5 -5
  162. package/scripts/document/document-byte-check.ts +0 -1
  163. package/scripts/document/document-read-cli.ts +0 -2
  164. package/scripts/document/document-section-cli.ts +1 -1
  165. package/scripts/document/document-section.ts +0 -3
  166. package/scripts/document/edit-files-cli.ts +0 -1
  167. package/scripts/document/entry-read-budget.ts +21 -7
  168. package/scripts/document/entry-read-set.ts +32 -8
  169. package/scripts/document/lane-child-read-set.ts +8 -6
  170. package/scripts/document/read-files-cli.ts +0 -4
  171. package/scripts/document/read-set-cli.ts +0 -2
  172. package/scripts/document/read-set-point-of-use.ts +9 -3
  173. package/scripts/document/read-set-pricing.ts +0 -1
  174. package/scripts/document/read-set-trim.ts +4 -2
  175. package/scripts/epic/epic-add.ts +1 -1
  176. package/scripts/epic/epic-audit-cli.ts +1 -4
  177. package/scripts/epic/epic-audit-orphans.ts +1 -3
  178. package/scripts/epic/epic-audit-rationale.ts +0 -1
  179. package/scripts/epic/epic-audit-report.ts +0 -2
  180. package/scripts/epic/epic-audit.ts +8 -22
  181. package/scripts/epic/epic-bundle-cli.ts +1 -1
  182. package/scripts/epic/epic-bundle-evidence.ts +0 -1
  183. package/scripts/epic/epic-bundle-referenced.ts +1 -5
  184. package/scripts/epic/epic-bundle.ts +0 -4
  185. package/scripts/epic/epic-busy.ts +4 -5
  186. package/scripts/epic/epic-candidate-confirm.ts +0 -5
  187. package/scripts/epic/epic-classify.ts +2 -2
  188. package/scripts/epic/epic-cli-argv.ts +0 -1
  189. package/scripts/epic/epic-close-comment.ts +1 -1
  190. package/scripts/epic/epic-close.ts +5 -2
  191. package/scripts/epic/epic-cross-repo.ts +2 -4
  192. package/scripts/epic/epic-decision.ts +0 -1
  193. package/scripts/epic/epic-fetch.ts +2 -2
  194. package/scripts/epic/epic-index.ts +2 -3
  195. package/scripts/epic/epic-issue.ts +1 -15
  196. package/scripts/epic/epic-lane-offer.ts +9 -8
  197. package/scripts/epic/epic-nested.ts +1 -1
  198. package/scripts/epic/epic-next-read.ts +1 -3
  199. package/scripts/epic/epic-next-views.ts +0 -1
  200. package/scripts/epic/epic-next.ts +1 -10
  201. package/scripts/epic/epic-parse.ts +0 -1
  202. package/scripts/epic/epic-promote.ts +0 -9
  203. package/scripts/epic/epic-rank.ts +2 -2
  204. package/scripts/epic/epic-read.ts +1 -2
  205. package/scripts/epic/epic-reconcile.ts +1 -1
  206. package/scripts/epic/epic-reference.ts +1 -13
  207. package/scripts/epic/epic-relation-recheck.ts +1 -1
  208. package/scripts/epic/epic-relations.ts +1 -1
  209. package/scripts/epic/epic-remove.ts +1 -1
  210. package/scripts/epic/epic-report.ts +0 -1
  211. package/scripts/epic/epic-run.ts +2 -3
  212. package/scripts/epic/epic-shape.ts +1 -1
  213. package/scripts/epic/epic-solo-stale.ts +107 -0
  214. package/scripts/epic/epic-solo.ts +3 -2
  215. package/scripts/epic/epic-triage.ts +1 -1
  216. package/scripts/epic/epic-validate.ts +1 -1
  217. package/scripts/epic/epic.ts +1 -1
  218. package/scripts/exports/unused-members-cli.ts +53 -0
  219. package/scripts/{git → followup}/followup-issue-number.ts +1 -6
  220. package/scripts/{git → followup}/git-followup-cleanup.ts +2 -1
  221. package/scripts/{git → followup}/git-followup-finish.ts +1 -3
  222. package/scripts/{git → followup}/git-followup-flush.ts +2 -2
  223. package/scripts/{git → followup}/git-followup-issue-close.ts +2 -2
  224. package/scripts/{git → followup}/git-followup-label.ts +4 -4
  225. package/scripts/followup/git-followup-merged.ts +112 -0
  226. package/scripts/{git → followup}/git-followup-pending.ts +1 -1
  227. package/scripts/{git → followup}/git-followup-workflow.ts +19 -11
  228. package/scripts/{git → followup}/git-pr-followup-wrapup.ts +9 -3
  229. package/scripts/{git → followup}/git-pr-followup.ts +53 -16
  230. package/scripts/gate/core-budget.ts +3 -9
  231. package/scripts/gate/gate-plan.ts +7 -4
  232. package/scripts/gate/gate-report.ts +0 -6
  233. package/scripts/gate/gate-tree.ts +1 -1
  234. package/scripts/gate/pre-commit-type-check.ts +0 -6
  235. package/scripts/gate/project-checks.ts +7 -8
  236. package/scripts/gate/scoped-green.ts +0 -1
  237. package/scripts/gate/type-check-step.ts +1 -1
  238. package/scripts/gate/verification-gate.ts +0 -2
  239. package/scripts/gh/fix-gh-packages.ts +15 -12
  240. package/scripts/gh/gh-spawn.ts +2 -2
  241. package/scripts/{git → gh}/git-ai-review-scan.ts +1 -5
  242. package/scripts/{git → gh}/git-gh-check.ts +2 -1
  243. package/scripts/{git → gh}/git-gh-exec.ts +1 -1
  244. package/scripts/{git → gh}/git-gh-failure.ts +1 -1
  245. package/scripts/{git → gh}/git-gh-helpers.ts +0 -1
  246. package/scripts/{git → gh}/git-gh-issue-list.ts +13 -10
  247. package/scripts/{git → gh}/git-gh-issue-read.ts +1 -1
  248. package/scripts/{git → gh}/git-gh-issue-rest.ts +6 -3
  249. package/scripts/{git → gh}/git-gh-issue-write.ts +4 -1
  250. package/scripts/{git → gh}/git-gh-pr-auto-merge.ts +4 -1
  251. package/scripts/{git → gh}/git-gh-pr-read.ts +24 -0
  252. package/scripts/{git → gh}/git-gh-pr-rest.ts +5 -2
  253. package/scripts/{git → gh}/git-gh-pr-review.ts +2 -2
  254. package/scripts/{git → gh}/git-gh-pr-rollup.ts +1 -3
  255. package/scripts/{git → gh}/git-gh-pr.ts +3 -1
  256. package/scripts/{git → gh}/git-pr-ai-review.ts +2 -5
  257. package/scripts/{git → gh}/git-pr-checks-eval.ts +0 -10
  258. package/scripts/{git → gh}/git-pr-checks-parse.ts +4 -20
  259. package/scripts/{git → gh}/git-pr-checks.ts +2 -1
  260. package/scripts/{git → gh}/git-pr-coderabbit.ts +2 -5
  261. package/scripts/{git → gh}/git-pr-confirmation.ts +1 -3
  262. package/scripts/{git → gh}/git-pr-managed-config.ts +2 -3
  263. package/scripts/{git → gh}/git-pr.ts +3 -3
  264. package/scripts/git/changed-file-scope.ts +0 -1
  265. package/scripts/git/git-branch.ts +3 -6
  266. package/scripts/git/git-command.ts +6 -1
  267. package/scripts/git/git-commit.ts +1 -1
  268. package/scripts/git/git-common-directory.ts +80 -24
  269. package/scripts/git/git-error.ts +66 -9
  270. package/scripts/git/git-issue.ts +1 -1
  271. package/scripts/git/git-preflight.ts +2 -2
  272. package/scripts/git/git-prompt.ts +6 -31
  273. package/scripts/git/git-push.ts +1 -1
  274. package/scripts/git/git-spawn-sync.ts +65 -0
  275. package/scripts/git/git-spawn.ts +5 -4
  276. package/scripts/git/git-staging.ts +1 -0
  277. package/scripts/git/git-status.ts +1 -1
  278. package/scripts/git/git-workflow.ts +1 -1
  279. package/scripts/git/gone-branch.ts +1 -0
  280. package/scripts/git/listing-cutoff.ts +1 -1
  281. package/scripts/git/main-merge.ts +1 -1
  282. package/scripts/git/main-sync.ts +19 -1
  283. package/scripts/git/parse-json-array.ts +0 -3
  284. package/scripts/git/repository-lock.ts +16 -16
  285. package/scripts/git/{git-stash.ts → stash/git-stash.ts} +1 -1
  286. package/scripts/git/{stash-pop-args.ts → stash/stash-pop-args.ts} +2 -7
  287. package/scripts/git/{stash-pop-cli.ts → stash/stash-pop-cli.ts} +0 -1
  288. package/scripts/git/{stash-sweep-lock.ts → stash/stash-sweep-lock.ts} +3 -3
  289. package/scripts/hooks/codex-hook-adapter.ts +0 -1
  290. package/scripts/hooks/edited-cspell.ts +1 -1
  291. package/scripts/hooks/format-edited-file.ts +2 -0
  292. package/scripts/hooks/pre-push-unit.ts +0 -4
  293. package/scripts/hooks/pretool-guard.ts +22 -4
  294. package/scripts/hooks/reserved-run.ts +1 -1
  295. package/scripts/hooks/step-zero-notice.ts +76 -0
  296. package/scripts/hooks/stop-guard.ts +47 -21
  297. package/scripts/init/claude-plugin-config.ts +4 -5
  298. package/scripts/init/hook-command-rewrite.ts +16 -8
  299. package/scripts/init/hook-launch.ts +41 -15
  300. package/scripts/init/init-basic.ts +2 -5
  301. package/scripts/init/init-file-action.ts +54 -0
  302. package/scripts/init/init-logic-migrate.ts +35 -17
  303. package/scripts/init/init-logic-secretlint.ts +1 -1
  304. package/scripts/init/init-logic.ts +10 -19
  305. package/scripts/init/init.ts +11 -71
  306. package/scripts/init/kit-written-paths.ts +2 -0
  307. package/scripts/init/project-profile.ts +9 -17
  308. package/scripts/init/start-exec.ts +1 -1
  309. package/scripts/init/start-setup-pr.ts +6 -6
  310. package/scripts/init/start-steps.ts +3 -1
  311. package/scripts/issue/behavior-change-lint.ts +0 -1
  312. package/scripts/issue/defect-rate-cli.ts +64 -23
  313. package/scripts/issue/defect-rate.ts +1 -2
  314. package/scripts/{git → issue}/git-next-issues.ts +3 -3
  315. package/scripts/issue/issue-backlinks-cli.ts +1 -5
  316. package/scripts/issue/issue-backlinks.ts +7 -14
  317. package/scripts/issue/issue-cite-cli.ts +2 -6
  318. package/scripts/issue/issue-cite.ts +12 -8
  319. package/scripts/issue/issue-classification.ts +1 -9
  320. package/scripts/issue/issue-closing-pr.ts +4 -4
  321. package/scripts/issue/issue-comment-cli.ts +2 -2
  322. package/scripts/issue/issue-file-cli.ts +5 -5
  323. package/scripts/issue/issue-file.ts +7 -14
  324. package/scripts/issue/issue-fold-cli.ts +1 -1
  325. package/scripts/issue/issue-fold-existing-cli.ts +1 -1
  326. package/scripts/{git → issue}/issue-labels.ts +8 -0
  327. package/scripts/issue/issue-lint-cli.ts +1 -1
  328. package/scripts/issue/issue-merged.ts +2 -2
  329. package/scripts/{git → issue}/issue-rank.ts +1 -1
  330. package/scripts/issue/issue-read-cli.ts +8 -47
  331. package/scripts/issue/issue-read.ts +0 -2
  332. package/scripts/issue/issue-report-failures.ts +80 -0
  333. package/scripts/issue/issue-scout-cli.ts +1 -7
  334. package/scripts/issue/issue-scout-closed.ts +2 -2
  335. package/scripts/issue/issue-scout.ts +0 -2
  336. package/scripts/issue/issue-state-cli.ts +5 -46
  337. package/scripts/issue/issue-state.ts +1 -5
  338. package/scripts/issue/markdown-section.ts +21 -6
  339. package/scripts/issue/measure-rerun-cli.ts +74 -15
  340. package/scripts/issue/reproduction-measure.ts +1 -1
  341. package/scripts/josh/cli-body.ts +1 -1
  342. package/scripts/josh/file-map-stamp.ts +0 -3
  343. package/scripts/josh/josh-command-map.ts +2 -0
  344. package/scripts/josh/josh-commands-ai.ts +9 -102
  345. package/scripts/josh/josh-commands-backlog.ts +5 -1
  346. package/scripts/josh/josh-commands-development.ts +8 -1
  347. package/scripts/josh/josh-commands-issue.ts +2 -2
  348. package/scripts/josh/josh-commands-maintenance.ts +7 -0
  349. package/scripts/josh/josh-commands-project.ts +7 -1
  350. package/scripts/josh/josh-commands-run.ts +114 -0
  351. package/scripts/josh/josh-commands-versioning.ts +8 -0
  352. package/scripts/josh/josh-commands-workflow.ts +3 -3
  353. package/scripts/josh/path-decision.ts +0 -3
  354. package/scripts/josh/process-owner.ts +16 -0
  355. package/scripts/josh/run-github-prerequisite.ts +3 -6
  356. package/scripts/josh/session-language-cli.ts +0 -1
  357. package/scripts/lane/lane-await.ts +46 -19
  358. package/scripts/lane/lane-capacity.ts +6 -3
  359. package/scripts/lane/lane-child-invocation.ts +20 -7
  360. package/scripts/lane/lane-cli.ts +1 -4
  361. package/scripts/lane/lane-close.ts +5 -4
  362. package/scripts/lane/lane-dispatch.ts +3 -4
  363. package/scripts/lane/lane-environment.ts +0 -9
  364. package/scripts/lane/lane-handoff.ts +38 -0
  365. package/scripts/lane/lane-launch-cli.ts +31 -27
  366. package/scripts/lane/lane-open.ts +0 -3
  367. package/scripts/lane/lane-output.ts +0 -1
  368. package/scripts/lane/lane-registry.ts +9 -0
  369. package/scripts/lane/openai-lane-ship.ts +2 -0
  370. package/scripts/lane/openai-lane-supervisor-decision.ts +2 -1
  371. package/scripts/lane/openai-lane-supervisor.ts +6 -4
  372. package/scripts/lane/openai-review-broker.ts +7 -1
  373. package/scripts/lib/bounded-pool.ts +1 -0
  374. package/scripts/lib/cli-flags.ts +31 -2
  375. package/scripts/lib/error-message.ts +12 -1
  376. package/scripts/lib/json-value.ts +5 -4
  377. package/scripts/lib/poll.ts +3 -1
  378. package/scripts/lib/timed-fetch.ts +15 -0
  379. package/scripts/lib/timeouts.ts +13 -0
  380. package/scripts/{yaml → lib}/yaml-document.ts +3 -1
  381. package/scripts/{bytes → lines}/bytes-command.ts +0 -2
  382. package/scripts/lines/line-targets.ts +0 -11
  383. package/scripts/lines/lines-command.ts +5 -4
  384. package/scripts/lint/lint-related-scope.ts +0 -1
  385. package/scripts/lint/lint-related.ts +1 -1
  386. package/scripts/{git → notify}/telegram-notify.ts +2 -2
  387. package/scripts/{git → notify}/telegram-test.ts +4 -4
  388. package/scripts/observations/observation-ledger-home.ts +0 -1
  389. package/scripts/observations/observation-ledger-line.ts +0 -1
  390. package/scripts/observations/observation-ledger-migrate.ts +1 -1
  391. package/scripts/observations/observations-flush-landing.ts +3 -3
  392. package/scripts/observations/observations-flush.ts +2 -2
  393. package/scripts/overrides/lockfile-overrides.ts +1 -1
  394. package/scripts/overrides/overrides-logic.ts +1 -1
  395. package/scripts/package/package-scout-cli.ts +2 -7
  396. package/scripts/package/package-scout.ts +0 -2
  397. package/scripts/propagate/propagate-git-failure.ts +0 -1
  398. package/scripts/propagate/propagate-git.ts +3 -10
  399. package/scripts/propagate/propagate-publish.ts +2 -3
  400. package/scripts/propagate/propagate-run.ts +0 -2
  401. package/scripts/propagate/propagate-steps.ts +3 -5
  402. package/scripts/propagate/propagate-targets.ts +0 -4
  403. package/scripts/propagate/propagate.ts +0 -4
  404. package/scripts/refactor/import-graph.ts +0 -1
  405. package/scripts/refactor/refactor-lint.ts +0 -2
  406. package/scripts/refactor/refactor-scan.ts +2 -2
  407. package/scripts/refactor/refactor-targets.ts +0 -1
  408. package/scripts/registry-migration/migrate-logic.ts +28 -21
  409. package/scripts/registry-migration/migrate.ts +25 -14
  410. package/scripts/release/github-release-cli.ts +19 -6
  411. package/scripts/release/github-release-environment.ts +46 -0
  412. package/scripts/release/github-release.ts +151 -94
  413. package/scripts/release/release-history.ts +0 -1
  414. package/scripts/release/release-plan.ts +0 -1
  415. package/scripts/release/release-publish.ts +38 -5
  416. package/scripts/release/release-scope-cli.ts +1 -2
  417. package/scripts/release/release-tag.ts +2 -4
  418. package/scripts/release/release-worktree.ts +97 -2
  419. package/scripts/repo/auto-merge-setting-logic.ts +1 -4
  420. package/scripts/repo/repo-setting.ts +1 -1
  421. package/scripts/repo/repository-labels.ts +3 -3
  422. package/scripts/repo/required-checks-logic.ts +206 -0
  423. package/scripts/repo/required-checks-report.ts +71 -0
  424. package/scripts/repo/ruleset-check-cli.ts +53 -0
  425. package/scripts/repo/ruleset-check.ts +147 -0
  426. package/scripts/report/report-lint-cli.ts +0 -4
  427. package/scripts/review/disposition-cli.ts +1 -1
  428. package/scripts/review/live-evidence.ts +1 -1
  429. package/scripts/review/review-attest-cli.ts +0 -6
  430. package/scripts/review/review-attest.ts +4 -16
  431. package/scripts/review/review-brief-cli.ts +23 -6
  432. package/scripts/review/review-brief.ts +21 -8
  433. package/scripts/review/review-checkout.ts +3 -2
  434. package/scripts/review/review-diff-parts.ts +89 -0
  435. package/scripts/review/review-diff-write.ts +97 -0
  436. package/scripts/review/review-finding-ledger.ts +0 -1
  437. package/scripts/review/review-record-cli.ts +10 -17
  438. package/scripts/review/review-record.ts +0 -1
  439. package/scripts/review/review-round2-cli.ts +1 -1
  440. package/scripts/review/review-stamps.ts +0 -3
  441. package/scripts/review/review-tree.ts +14 -2
  442. package/scripts/rules/decision-oracle-stage.ts +18 -0
  443. package/scripts/rules/decision-oracle.ts +10 -7
  444. package/scripts/rules/delivered-rules.ts +9 -1
  445. package/scripts/rules/destructive-command.ts +119 -0
  446. package/scripts/rules/direct-filing.ts +1 -1
  447. package/scripts/rules/early-heartbeat.ts +4 -3
  448. package/scripts/rules/file-body.ts +0 -3
  449. package/scripts/rules/filing-cap.ts +0 -2
  450. package/scripts/rules/gh-api.ts +7 -2
  451. package/scripts/rules/git-argv.ts +18 -7
  452. package/scripts/rules/git-force.ts +0 -2
  453. package/scripts/rules/implementation-cut.ts +0 -1
  454. package/scripts/rules/index-guard.ts +71 -0
  455. package/scripts/rules/issue-citation.ts +50 -25
  456. package/scripts/rules/lane-background.ts +15 -7
  457. package/scripts/rules/lane-park.ts +22 -6
  458. package/scripts/rules/last-prompt.ts +1 -0
  459. package/scripts/rules/oracle-consulted.ts +1 -1
  460. package/scripts/rules/oracle-firing.ts +1 -0
  461. package/scripts/rules/oracle-list-cli.ts +0 -3
  462. package/scripts/rules/permission-guards.ts +14 -0
  463. package/scripts/rules/protected-files.ts +74 -0
  464. package/scripts/rules/reply-language.ts +1 -1
  465. package/scripts/rules/rule-body-guard.ts +0 -3
  466. package/scripts/rules/rule-value-cli.ts +0 -1
  467. package/scripts/rules/shell-body-trigger.ts +0 -1
  468. package/scripts/rules/shell-segments.ts +0 -1
  469. package/scripts/rules/stop-rules.ts +20 -9
  470. package/scripts/rules/tail-commands.ts +1 -1
  471. package/scripts/rules/test-declared-commit.ts +1 -1
  472. package/scripts/rules/third-party-write.ts +0 -1
  473. package/scripts/rules/worktree-guard.ts +26 -9
  474. package/scripts/run/run-carry-args.ts +8 -12
  475. package/scripts/run/run-carry-cli.ts +0 -2
  476. package/scripts/run/run-carry-stash.ts +2 -2
  477. package/scripts/run/run-carry-streak.ts +1 -1
  478. package/scripts/run/run-cut-args.ts +1 -6
  479. package/scripts/run/run-cut-cli.ts +0 -7
  480. package/scripts/run/run-cut.ts +8 -54
  481. package/scripts/run/run-ending-cli.ts +2 -6
  482. package/scripts/run/run-ending.ts +1 -4
  483. package/scripts/run/run-entry-cli.ts +133 -25
  484. package/scripts/run/run-entry-stop.ts +104 -0
  485. package/scripts/run/run-entry.ts +0 -1
  486. package/scripts/run/run-event-cli.ts +0 -2
  487. package/scripts/run/run-event-follow.ts +1 -0
  488. package/scripts/run/run-event-render.ts +1 -1
  489. package/scripts/run/run-event-scope.ts +53 -4
  490. package/scripts/run/run-event-stream-emit.ts +7 -2
  491. package/scripts/run/run-event-stream.ts +0 -3
  492. package/scripts/run/run-event-watch.ts +1 -0
  493. package/scripts/run/run-halfrun-resume.ts +20 -7
  494. package/scripts/run/run-headless.ts +2 -2
  495. package/scripts/run/run-hold-cli.ts +33 -10
  496. package/scripts/run/run-hold.ts +29 -6
  497. package/scripts/run/run-issue-number.ts +1 -1
  498. package/scripts/run/run-liveness-cli.ts +2 -6
  499. package/scripts/run/run-liveness.ts +2 -3
  500. package/scripts/run/run-merge-cli.ts +7 -23
  501. package/scripts/run/run-merge-steps.ts +5 -5
  502. package/scripts/run/run-merge.ts +1 -1
  503. package/scripts/run/run-next-cli.ts +1 -1
  504. package/scripts/run/run-parent-cut-hook.ts +4 -2
  505. package/scripts/run/run-preflight.ts +2 -9
  506. package/scripts/run/run-prep-cli.ts +6 -3
  507. package/scripts/run/run-prep-locate.ts +1 -1
  508. package/scripts/run/run-progress-args.ts +20 -4
  509. package/scripts/run/run-progress-cli.ts +35 -36
  510. package/scripts/run/run-progress-clock.ts +10 -35
  511. package/scripts/run/run-progress-config.ts +0 -4
  512. package/scripts/run/run-progress-read.ts +1 -2
  513. package/scripts/run/run-progress.ts +1 -2
  514. package/scripts/run/run-prrun-resume.ts +117 -0
  515. package/scripts/run/run-report-cli.ts +1 -2
  516. package/scripts/run/run-report.ts +0 -1
  517. package/scripts/run/run-retrospective.ts +1 -1
  518. package/scripts/run/run-review-cli.ts +0 -3
  519. package/scripts/run/run-review-steps.ts +2 -0
  520. package/scripts/run/run-review.ts +0 -2
  521. package/scripts/run/run-ship-cli.ts +29 -19
  522. package/scripts/run/run-ship-detach.ts +1 -0
  523. package/scripts/run/run-ship-next.ts +106 -0
  524. package/scripts/run/run-ship-preflight.ts +1 -1
  525. package/scripts/run/run-ship-probe.ts +4 -1
  526. package/scripts/run/run-ship-return.ts +8 -3
  527. package/scripts/run/run-ship-review-steps.ts +18 -4
  528. package/scripts/run/run-ship-review.ts +11 -0
  529. package/scripts/run/run-ship-scoped.ts +1 -0
  530. package/scripts/run/run-ship-steps.ts +1 -1
  531. package/scripts/run/run-ship.ts +0 -1
  532. package/scripts/run/run-stage-read.ts +62 -0
  533. package/scripts/run/run-stage.ts +160 -0
  534. package/scripts/run/run-status-cli.ts +3 -16
  535. package/scripts/run/run-step-cli.ts +21 -14
  536. package/scripts/run/run-step.ts +1 -1
  537. package/scripts/run/run-stop-notify.ts +1 -3
  538. package/scripts/run/run-stranded-cli.ts +0 -4
  539. package/scripts/run/run-stranded-detect.ts +2 -2
  540. package/scripts/run/run-tail-cli.ts +17 -11
  541. package/scripts/run/run-tail.ts +2 -0
  542. package/scripts/run/run-tidy-lanes.ts +6 -2
  543. package/scripts/run/run-tidy-stashes.ts +12 -12
  544. package/scripts/run/run-wake-cli.ts +4 -13
  545. package/scripts/run/run-wake-loop.ts +2 -2
  546. package/scripts/run/run-wake.ts +2 -4
  547. package/scripts/run/run-watcher-guard-cli.ts +0 -4
  548. package/scripts/run/run-watcher-guard.ts +18 -12
  549. package/scripts/run/run-watcher-hook.ts +1 -1
  550. package/scripts/safe-chain/ci-installer-pin.ts +11 -5
  551. package/scripts/safe-chain/pack-hook.ts +92 -0
  552. package/scripts/safe-chain/project-config.ts +1 -1
  553. package/scripts/security/security-audit-provision-logic.ts +0 -1
  554. package/scripts/security/security-audit-provision.ts +3 -2
  555. package/scripts/security/security-audit.ts +0 -1
  556. package/scripts/security/security-updates-logic.ts +0 -1
  557. package/scripts/sonar/sonar-hotspots-cli.ts +10 -52
  558. package/scripts/sonar/sonar-hotspots.ts +0 -1
  559. package/scripts/sonar/sonar-new-code-cli.ts +150 -0
  560. package/scripts/sonar/sonar-new-code.ts +79 -0
  561. package/scripts/sonar/sonar-project.ts +97 -0
  562. package/scripts/split/split-assess-cli.ts +1 -1
  563. package/scripts/split/split-assess.ts +2 -5
  564. package/scripts/sync/managed-config-scope-cli.ts +1 -1
  565. package/scripts/sync/skill-migration.ts +0 -1
  566. package/scripts/sync/sync-ai-files.ts +4 -0
  567. package/scripts/sync/sync-hook-safety.ts +2 -3
  568. package/scripts/sync/sync.ts +1 -8
  569. package/scripts/sync/template-source-logic.ts +0 -1
  570. package/scripts/sync/workflow-pin-logic.ts +16 -28
  571. package/scripts/test/test-declared-changed.ts +13 -16
  572. package/scripts/test/test-declared-logic.ts +0 -1
  573. package/scripts/test/test-declared.ts +3 -9
  574. package/scripts/test/test-red-commit.ts +2 -2
  575. package/scripts/test/test-red.ts +14 -7
  576. package/scripts/test/test-type-logic.ts +1 -1
  577. package/scripts/test/unit-worker-share.ts +7 -16
  578. package/scripts/time-runtime/time-batch-guard.ts +1 -2
  579. package/scripts/time-runtime/time-bundle-call.ts +0 -1
  580. package/scripts/time-runtime/time-bundles.ts +0 -4
  581. package/scripts/time-runtime/time-density-hook.ts +0 -2
  582. package/scripts/time-runtime/time-followup-stage.ts +1 -1
  583. package/scripts/time-runtime/time-format.ts +0 -73
  584. package/scripts/time-runtime/time-round-trips.ts +0 -4
  585. package/scripts/time-runtime/time-single-check.ts +1 -1
  586. package/scripts/time-runtime/time-spans.ts +1 -1
  587. package/scripts/time-runtime/time-transcript-line.ts +1 -2
  588. package/scripts/ui/ui-routes-cli.ts +0 -5
  589. package/scripts/ui/ui-routes.ts +0 -5
  590. package/scripts/version/effective-upstream.ts +2 -2
  591. package/scripts/version/latest-corepack.ts +7 -9
  592. package/scripts/version/latest-scope-cli.ts +0 -2
  593. package/scripts/version/latest-update.ts +0 -2
  594. package/scripts/version/npm-registry.ts +2 -2
  595. package/scripts/version/publishable-range-check.ts +1 -1
  596. package/scripts/version/release-hold.ts +0 -4
  597. package/scripts/version/running-binary.ts +2 -2
  598. package/scripts/version/version-check-logic.ts +0 -2
  599. package/scripts/version/version-commands.ts +11 -1
  600. package/scripts/version/version-remote.ts +3 -3
  601. package/scripts/version/version-targets.ts +4 -4
  602. package/templates/CLAUDE.basic.md +6 -6
  603. package/templates/sonar-project.properties +28 -1
  604. package/templates/workflows/ci.yml +16 -82
  605. package/templates/workflows/dependabot-auto-merge.yml +6 -3
  606. package/templates/workflows/github-release.yml +79 -0
  607. package/tsconfig.sonar.json +4 -22
  608. package/prompts/collaboration-workflow/cross-repo-epic.md +0 -5
  609. package/prompts/collaboration-workflow/epic-audit.md +0 -5
  610. package/prompts/collaboration-workflow/epic-bundle.md +0 -5
  611. package/scripts/init/plugin-install-hint.ts +0 -47
  612. package/scripts/version/parse-json.ts +0 -13
  613. /package/scripts/{git → followup}/git-followup-stages.ts +0 -0
  614. /package/scripts/{git → gh}/git-gh-api-path.ts +0 -0
  615. /package/scripts/{git → gh}/git-gh-command.ts +0 -0
  616. /package/scripts/{git → gh}/git-gh-issue.ts +0 -0
  617. /package/scripts/{git → gh}/git-gh-pr-snapshot.ts +0 -0
  618. /package/scripts/{git → gh}/git-gh-reachability.ts +0 -0
  619. /package/scripts/{git → gh}/git-gh-repo.ts +0 -0
  620. /package/scripts/{git → gh}/git-gh-rest-state.ts +0 -0
  621. /package/scripts/{git → gh}/git-pr-checks-watch.ts +0 -0
  622. /package/scripts/{git → gh}/git-pr-error.ts +0 -0
  623. /package/scripts/{git → gh}/git-pr-messages.ts +0 -0
  624. /package/scripts/{git → gh}/github-issue-url.ts +0 -0
  625. /package/scripts/git/{stash-orphans.ts → stash/stash-orphans.ts} +0 -0
  626. /package/scripts/{git → issue}/issue-reference.ts +0 -0
  627. /package/scripts/{git → lib}/animation-helpers.ts +0 -0
  628. /package/scripts/{git → lib}/git-animation.ts +0 -0
  629. /package/scripts/{git → notify}/git-notify.ts +0 -0
  630. /package/scripts/{git → notify}/telegram-test-logic.ts +0 -0
@@ -185,10 +185,11 @@ function decide(call: GuardedCall, run: GuardRun, can_record: boolean): boolean
185
185
  // is the half that makes the rule believable — the promise was kept and the interval was not.
186
186
  const EARLY_HEARTBEAT_REASON =
187
187
  '⛔ early heartbeat: this call arms a wait timer of its own, and the progress clock is not yours ' +
188
- 'to keep. `pnpm josh run:progress --wait` waits the interval out for you ' +
188
+ 'to keep. `pnpm josh run:progress --wait` keeps it for you ' +
189
189
  '(`JOSH_PROGRESS_INTERVAL_MINUTES`, or `josh.progress_interval_minutes` in `package.json`, ' +
190
- 'default 20 minutes), prints the five labelled lines and exits — start it in the background, relay ' +
191
- 'the lines it printed when it exits, and start the next one. Two timers armed at ' +
190
+ 'default 20 minutes): start it once in the background and it reports the five labelled lines to ' +
191
+ "the run's event stream on its own, without waking you — relay nothing, and start it again only " +
192
+ 'after it exits, which it does when newly runnable work arrives. Two timers armed at ' +
192
193
  'once is what produced reports 3–5 minutes apart on a 15-minute setting ' +
193
194
  '(joshuafolkken/kit#1570): a new one was armed on the turn a timer fired and again on the turn a ' +
194
195
  "child's completion woke the run, and `--mark` recorded each report without anything refusing the " +
@@ -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 }
@@ -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
@@ -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.'
@@ -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
@@ -61,7 +62,15 @@ const NOTIFY_INVOCATION = /josh\s+(?:notify|nf)\b/u
61
62
  // notify appears and a `--task-type confirmation` appears. That is looser than `is_confirmation_notify`
62
63
  // on purpose — the guard's safe direction is to read a real stop notification as present, so a run
63
64
  // that sent one is never told it did not.
65
+ //
66
+ // **A command that sent the Telegram itself prints this line instead** (joshuafolkken/kit#3099):
67
+ // `run:entry` notifies from inside its own stop, so no `josh notify` invocation reaches the transcript,
68
+ // and the line it prints is what the tail carries. One constant, printed there and matched here.
69
+ const COMMAND_NOTIFY_MARKER = 'stop notified: a confirmation Telegram was sent by this command'
70
+
64
71
  function mentions_confirmation_notify(text: string): boolean {
72
+ if (text.includes(COMMAND_NOTIFY_MARKER)) return true
73
+
65
74
  return NOTIFY_INVOCATION.test(text) && CONFIRMATION_TASK_TYPE.test(text)
66
75
  }
67
76
 
@@ -70,13 +79,18 @@ function mentions_confirmation_notify(text: string): boolean {
70
79
  // confirmation stop, not on every `Bash` call in the run. `is_child_of` is the same mechanical
71
80
  // human-or-child fact the pre-gate cut reads: a person working in a lane carries no mark and sees no
72
81
  // refusal, and a mark that leaked in naming another issue is read as a person too.
73
- function is_unparked_stop(
74
- command: string,
75
- is_lane_child: boolean = lane_child_marker.is_child_of(process.cwd()),
76
- ): boolean {
82
+ //
83
+ // **A child that handed its region to the detached ship is not parking** (joshuafolkken/kit#2962): its
84
+ // stop waits on nobody, so the park checklist is the wrong advice. `lane_handoff.is_handed_off` is the
85
+ // reading the `Stop` hook stands its notify demand down on, so the two hooks cannot disagree.
86
+ function is_parking_child(directory: string = process.cwd()): boolean {
87
+ return lane_child_marker.is_child_of(directory) && !lane_handoff.is_handed_off(directory)
88
+ }
89
+
90
+ function is_unparked_stop(command: string, is_child: () => boolean = is_parking_child): boolean {
77
91
  if (!is_confirmation_notify(command)) return false
78
92
 
79
- return is_lane_child
93
+ return is_child()
80
94
  }
81
95
 
82
96
  // **Keeping this rule is applying `needs-decision`**, the one act the park asks for before the stop.
@@ -111,8 +125,10 @@ const LANE_PARK_REASON =
111
125
  'before it stops", and the park itself is `backlogrun-park.md` → "park and continue".'
112
126
 
113
127
  const lane_park = {
128
+ COMMAND_NOTIFY_MARKER,
114
129
  LANE_PARK_REASON,
115
130
  is_confirmation_notify,
131
+ is_parking_child,
116
132
  is_unparked_stop,
117
133
  mentions_confirmation_notify,
118
134
  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],
@@ -70,10 +70,7 @@ function main(argv: ReadonlyArray<string>): void {
70
70
  }
71
71
 
72
72
  const oracle_list_cli = {
73
- format_oracle,
74
- main,
75
73
  print_list,
76
- run,
77
74
  }
78
75
 
79
76
  if (process.argv[1] === fileURLToPath(import.meta.url)) main(process.argv.slice(ARGV_OFFSET))
@@ -0,0 +1,14 @@
1
+ import { destructive_command } from './destructive-command'
2
+ import { index_guard } from './index-guard'
3
+ import { protected_files } from './protected-files'
4
+
5
+ // The three rows that close the deny-list bypasses (joshuafolkken/kit#2983), gathered so
6
+ // `delivered-rules.ts` spreads one entry. Each reads argv or a file path rather than a glob: an index
7
+ // mutation in any git spelling, a recursive forced `rm` or a destructive `gh` call, and a Read of
8
+ // `.env` or an edit of a consumer's `.claude/settings.json`. Their triggers are disjoint from every
9
+ // other row's — `git restore` is split with `worktree-mutation` by `--staged` alone.
10
+ const ROWS = [index_guard.ROW, destructive_command.ROW, protected_files.ROW] as const
11
+
12
+ const permission_guards = { ROWS }
13
+
14
+ export { permission_guards }
@@ -0,0 +1,74 @@
1
+ import path from 'node:path'
2
+ import { doctor_consumer } from '#scripts/doctor/doctor-consumer'
3
+ import { json_value } from '#scripts/lib/json-value'
4
+ import type { GuardedCall } from '#scripts/time-runtime/time-batch-guard'
5
+
6
+ // The trigger and the delivered text behind the `protected-file` row of `delivered-rules.ts`
7
+ // (joshuafolkken/kit#2983): the two files a run's own file tools must not touch.
8
+ //
9
+ // - **`.env` is never read.** It carries the Telegram bot token, and a Read lands it in the transcript.
10
+ // The scripts that need it load it in their own process, so refusing the tool costs them nothing.
11
+ // - **`.claude/settings.json` is never edited in a consumer repository.** It is the deny list and the
12
+ // hooks that enforce every other rule, so a run that rewrites it can switch the guards off; `josh
13
+ // sync` owns it there. Only a kit consumer's file is refused — decided per file from the repository
14
+ // the settings file sits in, not the session's directory — so kit's own edits (it is the file's
15
+ // source) and the user-level `~/.claude/settings.json`, which belongs to no repository, both pass.
16
+ //
17
+ // It fires on every occurrence, for the reason `git-force.ts` does.
18
+
19
+ const READ_TOOL = 'Read'
20
+ const EDIT_TOOLS: ReadonlySet<string> = new Set(['Edit', 'Write'])
21
+ const ENVIRONMENT_FILE = '.env'
22
+ const SETTINGS_FILE = path.join('.claude', 'settings.json')
23
+
24
+ function file_path_of(call: GuardedCall): string {
25
+ if (!json_value.is_record(call.input)) return ''
26
+
27
+ const value = call.input['file_path']
28
+
29
+ return typeof value === 'string' ? value : ''
30
+ }
31
+
32
+ function is_environment_read(call: GuardedCall): boolean {
33
+ return call.name === READ_TOOL && path.basename(file_path_of(call)) === ENVIRONMENT_FILE
34
+ }
35
+
36
+ // The repository the settings file belongs to is two levels above it (`<root>/.claude/settings.json`).
37
+ function is_consumer_settings_edit(
38
+ call: GuardedCall,
39
+ is_kit_consumer: (root: string) => boolean,
40
+ ): boolean {
41
+ if (!EDIT_TOOLS.has(call.name)) return false
42
+
43
+ const file_path = path.resolve(file_path_of(call))
44
+
45
+ if (!file_path.endsWith(`${path.sep}${SETTINGS_FILE}`)) return false
46
+
47
+ return is_kit_consumer(path.dirname(path.dirname(file_path)))
48
+ }
49
+
50
+ function is_protected_file_call(
51
+ call: GuardedCall,
52
+ is_kit_consumer: (root: string) => boolean = doctor_consumer.is_kit_consumer,
53
+ ): boolean {
54
+ return is_environment_read(call) || is_consumer_settings_edit(call, is_kit_consumer)
55
+ }
56
+
57
+ const PROTECTED_FILE_REASON =
58
+ '⛔ protected file: `.env` holds the Telegram bot token, so reading it puts a secret in the ' +
59
+ 'transcript — the scripts that need it load it in their own process. `.claude/settings.json` in a ' +
60
+ 'consumer repository is the deny list and the hooks every other rule rests on, so a run must not ' +
61
+ 'rewrite it; `josh sync` owns it, and a change belongs upstream in kit (`CLAUDE.md` → "Route ' +
62
+ 'distributed-doc / config changes upstream to kit"). Leave both files alone, or ask the user. ' +
63
+ '**This rule fires on every occurrence, not once per run.**'
64
+
65
+ const ROW = {
66
+ id: 'protected-file',
67
+ is_trigger: is_protected_file_call,
68
+ reason: PROTECTED_FILE_REASON,
69
+ decide: (): boolean => true,
70
+ }
71
+
72
+ const protected_files = { ROW, is_protected_file_call }
73
+
74
+ export { protected_files }
@@ -111,6 +111,6 @@ function is_mismatch(message: string, lang: string): boolean {
111
111
  return matches_share(prose, script, pattern) < MATCH_SHARE_FLOOR
112
112
  }
113
113
 
114
- const reply_language = { MIN_PROSE_LETTERS, is_mismatch, script_of }
114
+ const reply_language = { is_mismatch, script_of }
115
115
 
116
116
  export { reply_language }
@@ -192,11 +192,8 @@ const ROW = {
192
192
  const rule_body_guard = {
193
193
  RULE_BODY_REASON,
194
194
  ROW,
195
- adds_rule_prose,
196
195
  answered_placement,
197
196
  is_rule_document,
198
- prose_of,
199
- runs_placement_oracle,
200
197
  writes_rule_prose,
201
198
  }
202
199
 
@@ -117,7 +117,6 @@ if (process.argv[1] === fileURLToPath(import.meta.url)) {
117
117
  }
118
118
 
119
119
  const rule_value_cli = {
120
- gather_runs,
121
120
  group_by_run,
122
121
  render,
123
122
  row,
@@ -196,7 +196,6 @@ const SHELL_BODY_REASON =
196
196
  const shell_body_trigger = {
197
197
  SHELL_BODY_REASON,
198
198
  carries_a_body,
199
- is_safe_body_form,
200
199
  is_shell_evaluated_body,
201
200
  keeps_body_safe,
202
201
  }
@@ -37,7 +37,6 @@ function is_josh_command(segment: string, names: ReadonlySet<string>): boolean {
37
37
  }
38
38
 
39
39
  const shell_segments = {
40
- SEGMENT_SEPARATOR,
41
40
  is_josh_command,
42
41
  segments_of,
43
42
  }