@joshuafolkken/kit 1.1050.0 → 1.1128.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (630) hide show
  1. package/.claude/settings.json +9 -8
  2. package/.claude/skills/epic-commands/SKILL.md +5 -7
  3. package/.claude/skills/workflow-commands/SKILL.md +20 -12
  4. package/.claude/skills/workflow-commands/background-commands.md +36 -84
  5. package/.claude/skills/workflow-commands/backlogrun-child.md +1 -1
  6. package/.claude/skills/workflow-commands/backlogrun-lanes.md +8 -6
  7. package/.claude/skills/workflow-commands/backlogrun-progress.md +30 -33
  8. package/.claude/skills/workflow-commands/backlogrun-steps.md +12 -12
  9. package/.claude/skills/workflow-commands/backlogrun.md +2 -2
  10. package/.claude/skills/workflow-commands/chain-rule.md +4 -2
  11. package/.claude/skills/workflow-commands/delegation.md +3 -3
  12. package/.claude/skills/workflow-commands/followup-reference.md +1 -1
  13. package/.claude/skills/workflow-commands/followup.md +7 -3
  14. package/.claude/skills/workflow-commands/fullrun-steps.md +3 -2
  15. package/.claude/skills/workflow-commands/fullrun.md +8 -6
  16. package/.claude/skills/workflow-commands/halfrun.md +19 -21
  17. package/.claude/skills/workflow-commands/issue-comments.md +1 -1
  18. package/.claude/skills/workflow-commands/issue-fold-existing.md +10 -10
  19. package/.claude/skills/workflow-commands/issue-scout.md +1 -1
  20. package/.claude/skills/workflow-commands/kickoff.md +9 -4
  21. package/.claude/skills/workflow-commands/latest-gate.md +8 -16
  22. package/.claude/skills/workflow-commands/needs-human-review.md +1 -1
  23. package/.claude/skills/workflow-commands/observation-filing.md +3 -3
  24. package/.claude/skills/workflow-commands/pre-gate-cut.md +4 -8
  25. package/.claude/skills/workflow-commands/prerequisite.md +1 -1
  26. package/.claude/skills/workflow-commands/prrun.md +36 -0
  27. package/.claude/skills/workflow-commands/retrospective.md +1 -1
  28. package/.claude/skills/workflow-commands/split-assessment.md +4 -18
  29. package/.claude/skills/workflow-commands/working-tree-hold.md +22 -2
  30. package/.codex/hooks.json +16 -20
  31. package/.github/actions/setup-node/action.yml +33 -0
  32. package/.github/actions/setup-pnpm/action.yml +93 -0
  33. package/.github/dependabot.yml +5 -1
  34. package/.github/workflows/auto-tag.yml +2 -3
  35. package/.github/workflows/ci.yml +31 -134
  36. package/.github/workflows/dependabot-auto-merge.yml +1 -0
  37. package/.github/workflows/pr-classification.yml +6 -44
  38. package/.github/workflows/production.yml +1 -0
  39. package/.github/workflows/publish.yml +43 -47
  40. package/.github/workflows/sonar-qube.yml +41 -4
  41. package/.pnpmfile.mjs +29 -0
  42. package/AGENTS.md +5 -2
  43. package/CLAUDE.md +33 -27
  44. package/GEMINI.md +5 -2
  45. package/README.md +66 -20
  46. package/SECURITY.md +37 -6
  47. package/cspell/index.yaml +6 -1
  48. package/dist/CLAUDE.basic.md +6 -6
  49. package/dist/CLAUDE.md +33 -27
  50. package/dist/CLAUDE.static.md +6 -6
  51. package/dist/config-merge/index.js +48 -12
  52. package/dist/hooks/batch-guard.js +4 -4
  53. package/dist/hooks/{chunk-7VPDUBRN.js → chunk-4JZDP5X5.js} +152 -155
  54. package/dist/hooks/{chunk-HJIISEAC.js → chunk-5SD2YM7Z.js} +5 -13
  55. package/dist/hooks/{chunk-NAS4C7GP.js → chunk-77J7IEQM.js} +2 -2
  56. package/dist/hooks/{chunk-DMQN45FN.js → chunk-7HVB7SZG.js} +3 -3
  57. package/dist/hooks/{chunk-RLDX5SOC.js → chunk-AIOIOMPX.js} +4413 -1970
  58. package/dist/hooks/{chunk-5BK3K7V4.js → chunk-M7QKEKWO.js} +873 -2049
  59. package/dist/hooks/{chunk-WQ4OSBSS.js → chunk-MKVGBQPA.js} +2 -2
  60. package/dist/hooks/{chunk-EJDX2TOB.js → chunk-NXYMNPUQ.js} +7 -88
  61. package/dist/hooks/{chunk-NJQOBE6L.js → chunk-QVLT52OV.js} +2 -7
  62. package/dist/hooks/{chunk-GQ7KP45M.js → chunk-XYUIQOW3.js} +2 -2
  63. package/dist/hooks/codex-hook-adapter.js +12 -48
  64. package/dist/hooks/duplicate-read-guard.js +5 -5
  65. package/dist/hooks/format-edited.js +2 -2
  66. package/dist/hooks/inputs.json +280 -0
  67. package/dist/hooks/investigation-guard.js +5 -5
  68. package/dist/hooks/pretool-guard.js +9 -9
  69. package/dist/hooks/session-lang.js +0 -1
  70. package/dist/hooks/stop-guard.js +192 -333
  71. package/dist/josh.js +240 -148
  72. package/dist/managed-marker/index.js +2 -1
  73. package/dist/version/index.js +70 -78
  74. package/eslint/rules/promise.js +5 -0
  75. package/eslint/rules/unicorn.js +3 -2
  76. package/package.json +26 -5
  77. package/pnpm-workspace.yaml +5 -7
  78. package/prompts/collaboration-workflow/glossary.md +17 -0
  79. package/prompts/collaboration-workflow/issue-citation.md +5 -5
  80. package/prompts/collaboration-workflow/issue-template.md +1 -1
  81. package/prompts/collaboration-workflow/operating-rules.md +5 -5
  82. package/prompts/collaboration-workflow/overview.md +13 -1
  83. package/prompts/collaboration-workflow/principles.md +9 -0
  84. package/prompts/collaboration-workflow/report-format.md +1 -1
  85. package/prompts/collaboration-workflow/residency.md +3 -3
  86. package/prompts/collaboration-workflow/rule-delivery.md +1 -1
  87. package/prompts/collaboration-workflow/turn-batching.md +3 -3
  88. package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
  89. package/prompts/collaboration-workflow/wip-cap.md +25 -22
  90. package/prompts/collaboration-workflow.md +6 -8
  91. package/prompts/review-rubric.md +1 -1
  92. package/prompts/review.md +3 -3
  93. package/prompts/sonar-hotspot-handling.md +11 -3
  94. package/prompts/testing-guide.md +3 -3
  95. package/scripts/adopt/adopt-toolkits.ts +0 -2
  96. package/scripts/adopt/adopt.ts +0 -2
  97. package/scripts/agent/agent-argv.ts +0 -2
  98. package/scripts/agent/agent-diagnostics.ts +1 -1
  99. package/scripts/agent/agent-role-profile.ts +0 -7
  100. package/scripts/agent/claude-agent-argv.ts +0 -2
  101. package/scripts/agent/codex-agent-argv.ts +1 -1
  102. package/scripts/agent/codex-hooks.ts +92 -0
  103. package/scripts/agent/interactive-ask.ts +1 -1
  104. package/scripts/auto-ok/auto-ok-cli.ts +6 -16
  105. package/scripts/backlog/backlog-arrival.ts +30 -10
  106. package/scripts/backlog/backlog-budget-cli.ts +15 -16
  107. package/scripts/backlog/backlog-budget.ts +0 -2
  108. package/scripts/backlog/backlog-defect-priority.ts +2 -2
  109. package/scripts/backlog/backlog-drive-cli.ts +10 -8
  110. package/scripts/backlog/backlog-drive-named-offer.ts +16 -3
  111. package/scripts/backlog/backlog-drive-named.ts +2 -1
  112. package/scripts/backlog/backlog-drive.ts +76 -16
  113. package/scripts/backlog/backlog-named.ts +0 -3
  114. package/scripts/backlog/backlog-next.ts +9 -15
  115. package/scripts/backlog/backlog-offer-cli.ts +6 -19
  116. package/scripts/backlog/backlog-plan-cli.ts +1 -7
  117. package/scripts/backlog/backlog-plan.ts +30 -19
  118. package/scripts/backlog/backlog-pool.ts +3 -6
  119. package/scripts/backlog/backlog-rank.ts +2 -2
  120. package/scripts/backlog/backlog-ready.ts +39 -10
  121. package/scripts/backlog/backlog-scope.ts +1 -3
  122. package/scripts/backlog/backlog-stalled-detect.ts +2 -2
  123. package/scripts/backlog/backlog-stalled.ts +0 -1
  124. package/scripts/backlog/backlog-waves.ts +5 -2
  125. package/scripts/behavior/behavior-cli.ts +1 -1
  126. package/scripts/build/build-codex-hooks.ts +26 -0
  127. package/scripts/build/build-hooks.ts +85 -9
  128. package/scripts/build/hook-bundle-stamp.ts +111 -0
  129. package/scripts/cases/cases-cli.ts +1 -1
  130. package/scripts/cases/cases-logic.ts +1 -1
  131. package/scripts/ci/composite-actions.ts +30 -0
  132. package/scripts/ci/pr-classification.ts +3 -3
  133. package/scripts/claude/workflow-destination.ts +10 -1
  134. package/scripts/clone/clone-fingerprint.ts +0 -1
  135. package/scripts/clone/clone-scan-cli.ts +1 -1
  136. package/scripts/clone/clone-scan.ts +1 -1
  137. package/scripts/config-merge/json-format.ts +0 -1
  138. package/scripts/config-merge/parse-jsonc.ts +33 -3
  139. package/scripts/config-merge/patch-json-key.ts +13 -6
  140. package/scripts/config-merge/patch-yaml-list.ts +1 -1
  141. package/scripts/cost-runtime/codex-usage.ts +2 -9
  142. package/scripts/cost-runtime/cost-attribute.ts +0 -1
  143. package/scripts/cost-runtime/cost-cli.ts +3 -10
  144. package/scripts/cost-runtime/cost-corpus.ts +0 -2
  145. package/scripts/cost-runtime/cost-format.ts +0 -3
  146. package/scripts/cost-runtime/cost-pricing.ts +0 -1
  147. package/scripts/cost-runtime/cost-tokens.ts +0 -1
  148. package/scripts/delegation/delegation-cli.ts +1 -1
  149. package/scripts/delegation/delegation-policy.ts +0 -1
  150. package/scripts/delegation/duplicate-read-guard.ts +0 -8
  151. package/scripts/delegation/fanout-cli.ts +1 -1
  152. package/scripts/delegation/fanout.ts +0 -2
  153. package/scripts/delegation/investigation-reads.ts +1 -164
  154. package/scripts/discovery/repo-map-logic.ts +0 -1
  155. package/scripts/discovery/repo-party-cli.ts +1 -1
  156. package/scripts/doctor/doctor-consumer.ts +6 -10
  157. package/scripts/doctor/doctor-io.ts +9 -13
  158. package/scripts/doctor/doctor-logic.ts +0 -4
  159. package/scripts/doctor/doctor.ts +14 -9
  160. package/scripts/document/backlogrun-parent-read-set.ts +12 -1
  161. package/scripts/document/document-byte-budget.ts +5 -5
  162. package/scripts/document/document-byte-check.ts +0 -1
  163. package/scripts/document/document-read-cli.ts +0 -2
  164. package/scripts/document/document-section-cli.ts +1 -1
  165. package/scripts/document/document-section.ts +0 -3
  166. package/scripts/document/edit-files-cli.ts +0 -1
  167. package/scripts/document/entry-read-budget.ts +21 -7
  168. package/scripts/document/entry-read-set.ts +32 -8
  169. package/scripts/document/lane-child-read-set.ts +8 -6
  170. package/scripts/document/read-files-cli.ts +0 -4
  171. package/scripts/document/read-set-cli.ts +0 -2
  172. package/scripts/document/read-set-point-of-use.ts +9 -3
  173. package/scripts/document/read-set-pricing.ts +0 -1
  174. package/scripts/document/read-set-trim.ts +4 -2
  175. package/scripts/epic/epic-add.ts +1 -1
  176. package/scripts/epic/epic-audit-cli.ts +1 -4
  177. package/scripts/epic/epic-audit-orphans.ts +1 -3
  178. package/scripts/epic/epic-audit-rationale.ts +0 -1
  179. package/scripts/epic/epic-audit-report.ts +0 -2
  180. package/scripts/epic/epic-audit.ts +8 -22
  181. package/scripts/epic/epic-bundle-cli.ts +1 -1
  182. package/scripts/epic/epic-bundle-evidence.ts +0 -1
  183. package/scripts/epic/epic-bundle-referenced.ts +1 -5
  184. package/scripts/epic/epic-bundle.ts +0 -4
  185. package/scripts/epic/epic-busy.ts +4 -5
  186. package/scripts/epic/epic-candidate-confirm.ts +0 -5
  187. package/scripts/epic/epic-classify.ts +2 -2
  188. package/scripts/epic/epic-cli-argv.ts +0 -1
  189. package/scripts/epic/epic-close-comment.ts +1 -1
  190. package/scripts/epic/epic-close.ts +5 -2
  191. package/scripts/epic/epic-cross-repo.ts +2 -4
  192. package/scripts/epic/epic-decision.ts +0 -1
  193. package/scripts/epic/epic-fetch.ts +2 -2
  194. package/scripts/epic/epic-index.ts +2 -3
  195. package/scripts/epic/epic-issue.ts +1 -15
  196. package/scripts/epic/epic-lane-offer.ts +9 -8
  197. package/scripts/epic/epic-nested.ts +1 -1
  198. package/scripts/epic/epic-next-read.ts +1 -3
  199. package/scripts/epic/epic-next-views.ts +0 -1
  200. package/scripts/epic/epic-next.ts +1 -10
  201. package/scripts/epic/epic-parse.ts +0 -1
  202. package/scripts/epic/epic-promote.ts +0 -9
  203. package/scripts/epic/epic-rank.ts +2 -2
  204. package/scripts/epic/epic-read.ts +1 -2
  205. package/scripts/epic/epic-reconcile.ts +1 -1
  206. package/scripts/epic/epic-reference.ts +1 -13
  207. package/scripts/epic/epic-relation-recheck.ts +1 -1
  208. package/scripts/epic/epic-relations.ts +1 -1
  209. package/scripts/epic/epic-remove.ts +1 -1
  210. package/scripts/epic/epic-report.ts +0 -1
  211. package/scripts/epic/epic-run.ts +2 -3
  212. package/scripts/epic/epic-shape.ts +1 -1
  213. package/scripts/epic/epic-solo-stale.ts +107 -0
  214. package/scripts/epic/epic-solo.ts +3 -2
  215. package/scripts/epic/epic-triage.ts +1 -1
  216. package/scripts/epic/epic-validate.ts +1 -1
  217. package/scripts/epic/epic.ts +1 -1
  218. package/scripts/exports/unused-members-cli.ts +53 -0
  219. package/scripts/{git → followup}/followup-issue-number.ts +1 -6
  220. package/scripts/{git → followup}/git-followup-cleanup.ts +2 -1
  221. package/scripts/{git → followup}/git-followup-finish.ts +1 -3
  222. package/scripts/{git → followup}/git-followup-flush.ts +2 -2
  223. package/scripts/{git → followup}/git-followup-issue-close.ts +2 -2
  224. package/scripts/{git → followup}/git-followup-label.ts +4 -4
  225. package/scripts/followup/git-followup-merged.ts +112 -0
  226. package/scripts/{git → followup}/git-followup-pending.ts +1 -1
  227. package/scripts/{git → followup}/git-followup-workflow.ts +19 -11
  228. package/scripts/{git → followup}/git-pr-followup-wrapup.ts +9 -3
  229. package/scripts/{git → followup}/git-pr-followup.ts +53 -16
  230. package/scripts/gate/core-budget.ts +3 -9
  231. package/scripts/gate/gate-plan.ts +7 -4
  232. package/scripts/gate/gate-report.ts +0 -6
  233. package/scripts/gate/gate-tree.ts +1 -1
  234. package/scripts/gate/pre-commit-type-check.ts +0 -6
  235. package/scripts/gate/project-checks.ts +7 -8
  236. package/scripts/gate/scoped-green.ts +0 -1
  237. package/scripts/gate/type-check-step.ts +1 -1
  238. package/scripts/gate/verification-gate.ts +0 -2
  239. package/scripts/gh/fix-gh-packages.ts +15 -12
  240. package/scripts/gh/gh-spawn.ts +2 -2
  241. package/scripts/{git → gh}/git-ai-review-scan.ts +1 -5
  242. package/scripts/{git → gh}/git-gh-check.ts +2 -1
  243. package/scripts/{git → gh}/git-gh-exec.ts +1 -1
  244. package/scripts/{git → gh}/git-gh-failure.ts +1 -1
  245. package/scripts/{git → gh}/git-gh-helpers.ts +0 -1
  246. package/scripts/{git → gh}/git-gh-issue-list.ts +13 -10
  247. package/scripts/{git → gh}/git-gh-issue-read.ts +1 -1
  248. package/scripts/{git → gh}/git-gh-issue-rest.ts +6 -3
  249. package/scripts/{git → gh}/git-gh-issue-write.ts +4 -1
  250. package/scripts/{git → gh}/git-gh-pr-auto-merge.ts +4 -1
  251. package/scripts/{git → gh}/git-gh-pr-read.ts +24 -0
  252. package/scripts/{git → gh}/git-gh-pr-rest.ts +5 -2
  253. package/scripts/{git → gh}/git-gh-pr-review.ts +2 -2
  254. package/scripts/{git → gh}/git-gh-pr-rollup.ts +1 -3
  255. package/scripts/{git → gh}/git-gh-pr.ts +3 -1
  256. package/scripts/{git → gh}/git-pr-ai-review.ts +2 -5
  257. package/scripts/{git → gh}/git-pr-checks-eval.ts +0 -10
  258. package/scripts/{git → gh}/git-pr-checks-parse.ts +4 -20
  259. package/scripts/{git → gh}/git-pr-checks.ts +2 -1
  260. package/scripts/{git → gh}/git-pr-coderabbit.ts +2 -5
  261. package/scripts/{git → gh}/git-pr-confirmation.ts +1 -3
  262. package/scripts/{git → gh}/git-pr-managed-config.ts +2 -3
  263. package/scripts/{git → gh}/git-pr.ts +3 -3
  264. package/scripts/git/changed-file-scope.ts +0 -1
  265. package/scripts/git/git-branch.ts +3 -6
  266. package/scripts/git/git-command.ts +6 -1
  267. package/scripts/git/git-commit.ts +1 -1
  268. package/scripts/git/git-common-directory.ts +80 -24
  269. package/scripts/git/git-error.ts +66 -9
  270. package/scripts/git/git-issue.ts +1 -1
  271. package/scripts/git/git-preflight.ts +2 -2
  272. package/scripts/git/git-prompt.ts +6 -31
  273. package/scripts/git/git-push.ts +1 -1
  274. package/scripts/git/git-spawn-sync.ts +65 -0
  275. package/scripts/git/git-spawn.ts +5 -4
  276. package/scripts/git/git-staging.ts +1 -0
  277. package/scripts/git/git-status.ts +1 -1
  278. package/scripts/git/git-workflow.ts +1 -1
  279. package/scripts/git/gone-branch.ts +1 -0
  280. package/scripts/git/listing-cutoff.ts +1 -1
  281. package/scripts/git/main-merge.ts +1 -1
  282. package/scripts/git/main-sync.ts +19 -1
  283. package/scripts/git/parse-json-array.ts +0 -3
  284. package/scripts/git/repository-lock.ts +16 -16
  285. package/scripts/git/{git-stash.ts → stash/git-stash.ts} +1 -1
  286. package/scripts/git/{stash-pop-args.ts → stash/stash-pop-args.ts} +2 -7
  287. package/scripts/git/{stash-pop-cli.ts → stash/stash-pop-cli.ts} +0 -1
  288. package/scripts/git/{stash-sweep-lock.ts → stash/stash-sweep-lock.ts} +3 -3
  289. package/scripts/hooks/codex-hook-adapter.ts +0 -1
  290. package/scripts/hooks/edited-cspell.ts +1 -1
  291. package/scripts/hooks/format-edited-file.ts +2 -0
  292. package/scripts/hooks/pre-push-unit.ts +0 -4
  293. package/scripts/hooks/pretool-guard.ts +22 -4
  294. package/scripts/hooks/reserved-run.ts +1 -1
  295. package/scripts/hooks/step-zero-notice.ts +76 -0
  296. package/scripts/hooks/stop-guard.ts +47 -21
  297. package/scripts/init/claude-plugin-config.ts +4 -5
  298. package/scripts/init/hook-command-rewrite.ts +16 -8
  299. package/scripts/init/hook-launch.ts +41 -15
  300. package/scripts/init/init-basic.ts +2 -5
  301. package/scripts/init/init-file-action.ts +54 -0
  302. package/scripts/init/init-logic-migrate.ts +35 -17
  303. package/scripts/init/init-logic-secretlint.ts +1 -1
  304. package/scripts/init/init-logic.ts +10 -19
  305. package/scripts/init/init.ts +11 -71
  306. package/scripts/init/kit-written-paths.ts +2 -0
  307. package/scripts/init/project-profile.ts +9 -17
  308. package/scripts/init/start-exec.ts +1 -1
  309. package/scripts/init/start-setup-pr.ts +6 -6
  310. package/scripts/init/start-steps.ts +3 -1
  311. package/scripts/issue/behavior-change-lint.ts +0 -1
  312. package/scripts/issue/defect-rate-cli.ts +64 -23
  313. package/scripts/issue/defect-rate.ts +1 -2
  314. package/scripts/{git → issue}/git-next-issues.ts +3 -3
  315. package/scripts/issue/issue-backlinks-cli.ts +1 -5
  316. package/scripts/issue/issue-backlinks.ts +7 -14
  317. package/scripts/issue/issue-cite-cli.ts +2 -6
  318. package/scripts/issue/issue-cite.ts +12 -8
  319. package/scripts/issue/issue-classification.ts +1 -9
  320. package/scripts/issue/issue-closing-pr.ts +4 -4
  321. package/scripts/issue/issue-comment-cli.ts +2 -2
  322. package/scripts/issue/issue-file-cli.ts +5 -5
  323. package/scripts/issue/issue-file.ts +7 -14
  324. package/scripts/issue/issue-fold-cli.ts +1 -1
  325. package/scripts/issue/issue-fold-existing-cli.ts +1 -1
  326. package/scripts/{git → issue}/issue-labels.ts +8 -0
  327. package/scripts/issue/issue-lint-cli.ts +1 -1
  328. package/scripts/issue/issue-merged.ts +2 -2
  329. package/scripts/{git → issue}/issue-rank.ts +1 -1
  330. package/scripts/issue/issue-read-cli.ts +8 -47
  331. package/scripts/issue/issue-read.ts +0 -2
  332. package/scripts/issue/issue-report-failures.ts +80 -0
  333. package/scripts/issue/issue-scout-cli.ts +1 -7
  334. package/scripts/issue/issue-scout-closed.ts +2 -2
  335. package/scripts/issue/issue-scout.ts +0 -2
  336. package/scripts/issue/issue-state-cli.ts +5 -46
  337. package/scripts/issue/issue-state.ts +1 -5
  338. package/scripts/issue/markdown-section.ts +21 -6
  339. package/scripts/issue/measure-rerun-cli.ts +74 -15
  340. package/scripts/issue/reproduction-measure.ts +1 -1
  341. package/scripts/josh/cli-body.ts +1 -1
  342. package/scripts/josh/file-map-stamp.ts +0 -3
  343. package/scripts/josh/josh-command-map.ts +2 -0
  344. package/scripts/josh/josh-commands-ai.ts +9 -102
  345. package/scripts/josh/josh-commands-backlog.ts +5 -1
  346. package/scripts/josh/josh-commands-development.ts +8 -1
  347. package/scripts/josh/josh-commands-issue.ts +2 -2
  348. package/scripts/josh/josh-commands-maintenance.ts +7 -0
  349. package/scripts/josh/josh-commands-project.ts +7 -1
  350. package/scripts/josh/josh-commands-run.ts +114 -0
  351. package/scripts/josh/josh-commands-versioning.ts +8 -0
  352. package/scripts/josh/josh-commands-workflow.ts +3 -3
  353. package/scripts/josh/path-decision.ts +0 -3
  354. package/scripts/josh/process-owner.ts +16 -0
  355. package/scripts/josh/run-github-prerequisite.ts +3 -6
  356. package/scripts/josh/session-language-cli.ts +0 -1
  357. package/scripts/lane/lane-await.ts +46 -19
  358. package/scripts/lane/lane-capacity.ts +6 -3
  359. package/scripts/lane/lane-child-invocation.ts +20 -7
  360. package/scripts/lane/lane-cli.ts +1 -4
  361. package/scripts/lane/lane-close.ts +5 -4
  362. package/scripts/lane/lane-dispatch.ts +3 -4
  363. package/scripts/lane/lane-environment.ts +0 -9
  364. package/scripts/lane/lane-handoff.ts +38 -0
  365. package/scripts/lane/lane-launch-cli.ts +31 -27
  366. package/scripts/lane/lane-open.ts +0 -3
  367. package/scripts/lane/lane-output.ts +0 -1
  368. package/scripts/lane/lane-registry.ts +9 -0
  369. package/scripts/lane/openai-lane-ship.ts +2 -0
  370. package/scripts/lane/openai-lane-supervisor-decision.ts +2 -1
  371. package/scripts/lane/openai-lane-supervisor.ts +6 -4
  372. package/scripts/lane/openai-review-broker.ts +7 -1
  373. package/scripts/lib/bounded-pool.ts +1 -0
  374. package/scripts/lib/cli-flags.ts +31 -2
  375. package/scripts/lib/error-message.ts +12 -1
  376. package/scripts/lib/json-value.ts +5 -4
  377. package/scripts/lib/poll.ts +3 -1
  378. package/scripts/lib/timed-fetch.ts +15 -0
  379. package/scripts/lib/timeouts.ts +13 -0
  380. package/scripts/{yaml → lib}/yaml-document.ts +3 -1
  381. package/scripts/{bytes → lines}/bytes-command.ts +0 -2
  382. package/scripts/lines/line-targets.ts +0 -11
  383. package/scripts/lines/lines-command.ts +5 -4
  384. package/scripts/lint/lint-related-scope.ts +0 -1
  385. package/scripts/lint/lint-related.ts +1 -1
  386. package/scripts/{git → notify}/telegram-notify.ts +2 -2
  387. package/scripts/{git → notify}/telegram-test.ts +4 -4
  388. package/scripts/observations/observation-ledger-home.ts +0 -1
  389. package/scripts/observations/observation-ledger-line.ts +0 -1
  390. package/scripts/observations/observation-ledger-migrate.ts +1 -1
  391. package/scripts/observations/observations-flush-landing.ts +3 -3
  392. package/scripts/observations/observations-flush.ts +2 -2
  393. package/scripts/overrides/lockfile-overrides.ts +1 -1
  394. package/scripts/overrides/overrides-logic.ts +1 -1
  395. package/scripts/package/package-scout-cli.ts +2 -7
  396. package/scripts/package/package-scout.ts +0 -2
  397. package/scripts/propagate/propagate-git-failure.ts +0 -1
  398. package/scripts/propagate/propagate-git.ts +3 -10
  399. package/scripts/propagate/propagate-publish.ts +2 -3
  400. package/scripts/propagate/propagate-run.ts +0 -2
  401. package/scripts/propagate/propagate-steps.ts +3 -5
  402. package/scripts/propagate/propagate-targets.ts +0 -4
  403. package/scripts/propagate/propagate.ts +0 -4
  404. package/scripts/refactor/import-graph.ts +0 -1
  405. package/scripts/refactor/refactor-lint.ts +0 -2
  406. package/scripts/refactor/refactor-scan.ts +2 -2
  407. package/scripts/refactor/refactor-targets.ts +0 -1
  408. package/scripts/registry-migration/migrate-logic.ts +28 -21
  409. package/scripts/registry-migration/migrate.ts +25 -14
  410. package/scripts/release/github-release-cli.ts +19 -6
  411. package/scripts/release/github-release-environment.ts +46 -0
  412. package/scripts/release/github-release.ts +151 -94
  413. package/scripts/release/release-history.ts +0 -1
  414. package/scripts/release/release-plan.ts +0 -1
  415. package/scripts/release/release-publish.ts +38 -5
  416. package/scripts/release/release-scope-cli.ts +1 -2
  417. package/scripts/release/release-tag.ts +2 -4
  418. package/scripts/release/release-worktree.ts +97 -2
  419. package/scripts/repo/auto-merge-setting-logic.ts +1 -4
  420. package/scripts/repo/repo-setting.ts +1 -1
  421. package/scripts/repo/repository-labels.ts +3 -3
  422. package/scripts/repo/required-checks-logic.ts +206 -0
  423. package/scripts/repo/required-checks-report.ts +71 -0
  424. package/scripts/repo/ruleset-check-cli.ts +53 -0
  425. package/scripts/repo/ruleset-check.ts +147 -0
  426. package/scripts/report/report-lint-cli.ts +0 -4
  427. package/scripts/review/disposition-cli.ts +1 -1
  428. package/scripts/review/live-evidence.ts +1 -1
  429. package/scripts/review/review-attest-cli.ts +0 -6
  430. package/scripts/review/review-attest.ts +4 -16
  431. package/scripts/review/review-brief-cli.ts +23 -6
  432. package/scripts/review/review-brief.ts +21 -8
  433. package/scripts/review/review-checkout.ts +3 -2
  434. package/scripts/review/review-diff-parts.ts +89 -0
  435. package/scripts/review/review-diff-write.ts +97 -0
  436. package/scripts/review/review-finding-ledger.ts +0 -1
  437. package/scripts/review/review-record-cli.ts +10 -17
  438. package/scripts/review/review-record.ts +0 -1
  439. package/scripts/review/review-round2-cli.ts +1 -1
  440. package/scripts/review/review-stamps.ts +0 -3
  441. package/scripts/review/review-tree.ts +14 -2
  442. package/scripts/rules/decision-oracle-stage.ts +18 -0
  443. package/scripts/rules/decision-oracle.ts +10 -7
  444. package/scripts/rules/delivered-rules.ts +9 -1
  445. package/scripts/rules/destructive-command.ts +119 -0
  446. package/scripts/rules/direct-filing.ts +1 -1
  447. package/scripts/rules/early-heartbeat.ts +4 -3
  448. package/scripts/rules/file-body.ts +0 -3
  449. package/scripts/rules/filing-cap.ts +0 -2
  450. package/scripts/rules/gh-api.ts +7 -2
  451. package/scripts/rules/git-argv.ts +18 -7
  452. package/scripts/rules/git-force.ts +0 -2
  453. package/scripts/rules/implementation-cut.ts +0 -1
  454. package/scripts/rules/index-guard.ts +71 -0
  455. package/scripts/rules/issue-citation.ts +50 -25
  456. package/scripts/rules/lane-background.ts +15 -7
  457. package/scripts/rules/lane-park.ts +22 -6
  458. package/scripts/rules/last-prompt.ts +1 -0
  459. package/scripts/rules/oracle-consulted.ts +1 -1
  460. package/scripts/rules/oracle-firing.ts +1 -0
  461. package/scripts/rules/oracle-list-cli.ts +0 -3
  462. package/scripts/rules/permission-guards.ts +14 -0
  463. package/scripts/rules/protected-files.ts +74 -0
  464. package/scripts/rules/reply-language.ts +1 -1
  465. package/scripts/rules/rule-body-guard.ts +0 -3
  466. package/scripts/rules/rule-value-cli.ts +0 -1
  467. package/scripts/rules/shell-body-trigger.ts +0 -1
  468. package/scripts/rules/shell-segments.ts +0 -1
  469. package/scripts/rules/stop-rules.ts +20 -9
  470. package/scripts/rules/tail-commands.ts +1 -1
  471. package/scripts/rules/test-declared-commit.ts +1 -1
  472. package/scripts/rules/third-party-write.ts +0 -1
  473. package/scripts/rules/worktree-guard.ts +26 -9
  474. package/scripts/run/run-carry-args.ts +8 -12
  475. package/scripts/run/run-carry-cli.ts +0 -2
  476. package/scripts/run/run-carry-stash.ts +2 -2
  477. package/scripts/run/run-carry-streak.ts +1 -1
  478. package/scripts/run/run-cut-args.ts +1 -6
  479. package/scripts/run/run-cut-cli.ts +0 -7
  480. package/scripts/run/run-cut.ts +8 -54
  481. package/scripts/run/run-ending-cli.ts +2 -6
  482. package/scripts/run/run-ending.ts +1 -4
  483. package/scripts/run/run-entry-cli.ts +133 -25
  484. package/scripts/run/run-entry-stop.ts +104 -0
  485. package/scripts/run/run-entry.ts +0 -1
  486. package/scripts/run/run-event-cli.ts +0 -2
  487. package/scripts/run/run-event-follow.ts +1 -0
  488. package/scripts/run/run-event-render.ts +1 -1
  489. package/scripts/run/run-event-scope.ts +53 -4
  490. package/scripts/run/run-event-stream-emit.ts +7 -2
  491. package/scripts/run/run-event-stream.ts +0 -3
  492. package/scripts/run/run-event-watch.ts +1 -0
  493. package/scripts/run/run-halfrun-resume.ts +20 -7
  494. package/scripts/run/run-headless.ts +2 -2
  495. package/scripts/run/run-hold-cli.ts +33 -10
  496. package/scripts/run/run-hold.ts +29 -6
  497. package/scripts/run/run-issue-number.ts +1 -1
  498. package/scripts/run/run-liveness-cli.ts +2 -6
  499. package/scripts/run/run-liveness.ts +2 -3
  500. package/scripts/run/run-merge-cli.ts +7 -23
  501. package/scripts/run/run-merge-steps.ts +5 -5
  502. package/scripts/run/run-merge.ts +1 -1
  503. package/scripts/run/run-next-cli.ts +1 -1
  504. package/scripts/run/run-parent-cut-hook.ts +4 -2
  505. package/scripts/run/run-preflight.ts +2 -9
  506. package/scripts/run/run-prep-cli.ts +6 -3
  507. package/scripts/run/run-prep-locate.ts +1 -1
  508. package/scripts/run/run-progress-args.ts +20 -4
  509. package/scripts/run/run-progress-cli.ts +35 -36
  510. package/scripts/run/run-progress-clock.ts +10 -35
  511. package/scripts/run/run-progress-config.ts +0 -4
  512. package/scripts/run/run-progress-read.ts +1 -2
  513. package/scripts/run/run-progress.ts +1 -2
  514. package/scripts/run/run-prrun-resume.ts +117 -0
  515. package/scripts/run/run-report-cli.ts +1 -2
  516. package/scripts/run/run-report.ts +0 -1
  517. package/scripts/run/run-retrospective.ts +1 -1
  518. package/scripts/run/run-review-cli.ts +0 -3
  519. package/scripts/run/run-review-steps.ts +2 -0
  520. package/scripts/run/run-review.ts +0 -2
  521. package/scripts/run/run-ship-cli.ts +29 -19
  522. package/scripts/run/run-ship-detach.ts +1 -0
  523. package/scripts/run/run-ship-next.ts +106 -0
  524. package/scripts/run/run-ship-preflight.ts +1 -1
  525. package/scripts/run/run-ship-probe.ts +4 -1
  526. package/scripts/run/run-ship-return.ts +8 -3
  527. package/scripts/run/run-ship-review-steps.ts +18 -4
  528. package/scripts/run/run-ship-review.ts +11 -0
  529. package/scripts/run/run-ship-scoped.ts +1 -0
  530. package/scripts/run/run-ship-steps.ts +1 -1
  531. package/scripts/run/run-ship.ts +0 -1
  532. package/scripts/run/run-stage-read.ts +62 -0
  533. package/scripts/run/run-stage.ts +160 -0
  534. package/scripts/run/run-status-cli.ts +3 -16
  535. package/scripts/run/run-step-cli.ts +21 -14
  536. package/scripts/run/run-step.ts +1 -1
  537. package/scripts/run/run-stop-notify.ts +1 -3
  538. package/scripts/run/run-stranded-cli.ts +0 -4
  539. package/scripts/run/run-stranded-detect.ts +2 -2
  540. package/scripts/run/run-tail-cli.ts +17 -11
  541. package/scripts/run/run-tail.ts +2 -0
  542. package/scripts/run/run-tidy-lanes.ts +6 -2
  543. package/scripts/run/run-tidy-stashes.ts +12 -12
  544. package/scripts/run/run-wake-cli.ts +4 -13
  545. package/scripts/run/run-wake-loop.ts +2 -2
  546. package/scripts/run/run-wake.ts +2 -4
  547. package/scripts/run/run-watcher-guard-cli.ts +0 -4
  548. package/scripts/run/run-watcher-guard.ts +18 -12
  549. package/scripts/run/run-watcher-hook.ts +1 -1
  550. package/scripts/safe-chain/ci-installer-pin.ts +11 -5
  551. package/scripts/safe-chain/pack-hook.ts +92 -0
  552. package/scripts/safe-chain/project-config.ts +1 -1
  553. package/scripts/security/security-audit-provision-logic.ts +0 -1
  554. package/scripts/security/security-audit-provision.ts +3 -2
  555. package/scripts/security/security-audit.ts +0 -1
  556. package/scripts/security/security-updates-logic.ts +0 -1
  557. package/scripts/sonar/sonar-hotspots-cli.ts +10 -52
  558. package/scripts/sonar/sonar-hotspots.ts +0 -1
  559. package/scripts/sonar/sonar-new-code-cli.ts +150 -0
  560. package/scripts/sonar/sonar-new-code.ts +79 -0
  561. package/scripts/sonar/sonar-project.ts +97 -0
  562. package/scripts/split/split-assess-cli.ts +1 -1
  563. package/scripts/split/split-assess.ts +2 -5
  564. package/scripts/sync/managed-config-scope-cli.ts +1 -1
  565. package/scripts/sync/skill-migration.ts +0 -1
  566. package/scripts/sync/sync-ai-files.ts +4 -0
  567. package/scripts/sync/sync-hook-safety.ts +2 -3
  568. package/scripts/sync/sync.ts +1 -8
  569. package/scripts/sync/template-source-logic.ts +0 -1
  570. package/scripts/sync/workflow-pin-logic.ts +16 -28
  571. package/scripts/test/test-declared-changed.ts +13 -16
  572. package/scripts/test/test-declared-logic.ts +0 -1
  573. package/scripts/test/test-declared.ts +3 -9
  574. package/scripts/test/test-red-commit.ts +2 -2
  575. package/scripts/test/test-red.ts +14 -7
  576. package/scripts/test/test-type-logic.ts +1 -1
  577. package/scripts/test/unit-worker-share.ts +7 -16
  578. package/scripts/time-runtime/time-batch-guard.ts +1 -2
  579. package/scripts/time-runtime/time-bundle-call.ts +0 -1
  580. package/scripts/time-runtime/time-bundles.ts +0 -4
  581. package/scripts/time-runtime/time-density-hook.ts +0 -2
  582. package/scripts/time-runtime/time-followup-stage.ts +1 -1
  583. package/scripts/time-runtime/time-format.ts +0 -73
  584. package/scripts/time-runtime/time-round-trips.ts +0 -4
  585. package/scripts/time-runtime/time-single-check.ts +1 -1
  586. package/scripts/time-runtime/time-spans.ts +1 -1
  587. package/scripts/time-runtime/time-transcript-line.ts +1 -2
  588. package/scripts/ui/ui-routes-cli.ts +0 -5
  589. package/scripts/ui/ui-routes.ts +0 -5
  590. package/scripts/version/effective-upstream.ts +2 -2
  591. package/scripts/version/latest-corepack.ts +7 -9
  592. package/scripts/version/latest-scope-cli.ts +0 -2
  593. package/scripts/version/latest-update.ts +0 -2
  594. package/scripts/version/npm-registry.ts +2 -2
  595. package/scripts/version/publishable-range-check.ts +1 -1
  596. package/scripts/version/release-hold.ts +0 -4
  597. package/scripts/version/running-binary.ts +2 -2
  598. package/scripts/version/version-check-logic.ts +0 -2
  599. package/scripts/version/version-commands.ts +11 -1
  600. package/scripts/version/version-remote.ts +3 -3
  601. package/scripts/version/version-targets.ts +4 -4
  602. package/templates/CLAUDE.basic.md +6 -6
  603. package/templates/sonar-project.properties +28 -1
  604. package/templates/workflows/ci.yml +16 -82
  605. package/templates/workflows/dependabot-auto-merge.yml +6 -3
  606. package/templates/workflows/github-release.yml +79 -0
  607. package/tsconfig.sonar.json +4 -22
  608. package/prompts/collaboration-workflow/cross-repo-epic.md +0 -5
  609. package/prompts/collaboration-workflow/epic-audit.md +0 -5
  610. package/prompts/collaboration-workflow/epic-bundle.md +0 -5
  611. package/scripts/init/plugin-install-hint.ts +0 -47
  612. package/scripts/version/parse-json.ts +0 -13
  613. /package/scripts/{git → followup}/git-followup-stages.ts +0 -0
  614. /package/scripts/{git → gh}/git-gh-api-path.ts +0 -0
  615. /package/scripts/{git → gh}/git-gh-command.ts +0 -0
  616. /package/scripts/{git → gh}/git-gh-issue.ts +0 -0
  617. /package/scripts/{git → gh}/git-gh-pr-snapshot.ts +0 -0
  618. /package/scripts/{git → gh}/git-gh-reachability.ts +0 -0
  619. /package/scripts/{git → gh}/git-gh-repo.ts +0 -0
  620. /package/scripts/{git → gh}/git-gh-rest-state.ts +0 -0
  621. /package/scripts/{git → gh}/git-pr-checks-watch.ts +0 -0
  622. /package/scripts/{git → gh}/git-pr-error.ts +0 -0
  623. /package/scripts/{git → gh}/git-pr-messages.ts +0 -0
  624. /package/scripts/{git → gh}/github-issue-url.ts +0 -0
  625. /package/scripts/git/{stash-orphans.ts → stash/stash-orphans.ts} +0 -0
  626. /package/scripts/{git → issue}/issue-reference.ts +0 -0
  627. /package/scripts/{git → lib}/animation-helpers.ts +0 -0
  628. /package/scripts/{git → lib}/git-animation.ts +0 -0
  629. /package/scripts/{git → notify}/git-notify.ts +0 -0
  630. /package/scripts/{git → notify}/telegram-test-logic.ts +0 -0
