@joshuafolkken/kit 1.1784.0 → 1.2114.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (690) hide show
  1. package/.claude/agents/reviewer-verification.md +19 -0
  2. package/.claude/agents/reviewer.md +19 -0
  3. package/.claude/settings.json +5 -6
  4. package/.claude/skills/dependency-update/SKILL.md +9 -10
  5. package/.claude/skills/workflow-commands/SKILL.md +6 -6
  6. package/.claude/skills/workflow-commands/background-commands.md +8 -5
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +3 -1
  8. package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +5 -2
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -3
  11. package/.claude/skills/workflow-commands/backlogrun-recovery.md +1 -1
  12. package/.claude/skills/workflow-commands/backlogrun-steps.md +3 -2
  13. package/.claude/skills/workflow-commands/backlogrun.md +1 -1
  14. package/.claude/skills/workflow-commands/chain-rule.md +41 -32
  15. package/.claude/skills/workflow-commands/delegation.md +6 -6
  16. package/.claude/skills/workflow-commands/entry-sequence.md +2 -2
  17. package/.claude/skills/workflow-commands/followup.md +7 -5
  18. package/.claude/skills/workflow-commands/fullrun-steps.md +6 -6
  19. package/.claude/skills/workflow-commands/fullrun.md +1 -1
  20. package/.claude/skills/workflow-commands/issue-comments.md +9 -4
  21. package/.claude/skills/workflow-commands/issue-fold-existing.md +2 -1
  22. package/.claude/skills/workflow-commands/kickoff.md +2 -2
  23. package/.claude/skills/workflow-commands/observation-filing.md +1 -1
  24. package/.claude/skills/workflow-commands/observation-ledger.md +6 -4
  25. package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -7
  26. package/.claude/skills/workflow-commands/prerequisite.md +3 -2
  27. package/.claude/skills/workflow-commands/retrospective.md +2 -2
  28. package/.claude/skills/workflow-commands/split-assessment.md +7 -5
  29. package/.codex/hooks.json +5 -5
  30. package/.github/actions/setup-pnpm/action.yml +9 -16
  31. package/.github/dependabot.yml +16 -0
  32. package/.github/workflows/auto-tag.yml +45 -0
  33. package/.github/workflows/ci.yml +155 -15
  34. package/.github/workflows/dependabot-auto-merge.yml +63 -4
  35. package/.github/workflows/production.yml +8 -0
  36. package/.github/workflows/publish.yml +59 -45
  37. package/.vscode/settings.json +19 -0
  38. package/CLAUDE.md +5 -12
  39. package/SECURITY.md +2 -2
  40. package/dist/CLAUDE.md +5 -12
  41. package/dist/commands/document-read-cli.js +2 -1
  42. package/dist/commands/document-section-main.js +2 -1
  43. package/dist/commands/read-set-cli.js +194 -134
  44. package/dist/commands/run-prep-main.js +9694 -10173
  45. package/dist/commands/run-step-cli.js +22138 -18285
  46. package/dist/hooks/audit-provision.js +23 -5
  47. package/dist/hooks/chunk-3GKE653K.js +6204 -0
  48. package/dist/hooks/chunk-45CJJOO7.js +1243 -0
  49. package/dist/hooks/{chunk-CWMBGKYW.js → chunk-5PM2JRGV.js} +2153 -856
  50. package/dist/hooks/{chunk-WR2KQAYZ.js → chunk-7SIUNQXK.js} +1207 -1470
  51. package/dist/hooks/{chunk-O2YBIDSI.js → chunk-CQD4LJE6.js} +1682 -1130
  52. package/dist/hooks/{chunk-VWWCFGWK.js → chunk-OPSRGWFU.js} +1 -1
  53. package/dist/hooks/{chunk-XGBNSWEI.js → chunk-UJ3FPMMM.js} +132 -49
  54. package/dist/hooks/chunk-VVNYJWEI.js +30 -0
  55. package/dist/hooks/chunk-Z6DQJKH3.js +2806 -0
  56. package/dist/hooks/codex-hook-adapter.js +8 -8
  57. package/dist/hooks/format-edited.js +4 -5
  58. package/dist/hooks/inputs.json +415 -389
  59. package/dist/hooks/pretool-guard.js +7 -6
  60. package/dist/hooks/session-lang.js +101 -258
  61. package/dist/hooks/stop-guard.js +1744 -2576
  62. package/dist/josh.js +7133 -6368
  63. package/dist/version/index.js +161 -1
  64. package/eslint/rules/comment-why-only.js +108 -0
  65. package/package.json +15 -8
  66. package/prompts/coding-standards.md +1 -1
  67. package/prompts/collaboration-workflow/file-edits.md +14 -11
  68. package/prompts/collaboration-workflow/issue-citation.md +0 -4
  69. package/prompts/collaboration-workflow/issue-template.md +40 -21
  70. package/prompts/collaboration-workflow/lane-instructions.md +3 -1
  71. package/prompts/collaboration-workflow/measurement.md +8 -1
  72. package/prompts/collaboration-workflow/operating-rules.md +11 -2
  73. package/prompts/collaboration-workflow/output-bounds.md +6 -2
  74. package/prompts/collaboration-workflow/plan-comment.md +1 -1
  75. package/prompts/collaboration-workflow/principles.md +9 -0
  76. package/prompts/collaboration-workflow/residency.md +3 -2
  77. package/prompts/collaboration-workflow/rule-delivery.md +13 -1
  78. package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
  79. package/prompts/collaboration-workflow/wip-cap.md +3 -1
  80. package/prompts/review-rubric.md +8 -0
  81. package/prompts/review.md +31 -22
  82. package/prompts/testing-guide.md +1 -0
  83. package/scripts/agent/agent-argv.ts +14 -16
  84. package/scripts/agent/agent-provider.ts +138 -0
  85. package/scripts/agent/agent-role-profile.ts +108 -156
  86. package/scripts/agent/agent-safe-text.ts +20 -5
  87. package/scripts/agent/api-usage-limit.ts +65 -0
  88. package/scripts/agent/claude-agent-argv.ts +19 -9
  89. package/scripts/agent/codex-agent-argv.ts +118 -22
  90. package/scripts/agent/usage-limit-reset.ts +179 -0
  91. package/scripts/auth/claude-token-output.ts +2 -2
  92. package/scripts/auto-ok/auto-ok-author.ts +53 -0
  93. package/scripts/auto-ok/auto-ok-cli.ts +20 -9
  94. package/scripts/backlog/backlog-defect-priority.ts +1 -1
  95. package/scripts/backlog/backlog-drive-cli.ts +6 -1
  96. package/scripts/backlog/backlog-drive-hold.ts +3 -3
  97. package/scripts/backlog/backlog-drive-idle.ts +10 -0
  98. package/scripts/backlog/backlog-drive-launch-pass.ts +90 -0
  99. package/scripts/backlog/backlog-drive-launch.ts +8 -2
  100. package/scripts/backlog/backlog-drive-named-offer.ts +73 -30
  101. package/scripts/backlog/backlog-drive-named.ts +28 -7
  102. package/scripts/backlog/backlog-drive-paused.ts +5 -4
  103. package/scripts/backlog/backlog-drive-restore.ts +11 -3
  104. package/scripts/backlog/backlog-drive.ts +21 -60
  105. package/scripts/backlog/backlog-gate-scope.ts +61 -0
  106. package/scripts/backlog/backlog-measure-close.ts +112 -0
  107. package/scripts/backlog/backlog-next.ts +39 -49
  108. package/scripts/backlog/backlog-occupied.ts +2 -2
  109. package/scripts/backlog/backlog-overlap.ts +42 -8
  110. package/scripts/backlog/backlog-plan-cli.ts +4 -1
  111. package/scripts/backlog/backlog-plan-comment.ts +81 -0
  112. package/scripts/backlog/backlog-plan-read.ts +19 -6
  113. package/scripts/backlog/backlog-pool.ts +50 -12
  114. package/scripts/backlog/backlog-rank.ts +60 -13
  115. package/scripts/backlog/backlog-stalled-detect.ts +2 -1
  116. package/scripts/backlog/backlog-waves.ts +17 -2
  117. package/scripts/backlog/backlogrun-launch.ts +7 -4
  118. package/scripts/cost-runtime/context-cut-payback.ts +27 -25
  119. package/scripts/cost-runtime/cost-cli.ts +37 -16
  120. package/scripts/cost-runtime/cost-pricing.ts +9 -0
  121. package/scripts/cost-runtime/cost-verdict.ts +4 -1
  122. package/scripts/delegation/delegation-policy.ts +2 -2
  123. package/scripts/delegation/duplicate-read-guard.ts +1 -0
  124. package/scripts/delegation/investigation-guard.ts +14 -2
  125. package/scripts/delegation/investigation-reads.ts +45 -23
  126. package/scripts/dependabot/dependabot-cooldown.ts +3 -2
  127. package/scripts/discovery/repo-party.ts +80 -20
  128. package/scripts/discovery/session-owner-pin.ts +51 -0
  129. package/scripts/document/capped-print.ts +1 -1
  130. package/scripts/document/command-reference-line-budget.ts +42 -0
  131. package/scripts/document/document-byte-budget.ts +17 -7
  132. package/scripts/document/document-checks.ts +20 -0
  133. package/scripts/document/document-ratchet-check.ts +101 -0
  134. package/scripts/document/document-section.ts +1 -0
  135. package/scripts/document/entry-read-budget.ts +7 -3
  136. package/scripts/document/issue-citation-budget.ts +94 -0
  137. package/scripts/epic/epic-cli-argv.ts +2 -2
  138. package/scripts/epic/epic-fetch.ts +4 -2
  139. package/scripts/epic/epic-graph.ts +7 -2
  140. package/scripts/epic/epic-issue.ts +3 -1
  141. package/scripts/epic/epic-rank.ts +5 -0
  142. package/scripts/exports/unused-members-check.ts +62 -0
  143. package/scripts/exports/unused-members-cli.ts +6 -51
  144. package/scripts/followup/followup-ci-path.ts +67 -0
  145. package/scripts/followup/followup-coderabbit-retrigger.ts +261 -0
  146. package/scripts/followup/followup-coderabbit-wait.ts +13 -10
  147. package/scripts/followup/followup-failed-tests.ts +160 -0
  148. package/scripts/followup/followup-job-needs.ts +100 -0
  149. package/scripts/followup/followup-job-rerun.ts +303 -0
  150. package/scripts/followup/followup-main-move.ts +113 -0
  151. package/scripts/followup/git-followup-finish.ts +43 -11
  152. package/scripts/followup/git-followup-pending.ts +3 -3
  153. package/scripts/followup/git-followup-stages.ts +41 -11
  154. package/scripts/followup/git-pr-followup-checks.ts +55 -16
  155. package/scripts/followup/git-pr-followup-wrapup.ts +24 -5
  156. package/scripts/followup/git-pr-followup.ts +62 -27
  157. package/scripts/fresh-machine/fresh-machine-script.ts +5 -9
  158. package/scripts/fresh-machine/specs/kit-test-backlogrun-python.json +2 -2
  159. package/scripts/fresh-machine/specs/kit-test-backlogrun.json +2 -2
  160. package/scripts/gate/busy-average.ts +34 -2
  161. package/scripts/gate/check-related-pinned.ts +43 -0
  162. package/scripts/gate/check-related-reuse.ts +64 -0
  163. package/scripts/gate/check-related-section.ts +57 -0
  164. package/scripts/gate/check-related-unplanned.ts +34 -0
  165. package/scripts/gate/check-related.ts +265 -0
  166. package/scripts/gate/command-memory.ts +1 -1
  167. package/scripts/gate/core-admission.ts +24 -6
  168. package/scripts/gate/core-budget-timing.ts +20 -6
  169. package/scripts/gate/core-budget.ts +40 -11
  170. package/scripts/gate/core-wait-record.ts +3 -2
  171. package/scripts/gate/core-wait.ts +25 -2
  172. package/scripts/gate/core-weights.ts +15 -7
  173. package/scripts/gate/gate-labels.ts +46 -0
  174. package/scripts/gate/gate-ledger.ts +14 -6
  175. package/scripts/gate/gate-plan.ts +103 -58
  176. package/scripts/gate/gate-report.ts +9 -7
  177. package/scripts/gate/gate-run-steps.ts +26 -3
  178. package/scripts/gate/gate-skip.ts +45 -6
  179. package/scripts/gate/gate-static-group.ts +60 -0
  180. package/scripts/gate/gate-steps.ts +2 -1
  181. package/scripts/gate/gate-tree.ts +4 -2
  182. package/scripts/gate/hook-gate-reuse.ts +19 -2
  183. package/scripts/gate/metrics-totals.ts +59 -0
  184. package/scripts/gate/scoped-green.ts +68 -15
  185. package/scripts/gate/since-green.ts +14 -6
  186. package/scripts/gate/structural-checks.ts +96 -0
  187. package/scripts/gate/verification-gate.ts +51 -16
  188. package/scripts/gate/verification-inputs.ts +21 -6
  189. package/scripts/gate/verification-tail.ts +52 -0
  190. package/scripts/gh/gh-author-association.ts +23 -2
  191. package/scripts/gh/git-ai-review-scan.ts +1 -1
  192. package/scripts/gh/git-gh-api-path.ts +12 -3
  193. package/scripts/gh/git-gh-comments-unreadable.ts +36 -0
  194. package/scripts/gh/git-gh-exec.ts +32 -2
  195. package/scripts/gh/git-gh-issue-read.ts +4 -2
  196. package/scripts/gh/git-gh-issue-rest.ts +1 -0
  197. package/scripts/gh/git-gh-issue-write.ts +8 -2
  198. package/scripts/gh/git-gh-issue.ts +12 -5
  199. package/scripts/gh/git-gh-pr-auto-merge.ts +13 -6
  200. package/scripts/gh/git-gh-pr-graphql-state.ts +56 -0
  201. package/scripts/gh/git-gh-pr-read.ts +74 -13
  202. package/scripts/gh/git-gh-pr-rest.ts +3 -1
  203. package/scripts/gh/git-gh-pr-snapshot.ts +22 -7
  204. package/scripts/gh/git-gh-pr-too-large.ts +20 -0
  205. package/scripts/gh/git-gh-pr.ts +21 -7
  206. package/scripts/gh/git-gh-retry.ts +141 -0
  207. package/scripts/gh/git-pr-ai-review.ts +15 -6
  208. package/scripts/gh/git-pr-checks-eval.ts +3 -0
  209. package/scripts/gh/git-pr-checks.ts +5 -5
  210. package/scripts/git/base-tree.ts +30 -0
  211. package/scripts/git/change-base.ts +4 -10
  212. package/scripts/git/changed-paths-sync.ts +63 -0
  213. package/scripts/git/changed-paths.ts +16 -1
  214. package/scripts/git/git-common-directory.ts +11 -1
  215. package/scripts/git/git-diff-reads.ts +66 -20
  216. package/scripts/git/git-error.ts +9 -2
  217. package/scripts/git/git-schemas.ts +13 -0
  218. package/scripts/git/git-worktree.ts +13 -0
  219. package/scripts/git/gone-branch.ts +4 -1
  220. package/scripts/git/main-merge-budget-conflict.ts +89 -0
  221. package/scripts/git/main-merge-guard.ts +55 -18
  222. package/scripts/git/main-merge-regenerate.ts +59 -25
  223. package/scripts/git/main-merge.ts +53 -5
  224. package/scripts/git/no-base-checkout.ts +127 -0
  225. package/scripts/git/stash/git-stash.ts +11 -2
  226. package/scripts/git/stash/stash-push-cli.ts +10 -0
  227. package/scripts/hooks/batch-guard.ts +40 -21
  228. package/scripts/hooks/edited-cspell.ts +37 -11
  229. package/scripts/hooks/format-edited-file.ts +22 -2
  230. package/scripts/hooks/lane-plan-guard.ts +50 -0
  231. package/scripts/hooks/pre-commit-lint-switch.ts +9 -0
  232. package/scripts/hooks/pre-commit-lint.ts +14 -1
  233. package/scripts/hooks/pre-push-related-switch.ts +10 -0
  234. package/scripts/hooks/pre-push-unit.ts +76 -10
  235. package/scripts/hooks/pretool-guard.ts +2 -0
  236. package/scripts/hooks/reserved-run.ts +14 -1
  237. package/scripts/hooks/run-hook.sh +23 -8
  238. package/scripts/hooks/step-zero-notice.ts +6 -1
  239. package/scripts/hooks/stop-actions.ts +3 -15
  240. package/scripts/hooks/stop-guard.ts +7 -6
  241. package/scripts/init/distributed-paths.ts +1 -0
  242. package/scripts/init/hook-command-rewrite.ts +5 -1
  243. package/scripts/init/hook-launch.ts +4 -2
  244. package/scripts/issue/aggregation-split.ts +52 -0
  245. package/scripts/issue/defect-origin-line.ts +19 -1
  246. package/scripts/issue/defect-rate-cli.ts +5 -102
  247. package/scripts/issue/defect-report.ts +4 -4
  248. package/scripts/issue/effect-audit-cli.ts +178 -0
  249. package/scripts/issue/effect-audit.ts +185 -0
  250. package/scripts/issue/expected-effect-lint.ts +64 -9
  251. package/scripts/issue/git-next-issues.ts +5 -0
  252. package/scripts/issue/issue-body-or-comment.ts +38 -4
  253. package/scripts/issue/issue-cite-cli.ts +1 -3
  254. package/scripts/issue/issue-classification.ts +1 -0
  255. package/scripts/issue/issue-closing-pr.ts +8 -1
  256. package/scripts/issue/issue-evidence-exit.ts +4 -2
  257. package/scripts/issue/issue-file-cap.ts +58 -0
  258. package/scripts/issue/issue-file-cli.ts +111 -38
  259. package/scripts/issue/issue-file-deferral.ts +52 -0
  260. package/scripts/issue/issue-file-fold.ts +29 -10
  261. package/scripts/issue/issue-file-interrupt.ts +85 -0
  262. package/scripts/issue/issue-file-lane-hint.ts +30 -0
  263. package/scripts/issue/issue-file.ts +43 -6
  264. package/scripts/issue/issue-labels.ts +19 -2
  265. package/scripts/issue/issue-lint-cli.ts +27 -2
  266. package/scripts/issue/issue-measured-cli.ts +13 -35
  267. package/scripts/issue/issue-measured-close.ts +58 -0
  268. package/scripts/issue/issue-not-before-label.ts +2 -2
  269. package/scripts/issue/issue-not-before.ts +4 -1
  270. package/scripts/issue/issue-priority-cli.ts +60 -0
  271. package/scripts/issue/issue-priority-raise.ts +55 -0
  272. package/scripts/issue/issue-priority.ts +174 -43
  273. package/scripts/issue/issue-rank.ts +21 -4
  274. package/scripts/issue/issue-read-cli.ts +32 -6
  275. package/scripts/issue/issue-read.ts +37 -12
  276. package/scripts/issue/issue-sample-gate.ts +95 -74
  277. package/scripts/issue/issue-sample-prime.ts +127 -0
  278. package/scripts/issue/issue-sample-required.ts +57 -0
  279. package/scripts/issue/issue-sample-source.ts +12 -11
  280. package/scripts/issue/issue-search.ts +124 -0
  281. package/scripts/issue/issue-state.ts +13 -1
  282. package/scripts/issue/issue-template-section.ts +43 -0
  283. package/scripts/issue/issue-watch-diff.ts +31 -1
  284. package/scripts/issue/issue-watch-hook.ts +11 -2
  285. package/scripts/issue/issue-watch.ts +55 -12
  286. package/scripts/issue/markdown-section.ts +1 -0
  287. package/scripts/issue/measure-declaration.ts +121 -0
  288. package/scripts/issue/measure-rerun-cli.ts +7 -70
  289. package/scripts/issue/plan-consumers-section.ts +22 -1
  290. package/scripts/issue/reproduction-measure.ts +3 -1
  291. package/scripts/issue/size-estimate.ts +90 -0
  292. package/scripts/issue/trusted-measure.ts +84 -0
  293. package/scripts/josh/command-usage.ts +3 -2
  294. package/scripts/josh/durable-state-migrate.ts +105 -0
  295. package/scripts/josh/durable-state.ts +112 -0
  296. package/scripts/josh/josh-aliases.ts +95 -0
  297. package/scripts/josh/josh-command-map.ts +1 -82
  298. package/scripts/josh/josh-commands-agent-hooks.ts +6 -6
  299. package/scripts/josh/josh-commands-ai.ts +5 -5
  300. package/scripts/josh/josh-commands-development.ts +59 -58
  301. package/scripts/josh/josh-commands-issue-write.ts +23 -4
  302. package/scripts/josh/josh-commands-issue.ts +32 -0
  303. package/scripts/josh/josh-commands-lane.ts +87 -4
  304. package/scripts/josh/josh-commands-lint.ts +16 -3
  305. package/scripts/josh/josh-commands-maintenance.ts +15 -0
  306. package/scripts/josh/josh-commands-review.ts +41 -6
  307. package/scripts/josh/josh-commands-ship.ts +56 -8
  308. package/scripts/josh/josh-commands-test-check.ts +80 -0
  309. package/scripts/josh/josh-commands-workflow.ts +1 -1
  310. package/scripts/josh/josh-environment-file.ts +43 -3
  311. package/scripts/josh/josh-in-process.ts +2 -2
  312. package/scripts/josh/josh-logic.ts +5 -3
  313. package/scripts/josh/josh-run.ts +19 -1
  314. package/scripts/josh/run-record-path.ts +15 -0
  315. package/scripts/josh/stamp-file.ts +11 -2
  316. package/scripts/lane/lane-adopt-cli.ts +98 -0
  317. package/scripts/lane/lane-adopt.ts +208 -0
  318. package/scripts/lane/lane-await.ts +5 -8
  319. package/scripts/lane/lane-baseline.ts +123 -0
  320. package/scripts/lane/lane-breakdown-cli.ts +64 -0
  321. package/scripts/lane/lane-breakdown-implement.ts +170 -0
  322. package/scripts/lane/lane-breakdown-laps.ts +107 -0
  323. package/scripts/lane/lane-breakdown-pinned.ts +76 -0
  324. package/scripts/lane/lane-breakdown-text.ts +145 -0
  325. package/scripts/lane/lane-breakdown.ts +239 -0
  326. package/scripts/lane/lane-check-stats.ts +29 -8
  327. package/scripts/lane/lane-child-invocation.ts +9 -2
  328. package/scripts/lane/lane-child-mark-keys.ts +12 -0
  329. package/scripts/lane/lane-child-marker.ts +20 -1
  330. package/scripts/lane/lane-ci-path-stats.ts +73 -0
  331. package/scripts/lane/lane-claim-stats.ts +84 -0
  332. package/scripts/lane/lane-close.ts +8 -3
  333. package/scripts/lane/lane-dispatch-log.ts +3 -3
  334. package/scripts/lane/lane-dispatch.ts +2 -2
  335. package/scripts/lane/lane-gap-stats.ts +7 -6
  336. package/scripts/lane/lane-guard-policy.ts +7 -1
  337. package/scripts/lane/lane-implement-stats.ts +207 -0
  338. package/scripts/lane/lane-implement-subagents.ts +90 -0
  339. package/scripts/lane/lane-investigation-switch.ts +16 -0
  340. package/scripts/lane/lane-ledger-kind.ts +31 -0
  341. package/scripts/lane/lane-ledger-schema-ship.ts +49 -0
  342. package/scripts/lane/lane-ledger-schema.ts +119 -36
  343. package/scripts/lane/lane-ledger-write.ts +257 -0
  344. package/scripts/lane/lane-ledger.ts +31 -177
  345. package/scripts/lane/lane-load.ts +1 -1
  346. package/scripts/lane/lane-measure-cli.ts +176 -59
  347. package/scripts/lane/lane-net-read.ts +44 -0
  348. package/scripts/lane/lane-net-time.ts +212 -0
  349. package/scripts/lane/lane-open.ts +16 -7
  350. package/scripts/lane/lane-output.ts +2 -4
  351. package/scripts/lane/lane-overrun-prompt.ts +147 -0
  352. package/scripts/lane/lane-overrun.ts +274 -0
  353. package/scripts/lane/lane-paths.ts +24 -1
  354. package/scripts/lane/lane-pause-cli.ts +4 -1
  355. package/scripts/lane/lane-paused-spans.ts +97 -0
  356. package/scripts/lane/lane-plan-check.ts +207 -0
  357. package/scripts/lane/lane-plan-cli.ts +41 -0
  358. package/scripts/lane/lane-plan.ts +144 -0
  359. package/scripts/lane/lane-registry.ts +14 -1
  360. package/scripts/lane/lane-relaunch.ts +1 -1
  361. package/scripts/lane/lane-round-one-stats.ts +51 -0
  362. package/scripts/lane/lane-sampler.ts +23 -4
  363. package/scripts/lane/lane-session-action.ts +93 -18
  364. package/scripts/lane/lane-session-broker.ts +49 -21
  365. package/scripts/lane/lane-session-reread-main.ts +14 -0
  366. package/scripts/lane/lane-session-reread.ts +51 -0
  367. package/scripts/lane/lane-ship-lap-stats.ts +74 -0
  368. package/scripts/lane/lane-sleep.ts +58 -0
  369. package/scripts/lane/lane-spent.ts +1 -1
  370. package/scripts/lane/lane-split-stats.ts +28 -0
  371. package/scripts/lane/lane-stage-stats.ts +13 -1
  372. package/scripts/lane/lane-state.ts +41 -9
  373. package/scripts/lane/lane-stats-tables.ts +58 -0
  374. package/scripts/lane/lane-stats.ts +21 -5
  375. package/scripts/lane/lane-stop-stats.ts +51 -19
  376. package/scripts/lane/lane-tail-stats.ts +32 -0
  377. package/scripts/lane/lane-transcript-calls.ts +67 -10
  378. package/scripts/lane/lane-transcript-stats.ts +44 -12
  379. package/scripts/lane/lane-value-cell.ts +72 -0
  380. package/scripts/lane/lane-value.ts +118 -0
  381. package/scripts/lane/lane-withdraw-closed.ts +124 -0
  382. package/scripts/lane/lane-withdraw.ts +108 -31
  383. package/scripts/lane/lane-yield.ts +85 -0
  384. package/scripts/lane/openai-lane-ship.ts +12 -11
  385. package/scripts/lane/openai-lane-supervisor-decision.ts +6 -8
  386. package/scripts/lane/openai-lane-supervisor-owner.ts +5 -8
  387. package/scripts/lane/openai-lane-supervisor.ts +5 -4
  388. package/scripts/lib/poll.ts +38 -9
  389. package/scripts/lib/settled-together.ts +10 -0
  390. package/scripts/lib/shell-quote.ts +21 -0
  391. package/scripts/lib/token-shape.ts +111 -0
  392. package/scripts/lint/eslint-daemon-sources.ts +79 -0
  393. package/scripts/lint/eslint-daemon.ts +45 -6
  394. package/scripts/lint/eslint-warm-cli.ts +7 -0
  395. package/scripts/lint/eslint-warm.ts +66 -0
  396. package/scripts/lint/import-graph.ts +141 -11
  397. package/scripts/lint/lint-gate-scope.ts +2 -2
  398. package/scripts/lint/lint-parallel.ts +54 -6
  399. package/scripts/lint/lint-related.ts +154 -33
  400. package/scripts/lint/rename-cli.ts +179 -0
  401. package/scripts/lint/rename-identifier.ts +192 -0
  402. package/scripts/lint/type-only-imports.ts +58 -0
  403. package/scripts/notify/telegram-notify.ts +12 -3
  404. package/scripts/observations/observation-record.ts +42 -16
  405. package/scripts/observations/observations-flush.ts +32 -9
  406. package/scripts/overrides/overrides-check.ts +9 -1
  407. package/scripts/release/release-approval-prune.ts +7 -1
  408. package/scripts/repo/required-checks-logic.ts +4 -1
  409. package/scripts/repo/ruleset-check.ts +4 -3
  410. package/scripts/report/markdown-shape.ts +28 -0
  411. package/scripts/report/report-format-reference.ts +15 -1
  412. package/scripts/report/report-labels.ts +12 -1
  413. package/scripts/report/report-lint-child-summary.ts +94 -0
  414. package/scripts/report/report-lint-cli.ts +26 -7
  415. package/scripts/report/report-lint.ts +2 -20
  416. package/scripts/review/prose-stale-cli.ts +88 -0
  417. package/scripts/review/prose-stale-scan.ts +152 -0
  418. package/scripts/review/review-attest.ts +73 -23
  419. package/scripts/review/review-brief-cli.ts +68 -19
  420. package/scripts/review/review-brief-paths.ts +22 -0
  421. package/scripts/review/review-brief.ts +14 -7
  422. package/scripts/review/review-comment-carry.ts +47 -0
  423. package/scripts/review/review-comment-round.ts +85 -22
  424. package/scripts/review/review-finding-ledger.ts +109 -7
  425. package/scripts/review/review-finding-text.ts +43 -0
  426. package/scripts/review/review-interaction.ts +11 -0
  427. package/scripts/review/review-lane-handover.ts +68 -0
  428. package/scripts/review/review-lint-cli.ts +57 -0
  429. package/scripts/review/review-lint-findings.ts +92 -0
  430. package/scripts/review/review-lint-sections.ts +80 -0
  431. package/scripts/review/review-lint.ts +221 -0
  432. package/scripts/review/review-prior-findings.ts +102 -0
  433. package/scripts/review/review-readers-scan.ts +4 -2
  434. package/scripts/review/review-record-cli.ts +177 -54
  435. package/scripts/review/review-record-code-round.ts +55 -0
  436. package/scripts/review/review-record-comment.ts +60 -0
  437. package/scripts/review/review-record-interaction.ts +35 -0
  438. package/scripts/review/review-record-pinned.ts +108 -0
  439. package/scripts/review/review-record.ts +25 -1
  440. package/scripts/review/review-reviewed-tree.ts +307 -0
  441. package/scripts/review/review-round-one-closure.ts +62 -0
  442. package/scripts/review/review-round-reuse.ts +106 -0
  443. package/scripts/review/review-round2-cli.ts +91 -29
  444. package/scripts/review/review-round2-skip-comment.ts +55 -0
  445. package/scripts/review/review-round2.ts +24 -8
  446. package/scripts/review/review-stamps.ts +7 -3
  447. package/scripts/review/review-stop-log.ts +20 -6
  448. package/scripts/review/review-stops-cli.ts +2 -1
  449. package/scripts/review/review-submit-cli.ts +101 -0
  450. package/scripts/rules/agent-model.ts +1 -1
  451. package/scripts/rules/bash-triggers.ts +3 -3
  452. package/scripts/rules/concise-reply.ts +88 -0
  453. package/scripts/rules/credential-body.ts +77 -0
  454. package/scripts/rules/decision-oracle.ts +1 -1
  455. package/scripts/rules/delivered-rules.ts +36 -17
  456. package/scripts/rules/destructive-command.ts +3 -11
  457. package/scripts/rules/direct-issue-comment.ts +34 -12
  458. package/scripts/rules/direct-issue-read.ts +191 -0
  459. package/scripts/rules/direct-pr-create.ts +4 -24
  460. package/scripts/rules/early-heartbeat.ts +2 -0
  461. package/scripts/rules/edit-tool.ts +27 -0
  462. package/scripts/rules/file-edit-rows.ts +17 -0
  463. package/scripts/rules/file-rewrite.ts +146 -0
  464. package/scripts/rules/firing-point.ts +3 -2
  465. package/scripts/rules/gh-api.ts +128 -7
  466. package/scripts/rules/gh-repo-selector.ts +84 -0
  467. package/scripts/rules/git-force.ts +2 -2
  468. package/scripts/rules/guard-remedy.ts +14 -5
  469. package/scripts/rules/implementation-cut.ts +61 -28
  470. package/scripts/rules/investigator-foreground.ts +231 -0
  471. package/scripts/rules/issue-citation.ts +15 -60
  472. package/scripts/rules/issue-comments.ts +9 -4
  473. package/scripts/rules/josh-git-bare.ts +1 -1
  474. package/scripts/rules/lane-background.ts +41 -13
  475. package/scripts/rules/lane-direct-tool.ts +107 -9
  476. package/scripts/rules/lane-interactive-ask.ts +4 -1
  477. package/scripts/rules/lane-park.ts +4 -2
  478. package/scripts/rules/lane-spilled-read.ts +90 -0
  479. package/scripts/rules/lane-split-park.ts +1 -1
  480. package/scripts/rules/lane-switch-main.ts +4 -4
  481. package/scripts/rules/last-prompt.ts +20 -47
  482. package/scripts/rules/oracle-consulted.ts +1 -1
  483. package/scripts/rules/permission-guards.ts +5 -1
  484. package/scripts/rules/piped-verification-shapes.ts +110 -0
  485. package/scripts/rules/piped-verification.ts +67 -17
  486. package/scripts/rules/poll-loop.ts +72 -9
  487. package/scripts/rules/pr-merge.ts +5 -5
  488. package/scripts/rules/pre-gate-cut.ts +3 -3
  489. package/scripts/rules/protected-files.ts +88 -24
  490. package/scripts/rules/reply-language.ts +3 -17
  491. package/scripts/rules/reply-prose.ts +34 -0
  492. package/scripts/rules/repo-admin.ts +132 -0
  493. package/scripts/rules/reviewer-foreground.ts +88 -0
  494. package/scripts/rules/round-one-check-related.ts +120 -0
  495. package/scripts/rules/rule-body-guard.ts +5 -15
  496. package/scripts/rules/rule-value-cache.ts +53 -5
  497. package/scripts/rules/rule-value-candidates.ts +84 -0
  498. package/scripts/rules/rule-value-cli.ts +59 -11
  499. package/scripts/rules/rule-value.ts +17 -4
  500. package/scripts/rules/run-tail-rule.ts +1 -1
  501. package/scripts/rules/sed-in-place.ts +196 -0
  502. package/scripts/rules/shell-segments.ts +10 -2
  503. package/scripts/rules/stop-rule-rows.ts +1 -13
  504. package/scripts/rules/stop-rules.ts +33 -58
  505. package/scripts/rules/test-declared-commit.ts +1 -1
  506. package/scripts/rules/third-party-write.ts +110 -23
  507. package/scripts/rules/timed-rerun.ts +1 -1
  508. package/scripts/rules/turn-filings.ts +90 -0
  509. package/scripts/rules/worktree-guard.ts +22 -7
  510. package/scripts/run/board/run-board-ending-reason.ts +6 -2
  511. package/scripts/run/board/run-board-fit.ts +24 -1
  512. package/scripts/run/board/run-board-found.ts +134 -0
  513. package/scripts/run/board/run-board-header.ts +8 -0
  514. package/scripts/run/board/run-board-labels.ts +11 -1
  515. package/scripts/run/board/run-board-lane-time.ts +1 -0
  516. package/scripts/run/board/run-board-link.ts +15 -2
  517. package/scripts/run/board/run-board-notes.ts +7 -1
  518. package/scripts/run/board/run-board-operation.ts +4 -2
  519. package/scripts/run/board/run-board-phase.ts +2 -5
  520. package/scripts/run/board/run-board-plan.ts +1 -1
  521. package/scripts/run/board/run-board-read.ts +46 -1
  522. package/scripts/run/board/run-board-reason.ts +20 -8
  523. package/scripts/run/board/run-board-render-checks.ts +3 -2
  524. package/scripts/run/board/run-board-render-drawn.ts +11 -0
  525. package/scripts/run/board/run-board-render-found.ts +157 -0
  526. package/scripts/run/board/run-board-render-lead.ts +9 -0
  527. package/scripts/run/board/run-board-render-legend.ts +19 -0
  528. package/scripts/run/board/run-board-render-tail.ts +1 -1
  529. package/scripts/run/board/run-board-render.ts +82 -18
  530. package/scripts/run/board/run-board-spin.ts +1 -3
  531. package/scripts/run/board/run-board-status.ts +2 -0
  532. package/scripts/run/board/run-board-tick.ts +39 -10
  533. package/scripts/run/carry/run-carry-ended.ts +3 -2
  534. package/scripts/run/carry/run-carry.ts +3 -2
  535. package/scripts/run/cut/run-cut-cli.ts +33 -133
  536. package/scripts/run/cut/run-cut-digest.ts +152 -0
  537. package/scripts/run/cut/run-cut-handoff.ts +52 -8
  538. package/scripts/run/cut/run-cut-report.ts +24 -3
  539. package/scripts/run/cut/run-cut-resume.ts +129 -0
  540. package/scripts/run/cut/run-cut-review.ts +105 -0
  541. package/scripts/run/cut/run-cut.ts +18 -7
  542. package/scripts/run/detached-launch.ts +1 -1
  543. package/scripts/run/entry/run-entry-cli.ts +88 -19
  544. package/scripts/run/entry/run-entry-spill.ts +83 -0
  545. package/scripts/run/entry/run-entry-stop.ts +5 -1
  546. package/scripts/run/entry/run-entry-trust.ts +91 -0
  547. package/scripts/run/event/run-event-baseline.ts +56 -0
  548. package/scripts/run/event/run-event-filed.ts +9 -3
  549. package/scripts/run/event/run-event-overrun.ts +197 -0
  550. package/scripts/run/event/run-event-render.ts +4 -0
  551. package/scripts/run/event/run-event-stream.ts +25 -3
  552. package/scripts/run/hold/run-stop-notify.ts +3 -8
  553. package/scripts/run/merge/run-merge-cap.ts +57 -0
  554. package/scripts/run/merge/run-merge-cli.ts +66 -23
  555. package/scripts/run/merge/run-merge-outcome.ts +2 -0
  556. package/scripts/run/merge/run-merge-ship.ts +13 -3
  557. package/scripts/run/merge/run-merge-signals.ts +40 -23
  558. package/scripts/run/merge/run-merge-steps.ts +56 -36
  559. package/scripts/run/merge/run-merge-usage-limit.ts +53 -0
  560. package/scripts/run/merge/run-merge-withdrawn.ts +53 -0
  561. package/scripts/run/merge/run-merge.ts +41 -14
  562. package/scripts/run/review/run-review-cli.ts +306 -20
  563. package/scripts/run/review/run-review-early-push.ts +121 -0
  564. package/scripts/run/review/run-review-join-read.ts +94 -0
  565. package/scripts/run/review/run-review-pinned-accepted.ts +126 -0
  566. package/scripts/run/review/run-review-pinned-join.ts +216 -0
  567. package/scripts/run/review/run-review-pinned-steps.ts +383 -0
  568. package/scripts/run/review/run-review-pinned-tree.ts +37 -0
  569. package/scripts/run/review/run-review-pinned.ts +53 -0
  570. package/scripts/run/review/run-review-steps.ts +70 -34
  571. package/scripts/run/review/run-review.ts +26 -6
  572. package/scripts/run/run-parent-cut-hook.ts +3 -4
  573. package/scripts/run/run-prep.ts +1 -0
  574. package/scripts/run/run-stage-read.ts +2 -6
  575. package/scripts/run/run-step-cli.ts +17 -5
  576. package/scripts/run/run-step-lane-plan.ts +27 -0
  577. package/scripts/run/run-step-section.ts +26 -7
  578. package/scripts/run/run-step.ts +5 -2
  579. package/scripts/run/ship/run-ship-args.ts +19 -0
  580. package/scripts/run/ship/run-ship-brokered-review.ts +106 -0
  581. package/scripts/run/ship/run-ship-cli.ts +131 -39
  582. package/scripts/run/ship/run-ship-conflict-probe.ts +59 -0
  583. package/scripts/run/ship/run-ship-detach.ts +10 -4
  584. package/scripts/run/ship/run-ship-handover.ts +106 -0
  585. package/scripts/run/ship/run-ship-infra-retry.ts +16 -1
  586. package/scripts/run/ship/run-ship-lap.ts +63 -0
  587. package/scripts/run/ship/run-ship-next.ts +27 -26
  588. package/scripts/run/ship/run-ship-overlap.ts +8 -3
  589. package/scripts/run/ship/run-ship-place.ts +9 -2
  590. package/scripts/run/ship/run-ship-planned.ts +92 -0
  591. package/scripts/run/ship/run-ship-pre-detach-pinned.ts +197 -0
  592. package/scripts/run/ship/run-ship-pre-detach-timed.ts +7 -8
  593. package/scripts/run/ship/run-ship-pre-detach.ts +77 -23
  594. package/scripts/run/ship/run-ship-preflight.ts +16 -4
  595. package/scripts/run/ship/run-ship-probe.ts +23 -9
  596. package/scripts/run/ship/run-ship-relaunch-cap.ts +43 -7
  597. package/scripts/run/ship/run-ship-relaunch.ts +51 -0
  598. package/scripts/run/ship/run-ship-return.ts +103 -29
  599. package/scripts/run/ship/run-ship-review-reason.ts +24 -0
  600. package/scripts/run/ship/run-ship-review-steps.ts +230 -59
  601. package/scripts/run/ship/run-ship-review.ts +171 -51
  602. package/scripts/run/ship/run-ship-reviewer.ts +138 -42
  603. package/scripts/run/ship/run-ship-scoped.ts +39 -10
  604. package/scripts/run/ship/run-ship-stage.ts +49 -13
  605. package/scripts/run/ship/run-ship-steps.ts +24 -4
  606. package/scripts/run/ship/run-ship-stop-cause.ts +43 -2
  607. package/scripts/run/ship/run-ship-stop-context.ts +50 -13
  608. package/scripts/run/ship/run-ship-sync.ts +171 -30
  609. package/scripts/run/ship/run-ship-synced-scope.ts +178 -0
  610. package/scripts/run/ship/run-ship-wait-cli.ts +145 -0
  611. package/scripts/run/ship/run-ship-waiter.ts +114 -0
  612. package/scripts/run/ship/run-ship.ts +16 -2
  613. package/scripts/run/wake/run-wake-caffeinate.ts +48 -0
  614. package/scripts/run/wake/run-wake-cli.ts +6 -113
  615. package/scripts/run/wake/run-wake-code.ts +53 -11
  616. package/scripts/run/wake/run-wake-driver.ts +5 -3
  617. package/scripts/run/wake/run-wake-finish.ts +137 -0
  618. package/scripts/run/wake/run-wake-loop.ts +5 -3
  619. package/scripts/run/wake/run-wake-ports.ts +11 -3
  620. package/scripts/run/wake/run-wake-session.ts +2 -0
  621. package/scripts/run/wake/run-wake.ts +3 -2
  622. package/scripts/safe-chain/ci-installer-pin.ts +49 -8
  623. package/scripts/safe-chain/project-config.ts +3 -2
  624. package/scripts/security/secretlint-scan.ts +42 -9
  625. package/scripts/security/security-audit-provision-main.ts +9 -1
  626. package/scripts/security/security-audit-provision.ts +1 -1
  627. package/scripts/security/security-audit.ts +21 -1
  628. package/scripts/security/sonar-file.ts +10 -5
  629. package/scripts/split/split-assess.ts +12 -3
  630. package/scripts/split/split-early-notice.ts +116 -0
  631. package/scripts/split/split-measure.ts +20 -2
  632. package/scripts/split/split-resolution.ts +107 -0
  633. package/scripts/test/direct-importers.ts +185 -0
  634. package/scripts/test/pure-files-entries.ts +83 -0
  635. package/scripts/test/related-heavy-tests.ts +81 -0
  636. package/scripts/test/test-no-base.ts +88 -0
  637. package/scripts/test/test-pinned-cache-logic.ts +363 -0
  638. package/scripts/test/test-pinned-cache.ts +337 -0
  639. package/scripts/test/test-pinned-emit.ts +49 -0
  640. package/scripts/test/test-pinned-functions.ts +116 -0
  641. package/scripts/test/test-pinned-ledger.ts +80 -0
  642. package/scripts/test/test-pinned-logic.ts +208 -20
  643. package/scripts/test/test-pinned-main.ts +84 -18
  644. package/scripts/test/test-pinned-pool.ts +73 -0
  645. package/scripts/test/test-pinned-probe.ts +254 -0
  646. package/scripts/test/test-pinned-prune-logic.ts +118 -0
  647. package/scripts/test/test-pinned-reach.ts +194 -0
  648. package/scripts/test/test-pinned-record.ts +196 -0
  649. package/scripts/test/test-pinned-rewire.ts +148 -0
  650. package/scripts/test/test-pinned-spawn.ts +81 -0
  651. package/scripts/test/test-pinned-stage.ts +70 -0
  652. package/scripts/test/test-pinned.ts +258 -47
  653. package/scripts/test/test-reach-cli.ts +61 -0
  654. package/scripts/test/test-read-map.ts +35 -11
  655. package/scripts/test/test-read-recording.ts +17 -5
  656. package/scripts/test/test-read-trace.ts +26 -8
  657. package/scripts/test/test-red-logic.ts +46 -7
  658. package/scripts/test/test-red.ts +34 -14
  659. package/scripts/test/test-related-claim.ts +37 -0
  660. package/scripts/test/test-related-main.ts +4 -1
  661. package/scripts/test/test-related-moved.ts +91 -0
  662. package/scripts/test/test-related-record.ts +43 -23
  663. package/scripts/test/test-related-scope.ts +99 -34
  664. package/scripts/test/test-related-synced.ts +135 -0
  665. package/scripts/test/test-related-touched.ts +84 -0
  666. package/scripts/test/test-related.ts +167 -83
  667. package/scripts/test/test-unit-guard.ts +28 -5
  668. package/scripts/test/unit-durations.ts +41 -0
  669. package/scripts/test/unit-worker-share.ts +5 -4
  670. package/scripts/test/vitest-cache-directory.ts +19 -0
  671. package/scripts/test/vitest-cli-excludes.ts +14 -0
  672. package/scripts/test/vitest-failure-summary.ts +111 -0
  673. package/scripts/test/whole-suite-files.ts +12 -1
  674. package/scripts/time-runtime/time-batch-guard.ts +42 -4
  675. package/scripts/time-runtime/time-bundle-call.ts +1 -1
  676. package/scripts/time-runtime/time-bundles.ts +36 -5
  677. package/scripts/time-runtime/time-markers.ts +2 -2
  678. package/scripts/time-runtime/time-search-call.ts +38 -0
  679. package/scripts/time-runtime/time-shell.ts +1 -1
  680. package/scripts/time-runtime/time-transcript-line.ts +17 -5
  681. package/scripts/version/development-engines-verdict.ts +124 -0
  682. package/scripts/version/latest-corepack.ts +2 -0
  683. package/templates/gitignore +2 -0
  684. package/templates/workflows/ci.yml +41 -0
  685. package/dist/hooks/chunk-AZX4FGQ3.js +0 -207
  686. package/dist/hooks/chunk-PT5R6UJD.js +0 -7131
  687. package/dist/hooks/chunk-TUIFS5E7.js +0 -72
  688. package/dist/hooks/chunk-YCDOIR3I.js +0 -3456
  689. package/scripts/cost-runtime/context-cut-threshold.ts +0 -11
  690. package/scripts/rules/filing-cap.ts +0 -139
