@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,63 @@
1
+ import { changed_paths } from './changed-paths'
2
+ import { git_diff_reads } from './git-diff-reads'
3
+ import { git_location_environment } from './git-location-environment'
4
+ import { git_spawn_sync, type GitSyncOptions } from './git-spawn-sync'
5
+
6
+ // The synchronous counterpart of `changed_paths.read_changed_paths(false)` — the branch diff since
7
+ // the merge base plus the untracked files — for a `PreToolUse` hook, which cannot await. It spawns the
8
+ // argument lists `git-diff-reads.ts` spawns, so the two readings agree on what "changed" is — through
9
+ // a merge of the default branch in progress too, measured from the base `change_base.resolved_through_merge`
10
+ // answers (joshuafolkken/kit#5309). Any failure is the empty list.
11
+
12
+ // With an explicit `cwd`, the git location variables are cleared so that directory is what git
13
+ // answers for, as in `git_spawn_sync.origin_url`.
14
+ function options_of(cwd: string | undefined): GitSyncOptions {
15
+ if (cwd === undefined) return {}
16
+
17
+ return { cwd, env: git_location_environment.location_free_environment() }
18
+ }
19
+
20
+ function default_branch_reference(options: GitSyncOptions): string {
21
+ const output = git_spawn_sync.read([...git_diff_reads.DEFAULT_BRANCH_ARGUMENTS], options)
22
+ const default_branch = git_diff_reads.default_branch_of(output)
23
+ const remote_reference = git_diff_reads.remote_reference_of(default_branch)
24
+ const check = git_diff_reads.reference_check_arguments(remote_reference)
25
+
26
+ return git_spawn_sync.read(check, options) === undefined ? default_branch : remote_reference
27
+ }
28
+
29
+ // While a merge is in progress, the later of the base of `HEAD` and the base of `MERGE_HEAD`.
30
+ function through_merge(base: string, reference: string, options: GitSyncOptions): string {
31
+ const incoming = git_spawn_sync.read(git_diff_reads.incoming_base_arguments(reference), options)
32
+
33
+ if (incoming === undefined) return base
34
+
35
+ const kept = git_spawn_sync.read(git_diff_reads.later_base_arguments(base, incoming), options)
36
+
37
+ return git_diff_reads.later_base_of(kept, base)
38
+ }
39
+
40
+ function change_base(options: GitSyncOptions): string {
41
+ const reference = default_branch_reference(options)
42
+ const base = git_spawn_sync.read(git_diff_reads.merge_base_arguments(reference), options)
43
+
44
+ if (base === undefined) return reference
45
+
46
+ return through_merge(base, reference, options)
47
+ }
48
+
49
+ // Repository-root-relative paths, as the asynchronous reading returns them.
50
+ function read_changed_paths(cwd?: string): ReadonlyArray<string> {
51
+ const options = options_of(cwd)
52
+ const tracked = git_spawn_sync.read(
53
+ git_diff_reads.names_since_arguments(change_base(options)),
54
+ options,
55
+ )
56
+ const untracked = git_spawn_sync.read(git_diff_reads.UNTRACKED_ARGUMENTS, options)
57
+
58
+ return [tracked, untracked].flatMap((raw = '') => changed_paths.to_paths(raw))
59
+ }
60
+
61
+ const changed_paths_sync = { read_changed_paths }
62
+
63
+ export { changed_paths_sync }
@@ -1,3 +1,4 @@
1
+ import { change_base } from './change-base'
1
2
  import { git_command } from './git-command'
2
3
 
3
4
  // The set of changed paths a mechanical, path-driven decision is made from.
@@ -12,13 +13,27 @@ function to_paths(raw: string): Array<string> {
12
13
  .filter((line) => line !== '')
13
14
  }
14
15
 
16
+ // joshuafolkken/kit#5307: **the tracked half is measured from the tree's base, through a merge in
17
+ // progress** (`change_base.resolved_through_merge`). A merge of the default branch stopped on a
18
+ // conflict holds the default branch's files in the tree while `HEAD` is still the commit before it,
19
+ // so the diff from `HEAD`'s merge-base read everything the merge brought in as this branch's own — and
20
+ // the ship's `unplanned` precondition refused the re-detach it had itself told the lane to make. A
21
+ // base that cannot be resolved reads as before.
22
+ async function tracked_names(): Promise<string> {
23
+ const base = await change_base.resolved_through_merge()
24
+
25
+ if (base === undefined) return await git_command.diff_main_names()
26
+
27
+ return await git_command.diff_names_since(base)
28
+ }
29
+
15
30
  // The branch diff **plus** the untracked files. `git diff` lists neither, so a change that adds a