@@ -0,0 +1,65 @@
1
+ import { read_spawn_stderr, read_spawn_stdout } from '#scripts/lib/spawn-exit'
2
+ import { execaSync } from 'execa'
3
+ import { git_utilities } from './constants'
4
+
5
+ // The one place a synchronous git command is spawned from (joshuafolkken/kit#3065) — the sync
6
+ // counterpart of `git-spawn.ts`. Every caller here wants an answer rather than an exception, so a
7
+ // non-zero exit is returned as a result, and every call is bounded: a git that never answers is an
8
+ // unknown the caller already handles, never a hang.
9
+
10
+ const GIT_TIMEOUT_MS = 10_000
11
+ const SUCCESS_EXIT_CODE = 0
12
+ // git translates its messages, so a caller matching stderr would fail under any non-English locale.
13
+ const C_LOCALE: Record<string, string> = { LC_ALL: 'C', LANGUAGE: 'C' }
14
+
15
+ interface GitSyncOptions {
16
+ cwd?: string
17
+ timeout?: number
18
+ env?: Record<string, string | undefined>
19
+ }
20
+
21
+ interface GitSyncResult {
22
+ exit_code: number | undefined
23
+ stdout: string
24
+ stderr: string
25
+ }
26
+
27
+ function run(args: ReadonlyArray<string>, options: GitSyncOptions = {}): GitSyncResult {
28
+ // execa runs the binary directly with an argument array and no `shell` option; the git command and
29
+ // args are internally controlled, never untrusted input. tssecurity:S8705 is a false positive here.
30
+ const result = execaSync(git_utilities.get_git_command_for_spawn(), args, {
31
+ ...options,
32
+ extendEnv: true,
33
+ reject: false,
34
+ timeout: options.timeout ?? GIT_TIMEOUT_MS,
35
+ }) // NOSONAR
36
+
37
+ return {
38
+ exit_code: result.exitCode,
39
+ stdout: read_spawn_stdout(result),
40
+ stderr: read_spawn_stderr(result),
41
+ }
42
+ }
43
+
44
+ // The trimmed output of a command that succeeded, or undefined for any failure.
45
+ function read(args: ReadonlyArray<string>, options: GitSyncOptions = {}): string | undefined {
46
+ const result = run(args, options)
47
+
48
+ return result.exit_code === SUCCESS_EXIT_CODE ? result.stdout.trim() : undefined
49
+ }
50
+
51
+ // The configured `origin` URL, or undefined when the repository has none.
52
+ function origin_url(cwd: string): string | undefined {
53
+ return read(['config', '--get', 'remote.origin.url'], { cwd })
54
+ }
55
+
56
+ // The absolute repository (or worktree) root, asked under the C locale so a caller can tell "not a
57
+ // repository" apart from every other failure by its stderr.
58
+ function toplevel(timeout: number = GIT_TIMEOUT_MS): GitSyncResult {
59
+ return run(['rev-parse', '--show-toplevel'], { env: C_LOCALE, timeout })
60
+ }
61
+
62
+ const git_spawn_sync = { GIT_TIMEOUT_MS, C_LOCALE, run, read, origin_url, toplevel }
63
+
64
+ export { git_spawn_sync }
65
+ export type { GitSyncResult }
@@ -18,10 +18,11 @@ import { git_ssh_keepalive } from './git-ssh-keepalive'
18
18
  // **`git-push-transport.ts` is the one deliberate exception among the command modules** and is not a
