@joshuafolkken/kit 1.1784.0 → 1.2116.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (690) hide show
  1. package/.claude/agents/reviewer-verification.md +19 -0
  2. package/.claude/agents/reviewer.md +19 -0
  3. package/.claude/settings.json +5 -6
  4. package/.claude/skills/dependency-update/SKILL.md +9 -10
  5. package/.claude/skills/workflow-commands/SKILL.md +6 -6
  6. package/.claude/skills/workflow-commands/background-commands.md +8 -5
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +3 -1
  8. package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +5 -2
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -3
  11. package/.claude/skills/workflow-commands/backlogrun-recovery.md +1 -1
  12. package/.claude/skills/workflow-commands/backlogrun-steps.md +3 -2
  13. package/.claude/skills/workflow-commands/backlogrun.md +1 -1
  14. package/.claude/skills/workflow-commands/chain-rule.md +41 -32
  15. package/.claude/skills/workflow-commands/delegation.md +6 -6
  16. package/.claude/skills/workflow-commands/entry-sequence.md +2 -2
  17. package/.claude/skills/workflow-commands/followup.md +7 -5
  18. package/.claude/skills/workflow-commands/fullrun-steps.md +6 -6
  19. package/.claude/skills/workflow-commands/fullrun.md +1 -1
  20. package/.claude/skills/workflow-commands/issue-comments.md +9 -4
  21. package/.claude/skills/workflow-commands/issue-fold-existing.md +2 -1
  22. package/.claude/skills/workflow-commands/kickoff.md +2 -2
  23. package/.claude/skills/workflow-commands/observation-filing.md +1 -1
  24. package/.claude/skills/workflow-commands/observation-ledger.md +6 -4
  25. package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -7
  26. package/.claude/skills/workflow-commands/prerequisite.md +3 -2
  27. package/.claude/skills/workflow-commands/retrospective.md +2 -2
  28. package/.claude/skills/workflow-commands/split-assessment.md +7 -5
  29. package/.codex/hooks.json +5 -5
  30. package/.github/actions/setup-pnpm/action.yml +9 -16
  31. package/.github/dependabot.yml +16 -0
  32. package/.github/workflows/auto-tag.yml +45 -0
  33. package/.github/workflows/ci.yml +155 -15
  34. package/.github/workflows/dependabot-auto-merge.yml +63 -4
  35. package/.github/workflows/production.yml +8 -0
  36. package/.github/workflows/publish.yml +60 -45
  37. package/.vscode/settings.json +19 -0
  38. package/CLAUDE.md +5 -12
  39. package/SECURITY.md +2 -2
  40. package/dist/CLAUDE.md +5 -12
  41. package/dist/commands/document-read-cli.js +2 -1
  42. package/dist/commands/document-section-main.js +2 -1
  43. package/dist/commands/read-set-cli.js +194 -134
  44. package/dist/commands/run-prep-main.js +9694 -10173
  45. package/dist/commands/run-step-cli.js +22138 -18285
  46. package/dist/hooks/audit-provision.js +23 -5
  47. package/dist/hooks/chunk-3GKE653K.js +6204 -0
  48. package/dist/hooks/chunk-45CJJOO7.js +1243 -0
  49. package/dist/hooks/{chunk-CWMBGKYW.js → chunk-5PM2JRGV.js} +2153 -856
  50. package/dist/hooks/{chunk-WR2KQAYZ.js → chunk-7SIUNQXK.js} +1207 -1470
  51. package/dist/hooks/{chunk-O2YBIDSI.js → chunk-CQD4LJE6.js} +1682 -1130
  52. package/dist/hooks/{chunk-VWWCFGWK.js → chunk-OPSRGWFU.js} +1 -1
  53. package/dist/hooks/{chunk-XGBNSWEI.js → chunk-UJ3FPMMM.js} +132 -49
  54. package/dist/hooks/chunk-VVNYJWEI.js +30 -0
  55. package/dist/hooks/chunk-Z6DQJKH3.js +2806 -0
  56. package/dist/hooks/codex-hook-adapter.js +8 -8
  57. package/dist/hooks/format-edited.js +4 -5
  58. package/dist/hooks/inputs.json +386 -360
  59. package/dist/hooks/pretool-guard.js +7 -6
  60. package/dist/hooks/session-lang.js +101 -258
  61. package/dist/hooks/stop-guard.js +1744 -2576
  62. package/dist/josh.js +7133 -6368
  63. package/dist/version/index.js +161 -1
  64. package/eslint/rules/comment-why-only.js +108 -0
  65. package/package.json +16 -9
  66. package/prompts/coding-standards.md +1 -1
  67. package/prompts/collaboration-workflow/file-edits.md +14 -11
  68. package/prompts/collaboration-workflow/issue-citation.md +0 -4
  69. package/prompts/collaboration-workflow/issue-template.md +40 -21
  70. package/prompts/collaboration-workflow/lane-instructions.md +3 -1
  71. package/prompts/collaboration-workflow/measurement.md +8 -1
  72. package/prompts/collaboration-workflow/operating-rules.md +11 -2
  73. package/prompts/collaboration-workflow/output-bounds.md +6 -2
  74. package/prompts/collaboration-workflow/plan-comment.md +1 -1
  75. package/prompts/collaboration-workflow/principles.md +9 -0
  76. package/prompts/collaboration-workflow/residency.md +3 -2
  77. package/prompts/collaboration-workflow/rule-delivery.md +13 -1
  78. package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
  79. package/prompts/collaboration-workflow/wip-cap.md +3 -1
  80. package/prompts/review-rubric.md +8 -0
  81. package/prompts/review.md +31 -22
  82. package/prompts/testing-guide.md +1 -0
  83. package/scripts/agent/agent-argv.ts +14 -16
  84. package/scripts/agent/agent-provider.ts +138 -0
  85. package/scripts/agent/agent-role-profile.ts +108 -156
  86. package/scripts/agent/agent-safe-text.ts +20 -5
  87. package/scripts/agent/api-usage-limit.ts +65 -0
  88. package/scripts/agent/claude-agent-argv.ts +19 -9
  89. package/scripts/agent/codex-agent-argv.ts +118 -22
  90. package/scripts/agent/usage-limit-reset.ts +179 -0
  91. package/scripts/auth/claude-token-output.ts +2 -2
  92. package/scripts/auto-ok/auto-ok-author.ts +53 -0
  93. package/scripts/auto-ok/auto-ok-cli.ts +20 -9
  94. package/scripts/backlog/backlog-defect-priority.ts +1 -1
  95. package/scripts/backlog/backlog-drive-cli.ts +6 -1
  96. package/scripts/backlog/backlog-drive-hold.ts +3 -3
  97. package/scripts/backlog/backlog-drive-idle.ts +10 -0
  98. package/scripts/backlog/backlog-drive-launch-pass.ts +90 -0
  99. package/scripts/backlog/backlog-drive-launch.ts +8 -2
  100. package/scripts/backlog/backlog-drive-named-offer.ts +73 -30
  101. package/scripts/backlog/backlog-drive-named.ts +28 -7
  102. package/scripts/backlog/backlog-drive-paused.ts +5 -4
  103. package/scripts/backlog/backlog-drive-restore.ts +11 -3
  104. package/scripts/backlog/backlog-drive.ts +21 -60
  105. package/scripts/backlog/backlog-gate-scope.ts +61 -0
  106. package/scripts/backlog/backlog-measure-close.ts +112 -0
  107. package/scripts/backlog/backlog-next.ts +39 -49
  108. package/scripts/backlog/backlog-occupied.ts +2 -2
  109. package/scripts/backlog/backlog-overlap.ts +42 -8
  110. package/scripts/backlog/backlog-plan-cli.ts +4 -1
  111. package/scripts/backlog/backlog-plan-comment.ts +81 -0
  112. package/scripts/backlog/backlog-plan-read.ts +19 -6
  113. package/scripts/backlog/backlog-pool.ts +50 -12
  114. package/scripts/backlog/backlog-rank.ts +60 -13
  115. package/scripts/backlog/backlog-stalled-detect.ts +2 -1
  116. package/scripts/backlog/backlog-waves.ts +17 -2
  117. package/scripts/backlog/backlogrun-launch.ts +7 -4
  118. package/scripts/cost-runtime/context-cut-payback.ts +27 -25
  119. package/scripts/cost-runtime/cost-cli.ts +37 -16
  120. package/scripts/cost-runtime/cost-pricing.ts +9 -0
  121. package/scripts/cost-runtime/cost-verdict.ts +4 -1
  122. package/scripts/delegation/delegation-policy.ts +2 -2
  123. package/scripts/delegation/duplicate-read-guard.ts +1 -0
  124. package/scripts/delegation/investigation-guard.ts +14 -2
  125. package/scripts/delegation/investigation-reads.ts +45 -23
  126. package/scripts/dependabot/dependabot-cooldown.ts +3 -2
  127. package/scripts/discovery/repo-party.ts +80 -20
  128. package/scripts/discovery/session-owner-pin.ts +51 -0
  129. package/scripts/document/capped-print.ts +1 -1
  130. package/scripts/document/command-reference-line-budget.ts +42 -0
  131. package/scripts/document/document-byte-budget.ts +17 -7
  132. package/scripts/document/document-checks.ts +20 -0
  133. package/scripts/document/document-ratchet-check.ts +101 -0
  134. package/scripts/document/document-section.ts +1 -0
  135. package/scripts/document/entry-read-budget.ts +7 -3
  136. package/scripts/document/issue-citation-budget.ts +94 -0
  137. package/scripts/epic/epic-cli-argv.ts +2 -2
  138. package/scripts/epic/epic-fetch.ts +4 -2
  139. package/scripts/epic/epic-graph.ts +7 -2
  140. package/scripts/epic/epic-issue.ts +3 -1
  141. package/scripts/epic/epic-rank.ts +5 -0
  142. package/scripts/exports/unused-members-check.ts +62 -0
  143. package/scripts/exports/unused-members-cli.ts +6 -51
  144. package/scripts/followup/followup-ci-path.ts +67 -0
  145. package/scripts/followup/followup-coderabbit-retrigger.ts +261 -0
  146. package/scripts/followup/followup-coderabbit-wait.ts +13 -10
  147. package/scripts/followup/followup-failed-tests.ts +160 -0
  148. package/scripts/followup/followup-job-needs.ts +100 -0
  149. package/scripts/followup/followup-job-rerun.ts +303 -0
  150. package/scripts/followup/followup-main-move.ts +113 -0
  151. package/scripts/followup/git-followup-finish.ts +43 -11
  152. package/scripts/followup/git-followup-pending.ts +3 -3
  153. package/scripts/followup/git-followup-stages.ts +41 -11
  154. package/scripts/followup/git-pr-followup-checks.ts +55 -16
  155. package/scripts/followup/git-pr-followup-wrapup.ts +24 -5
  156. package/scripts/followup/git-pr-followup.ts +62 -27
  157. package/scripts/fresh-machine/fresh-machine-script.ts +5 -9
  158. package/scripts/fresh-machine/specs/kit-test-backlogrun-python.json +2 -2
  159. package/scripts/fresh-machine/specs/kit-test-backlogrun.json +2 -2
  160. package/scripts/gate/busy-average.ts +34 -2
  161. package/scripts/gate/check-related-pinned.ts +43 -0
  162. package/scripts/gate/check-related-reuse.ts +64 -0
  163. package/scripts/gate/check-related-section.ts +57 -0
  164. package/scripts/gate/check-related-unplanned.ts +34 -0
  165. package/scripts/gate/check-related.ts +265 -0
  166. package/scripts/gate/command-memory.ts +1 -1
  167. package/scripts/gate/core-admission.ts +24 -6
  168. package/scripts/gate/core-budget-timing.ts +20 -6
  169. package/scripts/gate/core-budget.ts +40 -11
  170. package/scripts/gate/core-wait-record.ts +3 -2
  171. package/scripts/gate/core-wait.ts +25 -2
  172. package/scripts/gate/core-weights.ts +15 -7
  173. package/scripts/gate/gate-labels.ts +46 -0
  174. package/scripts/gate/gate-ledger.ts +14 -6
  175. package/scripts/gate/gate-plan.ts +103 -58
  176. package/scripts/gate/gate-report.ts +9 -7
  177. package/scripts/gate/gate-run-steps.ts +26 -3
  178. package/scripts/gate/gate-skip.ts +45 -6
  179. package/scripts/gate/gate-static-group.ts +60 -0
  180. package/scripts/gate/gate-steps.ts +2 -1
  181. package/scripts/gate/gate-tree.ts +4 -2
  182. package/scripts/gate/hook-gate-reuse.ts +19 -2
  183. package/scripts/gate/metrics-totals.ts +59 -0
  184. package/scripts/gate/scoped-green.ts +68 -15
  185. package/scripts/gate/since-green.ts +14 -6
  186. package/scripts/gate/structural-checks.ts +96 -0
  187. package/scripts/gate/verification-gate.ts +51 -16
  188. package/scripts/gate/verification-inputs.ts +21 -6
  189. package/scripts/gate/verification-tail.ts +52 -0
  190. package/scripts/gh/gh-author-association.ts +23 -2
  191. package/scripts/gh/git-ai-review-scan.ts +1 -1
  192. package/scripts/gh/git-gh-api-path.ts +12 -3
  193. package/scripts/gh/git-gh-comments-unreadable.ts +36 -0
  194. package/scripts/gh/git-gh-exec.ts +32 -2
  195. package/scripts/gh/git-gh-issue-read.ts +4 -2
  196. package/scripts/gh/git-gh-issue-rest.ts +1 -0
  197. package/scripts/gh/git-gh-issue-write.ts +8 -2
  198. package/scripts/gh/git-gh-issue.ts +12 -5
  199. package/scripts/gh/git-gh-pr-auto-merge.ts +13 -6
  200. package/scripts/gh/git-gh-pr-graphql-state.ts +56 -0
  201. package/scripts/gh/git-gh-pr-read.ts +74 -13
  202. package/scripts/gh/git-gh-pr-rest.ts +3 -1
  203. package/scripts/gh/git-gh-pr-snapshot.ts +22 -7
  204. package/scripts/gh/git-gh-pr-too-large.ts +20 -0
  205. package/scripts/gh/git-gh-pr.ts +21 -7
  206. package/scripts/gh/git-gh-retry.ts +141 -0
  207. package/scripts/gh/git-pr-ai-review.ts +15 -6
  208. package/scripts/gh/git-pr-checks-eval.ts +3 -0
  209. package/scripts/gh/git-pr-checks.ts +5 -5
  210. package/scripts/git/base-tree.ts +30 -0
  211. package/scripts/git/change-base.ts +4 -10
  212. package/scripts/git/changed-paths-sync.ts +63 -0
  213. package/scripts/git/changed-paths.ts +16 -1
  214. package/scripts/git/git-common-directory.ts +11 -1
  215. package/scripts/git/git-diff-reads.ts +66 -20
  216. package/scripts/git/git-error.ts +9 -2
  217. package/scripts/git/git-schemas.ts +13 -0
  218. package/scripts/git/git-worktree.ts +13 -0
  219. package/scripts/git/gone-branch.ts +4 -1
  220. package/scripts/git/main-merge-budget-conflict.ts +89 -0
  221. package/scripts/git/main-merge-guard.ts +55 -18
  222. package/scripts/git/main-merge-regenerate.ts +59 -25
  223. package/scripts/git/main-merge.ts +53 -5
  224. package/scripts/git/no-base-checkout.ts +127 -0
  225. package/scripts/git/stash/git-stash.ts +11 -2
  226. package/scripts/git/stash/stash-push-cli.ts +10 -0
  227. package/scripts/hooks/batch-guard.ts +40 -21
  228. package/scripts/hooks/edited-cspell.ts +37 -11
  229. package/scripts/hooks/format-edited-file.ts +22 -2
  230. package/scripts/hooks/lane-plan-guard.ts +50 -0
  231. package/scripts/hooks/pre-commit-lint-switch.ts +9 -0
  232. package/scripts/hooks/pre-commit-lint.ts +14 -1
  233. package/scripts/hooks/pre-push-related-switch.ts +10 -0
  234. package/scripts/hooks/pre-push-unit.ts +76 -10
  235. package/scripts/hooks/pretool-guard.ts +2 -0
  236. package/scripts/hooks/reserved-run.ts +14 -1
  237. package/scripts/hooks/run-hook.sh +23 -8
  238. package/scripts/hooks/step-zero-notice.ts +6 -1
  239. package/scripts/hooks/stop-actions.ts +3 -15
  240. package/scripts/hooks/stop-guard.ts +7 -6
  241. package/scripts/init/distributed-paths.ts +1 -0
  242. package/scripts/init/hook-command-rewrite.ts +5 -1
  243. package/scripts/init/hook-launch.ts +4 -2
  244. package/scripts/issue/aggregation-split.ts +52 -0
  245. package/scripts/issue/defect-origin-line.ts +19 -1
  246. package/scripts/issue/defect-rate-cli.ts +5 -102
  247. package/scripts/issue/defect-report.ts +4 -4
  248. package/scripts/issue/effect-audit-cli.ts +178 -0
  249. package/scripts/issue/effect-audit.ts +185 -0
  250. package/scripts/issue/expected-effect-lint.ts +64 -9
  251. package/scripts/issue/git-next-issues.ts +5 -0
  252. package/scripts/issue/issue-body-or-comment.ts +38 -4
  253. package/scripts/issue/issue-cite-cli.ts +1 -3
  254. package/scripts/issue/issue-classification.ts +1 -0
  255. package/scripts/issue/issue-closing-pr.ts +8 -1
  256. package/scripts/issue/issue-evidence-exit.ts +4 -2
  257. package/scripts/issue/issue-file-cap.ts +58 -0
  258. package/scripts/issue/issue-file-cli.ts +111 -38
  259. package/scripts/issue/issue-file-deferral.ts +52 -0
  260. package/scripts/issue/issue-file-fold.ts +29 -10
  261. package/scripts/issue/issue-file-interrupt.ts +85 -0
  262. package/scripts/issue/issue-file-lane-hint.ts +30 -0
  263. package/scripts/issue/issue-file.ts +43 -6
  264. package/scripts/issue/issue-labels.ts +19 -2
  265. package/scripts/issue/issue-lint-cli.ts +27 -2
  266. package/scripts/issue/issue-measured-cli.ts +13 -35
  267. package/scripts/issue/issue-measured-close.ts +58 -0
  268. package/scripts/issue/issue-not-before-label.ts +2 -2
  269. package/scripts/issue/issue-not-before.ts +4 -1
  270. package/scripts/issue/issue-priority-cli.ts +60 -0
  271. package/scripts/issue/issue-priority-raise.ts +55 -0
  272. package/scripts/issue/issue-priority.ts +174 -43
  273. package/scripts/issue/issue-rank.ts +21 -4
  274. package/scripts/issue/issue-read-cli.ts +32 -6
  275. package/scripts/issue/issue-read.ts +37 -12
  276. package/scripts/issue/issue-sample-gate.ts +95 -74
  277. package/scripts/issue/issue-sample-prime.ts +127 -0
  278. package/scripts/issue/issue-sample-required.ts +57 -0
  279. package/scripts/issue/issue-sample-source.ts +12 -11
  280. package/scripts/issue/issue-search.ts +124 -0
  281. package/scripts/issue/issue-state.ts +13 -1
  282. package/scripts/issue/issue-template-section.ts +43 -0
  283. package/scripts/issue/issue-watch-diff.ts +31 -1
  284. package/scripts/issue/issue-watch-hook.ts +11 -2
  285. package/scripts/issue/issue-watch.ts +55 -12
  286. package/scripts/issue/markdown-section.ts +1 -0
  287. package/scripts/issue/measure-declaration.ts +121 -0
  288. package/scripts/issue/measure-rerun-cli.ts +7 -70
  289. package/scripts/issue/plan-consumers-section.ts +22 -1
  290. package/scripts/issue/reproduction-measure.ts +3 -1
  291. package/scripts/issue/size-estimate.ts +90 -0
  292. package/scripts/issue/trusted-measure.ts +84 -0
  293. package/scripts/josh/command-usage.ts +3 -2
  294. package/scripts/josh/durable-state-migrate.ts +105 -0
  295. package/scripts/josh/durable-state.ts +112 -0
  296. package/scripts/josh/josh-aliases.ts +95 -0
  297. package/scripts/josh/josh-command-map.ts +1 -82
  298. package/scripts/josh/josh-commands-agent-hooks.ts +6 -6
  299. package/scripts/josh/josh-commands-ai.ts +5 -5
  300. package/scripts/josh/josh-commands-development.ts +59 -58
  301. package/scripts/josh/josh-commands-issue-write.ts +23 -4
  302. package/scripts/josh/josh-commands-issue.ts +32 -0
  303. package/scripts/josh/josh-commands-lane.ts +87 -4
  304. package/scripts/josh/josh-commands-lint.ts +16 -3
  305. package/scripts/josh/josh-commands-maintenance.ts +15 -0
  306. package/scripts/josh/josh-commands-review.ts +41 -6
  307. package/scripts/josh/josh-commands-ship.ts +56 -8
  308. package/scripts/josh/josh-commands-test-check.ts +80 -0
  309. package/scripts/josh/josh-commands-workflow.ts +1 -1
  310. package/scripts/josh/josh-environment-file.ts +43 -3
  311. package/scripts/josh/josh-in-process.ts +2 -2
  312. package/scripts/josh/josh-logic.ts +5 -3
  313. package/scripts/josh/josh-run.ts +19 -1
  314. package/scripts/josh/run-record-path.ts +15 -0
  315. package/scripts/josh/stamp-file.ts +11 -2
  316. package/scripts/lane/lane-adopt-cli.ts +98 -0
  317. package/scripts/lane/lane-adopt.ts +208 -0
  318. package/scripts/lane/lane-await.ts +5 -8
  319. package/scripts/lane/lane-baseline.ts +123 -0
  320. package/scripts/lane/lane-breakdown-cli.ts +64 -0
  321. package/scripts/lane/lane-breakdown-implement.ts +170 -0
  322. package/scripts/lane/lane-breakdown-laps.ts +107 -0
  323. package/scripts/lane/lane-breakdown-pinned.ts +76 -0
  324. package/scripts/lane/lane-breakdown-text.ts +145 -0
  325. package/scripts/lane/lane-breakdown.ts +239 -0
  326. package/scripts/lane/lane-check-stats.ts +29 -8
  327. package/scripts/lane/lane-child-invocation.ts +9 -2
  328. package/scripts/lane/lane-child-mark-keys.ts +12 -0
  329. package/scripts/lane/lane-child-marker.ts +20 -1
  330. package/scripts/lane/lane-ci-path-stats.ts +73 -0
  331. package/scripts/lane/lane-claim-stats.ts +84 -0
  332. package/scripts/lane/lane-close.ts +8 -3
  333. package/scripts/lane/lane-dispatch-log.ts +3 -3
  334. package/scripts/lane/lane-dispatch.ts +2 -2
  335. package/scripts/lane/lane-gap-stats.ts +7 -6
  336. package/scripts/lane/lane-guard-policy.ts +7 -1
  337. package/scripts/lane/lane-implement-stats.ts +207 -0
  338. package/scripts/lane/lane-implement-subagents.ts +90 -0
  339. package/scripts/lane/lane-investigation-switch.ts +16 -0
  340. package/scripts/lane/lane-ledger-kind.ts +31 -0
  341. package/scripts/lane/lane-ledger-schema-ship.ts +49 -0
  342. package/scripts/lane/lane-ledger-schema.ts +119 -36
  343. package/scripts/lane/lane-ledger-write.ts +257 -0
  344. package/scripts/lane/lane-ledger.ts +31 -177
  345. package/scripts/lane/lane-load.ts +1 -1
  346. package/scripts/lane/lane-measure-cli.ts +176 -59
  347. package/scripts/lane/lane-net-read.ts +44 -0
  348. package/scripts/lane/lane-net-time.ts +212 -0
  349. package/scripts/lane/lane-open.ts +16 -7
  350. package/scripts/lane/lane-output.ts +2 -4
  351. package/scripts/lane/lane-overrun-prompt.ts +147 -0
  352. package/scripts/lane/lane-overrun.ts +274 -0
  353. package/scripts/lane/lane-paths.ts +24 -1
  354. package/scripts/lane/lane-pause-cli.ts +4 -1
  355. package/scripts/lane/lane-paused-spans.ts +97 -0
  356. package/scripts/lane/lane-plan-check.ts +207 -0
  357. package/scripts/lane/lane-plan-cli.ts +41 -0
  358. package/scripts/lane/lane-plan.ts +144 -0
  359. package/scripts/lane/lane-registry.ts +14 -1
  360. package/scripts/lane/lane-relaunch.ts +1 -1
  361. package/scripts/lane/lane-round-one-stats.ts +51 -0
  362. package/scripts/lane/lane-sampler.ts +23 -4
  363. package/scripts/lane/lane-session-action.ts +93 -18
  364. package/scripts/lane/lane-session-broker.ts +49 -21
  365. package/scripts/lane/lane-session-reread-main.ts +14 -0
  366. package/scripts/lane/lane-session-reread.ts +51 -0
  367. package/scripts/lane/lane-ship-lap-stats.ts +74 -0
  368. package/scripts/lane/lane-sleep.ts +58 -0
  369. package/scripts/lane/lane-spent.ts +1 -1
  370. package/scripts/lane/lane-split-stats.ts +28 -0
  371. package/scripts/lane/lane-stage-stats.ts +13 -1
  372. package/scripts/lane/lane-state.ts +41 -9
  373. package/scripts/lane/lane-stats-tables.ts +58 -0
  374. package/scripts/lane/lane-stats.ts +21 -5
  375. package/scripts/lane/lane-stop-stats.ts +51 -19
  376. package/scripts/lane/lane-tail-stats.ts +32 -0
  377. package/scripts/lane/lane-transcript-calls.ts +67 -10
  378. package/scripts/lane/lane-transcript-stats.ts +44 -12
  379. package/scripts/lane/lane-value-cell.ts +72 -0
  380. package/scripts/lane/lane-value.ts +118 -0
  381. package/scripts/lane/lane-withdraw-closed.ts +124 -0
  382. package/scripts/lane/lane-withdraw.ts +108 -31
  383. package/scripts/lane/lane-yield.ts +85 -0
  384. package/scripts/lane/openai-lane-ship.ts +12 -11
  385. package/scripts/lane/openai-lane-supervisor-decision.ts +6 -8
  386. package/scripts/lane/openai-lane-supervisor-owner.ts +5 -8
  387. package/scripts/lane/openai-lane-supervisor.ts +5 -4
  388. package/scripts/lib/poll.ts +38 -9
  389. package/scripts/lib/settled-together.ts +10 -0
  390. package/scripts/lib/shell-quote.ts +21 -0
  391. package/scripts/lib/token-shape.ts +111 -0
  392. package/scripts/lint/eslint-daemon-sources.ts +79 -0
  393. package/scripts/lint/eslint-daemon.ts +45 -6
  394. package/scripts/lint/eslint-warm-cli.ts +7 -0
  395. package/scripts/lint/eslint-warm.ts +66 -0
  396. package/scripts/lint/import-graph.ts +141 -11
  397. package/scripts/lint/lint-gate-scope.ts +2 -2
  398. package/scripts/lint/lint-parallel.ts +54 -6
  399. package/scripts/lint/lint-related.ts +154 -33
  400. package/scripts/lint/rename-cli.ts +179 -0
  401. package/scripts/lint/rename-identifier.ts +192 -0
  402. package/scripts/lint/type-only-imports.ts +58 -0
  403. package/scripts/notify/telegram-notify.ts +12 -3
  404. package/scripts/observations/observation-record.ts +42 -16
  405. package/scripts/observations/observations-flush.ts +32 -9
  406. package/scripts/overrides/overrides-check.ts +9 -1
  407. package/scripts/release/release-approval-prune.ts +7 -1
  408. package/scripts/repo/required-checks-logic.ts +4 -1
  409. package/scripts/repo/ruleset-check.ts +4 -3
  410. package/scripts/report/markdown-shape.ts +28 -0
  411. package/scripts/report/report-format-reference.ts +15 -1
  412. package/scripts/report/report-labels.ts +12 -1
  413. package/scripts/report/report-lint-child-summary.ts +94 -0
  414. package/scripts/report/report-lint-cli.ts +26 -7
  415. package/scripts/report/report-lint.ts +2 -20
  416. package/scripts/review/prose-stale-cli.ts +88 -0
  417. package/scripts/review/prose-stale-scan.ts +152 -0
  418. package/scripts/review/review-attest.ts +73 -23
  419. package/scripts/review/review-brief-cli.ts +68 -19
  420. package/scripts/review/review-brief-paths.ts +22 -0
  421. package/scripts/review/review-brief.ts +14 -7
  422. package/scripts/review/review-comment-carry.ts +47 -0
  423. package/scripts/review/review-comment-round.ts +85 -22
  424. package/scripts/review/review-finding-ledger.ts +109 -7
  425. package/scripts/review/review-finding-text.ts +43 -0
  426. package/scripts/review/review-interaction.ts +11 -0
  427. package/scripts/review/review-lane-handover.ts +68 -0
  428. package/scripts/review/review-lint-cli.ts +57 -0
  429. package/scripts/review/review-lint-findings.ts +92 -0
  430. package/scripts/review/review-lint-sections.ts +80 -0
  431. package/scripts/review/review-lint.ts +221 -0
  432. package/scripts/review/review-prior-findings.ts +102 -0
  433. package/scripts/review/review-readers-scan.ts +4 -2
  434. package/scripts/review/review-record-cli.ts +177 -54
  435. package/scripts/review/review-record-code-round.ts +55 -0
  436. package/scripts/review/review-record-comment.ts +60 -0
  437. package/scripts/review/review-record-interaction.ts +35 -0
  438. package/scripts/review/review-record-pinned.ts +108 -0
  439. package/scripts/review/review-record.ts +25 -1
  440. package/scripts/review/review-reviewed-tree.ts +307 -0
  441. package/scripts/review/review-round-one-closure.ts +62 -0
  442. package/scripts/review/review-round-reuse.ts +106 -0
  443. package/scripts/review/review-round2-cli.ts +91 -29
  444. package/scripts/review/review-round2-skip-comment.ts +55 -0
  445. package/scripts/review/review-round2.ts +24 -8
  446. package/scripts/review/review-stamps.ts +7 -3
  447. package/scripts/review/review-stop-log.ts +20 -6
  448. package/scripts/review/review-stops-cli.ts +2 -1
  449. package/scripts/review/review-submit-cli.ts +101 -0
  450. package/scripts/rules/agent-model.ts +1 -1
  451. package/scripts/rules/bash-triggers.ts +3 -3
  452. package/scripts/rules/concise-reply.ts +88 -0
  453. package/scripts/rules/credential-body.ts +77 -0
  454. package/scripts/rules/decision-oracle.ts +1 -1
  455. package/scripts/rules/delivered-rules.ts +36 -17
  456. package/scripts/rules/destructive-command.ts +3 -11
  457. package/scripts/rules/direct-issue-comment.ts +34 -12
  458. package/scripts/rules/direct-issue-read.ts +191 -0
  459. package/scripts/rules/direct-pr-create.ts +4 -24
  460. package/scripts/rules/early-heartbeat.ts +2 -0
  461. package/scripts/rules/edit-tool.ts +27 -0
  462. package/scripts/rules/file-edit-rows.ts +17 -0
  463. package/scripts/rules/file-rewrite.ts +146 -0
  464. package/scripts/rules/firing-point.ts +3 -2
  465. package/scripts/rules/gh-api.ts +128 -7
  466. package/scripts/rules/gh-repo-selector.ts +84 -0
  467. package/scripts/rules/git-force.ts +2 -2
  468. package/scripts/rules/guard-remedy.ts +14 -5
  469. package/scripts/rules/implementation-cut.ts +61 -28
  470. package/scripts/rules/investigator-foreground.ts +231 -0
  471. package/scripts/rules/issue-citation.ts +15 -60
  472. package/scripts/rules/issue-comments.ts +9 -4
  473. package/scripts/rules/josh-git-bare.ts +1 -1
  474. package/scripts/rules/lane-background.ts +41 -13
  475. package/scripts/rules/lane-direct-tool.ts +107 -9
  476. package/scripts/rules/lane-interactive-ask.ts +4 -1
  477. package/scripts/rules/lane-park.ts +4 -2
  478. package/scripts/rules/lane-spilled-read.ts +90 -0
  479. package/scripts/rules/lane-split-park.ts +1 -1
  480. package/scripts/rules/lane-switch-main.ts +4 -4
  481. package/scripts/rules/last-prompt.ts +20 -47
  482. package/scripts/rules/oracle-consulted.ts +1 -1
  483. package/scripts/rules/permission-guards.ts +5 -1
  484. package/scripts/rules/piped-verification-shapes.ts +110 -0
  485. package/scripts/rules/piped-verification.ts +67 -17
  486. package/scripts/rules/poll-loop.ts +72 -9
  487. package/scripts/rules/pr-merge.ts +5 -5
  488. package/scripts/rules/pre-gate-cut.ts +3 -3
  489. package/scripts/rules/protected-files.ts +88 -24
  490. package/scripts/rules/reply-language.ts +3 -17
  491. package/scripts/rules/reply-prose.ts +34 -0
  492. package/scripts/rules/repo-admin.ts +132 -0
  493. package/scripts/rules/reviewer-foreground.ts +88 -0
  494. package/scripts/rules/round-one-check-related.ts +120 -0
  495. package/scripts/rules/rule-body-guard.ts +5 -15
  496. package/scripts/rules/rule-value-cache.ts +53 -5
  497. package/scripts/rules/rule-value-candidates.ts +84 -0
  498. package/scripts/rules/rule-value-cli.ts +59 -11
  499. package/scripts/rules/rule-value.ts +17 -4
  500. package/scripts/rules/run-tail-rule.ts +1 -1
  501. package/scripts/rules/sed-in-place.ts +196 -0
  502. package/scripts/rules/shell-segments.ts +10 -2
  503. package/scripts/rules/stop-rule-rows.ts +1 -13
  504. package/scripts/rules/stop-rules.ts +33 -58
  505. package/scripts/rules/test-declared-commit.ts +1 -1
  506. package/scripts/rules/third-party-write.ts +110 -23
  507. package/scripts/rules/timed-rerun.ts +1 -1
  508. package/scripts/rules/turn-filings.ts +90 -0
  509. package/scripts/rules/worktree-guard.ts +22 -7
  510. package/scripts/run/board/run-board-ending-reason.ts +6 -2
  511. package/scripts/run/board/run-board-fit.ts +24 -1
  512. package/scripts/run/board/run-board-found.ts +134 -0
  513. package/scripts/run/board/run-board-header.ts +8 -0
  514. package/scripts/run/board/run-board-labels.ts +11 -1
  515. package/scripts/run/board/run-board-lane-time.ts +1 -0
  516. package/scripts/run/board/run-board-link.ts +15 -2
  517. package/scripts/run/board/run-board-notes.ts +7 -1
  518. package/scripts/run/board/run-board-operation.ts +4 -2
  519. package/scripts/run/board/run-board-phase.ts +2 -5
  520. package/scripts/run/board/run-board-plan.ts +1 -1
  521. package/scripts/run/board/run-board-read.ts +46 -1
  522. package/scripts/run/board/run-board-reason.ts +20 -8
  523. package/scripts/run/board/run-board-render-checks.ts +3 -2
  524. package/scripts/run/board/run-board-render-drawn.ts +11 -0
  525. package/scripts/run/board/run-board-render-found.ts +157 -0
  526. package/scripts/run/board/run-board-render-lead.ts +9 -0
  527. package/scripts/run/board/run-board-render-legend.ts +19 -0
  528. package/scripts/run/board/run-board-render-tail.ts +1 -1
  529. package/scripts/run/board/run-board-render.ts +82 -18
  530. package/scripts/run/board/run-board-spin.ts +1 -3
  531. package/scripts/run/board/run-board-status.ts +2 -0
  532. package/scripts/run/board/run-board-tick.ts +39 -10
  533. package/scripts/run/carry/run-carry-ended.ts +3 -2
  534. package/scripts/run/carry/run-carry.ts +3 -2
  535. package/scripts/run/cut/run-cut-cli.ts +33 -133
  536. package/scripts/run/cut/run-cut-digest.ts +152 -0
  537. package/scripts/run/cut/run-cut-handoff.ts +52 -8
  538. package/scripts/run/cut/run-cut-report.ts +24 -3
  539. package/scripts/run/cut/run-cut-resume.ts +129 -0
  540. package/scripts/run/cut/run-cut-review.ts +105 -0
  541. package/scripts/run/cut/run-cut.ts +18 -7
  542. package/scripts/run/detached-launch.ts +1 -1
  543. package/scripts/run/entry/run-entry-cli.ts +88 -19
  544. package/scripts/run/entry/run-entry-spill.ts +83 -0
  545. package/scripts/run/entry/run-entry-stop.ts +5 -1
  546. package/scripts/run/entry/run-entry-trust.ts +91 -0
  547. package/scripts/run/event/run-event-baseline.ts +56 -0
  548. package/scripts/run/event/run-event-filed.ts +9 -3
  549. package/scripts/run/event/run-event-overrun.ts +197 -0
  550. package/scripts/run/event/run-event-render.ts +4 -0
  551. package/scripts/run/event/run-event-stream.ts +25 -3
  552. package/scripts/run/hold/run-stop-notify.ts +3 -8
  553. package/scripts/run/merge/run-merge-cap.ts +57 -0
  554. package/scripts/run/merge/run-merge-cli.ts +66 -23
  555. package/scripts/run/merge/run-merge-outcome.ts +2 -0
  556. package/scripts/run/merge/run-merge-ship.ts +13 -3
  557. package/scripts/run/merge/run-merge-signals.ts +40 -23
  558. package/scripts/run/merge/run-merge-steps.ts +56 -36
  559. package/scripts/run/merge/run-merge-usage-limit.ts +53 -0
  560. package/scripts/run/merge/run-merge-withdrawn.ts +53 -0
  561. package/scripts/run/merge/run-merge.ts +41 -14
  562. package/scripts/run/review/run-review-cli.ts +306 -20
  563. package/scripts/run/review/run-review-early-push.ts +121 -0
  564. package/scripts/run/review/run-review-join-read.ts +94 -0
  565. package/scripts/run/review/run-review-pinned-accepted.ts +126 -0
  566. package/scripts/run/review/run-review-pinned-join.ts +216 -0
  567. package/scripts/run/review/run-review-pinned-steps.ts +383 -0
  568. package/scripts/run/review/run-review-pinned-tree.ts +37 -0
  569. package/scripts/run/review/run-review-pinned.ts +53 -0
  570. package/scripts/run/review/run-review-steps.ts +70 -34
  571. package/scripts/run/review/run-review.ts +26 -6
  572. package/scripts/run/run-parent-cut-hook.ts +3 -4
  573. package/scripts/run/run-prep.ts +1 -0
  574. package/scripts/run/run-stage-read.ts +2 -6
  575. package/scripts/run/run-step-cli.ts +17 -5
  576. package/scripts/run/run-step-lane-plan.ts +27 -0
  577. package/scripts/run/run-step-section.ts +26 -7
  578. package/scripts/run/run-step.ts +5 -2
  579. package/scripts/run/ship/run-ship-args.ts +19 -0
  580. package/scripts/run/ship/run-ship-brokered-review.ts +106 -0
  581. package/scripts/run/ship/run-ship-cli.ts +131 -39
  582. package/scripts/run/ship/run-ship-conflict-probe.ts +59 -0
  583. package/scripts/run/ship/run-ship-detach.ts +10 -4
  584. package/scripts/run/ship/run-ship-handover.ts +106 -0
  585. package/scripts/run/ship/run-ship-infra-retry.ts +16 -1
  586. package/scripts/run/ship/run-ship-lap.ts +63 -0
  587. package/scripts/run/ship/run-ship-next.ts +27 -26
  588. package/scripts/run/ship/run-ship-overlap.ts +8 -3
  589. package/scripts/run/ship/run-ship-place.ts +9 -2
  590. package/scripts/run/ship/run-ship-planned.ts +92 -0
  591. package/scripts/run/ship/run-ship-pre-detach-pinned.ts +197 -0
  592. package/scripts/run/ship/run-ship-pre-detach-timed.ts +7 -8
  593. package/scripts/run/ship/run-ship-pre-detach.ts +77 -23
  594. package/scripts/run/ship/run-ship-preflight.ts +16 -4
  595. package/scripts/run/ship/run-ship-probe.ts +23 -9
  596. package/scripts/run/ship/run-ship-relaunch-cap.ts +43 -7
  597. package/scripts/run/ship/run-ship-relaunch.ts +51 -0
  598. package/scripts/run/ship/run-ship-return.ts +103 -29
  599. package/scripts/run/ship/run-ship-review-reason.ts +24 -0
  600. package/scripts/run/ship/run-ship-review-steps.ts +230 -59
  601. package/scripts/run/ship/run-ship-review.ts +171 -51
  602. package/scripts/run/ship/run-ship-reviewer.ts +138 -42
  603. package/scripts/run/ship/run-ship-scoped.ts +39 -10
  604. package/scripts/run/ship/run-ship-stage.ts +49 -13
  605. package/scripts/run/ship/run-ship-steps.ts +24 -4
  606. package/scripts/run/ship/run-ship-stop-cause.ts +43 -2
  607. package/scripts/run/ship/run-ship-stop-context.ts +50 -13
  608. package/scripts/run/ship/run-ship-sync.ts +171 -30
  609. package/scripts/run/ship/run-ship-synced-scope.ts +178 -0
  610. package/scripts/run/ship/run-ship-wait-cli.ts +145 -0
  611. package/scripts/run/ship/run-ship-waiter.ts +114 -0
  612. package/scripts/run/ship/run-ship.ts +16 -2
  613. package/scripts/run/wake/run-wake-caffeinate.ts +48 -0
  614. package/scripts/run/wake/run-wake-cli.ts +6 -113
  615. package/scripts/run/wake/run-wake-code.ts +53 -11
  616. package/scripts/run/wake/run-wake-driver.ts +5 -3
  617. package/scripts/run/wake/run-wake-finish.ts +137 -0
  618. package/scripts/run/wake/run-wake-loop.ts +5 -3
  619. package/scripts/run/wake/run-wake-ports.ts +11 -3
  620. package/scripts/run/wake/run-wake-session.ts +2 -0
  621. package/scripts/run/wake/run-wake.ts +3 -2
  622. package/scripts/safe-chain/ci-installer-pin.ts +49 -8
  623. package/scripts/safe-chain/project-config.ts +3 -2
  624. package/scripts/security/secretlint-scan.ts +42 -9
  625. package/scripts/security/security-audit-provision-main.ts +9 -1
  626. package/scripts/security/security-audit-provision.ts +1 -1
  627. package/scripts/security/security-audit.ts +21 -1
  628. package/scripts/security/sonar-file.ts +10 -5
  629. package/scripts/split/split-assess.ts +12 -3
  630. package/scripts/split/split-early-notice.ts +116 -0
  631. package/scripts/split/split-measure.ts +20 -2
  632. package/scripts/split/split-resolution.ts +107 -0
  633. package/scripts/test/direct-importers.ts +185 -0
  634. package/scripts/test/pure-files-entries.ts +83 -0
  635. package/scripts/test/related-heavy-tests.ts +81 -0
  636. package/scripts/test/test-no-base.ts +88 -0
  637. package/scripts/test/test-pinned-cache-logic.ts +363 -0
  638. package/scripts/test/test-pinned-cache.ts +337 -0
  639. package/scripts/test/test-pinned-emit.ts +49 -0
  640. package/scripts/test/test-pinned-functions.ts +116 -0
  641. package/scripts/test/test-pinned-ledger.ts +80 -0
  642. package/scripts/test/test-pinned-logic.ts +208 -20
  643. package/scripts/test/test-pinned-main.ts +84 -18
  644. package/scripts/test/test-pinned-pool.ts +73 -0
  645. package/scripts/test/test-pinned-probe.ts +254 -0
  646. package/scripts/test/test-pinned-prune-logic.ts +118 -0
  647. package/scripts/test/test-pinned-reach.ts +194 -0
  648. package/scripts/test/test-pinned-record.ts +196 -0
  649. package/scripts/test/test-pinned-rewire.ts +148 -0
  650. package/scripts/test/test-pinned-spawn.ts +81 -0
  651. package/scripts/test/test-pinned-stage.ts +70 -0
  652. package/scripts/test/test-pinned.ts +258 -47
  653. package/scripts/test/test-reach-cli.ts +61 -0
  654. package/scripts/test/test-read-map.ts +35 -11
  655. package/scripts/test/test-read-recording.ts +17 -5
  656. package/scripts/test/test-read-trace.ts +26 -8
  657. package/scripts/test/test-red-logic.ts +46 -7
  658. package/scripts/test/test-red.ts +34 -14
  659. package/scripts/test/test-related-claim.ts +37 -0
  660. package/scripts/test/test-related-main.ts +4 -1
  661. package/scripts/test/test-related-moved.ts +91 -0
  662. package/scripts/test/test-related-record.ts +43 -23
  663. package/scripts/test/test-related-scope.ts +99 -34
  664. package/scripts/test/test-related-synced.ts +135 -0
  665. package/scripts/test/test-related-touched.ts +84 -0
  666. package/scripts/test/test-related.ts +167 -83
  667. package/scripts/test/test-unit-guard.ts +28 -5
  668. package/scripts/test/unit-durations.ts +41 -0
  669. package/scripts/test/unit-worker-share.ts +5 -4
  670. package/scripts/test/vitest-cache-directory.ts +19 -0
  671. package/scripts/test/vitest-cli-excludes.ts +14 -0
  672. package/scripts/test/vitest-failure-summary.ts +111 -0
  673. package/scripts/test/whole-suite-files.ts +12 -1
  674. package/scripts/time-runtime/time-batch-guard.ts +42 -4
  675. package/scripts/time-runtime/time-bundle-call.ts +1 -1
  676. package/scripts/time-runtime/time-bundles.ts +36 -5
  677. package/scripts/time-runtime/time-markers.ts +2 -2
  678. package/scripts/time-runtime/time-search-call.ts +38 -0
  679. package/scripts/time-runtime/time-shell.ts +1 -1
  680. package/scripts/time-runtime/time-transcript-line.ts +17 -5
  681. package/scripts/version/development-engines-verdict.ts +124 -0
  682. package/scripts/version/latest-corepack.ts +2 -0
  683. package/templates/gitignore +2 -0
  684. package/templates/workflows/ci.yml +41 -0
  685. package/dist/hooks/chunk-AZX4FGQ3.js +0 -207
  686. package/dist/hooks/chunk-PT5R6UJD.js +0 -7131
  687. package/dist/hooks/chunk-TUIFS5E7.js +0 -72
  688. package/dist/hooks/chunk-YCDOIR3I.js +0 -3456
  689. package/scripts/cost-runtime/context-cut-threshold.ts +0 -11
  690. package/scripts/rules/filing-cap.ts +0 -139