@@ -0,0 +1,34 @@
1
+ // The prose of a session-facing reply — the text a person reads as sentences, with code, links and
2
+ // bare paths taken out. Two Stop rules read it: the reply's language (`reply-language.ts`) and its
3
+ // length (`concise-reply.ts`).
4
+
5
+ const CODE_PATTERNS: ReadonlyArray<RegExp> = [
6
+ /```[\s\S]*?(?:```|$)/gu,
7
+ /`[^`\n]*`/gu,
8
+ /\]\([^)\s]*\)/gu,
9
+ /https?:\/\/\S+/gu,
10
+ ]
11
+ // A run of printable ASCII; one holding a slash is a bare path the reply printed outside backticks.
12
+ const ASCII_RUN_PATTERN = /[!-~]+/gu
13
+ // A table row or a list item — the structure a reply's points are carried in, not its narrative.
14
+ const STRUCTURE_LINE_PATTERN = /^\s*(?:\||[-*+] |[・•] ?|\d+\. )/u
15
+
16
+ function prose_of(message: string): string {
17
+ let text = message
18
+
19
+ for (const pattern of CODE_PATTERNS) text = text.replaceAll(pattern, ' ')
20
+
21
+ return text.replaceAll(ASCII_RUN_PATTERN, (run) => (run.includes('/') ? ' ' : run))
22
+ }
23
+
24
+ // The prose outside tables and lists: what a reply narrates around its one table or list.
25
+ function narrative_of(message: string): string {
26
+ return prose_of(message)
27
+ .split('\n')
28
+ .filter((line) => !STRUCTURE_LINE_PATTERN.test(line))
29
+ .join('\n')
30
+ }
31
+
32
+ const reply_prose = { narrative_of, prose_of }
33
+
34
+ export { reply_prose }
@@ -0,0 +1,132 @@
1
+ import { bash_triggers } from './bash-triggers'
2
+ import { direct_pr_create } from './direct-pr-create'
3
+ import { gh_api } from './gh-api'
4
+ import { git_argv } from './git-argv'
5
+ import { pr_merge } from './pr-merge'
6
+ import { shell_segments } from './shell-segments'
7
+
8
+ // The trigger and the delivered text behind the `repo-admin` row of `delivered-rules.ts`: a write to
9
+ // the repository's own administration — the rulesets and branch protection, the collaborators and
10
+ // their invitations, the secrets and variables, the webhooks and deploy keys, and the repository's
11
+ // settings. The server-side ruleset is one of the two real boundaries of an unattended run, and the
12
+ // trust gate reads write permission, so one injected call that adds a collaborator or disables the
13
+ // ruleset hands the backlog to an attacker (joshuafolkken/kit#4650).
14
+ //
15
+ // **A `DELETE` is `destructive-command`'s**, which refuses every `DELETE repos/…` already; this row
16
+ // takes the other write methods, so one row claims each call. `gh ruleset` has no write subcommand.
17
+ //
18
+ // **It fires on every occurrence**, for the reason `git-force.ts` does.
19
+
20
+ const GH_COMMAND = 'gh'
21
+ const DELETE_METHOD = 'DELETE'
22
+ const PATCH_METHOD = 'PATCH'
23
+
24
+ // `repos/<o>/<r>` as a path or a full URL (`https://api.github.com/repos/…`), anchored on the whole
25
+ // argument so a path smuggled into a field value (`-f x=repos/…/hooks`) is not read as the endpoint.
26
+ const REPOSITORY_PREFIX = String.raw`^['"]?(?:https?:\/\/[^/\s'"]+)?\/?repos\/[^/\s'"]+\/[^/\s'"]+`
27
+ // The administration endpoints under it — the environments whole, since their protection rules move
28
+ // the deployment boundary as their secrets do.
29
+ const ADMIN_PATH = new RegExp(
30
+ REPOSITORY_PREFIX +
31
+ String.raw`\/(?:rulesets|branches\/[^\s'"]+\/protection|collaborators|invitations|hooks|keys|` +
32
+ String.raw`transfer|actions\/permissions|environments|` +
33
+ String.raw`(?:actions|dependabot|codespaces)\/(?:secrets|variables))(?:[/?'"]|$)`,
34
+ 'u',
35
+ )
36
+ // The repository itself — a `PATCH` here edits its settings (visibility, default branch, merge rules).
37
+ const REPOSITORY_BODY = new RegExp(String.raw`${REPOSITORY_PREFIX}\/?['"]?$`, 'u')
38
+ // The GraphQL mutations that do what the endpoints above do. Looked for in the whole line, as
39
+ // `pr-merge.ts` does, since the segment cut ignores quotes; a body read from a file is `pr-merge`'s.
40
+ const ADMIN_MUTATIONS =
41
+ /\b(?:updateRepository|archiveRepository|(?:create|update|delete)(?:BranchProtectionRule|RepositoryRuleset|Environment))\b/u
42
+
43
+ function is_admin_target(argument: string, method: string | undefined): boolean {
44
+ return ADMIN_PATH.test(argument) || (method === PATCH_METHOD && REPOSITORY_BODY.test(argument))
45
+ }
46
+
47
+ function is_admin_graphql_call(command: string, args: ReadonlyArray<string>): boolean {
48
+ return pr_merge.is_graphql_call(GH_COMMAND, args) && ADMIN_MUTATIONS.test(command)
49
+ }
50
+
51
+ // Judged on the call with its wrapper cut off, as `destructive-command.ts` does.
52
+ function is_admin_api_call(command: string, args: ReadonlyArray<string>): boolean {
53
+ const call = [GH_COMMAND, ...args].join(' ')
54
+
55
+ if (!gh_api.is_gh_api(call) || !gh_api.is_write(call)) return false
56
+ if (is_admin_graphql_call(command, args)) return true
57
+
58
+ const method = gh_api.method_of(call)
59
+
60
+ if (method === DELETE_METHOD) return false
61
+
62
+ return args.some((argument) => is_admin_target(argument, method))
63
+ }
64
+
65
+ // The read subcommands of the groups whose every other subcommand writes.
66
+ const READ_ACTIONS: ReadonlySet<string> = new Set(['list', 'ls', 'get', 'view'])
67
+ const ACTION_POSITION = 1
68
+ const SUB_ACTION_POSITION = 2
69
+ // Where the word that decides read vs write sits, keyed by the group (`gh secret <verb>`) or by the
70
+ // group and action (`gh repo deploy-key <verb>`); `gh repo edit` is its own verb and only writes.
71
+ const VERB_POSITIONS: ReadonlyMap<string, number> = new Map([
72
+ ['secret', ACTION_POSITION],
73
+ ['variable', ACTION_POSITION],
74
+ ['repo edit', ACTION_POSITION],
75
+ ['repo deploy-key', SUB_ACTION_POSITION],
76
+ ])
77
+
78
+ // The verb of an administration subcommand, or `undefined` for every other call. Read off the
79
+ // positional words, so a repository selector before the group (`gh -R o/r secret set`) is skipped.
80
+ function admin_verb(args: ReadonlyArray<string>): string | undefined {
81
+ const words = direct_pr_create.positional_words(args, direct_pr_create.API_VALUE_TAKING_FLAGS)
82
+ const position =
83
+ VERB_POSITIONS.get(words[0] ?? '') ??
84
+ VERB_POSITIONS.get(words.slice(0, SUB_ACTION_POSITION).join(' '))
85
+
86
+ if (position === undefined) return undefined
87
+
88
+ return words[position] ?? ''
89
+ }
90
+
91
+ function is_admin_cli_call(args: ReadonlyArray<string>): boolean {
92
+ const verb = admin_verb(args)
93
+
94
+ return verb !== undefined && !READ_ACTIONS.has(verb)
95
+ }
96
+
97
+ function is_admin_segment(command: string, segment: string): boolean {
98
+ const args = git_argv.arguments_of(segment, GH_COMMAND)
99
+
100
+ if (args === undefined) return false
101
+
102
+ return is_admin_cli_call(args) || is_admin_api_call(command, args)
103
+ }
104
+
105
+ function is_repo_admin_write(command: string): boolean {
106
+ return shell_segments.commands_of(command).some((segment) => is_admin_segment(command, segment))
107
+ }
108
+
109
+ const REPO_ADMIN_REASON =
110
+ '⛔ repository administration: a write to the rulesets, branch protection, collaborators, ' +
111
+ 'invitations, secrets, variables, webhooks, deploy keys or repository settings moves the ' +
112
+ 'boundary an unattended run relies on, which is Tier C. Ask the user to run it. It fires on every occurrence ' +
113
+ '(`prompts/collaboration-workflow/operating-rules.md`).'
114
+
115
+ const ROW = {
116
+ id: 'repo-admin',
117
+ is_trigger: bash_triggers.on_bash_command(is_repo_admin_write),
118
+ reason: REPO_ADMIN_REASON,
119
+ decide: (): boolean => true,
120
+ about: {
121
+ title: 'Repository administration',
122
+ topic: '`operating-rules.md`',
123
+ fires:
124
+ 'a `gh api` POST / PUT / PATCH (path or URL) to the rulesets, branch protection, collaborators, invitations, secrets, variables, hooks, keys, environments, actions permissions or transfer, a `PATCH` of the repository, the matching GraphQL mutations, `gh secret` / `gh variable` writes, `gh repo edit` / `deploy-key` writes. Every occurrence',
125
+ quiet:
126
+ '`gh secret list`, `gh variable get`, a `gh api` read — a `DELETE` is `destructive-command`',
127
+ },
128
+ }
129
+
130
+ const repo_admin = { REPO_ADMIN_REASON, ROW, is_repo_admin_write }
131
+
132
+ export { repo_admin }
@@ -0,0 +1,88 @@
1
+ import { lane_child_marker } from '#scripts/lane/lane-child-marker'
2
+ import { json_value } from '#scripts/lib/json-value'
3
+ import type { GuardedCall } from '#scripts/time-runtime/time-batch-guard'
4
+ import { agent_model } from './agent-model'
5
+
6
+ // A lane child's `reviewer` dispatched without `run_in_background: false` is run in the foreground
7
+ // instead (joshuafolkken/kit#5154).
8
+ //
9
+ // **A headless child's turn end kills a background reviewer**, so `chain-rule.md` → "A lane child" says
10
+ // not to background it. The subagent tool launches in the background by default, and 23 of 178 lanes
11
+ // did: #5129 polled the output file in a `sleep` loop, then waited again on `run:review --join`.
12
+ //
13
+ // **The fix is the same call with one field, so the hook makes it** (`guard-remedy.ts`): no round trip,
14
+ // and a build whose tool declares no `run_in_background` drops the added field as it drops the typed
15
+ // one. Lane children only — an interactive turn is re-invoked by the background result.
16
+
17
+ // `kit:reviewer` is the consumer's spelling of the same definitions.
18
+ const REVIEWER_AGENTS: ReadonlySet<string> = new Set(['reviewer', 'reviewer-verification'])
19
+
20
+ const BACKGROUND_FIELD = 'run_in_background'
21
+
22
+ const CHAIN_RULE_STEP = '`.claude/skills/workflow-commands/chain-rule.md` → "A lane child"'
23
+
24
+ const KILLED = 'reviewer foreground: a lane child’s turn end kills a background `reviewer`'
25
+ const FOREGROUND = `\`${BACKGROUND_FIELD}: false\``
26
+
27
+ const REVIEWER_FOREGROUND_NOTE = `↻ ${KILLED}, so the call ran with ${FOREGROUND} (${CHAIN_RULE_STEP}).`
28
+
29
+ // Delivered only where the rewrite cannot reach the call.
30
+ const REVIEWER_FOREGROUND_REASON = `⛔ ${KILLED}. Reissue the call with ${FOREGROUND} (${CHAIN_RULE_STEP}). It fires on every occurrence.`
31
+
32
+ function is_reviewer(call: GuardedCall): boolean {
33
+ if (!agent_model.SUBAGENT_TOOLS.has(call.name) || !json_value.is_record(call.input)) return false
34
+
35
+ const type = call.input['subagent_type']
36
+
37
+ return typeof type === 'string' && REVIEWER_AGENTS.has(type.split(':').at(-1) ?? '')
38
+ }
39
+
40
+ function is_foreground(call: GuardedCall): boolean {
41
+ return json_value.is_record(call.input) && call.input[BACKGROUND_FIELD] === false
42
+ }
43
+
44
+ function is_background_reviewer(
45
+ call: GuardedCall,
46
+ is_lane_child: boolean = lane_child_marker.is_child_of(process.cwd()),
47
+ ): boolean {
48
+ return is_lane_child && is_reviewer(call) && !is_foreground(call)
49
+ }
50
+
51
+ function foreground_input(
52
+ call: GuardedCall,
53
+ is_lane_child: boolean = lane_child_marker.is_child_of(process.cwd()),
54
+ ): Record<string, unknown> | undefined {
55
+ if (!is_background_reviewer(call, is_lane_child) || !json_value.is_record(call.input)) {
56
+ return undefined
57
+ }
58
+
59
+ return { ...call.input, [BACKGROUND_FIELD]: false }
60
+ }
61
+
62
+ const ROW = {
63
+ id: 'reviewer-foreground',
64
+ is_trigger: (call: GuardedCall): boolean => is_background_reviewer(call),
65
+ reason: REVIEWER_FOREGROUND_REASON,
66
+ decide: (): boolean => true,
67
+ keeps: (call: GuardedCall): boolean => is_reviewer(call) && is_foreground(call),
68
+ reaches: is_reviewer,
69
+ rewrite: (call: GuardedCall): Record<string, unknown> | undefined => foreground_input(call),
70
+ rewrite_note: REVIEWER_FOREGROUND_NOTE,
71
+ about: {
72
+ title: 'Lane child reviewer dispatched in the foreground',
73
+ topic: CHAIN_RULE_STEP,
74
+ fires:
75
+ 'a dispatched lane child’s `Agent` / `Task` call of the `reviewer` or `reviewer-verification` type without `run_in_background: false` — rewritten with it, every occurrence',
76
+ quiet: 'not a lane child, another agent type, or `run_in_background: false` set',
77
+ },
78
+ }
79
+
80
+ const reviewer_foreground = {
81
+ REVIEWER_FOREGROUND_NOTE,
82
+ REVIEWER_FOREGROUND_REASON,
83
+ ROW,
84
+ foreground_input,
85
+ is_background_reviewer,
86
+ }
87
+
88
+ export { reviewer_foreground }
@@ -0,0 +1,120 @@
1
+ import type { GuardRun } from '#scripts/josh/hook-decision'
2
+ import { lane_child_marker } from '#scripts/lane/lane-child-marker'
3
+ import { time_density_hook } from '#scripts/time-runtime/time-density-hook'
4
+ import { time_markers } from '#scripts/time-runtime/time-markers'
5
+ import { time_shell } from '#scripts/time-runtime/time-shell'
6
+ import { time_transcript_line, type Block } from '#scripts/time-runtime/time-transcript-line'
7
+ import { bash_triggers } from './bash-triggers'
8
+ import { shell_segments } from './shell-segments'
9
+ import { tail_commands } from './tail-commands'
10
+
11
+ // A lane child is stopped from running `check:related` on round 1's fixes before it joins the review.
12
+ //
13
+ // **Ship reruns the scoped pair on the fixed tree.** `chain-rule.md` → "A lane child" says the round's
14
+ // fixes take no `check:related` unless a brief follows: `josh ship`'s pre-detach checks the tree the
15
+ // fixes left. The #5168 lane fixed two findings between its brief and `run:review --join` and ran
16
+ // `check:related` after each, 12 of its 70 minutes, because the sentence was prose with no delivery.
17
+ //
18
+ // **The material is the run's own calls, read in order off the transcript tail.** The brief is a
19
+ // `run:review` in its writing mode, the fix an `Edit` / `Write` after it, and the round closes at
20
+ // `run:review --join` or `ship --detach`. Neither the brief file nor the join leaves a record on disk
21
+ // that tells "briefed, not yet joined" apart, so the tail is the one source that can answer.
22
+
23
+ // Named canonically — `shell_segments.is_josh_command` expands an alias (`josh cr`) before the match.
24
+ const CHECK_COMMANDS: ReadonlySet<string> = new Set(['check:related'])
25
+ const REVIEW_COMMANDS: ReadonlySet<string> = new Set(['run:review'])
26
+ const SHIP_COMMANDS: ReadonlySet<string> = new Set(['ship'])
27
+ const JOIN_FLAG = /(?:^|\s)--join(?:[=\s]|$)/u
28
+ // The `run:review` modes that read a running check rather than write a brief.
29
+ const READING_MODE_FLAG = /(?:^|\s)--(?:pinned|push)(?:[=\s]|$)/u
30
+ const DETACH_FLAG = /(?:^|\s)--detach(?:[=\s]|$)/u
31
+
32
+ type RoundEvent = 'brief' | 'close' | 'edit' | 'none'
33
+
34
+ function review_event(segment: string): RoundEvent {
35
+ if (JOIN_FLAG.test(segment)) return 'close'
36
+
37
+ return READING_MODE_FLAG.test(segment) ? 'none' : 'brief'
38
+ }
39
+
40
+ function segment_event(segment: string): RoundEvent {
41
+ if (shell_segments.is_josh_command(segment, REVIEW_COMMANDS)) return review_event(segment)
42
+
43
+ const is_detach =
44
+ shell_segments.is_josh_command(segment, SHIP_COMMANDS) && DETACH_FLAG.test(segment)
45
+
46
+ return is_detach ? 'close' : 'none'
47
+ }
48
+
49
+ function block_events(block: Block): ReadonlyArray<RoundEvent> {
50
+ if (tail_commands.is_bash_use(block)) {
51
+ const segments = shell_segments.segments_of(time_shell.bash_command(block.input))
52
+
53
+ return segments.map((segment) => segment_event(segment))
54
+ }
55
+
56
+ const is_edit = time_markers.tool_marker(block.name, block.input) === time_markers.EDIT_MARKER
57
+
58
+ return is_edit ? ['edit'] : []
59
+ }
60
+
61
+ // Whether the tail's last brief was followed by a fix and by neither a join nor a detach.
62
+ function fixes_an_open_round(tail: string): boolean {
63
+ const blocks = time_transcript_line.parse_text(tail).flatMap((line) => line.blocks)
64
+ const events = blocks.flatMap((block) => block_events(block))
65
+ const brief_at = events.lastIndexOf('brief')
66
+
67
+ if (brief_at === -1) return false
68
+
69
+ const since_brief = new Set(events.slice(brief_at))
70
+
71
+ return since_brief.has('edit') && !since_brief.has('close')
72
+ }
73
+
74
+ function runs_check_related(command: string): boolean {
75
+ return shell_segments
76
+ .segments_of(command)
77
+ .some((segment) => shell_segments.is_josh_command(segment, CHECK_COMMANDS))
78
+ }
79
+
80
+ // **The command test comes first and the world is consulted second**: a person working in a lane
81
+ // carries no mark and sees no refusal.
82
+ function is_candidate(command: string): boolean {
83
+ if (!runs_check_related(command)) return false
84
+
85
+ return lane_child_marker.is_child_of(process.cwd())
86
+ }
87
+
88
+ // Refused on every occurrence while the round stays open: the way on is the join, never a reissue.
89
+ function decide(_call: unknown, run: GuardRun): boolean {
90
+ return fixes_an_open_round(time_density_hook.read_tail(run.transcript))
91
+ }
92
+
93
+ const ROUND_ONE_CHECK_RELATED_REASON =
94
+ "⛔ round-one check:related: round 1's fixes need no `check:related` — ship's pre-detach reruns the " +
95
+ 'scoped pair on the fixed tree; refused on every occurrence. Go on to `pnpm josh run:review --join`; ' +
96
+ '`--join --fixing` while round 1 has fixes to make (`.claude/skills/workflow-commands/chain-rule.md` → "A lane child").'
97
+
98
+ // It declares no `keeps`: skipping the check is the absence of a call, so the row is reported
99
+ // unmeasured rather than scored on an act that does not exist (`lane-split-park.ts`).
100
+ const ROW = {
101
+ id: 'round-one-check-related',
102
+ is_trigger: bash_triggers.on_bash_command(is_candidate),
103
+ reason: ROUND_ONE_CHECK_RELATED_REASON,
104
+ decide,
105
+ about: {
106
+ title: "No check:related on round 1's fixes",
107
+ topic: '`.claude/skills/workflow-commands/chain-rule.md` → "A lane child"',
108
+ fires:
109
+ "`pnpm josh check:related` (`josh cr`) in a lane child after an `Edit` / `Write` that follows `run:review`'s brief, before `run:review --join` or `ship --detach`. Every occurrence",
110
+ quiet: 'no fix since the brief, already joined or detached, or not a lane child',
111
+ },
112
+ }
113
+
114
+ const round_one_check_related = {
115
+ ROUND_ONE_CHECK_RELATED_REASON,
116
+ ROW,
117
+ fixes_an_open_round,
118
+ }
119
+
120
+ export { round_one_check_related }
@@ -2,6 +2,7 @@ import { json_value } from '#scripts/lib/json-value'
2
2
  import { file_reader } from '#scripts/lib/read-file'