19
19
  // second helper of this kind: a push needs a transport-fault retry that no other command has, so it
20
20
  // spawns git itself. The timeout it carries is shared here by `read_remote` / `with_output_remote`. Those two files are the spawn sites of the ordinary command
21
- // modules — the claim stops there. Other parts of this package spawn git for their own purposes
22
- // (`scripts/run/run-progress-clock.ts`, `scripts/propagate/propagate-git.ts`,
23
- // `scripts/doctor/doctor-io.ts`, `scripts/git/git-fixture-workspace.ts`), and an audit of how the git
24
- // binary is resolved has to read those too.
21
+ // modules — the claim stops there. A synchronous caller goes through `git-spawn-sync.ts`, the same
22
+ // binary resolution with a result instead of an exception (joshuafolkken/kit#3065). Other parts of
23
+ // this package spawn git for their own purposes (`scripts/run/run-progress-clock.ts`,
24
+ // `scripts/git/git-fixture-workspace.ts`), and an audit of how the git binary is resolved has to read
25
+ // those too.
25
26
 
26
27
  async function read(arguments_: Array<string>): Promise<string> {
27
28
  const git_cmd = git_utilities.get_git_command_for_spawn()
@@ -62,6 +62,7 @@ async function stage_untracked_files(files: ReadonlyArray<string>): Promise<void
62
62
  if (files.length === 0) return
63
63
 
64
64
  for (const file of files) {
65
+ // eslint-disable-next-line no-await-in-loop -- git add holds the index lock, so two at once fail
65
66
  await git_command.add_path(file)
66
67
  }
67
68
 
@@ -1,4 +1,4 @@
1
- import { animation_helpers, type AnimationOptions } from './animation-helpers'
1
+ import { animation_helpers, type AnimationOptions } from '#scripts/lib/animation-helpers'
2
2
  import { REQUIRED_STATUS_LENGTH, STAGED_STATUS_INDEX, UNTRACKED_FILE_PREFIX } from './constants'
3
3
  import { git_command } from './git-command'
4
4
 
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env tsx
2
2
  import { parseArgs } from 'node:util'
3
+ import { git_pr } from '#scripts/gh/git-pr'
3
4
  import { cli_body } from '#scripts/josh/cli-body'
4
5
  import { test_red_commit } from '#scripts/test/test-red-commit'
5
6
  import { git_branch } from './git-branch'
6
7
  import { git_commit } from './git-commit'
7
8
  import { git_error } from './git-error'
8
9
  import { git_issue, type IssueInfo } from './git-issue'
9
- import { git_pr } from './git-pr'
10
10
  import { git_preflight } from './git-preflight'
11
11
  import { git_prompt, type WorkflowConfirmations } from './git-prompt'
12
12
  import { git_push } from './git-push'
@@ -89,6 +89,7 @@ async function delete_each(names: ReadonlyArray<string>): Promise<PruneResult> {
89
89
 
90
90
  for (const name of names) {
91
91
  try {
92
+ // eslint-disable-next-line no-await-in-loop -- branch deletions write the same refs, one at a time
92
93
  await git_spawn.read(['branch', '-d', name])
93
94
  result.deleted.push(name)
94
95
  } catch {
@@ -1,4 +1,4 @@
1
- import { MAX_SCANNED } from './git-gh-issue-list'
1
+ import { MAX_SCANNED } from '#scripts/gh/git-gh-issue-list'
2
2
 
3
3
  // Why an open-issue listing stopped short of the end of the backlog, or that it did not
4
4
  // (joshuafolkken/kit#1067).
@@ -114,7 +114,7 @@ async function main(argv: ReadonlyArray<string>): Promise<void> {
114
114
  process.exitCode = await run(argv)
115
115
  }
116
116
 
117
- const main_merge = { COMMAND_NAME, main, run }
117
+ const main_merge = { run }
118
118
 
119
119
  if (process.argv[1] === fileURLToPath(import.meta.url)) await main(process.argv.slice(ARGV_OFFSET))
120
120
 
@@ -70,9 +70,27 @@ async function prune_quietly(default_branch: string): Promise<void> {
70
70
  }
71
71
  }
72
72
 
73
+ // **The local default branch is fast-forwarded before it is checked out** (joshuafolkken/kit#2979).
74
+ // A run's ledger file is committed on its feature branch and merged; a line appended afterwards leaves
75
+ // it dirty, and git refuses to check out a stale default branch that lacks the file — so `run:tail`'s
76
+ // sync failed exactly when the flush after it had work. Once fast-forwarded, the default branch holds
77
+ // the committed file and the checkout carries the dirty lines over (the same step the flush takes,
78
+ // joshuafolkken/kit#2462). Skipped on the default branch, where `fetch` refuses to update the checked-out
79
+ // ref; a refusal elsewhere — a local default ahead of origin — is left to the checkout and pull to judge.
80
+ async function fast_forward_quietly(default_branch: string): Promise<void> {
81
+ if ((await git_command.branch()) === default_branch) return
82
+
83
+ try {
84
+ await git_command.fast_forward_local(default_branch)
85
+ } catch {
86
+ // The checkout and `pull --ff-only` below decide, exactly as before this step existed.
87
+ }
88
+ }
89
+
73
90
  async function synchronize(): Promise<number> {
74
91
  const default_branch = await git_command.get_default_branch()
75
92
 
93
+ await fast_forward_quietly(default_branch)
76
94
  await git_command.checkout(default_branch)
77
95
  await git_command.pull_fast_forward()
78
96
  await prune_quietly(default_branch)
@@ -115,7 +133,7 @@ async function main(argv: ReadonlyArray<string>): Promise<void> {
115
133
  process.exitCode = await run(argv)
116
134
  }
117
135
 
118
- const main_sync = { COMMAND_NAME, LANE_REFUSAL, main, run }
136
+ const main_sync = { run }
119
137
 
120
138
  if (process.argv[1] === fileURLToPath(import.meta.url)) await main(process.argv.slice(ARGV_OFFSET))
121
139
 
@@ -87,10 +87,7 @@ function parse_json_object_safe<T>(raw_json: string, schema: z.ZodType<T>): T |
87
87
  }
88
88
 
89
89
  const parse_json = {
90
- parse_json_array_safe,
91
- parse_json_array_or_undefined,
92
90
  parse_json_object_safe,
93
- read_json_listing,
94
91
  }
95
92
 
96
93
  export {
@@ -2,7 +2,9 @@ import { randomUUID } from 'node:crypto'
2
2
  import { linkSync, renameSync, rmSync } from 'node:fs'
3
3
  import { setTimeout as sleep } from 'node:timers/promises'
4
4
  import { process_identity } from '#scripts/josh/process-identity'
5
+ import { process_owner_schema, type ProcessOwner } from '#scripts/josh/process-owner'
5
6
  import { stamp_file } from '#scripts/josh/stamp-file'
7
+ import { json_value } from '#scripts/lib/json-value'
6
8
  import { git_common_directory } from './git-common-directory'
7
9
 
8
10
  // One holder at a time per repository, for work that every work tree of that repository shares
@@ -14,32 +16,29 @@ import { git_common_directory } from './git-common-directory'
14
16
 
15
17
  const POLL_INTERVAL_MS = 200
16
18
 
17
- interface LockOwner {
18
- pid: number
19
- process_start?: string
20
- }
21
-
22
- type IsGone = (owner: LockOwner) => boolean
19
+ type IsGone = (owner: ProcessOwner) => boolean
23
20
 
24
- function lock_path(prefix: string, cwd: string = process.cwd()): string {
25
- return stamp_file.stamp_path(prefix, git_common_directory.repository(cwd) ?? cwd)
21
+ // Without a `cwd` the read keeps the inherited git location variables, as every other git call of the
22
+ // running process does; an explicit `cwd` clears them so that directory is the one answered for.
23
+ function lock_path(prefix: string, cwd?: string): string {
24
+ return stamp_file.stamp_path(prefix, git_common_directory.repository(cwd) ?? cwd ?? process.cwd())
26
25
  }
27
26
 
28
- function parse_owner(raw: string | undefined): LockOwner | undefined {
27
+ // A record that is not JSON, or is JSON of any other shape — `null`, an array, an object with no
28
+ // numeric `pid` — is unreadable rather than an owner, so it is never judged and never cleared.
29
+ function parse_owner(raw: string | undefined): ProcessOwner | undefined {
29
30
  if (raw === undefined) return undefined
30
31
 
31
- try {
32
- return JSON.parse(raw) as LockOwner
33
- } catch {
34
- return undefined
35
- }
32
+ const parsed = process_owner_schema.safeParse(json_value.parse_or_undefined(raw))
33
+
34
+ return parsed.success ? parsed.data : undefined
36
35
  }
37
36
 
38
- function read_owner(target: string): LockOwner | undefined {
37
+ function read_owner(target: string): ProcessOwner | undefined {
39
38
  return parse_owner(stamp_file.read_stamp_text(target))
40
39
  }
41
40
 
42
- function is_owner_gone(owner: LockOwner): boolean {
41
+ function is_owner_gone(owner: ProcessOwner): boolean {
43
42
  return process_identity.is_same_process(owner.pid, owner.process_start) === false
44
43
  }
45
44
 
@@ -111,6 +110,7 @@ async function acquire(target: string, max_wait_ms: number): Promise<boolean> {
111
110
 
112
111
  while (!claim(target)) {
113
112
  if (Date.now() >= deadline) return false
113
+ // eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
114
114
  await sleep(POLL_INTERVAL_MS)
115
115
  }
116
116
 
@@ -1,4 +1,4 @@
1
- import { git_spawn } from './git-spawn'
1
+ import { git_spawn } from '#scripts/git/git-spawn'
2
2
 
3
3
  // The one place a sanctioned `git stash pop` is targeted by its message rather than its stack
4
4
  // position (joshuafolkken/kit#2050). The stash is a single repository-wide stack shared by every
@@ -21,12 +21,7 @@ interface Request {
21
21
  }
22
22
 
23
23
  function read_arguments(argv: ReadonlyArray<string>): ParsedValues | undefined {
24
- return cli_flags.parse_or_undefined({
25
- args: [...argv],
26
- options: OPTIONS,
27
- strict: true,
28
- allowPositionals: true,
29
- })
24
+ return cli_flags.arguments_of(argv, OPTIONS)
30
25
  }
31
26
 
32
27
  // The message is the sole positional and must be a non-empty string: an empty message matches every
@@ -47,7 +42,7 @@ function to_request(parsed: ParsedValues): Request | undefined {
47
42
  return { message, dir: parsed.values.dir }
48
43
  }
49
44
 
50
- const stash_pop_args = { USAGE, message_of, read_arguments, to_request }
45
+ const stash_pop_args = { USAGE, read_arguments, to_request }
51
46
 
52
47
  export type { Request }
53
48
  export { stash_pop_args }
@@ -97,7 +97,6 @@ const stash_pop_cli = {
97
97
  CONFLICTED_VERDICT,
98
98
  NO_MATCH_VERDICT,
99
99
  POPPED_VERDICT,
100
- main,
101
100
  run,
102
101
  }
103
102
 
@@ -1,4 +1,4 @@
1
- import { repository_lock } from './repository-lock'
1
+ import { repository_lock } from '#scripts/git/repository-lock'
2
2
 
3
3
  // One stash sweep at a time per repository (joshuafolkken/kit#2701). The stash is a single stack every
4
4
  // work tree shares, and a `backlogrun` runs one sweep per lane seat at once: two sweeps that each
@@ -11,7 +11,7 @@ const LOCK_PREFIX = 'josh-stash-sweep-lock-'
11
11
  // wait; the cap only bounds a holder that hung, and a sweep that gives up keeps its entries.
12
12
  const MAX_WAIT_MS = 30_000
13
13
 
14
- function lock_path(cwd: string = process.cwd()): string {
14
+ function lock_path(cwd?: string): string {
15
15
  return repository_lock.lock_path(LOCK_PREFIX, cwd)
16
16
  }
17
17
 
@@ -25,6 +25,6 @@ async function with_lock<T>(
25
25
  return await repository_lock.with_lock(work, target, max_wait_ms)
26
26
  }
27
27
 
28
- const stash_sweep_lock = { clear_stale: repository_lock.clear_stale, lock_path, with_lock }
28
+ const stash_sweep_lock = { clear_stale: repository_lock.clear_stale, with_lock }
29
29
 
30
30
  export { stash_sweep_lock }
@@ -146,7 +146,6 @@ if (process.argv[1] === fileURLToPath(import.meta.url)) {
146
146
 
147
147
  const codex_hook_adapter = {
148
148
  format_posttool_payloads,
149
- patch_paths,
150
149
  posttool_payloads,
151
150
  pretool_outcome,
152
151
  pretool_payload,
@@ -122,7 +122,7 @@ async function spelling_diagnostics(
122
122
  }
123
123
  }
124
124
 
125
- const edited_cspell = { format_unknown_words, is_checkable, spelling_diagnostics }
125
+ const edited_cspell = { format_unknown_words, spelling_diagnostics }
126
126
 
127
127
  export type { CspellRunner }
128
128
  export { edited_cspell, MAX_DIAGNOSTIC_CHARS }
@@ -327,6 +327,7 @@ async function run_command(command: FormatCommand, project_root: string): Promis
327
327
  let outcome: CommandOutcome = { exit_code: 0, stdout: '' }
328
328
 
329
329
  for (const invocation of resolve_invocations(command, project_root)) {
330
+ // eslint-disable-next-line no-await-in-loop -- a fallback route runs only when the previous one failed to start
330
331
  outcome = await spawn_invocation(invocation, project_root)
331
332
  if (!is_start_failure(outcome)) return outcome
332
333
  }
@@ -374,6 +375,7 @@ async function collect_unfixed(
374
375
 
375
376
  for (const command of plan) {
376
377
  try {
378
+ // eslint-disable-next-line no-await-in-loop -- formatters rewrite the same file, in plan order
377
379
  unfixed = eslint_unfixed(command, await runner(command, project_root)) ?? unfixed
378
380
  } catch {
379
381
  // One formatter failing to start is not a reason to skip the next: prettier runs last, and
@@ -136,10 +136,6 @@ if (process.argv[1] === fileURLToPath(import.meta.url)) {
136
136
 
137
137
  const pre_push_unit = {
138
138
  FORCE_ENV,
139
- format_skip,
140
- forwarded_arguments,
141
- read_push_tree,
142
- reusable_green_push,
143
139
  run_pre_push_unit,
144
140
  }
145
141
 
@@ -5,6 +5,7 @@ import { delivered_rules } from '#scripts/rules/delivered-rules'
5
5
  import { run_parent_cut_hook } from '#scripts/run/run-parent-cut-hook'
6
6
  import { run_watcher_hook } from '#scripts/run/run-watcher-hook'
7
7
  import { batch_outcome } from './batch-guard'
8
+ import { step_zero_notice } from './step-zero-notice'
8
9
 
9
10
  // One PreToolUse process for the three guards that used to be three (joshuafolkken/kit#1930). A Bash
10
11
  // call used to spawn `batch:guard`, `investigation:guard` and `rule:guard` separately — three pnpm
@@ -49,10 +50,20 @@ function with_duplicate_notice(combined: GuardOutcome, notice: string | undefine
49
50
  return { reason: undefined, notice, fault: undefined }
50
51
  }
51
52
 
53
+ // The Step 0 reminder is the last word (joshuafolkken/kit#2994): asked only where every guard stayed
54
+ // clear, so a refusal or another notice never spends its once-per-session stamp unseen.
55
+ function with_step_zero_notice(outcome: GuardOutcome, raw_payload: string): GuardOutcome {
56
+ if (!is_clear(outcome)) return outcome
57
+
58
+ const notice = step_zero_notice.notice(raw_payload)
59
+
60
+ return notice === undefined ? outcome : { reason: undefined, notice, fault: undefined }
61
+ }
62
+
52
63
  // All guards run unconditionally, exactly as the separate PreToolUse entries did: each records its own
53
64
  // once-per-run stamp, so short-circuiting on the first refusal would change which guard is allowed to
54
65
  // fire on a later call.
55
- function pretool_outcome(raw_payload: string): GuardOutcome {
66
+ function guard_outcome(raw_payload: string): GuardOutcome {
56
67
  const batch = batch_outcome(raw_payload)
57
68
  const investigation = investigation_refusal(raw_payload)
58
69
  const duplicate = duplicate_read_outcome(raw_payload)
@@ -63,6 +74,11 @@ function pretool_outcome(raw_payload: string): GuardOutcome {
63
74
  return with_duplicate_notice(combined, duplicate.notice)
64
75
  }
65
76
 
77
+ // The synchronous verdict the Codex adapter asks for, with the Step 0 reminder as its last layer.
78
+ function pretool_outcome(raw_payload: string): GuardOutcome {
79
+ return with_step_zero_notice(guard_outcome(raw_payload), raw_payload)
80
+ }
81
+
66
82
  // The watcher guard is the one composed rule that cannot answer synchronously — it reads the lane
67
83
  // registry and the watcher's life record off disk (joshuafolkken/kit#2353). So it is asked after the
68
84
  // synchronous guards and only where they stayed clear: a refusal from any of them wins first, exactly
@@ -81,15 +97,17 @@ async function async_reason(raw_payload: string): Promise<string | undefined> {
81
97
  }
82
98
 
83
99
  async function pretool_outcome_async(raw_payload: string): Promise<GuardOutcome> {
84
- const base = pretool_outcome(raw_payload)
100
+ const base = guard_outcome(raw_payload)
85
101
 
86
102
  if (!is_clear(base)) return base
87
103
 
88
104
  const reason = await async_reason(raw_payload)
89
105
 
90
- return reason === undefined ? base : { reason, notice: undefined, fault: undefined }
106
+ if (reason !== undefined) return { reason, notice: undefined, fault: undefined }
107
+
108
+ return with_step_zero_notice(base, raw_payload)
91
109
  }
92
110
 
93
- const pretool_guard = { combine_outcomes, pretool_outcome, pretool_outcome_async }
111
+ const pretool_guard = { combine_outcomes, pretool_outcome }
94
112
 
95
113
  export { pretool_guard, pretool_outcome, pretool_outcome_async }
@@ -85,6 +85,6 @@ if (process.argv[1] === fileURLToPath(import.meta.url)) {
85
85
  process.exitCode = await run_reserved(process.argv.slice(FIRST_ARGUMENT_INDEX))
86
86
  }
87
87
 
88
- const reserved_run = { parse_arguments, run_command, run_reserved }
88
+ const reserved_run = { parse_arguments, run_reserved }
89
89
 
90
90
  export { reserved_run }
@@ -0,0 +1,76 @@
1
+ import path from 'node:path'
2
+ import { hook_decision } from '#scripts/josh/hook-decision'
3
+ import { json_value } from '#scripts/lib/json-value'
4
+ import { test_declared_logic } from '#scripts/test/test-declared-logic'
5
+
6
+ // The Code Change Rules Step 0 reminder, delivered at the moment implementation code is about to be
7
+ // written rather than on every prompt (joshuafolkken/kit#2994). As a `UserPromptSubmit` echo it was
8
+ // injected into every turn — a question that writes nothing included — and re-read as accumulated
9
+ // context on each turn after it. The trigger the rule names is "before writing any implementation
10
+ // code", so the hook that delivers it is the one that sees that write: the first `Edit` / `Write` of a
11
+ // runtime file in the session.
12
+ //
13
+ // **A runtime file only.** What counts is `test_declared_logic.is_exempt`, the same classification
14
+ // `pnpm josh test:declared` answers at the commit, so a doc or prompt edit neither shows the notice nor
15
+ // spends it. A path outside the working tree (a memory file, a scratchpad) is not this project's code.
16
+ //
17
+ // **Once per session**, on a stamp keyed by the transcript like every other guard record here. A stamp
18
+ // that cannot be written stays silent rather than repeating the notice on every edit.
19
+ const STAMP_PREFIX = 'josh-step-zero-notice-'
20
+ const EDIT_TOOLS: ReadonlySet<string> = new Set(['Edit', 'Write'])
21
+ const PARENT_PREFIX = '..'
22
+
23
+ const NOTICE =
24
+ 'Before writing any implementation code: present the two-layer work summary (Now / Change / Check, then every change with its test) once per Issue. Full rule: Code Change Rules Step 0 in CLAUDE.md.'
25
+
26
+ const STAMP = hook_decision.create_refusal_stamp(STAMP_PREFIX)
27
+
28
+ // A Codex `apply_patch` arrives translated with its first file as `file_path` and every file in
29
+ // `file_paths`, so a patch that leads with a doc and also writes code is still a runtime write.
30
+ function edited_paths(tool_input: unknown): Array<string> {
31
+ if (!json_value.is_record(tool_input)) return []
32
+
33
+ const { file_path, file_paths } = tool_input
34
+ const listed: ReadonlyArray<unknown> = Array.isArray(file_paths) ? file_paths : []
35
+
36
+ return [file_path, ...listed].filter(
37
+ (entry): entry is string => typeof entry === 'string' && entry.length > 0,
38
+ )
39
+ }
40
+
41
+ function is_runtime_file(file_path: string, root: string): boolean {
42
+ const relative = path.relative(root, path.resolve(root, file_path))
43
+
44
+ if (relative.startsWith(PARENT_PREFIX) || path.isAbsolute(relative)) return false
45
+
46
+ return !test_declared_logic.is_exempt(relative.split(path.sep).join('/'))
47
+ }
48
+
49
+ function is_candidate(raw_payload: string, root: string): string | undefined {
50
+ const payload = hook_decision.parse_hook_payload(raw_payload)
51
+
52
+ if (payload === undefined || !EDIT_TOOLS.has(payload.tool_name)) return undefined
53
+
54
+ const has_runtime_file = edited_paths(payload.tool_input).some((file_path) =>
55
+ is_runtime_file(file_path, root),
56
+ )
57
+
58
+ return has_runtime_file ? payload.transcript_path : undefined
59
+ }
60
+
61
+ function notice(raw_payload: string, root: string = process.cwd()): string | undefined {
62
+ const transcript = is_candidate(raw_payload, root)
63
+
64
+ if (transcript === undefined) return undefined
65
+
66
+ const target = STAMP.path(transcript)
67
+
68
+ if (STAMP.last_ms(target) !== hook_decision.NEVER_MS) return undefined
69
+ if (!STAMP.record(target, Date.now())) return undefined
70
+
71
+ return NOTICE
72
+ }
73
+
74
+ const step_zero_notice = { NOTICE, notice, stamp_path: STAMP.path }
75
+
76
+ export { step_zero_notice }
@@ -7,12 +7,15 @@ import { repo_party } from '#scripts/discovery/repo-party'
7
7
  import { hook_decision } from '#scripts/josh/hook-decision'
8
8
  import { session_language } from '#scripts/josh/session-language'
9
9
  import { lane_child_marker } from '#scripts/lane/lane-child-marker'
10
+ import { lane_handoff } from '#scripts/lane/lane-handoff'
10
11
  import { filing_cap } from '#scripts/rules/filing-cap'
11
12
  import { lane_background } from '#scripts/rules/lane-background'
12
13
  import { lane_park } from '#scripts/rules/lane-park'
13
14
  import { last_prompt } from '#scripts/rules/last-prompt'
14
15
  import { stop_rules, type StopContext, type StopOutcome } from '#scripts/rules/stop-rules'
16
+ import { run_carry } from '#scripts/run/run-carry'
15
17
  import { run_cut } from '#scripts/run/run-cut'
18
+ import { run_halfrun_resume } from '#scripts/run/run-halfrun-resume'
16
19
  import { run_headless } from '#scripts/run/run-headless'
17
20
  import { run_hold } from '#scripts/run/run-hold'
18
21
  import { run_stranded_detect } from '#scripts/run/run-stranded-detect'
@@ -29,16 +32,17 @@ import { time_hook_transcript } from '#scripts/time-runtime/time-hook-transcript
29
32
  // resolving (send the notify, release the hold) and `stop_hook_active` is the backstop, so failing
30
33
  // open here costs at most a missed nudge, never a stuck run.
31
34
 
32
- // The hold record for this working tree is still in place. `unreadable` reads as absent: the safe
33
- // direction for a stop guard is not to block, and an unreadable record is not proof a run is holding.
34
- async function is_hold_present(): Promise<boolean> {
35
+ // The hold record for this working tree is still in place, and whether it is a `prrun` stop's
36
+ // (joshuafolkken/kit#3023). `unreadable` reads as absent: the safe direction for a stop guard is not to
37
+ // block, and an unreadable record is not proof a run is holding.
38
+ async function hold_facts(): Promise<Pick<StopContext, 'hold_present' | 'prrun_stopped'>> {
35
39
  const directory = await run_hold.worktree_directory()
40
+ const hold =
41
+ directory === undefined
42
+ ? undefined
43
+ : run_halfrun_resume.hold_of(run_hold.read_hold(run_hold.hold_path(directory)))
36
44
 
37
- if (directory === undefined) return false
38
-
39
- const read = run_hold.read_hold(run_hold.hold_path(directory))
40
-
41
- return read.kind === 'held' || read.kind === 'stale'
45
+ return { hold_present: hold !== undefined, prrun_stopped: hold?.prrun_stop_head !== undefined }
42
46
  }
43
47
 
44
48
  // A `confirmation` notify sits on this run's transcript tail. The tail is derived exactly as the
@@ -67,7 +71,7 @@ async function build_context(
67
71
  const tail = transcript_tail(transcript_path)
68
72
 
69
73
  return {
70
- hold_present: await is_hold_present(),
74
+ ...(await hold_facts()),
71
75
  tree_clean: !(await run_hold.is_tree_dirty()),
72
76
  notified: lane_park.mentions_confirmation_notify(tail),
73
77
  message: payload_tail.message,
@@ -81,6 +85,7 @@ async function build_context(
81
85
  lane_child: lane_child_marker.is_child_of(process.cwd()),
82
86
  background_pending: lane_background.pending_background_ids(tail).length > 0,
83
87
  agent_pending: lane_background.pending_agent_ids(tail).length > 0,
88
+ handed_off: lane_handoff.is_handed_off(process.cwd()),
84
89
  session_lang: session_lang(),
85
90
  }
86
91
  }
@@ -106,22 +111,43 @@ async function outcome_of(raw_payload: string): Promise<StopOutcome> {
106
111
  }
107
112
  }
108
113
 
114
+ // A live carry record is in place — `carried` alone reads as a run. Both report checks below are about
115
+ // a carried run: the strand judge reads this very record and returns on anything but `carried`, and a
116
+ // stall needs a backlog driver, which begins one before its plan. A spent (`expired`) or `unreadable`
117
+ // record a crashed run left behind is no run either, so it does not re-arm the stall's backlog probe
118
+ // on every stop (joshuafolkken/kit#2995).
119
+ // A failed git read — outside a repository, `git rev-parse` exits non-zero — reads as no run, since this
120
+ // gate sits ahead of the checks' own swallowing and must not throw into the stop decision either.
121
+ async function has_run_record(): Promise<boolean> {
122
+ try {
123
+ const directory = await run_carry.repository_directory()
124
+
125
+ if (directory === undefined) return false
126
+
127
+ return run_carry.read_carry(run_carry.carry_path(directory)).kind === 'carried'
128
+ } catch {
129
+ return false
130
+ }
131
+ }
132
+
133
+ // The stall check rides the Stop hook because the stop *is* the loop boundary: a run alive but not
134
+ // advancing ends turns without dispatching (joshuafolkken/kit#2359). The strand check rides the same
135
+ // boundary and is the step before the stall (joshuafolkken/kit#2375): it fires when the driver is gone
136
+ // — the budget handed off, the owner dead, no supervisor watching. Both only report and swallow their
137
+ // own failures, so neither can change the stop decision. An ordinary stop with no run record skips
138
+ // both, so it pays one directory read rather than their reads and a stale stream's backlog probe.
139
+ async function run_report_checks(): Promise<void> {
140
+ if (!(await has_run_record())) return
141
+
142
+ await backlog_stalled_detect.run_stall_check(backlog_ready.DEFAULT_PORTS)
143
+ await run_stranded_detect.run_stranded_check()
144
+ }
145
+
109
146
  // Nothing reaches stdout on an ordinary stop, so what the harness parses stays empty unless the stop
110
147
  // is being held — all three rules block, so a bare `#N` is reported the same way (joshuafolkken/kit#2247).
111
148
  async function write_stop_decision(raw_payload: string): Promise<void> {
112
149
  hook_decision.load_environment_file()
113
-
114
- // The stall check rides the Stop hook because the stop *is* the loop boundary: a run alive but not
115
- // advancing ends turns without dispatching (joshuafolkken/kit#2359). It only reports — leaves a
116
- // marker, sends a notification — and swallows its own failures, so it can never change the decision
117
- // below or hold the stop.
118
- await backlog_stalled_detect.run_stall_check(backlog_ready.DEFAULT_PORTS)
119
-
120
- // The strand check rides the same boundary for the same reason, and is the step before the stall
121
- // (joshuafolkken/kit#2375): the stall detector needs a live driver that could dispatch, and this one
122
- // fires when that driver is gone — the budget handed off, the owner dead, no supervisor watching. It
123
- // too only reports and swallows its own failures, so it never touches the stop decision below.
124
- await run_stranded_detect.run_stranded_check()
150
+ await run_report_checks()
125
151
 
126
152
  const { reason } = await outcome_of(raw_payload)
127
153