@@ -1,6 +1,7 @@
1
1
  import { randomUUID } from 'node:crypto'
2
2
  import type { AgentProfile } from '#scripts/agent/agent-role-profile'
3
3
  import { lane_close } from '#scripts/lane/lane-close'
4
+ import { lane_withdraw_closed } from '#scripts/lane/lane-withdraw-closed'
4
5
  import { poll } from '#scripts/lib/poll'
5
6
  import { run_carry } from '#scripts/run/carry/run-carry'
6
7
  import { run_event_setup } from '#scripts/run/event/run-event-setup'
@@ -54,6 +55,15 @@ function wake_session(
54
55
  return result
55
56
  }
56
57
 
58
+ // The lanes the supervisor ends each pass: closes left incomplete, and lanes whose issue was closed as
59
+ // not planned (`lane-withdraw-closed.ts`), each withdrawal said on stderr.
60
+ async function retry_closes(): Promise<void> {
61
+ await lane_close.retry_closes()
62
+ const notes = await lane_withdraw_closed.withdraw_closed()
63
+
64
+ for (const note of notes) note_to_stderr(note)
65
+ }
66
+
57
67
  // **A record this supervisor owns itself is not a session at work.** A failed driver leaves the record
58
68
  // adopted for this process, so reading that owner as live would have every restarted pass wait on