3
3
  import type { GuardedCall } from '#scripts/time-runtime/time-batch-guard'
4
4
  import { bash_triggers } from './bash-triggers'
5
+ import { edit_tool } from './edit-tool'
5
6
  import { shell_segments } from './shell-segments'
6
7
  import { tail_commands } from './tail-commands'
7
8
 
@@ -29,10 +30,9 @@ import { tail_commands } from './tail-commands'
29
30
  // refuses until it is met. It passes on answering the questions, not on reading the
30
31
  // reminder. Keeping the rule is therefore running those two commands, which `keeps` names.
31
32
 
32
- // The two edit tools the `PreToolUse` matcher routes here. A `Write` carries the whole new file; an
33
- // `Edit` carries the region as `old_string` / `new_string`.
34
- const EDIT_TOOL = 'Edit'
35
- const WRITE_TOOL = 'Write'
33
+ // The two edit tools the `PreToolUse` matcher routes here (`edit-tool.ts`). A `Write` carries the whole
34
+ // new file; an `Edit` carries the region as `old_string` / `new_string`.
35
+ const { WRITE, is_edit_tool, string_field } = edit_tool
36
36
 
37
37
  // The three rule-document families question 0 must be pushed at: the resident source, the
38
38
  // collaboration-workflow prompts, and the skill bodies. Anchored at a path separator or the string