16
31
  // new module and edits one inert file looked like an inert-only change and was handed `low`. The
17
32
  // staged form needs no such addition: a file staged for addition is already in the cached diff.
18
33
  async function read_changed_paths(is_staged: boolean): Promise<Array<string>> {
19
34
  if (is_staged) return to_paths(await git_command.diff_cached_names())
20
35
 
21
- const tracked = to_paths(await git_command.diff_main_names())
36
+ const tracked = to_paths(await tracked_names())
22
37
  const untracked = to_paths(await git_command.untracked_names())
23
38
 
24
39
  return [...tracked, ...untracked]
@@ -8,6 +8,9 @@ import { git_location_environment, GIT_LOCATION_VARIABLES } from './git-location
8
8
  // cannot name different directories. It had been run in three places with three timeouts and no
9
9
  // memory of the answer, though a `PreToolUse` hook may ask it several times in one call.
10
10
 
11
+ // josh's own per-clone state inside the common git directory, in one entry of it so nothing josh writes
12
+ // sits at its root beside git's own files.
13
+ const STATE_DIRECTORY = 'josh'
11
14
  const OWN_GIT_DIRECTORY = 0
12
15
  const COMMON_GIT_DIRECTORY = 1
13
16
  // The read runs inside `PreToolUse` hooks, which hold the tool call for as long as it takes;
@@ -97,6 +100,13 @@ function resolve(cwd: string): string | undefined {
97
100
  return select_linked(directories(cwd))
98
101
  }
99
102
 
100
- const git_common_directory = { directories, own, repository, resolve, select_linked }
103
+ const git_common_directory = {
104
+ STATE_DIRECTORY,
105
+ directories,
106
+ own,
107
+ repository,
108
+ resolve,
109
+ select_linked,
110
+ }
101
111
 
102
112
  export { git_common_directory }
@@ -31,6 +31,16 @@ async function get_default_branch(): Promise<string> {
31
31
 
32
32
  const MERGE_BASE_COMMAND = 'merge-base'
33
33
 
34
+ // The argument lists below are shared with `changed-paths-sync.ts`, so the hook-side synchronous
35
+ // reading cannot drift from this one.
36
+ function reference_check_arguments(reference: string): ReadonlyArray<string> {
37
+ return ['rev-parse', '--verify', '--quiet', reference]
38
+ }
39
+
40
+ function remote_reference_of(default_branch: string): string {
41
+ return `${REFS_REMOTES_ORIGIN_PREFIX}${default_branch}`
42
+ }
43
+
34
44
  // **The ref the default branch is actually at**, which is not the same thing as its name.
35
45
  // `get_default_branch` returns the bare name, and git resolves that to the
36
46
  // *local* `refs/heads/<default>` — a ref nothing in this workflow advances, because merges happen on
@@ -45,7 +55,7 @@ const MERGE_BASE_COMMAND = 'merge-base'
45
55
  // `prevent-main-commit.ts` exists to stop.
46
56
  async function reference_exists(reference: string): Promise<boolean> {
47
57
  try {
48
- await git_spawn.read(['rev-parse', '--verify', '--quiet', reference])
58
+ await git_spawn.read([...reference_check_arguments(reference)])
49
59
 
50
60
  return true
51
61
  } catch {
@@ -55,11 +65,33 @@ async function reference_exists(reference: string): Promise<boolean> {
55
65
 
56
66
  async function default_branch_reference(): Promise<string> {
57
67
  const default_branch = await get_default_branch()
58
- const remote_reference = `${REFS_REMOTES_ORIGIN_PREFIX}${default_branch}`
68
+ const remote_reference = remote_reference_of(default_branch)
59
69
 
60
70
  return (await reference_exists(remote_reference)) ? remote_reference : default_branch
61
71
  }
62
72
 
73
+ function merge_base_arguments(reference: string): ReadonlyArray<string> {
74
+ return [MERGE_BASE_COMMAND, reference, 'HEAD']
75
+ }
76
+
77
+ // Where the side a merge in progress brings in left the default branch; git fails it where no merge
78
+ // is in progress. These three are `change_base.resolved_through_merge`'s, shared with the sync reading.
79
+ function incoming_base_arguments(reference: string): ReadonlyArray<string> {
80
+ return [MERGE_BASE_COMMAND, reference, 'MERGE_HEAD']
81
+ }
82
+
83
+ // `--independent` drops every commit another one listed reaches, so of two commits on the default
84
+ // branch's history it keeps the later — read from its output by `later_base_of`.
85
+ function later_base_arguments(base: string, incoming: string): ReadonlyArray<string> {
86
+ return [MERGE_BASE_COMMAND, '--independent', base, incoming]
87
+ }
88
+
89
+ function later_base_of(output: string | undefined, base: string): string {
90
+ const [later = ''] = output?.split('\n', 1) ?? []
91
+
92
+ return later === '' ? base : later
93
+ }
94
+
63
95
  // The commit this branch was cut from — and the base every "changed" reading below measures
64
96
  // against, in place of the default branch itself.
65
97
  //
@@ -89,7 +121,7 @@ async function change_base(): Promise<string> {
89
121
  const default_branch = await default_branch_reference()
90
122
 
91
123
  try {
92
- return await git_spawn.read([MERGE_BASE_COMMAND, default_branch, 'HEAD'])
124
+ return await git_spawn.read([...merge_base_arguments(default_branch)])
93
125
  } catch {
94
126
  return default_branch
95
127
  }
@@ -153,8 +185,8 @@ async function change_base_commit(): Promise<string> {
153
185
 
154
186
  // The working tree against any commit, with the same flags as the branch diff. `josh test:related`
155
187
  // reads the change since the commit its test-read map was recorded on, which is not the merge base.
156
- async function diff_names_since(commit: string): Promise<string> {
157
- return await git_spawn.read([
188
+ function names_since_arguments(commit: string): ReadonlyArray<string> {
189
+ return [
158
190
  ...NO_PATH_QUOTING,
159
191
  'diff',
160
192
  NAME_ONLY_FLAG,
@@ -162,7 +194,11 @@ async function diff_names_since(commit: string): Promise<string> {
162
194
  NO_RENAME_DETECTION,
163
195
  commit,
164
196
  '--',
165
- ])
197
+ ]
198
+ }
199
+
200
+ async function diff_names_since(commit: string): Promise<string> {
201
+ return await git_spawn.read([...names_since_arguments(commit)])
166
202
  }
167
203
 
168
204
  // Which of `paths` a commit's tree holds. `josh test:related` asks it of the tree its test-read map
@@ -197,17 +233,17 @@ async function diff_cached_names(): Promise<string> {
197
233
  ])
198
234
  }
199
235
 
200
- // The branch diff as `added\tdeleted\tpath` rows — the same base and flags as `diff_main_names`, so
201
- // the size read against and the name read agree on what "changed" is. A binary file prints `-` for
202
- // both counts; the parser above `josh split:assess` reads it treats those as zero changed lines.
203
- async function diff_main_numstat(): Promise<string> {
236
+ // The diff since `base` as `added\tdeleted\tpath` rows — the same flags as `diff_names_since`, so the
237
+ // size read and the name read agree on what "changed" is. A binary file prints `-` for both counts;
238
+ // the parser above `josh split:assess` reads it treats those as zero changed lines.
239
+ async function diff_numstat_since(base: string): Promise<string> {
204
240
  return await git_spawn.read([
205
241
  ...NO_PATH_QUOTING,
206
242
  'diff',
207
243
  '--numstat',
208
244
  NO_RELATIVE_PATHS,
209
245
  NO_RENAME_DETECTION,
210
- await change_base(),
246
+ base,
211
247
  '--',
212
248
  ])
213
249
  }
@@ -226,19 +262,22 @@ async function diff_main_numstat(): Promise<string> {
226
262
  // pathspec restores the whole tree; the flag restores the root-relative spelling.
227
263
  const WHOLE_TREE_PATHSPEC = ':/'
228
264
 
265
+ const UNTRACKED_ARGUMENTS: ReadonlyArray<string> = [
266
+ ...NO_PATH_QUOTING,
267
+ 'ls-files',
268
+ '--others',
269
+ '--exclude-standard',
270
+ '--full-name',
271
+ WHOLE_TREE_PATHSPEC,
272
+ ]
273
+
229
274
  async function untracked_names(): Promise<string> {
230
- return await git_spawn.read([
231
- ...NO_PATH_QUOTING,
232
- 'ls-files',
233
- '--others',
234
- '--exclude-standard',
235
- '--full-name',
236
- WHOLE_TREE_PATHSPEC,
237
- ])
275
+ return await git_spawn.read([...UNTRACKED_ARGUMENTS])
238
276
  }
239
277
 
240
278
  const git_diff_reads = {
241
279
  DEFAULT_BRANCH_ARGUMENTS,
280
+ UNTRACKED_ARGUMENTS,
242
281
  change_base,
243
282
  change_base_commit,
244
283
  default_branch_of,
@@ -246,9 +285,16 @@ const git_diff_reads = {
246
285
  diff_cached_names,
247
286
  diff_main,
248
287
  diff_main_names,
249
- diff_main_numstat,
288
+ diff_numstat_since,
250
289
  diff_names_since,
251
290
  get_default_branch,
291
+ incoming_base_arguments,
292
+ later_base_arguments,
293
+ later_base_of,
294
+ merge_base_arguments,
295
+ names_since_arguments,
296
+ reference_check_arguments,
297
+ remote_reference_of,
252
298
  tree_names_at,
253
299
  untracked_names,
254
300
  }
@@ -25,13 +25,18 @@ function get_cause_message(cause: unknown): string | undefined {
25
25
  return undefined
26
26
  }
27
27
 
28
+ // The heads of the lines a failed command names the error it ended on, and that error's cause, with —
29
+ // read back by a stopped `josh ship` stage (joshuafolkken/kit#5052).
30
+ const FAILURE_PREFIX = '❌ Error:'
31
+ const DETAILS_PREFIX = '💡 Details:'
32
+
28
33
  function display_error_details(cause: unknown): void {
29
34
  const cause_message = get_cause_message(cause)
30
35
 
31
36
  if (cause_message === undefined || cause_message.length === 0) return
32
37
 
33
38
  console.error('')
34
- console.error('💡 Details:', cause_message)
39
+ console.error(DETAILS_PREFIX, cause_message)
35
40
  }
36
41
 
37
42
  const FAILURE_EXIT_CODE = 1
@@ -72,7 +77,7 @@ function display_failure(error: unknown): void {
72
77
  const error_message = error_text.message_of(error)
73
78
 
74
79
  console.error('')
75
- console.error('❌ Error:', error_message)
80
+ console.error(FAILURE_PREFIX, error_message)
76
81
 
77
82
  if (error instanceof Error && error.cause !== undefined) {
78
83
  display_error_details(error.cause)
@@ -118,6 +123,8 @@ function handle(error: unknown): void {
118
123
  }
119
124
 
120
125
  const git_error = {
126
+ DETAILS_PREFIX,
127
+ FAILURE_PREFIX,
121
128
  handle,
122
129
  }
123
130
 
@@ -36,6 +36,7 @@ const ai_review_pull_comment_schema = z.object({
36
36
  body: z.string().optional(),
37
37
  url: z.string().optional(),
38
38
  author: z.object({ login: z.string().optional() }).optional(),
39
+ updatedAt: z.string().optional(),
39
40
  })
40
41
 
41
42
  const pr_info_schema = z.object({
@@ -108,6 +109,7 @@ const rest_comment_schema = z.looseObject({
108
109
  body: z.string().nullish(),
109
110
  html_url: z.string().optional(),
110
111
  user: z.looseObject({ login: z.string().optional() }).nullish(),
112
+ updated_at: z.string().optional(),
111
113
  })
112
114
 
113
115
  // The `number,state,labels,body` read, for the epic check and the `--add` closed-epic refusal.
@@ -137,6 +139,12 @@ const epic_subject_schema = z.object({
137
139
  // So `blockedBy` is optional for the reason it is absent in practice — the display and the busy
138
140
  // check never ask for it, and a field that was not asked for is left out of the mapped row rather
139
141
  // than filled in.
142
+ // Who wrote an issue, as REST names it — read through `gh_author_association.author_of`.
143
+ const author_fields_schema = {
144
+ author_association: z.string().nullish(),
145
+ user: z.looseObject({ login: z.string() }).nullish(),
146
+ }
147
+
140
148
  const open_issue_schema = z.object({
141
149
  number: z.number(),
142
150
  title: z.string(),
@@ -145,6 +153,10 @@ const open_issue_schema = z.object({
145
153
  blockedBy: blocked_by_schema,
146
154
  // Present only on the pickup listing, which reads it for the paths each issue declares.
147
155
  body: z.string().optional(),
156
+ ...author_fields_schema,
157
+ // Assembled by the pickup from the author above, never read off the listing: whether the author
158
+ // has write access. Absent on every other listing.
159
+ author_trusted: z.boolean().optional(),
148
160
  })
149
161
 
150
162
  type RollupItemData = z.infer<typeof rollup_item_schema>
@@ -154,6 +166,7 @@ type OpenIssueData = z.infer<typeof open_issue_schema>
154
166
  type RestCommentData = z.infer<typeof rest_comment_schema>
155
167
 
156
168
  export {
169
+ author_fields_schema,
157
170
  package_name_schema,
158
171
  rollup_item_schema,
159
172
  pr_raw_schema,
@@ -19,6 +19,7 @@ import { repository_lock } from './repository-lock'
19
19
  // `lane-start-point.ts` and `release-publish.ts` both act on — so this module stops at "what git
20
20
  // printed" and the meaning of it is decided there.
21
21
  const WORKTREE = 'worktree'
22
+ const ORIGIN = 'origin'
22
23
 
23
24
  // **Every call that writes `.git/worktrees/` runs under one repository-wide lock**.
24
25
  // `git worktree add` is not safe against itself: while one add is still
@@ -87,6 +88,17 @@ async function worktree_add(
87
88
  return await locked([WORKTREE, ...flags, directory, start_point ?? branch_name], SUITE_TIMEOUT_MS)
88
89
  }
89
90
 
91
+ // **A lane's upstream is written when it is opened, not by its first push**
92
+ // (joshuafolkken/kit#4653). A Codex lane's sandbox cannot write the common directory's `config`, so the
93
+ // `--set-upstream` its push falls back to records nothing, and every later reader of `@{upstream}`
94
+ // would take the pushed lane for an unpushed one. Pointing it at the lane's own name on `origin` keeps
95
+ // a bare `git push` working before the remote branch exists. Under the work-tree lock, since two lanes
96
+ // opened at once would otherwise race on `config.lock`.
97
+ async function set_upstream(branch_name: string): Promise<void> {
98
+ await locked(['config', `branch.${branch_name}.remote`, ORIGIN])
99
+ await locked(['config', `branch.${branch_name}.merge`, `refs/heads/${branch_name}`])
100
+ }
101
+
90
102
  // A throwaway tree at one commit, on no branch — `josh test:red` checks the merge-base out here, so
91
103
  // the pre-fix tree is built without creating a branch or touching the caller's tree and index.
92
104
  async function worktree_add_detached(directory: string, commit: string): Promise<string> {
@@ -139,6 +151,7 @@ async function branch_delete(branch_name: string): Promise<string> {
139
151
  const git_worktree = {
140
152
  branch_delete,
141
153
  ls_remote_branch,
154
+ set_upstream,
142
155
  worktree_add,
143
156
  worktree_add_detached,
144
157
  worktree_list,
@@ -7,7 +7,10 @@ import { git_spawn } from './git-spawn'
7
7
  // **A branch is removed only when all three hold** — its upstream is gone, it is merged into the
8
8
  // default branch, and no work tree has it checked out. Gone alone is not enough: a branch whose remote
9
9
  // was deleted by hand before its work merged still holds the only copy of it. A branch with no
10
- // upstream at all is never gone, so a local-only branch stays.
10
+ // upstream at all is never gone, so a local-only branch stays. A lane branch has its upstream from the
11
+ // moment it opens (`lane-open.ts`), so an unpushed lane reads `[gone]`: the merge test keeps one with
12
+ // commits of its own, and one with none — merged already — is kept by its work tree, then deleted with
13
+ // nothing lost once the tree is gone.
11
14
  //
12
15
  // **One `for-each-ref` read carries the work-tree answer too** — `%(worktreepath)` is git's own
13
16
  // record of which tree holds the branch, so no `git worktree list` parse is repeated here.
@@ -0,0 +1,89 @@
1
+ // The resolution of a merge that stopped on `document-byte-budget.ts`'s ceiling rows
2
+ // (joshuafolkken/kit#4976). Two lanes that grow the same page each raise that page's ceiling and add a
3
+ // comment naming their Issue, so the later merge stops on the same row from both sides.
4
+ //
5
+ // **Only a hunk made of ceiling rows and their comments is resolved**: each side is comment lines
6
+ // followed by at most one ceiling row, both rows name the same page, and the result keeps every
7
+ // comment from both sides and the larger ceiling. A hunk holding only comments is resolved only when
8
+ // the row it annotates follows it. Any other hunk — the table's structure, another function — throws,
9
+ // so the merge stays the `conflict` it was. The merged page's size is still checked against the kept
10
+ // ceiling by `document-byte-budget.test.ts`.
11
+
12
+ const BUDGET_TABLE_PATH = 'scripts/document/document-byte-budget.ts'
13
+ const CEILING_ROW = /^\t\{ path: '(?<path>[^']+)', bytes: (?<bytes>[\d_]+) \},$/u
14
+ const COMMENT_PREFIX = '\t// '
15
+ const CONFLICT_MARKER = /^(?:<{7}|={7}|>{7}|\|{7})/mu
16
+ // A diff3 base section, dropped before the hunks are read: the resolution needs only the two sides.
17
+ const BASE_SECTION = /^\|{7} .*\n(?:.*\n)*?(?=={7}\n)/gmu
18
+ // One conflict hunk; the line after it is captured without being consumed.
19
+ const HUNK = /^<{7} .*\n(?<ours>(?:.*\n)*?)={7}\n(?<theirs>(?:.*\n)*?)>{7} .*\n(?=(?<after>.*))/gmu
20
+
21
+ interface Side {
22
+ comments: ReadonlyArray<string>
23
+ row: string | undefined
24
+ }
25
+
26
+ function side_of(text: string): Side {
27
+ const lines = text.split('\n').slice(0, -1)
28
+ const last = lines.at(-1) ?? ''
29
+ const row = CEILING_ROW.test(last) ? last : undefined
30
+ const comments = row === undefined ? lines : lines.slice(0, -1)
31
+
32
+ if (comments.some((line) => !line.startsWith(COMMENT_PREFIX))) {
33
+ throw new Error(`${BUDGET_TABLE_PATH}: a conflict outside the ceiling rows`)
34
+ }
35
+
36
+ return { comments, row }
37
+ }
38
+
39
+ function ceiling_of(row: string): { path: string; bytes: number } {
40
+ const groups: Partial<Record<'path' | 'bytes', string>> = CEILING_ROW.exec(row)?.groups ?? {}
41
+
42
+ return { path: groups.path ?? '', bytes: Number(groups.bytes?.replaceAll('_', '')) }
43
+ }
44
+
45
+ function larger_row(ours: string, theirs: string): string {
46
+ const [mine, other] = [ceiling_of(ours), ceiling_of(theirs)]
47
+
48
+ if (mine.path !== other.path) {
49
+ throw new Error(
50
+ `${BUDGET_TABLE_PATH}: rows of two pages conflict (${mine.path}, ${other.path})`,
51
+ )
52
+ }
53
+
54
+ return mine.bytes >= other.bytes ? ours : theirs
55
+ }
56
+
57
+ function rows_of(ours: Side, theirs: Side, after: string): ReadonlyArray<string> {
58
+ if (ours.row !== undefined && theirs.row !== undefined) return [larger_row(ours.row, theirs.row)]
59
+ // Equal here only when both are undefined: a hunk of comments alone, kept only above a row.
60
+ if (ours.row === theirs.row && CEILING_ROW.test(after)) return []
61
+
62
+ throw new Error(`${BUDGET_TABLE_PATH}: a ceiling row changed on one side only`)
63
+ }
64
+
65
+ function merge_hunk(ours: string, theirs: string, after: string): string {
66
+ const [mine, other] = [side_of(ours), side_of(theirs)]
67
+ const comments = [...new Set([...mine.comments, ...other.comments])]
68
+
69
+ return [...comments, ...rows_of(mine, other, after)].map((line) => `${line}\n`).join('')
70
+ }
71
+
72
+ // The file with every hunk resolved; throws when any hunk is not a ceiling-row conflict.
73
+ function resolve(content: string): string {
74
+ const resolved = content
75
+ .replaceAll(BASE_SECTION, '')
76
+ .replaceAll(HUNK, (_hunk: string, ours: string, theirs: string, after: string) =>
77
+ merge_hunk(ours, theirs, after),
78
+ )
79
+
80
+ if (resolved === content || CONFLICT_MARKER.test(resolved)) {
81
+ throw new Error(`${BUDGET_TABLE_PATH}: a conflict left unresolved`)
82
+ }
83
+
84
+ return resolved
85
+ }
86
+
87
+ const main_merge_budget_conflict = { BUDGET_TABLE_PATH, resolve }
88
+
89
+ export { main_merge_budget_conflict }
@@ -1,3 +1,4 @@
1
+ import { lane_child_marker } from '#scripts/lane/lane-child-marker'
1
2
  import { git_spawn } from './git-spawn'
2
3
 
3
4
  // What `josh main:merge` refuses before it merges, and what it tells the run to do instead.
@@ -18,8 +19,12 @@ const UNMERGED_CODES = new Set(['DD', 'AU', 'UD', 'UA', 'DU', 'AA', 'UU'])
18
19
  const UNSTAGED_INDEX_CODES = new Set([' ', '?', '!'])
19
20
  const DIRECTORY_SUFFIX = '/'
20
21
  const COMMIT_COMMAND = '`pnpm josh git -y`'
22
+ // A lane child's push is `josh ship`'s, so the lane-background row refuses a pushing `git -y` there;
23
+ // this is the commit-only form ship's own sync closes a merge with (`run-ship-sync.ts`).
24
+ const LANE_COMMIT_COMMAND = '`pnpm josh git -y --skip-push --skip-pr "<title> #<N>"`'
21
25
  const PROCEDURE_POINTER =
22
26
  '`.claude/skills/workflow-commands/chain-rule.md` → "origin/main is merged in before the gate"'
27
+ const MERGE_RERUN = '`pnpm josh main:merge`'
23
28
 
24
29
  function status_lines(status: string): Array<string> {
25
30
  return status.split('\n').filter((line) => line.length > STATUS_PREFIX_LENGTH)
@@ -57,55 +62,85 @@ function overlapping_paths(status: string, incoming: ReadonlyArray<string>): Arr
57
62
  return uncommitted.filter((path) => incoming.some((changed) => covers(path, changed)))
58
63
  }
59
64
 
60
- function unmerged_message(paths: ReadonlyArray<string>): string {
65
+ function commit_command(is_lane_child = lane_child_marker.is_child_of(process.cwd())): string {
66
+ return is_lane_child ? LANE_COMMIT_COMMAND : COMMIT_COMMAND
67
+ }
68
+
69
+ // `prefix` names the refusing command, `rerun` what to run once the merge is closed — `josh stash:push`
70
+ // refuses the same index, since `git stash` cannot set unresolved paths aside.
71
+ function unresolved_message(
72
+ prefix: string,
73
+ paths: ReadonlyArray<string>,
74
+ rerun: string,
75
+ commit = commit_command(),
76
+ ): string {
61
77
  return (
62
- `main:merge: the index still holds unresolved paths (${paths.join(', ')}). Remove the conflict ` +
63
- `markers, then finish through ${COMMIT_COMMAND} — it stages and commits them, so no \`git add\` ` +
64
- `permission is needed, and inside a lane this is Tier A. Rerun \`pnpm josh main:merge\` after it ` +
78
+ `${prefix}: the index still holds unresolved paths (${paths.join(', ')}). Remove the conflict ` +
79
+ `markers, then finish through ${commit} — it stages and commits them, so no \`git add\` ` +
80
+ `permission is needed, and inside a lane this is Tier A. Rerun ${rerun} after it ` +
65
81
  `(${PROCEDURE_POINTER}).`
66
82
  )
67
83
  }
68
84
 
69
- function staged_message(paths: ReadonlyArray<string>): string {
85
+ function staged_message(paths: ReadonlyArray<string>, commit: string): string {
70
86
  return (
71
87
  `main:merge: the index holds staged changes (${paths.join(', ')}), which git refuses to merge ` +
72
- `over. Commit them first through ${COMMIT_COMMAND}, then rerun \`pnpm josh main:merge\` ` +
88
+ `over. Commit them first through ${commit}, then rerun \`pnpm josh main:merge\` ` +
73
89
  `(${PROCEDURE_POINTER}).`
74
90
  )
75
91
  }
76
92
 
77
- function overlap_message(default_branch: string, paths: ReadonlyArray<string>): string {
93
+ function overlap_message(
94
+ default_branch: string,
95
+ paths: ReadonlyArray<string>,
96
+ commit: string,
97
+ ): string {
78
98
  return (
79
99
  `main:merge: uncommitted changes touch files origin/${default_branch} also changed ` +
80
- `(${paths.join(', ')}). Commit the work first through ${COMMIT_COMMAND}, then rerun ` +
100
+ `(${paths.join(', ')}). Commit the work first through ${commit}, then rerun ` +
81
101
  `\`pnpm josh main:merge\`. Never stash around the merge — a stash reapplied over it leaves the ` +
82
102
  `conflict half-recorded in the index (${PROCEDURE_POINTER}).`
83
103
  )
84
104
  }
85
105
 
86
106
  // Appended to git's own report when the merge itself stops on a conflict.
87
- const CONFLICT_HINT =
88
- `main:merge: finish a conflicted merge by removing the conflict markers, then ${COMMIT_COMMAND} ` +
89
- `records the merge commit — no \`git add\` permission is needed (${PROCEDURE_POINTER}).`
107
+ function conflict_hint(commit = commit_command()): string {
108
+ return (
109
+ `main:merge: finish a conflicted merge by removing the conflict markers, then ${commit} ` +
110
+ `records the merge commit — no \`git add\` permission is needed (${PROCEDURE_POINTER}).`
111
+ )
112
+ }
90
113
 
91
- function refusal(
114
+ function merge_refusal(
92
115
  status: string,
93
116
  incoming: ReadonlyArray<string>,
94
117
  default_branch: string,
118
+ commit: string,
95
119
  ): string | undefined {
96
- const unmerged = unmerged_paths(status)
97
-
98
- if (unmerged.length > 0) return unmerged_message(unmerged)
99
120
  // Nothing incoming means git answers "Already up to date" whatever the index holds.
100
121
  if (incoming.length === 0) return undefined
101
122
 
102
123
  const staged = staged_paths(status)
103
124
 
104
- if (staged.length > 0) return staged_message(staged)
125
+ if (staged.length > 0) return staged_message(staged, commit)
105
126
 
106
127
  const overlap = overlapping_paths(status, incoming)
107
128
 
108
- return overlap.length > 0 ? overlap_message(default_branch, overlap) : undefined
129
+ return overlap.length > 0 ? overlap_message(default_branch, overlap, commit) : undefined
130
+ }
131
+
132
+ // `commit` is the command the message names, resolved from the lane mark unless a caller passes it.
133
+ function refusal(
134
+ status: string,
135
+ incoming: ReadonlyArray<string>,
136
+ default_branch: string,
137
+ commit = commit_command(),
138
+ ): string | undefined {
139
+ const unmerged = unmerged_paths(status)
140
+
141
+ if (unmerged.length > 0) return unresolved_message('main:merge', unmerged, MERGE_RERUN, commit)
142
+
143
+ return merge_refusal(status, incoming, default_branch, commit)
109
144
  }
110
145
 
111
146
  // The paths the default branch changed since this branch left it — what the merge would bring in.
@@ -122,12 +157,14 @@ async function incoming_paths(default_branch: string): Promise<Array<string>> {
122
157
  }
123
158
 
124
159
  const main_merge_guard = {
125
- CONFLICT_HINT,
160
+ commit_command,
161
+ conflict_hint,
126
162
  incoming_paths,
127
163
  overlapping_paths,
128
164
  refusal,
129
165
  staged_paths,
130
166
  unmerged_paths,
167
+ unresolved_message,
131
168
  }
132
169
 
133
170
  export { main_merge_guard }