59
69
  // itself and never drive again.
@@ -79,9 +89,7 @@ function ports_for(
79
89
  wake_session(context, invocation, profile, { id: session_id, material }),
80
90
  sleep: poll.sleep,
81
91
  now: () => new Date(),
82
- retry_closes: async () => {
83
- await lane_close.retry_closes()
84
- },
92
+ retry_closes,
85
93
  }
86
94
  }
87
95
 
@@ -9,6 +9,7 @@ import { claude_agent_argv } from '#scripts/agent/claude-agent-argv'
9
9
  import { backlogrun_launch } from '#scripts/backlog/backlogrun-launch'
10
10
  import { detached_launch, type LaunchArgv } from '#scripts/run/detached-launch'
11
11
  import { run_invocation } from '#scripts/run/run-invocation'
12
+ import { run_wake_caffeinate } from './run-wake-caffeinate'
12
13
 
13
14
  // How the supervisor starts things: the next agent session, and — at `--start` — its own detached
14
15
  // self. Both go through one `launch`, because the two differ only in what is being run.
@@ -164,6 +165,7 @@ const run_wake_session = {
164
165
  WAKE_FLAGS,
165
166
  ensure_log: detached_launch.ensure_log,
166
167
  is_safe_argv: detached_launch.is_safe_argv,
168
+ keep_awake: run_wake_caffeinate.keep_awake,
167
169
  launch: detached_launch.launch,
168
170
  chosen_profile,
169
171
  scheduler_profile,
@@ -1,5 +1,6 @@
1
1
  import { agent_role_profile, type AgentProfile } from '#scripts/agent/agent-role-profile'
2
2
  import { backlog_budget } from '#scripts/backlog/backlog-budget'
3
+ import { durable_state } from '#scripts/josh/durable-state'
3
4
  import { process_identity } from '#scripts/josh/process-identity'
4
5
  import { process_owner_schema } from '#scripts/josh/process-owner'
5
6
  import { stamp_file } from '#scripts/josh/stamp-file'
@@ -16,7 +17,7 @@ import { z } from 'zod'
16
17
 
17
18
  const WAKE_PREFIX = 'josh-run-wake-'
18
19
  // The output of every session this starts, appended per repository so a silent death is diagnosable.
19
- const WAKE_LOG_PREFIX = 'josh-run-wake-log-'
20
+ const WAKE_LOG_PREFIX = durable_state.PREFIX.WAKE_LOG
20
21
  const WAKE_LOG_SUFFIX = '.log'
21
22
  // How long a woken session has to claim the carry record — the only launch-failure detector, since a
22
23
  // claim also catches a session that dies in boot or never picks the run up. It covers a slow cold start.
@@ -153,7 +154,7 @@ function wake_path(git_directory: string): string {
153
154
  }
154
155
 
155
156
  function wake_log_path(git_directory: string): string {
156
- return stamp_file.stamp_path(WAKE_LOG_PREFIX, git_directory, WAKE_LOG_SUFFIX)
157
+ return durable_state.path(WAKE_LOG_PREFIX, git_directory, WAKE_LOG_SUFFIX)
157
158
  }
158
159
 
159
160
  function parse_wake(raw: string): RunWake | undefined {
@@ -1,5 +1,7 @@
1
1
  import { createHash } from 'node:crypto'
2
- import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'
2
+ import { existsSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
3
+ import { tmpdir } from 'node:os'
4
+ import path from 'node:path'
3
5
  import { composite_actions } from '#scripts/ci/composite-actions'
4
6
  import { execaSync } from 'execa'
5
7
 
@@ -16,6 +18,9 @@ const VERSION_RE = /^(?<key>[ \t]*SAFE_CHAIN_INSTALLER_VERSION:[ \t]*)(?<value>\
16
18
  const SHA256_RE = /^(?<key>[ \t]*SAFE_CHAIN_INSTALLER_SHA256:[ \t]*)(?<value>\S+)[ \t]*$/mu
17
19
  const VALUE_GROUP = 'value'
18
20
  const DOWNLOAD_TIMEOUT_MS = 30_000
21
+ const REPOSITORY = 'AikidoSec/safe-chain'
22
+ const INSTALLER_NAME = 'install-safe-chain.sh'
23
+ const ATTESTATION_FAILURE = 'could not be verified against its release attestation'
19
24
 
20
25
  interface InstallerPin {
21
26
  version: string
@@ -23,7 +28,7 @@ interface InstallerPin {
23
28
  }
24
29
 
25
30
  function installer_url(version: string): string {
26
- return `https://github.com/AikidoSec/safe-chain/releases/download/${version}/install-safe-chain.sh`
31
+ return `https://github.com/${REPOSITORY}/releases/download/${version}/${INSTALLER_NAME}`
27
32
  }
28
33
 
29
34
  // The local composite actions follow the workflows: kit's own pin lives in
@@ -50,7 +55,7 @@ function rewrite_pin(content: string, pin: InstallerPin): string {
50
55
  .replace(SHA256_RE, (_match, key: string) => `${key}${pin.sha256}`)
51
56
  }
52
57
 
53
- function fetch_installer_sha256(version: string): string | undefined {
58
+ function fetch_installer(version: string): Uint8Array | undefined {
54
59
  // `--proto =https` keeps the release redirect from being followed onto plain HTTP.
55
60
  const result = execaSync('curl', ['--proto', '=https', '-fsSL', installer_url(version)], {
56
61
  encoding: 'buffer',
@@ -61,7 +66,41 @@ function fetch_installer_sha256(version: string): string | undefined {
61
66
  })
62
67
  if (result.exitCode !== 0 || result.stdout.length === 0) return undefined
63
68
 
64
- return createHash('sha256').update(result.stdout).digest('hex')
69
+ return result.stdout
70
+ }
71
+
72
+ // joshuafolkken/kit#4669: the hash recorded is the one the release's GitHub attestation signs, not
73
+ // whatever the download happened to return. `gh release verify-asset` checks the signed attestation
74
+ // GitHub issued when the release was published, so a release asset swapped afterwards fails here.
75
+ function verify_installer(version: string, installer: Uint8Array): boolean {
76
+ const directory = mkdtempSync(path.join(tmpdir(), 'safe-chain-installer-'))
77
+ const installer_path = path.join(directory, INSTALLER_NAME)
78
+
79
+ try {
80
+ writeFileSync(installer_path, installer)
81
+ const result = execaSync(
82
+ 'gh',
83
+ ['release', 'verify-asset', version, installer_path, '--repo', REPOSITORY],
84
+ {
85
+ reject: false,
86
+ timeout: DOWNLOAD_TIMEOUT_MS,
87
+ },
88
+ )
89
+
90
+ return result.exitCode === 0
91
+ } finally {
92
+ rmSync(directory, { recursive: true, force: true })
93
+ }
94
+ }
95
+
96
+ // The hash to record, or why there is none — a pin is written only from a verified installer.
97
+ function fetch_installer_sha256(version: string): { sha256: string } | { failure: string } {
98
+ const installer = fetch_installer(version)
99
+ if (installer === undefined) return { failure: 'could not be downloaded' }
100
+ // A missing or signed-out `gh` lands here too: no verification means no pin, whatever the reason.
101
+ if (!verify_installer(version, installer)) return { failure: ATTESTATION_FAILURE }
102
+
103
+ return { sha256: createHash('sha256').update(installer).digest('hex') }
65
104
  }
66
105
 
67
106
  // The workflows whose pin lags `latest` — a missing file or one without the pin is not a target.
@@ -83,15 +122,17 @@ function sync(latest: string, workflow_paths: ReadonlyArray<string> = list_workf
83
122
  const targets = stale_workflows(latest, workflow_paths)
84
123
  if (targets.length === 0) return
85
124
 
86
- const sha256 = fetch_installer_sha256(latest)
125
+ const fetched = fetch_installer_sha256(latest)
87
126
 
88
- if (sha256 === undefined) {
89
- console.warn(`\n⚠ Could not download the safe-chain ${latest} installer; CI pin left as is`)
127
+ if ('failure' in fetched) {
128
+ console.warn(`\n⚠ The safe-chain ${latest} installer ${fetched.failure}; CI pin left as is`)
90
129
 
91
130
  return
92
131
  }
93
132
 
94
- for (const workflow_path of targets) write_pin(workflow_path, { version: latest, sha256 })
133
+ for (const workflow_path of targets) {
134
+ write_pin(workflow_path, { version: latest, sha256: fetched.sha256 })
135
+ }
95
136
  }
96
137
 
97
138
  const ci_installer_pin = {
@@ -1,7 +1,8 @@
1
- import { existsSync, readFileSync, writeFileSync } from 'node:fs'
1
+ import { existsSync, readFileSync } from 'node:fs'
2
2
  import path from 'node:path'
3
3
  import { file_reader } from '#scripts/lib/read-file'
4
4
  import { yaml_document } from '#scripts/lib/yaml-document'
5
+ import { file_content } from '#scripts/sync/file-content'
5
6
  import { release_window } from '#scripts/version/release-window'
6
7
  import { dump } from 'js-yaml'
7
8
 
@@ -139,7 +140,7 @@ function sync_project_config(root: string): boolean {
139
140
  const workspace = readFileSync(workspace_path, 'utf8')
140
141
  const merged = merge_project_config(existing, workspace)
141
142
  if (merged === existing) return false
142
- writeFileSync(config_path, merged)
143
+ file_content.write_contained(config_path, merged)
143
144
 
144
145
  return true
145
146
  }
@@ -7,7 +7,11 @@ import { execaSync } from 'execa'
7
7
 
8
8
  const SECRETLINT_BIN = 'secretlint'
9
9
  const NO_GLOB_FLAG = '--no-glob'
10
+ const END_OF_OPTIONS = '--'
10
11
  const ARGV_OFFSET = 2
12
+ // Set by the CI `Secret Scan` job, where nothing provisions the binary later: there a missing
13
+ // secretlint would turn the scan into a silent pass, so it fails instead (kit#4657).
14
+ const REQUIRE_ENV = 'JOSH_SECRETLINT_REQUIRE'
11
15
 
12
16
  // The scan is defense in depth ahead of GitHub push protection, not the only gate, so a
13
17
  // missing binary must not block the commit. kit ships the pre-commit rule inside
@@ -21,7 +25,14 @@ const MISSING_NOTICE =
21
25
  ` The kit pre-commit hook ships ahead of the dependency it needs.\n` +
22
26
  ` Run \`pnpm josh sync && pnpm install\` to provision it.`
23
27
 
24
- type ScanDecision = { kind: 'skip'; notice?: string } | { kind: 'scan'; binary: string }
28
+ const REQUIRED_MISSING_ERROR =
29
+ `❌ secretlint is not installed, and ${REQUIRE_ENV} requires the scan.\n` +
30
+ ` Add it to the devDependencies with \`pnpm josh sync && pnpm install\`.`
31
+
32
+ type ScanDecision =
33
+ | { kind: 'skip'; notice?: string }
34
+ | { kind: 'fail'; error: string }
35
+ | { kind: 'scan'; binary: string }
25
36
 
26
37
  function resolve_secretlint_binary(project_root: string): string | undefined {
27
38
  const candidate = resolve_local_bin(project_root, SECRETLINT_BIN)
@@ -31,17 +42,28 @@ function resolve_secretlint_binary(project_root: string): string | undefined {
31
42
 
32
43
  // lefthook substitutes literal paths, so `--no-glob` is mandatory: a SvelteKit route directory
33
44
  // such as `(app)` or `[id]` would otherwise reach secretlint's glob engine as a pattern.
34
- // Masking and the .gitignore cascade are both on by default in v13 — no flag adds them.
45
+ // Masking and the .gitignore cascade are both on by default in v13 — no flag adds them. `--` ends
46
+ // the options, so a staged file named like `--secretlintrc=evil.json` stays a path, not a flag.
35
47
  function build_scan_arguments(staged_files: ReadonlyArray<string>): Array<string> {
36
- return [NO_GLOB_FLAG, ...staged_files]
48
+ return [NO_GLOB_FLAG, END_OF_OPTIONS, ...staged_files]
49
+ }
50
+
51
+ function plan_missing(is_required: boolean): ScanDecision {
52
+ return is_required
53
+ ? { kind: 'fail', error: REQUIRED_MISSING_ERROR }
54
+ : { kind: 'skip', notice: MISSING_NOTICE }
37
55
  }
38
56
 
39
- function plan_scan(staged_files: ReadonlyArray<string>, project_root: string): ScanDecision {
57
+ function plan_scan(
58
+ staged_files: ReadonlyArray<string>,
59
+ project_root: string,
60
+ is_required = false,
61
+ ): ScanDecision {
40
62
  if (staged_files.length === 0) return { kind: 'skip' }
41
63
 
42
64
  const binary = resolve_secretlint_binary(project_root)
43
65
 
44
- if (binary === undefined) return { kind: 'skip', notice: MISSING_NOTICE }
66
+ if (binary === undefined) return plan_missing(is_required)
45
67
 
46
68
  return { kind: 'scan', binary }
47
69
  }
@@ -59,18 +81,29 @@ function run_scan(binary: string, staged_files: ReadonlyArray<string>): number {
59
81
  return resolve_spawn_exit(binary, result)
60
82
  }
61
83
 
62
- function main(staged_files: ReadonlyArray<string>, project_root: string): number {
63
- const decision = plan_scan(staged_files, project_root)
84
+ function main(
85
+ staged_files: ReadonlyArray<string>,
86
+ project_root: string,
87
+ is_required = false,
88
+ ): number {
89
+ const decision = plan_scan(staged_files, project_root, is_required)
64
90
 
65
91
  if (decision.kind === 'scan') return run_scan(decision.binary, staged_files)
66
92
 
93
+ if (decision.kind === 'fail') {
94
+ console.error(decision.error)
95
+
96
+ return 1
97
+ }
98
+
67
99
  if (decision.notice !== undefined) console.warn(decision.notice)
68
100
 
69
101
  return 0
70
102
  }
71
103
 
72
104
  if (process.argv[1] === fileURLToPath(import.meta.url)) {
73
- const exit_code = main(process.argv.slice(ARGV_OFFSET), process.cwd())
105
+ const is_required = process.env[REQUIRE_ENV] === '1'
106
+ const exit_code = main(process.argv.slice(ARGV_OFFSET), process.cwd(), is_required)
74
107
 
75
108
  if (exit_code !== 0) process.exit(exit_code)
76
109
  }
@@ -83,4 +116,4 @@ const secretlint_scan = {
83
116
  run_scan,
84
117
  }
85
118
 
86
- export { MISSING_NOTICE, secretlint_scan }
119
+ export { MISSING_NOTICE, REQUIRE_ENV, REQUIRED_MISSING_ERROR, secretlint_scan }
@@ -1,12 +1,20 @@
1
1
  #!/usr/bin/env tsx
2
2
  import { fileURLToPath } from 'node:url'
3
+ import { session_owner_pin } from '#scripts/discovery/session-owner-pin'
3
4
  import { security_audit_provision } from './security-audit-provision'
4
5
 
5
6
  // The `josh audit:provision` entry and the session-start hook's bundle, kept apart from
6
7
  // `security-audit-provision.ts` because `start-steps.ts` imports that one: a bundle is one file, so a
7
8
  // main guard there would fire for every command that carries it (joshuafolkken/kit#4186).
9
+ //
10
+ // Run by the session-start hook (`--session-start`), it also pins the session's owner
11
+ // (`session-owner-pin.ts`) at no spawn of its own. A manual `josh audit:provision` pins only when
12
+ // passed `--session-start`, which re-pins to whatever owner `origin` names at that moment.
8
13
  if (process.argv[1] === fileURLToPath(import.meta.url)) {
9
14
  const ARGV_OFFSET = 2
15
+ const SESSION_START_FLAG = '--session-start'
16
+ const argv = process.argv.slice(ARGV_OFFSET)
10
17
 
11
- await security_audit_provision.run(process.argv.slice(ARGV_OFFSET))
18
+ if (argv.includes(SESSION_START_FLAG)) session_owner_pin.pin()
19
+ await security_audit_provision.run(argv)
12
20
  }
@@ -140,7 +140,7 @@ async function report(
140
140
  is_forced: boolean,
141
141
  ): Promise<string> {
142
142
  const logic = security_audit_provision_logic
143
- const target_path = security_audit_logic.build_managed_binary_path(project_root, platform)
143
+ const target_path = security_audit.managed_binary_path(project_root, platform)
144
144
  const existing = existing_scanner(target_path)
145
145
  if (existing !== undefined) return logic.format_already_present(existing)
146
146
 
@@ -1,10 +1,13 @@
1
1
  import { accessSync, constants, statSync } from 'node:fs'
2
+ import path from 'node:path'
3
+ import { git_common_directory } from '#scripts/git/git-common-directory'
2
4
  import { PROJECT_ROOT } from '#scripts/init/init-paths'
3
5
  import { execaSync } from 'execa'
4
6
  import { security_audit_logic } from './security-audit-logic'
5
7
  import { security_audit_provision_logic } from './security-audit-provision-logic'
6
8
 
7
9
  const FAILURE_EXIT_CODE = 1
10
+ const GIT_DIRECTORY_NAME = '.git'
8
11
  const UNKNOWN_VERSION = 'unknown'
9
12
 
10
13
  // execa reports `exitCode: undefined` only when the binary could not be spawned
@@ -56,11 +59,27 @@ interface ScannerChoice {
56
59
  is_below_floor: boolean
57
60
  }
58
61
 
62
+ // A linked work tree shares the primary checkout's managed scanner, so a lane neither downloads its
63
+ // own copy at every session start nor keeps its own no-retry record (joshuafolkken/kit#4942). Where
64
+ // the primary checkout cannot be named — a bare repository, a submodule, or no repository — the root
65
+ // is the project's own. The primary checkout reads git's answer too, so it keys the no-retry record
66
+ // on the same real path its lanes do even when it was entered through a symlink.
67
+ function managed_root(project_root: string): string {
68
+ const common = git_common_directory.repository(project_root)
69
+ if (common === undefined || path.basename(common) !== GIT_DIRECTORY_NAME) return project_root
70
+
71
+ return path.dirname(common)
72
+ }
73
+
74
+ function managed_binary_path(project_root: string, platform: string): string {
75
+ return security_audit_logic.build_managed_binary_path(managed_root(project_root), platform)
76
+ }
77
+
59
78
  // A provisioned copy counts only when it is both a real executable and at or above the floor: a
60
79
  // leftover from an earlier pinned version would otherwise be preferred over the PATH binary while
61
80
  // reading less of the lockfile than it should.
62
81
  function managed_scanner(project_root: string, platform: string): string | undefined {
63
- const managed_path = security_audit_logic.build_managed_binary_path(project_root, platform)
82
+ const managed_path = managed_binary_path(project_root, platform)
64
83
 
65
84
  return is_executable_file(managed_path) && meets_floor(managed_path) ? managed_path : undefined
66
85
  }
@@ -132,6 +151,7 @@ function run(): number {
132
151
  const security_audit = {
133
152
  is_binary_available,
134
153
  is_executable_file,
154
+ managed_binary_path,
135
155
  meets_floor,
136
156
  resolve_scanner,
137
157
  run,
@@ -1,7 +1,10 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
2
- import path from 'node:path'
1
+ import { existsSync, readFileSync } from 'node:fs'
3
2
  import { init_logic } from '#scripts/init/init-logic'
4
3
  import type { SonarIdentifiers } from '#scripts/init/init-logic-sonar'
4
+ import { file_content } from '#scripts/sync/file-content'
5
+
6
+ // Written through `write_contained` like every other sync write, so a `sonar-project.properties`
7
+ // linked outside the project is refused rather than written through (joshuafolkken/kit#4634).
5
8
 
6
9
  function write_sonar_file(
7
10
  template_source: string,
@@ -14,8 +17,7 @@ function write_sonar_file(
14
17
  identifiers.organization,
15
18
  )
16
19
 
17
- mkdirSync(path.dirname(destination_path), { recursive: true })
18
- writeFileSync(destination_path, content)
20
+ file_content.write_contained(destination_path, content)
19
21
  }
20
22
 
21
23
  function merge_sonar_file(
@@ -36,7 +38,10 @@ function merge_sonar_file(
36
38
  )
37
39
  const existing = readFileSync(destination_path, 'utf8')
38
40
 
39
- writeFileSync(destination_path, init_logic.merge_sonar_properties(existing, template_content))
41
+ file_content.write_contained(
42
+ destination_path,
43
+ init_logic.merge_sonar_properties(existing, template_content),
44
+ )
40
45
  }
41
46
 
42
47
  const sonar_file = { write_sonar_file, merge_sonar_file }
@@ -76,7 +76,8 @@ function non_test_changes(changes: ReadonlyArray<FileChange>): Array<FileChange>
76
76
  }
77
77
 
78
78
  // `split` only when **both** guides are exceeded together — the size condition a split has to clear,
79
- // per `split-assessment.md`'s conservative default. Either one alone leaves the change one Issue.
79
+ // per `split-assessment.md`'s conservative default. Either one alone leaves the change one Issue. A
80
+ // filing's declared estimate is judged by this same call (`issue/size-estimate.ts`).
80
81
  function verdict_for(files: number, lines: number): SplitVerdict {
81
82
  return files > FILE_GUIDE && lines > LINE_GUIDE ? SPLIT_VERDICT : SINGLE_VERDICT
82
83
  }
@@ -107,9 +108,14 @@ function reason(measurement: SizeMeasurement): string {
107
108
  return `${counted} (${guide}) — ${tail}`
108
109
  }
109
110
 
110
- // The `split-assessment.md` heading the notice points at; the document-rule test pins the document to it.
111
+ // The `split-assessment.md` headings the notice and a filing refusal point at; the document-rule test
112
+ // pins the document to both.
111
113
  const NOTICE_SECTION = 'Over the guide before the gate'
112
- const NOTICE_ACTION = `record why it stays one Issue, or carve the rest out into a new Issue — split-assessment.md → "${NOTICE_SECTION}"`
114
+ const QUESTION_SECTION = 'The question'
115
+ // The line that records why an Issue stays one — read the same in a filed body (`size_estimate`) and
116
+ // in the Issue comment that answers the notice (`split_resolution`).
117
+ const REASON_PREFIX = '- 分割しない理由:'
118
+ const NOTICE_ACTION = `record why it stays one Issue in an Issue comment line \`${REASON_PREFIX} <理由>\`, or carve the rest out with \`pnpm josh issue:file --route split\` — split-assessment.md → "${NOTICE_SECTION}"`
113
119
 
114
120
  // The pre-gate notice `josh main:merge` prints for a diff over the guide. "Clearly" is the `split`
115
121
  // verdict — both guides exceeded — so the one bar this file draws is the one the notice fires on,
@@ -124,12 +130,15 @@ const split_assess = {
124
130
  FILE_GUIDE,
125
131
  LINE_GUIDE,
126
132
  NOTICE_SECTION,
133
+ QUESTION_SECTION,
134
+ REASON_PREFIX,
127
135
  SPLIT_VERDICT,
128
136
  SINGLE_VERDICT,
129
137
  assess,
130
138
  notice,
131
139
  parse_numstat,
132
140
  reason,
141
+ verdict_for,
133
142
  }
134
143
 
135
144
  export type { FileChange, SizeMeasurement, SplitVerdict }
@@ -0,0 +1,116 @@
1
+ import { existsSync } from 'node:fs'
2
+ import { writeFile } from 'node:fs/promises'
3
+ import path from 'node:path'
4
+ import { git_branch } from '#scripts/git/git-branch'
5
+ import { git_command } from '#scripts/git/git-command'
6
+ import { lane_ledger_write } from '#scripts/lane/lane-ledger-write'
7
+ import { split_assess, type SizeMeasurement } from './split-assess'
8
+ import { split_measure } from './split-measure'
9
+
10
+ // **The split notice, shown mid-implementation** (joshuafolkken/kit#4642). `josh main:merge` prints it
11
+ // only before the gate, when the run can no longer carve anything out; a lane that grew to 17 files met
12
+ // it 25 minutes in. The first `josh lint:related` or `josh test:related` after the branch's diff passes
13
+ // the guide prints the same notice — `split_assess.notice`, so the bar and the question are one
14
+ // definition — once per Issue: a marker in the work tree's git directory, created exclusively, records
15
+ // that it was shown. A diff under the guide leaves no marker, so the first crossing still prints.
16
+ // Advisory only: an unmeasurable diff or a branch with no Issue prints nothing.
17
+
18
+ const MARKER_PREFIX = 'josh-split-notice-'
19
+ const EXISTS_CODE = 'EEXIST'
20
+
21
+ async function marker_path(issue_number: number): Promise<string | undefined> {
22
+ const [git_directory] = await git_command.git_directories()
23
+
24
+ if (git_directory === undefined) return undefined
25
+
26
+ return path.join(git_directory, `${MARKER_PREFIX}${String(issue_number)}`)
27
+ }
28
+
29
+ // Undefined once shown, so a later run skips the measurement — a diff against main and a read of
30
+ // every untracked file.
31
+ async function unclaimed_marker(issue_number: number): Promise<string | undefined> {
32
+ const target = await marker_path(issue_number)
33
+
34
+ return target === undefined || existsSync(target) ? undefined : target
35
+ }
36
+
37
+ function is_exists_error(error: unknown): boolean {
38
+ return error instanceof Error && 'code' in error && error.code === EXISTS_CODE
39
+ }
40
+
41
+ // True only for the call that created the marker — the one that shows the notice.
42
+ async function claim(target: string): Promise<boolean> {
43
+ try {
44
+ await writeFile(target, '', { flag: 'wx' })
45
+
46
+ return true
47
+ } catch (error) {
48
+ if (is_exists_error(error)) return false
49
+ throw error
50
+ }
51
+ }
52
+
53
+ // The claim that shows the notice first also writes it to the lane ledger, so the ledger holds one
54
+ // line per Issue, whichever command showed it (joshuafolkken/kit#4695).
55
+ async function claim_notice(
56
+ target: string,
57
+ issue: number,
58
+ measurement: SizeMeasurement,
59
+ ): Promise<boolean> {
60
+ if (!(await claim(target))) return false
61
+ await lane_ledger_write.record_split_notice({
62
+ issue,
63
+ files: measurement.files,
64
+ lines: measurement.lines,
65
+ })
66
+
67
+ return true
68
+ }
69
+
70
+ async function branch_issue(): Promise<number | undefined> {
71
+ return git_branch.issue_from_branch(await git_command.branch())
72
+ }
73
+
74
+ async function pending_notice(): Promise<string | undefined> {
75
+ const issue_number = await branch_issue()
76
+
77
+ if (issue_number === undefined) return undefined
78
+ const target = await unclaimed_marker(issue_number)
79
+
80
+ if (target === undefined) return undefined
81
+ const measurement = await split_measure.read_branch()
82
+ const notice = split_assess.notice(measurement)
83
+
84
+ return notice !== undefined && (await claim_notice(target, issue_number, measurement))
85
+ ? notice
86
+ : undefined
87
+ }
88
+
89
+ // `josh main:merge` prints its notice on every merge; this records the first showing, as the scoped
90
+ // checks do, when neither of them showed it before. Advisory, as `surface` is.
91
+ async function record(measurement: SizeMeasurement): Promise<void> {
92
+ try {
93
+ const issue_number = await branch_issue()
94
+ const target = issue_number === undefined ? undefined : await unclaimed_marker(issue_number)
95
+
96
+ if (issue_number !== undefined && target !== undefined) {
97
+ await claim_notice(target, issue_number, measurement)
98
+ }
99
+ } catch {
100
+ // Advisory: the notice was printed; only its record is lost.
101
+ }
102
+ }
103
+
104
+ async function surface(): Promise<void> {
105
+ try {
106
+ const notice = await pending_notice()
107
+
108
+ if (notice !== undefined) console.warn(`\n${notice}`)
109
+ } catch {
110
+ // Advisory: `josh main:merge` reports an unmeasurable diff before the gate.
111
+ }
112
+ }
113
+
114
+ const split_early_notice = { MARKER_PREFIX, record, surface }
115
+
116
+ export { split_early_notice }
@@ -1,5 +1,6 @@
1
1
  import { readFile } from 'node:fs/promises'
2
2
  import path from 'node:path'
3
+ import { change_base } from '#scripts/git/change-base'
3
4
  import { changed_paths } from '#scripts/git/changed-paths'
4
5
  import { git_command } from '#scripts/git/git-command'
5
6
  import { git_spawn } from '#scripts/git/git-spawn'
@@ -14,7 +15,16 @@ import { split_assess } from './split-assess'
14
15
  // `git diff --numstat` counts it. An entry with no readable content — a dangling symlink, a nested
15
16
  // repository's directory — still counts as a file, of zero lines, so one such entry cannot reject
16
17
  // the whole measurement.
17
-
18
+ //
19
+ // joshuafolkken/kit#4696: **the tracked half is measured from the tree's base, through a merge in
20
+ // progress** (`change_base.resolved_through_merge`). A merge of the default branch stopped on a
21
+ // conflict has already put the default branch's files in the work tree while `HEAD` is still the
22
+ // commit before it, so measuring from `HEAD`'s merge-base counted everything the merge brought in as
23
+ // this branch's own — 53 files where the branch had 10. A base that cannot be resolved throws, so no
24
+ // caller reads it as under the guide: the notices report the diff as unmeasured and `split:assess`
25
+ // fails outright.
26
+
27
+ const UNRESOLVED_BASE = 'the change base could not be resolved'
18
28
  const NUL_BYTE = 0
19
29
  const NO_CONTENT = Buffer.alloc(0)
20
30
  const NEWLINE = '\n'
@@ -54,8 +64,16 @@ async function untracked_numstat(): Promise<string> {
54
64
  return rows.join(NEWLINE)
55
65
  }
56
66
 
67
+ async function tracked_numstat(): Promise<string> {
68
+ const base = await change_base.resolved_through_merge()
69
+
70
+ if (base === undefined) throw new Error(UNRESOLVED_BASE)
71
+
72
+ return await git_command.diff_numstat_since(base)
73
+ }
74
+
57
75
  async function read_branch(): Promise<ReturnType<typeof split_assess.assess>> {
58
- const tracked = await git_command.diff_main_numstat()
76
+ const tracked = await tracked_numstat()
59
77
 
60
78
  return split_assess.assess(`${tracked}${NEWLINE}${await untracked_numstat()}`)
61
79
  }