@@ -69,12 +69,6 @@ function adds_rule_prose(old_text: string, new_text: string): boolean {
69
69
  return prose_of(new_text).length - prose_of(old_text).length >= MIN_APPENDED_PROSE
70
70
  }
71
71
 
72
- function string_field(input: Record<string, unknown>, key: string): string {
73
- const value = input[key]
74
-
75
- return typeof value === 'string' ? value : ''
76
- }
77
-
78
72
  // The file's current text, read synchronously before the write lands so a `Write` has an `old` to
79
73
  // measure against. Injected so the suite controls it without touching the real filesystem, the way
80
74
  // `file-body.ts` injects its existence check. A new file reads as empty, so its whole body is added.
@@ -87,7 +81,7 @@ function texts_of(
87
81
  input: Record<string, unknown>,
88
82
  read: (file_path: string) => string,
89
83
  ): { old_text: string; new_text: string } {
90
- if (name === WRITE_TOOL) {
84
+ if (name === WRITE) {
91
85
  return {
92
86
  old_text: read(string_field(input, 'file_path')),
93
87
  new_text: string_field(input, 'content'),
@@ -100,10 +94,6 @@ function texts_of(
100
94
  }
101
95
  }
102
96
 
103
- function is_edit_tool(name: string): boolean {
104
- return name === EDIT_TOOL || name === WRITE_TOOL
105
- }
106
-
107
97
  // The call's input when it is an edit of a rule document, and `undefined` otherwise. The tool-name and
108
98
  // path tests run before the text read, so an ordinary edit pays nothing and a `Write`'s file read
109
99
  // happens only for a rule document.
@@ -1,6 +1,7 @@
1
1
  import { spawn } from 'node:child_process'
2
2
  import { statSync } from 'node:fs'
3
3
  import path from 'node:path'
4
+ import { git_common_directory } from '#scripts/git/git-common-directory'
4
5
  import { atomic_write } from '#scripts/lib/atomic-write'
5
6
  import { file_reader } from '#scripts/lib/read-file'
6
7
  import { MS_PER_MINUTE } from '#scripts/lib/timeouts'
@@ -14,7 +15,12 @@ import { MS_PER_MINUTE } from '#scripts/lib/timeouts'
14
15
  // **It reports and never fails**, as `rule:value` itself does: a missing cache, an unwritable directory
15
16
  // or a refresh that could not start prints at most nothing, and never changes the offer's answer.
16
17
 
17
- const CACHE_DIRECTORY = ['node_modules', '.cache', 'josh']
18
+ // Outside a repository only: inside one the cache lives in the common git directory, so a lane's work
19
+ // tree reads the reading its parent's loop head stored rather than measuring again
20
+ // (joshuafolkken/kit#5186). The reading is the main checkout's — its transcripts and every lane's —
21
+ // because only the main checkout writes it (`is_linked_work_tree`); a lane's own measurement reaches
22
+ // only its own transcripts (`cost_transcript.transcript_directories`).
23
+ const FALLBACK_DIRECTORY = ['node_modules', '.cache', 'josh']
18
24
  const CACHE_FILE = 'rule-value.txt'
19
25
  // Touched when a refresh starts, so the loop head starts at most one per interval however often it runs.
20
26
  const STAMP_FILE = 'rule-value.stamp'
@@ -28,14 +34,48 @@ interface CachePorts {
28
34
  start_refresh: (cwd: string) => void
29
35
  }
30
36
 
37
+ interface FreshReading {
38
+ text: string
39
+ taken_at: Date
40
+ }
41
+
31
42
  function cache_path(cwd: string, file: string): string {
32
- return path.join(cwd, ...CACHE_DIRECTORY, file)
43
+ const common = git_common_directory.repository(cwd)
44
+
45
+ if (common === undefined) return path.join(cwd, ...FALLBACK_DIRECTORY, file)
46
+
47
+ return path.join(common, git_common_directory.STATE_DIRECTORY, file)
33
48
  }
34
49
 
35
50
  function read_cached(cwd: string): string | undefined {
36
51
  return file_reader.read_if_readable(cache_path(cwd, CACHE_FILE))
37
52
  }
38
53
 
54
+ function taken_at_if_fresh(cwd: string, now_ms: number): Date | undefined {
55
+ try {
56
+ const { mtime } = statSync(cache_path(cwd, CACHE_FILE))
57
+
58
+ return now_ms - mtime.getTime() < REFRESH_MS ? mtime : undefined
59
+ } catch {
60
+ return undefined
61
+ }
62
+ }
63
+
64
+ // The stored reading when it was taken inside the refresh interval — what `josh rule:value` prints
65
+ // instead of measuring. `undefined` is a miss: no reading, or one older than the interval.
66
+ function read_fresh(
67
+ cwd: string = process.cwd(),
68
+ now_ms: number = Date.now(),
69
+ ): FreshReading | undefined {
70
+ const taken_at = taken_at_if_fresh(cwd, now_ms)
71
+
72
+ if (taken_at === undefined) return undefined
73
+
74
+ const text = read_cached(cwd)
75
+
76
+ return text === undefined ? undefined : { text, taken_at }
77
+ }
78
+
39
79
  function is_refresh_due(cwd: string, now_ms: number): boolean {
40
80
  try {
41
81
  return now_ms - statSync(cache_path(cwd, STAMP_FILE)).mtimeMs >= REFRESH_MS
@@ -63,8 +103,14 @@ function start_refresh_default(cwd: string): void {
63
103
 
64
104
  const DEFAULT_PORTS: CachePorts = { now: Date.now, start_refresh: start_refresh_default }
65
105
 
106
+ // A linked work tree — a lane — measures its own transcripts alone, so it never writes the main
107
+ // checkout's reading or its stamp: either would stand in for the whole repository's for an interval.
108
+ function is_linked_work_tree(cwd: string): boolean {
109
+ return git_common_directory.resolve(cwd) !== undefined
110
+ }
111
+
66
112
  function refresh_if_due(cwd: string, ports: CachePorts): void {
67
- if (!is_refresh_due(cwd, ports.now())) return
113
+ if (is_linked_work_tree(cwd) || !is_refresh_due(cwd, ports.now())) return
68
114
 
69
115
  write_cache_file(cwd, STAMP_FILE, new Date(ports.now()).toISOString())
70
116
  ports.start_refresh(cwd)
@@ -85,10 +131,12 @@ function emit(cwd: string = process.cwd(), ports: CachePorts = DEFAULT_PORTS): v
85
131
 
86
132
  // The detached refresh's body: the reading written whole, so a reader never sees half of one.
87
133
  function store(text: string, cwd: string = process.cwd()): void {
134
+ if (is_linked_work_tree(cwd)) return
135
+
88
136
  write_cache_file(cwd, CACHE_FILE, `${text}\n`)
89
137
  }
90
138
 
91
- const rule_value_cache = { CACHE_FILE, REFRESH_MS, STAMP_FILE, cache_path, emit, store }
139
+ const rule_value_cache = { CACHE_FILE, REFRESH_MS, STAMP_FILE, cache_path, emit, read_fresh, store }
92
140
 
93
- export type { CachePorts }
141
+ export type { CachePorts, FreshReading }
94
142
  export { rule_value_cache }
@@ -0,0 +1,84 @@
1
+ import { delivered_rules, type MeasuredRule } from './delivered-rules'
2
+ import type { RuleReading } from './rule-value'
3
+
4
+ // The rules `rule:value`'s reading says can go or shrink — the evidence
5
+ // `prompts/collaboration-workflow/residency.md` lets a retirement or a condensation rest on. **It lists, never removes**: each candidate is retired or condensed in an
6
+ // Issue of its own, or kept with a recorded reason.
7
+ //
8
+ // - **Retire**: no run reached the rule, over a window large enough for "never" to mean something.
9
+ // Below it nothing is judged, since a fresh checkout reaches no rule at all. **Measurable rows
10
+ // only**: an unmeasured row's trigger is the violation itself, so its `reached 0` says the rule was
11
+ // never broken — the guard working — not that its situation never arose. A measurable row's trigger
12
+ // is a neutral act or it declares `reaches` (`rule-value.ts`, `RuleReading.sessions`).
13
+ // - **Condense**: the hook refuses the rule on every occurrence (`decide`) and has refused it at least
14
+ // once, so the prose need only point at the row — the hook, not the text, keeps it.
15
+
16
+ // The one threshold: the runs a reading must cover before a rule no run reached is a retirement
17
+ // candidate.
18
+ const MIN_RUNS_FOR_RETIREMENT = 20
19
+ const SEPARATOR = ', '
20
+ const NONE = 'none'
21
+
22
+ interface RuleCandidates {
23
+ retire: ReadonlyArray<string>
24
+ condense: ReadonlyArray<string>
25
+ }
26
+
27
+ function retire_candidates(readings: ReadonlyArray<RuleReading>, runs: number): Array<string> {
28
+ if (runs < MIN_RUNS_FOR_RETIREMENT) return []
29
+
30
+ return readings
31
+ .filter((reading) => reading.is_measurable && reading.sessions === 0)
32
+ .map((reading) => reading.id)
33
+ }
34
+
35
+ function is_enforced_on_every_occurrence(id: string, rules: ReadonlyArray<MeasuredRule>): boolean {
36
+ return rules.some((rule) => rule.id === id && rule.decide !== undefined)
37
+ }
38
+
39
+ function condense_candidates(
40
+ readings: ReadonlyArray<RuleReading>,
41
+ rules: ReadonlyArray<MeasuredRule> = delivered_rules.MEASURED_RULES,
42
+ ): Array<string> {
43
+ return readings
44
+ .filter((reading) => reading.refusals > 0)
45
+ .filter((reading) => is_enforced_on_every_occurrence(reading.id, rules))
46
+ .map((reading) => reading.id)
47
+ }
48
+
49
+ function judge(
50
+ readings: ReadonlyArray<RuleReading>,
51
+ runs: number,
52
+ rules: ReadonlyArray<MeasuredRule> = delivered_rules.MEASURED_RULES,
53
+ ): RuleCandidates {
54
+ return {
55
+ retire: retire_candidates(readings, runs),
56
+ condense: condense_candidates(readings, rules),
57
+ }
58
+ }
59
+
60
+ function listed(ids: ReadonlyArray<string>): string {
61
+ return ids.length === 0 ? NONE : ids.join(SEPARATOR)
62
+ }
63
+
64
+ function render(candidates: RuleCandidates, runs: number): string {
65
+ const window = `${runs.toString()} runs, threshold ${MIN_RUNS_FOR_RETIREMENT.toString()}`
66
+
67
+ return [
68
+ 'candidates:',
69
+ ` retire (reached 0; ${window}): ${listed(candidates.retire)}`,
70
+ ` condense (refused on every occurrence by its hook): ${listed(candidates.condense)}`,
71
+ ].join('\n')
72
+ }
73
+
74
+ const rule_value_candidates = {
75
+ condense_candidates,
76
+ judge,
77
+ render,
78
+ retire_candidates,
79
+ MIN_RUNS_FOR_RETIREMENT,
80
+ NONE,
81
+ }
82
+
83
+ export type { RuleCandidates }
84
+ export { rule_value_candidates }