@joshuafolkken/kit 1.1050.0 → 1.1094.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 (581) 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 +19 -11
  4. package/.claude/skills/workflow-commands/background-commands.md +4 -3
  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 +1 -1
  8. package/.claude/skills/workflow-commands/backlogrun-steps.md +10 -10
  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 +3 -2
  16. package/.claude/skills/workflow-commands/halfrun.md +16 -19
  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 +1 -1
  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/prerequisite.md +1 -1
  25. package/.claude/skills/workflow-commands/prrun.md +36 -0
  26. package/.claude/skills/workflow-commands/retrospective.md +1 -1
  27. package/.claude/skills/workflow-commands/working-tree-hold.md +22 -2
  28. package/.codex/hooks.json +16 -20
  29. package/.github/actions/setup-pnpm/action.yml +93 -0
  30. package/.github/dependabot.yml +5 -1
  31. package/.github/workflows/ci.yml +26 -128
  32. package/.github/workflows/pr-classification.yml +5 -41
  33. package/.github/workflows/publish.yml +33 -38
  34. package/.github/workflows/sonar-qube.yml +37 -4
  35. package/AGENTS.md +12 -2
  36. package/CLAUDE.md +15 -16
  37. package/GEMINI.md +14 -2
  38. package/README.md +59 -18
  39. package/SECURITY.md +36 -6
  40. package/cspell/index.yaml +2 -1
  41. package/dist/CLAUDE.md +15 -16
  42. package/dist/config-merge/index.js +15 -3
  43. package/dist/hooks/batch-guard.js +4 -4
  44. package/dist/hooks/{chunk-HJIISEAC.js → chunk-3C4YCCEF.js} +5 -13
  45. package/dist/hooks/{chunk-EJDX2TOB.js → chunk-7ZPFAVR7.js} +7 -88
  46. package/dist/hooks/{chunk-WQ4OSBSS.js → chunk-E54KGFEQ.js} +2 -2
  47. package/dist/hooks/{chunk-GQ7KP45M.js → chunk-IL27YTPH.js} +2 -2
  48. package/dist/hooks/{chunk-DMQN45FN.js → chunk-KHWHKJOM.js} +3 -3
  49. package/dist/hooks/{chunk-5BK3K7V4.js → chunk-M2XDCUKD.js} +997 -478
  50. package/dist/hooks/{chunk-7VPDUBRN.js → chunk-NKOG3XAV.js} +150 -153
  51. package/dist/hooks/{chunk-NJQOBE6L.js → chunk-O4LL4HTI.js} +2 -7
  52. package/dist/hooks/{chunk-NAS4C7GP.js → chunk-OIZUHPJI.js} +2 -2
  53. package/dist/hooks/{chunk-RLDX5SOC.js → chunk-UD24EAIL.js} +2084 -1412
  54. package/dist/hooks/codex-hook-adapter.js +10 -11
  55. package/dist/hooks/duplicate-read-guard.js +5 -5
  56. package/dist/hooks/format-edited.js +2 -2
  57. package/dist/hooks/inputs.json +279 -0
  58. package/dist/hooks/investigation-guard.js +5 -5
  59. package/dist/hooks/pretool-guard.js +9 -9
  60. package/dist/hooks/session-lang.js +0 -1
  61. package/dist/hooks/stop-guard.js +178 -324
  62. package/dist/josh.js +162 -119
  63. package/dist/managed-marker/index.js +2 -1
  64. package/dist/version/index.js +34 -58
  65. package/eslint/rules/promise.js +5 -0
  66. package/package.json +9 -4
  67. package/prompts/collaboration-workflow/issue-citation.md +5 -5
  68. package/prompts/collaboration-workflow/operating-rules.md +4 -4
  69. package/prompts/collaboration-workflow/overview.md +13 -1
  70. package/prompts/collaboration-workflow/report-format.md +1 -1
  71. package/prompts/collaboration-workflow/residency.md +3 -3
  72. package/prompts/collaboration-workflow/rule-delivery.md +1 -1
  73. package/prompts/collaboration-workflow/turn-batching.md +3 -3
  74. package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
  75. package/prompts/collaboration-workflow/wip-cap.md +25 -22
  76. package/prompts/collaboration-workflow.md +5 -8
  77. package/prompts/review-rubric.md +1 -1
  78. package/prompts/review.md +3 -3
  79. package/prompts/sonar-hotspot-handling.md +11 -3
  80. package/prompts/testing-guide.md +3 -3
  81. package/scripts/adopt/adopt-toolkits.ts +0 -2
  82. package/scripts/adopt/adopt.ts +0 -2
  83. package/scripts/agent/agent-argv.ts +0 -2
  84. package/scripts/agent/agent-diagnostics.ts +1 -1
  85. package/scripts/agent/agent-role-profile.ts +0 -7
  86. package/scripts/agent/claude-agent-argv.ts +0 -2
  87. package/scripts/agent/codex-agent-argv.ts +1 -1
  88. package/scripts/agent/codex-hooks.ts +92 -0
  89. package/scripts/agent/interactive-ask.ts +1 -1
  90. package/scripts/auto-ok/auto-ok-cli.ts +6 -16
  91. package/scripts/backlog/backlog-budget.ts +0 -2
  92. package/scripts/backlog/backlog-defect-priority.ts +2 -2
  93. package/scripts/backlog/backlog-drive-cli.ts +10 -8
  94. package/scripts/backlog/backlog-drive-named-offer.ts +16 -3
  95. package/scripts/backlog/backlog-drive-named.ts +2 -1
  96. package/scripts/backlog/backlog-drive.ts +76 -16
  97. package/scripts/backlog/backlog-named.ts +0 -3
  98. package/scripts/backlog/backlog-next.ts +9 -15
  99. package/scripts/backlog/backlog-offer-cli.ts +0 -5
  100. package/scripts/backlog/backlog-plan-cli.ts +1 -7
  101. package/scripts/backlog/backlog-plan.ts +1 -1
  102. package/scripts/backlog/backlog-pool.ts +3 -6
  103. package/scripts/backlog/backlog-rank.ts +2 -2
  104. package/scripts/backlog/backlog-ready.ts +19 -3
  105. package/scripts/backlog/backlog-scope.ts +1 -3
  106. package/scripts/backlog/backlog-stalled-detect.ts +2 -2
  107. package/scripts/backlog/backlog-stalled.ts +0 -1
  108. package/scripts/backlog/backlog-waves.ts +5 -2
  109. package/scripts/behavior/behavior-cli.ts +1 -1
  110. package/scripts/build/build-codex-hooks.ts +26 -0
  111. package/scripts/build/build-hooks.ts +85 -9
  112. package/scripts/build/hook-bundle-stamp.ts +111 -0
  113. package/scripts/cases/cases-cli.ts +1 -1
  114. package/scripts/cases/cases-logic.ts +1 -1
  115. package/scripts/ci/composite-actions.ts +30 -0
  116. package/scripts/ci/pr-classification.ts +3 -3
  117. package/scripts/claude/workflow-destination.ts +10 -1
  118. package/scripts/clone/clone-fingerprint.ts +0 -1
  119. package/scripts/clone/clone-scan-cli.ts +1 -1
  120. package/scripts/clone/clone-scan.ts +1 -1
  121. package/scripts/config-merge/json-format.ts +0 -1
  122. package/scripts/config-merge/patch-yaml-list.ts +1 -1
  123. package/scripts/cost-runtime/codex-usage.ts +2 -9
  124. package/scripts/cost-runtime/cost-attribute.ts +0 -1
  125. package/scripts/cost-runtime/cost-cli.ts +0 -3
  126. package/scripts/cost-runtime/cost-corpus.ts +0 -2
  127. package/scripts/cost-runtime/cost-format.ts +0 -3
  128. package/scripts/cost-runtime/cost-pricing.ts +0 -1
  129. package/scripts/cost-runtime/cost-tokens.ts +0 -1
  130. package/scripts/delegation/delegation-cli.ts +1 -1
  131. package/scripts/delegation/delegation-policy.ts +0 -1
  132. package/scripts/delegation/duplicate-read-guard.ts +0 -8
  133. package/scripts/delegation/fanout-cli.ts +1 -1
  134. package/scripts/delegation/fanout.ts +0 -2
  135. package/scripts/delegation/investigation-reads.ts +1 -164
  136. package/scripts/discovery/repo-map-logic.ts +0 -1
  137. package/scripts/discovery/repo-party-cli.ts +1 -1
  138. package/scripts/doctor/doctor-consumer.ts +4 -6
  139. package/scripts/doctor/doctor-logic.ts +0 -4
  140. package/scripts/doctor/doctor.ts +14 -9
  141. package/scripts/document/document-byte-budget.ts +4 -5
  142. package/scripts/document/document-byte-check.ts +0 -1
  143. package/scripts/document/document-read-cli.ts +0 -2
  144. package/scripts/document/document-section-cli.ts +1 -1
  145. package/scripts/document/document-section.ts +0 -3
  146. package/scripts/document/edit-files-cli.ts +0 -1
  147. package/scripts/document/entry-read-budget.ts +10 -2
  148. package/scripts/document/lane-child-read-set.ts +1 -6
  149. package/scripts/document/read-files-cli.ts +0 -4
  150. package/scripts/document/read-set-cli.ts +0 -2
  151. package/scripts/document/read-set-point-of-use.ts +1 -0
  152. package/scripts/document/read-set-pricing.ts +0 -1
  153. package/scripts/document/read-set-trim.ts +1 -1
  154. package/scripts/epic/epic-add.ts +1 -1
  155. package/scripts/epic/epic-audit-cli.ts +1 -4
  156. package/scripts/epic/epic-audit-orphans.ts +1 -3
  157. package/scripts/epic/epic-audit-rationale.ts +0 -1
  158. package/scripts/epic/epic-audit-report.ts +0 -2
  159. package/scripts/epic/epic-audit.ts +5 -4
  160. package/scripts/epic/epic-bundle-cli.ts +1 -1
  161. package/scripts/epic/epic-bundle-evidence.ts +0 -1
  162. package/scripts/epic/epic-bundle-referenced.ts +1 -5
  163. package/scripts/epic/epic-bundle.ts +0 -4
  164. package/scripts/epic/epic-busy.ts +4 -5
  165. package/scripts/epic/epic-candidate-confirm.ts +0 -5
  166. package/scripts/epic/epic-classify.ts +2 -2
  167. package/scripts/epic/epic-cli-argv.ts +0 -1
  168. package/scripts/epic/epic-close-comment.ts +1 -1
  169. package/scripts/epic/epic-close.ts +5 -2
  170. package/scripts/epic/epic-cross-repo.ts +2 -4
  171. package/scripts/epic/epic-decision.ts +0 -1
  172. package/scripts/epic/epic-fetch.ts +2 -2
  173. package/scripts/epic/epic-index.ts +2 -3
  174. package/scripts/epic/epic-issue.ts +1 -15
  175. package/scripts/epic/epic-lane-offer.ts +9 -8
  176. package/scripts/epic/epic-nested.ts +1 -1
  177. package/scripts/epic/epic-next-read.ts +1 -3
  178. package/scripts/epic/epic-next-views.ts +0 -1
  179. package/scripts/epic/epic-next.ts +1 -10
  180. package/scripts/epic/epic-parse.ts +0 -1
  181. package/scripts/epic/epic-promote.ts +0 -9
  182. package/scripts/epic/epic-rank.ts +2 -2
  183. package/scripts/epic/epic-read.ts +1 -2
  184. package/scripts/epic/epic-reconcile.ts +1 -1
  185. package/scripts/epic/epic-reference.ts +1 -13
  186. package/scripts/epic/epic-relation-recheck.ts +1 -1
  187. package/scripts/epic/epic-relations.ts +1 -1
  188. package/scripts/epic/epic-remove.ts +1 -1
  189. package/scripts/epic/epic-report.ts +0 -1
  190. package/scripts/epic/epic-run.ts +2 -3
  191. package/scripts/epic/epic-shape.ts +1 -1
  192. package/scripts/epic/epic-solo-stale.ts +107 -0
  193. package/scripts/epic/epic-solo.ts +3 -2
  194. package/scripts/epic/epic-triage.ts +1 -1
  195. package/scripts/epic/epic-validate.ts +1 -1
  196. package/scripts/epic/epic.ts +1 -1
  197. package/scripts/exports/unused-members-cli.ts +53 -0
  198. package/scripts/{git → followup}/followup-issue-number.ts +1 -6
  199. package/scripts/{git → followup}/git-followup-cleanup.ts +2 -1
  200. package/scripts/{git → followup}/git-followup-finish.ts +1 -3
  201. package/scripts/{git → followup}/git-followup-flush.ts +2 -2
  202. package/scripts/{git → followup}/git-followup-issue-close.ts +2 -2
  203. package/scripts/{git → followup}/git-followup-label.ts +4 -4
  204. package/scripts/followup/git-followup-merged.ts +112 -0
  205. package/scripts/{git → followup}/git-followup-pending.ts +1 -1
  206. package/scripts/{git → followup}/git-followup-workflow.ts +19 -11
  207. package/scripts/{git → followup}/git-pr-followup-wrapup.ts +9 -3
  208. package/scripts/{git → followup}/git-pr-followup.ts +53 -16
  209. package/scripts/gate/core-budget.ts +3 -9
  210. package/scripts/gate/gate-plan.ts +7 -4
  211. package/scripts/gate/gate-report.ts +0 -6
  212. package/scripts/gate/gate-tree.ts +1 -1
  213. package/scripts/gate/pre-commit-type-check.ts +0 -6
  214. package/scripts/gate/project-checks.ts +7 -8
  215. package/scripts/gate/scoped-green.ts +0 -1
  216. package/scripts/gate/type-check-step.ts +1 -1
  217. package/scripts/gate/verification-gate.ts +0 -2
  218. package/scripts/gh/fix-gh-packages.ts +15 -12
  219. package/scripts/gh/gh-spawn.ts +2 -2
  220. package/scripts/{git → gh}/git-ai-review-scan.ts +1 -5
  221. package/scripts/{git → gh}/git-gh-check.ts +2 -1
  222. package/scripts/{git → gh}/git-gh-exec.ts +1 -1
  223. package/scripts/{git → gh}/git-gh-failure.ts +1 -1
  224. package/scripts/{git → gh}/git-gh-helpers.ts +0 -1
  225. package/scripts/{git → gh}/git-gh-issue-list.ts +2 -0
  226. package/scripts/{git → gh}/git-gh-issue-read.ts +1 -1
  227. package/scripts/{git → gh}/git-gh-issue-rest.ts +6 -3
  228. package/scripts/{git → gh}/git-gh-pr-read.ts +24 -0
  229. package/scripts/{git → gh}/git-gh-pr-rest.ts +5 -2
  230. package/scripts/{git → gh}/git-gh-pr-review.ts +2 -2
  231. package/scripts/{git → gh}/git-gh-pr-rollup.ts +1 -3
  232. package/scripts/{git → gh}/git-gh-pr.ts +3 -1
  233. package/scripts/{git → gh}/git-pr-ai-review.ts +2 -5
  234. package/scripts/{git → gh}/git-pr-checks-eval.ts +0 -10
  235. package/scripts/{git → gh}/git-pr-checks-parse.ts +4 -20
  236. package/scripts/{git → gh}/git-pr-checks.ts +2 -1
  237. package/scripts/{git → gh}/git-pr-coderabbit.ts +2 -5
  238. package/scripts/{git → gh}/git-pr-confirmation.ts +1 -3
  239. package/scripts/{git → gh}/git-pr-managed-config.ts +2 -3
  240. package/scripts/{git → gh}/git-pr.ts +3 -3
  241. package/scripts/git/changed-file-scope.ts +0 -1
  242. package/scripts/git/git-branch.ts +3 -6
  243. package/scripts/git/git-commit.ts +1 -1
  244. package/scripts/git/git-common-directory.ts +80 -24
  245. package/scripts/git/git-error.ts +66 -9
  246. package/scripts/git/git-issue.ts +1 -1
  247. package/scripts/git/git-preflight.ts +2 -2
  248. package/scripts/git/git-prompt.ts +6 -31
  249. package/scripts/git/git-push.ts +1 -1
  250. package/scripts/git/git-staging.ts +1 -0
  251. package/scripts/git/git-status.ts +1 -1
  252. package/scripts/git/git-workflow.ts +1 -1
  253. package/scripts/git/gone-branch.ts +1 -0
  254. package/scripts/git/listing-cutoff.ts +1 -1
  255. package/scripts/git/main-merge.ts +1 -1
  256. package/scripts/git/main-sync.ts +19 -1
  257. package/scripts/git/parse-json-array.ts +0 -3
  258. package/scripts/git/repository-lock.ts +16 -16
  259. package/scripts/git/{git-stash.ts → stash/git-stash.ts} +1 -1
  260. package/scripts/git/{stash-pop-args.ts → stash/stash-pop-args.ts} +1 -1
  261. package/scripts/git/{stash-pop-cli.ts → stash/stash-pop-cli.ts} +0 -1
  262. package/scripts/git/{stash-sweep-lock.ts → stash/stash-sweep-lock.ts} +3 -3
  263. package/scripts/hooks/codex-hook-adapter.ts +0 -1
  264. package/scripts/hooks/edited-cspell.ts +1 -1
  265. package/scripts/hooks/format-edited-file.ts +2 -0
  266. package/scripts/hooks/pre-push-unit.ts +0 -4
  267. package/scripts/hooks/pretool-guard.ts +22 -4
  268. package/scripts/hooks/reserved-run.ts +1 -1
  269. package/scripts/hooks/step-zero-notice.ts +76 -0
  270. package/scripts/hooks/stop-guard.ts +47 -21
  271. package/scripts/init/claude-plugin-config.ts +4 -5
  272. package/scripts/init/hook-command-rewrite.ts +16 -8
  273. package/scripts/init/hook-launch.ts +41 -15
  274. package/scripts/init/init-basic.ts +2 -5
  275. package/scripts/init/init-logic.ts +7 -0
  276. package/scripts/init/init.ts +0 -3
  277. package/scripts/init/project-profile.ts +6 -11
  278. package/scripts/init/start-exec.ts +1 -1
  279. package/scripts/init/start-setup-pr.ts +6 -6
  280. package/scripts/init/start-steps.ts +1 -0
  281. package/scripts/issue/behavior-change-lint.ts +0 -1
  282. package/scripts/issue/defect-rate-cli.ts +3 -3
  283. package/scripts/issue/defect-rate.ts +1 -2
  284. package/scripts/{git → issue}/git-next-issues.ts +3 -3
  285. package/scripts/issue/issue-backlinks-cli.ts +1 -5
  286. package/scripts/issue/issue-cite-cli.ts +2 -6
  287. package/scripts/issue/issue-cite.ts +0 -2
  288. package/scripts/issue/issue-classification.ts +1 -9
  289. package/scripts/issue/issue-closing-pr.ts +4 -4
  290. package/scripts/issue/issue-comment-cli.ts +2 -2
  291. package/scripts/issue/issue-file-cli.ts +5 -5
  292. package/scripts/issue/issue-file.ts +2 -2
  293. package/scripts/issue/issue-fold-cli.ts +1 -1
  294. package/scripts/issue/issue-fold-existing-cli.ts +1 -1
  295. package/scripts/{git → issue}/issue-labels.ts +8 -0
  296. package/scripts/issue/issue-lint-cli.ts +1 -1
  297. package/scripts/issue/issue-merged.ts +2 -2
  298. package/scripts/{git → issue}/issue-rank.ts +1 -1
  299. package/scripts/issue/issue-read-cli.ts +8 -47
  300. package/scripts/issue/issue-read.ts +0 -2
  301. package/scripts/issue/issue-report-failures.ts +80 -0
  302. package/scripts/issue/issue-scout-cli.ts +1 -7
  303. package/scripts/issue/issue-scout-closed.ts +2 -2
  304. package/scripts/issue/issue-scout.ts +0 -2
  305. package/scripts/issue/issue-state-cli.ts +5 -46
  306. package/scripts/issue/issue-state.ts +1 -5
  307. package/scripts/issue/markdown-section.ts +1 -1
  308. package/scripts/issue/measure-rerun-cli.ts +1 -1
  309. package/scripts/issue/reproduction-measure.ts +1 -1
  310. package/scripts/josh/cli-body.ts +1 -1
  311. package/scripts/josh/file-map-stamp.ts +0 -3
  312. package/scripts/josh/josh-command-map.ts +2 -0
  313. package/scripts/josh/josh-commands-ai.ts +9 -102
  314. package/scripts/josh/josh-commands-backlog.ts +5 -1
  315. package/scripts/josh/josh-commands-development.ts +8 -1
  316. package/scripts/josh/josh-commands-issue.ts +2 -2
  317. package/scripts/josh/josh-commands-maintenance.ts +7 -0
  318. package/scripts/josh/josh-commands-project.ts +6 -0
  319. package/scripts/josh/josh-commands-run.ts +114 -0
  320. package/scripts/josh/josh-commands-versioning.ts +8 -0
  321. package/scripts/josh/josh-commands-workflow.ts +2 -2
  322. package/scripts/josh/path-decision.ts +0 -3
  323. package/scripts/josh/process-owner.ts +16 -0
  324. package/scripts/josh/session-language-cli.ts +0 -1
  325. package/scripts/lane/lane-await.ts +3 -6
  326. package/scripts/lane/lane-capacity.ts +6 -3
  327. package/scripts/lane/lane-child-invocation.ts +20 -7
  328. package/scripts/lane/lane-cli.ts +1 -4
  329. package/scripts/lane/lane-close.ts +1 -3
  330. package/scripts/lane/lane-dispatch.ts +3 -4
  331. package/scripts/lane/lane-environment.ts +0 -9
  332. package/scripts/lane/lane-handoff.ts +38 -0
  333. package/scripts/lane/lane-launch-cli.ts +21 -11
  334. package/scripts/lane/lane-open.ts +0 -3
  335. package/scripts/lane/lane-output.ts +0 -1
  336. package/scripts/lane/lane-registry.ts +9 -0
  337. package/scripts/lane/openai-lane-ship.ts +2 -0
  338. package/scripts/lane/openai-lane-supervisor-decision.ts +2 -1
  339. package/scripts/lane/openai-lane-supervisor.ts +6 -4
  340. package/scripts/lane/openai-review-broker.ts +3 -0
  341. package/scripts/lib/bounded-pool.ts +1 -0
  342. package/scripts/lib/json-value.ts +5 -4
  343. package/scripts/lib/poll.ts +3 -1
  344. package/scripts/lib/timed-fetch.ts +15 -0
  345. package/scripts/lib/timeouts.ts +13 -0
  346. package/scripts/{yaml → lib}/yaml-document.ts +3 -1
  347. package/scripts/{bytes → lines}/bytes-command.ts +0 -2
  348. package/scripts/lines/lines-command.ts +0 -1
  349. package/scripts/lint/lint-related-scope.ts +0 -1
  350. package/scripts/lint/lint-related.ts +1 -1
  351. package/scripts/{git → notify}/telegram-notify.ts +2 -2
  352. package/scripts/{git → notify}/telegram-test.ts +4 -4
  353. package/scripts/observations/observation-ledger-home.ts +0 -1
  354. package/scripts/observations/observation-ledger-line.ts +0 -1
  355. package/scripts/observations/observation-ledger-migrate.ts +1 -1
  356. package/scripts/observations/observations-flush-landing.ts +3 -3
  357. package/scripts/observations/observations-flush.ts +2 -2
  358. package/scripts/overrides/lockfile-overrides.ts +1 -1
  359. package/scripts/overrides/overrides-logic.ts +1 -1
  360. package/scripts/package/package-scout-cli.ts +2 -7
  361. package/scripts/package/package-scout.ts +0 -2
  362. package/scripts/propagate/propagate-git-failure.ts +0 -1
  363. package/scripts/propagate/propagate-git.ts +0 -2
  364. package/scripts/propagate/propagate-publish.ts +2 -3
  365. package/scripts/propagate/propagate-run.ts +0 -2
  366. package/scripts/propagate/propagate-steps.ts +3 -5
  367. package/scripts/propagate/propagate-targets.ts +0 -4
  368. package/scripts/propagate/propagate.ts +0 -4
  369. package/scripts/refactor/import-graph.ts +0 -1
  370. package/scripts/refactor/refactor-lint.ts +0 -2
  371. package/scripts/refactor/refactor-scan.ts +0 -1
  372. package/scripts/refactor/refactor-targets.ts +0 -1
  373. package/scripts/registry-migration/migrate-logic.ts +0 -2
  374. package/scripts/registry-migration/migrate.ts +19 -9
  375. package/scripts/release/github-release-cli.ts +8 -6
  376. package/scripts/release/github-release-environment.ts +46 -0
  377. package/scripts/release/github-release.ts +151 -94
  378. package/scripts/release/release-history.ts +0 -1
  379. package/scripts/release/release-plan.ts +0 -1
  380. package/scripts/release/release-publish.ts +2 -3
  381. package/scripts/release/release-scope-cli.ts +1 -2
  382. package/scripts/release/release-tag.ts +2 -4
  383. package/scripts/repo/auto-merge-setting-logic.ts +1 -4
  384. package/scripts/repo/repo-setting.ts +1 -1
  385. package/scripts/repo/repository-labels.ts +3 -3
  386. package/scripts/repo/required-checks-logic.ts +206 -0
  387. package/scripts/repo/required-checks-report.ts +71 -0
  388. package/scripts/repo/ruleset-check-cli.ts +53 -0
  389. package/scripts/repo/ruleset-check.ts +147 -0
  390. package/scripts/report/report-lint-cli.ts +0 -4
  391. package/scripts/review/disposition-cli.ts +1 -1
  392. package/scripts/review/live-evidence.ts +1 -1
  393. package/scripts/review/review-attest-cli.ts +0 -6
  394. package/scripts/review/review-attest.ts +4 -16
  395. package/scripts/review/review-brief-cli.ts +23 -6
  396. package/scripts/review/review-brief.ts +21 -8
  397. package/scripts/review/review-diff-parts.ts +89 -0
  398. package/scripts/review/review-diff-write.ts +97 -0
  399. package/scripts/review/review-finding-ledger.ts +0 -1
  400. package/scripts/review/review-record-cli.ts +1 -1
  401. package/scripts/review/review-record.ts +0 -1
  402. package/scripts/review/review-round2-cli.ts +1 -1
  403. package/scripts/review/review-stamps.ts +0 -3
  404. package/scripts/review/review-tree.ts +14 -2
  405. package/scripts/rules/decision-oracle-stage.ts +18 -0
  406. package/scripts/rules/decision-oracle.ts +10 -7
  407. package/scripts/rules/delivered-rules.ts +9 -1
  408. package/scripts/rules/destructive-command.ts +119 -0
  409. package/scripts/rules/direct-filing.ts +1 -1
  410. package/scripts/rules/file-body.ts +0 -3
  411. package/scripts/rules/filing-cap.ts +0 -2
  412. package/scripts/rules/gh-api.ts +7 -2
  413. package/scripts/rules/git-argv.ts +18 -7
  414. package/scripts/rules/git-force.ts +0 -2
  415. package/scripts/rules/implementation-cut.ts +0 -1
  416. package/scripts/rules/index-guard.ts +71 -0
  417. package/scripts/rules/issue-citation.ts +50 -25
  418. package/scripts/rules/lane-background.ts +15 -7
  419. package/scripts/rules/lane-park.ts +13 -6
  420. package/scripts/rules/last-prompt.ts +1 -0
  421. package/scripts/rules/oracle-consulted.ts +1 -1
  422. package/scripts/rules/oracle-firing.ts +1 -0
  423. package/scripts/rules/oracle-list-cli.ts +0 -3
  424. package/scripts/rules/permission-guards.ts +14 -0
  425. package/scripts/rules/protected-files.ts +74 -0
  426. package/scripts/rules/reply-language.ts +1 -1
  427. package/scripts/rules/rule-body-guard.ts +0 -3
  428. package/scripts/rules/rule-value-cli.ts +0 -1
  429. package/scripts/rules/shell-body-trigger.ts +0 -1
  430. package/scripts/rules/shell-segments.ts +0 -1
  431. package/scripts/rules/stop-rules.ts +13 -5
  432. package/scripts/rules/tail-commands.ts +1 -1
  433. package/scripts/rules/test-declared-commit.ts +1 -1
  434. package/scripts/rules/third-party-write.ts +0 -1
  435. package/scripts/rules/worktree-guard.ts +26 -9
  436. package/scripts/run/run-carry-cli.ts +0 -2
  437. package/scripts/run/run-carry-stash.ts +2 -2
  438. package/scripts/run/run-carry-streak.ts +1 -1
  439. package/scripts/run/run-cut-cli.ts +0 -7
  440. package/scripts/run/run-cut.ts +8 -54
  441. package/scripts/run/run-ending-cli.ts +1 -1
  442. package/scripts/run/run-ending.ts +1 -4
  443. package/scripts/run/run-entry-cli.ts +101 -24
  444. package/scripts/run/run-entry.ts +0 -1
  445. package/scripts/run/run-event-cli.ts +0 -2
  446. package/scripts/run/run-event-follow.ts +1 -0
  447. package/scripts/run/run-event-render.ts +1 -1
  448. package/scripts/run/run-event-scope.ts +53 -4
  449. package/scripts/run/run-event-stream.ts +0 -3
  450. package/scripts/run/run-event-watch.ts +1 -0
  451. package/scripts/run/run-halfrun-resume.ts +20 -7
  452. package/scripts/run/run-headless.ts +2 -2
  453. package/scripts/run/run-hold-cli.ts +33 -10
  454. package/scripts/run/run-hold.ts +25 -5
  455. package/scripts/run/run-issue-number.ts +1 -1
  456. package/scripts/run/run-liveness-cli.ts +1 -1
  457. package/scripts/run/run-liveness.ts +2 -3
  458. package/scripts/run/run-merge-cli.ts +5 -13
  459. package/scripts/run/run-merge-steps.ts +5 -5
  460. package/scripts/run/run-merge.ts +1 -1
  461. package/scripts/run/run-next-cli.ts +1 -1
  462. package/scripts/run/run-parent-cut-hook.ts +0 -1
  463. package/scripts/run/run-preflight.ts +2 -9
  464. package/scripts/run/run-prep-cli.ts +2 -2
  465. package/scripts/run/run-prep-locate.ts +1 -1
  466. package/scripts/run/run-progress-cli.ts +4 -7
  467. package/scripts/run/run-progress-clock.ts +6 -34
  468. package/scripts/run/run-progress-config.ts +0 -4
  469. package/scripts/run/run-progress-read.ts +1 -2
  470. package/scripts/run/run-progress.ts +1 -2
  471. package/scripts/run/run-prrun-resume.ts +117 -0
  472. package/scripts/run/run-report-cli.ts +1 -2
  473. package/scripts/run/run-report.ts +0 -1
  474. package/scripts/run/run-retrospective.ts +1 -1
  475. package/scripts/run/run-review-cli.ts +0 -3
  476. package/scripts/run/run-review-steps.ts +2 -0
  477. package/scripts/run/run-review.ts +0 -2
  478. package/scripts/run/run-ship-cli.ts +21 -3
  479. package/scripts/run/run-ship-detach.ts +1 -0
  480. package/scripts/run/run-ship-next.ts +106 -0
  481. package/scripts/run/run-ship-preflight.ts +1 -1
  482. package/scripts/run/run-ship-return.ts +8 -3
  483. package/scripts/run/run-ship-review-steps.ts +18 -4
  484. package/scripts/run/run-ship-review.ts +11 -0
  485. package/scripts/run/run-ship-scoped.ts +1 -0
  486. package/scripts/run/run-ship-steps.ts +1 -1
  487. package/scripts/run/run-ship.ts +0 -1
  488. package/scripts/run/run-stage-read.ts +62 -0
  489. package/scripts/run/run-stage.ts +160 -0
  490. package/scripts/run/run-status-cli.ts +1 -1
  491. package/scripts/run/run-step-cli.ts +21 -14
  492. package/scripts/run/run-step.ts +1 -1
  493. package/scripts/run/run-stop-notify.ts +1 -3
  494. package/scripts/run/run-stranded-cli.ts +0 -4
  495. package/scripts/run/run-stranded-detect.ts +2 -2
  496. package/scripts/run/run-tail-cli.ts +17 -11
  497. package/scripts/run/run-tail.ts +2 -0
  498. package/scripts/run/run-tidy-lanes.ts +2 -1
  499. package/scripts/run/run-tidy-stashes.ts +12 -12
  500. package/scripts/run/run-wake-cli.ts +2 -3
  501. package/scripts/run/run-wake-loop.ts +2 -2
  502. package/scripts/run/run-wake.ts +2 -4
  503. package/scripts/run/run-watcher-guard-cli.ts +0 -4
  504. package/scripts/run/run-watcher-guard.ts +9 -7
  505. package/scripts/run/run-watcher-hook.ts +1 -1
  506. package/scripts/safe-chain/ci-installer-pin.ts +11 -5
  507. package/scripts/safe-chain/project-config.ts +1 -1
  508. package/scripts/security/security-audit-provision-logic.ts +0 -1
  509. package/scripts/security/security-audit-provision.ts +3 -2
  510. package/scripts/security/security-audit.ts +0 -1
  511. package/scripts/security/security-updates-logic.ts +0 -1
  512. package/scripts/sonar/sonar-hotspots-cli.ts +10 -52
  513. package/scripts/sonar/sonar-hotspots.ts +0 -1
  514. package/scripts/sonar/sonar-new-code-cli.ts +150 -0
  515. package/scripts/sonar/sonar-new-code.ts +79 -0
  516. package/scripts/sonar/sonar-project.ts +97 -0
  517. package/scripts/split/split-assess-cli.ts +1 -1
  518. package/scripts/split/split-assess.ts +2 -5
  519. package/scripts/sync/managed-config-scope-cli.ts +1 -1
  520. package/scripts/sync/skill-migration.ts +0 -1
  521. package/scripts/sync/sync-hook-safety.ts +2 -3
  522. package/scripts/sync/sync.ts +1 -8
  523. package/scripts/sync/template-source-logic.ts +0 -1
  524. package/scripts/sync/workflow-pin-logic.ts +16 -28
  525. package/scripts/test/test-declared-logic.ts +0 -1
  526. package/scripts/test/test-declared.ts +0 -2
  527. package/scripts/test/test-red-commit.ts +2 -2
  528. package/scripts/test/test-red.ts +14 -7
  529. package/scripts/test/test-type-logic.ts +1 -1
  530. package/scripts/test/unit-worker-share.ts +7 -16
  531. package/scripts/time-runtime/time-batch-guard.ts +1 -2
  532. package/scripts/time-runtime/time-bundle-call.ts +0 -1
  533. package/scripts/time-runtime/time-bundles.ts +0 -4
  534. package/scripts/time-runtime/time-density-hook.ts +0 -2
  535. package/scripts/time-runtime/time-followup-stage.ts +1 -1
  536. package/scripts/time-runtime/time-format.ts +0 -73
  537. package/scripts/time-runtime/time-round-trips.ts +0 -4
  538. package/scripts/time-runtime/time-single-check.ts +1 -1
  539. package/scripts/time-runtime/time-spans.ts +1 -1
  540. package/scripts/time-runtime/time-transcript-line.ts +1 -2
  541. package/scripts/ui/ui-routes-cli.ts +0 -5
  542. package/scripts/ui/ui-routes.ts +0 -5
  543. package/scripts/version/effective-upstream.ts +2 -2
  544. package/scripts/version/latest-corepack.ts +7 -9
  545. package/scripts/version/latest-scope-cli.ts +0 -2
  546. package/scripts/version/latest-update.ts +0 -2
  547. package/scripts/version/npm-registry.ts +2 -2
  548. package/scripts/version/publishable-range-check.ts +1 -1
  549. package/scripts/version/release-hold.ts +0 -4
  550. package/scripts/version/running-binary.ts +2 -2
  551. package/scripts/version/version-check-logic.ts +0 -2
  552. package/scripts/version/version-remote.ts +3 -3
  553. package/scripts/version/version-targets.ts +4 -4
  554. package/templates/sonar-project.properties +28 -1
  555. package/templates/workflows/dependabot-auto-merge.yml +5 -3
  556. package/templates/workflows/github-release.yml +81 -0
  557. package/prompts/collaboration-workflow/cross-repo-epic.md +0 -5
  558. package/prompts/collaboration-workflow/epic-audit.md +0 -5
  559. package/prompts/collaboration-workflow/epic-bundle.md +0 -5
  560. package/scripts/init/plugin-install-hint.ts +0 -47
  561. package/scripts/version/parse-json.ts +0 -13
  562. /package/scripts/{git → followup}/git-followup-stages.ts +0 -0
  563. /package/scripts/{git → gh}/git-gh-api-path.ts +0 -0
  564. /package/scripts/{git → gh}/git-gh-command.ts +0 -0
  565. /package/scripts/{git → gh}/git-gh-issue-write.ts +0 -0
  566. /package/scripts/{git → gh}/git-gh-issue.ts +0 -0
  567. /package/scripts/{git → gh}/git-gh-pr-auto-merge.ts +0 -0
  568. /package/scripts/{git → gh}/git-gh-pr-snapshot.ts +0 -0
  569. /package/scripts/{git → gh}/git-gh-reachability.ts +0 -0
  570. /package/scripts/{git → gh}/git-gh-repo.ts +0 -0
  571. /package/scripts/{git → gh}/git-gh-rest-state.ts +0 -0
  572. /package/scripts/{git → gh}/git-pr-checks-watch.ts +0 -0
  573. /package/scripts/{git → gh}/git-pr-error.ts +0 -0
  574. /package/scripts/{git → gh}/git-pr-messages.ts +0 -0
  575. /package/scripts/{git → gh}/github-issue-url.ts +0 -0
  576. /package/scripts/git/{stash-orphans.ts → stash/stash-orphans.ts} +0 -0
  577. /package/scripts/{git → issue}/issue-reference.ts +0 -0
  578. /package/scripts/{git → lib}/animation-helpers.ts +0 -0
  579. /package/scripts/{git → lib}/git-animation.ts +0 -0
  580. /package/scripts/{git → notify}/git-notify.ts +0 -0
  581. /package/scripts/{git → notify}/telegram-test-logic.ts +0 -0
@@ -17,6 +17,7 @@ import {
17
17
  filing_cap,
18
18
  gh_failure,
19
19
  git_command,
20
+ git_common_directory,
20
21
  git_gh_api_path,
21
22
  git_gh_exec,
22
23
  has_any_label,
@@ -34,36 +35,34 @@ import {
34
35
  run_cut,
35
36
  run_headless,
36
37
  run_hold,
37
- run_progress_clock,
38
38
  run_tail,
39
- run_watcher_guard,
40
39
  shell_segments,
41
40
  tail_commands
42
- } from "./chunk-RLDX5SOC.js";
41
+ } from "./chunk-UD24EAIL.js";
43
42
  import {
44
43
  find_local_bin_upwards
45
44
  } from "./chunk-3V37IID6.js";
46
45
  import {
47
46
  batch_outcome
48
- } from "./chunk-GQ7KP45M.js";
47
+ } from "./chunk-IL27YTPH.js";
49
48
  import {
50
49
  investigation_refusal
51
- } from "./chunk-DMQN45FN.js";
50
+ } from "./chunk-KHWHKJOM.js";
52
51
  import {
53
52
  duplicate_read_outcome
54
- } from "./chunk-HJIISEAC.js";
53
+ } from "./chunk-3C4YCCEF.js";
55
54
  import {
56
55
  investigation_reads
57
- } from "./chunk-EJDX2TOB.js";
56
+ } from "./chunk-7ZPFAVR7.js";
58
57
  import {
59
58
  lane_guard_policy,
60
59
  time_batch_guard
61
- } from "./chunk-NJQOBE6L.js";
60
+ } from "./chunk-O4LL4HTI.js";
62
61
  import {
63
62
  hook_decision,
64
63
  lane_child_marker,
65
64
  run_issue_number
66
- } from "./chunk-WQ4OSBSS.js";
65
+ } from "./chunk-E54KGFEQ.js";
67
66
  import {
68
67
  PLATFORM_TEMP_ROOT,
69
68
  cost_attribute,
@@ -75,10 +74,10 @@ import {
75
74
  lane_paths,
76
75
  stamp_file,
77
76
  time_shell
78
- } from "./chunk-7VPDUBRN.js";
77
+ } from "./chunk-NKOG3XAV.js";
79
78
 
80
79
  // scripts/rules/direct-filing.ts
81
- var DIRECT_FILING_REASON = '\u26D4 direct filing: an Issue is filed with `pnpm josh issue:file "<title>" --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>]`, never with `gh api \u2026/issues` or `gh issue create`. The command runs every filing step in order \u2014 the duplicate scout, the body lint and its classification labels, the depth and `route:` labels, the `## Origin` check when filing into another repository, and `epic:bundle` after the create \u2014 so none of them is a step to remember. When the scout prints candidates it holds the filing: read each, then reissue with `--distinct <N,\u2026>` for the ones that are separate deliverables. Reference: `docs/josh-commands.md` \u2192 "`josh issue:file`". **This rule fires on every occurrence, not once per run.**';
80
+ var DIRECT_FILING_REASON = '\u26D4 direct filing: an Issue is filed with `pnpm josh issue:file "<title>" --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>]`, never with `gh api \u2026/issues` or `gh issue create`. The command runs every filing step in order \u2014 the duplicate scout, the body lint and its classification labels, the depth and `route:` labels, the `## Origin` check when filing into another repository, and `epic:bundle` after the create \u2014 so none of them is a step to remember. When the scout prints candidates it holds the filing: read each, then reissue with `--distinct <N,\u2026>` for the ones that are separate deliverables. Reference: `docs/josh-commands-automation.md` \u2192 "`josh issue:file`". **This rule fires on every occurrence, not once per run.**';
82
81
  function is_any_filing(command) {
83
82
  return bash_triggers.is_direct_filing(command) || bash_triggers.is_issue_filing(command);
84
83
  }
@@ -204,7 +203,6 @@ var run_progress = {
204
203
  format_line,
205
204
  format_next_line,
206
205
  format_next_report,
207
- format_record,
208
206
  format_report,
209
207
  is_due,
210
208
  minutes_from,
@@ -212,16 +210,139 @@ var run_progress = {
212
210
  observation_key
213
211
  };
214
212
 
213
+ // scripts/run/run-progress-clock.ts
214
+ import { z } from "zod";
215
+ var PROGRESS_PREFIX = "josh-run-progress-";
216
+ var LIFE_PREFIX = "josh-run-progress-life-";
217
+ var LOG_SUFFIX = ".log";
218
+ var LOG_KEEP = 12;
219
+ var MS_PER_MINUTE2 = 6e4;
220
+ var LOG_STALE_MINUTES = 90;
221
+ var LOG_STALE_MS = LOG_STALE_MINUTES * MS_PER_MINUTE2;
222
+ var BLOCK_SEPARATOR = "\n\n";
223
+ var report_stamp_schema = z.object({ reported_at: z.string(), line: z.string().optional() });
224
+ function parse_stamp(raw) {
225
+ const parsed = report_stamp_schema.safeParse(JSON.parse(raw));
226
+ if (!parsed.success) return void 0;
227
+ const reported_at = Date.parse(parsed.data.reported_at);
228
+ return Number.isNaN(reported_at) ? void 0 : reported_at;
229
+ }
230
+ function read_last_line(target) {
231
+ const raw = stamp_file.read_stamp_text(target);
232
+ if (raw === void 0) return void 0;
233
+ try {
234
+ return report_stamp_schema.safeParse(JSON.parse(raw)).data?.line;
235
+ } catch {
236
+ return void 0;
237
+ }
238
+ }
239
+ function read_last_report(target) {
240
+ const raw = stamp_file.read_stamp_text(target);
241
+ if (raw === void 0) return void 0;
242
+ try {
243
+ return parse_stamp(raw);
244
+ } catch {
245
+ return void 0;
246
+ }
247
+ }
248
+ function log_path_of(target) {
249
+ return `${target}${LOG_SUFFIX}`;
250
+ }
251
+ function is_log_stale(target, now_ms) {
252
+ const previous_ms = read_last_report(target);
253
+ return previous_ms === void 0 || now_ms - previous_ms > LOG_STALE_MS;
254
+ }
255
+ function recent_blocks(log_target2, is_fresh) {
256
+ if (is_fresh) return [];
257
+ const raw = stamp_file.read_stamp_text(log_target2);
258
+ if (raw === void 0) return [];
259
+ return raw.split(BLOCK_SEPARATOR).map((block) => block.trimEnd()).filter((block) => block.length > 0);
260
+ }
261
+ function append_line(log_target2, reported_at, line, is_fresh) {
262
+ const block = `${reported_at}
263
+ ${line}`;
264
+ const blocks = [...recent_blocks(log_target2, is_fresh), block].slice(-LOG_KEEP);
265
+ stamp_file.write_text_stamp(log_target2, `${blocks.join(BLOCK_SEPARATOR)}
266
+ `);
267
+ }
268
+ function mark(target, now_ms, line) {
269
+ const reported_at = new Date(now_ms).toISOString();
270
+ const kept = line ?? read_last_line(target);
271
+ if (line !== void 0) {
272
+ append_line(log_path_of(target), reported_at, line, is_log_stale(target, now_ms));
273
+ }
274
+ stamp_file.write_stamp(target, kept === void 0 ? { reported_at } : { reported_at, line: kept });
275
+ }
276
+ function stamp_target_of(git_directory) {
277
+ return stamp_file.stamp_path(PROGRESS_PREFIX, git_directory);
278
+ }
279
+ function life_target_of(git_directory) {
280
+ return stamp_file.stamp_path(LIFE_PREFIX, git_directory);
281
+ }
282
+ var life_schema = z.object({ alive: z.literal(true), pinged_at: z.string().optional() });
283
+ function begin_life(target) {
284
+ stamp_file.write_stamp(target, { alive: true, pinged_at: (/* @__PURE__ */ new Date()).toISOString() });
285
+ }
286
+ function ping_life(target) {
287
+ begin_life(target);
288
+ }
289
+ function parse_pinged_at(raw) {
290
+ const parsed = life_schema.safeParse(JSON.parse(raw));
291
+ if (!parsed.success || parsed.data.pinged_at === void 0) return void 0;
292
+ const pinged_ms = Date.parse(parsed.data.pinged_at);
293
+ return Number.isNaN(pinged_ms) ? void 0 : pinged_ms;
294
+ }
295
+ function is_life_fresh(target, threshold_ms) {
296
+ const raw = stamp_file.read_stamp_text(target);
297
+ if (raw === void 0) return false;
298
+ try {
299
+ const pinged_ms = parse_pinged_at(raw);
300
+ return pinged_ms !== void 0 && Date.now() - pinged_ms < threshold_ms;
301
+ } catch {
302
+ return false;
303
+ }
304
+ }
305
+ function is_life_ended(target) {
306
+ return stamp_file.read_stamp_text(target) === void 0;
307
+ }
308
+ function end_life(target) {
309
+ stamp_file.remove_stamp(target);
310
+ }
311
+ function stamp_target_sync() {
312
+ const directory = git_common_directory.own();
313
+ return directory === void 0 ? void 0 : stamp_target_of(directory);
314
+ }
315
+ function read_last_report_sync() {
316
+ const target = stamp_target_sync();
317
+ return target === void 0 ? void 0 : read_last_report(target);
318
+ }
319
+ var run_progress_clock = {
320
+ LIFE_PREFIX,
321
+ LOG_KEEP,
322
+ LOG_STALE_MS,
323
+ begin_life,
324
+ end_life,
325
+ is_life_ended,
326
+ is_life_fresh,
327
+ life_target_of,
328
+ log_path_of,
329
+ mark,
330
+ parse_stamp,
331
+ ping_life,
332
+ read_last_line,
333
+ read_last_report,
334
+ read_last_report_sync,
335
+ stamp_target_of
336
+ };
337
+
215
338
  // scripts/run/run-progress-config.ts
216
339
  import { readFileSync } from "node:fs";
217
340
  import path from "node:path";
218
- import { z } from "zod";
341
+ import { z as z2 } from "zod";
219
342
  var PACKAGE_FILE = "package.json";
220
- var CONFIG_FIELD = "josh";
221
- var INTERVAL_FIELD = "progress_interval_minutes";
222
343
  var MAX_DEPTH = 10;
223
- var package_schema = z.object({
224
- josh: z.object({ progress_interval_minutes: z.number().positive() }).optional()
344
+ var package_schema = z2.object({
345
+ josh: z2.object({ progress_interval_minutes: z2.number().positive() }).optional()
225
346
  });
226
347
  function ancestors_of(start) {
227
348
  const directories = [];
@@ -258,8 +379,6 @@ function configured_interval_ms(directory = process.cwd()) {
258
379
  return resolve_interval_ms(void 0, directory);
259
380
  }
260
381
  var run_progress_config = {
261
- CONFIG_FIELD,
262
- INTERVAL_FIELD,
263
382
  PACKAGE_FILE,
264
383
  configured_interval_ms,
265
384
  read_package_minutes,
@@ -406,10 +525,7 @@ var ROW2 = {
406
525
  var file_body = {
407
526
  FILE_BODY_REASON,
408
527
  ROW: ROW2,
409
- carries_a_file_body,
410
- is_in_place_perl,
411
- is_interpreter_write,
412
- writes_existing_file
528
+ carries_a_file_body
413
529
  };
414
530
 
415
531
  // scripts/rules/gh-api.ts
@@ -424,8 +540,11 @@ var REPO_GROUP = 2;
424
540
  function is_gh_api(segment) {
425
541
  return GH_API_COMMAND.test(segment);
426
542
  }
543
+ function method_of(segment) {
544
+ return API_METHOD.exec(segment)?.[1]?.toUpperCase();
545
+ }
427
546
  function is_read(segment) {
428
- const method = API_METHOD.exec(segment)?.[1];
547
+ const method = method_of(segment);
429
548
  if (method !== void 0) return method.toUpperCase() === READ_METHOD;
430
549
  return !API_FIELD.test(segment);
431
550
  }
@@ -437,7 +556,7 @@ function repo_target(segment) {
437
556
  if (match === null) return void 0;
438
557
  return { owner: match[OWNER_GROUP] ?? "", repo: match[REPO_GROUP] ?? "" };
439
558
  }
440
- var gh_api = { GH_API_COMMAND, GH_FLAGS, is_gh_api, is_read, is_write, repo_target };
559
+ var gh_api = { GH_FLAGS, is_gh_api, is_read, is_write, method_of, repo_target };
441
560
 
442
561
  // scripts/rules/git-argv.ts
443
562
  var ENV_ASSIGNMENT = /^[A-Za-z_]\w*=/u;
@@ -447,7 +566,8 @@ var WRAPPER_WORDS = /* @__PURE__ */ new Set([
447
566
  "exec",
448
567
  "run",
449
568
  "sudo",
450
- "command"
569
+ "command",
570
+ "env"
451
571
  ]);
452
572
  var SUBSHELL_OPEN = "(";
453
573
  var VALUE_TAKING_GLOBALS = /* @__PURE__ */ new Set([
@@ -487,11 +607,15 @@ function after_globals(words, start) {
487
607
  }
488
608
  return index;
489
609
  }
490
- function parse(segment) {
610
+ function arguments_of(segment, command) {
491
611
  const words = words_of(segment);
492
- const git_index = after_wrapper(words);
493
- if (words[git_index] !== GIT_COMMAND) return void 0;
494
- const subcommand_index = after_globals(words, git_index + NEXT);
612
+ const command_index = after_wrapper(words);
613
+ return words[command_index] === command ? words.slice(command_index + NEXT) : void 0;
614
+ }
615
+ function parse(segment) {
616
+ const words = arguments_of(segment, GIT_COMMAND);
617
+ if (words === void 0) return void 0;
618
+ const subcommand_index = after_globals(words, 0);
495
619
  return { subcommand: words[subcommand_index], args: words.slice(subcommand_index + NEXT) };
496
620
  }
497
621
  var SHORT_CLUSTER = /^-[A-Za-z]+$/u;
@@ -503,7 +627,7 @@ function short_cluster_has(token, letters) {
503
627
  }
504
628
  return false;
505
629
  }
506
- var git_argv = { parse, short_cluster_has, words_of };
630
+ var git_argv = { arguments_of, parse, short_cluster_has };
507
631
 
508
632
  // scripts/rules/git-force.ts
509
633
  var FORCE_LONG_PREFIX = "--force";
@@ -542,9 +666,7 @@ var ROW3 = {
542
666
  var git_force = {
543
667
  GIT_FORCE_REASON,
544
668
  ROW: ROW3,
545
- is_branch_delete,
546
- is_force_or_delete,
547
- is_force_or_delete_push
669
+ is_force_or_delete
548
670
  };
549
671
 
550
672
  // scripts/cost-runtime/cost-cli.ts
@@ -554,30 +676,23 @@ import { parseArgs } from "node:util";
554
676
  // scripts/cost-runtime/codex-usage.ts
555
677
  import { globSync, readFileSync as readFileSync2 } from "node:fs";
556
678
  import path2 from "node:path";
557
- import { z as z2 } from "zod";
679
+ import { z as z3 } from "zod";
558
680
  var THREAD_ID_PATTERN = /^[A-Za-z0-9-]+$/u;
559
- var SESSION_META_SCHEMA = z2.looseObject({
560
- type: z2.literal("session_meta"),
561
- payload: z2.looseObject({ id: z2.string(), cwd: z2.string() })
681
+ var SESSION_META_SCHEMA = z3.looseObject({
682
+ type: z3.literal("session_meta"),
683
+ payload: z3.looseObject({ id: z3.string(), cwd: z3.string() })
562
684
  });
563
- var TOTAL_USAGE_SCHEMA = z2.looseObject({ input_tokens: z2.number().nonnegative() });
564
- var TOKEN_COUNT_SCHEMA = z2.looseObject({
565
- type: z2.literal("event_msg"),
566
- payload: z2.looseObject({
567
- type: z2.literal("token_count"),
568
- info: z2.looseObject({
685
+ var TOTAL_USAGE_SCHEMA = z3.looseObject({ input_tokens: z3.number().nonnegative() });
686
+ var TOKEN_COUNT_SCHEMA = z3.looseObject({
687
+ type: z3.literal("event_msg"),
688
+ payload: z3.looseObject({
689
+ type: z3.literal("token_count"),
690
+ info: z3.looseObject({
569
691
  total_token_usage: TOTAL_USAGE_SCHEMA,
570
692
  last_token_usage: TOTAL_USAGE_SCHEMA
571
693
  })
572
694
  })
573
695
  });
574
- function decode(line) {
575
- try {
576
- return JSON.parse(line);
577
- } catch {
578
- return void 0;
579
- }
580
- }
581
696
  function same_project(cwd, target) {
582
697
  return cost_transcript.session_cwd(cwd) === cost_transcript.session_cwd(target);
583
698
  }
@@ -585,7 +700,7 @@ function billed_per_request(usages) {
585
700
  return usages.map((usage) => usage.last_token_usage.input_tokens);
586
701
  }
587
702
  function measurement_from(content, target, thread_id) {
588
- const values = content.split("\n").map((line) => decode(line));
703
+ const values = content.split("\n").map((line) => json_value.parse_or_undefined(line));
589
704
  const metadata = values.flatMap((value) => {
590
705
  const parsed = SESSION_META_SCHEMA.safeParse(value);
591
706
  return parsed.success ? [parsed.data] : [];
@@ -736,11 +851,9 @@ function mainline_records(pairs) {
736
851
  return [...groups.values()];
737
852
  }
738
853
  var cost_corpus = {
739
- accumulate_missing,
740
854
  load_corpus,
741
855
  attribute_corpus,
742
856
  floor_for_issue,
743
- dedupe_across_sessions,
744
857
  attributed,
745
858
  mainline_records
746
859
  };
@@ -830,8 +943,8 @@ function selected_threshold(values) {
830
943
  function threshold_option(over) {
831
944
  return over === void 0 ? {} : { over };
832
945
  }
833
- function path_option(path7) {
834
- return path7 === void 0 ? {} : { path: path7 };
946
+ function path_option(path10) {
947
+ return path10 === void 0 ? {} : { path: path10 };
835
948
  }
836
949
  function to_options(values) {
837
950
  if (values.cut === true && values.over !== void 0) return void 0;
@@ -947,11 +1060,8 @@ var cost_cli = {
947
1060
  USAGE,
948
1061
  parse_options,
949
1062
  to_threshold,
950
- load_corpus: cost_corpus.load_corpus,
951
- attributed: cost_corpus.attributed,
952
1063
  run,
953
- session_verdict,
954
- main
1064
+ session_verdict
955
1065
  };
956
1066
  if (process.argv[1] === fileURLToPath(import.meta.url)) main(process.argv.slice(ARGV_OFFSET));
957
1067
 
@@ -970,16 +1080,13 @@ function format_share(part, whole) {
970
1080
  return `${(part / whole * PERCENT_SCALE).toFixed(PERCENT_DECIMALS)}%`;
971
1081
  }
972
1082
  var cost_format = {
973
- USD_DECIMALS,
974
- PERCENT_SCALE,
975
- PERCENT_DECIMALS,
976
1083
  format_usd,
977
1084
  format_tokens,
978
1085
  format_share
979
1086
  };
980
1087
 
981
1088
  // scripts/rules/implementation-cut-verdict.ts
982
- import { z as z3 } from "zod";
1089
+ import { z as z4 } from "zod";
983
1090
  var VERDICT_CACHE_PREFIX = "josh-impl-cut-verdict-";
984
1091
  var VERDICT_REUSE_MS = 5e3;
985
1092
  var VERDICT_VALUES = [
@@ -987,7 +1094,7 @@ var VERDICT_VALUES = [
987
1094
  "under",
988
1095
  "unmeasurable"
989
1096
  ];
990
- var cache_schema = z3.object({ read_at_ms: z3.number(), verdict: z3.enum(VERDICT_VALUES) });
1097
+ var cache_schema = z4.object({ read_at_ms: z4.number(), verdict: z4.enum(VERDICT_VALUES) });
991
1098
  function cache_path(directory) {
992
1099
  return stamp_file.stamp_path(VERDICT_CACHE_PREFIX, directory);
993
1100
  }
@@ -1083,7 +1190,6 @@ var implementation_cut = {
1083
1190
  REISSUE_WINDOW_MS,
1084
1191
  ROW: ROW4,
1085
1192
  decide: decide2,
1086
- is_edit_tool,
1087
1193
  is_over_threshold_edit,
1088
1194
  is_reissued_refusal,
1089
1195
  takes_the_impl_cut,
@@ -1159,20 +1265,20 @@ var lane_carry_conflict = {
1159
1265
  };
1160
1266
 
1161
1267
  // scripts/agent/interactive-ask.ts
1162
- import { z as z4 } from "zod";
1268
+ import { z as z5 } from "zod";
1163
1269
  var INTERACTIVE_TOOLS = /* @__PURE__ */ new Set(["AskUserQuestion"]);
1164
1270
  function is_interactive_tool(name) {
1165
1271
  return INTERACTIVE_TOOLS.has(name);
1166
1272
  }
1167
- var OPTION_SCHEMA = z4.looseObject({ label: z4.string().optional() });
1168
- var QUESTION_SCHEMA = z4.looseObject({
1169
- question: z4.string().optional(),
1170
- options: z4.array(OPTION_SCHEMA).optional()
1273
+ var OPTION_SCHEMA = z5.looseObject({ label: z5.string().optional() });
1274
+ var QUESTION_SCHEMA = z5.looseObject({
1275
+ question: z5.string().optional(),
1276
+ options: z5.array(OPTION_SCHEMA).optional()
1171
1277
  });
1172
- var ASK_INPUT_SCHEMA = z4.looseObject({ questions: z4.array(QUESTION_SCHEMA).optional() });
1173
- var DENIAL_SCHEMA = z4.looseObject({
1174
- tool_name: z4.string().optional(),
1175
- tool_input: z4.unknown().optional()
1278
+ var ASK_INPUT_SCHEMA = z5.looseObject({ questions: z5.array(QUESTION_SCHEMA).optional() });
1279
+ var DENIAL_SCHEMA = z5.looseObject({
1280
+ tool_name: z5.string().optional(),
1281
+ tool_input: z5.unknown().optional()
1176
1282
  });
1177
1283
  var UNKNOWN_QUESTION = "(question text unavailable)";
1178
1284
  var OPTION_SEPARATOR = " / ";
@@ -1198,7 +1304,7 @@ function refused_ask_of(permission_denials) {
1198
1304
  if (questions.length === 0) return void 0;
1199
1305
  return questions.map((question) => render_question(question)).join(QUESTION_SEPARATOR);
1200
1306
  }
1201
- var interactive_ask = { INTERACTIVE_TOOLS, is_interactive_tool, refused_ask_of };
1307
+ var interactive_ask = { is_interactive_tool, refused_ask_of };
1202
1308
 
1203
1309
  // scripts/rules/lane-interactive-ask.ts
1204
1310
  function is_interactive_ask(call, is_lane_child = lane_child_marker.is_child_of(process.cwd())) {
@@ -1257,6 +1363,108 @@ var lane_switch_main = {
1257
1363
  switch_targets
1258
1364
  };
1259
1365
 
1366
+ // scripts/run/run-stage.ts
1367
+ var KICKOFF = "kickoff";
1368
+ var HALFRUN = "halfrun";
1369
+ var PRRUN = "prrun";
1370
+ var FULLRUN = "fullrun";
1371
+ var COMMANDS = [KICKOFF, HALFRUN, PRRUN, FULLRUN];
1372
+ var DEFAULT_COMMAND = FULLRUN;
1373
+ var FRESH = "fresh";
1374
+ var PLANNED = "planned";
1375
+ var HALFRUN_STOPPED = "halfrun-stopped";
1376
+ var PRRUN_STOPPED = "prrun-stopped";
1377
+ var MERGED = "merged";
1378
+ var STATES = [FRESH, PLANNED, HALFRUN_STOPPED, PRRUN_STOPPED, MERGED];
1379
+ var REACHED = "reached";
1380
+ var STARTS = {
1381
+ [FRESH]: "plan",
1382
+ [PLANNED]: "implement",
1383
+ [HALFRUN_STOPPED]: "gate",
1384
+ [PRRUN_STOPPED]: "followup",
1385
+ [MERGED]: REACHED
1386
+ };
1387
+ var START_TOKENS = [...new Set(Object.values(STARTS))];
1388
+ var ENDS = {
1389
+ [KICKOFF]: "plan posted",
1390
+ [HALFRUN]: "gated, before the commit",
1391
+ [PRRUN]: "green, mergeable PR",
1392
+ [FULLRUN]: "merged"
1393
+ };
1394
+ var NEXT_PREFIX = "Next: ";
1395
+ var NEXT_SEPARATOR = " | ";
1396
+ var STATE_HEADER = "Issue state";
1397
+ var CELL_ARROW = " \u2192 ";
1398
+ var REACHED_CELL = "reached \u2014 report and stop";
1399
+ function to_command(value) {
1400
+ return COMMANDS.find((command) => command === value);
1401
+ }
1402
+ function state_of(facts) {
1403
+ if (facts.is_closed) return MERGED;
1404
+ if (facts.is_prrun_stopped) return PRRUN_STOPPED;
1405
+ if (facts.is_halfrun_stopped) return HALFRUN_STOPPED;
1406
+ return facts.is_planned ? PLANNED : FRESH;
1407
+ }
1408
+ function decide3(state, command) {
1409
+ const is_reached = STATES.indexOf(state) > COMMANDS.indexOf(command);
1410
+ const start = is_reached ? REACHED : STARTS[state];
1411
+ return { state, command, start, end: ENDS[command], is_reached };
1412
+ }
1413
+ function next_commands(command) {
1414
+ return COMMANDS.slice(COMMANDS.indexOf(command) + 1);
1415
+ }
1416
+ function next_line(command, issue) {
1417
+ const commands = next_commands(command).map((next) => `${next} #${issue}`);
1418
+ return `${NEXT_PREFIX}${commands.join(NEXT_SEPARATOR)}`;
1419
+ }
1420
+ function format_decision(issue, decision) {
1421
+ const fields = [`at: ${decision.state}`, `to: ${decision.command}`, `start: ${decision.start}`];
1422
+ return `stage #${issue} \u2014 ${fields.join(" \xB7 ")}`;
1423
+ }
1424
+ function cell(state, command) {
1425
+ const decision = decide3(state, command);
1426
+ return decision.is_reached ? REACHED_CELL : `${decision.start}${CELL_ARROW}${decision.end}`;
1427
+ }
1428
+ function table_rows() {
1429
+ const header = [STATE_HEADER, ...COMMANDS.map((command) => `\`${command}\``)];
1430
+ const rows = STATES.map((state) => [
1431
+ `\`${state}\``,
1432
+ ...COMMANDS.map((command) => cell(state, command))
1433
+ ]);
1434
+ return [header, ...rows];
1435
+ }
1436
+ var run_stage = {
1437
+ COMMANDS,
1438
+ DEFAULT_COMMAND,
1439
+ FRESH,
1440
+ HALFRUN,
1441
+ HALFRUN_STOPPED,
1442
+ KICKOFF,
1443
+ MERGED,
1444
+ PLANNED,
1445
+ PRRUN,
1446
+ PRRUN_STOPPED,
1447
+ REACHED,
1448
+ START_TOKENS,
1449
+ STATES,
1450
+ decide: decide3,
1451
+ format_decision,
1452
+ next_commands,
1453
+ next_line,
1454
+ state_of,
1455
+ table_rows,
1456
+ to_command
1457
+ };
1458
+
1459
+ // scripts/rules/decision-oracle-stage.ts
1460
+ var RUN_ENTRY_ORACLE = {
1461
+ name: "run:entry",
1462
+ decision: "Where a run on an issue starts, and whether the typed command has already been reached",
1463
+ args: "<N> [--to kickoff|halfrun|prrun|fullrun]",
1464
+ vocabulary: run_stage.START_TOKENS,
1465
+ single_source: ".claude/skills/workflow-commands/SKILL.md \u2192 \xA72k"
1466
+ };
1467
+
1260
1468
  // scripts/rules/decision-oracle.ts
1261
1469
  var CHAIN_RULE_MD = ".claude/skills/workflow-commands/chain-rule.md";
1262
1470
  var BACKLOGRUN_PROGRESS_MD = ".claude/skills/workflow-commands/backlogrun-progress.md";
@@ -1264,11 +1472,11 @@ var SKILL_2E = ".claude/skills/workflow-commands/SKILL.md \u2192 \xA72e";
1264
1472
  var SPLIT_ASSESSMENT_QUESTION = ".claude/skills/workflow-commands/split-assessment.md \u2192 The question";
1265
1473
  var PRE_GATE_CUT_MD = ".claude/skills/workflow-commands/pre-gate-cut.md";
1266
1474
  var BACKLOGRUN_MD = ".claude/skills/workflow-commands/backlogrun.md";
1267
- var RUN_MERGE_REFERENCE = "docs/josh-commands.md \u2192 `josh run:merge`";
1268
- var EPIC_NEXT_REFERENCE = "docs/josh-commands.md \u2192 `josh epic:next`";
1269
- var BACKLOG_BUDGET_REFERENCE = "docs/josh-commands.md \u2192 `josh backlog:budget`";
1270
- var RUN_LIVENESS_REFERENCE = "docs/josh-commands.md \u2192 `josh run:liveness`";
1271
- var AUTO_OK_NEXT_REFERENCE = "docs/josh-commands.md \u2192 `josh auto-ok:next`";
1475
+ var RUN_MERGE_REFERENCE = "docs/josh-commands-automation.md \u2192 `josh run:merge`";
1476
+ var EPIC_NEXT_REFERENCE = "docs/josh-commands-automation.md \u2192 `josh epic:next`";
1477
+ var BACKLOG_BUDGET_REFERENCE = "docs/josh-commands-automation.md \u2192 `josh backlog:budget`";
1478
+ var RUN_LIVENESS_REFERENCE = "docs/josh-commands-automation.md \u2192 `josh run:liveness`";
1479
+ var AUTO_OK_NEXT_REFERENCE = "docs/josh-commands-automation.md \u2192 `josh auto-ok:next`";
1272
1480
  var RUN_CUT_CMD = "run:cut";
1273
1481
  var REQUIRED = "required";
1274
1482
  var SKIP = "skip";
@@ -1520,15 +1728,16 @@ var DECISION_ORACLES = [
1520
1728
  decision: "Whether an epic's declaration matches its recorded relations, and the repair when it does not",
1521
1729
  args: "--reconcile <E>",
1522
1730
  vocabulary: [RECONCILED, NOTHING_TO_RECONCILE],
1523
- single_source: "docs/josh-commands.md \u2192 `josh epic --reconcile`"
1731
+ single_source: "docs/josh-commands-automation.md \u2192 `josh epic --reconcile`"
1524
1732
  },
1525
1733
  {
1526
1734
  name: "lane:list",
1527
1735
  decision: "Whether each in-progress issue holds a live lane, and the two-directional difference",
1528
1736
  args: "",
1529
1737
  vocabulary: [LIVE, STOPPED, UNKNOWN],
1530
- single_source: "docs/josh-commands.md \u2192 The `in-progress` / lane difference"
1531
- }
1738
+ single_source: "docs/josh-commands-automation.md \u2192 The `in-progress` / lane difference"
1739
+ },
1740
+ RUN_ENTRY_ORACLE
1532
1741
  ];
1533
1742
  function get_command(oracle) {
1534
1743
  return oracle.command ?? oracle.name;
@@ -1591,6 +1800,7 @@ var NOT_NAMED = /* @__PURE__ */ new Map([
1591
1800
  ["epic:next", READ],
1592
1801
  ["run:merge", PHASE],
1593
1802
  ["run:step", SELF],
1803
+ ["run:entry", SELF],
1594
1804
  ["refactor:scan", PHASE],
1595
1805
  ["split:assess", PHASE],
1596
1806
  ["sonar:hotspots", READ],
@@ -1643,7 +1853,337 @@ function row_for(oracle, firing_point) {
1643
1853
  };
1644
1854
  }
1645
1855
  var ROWS = oracle_firing.firing_oracles().map(({ oracle, firing_point }) => row_for(oracle, firing_point));
1646
- var oracle_consulted = { ROWS, command_line, reason_for, row_for, runs_the_oracle };
1856
+ var oracle_consulted = { ROWS, reason_for };
1857
+
1858
+ // scripts/rules/destructive-command.ts
1859
+ var RM_COMMAND = "rm";
1860
+ var RECURSIVE_LONG = "--recursive";
1861
+ var RECURSIVE_LETTERS = "rR";
1862
+ var FORCE_LONG = "--force";
1863
+ var FORCE_LETTER = "f";
1864
+ function has_flag(args, long, letters) {
1865
+ return args.some((argument) => argument === long || git_argv.short_cluster_has(argument, letters));
1866
+ }
1867
+ function is_recursive_forced_rm(segment) {
1868
+ const args = git_argv.arguments_of(segment, RM_COMMAND);
1869
+ if (args === void 0) return false;
1870
+ return has_flag(args, RECURSIVE_LONG, RECURSIVE_LETTERS) && has_flag(args, FORCE_LONG, FORCE_LETTER);
1871
+ }
1872
+ var GH_COMMAND = "gh";
1873
+ var REPO_GROUP2 = "repo";
1874
+ var REPO_REMOVALS = /* @__PURE__ */ new Set(["delete", "archive"]);
1875
+ var REPO_EDIT = "edit";
1876
+ var VISIBILITY_FLAG = "--visibility";
1877
+ var PR_GROUP = "pr";
1878
+ var PR_CLOSE = "close";
1879
+ function is_destructive_repo_action(action, args) {
1880
+ if (REPO_REMOVALS.has(action)) return true;
1881
+ return action === REPO_EDIT && args.some((argument) => argument.startsWith(VISIBILITY_FLAG));
1882
+ }
1883
+ function is_destructive_gh_command(args) {
1884
+ const [group, action = ""] = args;
1885
+ if (group === PR_GROUP) return action === PR_CLOSE;
1886
+ return group === REPO_GROUP2 && is_destructive_repo_action(action, args);
1887
+ }
1888
+ var DELETE_METHOD = "DELETE";
1889
+ var REPOSITORY_PATH = "repos/";
1890
+ var ISSUE_LABEL_PATH = /^['"]?\/?repos\/[^/\s'"]+\/[^/\s'"]+\/issues\/\d+\/labels\/[^/\s'"]+['"]?$/u;
1891
+ function is_destructive_api_call(args) {
1892
+ const call = [GH_COMMAND, ...args].join(" ");
1893
+ if (!gh_api.is_gh_api(call) || gh_api.method_of(call) !== DELETE_METHOD) return false;
1894
+ return args.some(
1895
+ (argument) => argument.includes(REPOSITORY_PATH) && !ISSUE_LABEL_PATH.test(argument)
1896
+ );
1897
+ }
1898
+ function is_destructive_gh(segment) {
1899
+ const args = git_argv.arguments_of(segment, GH_COMMAND);
1900
+ if (args === void 0) return false;
1901
+ return is_destructive_gh_command(args) || is_destructive_api_call(args);
1902
+ }
1903
+ function is_destructive_segment2(segment) {
1904
+ return is_recursive_forced_rm(segment) || is_destructive_gh(segment);
1905
+ }
1906
+ function is_destructive_command(command) {
1907
+ return shell_segments.segments_of(command).some((segment) => is_destructive_segment2(segment));
1908
+ }
1909
+ var DESTRUCTIVE_COMMAND_REASON = "\u26D4 destructive command: a recursive forced `rm` (`rm -rf`, `rm -fr`, `rm -r -f`, `rm --recursive --force`), `gh repo delete` / `archive`, `gh repo edit --visibility`, `gh pr close`, or a `gh api -X DELETE repos/\u2026` call deletes or closes something that cannot be restored, which is Tier C and needs explicit current-turn user instruction (`prompts/collaboration-workflow/operating-rules.md`). The `.claude/settings.json` deny list matches prefix globs, so it misses these spellings; this row reads the argv instead. Remove a file or directory one path at a time without `-f`, or ask the user to run the command in their own terminal. `gh issue close` and removing a label from an Issue (`DELETE repos/<o>/<r>/issues/<N>/labels/<name>`) are not refused. **This rule fires on every occurrence, not once per run.**";
1910
+ var ROW10 = {
1911
+ id: "destructive-command",
1912
+ is_trigger: bash_triggers.on_bash_command(is_destructive_command),
1913
+ reason: DESTRUCTIVE_COMMAND_REASON,
1914
+ decide: () => true
1915
+ };
1916
+ var destructive_command = { DESTRUCTIVE_COMMAND_REASON, ROW: ROW10, is_destructive_command };
1917
+
1918
+ // scripts/rules/worktree-guard.ts
1919
+ var CHECKOUT_SUBCOMMAND = "checkout";
1920
+ var RESTORE_SUBCOMMAND = "restore";
1921
+ var STASH_SUBCOMMAND = "stash";
1922
+ var PATHSPEC_SEPARATOR = "--";
1923
+ function is_worktree_checkout(args) {
1924
+ return args.includes(PATHSPEC_SEPARATOR);
1925
+ }
1926
+ var STAGED_LONG = "--staged";
1927
+ var STAGED_LETTER = "S";
1928
+ var WORKTREE_LONG = "--worktree";
1929
+ var WORKTREE_LETTER = "W";
1930
+ function touches_worktree(args) {
1931
+ const is_staged = args.some(
1932
+ (argument) => argument === STAGED_LONG || git_argv.short_cluster_has(argument, STAGED_LETTER)
1933
+ );
1934
+ const is_worktree = args.some(
1935
+ (argument) => argument === WORKTREE_LONG || git_argv.short_cluster_has(argument, WORKTREE_LETTER)
1936
+ );
1937
+ return !is_staged || is_worktree;
1938
+ }
1939
+ var PUSH_STASH = "push";
1940
+ var MESSAGE_LONG = "--message";
1941
+ var MESSAGE_SHORT_LETTER = "m";
1942
+ var READ_ONLY_STASH = /* @__PURE__ */ new Set(["list", "show"]);
1943
+ function has_message(args) {
1944
+ return args.some(
1945
+ (argument) => argument === MESSAGE_LONG || argument.startsWith(`${MESSAGE_LONG}=`) || git_argv.short_cluster_has(argument, MESSAGE_SHORT_LETTER)
1946
+ );
1947
+ }
1948
+ function is_unauthorized_stash(args) {
1949
+ const [stash_subcommand, ...rest] = args;
1950
+ if (stash_subcommand === void 0) return true;
1951
+ if (READ_ONLY_STASH.has(stash_subcommand)) return false;
1952
+ if (stash_subcommand === PUSH_STASH) return !has_message(rest);
1953
+ return true;
1954
+ }
1955
+ var CLEAN_SUBCOMMAND = "clean";
1956
+ var FORCE_LONG2 = "--force";
1957
+ var FORCE_LETTER2 = "f";
1958
+ function is_forced_clean(args) {
1959
+ return args.some(
1960
+ (argument) => argument === FORCE_LONG2 || git_argv.short_cluster_has(argument, FORCE_LETTER2)
1961
+ );
1962
+ }
1963
+ var JUDGED_SUBCOMMANDS = /* @__PURE__ */ new Map([
1964
+ [CHECKOUT_SUBCOMMAND, is_worktree_checkout],
1965
+ [RESTORE_SUBCOMMAND, touches_worktree],
1966
+ [CLEAN_SUBCOMMAND, is_forced_clean],
1967
+ [STASH_SUBCOMMAND, is_unauthorized_stash]
1968
+ ]);
1969
+ function is_unauthorized_segment(segment) {
1970
+ const call = git_argv.parse(segment);
1971
+ if (call === void 0) return false;
1972
+ return JUDGED_SUBCOMMANDS.get(call.subcommand ?? "")?.(call.args) === true;
1973
+ }
1974
+ function is_unauthorized_worktree_change(command) {
1975
+ return shell_segments.segments_of(command).some((segment) => is_unauthorized_segment(segment));
1976
+ }
1977
+ var WORKTREE_MUTATION_REASON = '\u26D4 unauthorized working-tree change: `git checkout -- <path>`, `git restore <path>`, a forced `git clean` and an unauthorized `git stash` discard work or mutate the repository-wide stash every work tree shares, and none is on the `.claude/settings.json` deny list (`operating-rules.md`). Do not run them on your own judgement. A commit goes through `pnpm josh git`; a stash pop goes through `pnpm josh stash:pop "<message>"`, never a positional `git stash pop` a shared stack lets another lane divert. A stash push is authorized only inside a documented flow and only with a findable message \u2014 `git stash push -u -m "<message>"` \u2014 which this row allows; a bare `git stash`, a message-less push, or `pop` / `apply` / `drop` is refused. **This rule fires on every occurrence, not once per run.**';
1978
+ var ROW11 = {
1979
+ id: "worktree-mutation",
1980
+ is_trigger: bash_triggers.on_bash_command(is_unauthorized_worktree_change),
1981
+ reason: WORKTREE_MUTATION_REASON,
1982
+ decide: () => true
1983
+ };
1984
+ var worktree_guard = {
1985
+ ROW: ROW11,
1986
+ WORKTREE_MUTATION_REASON,
1987
+ is_unauthorized_worktree_change,
1988
+ touches_worktree
1989
+ };
1990
+
1991
+ // scripts/rules/index-guard.ts
1992
+ var INDEX_SUBCOMMANDS = /* @__PURE__ */ new Set([
1993
+ "add",
1994
+ "commit",
1995
+ "mv",
1996
+ "reset",
1997
+ "rm",
1998
+ "stage"
1999
+ ]);
2000
+ var RESTORE_SUBCOMMAND2 = "restore";
2001
+ function is_index_restore(args) {
2002
+ return !worktree_guard.touches_worktree(args);
2003
+ }
2004
+ function is_index_segment(segment) {
2005
+ const call = git_argv.parse(segment);
2006
+ if (call === void 0) return false;
2007
+ if (INDEX_SUBCOMMANDS.has(call.subcommand ?? "")) return true;
2008
+ return call.subcommand === RESTORE_SUBCOMMAND2 && is_index_restore(call.args);
2009
+ }
2010
+ function is_index_mutation(command) {
2011
+ return shell_segments.segments_of(command).some((segment) => is_index_segment(segment));
2012
+ }
2013
+ var INDEX_MUTATION_REASON = '\u26D4 git index mutation: `git add` / `stage` / `commit` / `reset` / `rm` / `mv` and `git restore --staged` overwrite the user\'s staged snapshot, which `CLAUDE.md` \u2192 Git Rules forbids on your own judgement (`prompts/collaboration-workflow/operating-rules.md` \u2192 "git index \u3092\u52DD\u624B\u306B\u5909\u66F4\u3057\u306A\u3044"). The `.claude/settings.json` deny list matches prefix globs, so it misses `git -C . commit`, `git -c k=v commit` and `env git commit`; this row reads the argv instead, so the spelling does not matter. A commit goes through `pnpm josh git -y`; any other staging needs explicit current-turn user instruction, run by the user in their own terminal. **This rule fires on every occurrence, not once per run.**';
2014
+ var ROW12 = {
2015
+ id: "index-mutation",
2016
+ is_trigger: bash_triggers.on_bash_command(is_index_mutation),
2017
+ reason: INDEX_MUTATION_REASON,
2018
+ decide: () => true
2019
+ };
2020
+ var index_guard = { INDEX_MUTATION_REASON, ROW: ROW12, is_index_mutation };
2021
+
2022
+ // scripts/rules/protected-files.ts
2023
+ import path5 from "node:path";
2024
+
2025
+ // scripts/doctor/doctor-consumer.ts
2026
+ import { existsSync as existsSync2 } from "node:fs";
2027
+ import path4 from "node:path";
2028
+
2029
+ // scripts/lib/spawn-exit.ts
2030
+ function read_spawn_stdout(result) {
2031
+ return result.stdout ?? "";
2032
+ }
2033
+
2034
+ // scripts/version/kit-descriptor.ts
2035
+ var KIT_PACKAGE_NAME = "@joshuafolkken/kit";
2036
+
2037
+ // scripts/doctor/doctor-consumer.ts
2038
+ import { execaSync } from "execa";
2039
+ import { z as z6 } from "zod";
2040
+ var NODE_MODULES = "node_modules";
2041
+ var SETTINGS_PATH = path4.join(".claude", "settings.json");
2042
+ var CLAUDE_MD = "CLAUDE.md";
2043
+ var PLUGIN_ID = "kit@kit";
2044
+ var CLAUDE_MD_POINTER = `@${NODE_MODULES}/${KIT_PACKAGE_NAME}/dist/${CLAUDE_MD}`;
2045
+ var SECRETLINT_BIN = path4.join(NODE_MODULES, ".bin", "secretlint");
2046
+ var GIT_TIMEOUT_MS = 2e3;
2047
+ var manifest_schema = z6.object({
2048
+ name: z6.string().optional(),
2049
+ dependencies: z6.record(z6.string(), z6.string()).optional(),
2050
+ devDependencies: z6.record(z6.string(), z6.string()).optional()
2051
+ });
2052
+ var settings_schema = z6.object({
2053
+ enabledPlugins: z6.record(z6.string(), z6.boolean()).optional()
2054
+ });
2055
+ var STATE_OK = "ok";
2056
+ var STATE_TARGET_MISSING = "target-missing";
2057
+ var STATE_MISSING = "missing";
2058
+ function parse_manifest(root) {
2059
+ const content = file_reader.read_if_readable(path4.join(root, "package.json"));
2060
+ if (content === void 0) return void 0;
2061
+ const parsed = manifest_schema.safeParse(json_value.parse_or_undefined(content));
2062
+ return parsed.success ? parsed.data : void 0;
2063
+ }
2064
+ function lists_kit_dependency(manifest) {
2065
+ if (manifest === void 0) return false;
2066
+ return Object.hasOwn(manifest.dependencies ?? {}, KIT_PACKAGE_NAME) || Object.hasOwn(manifest.devDependencies ?? {}, KIT_PACKAGE_NAME);
2067
+ }
2068
+ function is_kit_consumer(root) {
2069
+ const manifest = parse_manifest(root);
2070
+ if (manifest?.name === KIT_PACKAGE_NAME) return false;
2071
+ return lists_kit_dependency(manifest) || existsSync2(path4.join(root, NODE_MODULES, KIT_PACKAGE_NAME));
2072
+ }
2073
+ function is_plugin_declared(root) {
2074
+ const content = file_reader.read_if_readable(path4.join(root, SETTINGS_PATH));
2075
+ if (content === void 0) return false;
2076
+ const parsed = settings_schema.safeParse(json_value.parse_or_undefined(content));
2077
+ return parsed.success && parsed.data.enabledPlugins?.[PLUGIN_ID] === true;
2078
+ }
2079
+ function configured_hooks_path(root) {
2080
+ const result = execaSync("git", ["-C", root, "config", "--get", "core.hooksPath"], {
2081
+ reject: false,
2082
+ timeout: GIT_TIMEOUT_MS
2083
+ });
2084
+ const value = read_spawn_stdout(result).trim();
2085
+ return value === "" ? void 0 : value;
2086
+ }
2087
+ function claude_md_state(root) {
2088
+ const content = file_reader.read_if_readable(path4.join(root, CLAUDE_MD));
2089
+ if (content === void 0) return STATE_MISSING;
2090
+ if (!content.includes(CLAUDE_MD_POINTER)) return STATE_OK;
2091
+ return existsSync2(path4.join(root, NODE_MODULES, KIT_PACKAGE_NAME, "dist", CLAUDE_MD)) ? STATE_OK : STATE_TARGET_MISSING;
2092
+ }
2093
+ function is_secretlint_runnable(root) {
2094
+ return existsSync2(path4.join(root, SECRETLINT_BIN));
2095
+ }
2096
+ function status_line(is_ok, ok_text, warn_text) {
2097
+ return is_ok ? ` \u2713 ${ok_text}` : ` \u26A0 ${warn_text}`;
2098
+ }
2099
+ function plugin_line(is_declared2) {
2100
+ return status_line(
2101
+ is_declared2,
2102
+ "kit plugin declared (skills load in a trusted workspace; headless from its second session)",
2103
+ "kit plugin not declared in .claude/settings.json \u2014 run `pnpm josh sync`"
2104
+ );
2105
+ }
2106
+ function hooks_path_line(hooks_path) {
2107
+ return status_line(
2108
+ hooks_path === void 0,
2109
+ "git hooks install normally (core.hooksPath unset)",
2110
+ `core.hooksPath is set (${hooks_path ?? ""}) \u2014 lefthook installs no git hooks; unset it`
2111
+ );
2112
+ }
2113
+ function claude_md_line(state) {
2114
+ if (state === STATE_OK) return " \u2713 CLAUDE.md resolves to the installed kit rules";
2115
+ if (state === STATE_TARGET_MISSING) {
2116
+ return " \u26A0 CLAUDE.md points at rules that are not installed \u2014 run `pnpm install`";
2117
+ }
2118
+ return " \u26A0 CLAUDE.md is missing \u2014 run `pnpm josh init`";
2119
+ }
2120
+ function secretlint_line(is_runnable) {
2121
+ return status_line(
2122
+ is_runnable,
2123
+ "secretlint is runnable",
2124
+ "secretlint is not installed \u2014 run `pnpm install`"
2125
+ );
2126
+ }
2127
+ function consumer_setup_lines(root) {
2128
+ return [
2129
+ plugin_line(is_plugin_declared(root)),
2130
+ hooks_path_line(configured_hooks_path(root)),
2131
+ claude_md_line(claude_md_state(root)),
2132
+ secretlint_line(is_secretlint_runnable(root))
2133
+ ];
2134
+ }
2135
+ function report_consumer_setup(root) {
2136
+ if (!is_kit_consumer(root)) return;
2137
+ console.info("");
2138
+ console.info("Consumer setup:");
2139
+ for (const line of consumer_setup_lines(root)) console.info(line);
2140
+ }
2141
+ var doctor_consumer = {
2142
+ claude_md_line,
2143
+ claude_md_state,
2144
+ hooks_path_line,
2145
+ is_kit_consumer,
2146
+ is_plugin_declared,
2147
+ is_secretlint_runnable,
2148
+ plugin_line,
2149
+ report_consumer_setup,
2150
+ secretlint_line
2151
+ };
2152
+
2153
+ // scripts/rules/protected-files.ts
2154
+ var READ_TOOL = "Read";
2155
+ var EDIT_TOOLS2 = /* @__PURE__ */ new Set(["Edit", "Write"]);
2156
+ var ENVIRONMENT_FILE = ".env";
2157
+ var SETTINGS_FILE = path5.join(".claude", "settings.json");
2158
+ function file_path_of(call) {
2159
+ if (!json_value.is_record(call.input)) return "";
2160
+ const value = call.input["file_path"];
2161
+ return typeof value === "string" ? value : "";
2162
+ }
2163
+ function is_environment_read(call) {
2164
+ return call.name === READ_TOOL && path5.basename(file_path_of(call)) === ENVIRONMENT_FILE;
2165
+ }
2166
+ function is_consumer_settings_edit(call, is_kit_consumer2) {
2167
+ if (!EDIT_TOOLS2.has(call.name)) return false;
2168
+ const file_path = path5.resolve(file_path_of(call));
2169
+ if (!file_path.endsWith(`${path5.sep}${SETTINGS_FILE}`)) return false;
2170
+ return is_kit_consumer2(path5.dirname(path5.dirname(file_path)));
2171
+ }
2172
+ function is_protected_file_call(call, is_kit_consumer2 = doctor_consumer.is_kit_consumer) {
2173
+ return is_environment_read(call) || is_consumer_settings_edit(call, is_kit_consumer2);
2174
+ }
2175
+ var PROTECTED_FILE_REASON = '\u26D4 protected file: `.env` holds the Telegram bot token, so reading it puts a secret in the transcript \u2014 the scripts that need it load it in their own process. `.claude/settings.json` in a consumer repository is the deny list and the hooks every other rule rests on, so a run must not rewrite it; `josh sync` owns it, and a change belongs upstream in kit (`CLAUDE.md` \u2192 "Route distributed-doc / config changes upstream to kit"). Leave both files alone, or ask the user. **This rule fires on every occurrence, not once per run.**';
2176
+ var ROW13 = {
2177
+ id: "protected-file",
2178
+ is_trigger: is_protected_file_call,
2179
+ reason: PROTECTED_FILE_REASON,
2180
+ decide: () => true
2181
+ };
2182
+ var protected_files = { ROW: ROW13, is_protected_file_call };
2183
+
2184
+ // scripts/rules/permission-guards.ts
2185
+ var ROWS2 = [index_guard.ROW, destructive_command.ROW, protected_files.ROW];
2186
+ var permission_guards = { ROWS: ROWS2 };
1647
2187
 
1648
2188
  // scripts/rules/piped-verification.ts
1649
2189
  var VERIFICATION_COMMANDS = /* @__PURE__ */ new Set([
@@ -1713,7 +2253,7 @@ function is_poll_loop(command) {
1713
2253
  return LOOP_KEYWORD2.test(plain) && SLEEP_COMMAND.test(plain);
1714
2254
  }
1715
2255
  var POLL_LOOP_REASON = '\u26D4 output poll loop: this hand-writes a `while`/`until` wait loop over a command\'s output, a marker file or a process \u2014 with a `sleep` or, worse, without one \u2014 and the loop does not know when the command finished. A regex that never matches waits to the harness block limit; one that matches a mid-run line exits too early \u2014 either way the command exit is not what ends the wait, and each pass spends a full-context round trip (joshuafolkken/kit#2371 measured about 45 minutes, 13% of six lanes, lost to exactly this). Do not poll the output file. A command known to take minutes \u2014 `pnpm josh gate`, `pnpm josh followup`, `pnpm josh format` \u2014 is started detached from the first with `run_in_background` set, and the harness re-invokes you when it exits: its completion notification is what ends the wait, on the task exit rather than a regex or the block limit. So issue the long command in the background and end the turn \u2014 do not arm a loop; the wake-up brings you back. To glance at interim output, `Read` the output file once, never in a sleep loop. If you are waiting on CI, `pnpm josh followup` waits on it for you. The procedure is `.claude/skills/workflow-commands/background-commands.md`, "A command that can take minutes is issued in the background". **This rule fires on every occurrence, not once per run.**';
1716
- var ROW10 = {
2256
+ var ROW14 = {
1717
2257
  id: "poll-loop",
1718
2258
  is_trigger: bash_triggers.on_bash_command(is_poll_loop),
1719
2259
  reason: POLL_LOOP_REASON,
@@ -1721,7 +2261,7 @@ var ROW10 = {
1721
2261
  };
1722
2262
  var poll_loop = {
1723
2263
  POLL_LOOP_REASON,
1724
- ROW: ROW10,
2264
+ ROW: ROW14,
1725
2265
  is_poll_loop
1726
2266
  };
1727
2267
 
@@ -1841,13 +2381,13 @@ function posts_at_path_literally(command) {
1841
2381
  return RAW_FIELD_BODY_AT.test(command);
1842
2382
  }
1843
2383
  var RAW_FIELD_BODY_REASON = "\u26D4 literal @path body: this passes `body=@<path>` to `gh api` with a raw field flag (`-f` / `--raw-field`), which sends the value verbatim \u2014 the string `@<path>` is posted as the comment, not the file it points at. `-F` / `--field` is the flag that reads the file, and the two spellings differ by one character while `gh` exits 0 and returns a comment URL either way, so the break is invisible until a person reads the issue (joshuafolkken/kit#2304 lost two park comments this way). Post an issue or PR comment with `pnpm josh issue:comment <N> --body-file <path>` \u2014 the one spelling, which cannot take the wrong flag. The rule and the safe forms are in `prompts/collaboration-workflow/shell-body.md`. This rule fires on every occurrence, not once per run.";
1844
- var ROW11 = {
2384
+ var ROW15 = {
1845
2385
  id: "raw-field-body",
1846
2386
  is_trigger: bash_triggers.on_bash_command(posts_at_path_literally),
1847
2387
  reason: RAW_FIELD_BODY_REASON,
1848
2388
  decide: () => true
1849
2389
  };
1850
- var raw_field_body = { RAW_FIELD_BODY_REASON, ROW: ROW11, posts_at_path_literally };
2390
+ var raw_field_body = { RAW_FIELD_BODY_REASON, ROW: ROW15, posts_at_path_literally };
1851
2391
 
1852
2392
  // scripts/rules/rule-body-guard.ts
1853
2393
  var EDIT_TOOL = "Edit";
@@ -1918,7 +2458,7 @@ function runs_placement_oracle(command) {
1918
2458
  (names) => shell_segments.segments_of(command).some((segment) => shell_segments.is_josh_command(segment, names))
1919
2459
  );
1920
2460
  }
1921
- var ROW12 = {
2461
+ var ROW16 = {
1922
2462
  id: "rule-body",
1923
2463
  is_trigger: writes_rule_prose,
1924
2464
  reason: RULE_BODY_REASON,
@@ -1927,12 +2467,9 @@ var ROW12 = {
1927
2467
  };
1928
2468
  var rule_body_guard = {
1929
2469
  RULE_BODY_REASON,
1930
- ROW: ROW12,
1931
- adds_rule_prose,
2470
+ ROW: ROW16,
1932
2471
  answered_placement,
1933
2472
  is_rule_document,
1934
- prose_of,
1935
- runs_placement_oracle,
1936
2473
  writes_rule_prose
1937
2474
  };
1938
2475
 
@@ -2002,7 +2539,6 @@ var SHELL_BODY_REASON = "\u26D4 shell-evaluated body: this command carries a bod
2002
2539
  var shell_body_trigger = {
2003
2540
  SHELL_BODY_REASON,
2004
2541
  carries_a_body,
2005
- is_safe_body_form,
2006
2542
  is_shell_evaluated_body,
2007
2543
  keeps_body_safe
2008
2544
  };
@@ -2011,18 +2547,13 @@ var shell_body_trigger = {
2011
2547
  import { execFileSync } from "node:child_process";
2012
2548
 
2013
2549
  // scripts/gate/project-checks.ts
2014
- import { existsSync as existsSync3, globSync as globSync2, readFileSync as readFileSync4 } from "node:fs";
2015
- import path5 from "node:path";
2016
-
2017
- // scripts/init/project-profile.ts
2018
- import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync3 } from "node:fs";
2019
- import path4 from "node:path";
2020
-
2021
- // scripts/version/kit-descriptor.ts
2022
- var KIT_PACKAGE_NAME = "@joshuafolkken/kit";
2550
+ import { existsSync as existsSync4, globSync as globSync2, readFileSync as readFileSync4 } from "node:fs";
2551
+ import path7 from "node:path";
2023
2552
 
2024
2553
  // scripts/init/project-profile.ts
2025
- import { execaSync } from "execa";
2554
+ import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3 } from "node:fs";
2555
+ import path6 from "node:path";
2556
+ import { execaSync as execaSync2 } from "execa";
2026
2557
  var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([".git", "node_modules", "dist", "build", ".svelte-kit"]);
2027
2558
  var WEB_EXTENSIONS = /* @__PURE__ */ new Set([".html", ".css", ".js", ".jsx", ".mjs", ".cjs"]);
2028
2559
  var TYPESCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx"]);
@@ -2054,26 +2585,21 @@ function requested_profile(args, usage = "josh init [--profile basic|full]") {
2054
2585
  throw new Error("Profile must be basic or full");
2055
2586
  }
2056
2587
  function read_manifest(root) {
2057
- const filename = path4.join(root, "package.json");
2058
- if (!existsSync2(filename)) return void 0;
2588
+ const filename = path6.join(root, "package.json");
2589
+ if (!existsSync3(filename)) return void 0;
2059
2590
  const parsed = JSON.parse(readFileSync3(filename, "utf8"));
2060
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
2061
- throw new Error("package.json must contain an object");
2062
- }
2591
+ if (!json_value.is_record(parsed)) throw new Error("package.json must contain an object");
2063
2592
  return parsed;
2064
2593
  }
2065
- function is_record(value) {
2066
- return typeof value === "object" && value !== null && !Array.isArray(value);
2067
- }
2068
2594
  function recorded_profile(manifest) {
2069
2595
  const { josh } = manifest;
2070
- return is_record(josh) ? parse_profile(josh["profile"]) : void 0;
2596
+ return json_value.is_record(josh) ? parse_profile(josh["profile"]) : void 0;
2071
2597
  }
2072
2598
  function has_build_script(value) {
2073
- return is_record(value) && ("build" in value || "dev" in value);
2599
+ return json_value.is_record(value) && ("build" in value || "dev" in value);
2074
2600
  }
2075
2601
  function has_project_dependencies(value) {
2076
- if (!is_record(value)) return false;
2602
+ if (!json_value.is_record(value)) return false;
2077
2603
  return Object.keys(value).some((name) => name !== KIT_PACKAGE_NAME);
2078
2604
  }
2079
2605
  function inferred_profile(manifest) {
@@ -2099,9 +2625,9 @@ function should_visit(entry) {
2099
2625
  function scan_directory(directory, pending) {
2100
2626
  const entries = readdirSync(directory, { withFileTypes: true });
2101
2627
  pending.push(
2102
- ...entries.filter((entry) => should_visit(entry)).map((entry) => path4.join(directory, entry.name))
2628
+ ...entries.filter((entry) => should_visit(entry)).map((entry) => path6.join(directory, entry.name))
2103
2629
  );
2104
- return entries.filter((entry) => entry.isFile()).map((entry) => path4.extname(entry.name));
2630
+ return entries.filter((entry) => entry.isFile()).map((entry) => path6.extname(entry.name));
2105
2631
  }
2106
2632
  function file_extensions(root) {
2107
2633
  const pending = [root];
@@ -2118,7 +2644,7 @@ function scan_files(root) {
2118
2644
  return { has_web, has_typescript };
2119
2645
  }
2120
2646
  function has_github_remote(root) {
2121
- const result = execaSync("git", ["config", "--get", "remote.origin.url"], {
2647
+ const result = execaSync2("git", ["config", "--get", "remote.origin.url"], {
2122
2648
  cwd: root,
2123
2649
  reject: false
2124
2650
  });
@@ -2127,7 +2653,7 @@ function has_github_remote(root) {
2127
2653
  function inspect_project(root, requested) {
2128
2654
  const profile = resolve_profile(root, requested);
2129
2655
  const files = scan_files(root);
2130
- const has_git = existsSync2(path4.join(root, ".git"));
2656
+ const has_git = existsSync3(path6.join(root, ".git"));
2131
2657
  return { ...profile, ...files, has_git, has_github: has_git && has_github_remote(root) };
2132
2658
  }
2133
2659
  var project_profile = {
@@ -2142,7 +2668,7 @@ var project_profile = {
2142
2668
  var SKIP_MARKER = "\u2014 skipping";
2143
2669
 
2144
2670
  // scripts/gate/project-checks.ts
2145
- import { z as z5 } from "zod";
2671
+ import { z as z7 } from "zod";
2146
2672
  var PACKAGE_JSON = "package.json";
2147
2673
  var IGNORED_DIRS = /* @__PURE__ */ new Set([
2148
2674
  "node_modules",
@@ -2177,11 +2703,11 @@ var CSPELL_CONFIGS = [
2177
2703
  ];
2178
2704
  var TYPE_CONFIGS = ["tsconfig.json", "jsconfig.json"];
2179
2705
  var DEPENDENCY_FIELDS = ["dependencies", "devDependencies"];
2180
- var object_schema = z5.record(z5.string(), z5.unknown());
2706
+ var object_schema = z7.record(z7.string(), z7.unknown());
2181
2707
  function project_root(directory) {
2182
2708
  let current = directory;
2183
- while (!existsSync3(path5.join(current, PACKAGE_JSON))) {
2184
- const parent = path5.dirname(current);
2709
+ while (!existsSync4(path7.join(current, PACKAGE_JSON))) {
2710
+ const parent = path7.dirname(current);
2185
2711
  if (parent === current) return directory;
2186
2712
  current = parent;
2187
2713
  }
@@ -2194,24 +2720,23 @@ function has_files(directory, pattern) {
2194
2720
  return globSync2(pattern, { cwd: project_root(directory), exclude: is_ignored }).length > 0;
2195
2721
  }
2196
2722
  function has_config(directory, names) {
2197
- return names.some((name) => existsSync3(path5.join(project_root(directory), name)));
2723
+ return names.some((name) => existsSync4(path7.join(project_root(directory), name)));
2198
2724
  }
2199
2725
  function has_bin(directory, bin_name) {
2200
2726
  return find_local_bin_upwards(directory, bin_name) !== void 0;
2201
2727
  }
2202
2728
  function josh_settings(manifest) {
2203
- if (typeof manifest !== "object" || manifest === null || !("josh" in manifest)) return void 0;
2204
- return manifest.josh;
2729
+ return json_value.is_record(manifest) ? manifest["josh"] : void 0;
2205
2730
  }
2206
2731
  function is_basic_manifest(manifest) {
2207
2732
  const josh = josh_settings(manifest);
2208
- if (typeof josh !== "object" || josh === null || !("profile" in josh)) return false;
2209
- return project_profile.parse_profile(josh.profile) === "basic";
2733
+ if (!json_value.is_record(josh)) return false;
2734
+ return project_profile.parse_profile(josh["profile"]) === "basic";
2210
2735
  }
2211
2736
  function read_manifest2(directory) {
2212
2737
  try {
2213
- const manifest_path = path5.join(project_root(directory), PACKAGE_JSON);
2214
- return JSON.parse(readFileSync4(manifest_path, "utf8"));
2738
+ const manifest_path = path7.join(project_root(directory), PACKAGE_JSON);
2739
+ return json_value.parse_or_undefined(readFileSync4(manifest_path, "utf8"));
2215
2740
  } catch {
2216
2741
  return void 0;
2217
2742
  }
@@ -2231,8 +2756,8 @@ function missing_tool_reason(directory, package_name, bin_name) {
2231
2756
  if (has_bin(directory, bin_name) || is_declared(directory, package_name)) return void 0;
2232
2757
  return `${package_name} is not installed`;
2233
2758
  }
2234
- function skip_notice(check3, reason) {
2235
- return `josh ${check3}: ${reason} ${SKIP_MARKER} ${check3}.`;
2759
+ function skip_notice(check4, reason) {
2760
+ return `josh ${check4}: ${reason} ${SKIP_MARKER} ${check4}.`;
2236
2761
  }
2237
2762
  function type_check_skip_reason(directory) {
2238
2763
  if (!is_basic(directory)) return void 0;
@@ -2254,8 +2779,6 @@ function eslint_skip_reason(directory) {
2254
2779
  var project_checks = {
2255
2780
  CSPELL_CONFIGS,
2256
2781
  ESLINT_CONFIGS,
2257
- SCRIPT_FILES,
2258
- TYPE_CONFIGS,
2259
2782
  TYPE_FILES,
2260
2783
  WEB_FILES,
2261
2784
  eslint_skip_reason,
@@ -2293,46 +2816,45 @@ var BASIC_REQUIRED_SUFFIXES = [
2293
2816
  ".toml"
2294
2817
  ];
2295
2818
  function normalize(paths) {
2296
- return paths.map((path7) => path7.trim()).filter((path7) => path7 !== "");
2819
+ return paths.map((path10) => path10.trim()).filter((path10) => path10 !== "");
2297
2820
  }
2298
- function is_test_file(path7) {
2299
- return TEST_SUFFIXES.some((suffix) => path7.endsWith(suffix));
2821
+ function is_test_file(path10) {
2822
+ return TEST_SUFFIXES.some((suffix) => path10.endsWith(suffix));
2300
2823
  }
2301
- function is_basic_manual(path7, is_basic2) {
2302
- const lower = path7.toLowerCase();
2824
+ function is_basic_manual(path10, is_basic2) {
2825
+ const lower = path10.toLowerCase();
2303
2826
  return is_basic2 && BASIC_REQUIRED_SUFFIXES.every((suffix) => !lower.endsWith(suffix));
2304
2827
  }
2305
- function is_basic_visual(path7) {
2306
- const lower = path7.toLowerCase();
2828
+ function is_basic_visual(path10) {
2829
+ const lower = path10.toLowerCase();
2307
2830
  return BASIC_VISUAL_SUFFIXES.some((suffix) => lower.endsWith(suffix));
2308
2831
  }
2309
- function is_exempt(path7, is_basic2 = false) {
2310
- if (EXEMPT_PATHS.includes(path7) || is_basic_manual(path7, is_basic2)) return true;
2311
- return EXEMPT_SUFFIXES.some((suffix) => path7.endsWith(suffix)) || EXEMPT_PREFIXES.some((prefix) => path7.startsWith(prefix));
2832
+ function is_exempt(path10, is_basic2 = false) {
2833
+ if (EXEMPT_PATHS.includes(path10) || is_basic_manual(path10, is_basic2)) return true;
2834
+ return EXEMPT_SUFFIXES.some((suffix) => path10.endsWith(suffix)) || EXEMPT_PREFIXES.some((prefix) => path10.startsWith(prefix));
2312
2835
  }
2313
- function is_runtime(path7, is_basic2 = false) {
2314
- return !is_test_file(path7) && !is_exempt(path7, is_basic2);
2836
+ function is_runtime(path10, is_basic2 = false) {
2837
+ return !is_test_file(path10) && !is_exempt(path10, is_basic2);
2315
2838
  }
2316
2839
  function verdict_for(paths, is_basic2 = false) {
2317
2840
  const changed = normalize(paths);
2318
- if (changed.some((path7) => is_test_file(path7))) return "satisfied";
2319
- if (changed.some((path7) => is_runtime(path7, is_basic2))) return "required";
2841
+ if (changed.some((path10) => is_test_file(path10))) return "satisfied";
2842
+ if (changed.some((path10) => is_runtime(path10, is_basic2))) return "required";
2320
2843
  return "exempt";
2321
2844
  }
2322
2845
  function runtime_files(paths, is_basic2 = false) {
2323
- return normalize(paths).filter((path7) => is_runtime(path7, is_basic2));
2846
+ return normalize(paths).filter((path10) => is_runtime(path10, is_basic2));
2324
2847
  }
2325
2848
  function exempt_files(paths, is_basic2 = false) {
2326
- return normalize(paths).filter((path7) => is_exempt(path7, is_basic2));
2849
+ return normalize(paths).filter((path10) => is_exempt(path10, is_basic2));
2327
2850
  }
2328
2851
  function manual_check_files(paths, is_basic2) {
2329
- return normalize(paths).filter((path7) => is_exempt(path7, is_basic2) && !is_exempt(path7));
2852
+ return normalize(paths).filter((path10) => is_exempt(path10, is_basic2) && !is_exempt(path10));
2330
2853
  }
2331
2854
  var test_declared_logic = {
2332
2855
  EXEMPT_PATHS,
2333
2856
  EXEMPT_PREFIXES,
2334
2857
  EXEMPT_SUFFIXES,
2335
- TEST_SUFFIXES,
2336
2858
  exempt_files,
2337
2859
  is_basic_visual,
2338
2860
  is_exempt,
@@ -2393,8 +2915,8 @@ function is_untested_commit(call) {
2393
2915
  return test_declared_changed.current_verdict() === "required";
2394
2916
  }
2395
2917
  var REASON = '\u26D4 test declared: this commits a runtime code change with no test beside it \u2014 `pnpm josh test:declared` reads the working tree as `required` (a changed file that is neither a test \u2014 `*.test.ts` / `*.e2e.ts` \u2014 nor a mechanically-exempt non-runtime path). `CLAUDE.md` \u2192 Code Change Rules requires a test for ALL code changes: a bug fix gets a regression test, a refactor gets tests pinning behavior first, logic gets a unit test, an observable UI/timing change gets an E2E. Add the declared test and reissue this commit. **If the change genuinely touches no executable runtime path** it is the pre-approved non-runtime exception \u2014 declare it in your Step 0 work summary with the reason it is exempt (non-executable config, a cosmetic asset swap) and reissue; the exception is a presentation, not a stop. Run `pnpm josh test:declared` to see the files it names. The procedure is `prompts/collaboration-workflow/rule-delivery.md` \u2192 "\u914D\u9001\u3055\u308C\u3066\u3044\u308B\u898F\u5247". This fires once per run, so reissuing will not repeat on the call in hand.';
2396
- var ROW13 = { id: "test-declared", is_trigger: is_untested_commit, reason: REASON };
2397
- var test_declared_commit = { REASON, ROW: ROW13, is_untested_commit };
2918
+ var ROW17 = { id: "test-declared", is_trigger: is_untested_commit, reason: REASON };
2919
+ var test_declared_commit = { REASON, ROW: ROW17 };
2398
2920
 
2399
2921
  // scripts/rules/third-party-write.ts
2400
2922
  function is_third_party_write_segment(segment, session_owner) {
@@ -2410,87 +2932,24 @@ function writes_third_party(command, resolve_owner = repo_party.current_owner) {
2410
2932
  return targets.some((segment) => is_third_party_write_segment(segment, session_owner));
2411
2933
  }
2412
2934
  var THIRD_PARTY_WRITE_REASON = '\u26D4 third-party write: this `gh api` call writes to a repository whose owner is not this session \u2014 a tracker we do not own is Tier C, and every write there (Issue, comment, PR, Discussion, review) needs explicit current-turn user instruction; typing the target, or holding a correct diagnosis, is not that instruction (`CLAUDE.md` \u2192 "Third-party repositories are Tier C", `prompts/collaboration-workflow/upstream-interrupt.md`). Confirm the party with `pnpm josh repo:party <owner/repo>` \u2014 owner equality, computed not judged. A read (`-X GET`, or no field flag) passes untouched; only a write (`-f`/`-F`/`--field`/`--raw-field`/`--input`, or `-X POST|PATCH|PUT|DELETE`) is refused. Record the finding on our own Issue and draft the artifact for a person to post \u2014 do not publish it yourself. **This rule fires on every occurrence, not once per run.**';
2413
- var ROW14 = {
2935
+ var ROW18 = {
2414
2936
  id: "third-party-write",
2415
2937
  is_trigger: bash_triggers.on_bash_command((command) => writes_third_party(command)),
2416
2938
  reason: THIRD_PARTY_WRITE_REASON,
2417
2939
  decide: () => true
2418
2940
  };
2419
2941
  var third_party_write = {
2420
- ROW: ROW14,
2942
+ ROW: ROW18,
2421
2943
  THIRD_PARTY_WRITE_REASON,
2422
- is_third_party_write_segment,
2423
2944
  writes_third_party
2424
2945
  };
2425
2946
 
2426
- // scripts/rules/worktree-guard.ts
2427
- var CHECKOUT_SUBCOMMAND = "checkout";
2428
- var RESTORE_SUBCOMMAND = "restore";
2429
- var STASH_SUBCOMMAND = "stash";
2430
- var PATHSPEC_SEPARATOR = "--";
2431
- function is_worktree_checkout(args) {
2432
- return args.includes(PATHSPEC_SEPARATOR);
2433
- }
2434
- var STAGED_LONG = "--staged";
2435
- var STAGED_LETTER = "S";
2436
- var WORKTREE_LONG = "--worktree";
2437
- var WORKTREE_LETTER = "W";
2438
- function touches_worktree(args) {
2439
- const is_staged = args.some(
2440
- (argument) => argument === STAGED_LONG || git_argv.short_cluster_has(argument, STAGED_LETTER)
2441
- );
2442
- const is_worktree = args.some(
2443
- (argument) => argument === WORKTREE_LONG || git_argv.short_cluster_has(argument, WORKTREE_LETTER)
2444
- );
2445
- return !is_staged || is_worktree;
2446
- }
2447
- var PUSH_STASH = "push";
2448
- var MESSAGE_LONG = "--message";
2449
- var MESSAGE_SHORT_LETTER = "m";
2450
- var READ_ONLY_STASH = /* @__PURE__ */ new Set(["list", "show"]);
2451
- function has_message(args) {
2452
- return args.some(
2453
- (argument) => argument === MESSAGE_LONG || argument.startsWith(`${MESSAGE_LONG}=`) || git_argv.short_cluster_has(argument, MESSAGE_SHORT_LETTER)
2454
- );
2455
- }
2456
- function is_unauthorized_stash(args) {
2457
- const [stash_subcommand, ...rest] = args;
2458
- if (stash_subcommand === void 0) return true;
2459
- if (READ_ONLY_STASH.has(stash_subcommand)) return false;
2460
- if (stash_subcommand === PUSH_STASH) return !has_message(rest);
2461
- return true;
2462
- }
2463
- function is_unauthorized_segment(segment) {
2464
- const call = git_argv.parse(segment);
2465
- if (call === void 0) return false;
2466
- if (call.subcommand === CHECKOUT_SUBCOMMAND) return is_worktree_checkout(call.args);
2467
- if (call.subcommand === RESTORE_SUBCOMMAND) return touches_worktree(call.args);
2468
- return call.subcommand === STASH_SUBCOMMAND && is_unauthorized_stash(call.args);
2469
- }
2470
- function is_unauthorized_worktree_change(command) {
2471
- return shell_segments.segments_of(command).some((segment) => is_unauthorized_segment(segment));
2472
- }
2473
- var WORKTREE_MUTATION_REASON = '\u26D4 unauthorized working-tree change: `git checkout -- <path>`, `git restore <path>` and an unauthorized `git stash` mutate the working tree or the repository-wide stash every work tree shares, and none is on the `.claude/settings.json` deny list (`operating-rules.md`). Do not run them on your own judgement. A commit goes through `pnpm josh git`; a stash pop goes through `pnpm josh stash:pop "<message>"`, never a positional `git stash pop` a shared stack lets another lane divert. A stash push is authorized only inside a documented flow and only with a findable message \u2014 `git stash push -u -m "<message>"` \u2014 which this row allows; a bare `git stash`, a message-less push, or `pop` / `apply` / `drop` is refused. **This rule fires on every occurrence, not once per run.**';
2474
- var ROW15 = {
2475
- id: "worktree-mutation",
2476
- is_trigger: bash_triggers.on_bash_command(is_unauthorized_worktree_change),
2477
- reason: WORKTREE_MUTATION_REASON,
2478
- decide: () => true
2479
- };
2480
- var worktree_guard = {
2481
- ROW: ROW15,
2482
- WORKTREE_MUTATION_REASON,
2483
- is_unauthorized_stash,
2484
- is_unauthorized_worktree_change,
2485
- is_worktree_checkout,
2486
- touches_worktree
2487
- };
2488
-
2489
2947
  // scripts/rules/delivered-rules.ts
2490
2948
  var SWITCH_ENV_KEY = "JOSH_RULE_GUARD";
2491
2949
  var STAMP_PREFIX = "josh-rule-guard-";
2492
2950
  var { is_issue_filing, on_bash_command } = bash_triggers;
2493
- var WIP_CAP_REASON = "\u26D4 backlog WIP cap: count the target repository's open Issues before filing. With more than 30 open, close one first; nothing honestly closable means do not file. Two filings are exempt and proceed while stating the overage \u2014 one the run is blocked by, and an interrupt, decided by three tests rather than judgement: a verification answers wrongly, a documented workflow cannot complete, or data is lost or written outside the repository. Meeting none of the three, the finding is discretionary and waits. The count command and both procedures are in `prompts/collaboration-workflow/wip-cap.md`. Reissue this call once you have counted \u2014 it fires once per run and cannot repeat on the call in hand.";
2951
+ var WIP_CAP = 30;
2952
+ var WIP_CAP_REASON = `\u26D4 backlog WIP cap: count the target repository's open Issues before filing. With more than ${String(WIP_CAP)} open, close one first; nothing honestly closable means do not file. Two filings are exempt and proceed while stating the overage \u2014 one the run is blocked by, and an interrupt, decided by three tests rather than judgement: a verification answers wrongly, a documented workflow cannot complete, or data is lost or written outside the repository. Meeting none of the three, the finding is discretionary and waits. The count command and both procedures are in \`prompts/collaboration-workflow/wip-cap.md\`. Reissue this call once you have counted \u2014 it fires once per run and cannot repeat on the call in hand.`;
2494
2953
  var ISSUE_VIEW_COMMAND = new RegExp(String.raw`^gh\s+${gh_api.GH_FLAGS}issue\s+view\s`, "u");
2495
2954
  var ISSUE_BODY_PATH = /repos\/[^\s'"]*\/issues\/\d+(?=$|["'\s])/u;
2496
2955
  var FETCHES_COMMENTS = /--comments\b|--json\s[\w,]*\bcomments\b|\/comments\b/u;
@@ -2727,6 +3186,10 @@ var DELIVERED_RULES = [
2727
3186
  git_force.ROW,
2728
3187
  worktree_guard.ROW,
2729
3188
  file_body.ROW,
3189
+ // **The deny-list bypasses closed by argv and path rather than glob** (joshuafolkken/kit#2983) — an
3190
+ // index mutation, a recursive forced `rm` or destructive `gh` call, and a protected file. Each
3191
+ // claims a command or file no row above does and refuses every occurrence (`permission-guards.ts`).
3192
+ ...permission_guards.ROWS,
2730
3193
  // **The hand-written wait loop a lane child improvises over a backgrounded command's output**
2731
3194
  // (joshuafolkken/kit#2371). `early-heartbeat` refuses a bare `sleep` and stands down on any loop
2732
3195
  // keyword; this is the loop it left — a `while`/`until` that sleeps between probes of an output
@@ -2819,12 +3282,12 @@ function is_first_delivery(tail, call, delivered_at_ms, run2) {
2819
3282
  return delivered_at_ms === hook_decision.NEVER_MS && !will_batch_guard_refuse(tail, call, run2);
2820
3283
  }
2821
3284
  function delivery_decision(rule) {
2822
- const { decide: decide5, already_satisfied } = rule;
2823
- if (decide5 === void 0 && already_satisfied === void 0) return is_first_delivery;
3285
+ const { decide: decide6, already_satisfied } = rule;
3286
+ if (decide6 === void 0 && already_satisfied === void 0) return is_first_delivery;
2824
3287
  return function should_block(tail, call, delivered_at_ms, run2) {
2825
3288
  if (already_satisfied?.(tail, call) === true) return false;
2826
- if (decide5 === void 0) return true;
2827
- return decide5(call, run2, !will_batch_guard_refuse(tail, call, run2), delivered_at_ms);
3289
+ if (decide6 === void 0) return true;
3290
+ return decide6(call, run2, !will_batch_guard_refuse(tail, call, run2), delivered_at_ms);
2828
3291
  };
2829
3292
  }
2830
3293
  function guard_of(rule) {
@@ -2870,6 +3333,7 @@ var delivered_rules = {
2870
3333
  SHELL_BODY_REASON: SHELL_BODY_REASON2,
2871
3334
  SWITCH_ENV_KEY,
2872
3335
  THIRD_PARTY_WRITE_REASON: third_party_write.THIRD_PARTY_WRITE_REASON,
3336
+ WIP_CAP,
2873
3337
  WIP_CAP_REASON,
2874
3338
  WORKTREE_MUTATION_REASON: worktree_guard.WORKTREE_MUTATION_REASON,
2875
3339
  delivery,
@@ -2880,12 +3344,12 @@ var delivered_rules = {
2880
3344
  };
2881
3345
 
2882
3346
  // scripts/run/run-watcher-hook.ts
2883
- import { z as z17 } from "zod";
3347
+ import { z as z19 } from "zod";
2884
3348
 
2885
3349
  // scripts/run/run-progress-read.ts
2886
3350
  import { loadavg } from "node:os";
2887
3351
 
2888
- // scripts/git/git-gh-helpers.ts
3352
+ // scripts/gh/git-gh-helpers.ts
2889
3353
  function parse_pr_state_string(result) {
2890
3354
  const trimmed = result.trim();
2891
3355
  return trimmed.length > 0 ? trimmed : void 0;
@@ -2908,95 +3372,94 @@ function handle_pr_create_error(error) {
2908
3372
  }
2909
3373
  var git_gh_helpers = {
2910
3374
  parse_pr_state_string,
2911
- is_pr_already_exists_message,
2912
3375
  get_error_message_with_stderr,
2913
3376
  handle_pr_create_error
2914
3377
  };
2915
3378
 
2916
- // scripts/git/git-gh-issue-rest.ts
2917
- import { z as z7 } from "zod";
2918
-
2919
- // scripts/git/git-gh-rest-state.ts
2920
- var MERGED_STATE = "MERGED";
2921
- function to_gh_state(state) {
2922
- return state?.toUpperCase();
2923
- }
2924
-
2925
3379
  // scripts/git/schemas.ts
2926
- import { z as z6 } from "zod";
2927
- var package_name_schema = z6.object({ name: z6.string().min(1) });
2928
- var rollup_item_schema = z6.looseObject({
3380
+ import { z as z8 } from "zod";
3381
+ var package_name_schema = z8.object({ name: z8.string().min(1) });
3382
+ var rollup_item_schema = z8.looseObject({
2929
3383
  // eslint-disable-next-line @typescript-eslint/naming-convention -- GraphQL field name from GitHub API
2930
- __typename: z6.string().optional(),
2931
- state: z6.string().optional(),
2932
- status: z6.string().optional(),
2933
- conclusion: z6.string().optional(),
2934
- name: z6.string().optional(),
2935
- context: z6.string().optional()
3384
+ __typename: z8.string().optional(),
3385
+ state: z8.string().optional(),
3386
+ status: z8.string().optional(),
3387
+ conclusion: z8.string().optional(),
3388
+ name: z8.string().optional(),
3389
+ context: z8.string().optional()
2936
3390
  });
2937
- var pr_raw_schema = z6.object({
2938
- statusCheckRollup: z6.array(rollup_item_schema).optional(),
2939
- mergeStateStatus: z6.string().optional(),
2940
- reviewDecision: z6.string().optional()
3391
+ var pr_raw_schema = z8.object({
3392
+ statusCheckRollup: z8.array(rollup_item_schema).optional(),
3393
+ mergeStateStatus: z8.string().optional(),
3394
+ reviewDecision: z8.string().optional()
2941
3395
  });
2942
- var pull_comment_schema = z6.object({
2943
- body: z6.string().optional(),
2944
- html_url: z6.string().optional(),
2945
- user: z6.object({ login: z6.string().optional() }).optional()
3396
+ var pull_comment_schema = z8.object({
3397
+ body: z8.string().optional(),
3398
+ html_url: z8.string().optional(),
3399
+ user: z8.object({ login: z8.string().optional() }).optional()
2946
3400
  });
2947
- var ai_review_pull_comment_schema = z6.object({
2948
- body: z6.string().optional(),
2949
- url: z6.string().optional(),
2950
- author: z6.object({ login: z6.string().optional() }).optional()
3401
+ var ai_review_pull_comment_schema = z8.object({
3402
+ body: z8.string().optional(),
3403
+ url: z8.string().optional(),
3404
+ author: z8.object({ login: z8.string().optional() }).optional()
2951
3405
  });
2952
- var pr_info_schema = z6.object({
2953
- mergeable: z6.union([z6.boolean(), z6.string()]).nullable().optional(),
2954
- mergeStateStatus: z6.string().nullable().optional(),
2955
- state: z6.string().optional()
3406
+ var pr_info_schema = z8.object({
3407
+ mergeable: z8.union([z8.boolean(), z8.string()]).nullable().optional(),
3408
+ mergeStateStatus: z8.string().nullable().optional(),
3409
+ state: z8.string().optional()
2956
3410
  });
2957
- var epic_issue_schema = z6.object({
2958
- number: z6.number(),
2959
- body: z6.string().optional()
3411
+ var epic_issue_schema = z8.object({
3412
+ number: z8.number(),
3413
+ body: z8.string().optional()
2960
3414
  });
2961
- var blocking_issue_schema = z6.object({
2962
- number: z6.number(),
2963
- state: z6.string().optional(),
2964
- repository_url: z6.string().optional()
3415
+ var blocking_issue_schema = z8.object({
3416
+ number: z8.number(),
3417
+ state: z8.string().optional(),
3418
+ repository_url: z8.string().optional()
2965
3419
  });
2966
- var blocked_by_schema = z6.object({
2967
- nodes: z6.array(blocking_issue_schema).default([]),
2968
- totalCount: z6.number().optional()
3420
+ var blocked_by_schema = z8.object({
3421
+ nodes: z8.array(blocking_issue_schema).default([]),
3422
+ totalCount: z8.number().optional()
2969
3423
  }).optional();
2970
- var epic_child_schema = z6.object({
2971
- state: z6.string().optional(),
3424
+ var epic_child_schema = z8.object({
3425
+ state: z8.string().optional(),
2972
3426
  blockedBy: blocked_by_schema
2973
3427
  });
2974
- var rest_comment_schema = z6.looseObject({
2975
- body: z6.string().nullish(),
2976
- html_url: z6.string().optional(),
2977
- user: z6.looseObject({ login: z6.string().optional() }).nullish()
3428
+ var rest_comment_schema = z8.looseObject({
3429
+ body: z8.string().nullish(),
3430
+ html_url: z8.string().optional(),
3431
+ user: z8.looseObject({ login: z8.string().optional() }).nullish()
2978
3432
  });
2979
- var issue_label_schema = z6.object({ name: z6.string() });
2980
- var epic_subject_schema = z6.object({
2981
- number: z6.number(),
2982
- state: z6.string().optional(),
2983
- labels: z6.array(issue_label_schema).optional(),
2984
- body: z6.string().optional()
3433
+ var issue_label_schema = z8.object({ name: z8.string() });
3434
+ var epic_subject_schema = z8.object({
3435
+ number: z8.number(),
3436
+ state: z8.string().optional(),
3437
+ labels: z8.array(issue_label_schema).optional(),
3438
+ body: z8.string().optional()
2985
3439
  });
2986
- var open_issue_schema = z6.object({
2987
- number: z6.number(),
2988
- title: z6.string(),
2989
- labels: z6.array(issue_label_schema).optional(),
2990
- createdAt: z6.string(),
3440
+ var open_issue_schema = z8.object({
3441
+ number: z8.number(),
3442
+ title: z8.string(),
3443
+ labels: z8.array(issue_label_schema).optional(),
3444
+ createdAt: z8.string(),
2991
3445
  blockedBy: blocked_by_schema
2992
3446
  });
2993
3447
 
2994
- // scripts/git/git-gh-issue-rest.ts
2995
- var rest_issue_schema = z7.looseObject({
2996
- number: z7.number(),
2997
- issue_dependencies_summary: z7.looseObject({ total_blocked_by: z7.number().optional() }).nullish(),
3448
+ // scripts/gh/git-gh-issue-rest.ts
3449
+ import { z as z9 } from "zod";
3450
+
3451
+ // scripts/gh/git-gh-rest-state.ts
3452
+ var MERGED_STATE = "MERGED";
3453
+ function to_gh_state(state) {
3454
+ return state?.toUpperCase();
3455
+ }
3456
+
3457
+ // scripts/gh/git-gh-issue-rest.ts
3458
+ var rest_issue_schema = z9.looseObject({
3459
+ number: z9.number(),
3460
+ issue_dependencies_summary: z9.looseObject({ total_blocked_by: z9.number().optional() }).nullish(),
2998
3461
  // Present only on a pull request, which this endpoint serves as readily as an issue.
2999
- pull_request: z7.looseObject({ merged_at: z7.string().nullish() }).nullish()
3462
+ pull_request: z9.looseObject({ merged_at: z9.string().nullish() }).nullish()
3000
3463
  });
3001
3464
  var REPOSITORY_URL = /\/repos\/([\w.-]+\/[\w.-]+)$/u;
3002
3465
  var REPOSITORY_URL_GROUP = 1;
@@ -3090,7 +3553,7 @@ var git_gh_issue_rest = {
3090
3553
  to_field_text
3091
3554
  };
3092
3555
 
3093
- // scripts/git/git-gh-reachability.ts
3556
+ // scripts/gh/git-gh-reachability.ts
3094
3557
  var RATE_LIMITED_STATUS = 429;
3095
3558
  var SERVER_ERROR_FLOOR = 500;
3096
3559
  function is_retryable_status(status) {
@@ -3103,7 +3566,7 @@ function classify_status(status) {
3103
3566
  }
3104
3567
  var gh_reachability = { classify_status };
3105
3568
 
3106
- // scripts/git/git-gh-issue-read.ts
3569
+ // scripts/gh/git-gh-issue-read.ts
3107
3570
  async function read_blocked_by_listing(issue_number, repo, exact_total) {
3108
3571
  const json = await git_gh_exec.exec_gh_api({
3109
3572
  path: `${git_gh_api_path.blocked_by_api_path(issue_number, repo)}${git_gh_api_path.FULL_PAGE_QUERY}`
@@ -3209,9 +3672,9 @@ async function issue_get_labels_and_body(issue_number) {
3209
3672
  return await issue_view_json(issue_number, "number,state,labels,body");
3210
3673
  }
3211
3674
  async function issue_list_comments(issue_number) {
3212
- const path7 = `${git_gh_api_path.issue_comments_api_path(issue_number)}${git_gh_api_path.FULL_PAGE_QUERY}`;
3675
+ const path10 = `${git_gh_api_path.issue_comments_api_path(issue_number)}${git_gh_api_path.FULL_PAGE_QUERY}`;
3213
3676
  try {
3214
- return await git_gh_exec.exec_gh_api({ path: path7, should_paginate: true });
3677
+ return await git_gh_exec.exec_gh_api({ path: path10, should_paginate: true });
3215
3678
  } catch {
3216
3679
  return void 0;
3217
3680
  }
@@ -3252,7 +3715,7 @@ var git_gh_issue_read = {
3252
3715
  issue_list_comments
3253
3716
  };
3254
3717
 
3255
- // scripts/git/git-gh-issue-list.ts
3718
+ // scripts/gh/git-gh-issue-list.ts
3256
3719
  var PER_PAGE = 100;
3257
3720
  var FIRST_PAGE = 1;
3258
3721
  var DEFAULT_STATE = "open";
@@ -3286,8 +3749,8 @@ function is_selected(rest, request) {
3286
3749
  return !git_gh_issue_rest.is_pull_request(rest) && matches_body(rest, request.body_term);
3287
3750
  }
3288
3751
  async function fetch_page(request, page) {
3289
- const path7 = listing_path(request, page);
3290
- const rows = git_gh_issue_rest.parse_rest_issues(await git_gh_exec.exec_gh_api({ path: path7 }));
3752
+ const path10 = listing_path(request, page);
3753
+ const rows = git_gh_issue_rest.parse_rest_issues(await git_gh_exec.exec_gh_api({ path: path10 }));
3291
3754
  return {
3292
3755
  selected: rows.filter((row) => is_selected(row, request)),
3293
3756
  is_full: rows.length >= PER_PAGE
@@ -3337,9 +3800,9 @@ var git_gh_issue_list = {
3337
3800
  issue_list
3338
3801
  };
3339
3802
 
3340
- // scripts/git/git-gh-issue-write.ts
3803
+ // scripts/gh/git-gh-issue-write.ts
3341
3804
  var PATCH_METHOD = "PATCH";
3342
- var DELETE_METHOD = "DELETE";
3805
+ var DELETE_METHOD2 = "DELETE";
3343
3806
  var HTML_URL_FILTER = ".html_url";
3344
3807
  var ID_FILTER = ".id";
3345
3808
  var LABELS_SEGMENT = "/labels";
@@ -3427,7 +3890,7 @@ async function issue_remove_label(issue_number, label) {
3427
3890
  const labels_path = `${git_gh_api_path.issue_api_path(issue_number)}${LABELS_SEGMENT}`;
3428
3891
  await git_gh_exec.exec_gh_api({
3429
3892
  path: `${labels_path}/${encodeURIComponent(label)}`,
3430
- method: DELETE_METHOD
3893
+ method: DELETE_METHOD2
3431
3894
  });
3432
3895
  }
3433
3896
  async function read_issue_id(issue_number) {
@@ -3456,7 +3919,7 @@ async function issue_remove_blocked_by(issue_number, blocker) {
3456
3919
  const relations_path = git_gh_api_path.blocked_by_api_path(issue_number);
3457
3920
  await git_gh_exec.exec_gh_api({
3458
3921
  path: `${relations_path}/${String(issue_id)}`,
3459
- method: DELETE_METHOD
3922
+ method: DELETE_METHOD2
3460
3923
  });
3461
3924
  });
3462
3925
  }
@@ -3474,7 +3937,7 @@ var git_gh_issue_write = {
3474
3937
  issue_remove_blocked_by
3475
3938
  };
3476
3939
 
3477
- // scripts/git/git-gh-issue.ts
3940
+ // scripts/gh/git-gh-issue.ts
3478
3941
  var NUMBER_AND_BODY_FIELDS = "number,body";
3479
3942
  var BACKLOG_SCAN_FIELDS = `number,title,body,${BLOCKED_BY_COUNT_FIELD}`;
3480
3943
  var NUMBER_TITLE_AND_LABELS_FIELDS = "number,title,labels";
@@ -3530,18 +3993,18 @@ var git_gh_issue = {
3530
3993
  // scripts/ci/pr-classification.ts
3531
3994
  import { readFileSync as readFileSync5 } from "node:fs";
3532
3995
  import { fileURLToPath as fileURLToPath2 } from "node:url";
3533
- import { z as z8 } from "zod";
3996
+ import { z as z10 } from "zod";
3534
3997
  var CLASSIFICATION_SET = new Set(RELEASE_CLASSIFICATION_NAMES);
3535
3998
  var ISSUE_BUG_LABEL = "bug";
3536
3999
  var DECLARATION_PREFIX = "- \u30EA\u30EA\u30FC\u30B9\u5206\u985E: ";
3537
4000
  var DECLARATION = new RegExp(`^${DECLARATION_PREFIX}(.+)$`, "gmu");
3538
4001
  var LEGACY_LABELS = /* @__PURE__ */ new Set(["semver-major", "semver-minor"]);
3539
- var LABEL = z8.object({ name: z8.string() });
3540
- var USER = z8.object({ login: z8.string() });
3541
- var PULL_REQUEST = z8.object({ number: z8.number(), user: USER });
3542
- var EVENT = z8.object({
4002
+ var LABEL = z10.object({ name: z10.string() });
4003
+ var USER = z10.object({ login: z10.string() });
4004
+ var PULL_REQUEST = z10.object({ number: z10.number(), user: USER });
4005
+ var EVENT = z10.object({
3543
4006
  pull_request: PULL_REQUEST,
3544
- repository: z8.object({ full_name: z8.string() })
4007
+ repository: z10.object({ full_name: z10.string() })
3545
4008
  });
3546
4009
  function classification_error(labels, author) {
3547
4010
  const legacy = labels.filter((label) => LEGACY_LABELS.has(label.toLowerCase()));
@@ -3564,7 +4027,7 @@ function release_candidates(candidates) {
3564
4027
  return candidates.filter((candidate) => candidate !== ENHANCEMENT_LABEL);
3565
4028
  }
3566
4029
  function issue_candidates(issue_json) {
3567
- const issue = z8.object({ labels: z8.array(LABEL), body: z8.string().nullable() }).parse(JSON.parse(issue_json));
4030
+ const issue = z10.object({ labels: z10.array(LABEL), body: z10.string().nullable() }).parse(JSON.parse(issue_json));
3568
4031
  const names = issue.labels.map((label) => label.name.toLowerCase());
3569
4032
  const declared = [...(issue.body ?? "").matchAll(DECLARATION)].map((match) => match[1] ?? "");
3570
4033
  const candidates = [...release_candidates([...names, ...declared].filter(is_classification))];
@@ -3587,9 +4050,9 @@ function select_issue_classification(issue_json) {
3587
4050
  return label;
3588
4051
  }
3589
4052
  function fetch_current_labels(repository, pull_number) {
3590
- const path7 = `repos/${repository}/issues/${String(pull_number)}/labels`;
4053
+ const path10 = `repos/${repository}/issues/${String(pull_number)}/labels`;
3591
4054
  try {
3592
- const names = git_gh_exec.exec_gh_api_sync({ path: path7, jq_filter: ".[].name" });
4055
+ const names = git_gh_exec.exec_gh_api_sync({ path: path10, jq_filter: ".[].name" });
3593
4056
  return names.split("\n").filter((name) => name !== "");
3594
4057
  } catch (error) {
3595
4058
  const detail = error_text.message_of(error);
@@ -3638,32 +4101,32 @@ async function poll_until(is_done, options) {
3638
4101
  }
3639
4102
  var poll = { poll_until, sleep };
3640
4103
 
3641
- // scripts/git/git-gh-pr.ts
3642
- import { z as z12 } from "zod";
4104
+ // scripts/gh/git-gh-pr.ts
4105
+ import { z as z14 } from "zod";
3643
4106
 
3644
- // scripts/git/git-gh-pr-rest.ts
3645
- import { z as z9 } from "zod";
3646
- var rest_repo_schema = z9.looseObject({ full_name: z9.string().optional() }).nullish();
3647
- var rest_pull_side_schema = z9.looseObject({ repo: rest_repo_schema });
3648
- var rest_pull_schema = z9.looseObject({
3649
- number: z9.number(),
3650
- html_url: z9.string().optional(),
3651
- body: z9.string().nullish(),
3652
- state: z9.string().optional(),
3653
- merged: z9.boolean().nullish(),
3654
- merged_at: z9.string().nullish(),
3655
- mergeable: z9.boolean().nullish(),
3656
- mergeable_state: z9.string().optional(),
4107
+ // scripts/gh/git-gh-pr-rest.ts
4108
+ import { z as z11 } from "zod";
4109
+ var rest_repo_schema = z11.looseObject({ full_name: z11.string().optional() }).nullish();
4110
+ var rest_pull_side_schema = z11.looseObject({ repo: rest_repo_schema });
4111
+ var rest_pull_schema = z11.looseObject({
4112
+ number: z11.number(),
4113
+ html_url: z11.string().optional(),
4114
+ body: z11.string().nullish(),
4115
+ state: z11.string().optional(),
4116
+ merged: z11.boolean().nullish(),
4117
+ merged_at: z11.string().nullish(),
4118
+ mergeable: z11.boolean().nullish(),
4119
+ mergeable_state: z11.string().optional(),
3657
4120
  // `sha` is the head commit, which is what both halves of the merge-gate rollup are keyed by —
3658
4121
  // REST hangs the check runs and the status contexts off the commit rather than off the pull
3659
4122
  // request (joshuafolkken/kit#1028).
3660
- head: z9.looseObject({ ref: z9.string().optional(), sha: z9.string().optional(), repo: rest_repo_schema }).nullish(),
4123
+ head: z11.looseObject({ ref: z11.string().optional(), sha: z11.string().optional(), repo: rest_repo_schema }).nullish(),
3661
4124
  base: rest_pull_side_schema.nullish(),
3662
4125
  // `node_id` is what the GraphQL auto-merge mutation addresses a pull request by, and `auto_merge`
3663
4126
  // is `null` until auto-merge is enabled — both read by `git-gh-pr-auto-merge.ts`
3664
4127
  // (joshuafolkken/kit#2497).
3665
- node_id: z9.string().optional(),
3666
- auto_merge: z9.looseObject({}).nullish()
4128
+ node_id: z11.string().optional(),
4129
+ auto_merge: z11.looseObject({}).nullish()
3667
4130
  });
3668
4131
  var NOT_A_PULL_MESSAGE = "gh api answered something other than a pull request object";
3669
4132
  var NOT_A_PULL_LISTING_MESSAGE = "gh api answered something other than a pull request listing";
@@ -3723,7 +4186,7 @@ var git_gh_pr_rest = {
3723
4186
  to_pr_comments
3724
4187
  };
3725
4188
 
3726
- // scripts/git/git-gh-pr-read.ts
4189
+ // scripts/gh/git-gh-pr-read.ts
3727
4190
  var pr_number_by_branch = /* @__PURE__ */ new Map();
3728
4191
  var LOOKUP_QUERY = "state=all&sort=created&direction=desc&per_page=100";
3729
4192
  var COMMENTS_QUERY = FULL_PAGE_QUERY;
@@ -3810,6 +4273,15 @@ async function pr_get_url(branch_name) {
3810
4273
  if (pull?.html_url === void 0) return void 0;
3811
4274
  return git_gh_helpers.parse_pr_state_string(pull.html_url);
3812
4275
  }
4276
+ async function pr_get_merge_state(branch_name) {
4277
+ const pull = await read_pull_of_branch(branch_name);
4278
+ if (pull === void 0) return void 0;
4279
+ return {
4280
+ is_merged: git_gh_pr_rest.is_merged(pull),
4281
+ merged_at: pull.merged_at ?? void 0,
4282
+ head_sha: pull.head?.sha
4283
+ };
4284
+ }
3813
4285
  async function pr_get_body(branch_name) {
3814
4286
  const pull = await read_pull_of_branch(branch_name);
3815
4287
  const body = pull?.body;
@@ -3823,9 +4295,9 @@ async function pr_view(branch_name) {
3823
4295
  async function read_comments(branch_name, to_path, to_json) {
3824
4296
  const pr_number = await resolve_pr_number(branch_name);
3825
4297
  if (pr_number === void 0) return void 0;
3826
- const path7 = `${to_path(String(pr_number))}${COMMENTS_QUERY}`;
4298
+ const path10 = `${to_path(String(pr_number))}${COMMENTS_QUERY}`;
3827
4299
  try {
3828
- return to_json(await git_gh_exec.exec_gh_api({ path: path7, should_paginate: true }));
4300
+ return to_json(await git_gh_exec.exec_gh_api({ path: path10, should_paginate: true }));
3829
4301
  } catch {
3830
4302
  return void 0;
3831
4303
  }
@@ -3847,20 +4319,21 @@ var git_gh_pr_read = {
3847
4319
  pr_get_number,
3848
4320
  pr_get_url,
3849
4321
  pr_get_body,
4322
+ pr_get_merge_state,
3850
4323
  pr_view,
3851
4324
  pr_get_comments,
3852
4325
  pr_get_review_comments
3853
4326
  };
3854
4327
 
3855
- // scripts/git/git-gh-pr-review.ts
3856
- import { z as z10 } from "zod";
4328
+ // scripts/gh/git-gh-pr-review.ts
4329
+ import { z as z12 } from "zod";
3857
4330
  var REVIEW_APPROVED = "APPROVED";
3858
4331
  var REVIEW_CHANGES_REQUESTED = "CHANGES_REQUESTED";
3859
4332
  var REVIEW_NONE = "";
3860
4333
  var STATE_CHANGING_REVIEWS = /* @__PURE__ */ new Set([REVIEW_APPROVED, REVIEW_CHANGES_REQUESTED]);
3861
- var rest_review_schema = z10.looseObject({
3862
- state: z10.string().optional(),
3863
- user: z10.looseObject({ login: z10.string().optional() }).nullish()
4334
+ var rest_review_schema = z12.looseObject({
4335
+ state: z12.string().optional(),
4336
+ user: z12.looseObject({ login: z12.string().optional() }).nullish()
3864
4337
  });
3865
4338
  var NOT_A_REVIEW_LISTING = "gh api answered something other than a review listing";
3866
4339
  function parse_rest_reviews(reviews_json) {
@@ -3890,21 +4363,21 @@ function to_review_decision(reviews_json) {
3890
4363
  if (latest.has(REVIEW_CHANGES_REQUESTED)) return REVIEW_CHANGES_REQUESTED;
3891
4364
  return latest.has(REVIEW_APPROVED) ? REVIEW_APPROVED : REVIEW_NONE;
3892
4365
  }
3893
- var git_gh_pr_review = { to_review_decision, parse_rest_reviews };
4366
+ var git_gh_pr_review = { to_review_decision };
3894
4367
 
3895
- // scripts/git/git-gh-pr-rollup.ts
3896
- import { z as z11 } from "zod";
4368
+ // scripts/gh/git-gh-pr-rollup.ts
4369
+ import { z as z13 } from "zod";
3897
4370
  var STATUS_CONTEXT_TYPE_NAME = "StatusContext";
3898
4371
  var TYPE_NAME_KEY = "__typename";
3899
- var rollup_element_schema = z11.looseObject({});
3900
- var check_runs_page_schema = z11.looseObject({
4372
+ var rollup_element_schema = z13.looseObject({});
4373
+ var check_runs_page_schema = z13.looseObject({
3901
4374
  // Required, not optional: GitHub always names the key, and accepting a page without one would
3902
4375
  // answer an empty rollup — which `git-pr-followup.ts` reports as "this branch has no checks".
3903
- check_runs: z11.array(rollup_element_schema)
4376
+ check_runs: z13.array(rollup_element_schema)
3904
4377
  });
3905
- var id_holder_schema = z11.object({ id: z11.number() });
3906
- var status_page_schema = z11.looseObject({
3907
- statuses: z11.array(rollup_element_schema)
4378
+ var id_holder_schema = z13.object({ id: z13.number() });
4379
+ var status_page_schema = z13.looseObject({
4380
+ statuses: z13.array(rollup_element_schema)
3908
4381
  });
3909
4382
  var NOT_A_CHECK_RUNS_LISTING = "gh api answered something other than a check run listing";
3910
4383
  var NOT_A_STATUS_LISTING = "gh api answered something other than a commit status listing";
@@ -3965,23 +4438,21 @@ function to_status_check_rollup(input) {
3965
4438
  ];
3966
4439
  }
3967
4440
  var git_gh_pr_rollup = {
3968
- to_check_run_items,
3969
- to_status_context_items,
3970
4441
  to_status_check_rollup
3971
4442
  };
3972
4443
 
3973
- // scripts/git/git-gh-pr-snapshot.ts
4444
+ // scripts/gh/git-gh-pr-snapshot.ts
3974
4445
  var NO_HEAD_SHA_MESSAGE = "gh api answered a pull request with no head commit";
3975
- async function read_object_pages(path7) {
4446
+ async function read_object_pages(path10) {
3976
4447
  return await git_gh_exec.exec_gh_api({
3977
- path: `${path7}${FULL_PAGE_QUERY}`,
4448
+ path: `${path10}${FULL_PAGE_QUERY}`,
3978
4449
  should_paginate: true,
3979
4450
  should_slurp: true
3980
4451
  });
3981
4452
  }
3982
- async function read_array_pages(path7) {
4453
+ async function read_array_pages(path10) {
3983
4454
  return await git_gh_exec.exec_gh_api({
3984
- path: `${path7}${FULL_PAGE_QUERY}`,
4455
+ path: `${path10}${FULL_PAGE_QUERY}`,
3985
4456
  should_paginate: true
3986
4457
  });
3987
4458
  }
@@ -3998,8 +4469,8 @@ async function read_status_check_rollup(commit_sha) {
3998
4469
  return git_gh_pr_rollup.to_status_check_rollup({ check_runs_json, status_json });
3999
4470
  }
4000
4471
  async function pr_get_review_decision(pr_number) {
4001
- const path7 = git_gh_api_path.pull_reviews_api_path(String(pr_number));
4002
- return git_gh_pr_review.to_review_decision(await read_array_pages(path7));
4472
+ const path10 = git_gh_api_path.pull_reviews_api_path(String(pr_number));
4473
+ return git_gh_pr_review.to_review_decision(await read_array_pages(path10));
4003
4474
  }
4004
4475
  async function build_checks_fields(pull) {
4005
4476
  return {
@@ -4029,7 +4500,7 @@ var git_gh_pr_snapshot = {
4029
4500
  pr_get_review_decision
4030
4501
  };
4031
4502
 
4032
- // scripts/git/git-gh-pr.ts
4503
+ // scripts/gh/git-gh-pr.ts
4033
4504
  var HTML_URL_FILTER2 = ".html_url";
4034
4505
  var PUT_METHOD = "PUT";
4035
4506
  var PATCH_METHOD2 = "PATCH";
@@ -4040,7 +4511,7 @@ var MERGE_READ_BACK_ATTEMPTS = 3;
4040
4511
  var MERGE_READ_BACK_INTERVAL_MS = 1e3;
4041
4512
  var PR_NUMBER_PATTERN = /\/pull\/([1-9]\d*)$/u;
4042
4513
  var LABELS_SEGMENT2 = "/labels";
4043
- var PR_LABELS = z12.array(z12.object({ name: z12.string() }));
4514
+ var PR_LABELS = z14.array(z14.object({ name: z14.string() }));
4044
4515
  async function add_pr_classification(number, label) {
4045
4516
  await git_gh_exec.exec_gh_api({
4046
4517
  path: `${git_gh_api_path.issue_api_path(number)}${LABELS_SEGMENT2}`,
@@ -4145,7 +4616,7 @@ var git_gh_pr = {
4145
4616
  pr_update_body
4146
4617
  };
4147
4618
 
4148
- // scripts/git/git-gh-pr-auto-merge.ts
4619
+ // scripts/gh/git-gh-pr-auto-merge.ts
4149
4620
  var GRAPHQL_PATH = "graphql";
4150
4621
  var OPEN_PULLS_QUERY = `${git_gh_api_path.FULL_PAGE_QUERY}&state=open`;
4151
4622
  var MISSING_NODE_ID_MESSAGE = "gh api answered a pull request without a node_id";
@@ -4191,7 +4662,7 @@ var git_gh_pr_auto_merge = {
4191
4662
  pr_list_open_with_head_prefix
4192
4663
  };
4193
4664
 
4194
- // scripts/git/git-gh-repo.ts
4665
+ // scripts/gh/git-gh-repo.ts
4195
4666
  async function repo_get_name_with_owner() {
4196
4667
  try {
4197
4668
  const result = await git_gh_exec.exec_gh_api({
@@ -4207,7 +4678,7 @@ var git_gh_repo = {
4207
4678
  repo_get_name_with_owner
4208
4679
  };
4209
4680
 
4210
- // scripts/git/git-pr-checks-parse.ts
4681
+ // scripts/gh/git-pr-checks-parse.ts
4211
4682
  var CHECK_STATUS_PASS = "pass";
4212
4683
  var CHECK_STATUS_PENDING = "pending";
4213
4684
  var CHECK_STATUS_FAIL = "fail";
@@ -4251,20 +4722,13 @@ function read_rollup_array(parsed) {
4251
4722
  if (!result.success) return [];
4252
4723
  return result.data.statusCheckRollup ?? [];
4253
4724
  }
4254
- function parse_json_safe(raw_json) {
4255
- try {
4256
- return JSON.parse(raw_json);
4257
- } catch {
4258
- return void 0;
4259
- }
4260
- }
4261
4725
  function parse_rollup_item(item) {
4262
4726
  const name = read_string(item[KEY_NAME]) ?? read_string(item[KEY_CONTEXT]);
4263
4727
  if (name === void 0) return void 0;
4264
4728
  return { name, status: parse_rollup_status(item) };
4265
4729
  }
4266
4730
  function parse_rollup_checks(raw_json) {
4267
- const parsed = parse_json_safe(raw_json);
4731
+ const parsed = json_value.parse_or_undefined(raw_json);
4268
4732
  const rollup = read_rollup_array(parsed);
4269
4733
  const checks = [];
4270
4734
  for (const item of rollup) {
@@ -4274,7 +4738,7 @@ function parse_rollup_checks(raw_json) {
4274
4738
  return checks;
4275
4739
  }
4276
4740
  function parse_pr_state_snapshot(raw_json) {
4277
- const parsed = parse_json_safe(raw_json);
4741
+ const parsed = json_value.parse_or_undefined(raw_json);
4278
4742
  const result = pr_raw_schema.safeParse(parsed);
4279
4743
  const data = result.success ? result.data : void 0;
4280
4744
  return {
@@ -4284,14 +4748,14 @@ function parse_pr_state_snapshot(raw_json) {
4284
4748
  };
4285
4749
  }
4286
4750
 
4287
- // scripts/git/git-pr-checks-eval.ts
4751
+ // scripts/gh/git-pr-checks-eval.ts
4288
4752
  var DEFAULT_REQUIRED_CHECKS = ["SonarQube"];
4289
4753
  var CODERABBIT_CHECK_NAME = "CodeRabbit";
4290
4754
  var REQUIRED_CHECKS_ENV_VAR = "JOSH_REQUIRED_CHECKS";
4291
4755
  function parse_required_checks() {
4292
4756
  const raw = process.env[REQUIRED_CHECKS_ENV_VAR];
4293
4757
  if (!raw) return DEFAULT_REQUIRED_CHECKS;
4294
- return raw.split(",").map((check3) => check3.trim()).filter((check3) => check3.length > 0);
4758
+ return raw.split(",").map((check4) => check4.trim()).filter((check4) => check4.length > 0);
4295
4759
  }
4296
4760
  var REQUIRED_CHECKS = parse_required_checks();
4297
4761
  var MERGE_STATE_CLEAN = "CLEAN";
@@ -4308,7 +4772,7 @@ function is_required_match(check_name, required_name) {
4308
4772
  return check_name.startsWith(`${required_name}${CHECK_SUITE_SEPARATOR}`);
4309
4773
  }
4310
4774
  function find_required_check(checks, required_name) {
4311
- return checks.find((check3) => is_required_match(check3.name, required_name));
4775
+ return checks.find((check4) => is_required_match(check4.name, required_name));
4312
4776
  }
4313
4777
  function read_required_statuses(checks) {
4314
4778
  return REQUIRED_CHECKS.map(
@@ -4338,19 +4802,19 @@ function is_coderabbit_check(check_name) {
4338
4802
  }
4339
4803
  function is_unstable_only_from_coderabbit(snapshot) {
4340
4804
  if (snapshot.merge_state_status !== MERGE_STATE_UNSTABLE) return false;
4341
- const non_passing = snapshot.rollup.filter((check3) => check3.status !== CHECK_STATUS_PASS);
4805
+ const non_passing = snapshot.rollup.filter((check4) => check4.status !== CHECK_STATUS_PASS);
4342
4806
  if (non_passing.length === 0) return false;
4343
- return non_passing.every((check3) => is_coderabbit_check(check3.name));
4807
+ return non_passing.every((check4) => is_coderabbit_check(check4.name));
4344
4808
  }
4345
4809
  function is_required_check(check_name) {
4346
4810
  return REQUIRED_CHECKS.some((required) => is_required_match(check_name, required));
4347
4811
  }
4348
- function is_blocking_failure(check3) {
4349
- if (check3.status !== CHECK_STATUS_FAIL) return false;
4350
- return !is_coderabbit_check(check3.name) || is_required_check(check3.name);
4812
+ function is_blocking_failure(check4) {
4813
+ if (check4.status !== CHECK_STATUS_FAIL) return false;
4814
+ return !is_coderabbit_check(check4.name) || is_required_check(check4.name);
4351
4815
  }
4352
4816
  function collect_blocking_failures(snapshot) {
4353
- return snapshot.rollup.filter((check3) => is_blocking_failure(check3)).map((check3) => check3.name);
4817
+ return snapshot.rollup.filter((check4) => is_blocking_failure(check4)).map((check4) => check4.name);
4354
4818
  }
4355
4819
  function is_mergeable_state(snapshot) {
4356
4820
  if (is_merge_state_clean(snapshot.merge_state_status)) return true;
@@ -4386,7 +4850,7 @@ function is_review_decision_decisive(snapshot) {
4386
4850
  return evaluate_pr_state(snapshot) !== "pending";
4387
4851
  }
4388
4852
 
4389
- // scripts/git/git-pr-checks.ts
4853
+ // scripts/gh/git-pr-checks.ts
4390
4854
  var SECONDS_TO_MS = 1e3;
4391
4855
  var CHECK_WAIT_INTERVAL_MS = 1e4;
4392
4856
  var DEFAULT_TIMEOUT_SECONDS = 1920;
@@ -4489,25 +4953,25 @@ async function default_fetch_pr_state(branch_name, should_read_review_decision =
4489
4953
  return { ...snapshot, review_decision: read_string(decision) };
4490
4954
  }
4491
4955
 
4492
- // scripts/git/git-pr-checks-watch.ts
4956
+ // scripts/gh/git-pr-checks-watch.ts
4493
4957
  var PR_CHECKS_WATCH_TIMEOUT_MS = 12e4;
4494
4958
  var WATCH_TIMED_OUT_NOTE = "\u23F1\uFE0F pr checks --watch timed out.";
4495
4959
  var NO_CHECKS_MESSAGE = "gh api reported no checks on the branch";
4496
4960
  var CHECKS_FAILED_MESSAGE = "gh api reported a failing check on the branch";
4497
- function is_awaited_check(check3) {
4498
- return !is_coderabbit_check(check3.name) || is_required_check(check3.name);
4961
+ function is_awaited_check(check4) {
4962
+ return !is_coderabbit_check(check4.name) || is_required_check(check4.name);
4499
4963
  }
4500
4964
  function evaluate_checks_settled(snapshot) {
4501
- const awaited = snapshot.rollup.filter((check3) => is_awaited_check(check3));
4965
+ const awaited = snapshot.rollup.filter((check4) => is_awaited_check(check4));
4502
4966
  const considered = awaited.length === 0 ? snapshot.rollup : awaited;
4503
- if (considered.length === 0 || considered.some((check3) => check3.status === CHECK_STATUS_PENDING)) {
4967
+ if (considered.length === 0 || considered.some((check4) => check4.status === CHECK_STATUS_PENDING)) {
4504
4968
  return "pending";
4505
4969
  }
4506
- return snapshot.rollup.some((check3) => check3.status === CHECK_STATUS_FAIL) ? "failure" : "success";
4970
+ return snapshot.rollup.some((check4) => check4.status === CHECK_STATUS_FAIL) ? "failure" : "success";
4507
4971
  }
4508
4972
  function describe_checks_failure(snapshot) {
4509
- const failed = snapshot.rollup.filter((check3) => check3.status === CHECK_STATUS_FAIL);
4510
- return `${CHECKS_FAILED_MESSAGE}: ${failed.map((check3) => check3.name).join(", ")}`;
4973
+ const failed = snapshot.rollup.filter((check4) => check4.status === CHECK_STATUS_FAIL);
4974
+ return `${CHECKS_FAILED_MESSAGE}: ${failed.map((check4) => check4.name).join(", ")}`;
4511
4975
  }
4512
4976
  var SHOULD_NEVER_READ_REVIEW_DECISION = () => false;
4513
4977
  var CHECKS_SETTLED_EVALUATOR = {
@@ -4545,7 +5009,7 @@ async function pr_checks_watch(branch_name) {
4545
5009
  }
4546
5010
  var git_pr_checks_watch = { pr_checks_watch };
4547
5011
 
4548
- // scripts/git/git-gh-command.ts
5012
+ // scripts/gh/git-gh-command.ts
4549
5013
  var git_gh_command = {
4550
5014
  ...git_gh_pr,
4551
5015
  ...git_gh_pr_auto_merge,
@@ -4610,7 +5074,6 @@ var epic_busy = {
4610
5074
  unreadable_message,
4611
5075
  truncated_message,
4612
5076
  busy_reason,
4613
- format_holders,
4614
5077
  is_parked,
4615
5078
  parse_listing,
4616
5079
  read_repository
@@ -4619,28 +5082,28 @@ var epic_busy = {
4619
5082
  // scripts/run/run-liveness.ts
4620
5083
  import { readFileSync as readFileSync6, realpathSync, statSync } from "node:fs";
4621
5084
  import { homedir, tmpdir } from "node:os";
4622
- import path6 from "node:path";
5085
+ import path8 from "node:path";
4623
5086
  import { setTimeout as sleep2 } from "node:timers/promises";
4624
5087
 
4625
5088
  // scripts/agent/agent-event.ts
4626
- import { z as z14 } from "zod";
5089
+ import { z as z16 } from "zod";
4627
5090
 
4628
5091
  // scripts/agent/claude-result-event.ts
4629
- import { z as z13 } from "zod";
4630
- var RESULT_EVENT_SCHEMA = z13.looseObject({
4631
- type: z13.literal("result"),
4632
- is_error: z13.unknown().optional(),
4633
- subtype: z13.unknown().optional(),
4634
- num_turns: z13.unknown().optional(),
4635
- permission_denials: z13.unknown().optional(),
4636
- result: z13.unknown().optional(),
4637
- session_id: z13.unknown().optional(),
4638
- usage: z13.unknown().optional()
5092
+ import { z as z15 } from "zod";
5093
+ var RESULT_EVENT_SCHEMA = z15.looseObject({
5094
+ type: z15.literal("result"),
5095
+ is_error: z15.unknown().optional(),
5096
+ subtype: z15.unknown().optional(),
5097
+ num_turns: z15.unknown().optional(),
5098
+ permission_denials: z15.unknown().optional(),
5099
+ result: z15.unknown().optional(),
5100
+ session_id: z15.unknown().optional(),
5101
+ usage: z15.unknown().optional()
4639
5102
  });
4640
- var USAGE_SCHEMA = z13.looseObject({
4641
- input_tokens: z13.unknown().optional(),
4642
- cache_read_input_tokens: z13.unknown().optional(),
4643
- output_tokens: z13.unknown().optional()
5103
+ var USAGE_SCHEMA = z15.looseObject({
5104
+ input_tokens: z15.unknown().optional(),
5105
+ cache_read_input_tokens: z15.unknown().optional(),
5106
+ output_tokens: z15.unknown().optional()
4644
5107
  });
4645
5108
  function usable_reason(value) {
4646
5109
  return typeof value === "string" && value.trim() !== "" ? value : void 0;
@@ -4661,7 +5124,7 @@ function usage_of(value) {
4661
5124
  };
4662
5125
  return Object.values(usage).some((count) => count !== void 0) ? usage : void 0;
4663
5126
  }
4664
- function decode2(value) {
5127
+ function decode(value) {
4665
5128
  const parsed = RESULT_EVENT_SCHEMA.safeParse(value);
4666
5129
  if (!parsed.success) return void 0;
4667
5130
  const is_error = parsed.data.is_error === true;
@@ -4676,34 +5139,34 @@ function decode2(value) {
4676
5139
  usage: usage_of(parsed.data.usage)
4677
5140
  };
4678
5141
  }
4679
- var claude_result_event = { decode: decode2 };
5142
+ var claude_result_event = { decode };
4680
5143
 
4681
5144
  // scripts/agent/agent-event.ts
4682
- var TEXT_BLOCK_SCHEMA = z14.looseObject({ type: z14.literal("text"), text: z14.string() });
4683
- var CLAUDE_MESSAGE_SCHEMA = z14.looseObject({ content: z14.array(z14.unknown()).optional() });
4684
- var CLAUDE_INIT_SCHEMA = z14.looseObject({ type: z14.literal("system"), subtype: z14.literal("init") });
4685
- var CLAUDE_ASSISTANT_SCHEMA = z14.looseObject({
4686
- type: z14.literal("assistant"),
5145
+ var TEXT_BLOCK_SCHEMA = z16.looseObject({ type: z16.literal("text"), text: z16.string() });
5146
+ var CLAUDE_MESSAGE_SCHEMA = z16.looseObject({ content: z16.array(z16.unknown()).optional() });
5147
+ var CLAUDE_INIT_SCHEMA = z16.looseObject({ type: z16.literal("system"), subtype: z16.literal("init") });
5148
+ var CLAUDE_ASSISTANT_SCHEMA = z16.looseObject({
5149
+ type: z16.literal("assistant"),
4687
5150
  message: CLAUDE_MESSAGE_SCHEMA
4688
5151
  });
4689
- var USAGE_SCHEMA2 = z14.looseObject({
4690
- input_tokens: z14.number().optional(),
4691
- cached_input_tokens: z14.number().optional(),
4692
- output_tokens: z14.number().optional()
5152
+ var USAGE_SCHEMA2 = z16.looseObject({
5153
+ input_tokens: z16.number().optional(),
5154
+ cached_input_tokens: z16.number().optional(),
5155
+ output_tokens: z16.number().optional()
4693
5156
  });
4694
- var CODEX_START_SCHEMA = z14.looseObject({ type: z14.enum(["thread.started", "turn.started"]) });
4695
- var CODEX_PROGRESS_SCHEMA = z14.looseObject({
4696
- type: z14.enum(["item.started", "item.updated", "item.completed"]),
4697
- item: z14.looseObject({ type: z14.string(), text: z14.string().optional() }).optional()
5157
+ var CODEX_START_SCHEMA = z16.looseObject({ type: z16.enum(["thread.started", "turn.started"]) });
5158
+ var CODEX_PROGRESS_SCHEMA = z16.looseObject({
5159
+ type: z16.enum(["item.started", "item.updated", "item.completed"]),
5160
+ item: z16.looseObject({ type: z16.string(), text: z16.string().optional() }).optional()
4698
5161
  });
4699
- var CODEX_COMPLETE_SCHEMA = z14.looseObject({
4700
- type: z14.literal("turn.completed"),
5162
+ var CODEX_COMPLETE_SCHEMA = z16.looseObject({
5163
+ type: z16.literal("turn.completed"),
4701
5164
  usage: USAGE_SCHEMA2.optional()
4702
5165
  });
4703
- var CODEX_FAILURE_SCHEMA = z14.looseObject({
4704
- type: z14.enum(["turn.failed", "error"]),
4705
- error: z14.looseObject({ message: z14.string().optional() }).optional(),
4706
- message: z14.string().optional()
5166
+ var CODEX_FAILURE_SCHEMA = z16.looseObject({
5167
+ type: z16.enum(["turn.failed", "error"]),
5168
+ error: z16.looseObject({ message: z16.string().optional() }).optional(),
5169
+ message: z16.string().optional()
4707
5170
  });
4708
5171
  var EMPTY_STATE = {
4709
5172
  provider: void 0,
@@ -4794,7 +5257,7 @@ function describe(state) {
4794
5257
  var agent_event = { describe, read };
4795
5258
 
4796
5259
  // scripts/issue/issue-state.ts
4797
- import { z as z15 } from "zod";
5260
+ import { z as z17 } from "zod";
4798
5261
  var NO_LABELS = "(none)";
4799
5262
  var LABEL_SEPARATOR = ", ";
4800
5263
  var STATE_LABEL = "state: ";
@@ -4804,9 +5267,9 @@ var YES = "yes";
4804
5267
  var NO = "no";
4805
5268
  var ISSUE_LABEL = "issue: ";
4806
5269
  var HUMAN_REVIEW_LABELS = /* @__PURE__ */ new Set([NEEDS_HUMAN_REVIEW_LABEL]);
4807
- var label_schema = z15.looseObject({ name: z15.string() });
4808
- var issue_state_schema = z15.looseObject({
4809
- state: z15.string(),
5270
+ var label_schema = z17.looseObject({ name: z17.string() });
5271
+ var issue_state_schema = z17.looseObject({
5272
+ state: z17.string(),
4810
5273
  labels: label_schema.array().optional()
4811
5274
  });
4812
5275
  function parse_issue_state(json) {
@@ -4838,10 +5301,6 @@ ${format_issue_state(state)}`;
4838
5301
  }
4839
5302
  var issue_state = {
4840
5303
  NO_LABELS,
4841
- STATE_LABEL,
4842
- LABELS_LABEL,
4843
- HUMAN_REVIEW_LABEL_LINE,
4844
- ISSUE_LABEL,
4845
5304
  parse_issue_state,
4846
5305
  format_issue_state,
4847
5306
  format_attributed_issue_state
@@ -4856,7 +5315,7 @@ var PROCESS_ALIVE = "alive";
4856
5315
  var PROCESS_UNKNOWN = "unknown";
4857
5316
  var DEFAULT_SILENT_MINUTES = 30;
4858
5317
  var DEFAULT_GAP_SECONDS = 5;
4859
- var MS_PER_MINUTE2 = 6e4;
5318
+ var MS_PER_MINUTE3 = 6e4;
4860
5319
  var MS_PER_SECOND2 = 1e3;
4861
5320
  var OPEN_STATE3 = "OPEN";
4862
5321
  var STATE_FIELDS = "state,labels";
@@ -4904,7 +5363,7 @@ function to_advice(verdict, has_work_to_stash) {
4904
5363
  if (verdict === UNDETERMINED_VERDICT) return UNDETERMINED_ADVICE;
4905
5364
  return has_work_to_stash ? STOPPED_DIRTY_ADVICE : STOPPED_CLEAN_ADVICE;
4906
5365
  }
4907
- function decide3(traces) {
5366
+ function decide4(traces) {
4908
5367
  const verdict = to_verdict(traces);
4909
5368
  const has_work_to_stash = verdict === STOPPED_VERDICT && traces.is_tree_dirty;
4910
5369
  return {
@@ -4927,12 +5386,12 @@ var ALLOWED_ROOTS = [
4927
5386
  )
4928
5387
  ];
4929
5388
  function is_within(candidate, root) {
4930
- const relative = path6.relative(root, candidate);
4931
- return relative !== "" && !relative.startsWith("..") && !path6.isAbsolute(relative);
5389
+ const relative = path8.relative(root, candidate);
5390
+ return relative !== "" && !relative.startsWith("..") && !path8.isAbsolute(relative);
4932
5391
  }
4933
5392
  function to_safe_path(output_path) {
4934
- const normalized2 = path6.normalize(output_path);
4935
- if (!path6.isAbsolute(normalized2)) return void 0;
5393
+ const normalized2 = path8.normalize(output_path);
5394
+ if (!path8.isAbsolute(normalized2)) return void 0;
4936
5395
  return ALLOWED_ROOTS.some((root) => is_within(normalized2, root)) ? normalized2 : void 0;
4937
5396
  }
4938
5397
  function sample_output(output_path) {
@@ -4986,7 +5445,7 @@ async function read_traces(request) {
4986
5445
  gap_ms: request.gap_ms ?? DEFAULT_GAP_SECONDS * MS_PER_SECOND2,
4987
5446
  now_ms: Date.now(),
4988
5447
  output_path: request.output_path,
4989
- silent_window_ms: request.silent_window_ms ?? DEFAULT_SILENT_MINUTES * MS_PER_MINUTE2
5448
+ silent_window_ms: request.silent_window_ms ?? DEFAULT_SILENT_MINUTES * MS_PER_MINUTE3
4990
5449
  }),
4991
5450
  run_hold.is_tree_dirty()
4992
5451
  ]);
@@ -5003,14 +5462,13 @@ async function read_traces(request) {
5003
5462
  }
5004
5463
  async function check(request) {
5005
5464
  run_issue_number.require_issue_number(request.issue);
5006
- return decide3(await read_traces(request));
5465
+ return decide4(await read_traces(request));
5007
5466
  }
5008
5467
  var run_liveness = {
5009
5468
  check,
5010
- decide: decide3,
5469
+ decide: decide4,
5011
5470
  describe_agent_state,
5012
5471
  read_child_settled,
5013
- read_agent_state,
5014
5472
  read_output_frozen,
5015
5473
  sample_output,
5016
5474
  to_safe_path
@@ -5079,7 +5537,7 @@ var lane_report = {
5079
5537
  };
5080
5538
 
5081
5539
  // scripts/run/run-preflight.ts
5082
- import { z as z16 } from "zod";
5540
+ import { z as z18 } from "zod";
5083
5541
  var CLEAN_VERDICT = "clean";
5084
5542
  var RECLAIM_VERDICT = "reclaim";
5085
5543
  var RESUME_VERDICT = "resume";
@@ -5089,7 +5547,7 @@ var OPEN_PR = "open";
5089
5547
  var MERGED_PR = "merged";
5090
5548
  var CLOSED_PR = "closed";
5091
5549
  var NO_CHILD_WORK = { branch_name: void 0, pr_state: NO_PR };
5092
- var pr_info_schema2 = z16.object({ state: z16.string().optional() });
5550
+ var pr_info_schema2 = z18.object({ state: z18.string().optional() });
5093
5551
  var GH_PR_STATES = /* @__PURE__ */ new Map([
5094
5552
  ["CLOSED", CLOSED_PR],
5095
5553
  ["MERGED", MERGED_PR],
@@ -5100,7 +5558,7 @@ var CLEAN_ADVICE = "Start the child.";
5100
5558
  var RESUME_ADVICE = "Reuse the branch and run the whole verification gate from the start \u2014 refactor, `pnpm josh gate`, `/code-review` \u2014 never only the part the interrupted run had not reached. Nobody verified what it already committed.";
5101
5559
  var PARK_ADVICE = "Park the child: add `needs-decision` and comment what was found. Do not delete the branch, do not reopen the pull request, and do not commit on top of it.";
5102
5560
  var STASH_LABEL_PREFIX = "run:hold reclaimed before #";
5103
- var { ISSUE_NUMBER_PATTERN, require_issue_number } = run_issue_number;
5561
+ var { require_issue_number } = run_issue_number;
5104
5562
  var UNREADABLE_PR_MESSAGE = "The pull request could not be read for branch ";
5105
5563
  function needs_reclaim(tree) {
5106
5564
  return tree.is_dirty || tree.branch !== tree.default_branch;
@@ -5158,7 +5616,7 @@ function to_advice2(verdict, issue, tree) {
5158
5616
  if (verdict === PARK_VERDICT) return PARK_ADVICE;
5159
5617
  return CLEAN_ADVICE;
5160
5618
  }
5161
- function decide4(tree, child, issue) {
5619
+ function decide5(tree, child, issue) {
5162
5620
  const verdict = to_verdict2(tree, child);
5163
5621
  return {
5164
5622
  advice: to_advice2(verdict, issue, tree),
@@ -5259,30 +5717,23 @@ async function read_child_state(issue) {
5259
5717
  async function check2(issue) {
5260
5718
  require_issue_number(issue);
5261
5719
  const tree = await read_tree_state();
5262
- if (needs_reclaim(tree)) return decide4(tree, NO_CHILD_WORK, issue);
5263
- return decide4(tree, await read_child_state(issue), issue);
5720
+ if (needs_reclaim(tree)) return decide5(tree, NO_CHILD_WORK, issue);
5721
+ return decide5(tree, await read_child_state(issue), issue);
5264
5722
  }
5265
5723
  var run_preflight = {
5266
- CLEAN_ADVICE,
5267
- CLEAN_REASON,
5268
5724
  CLEAN_VERDICT,
5269
- ISSUE_NUMBER_PATTERN,
5270
- PARK_ADVICE,
5271
- PARK_VERDICT,
5272
- RECLAIM_VERDICT,
5273
5725
  RESUME_ADVICE,
5274
- RESUME_VERDICT,
5275
5726
  MERGED_PR,
5276
5727
  STASH_LABEL_PREFIX,
5277
5728
  check: check2,
5278
- decide: decide4,
5729
+ decide: decide5,
5279
5730
  read_child_state,
5280
5731
  read_pr_state: read_pr_state2,
5281
5732
  to_pr_state: to_pr_state2
5282
5733
  };
5283
5734
 
5284
5735
  // scripts/run/run-progress-read.ts
5285
- var { PROGRESS_PREFIX, mark, parse_stamp, read_last_report } = run_progress_clock;
5736
+ var { mark: mark2, parse_stamp: parse_stamp2, read_last_report: read_last_report2 } = run_progress_clock;
5286
5737
  var FIRST_LOAD_AVERAGE = 0;
5287
5738
  var IDLE_READ = { kind: "idle" };
5288
5739
  var UNREADABLE_READ = { kind: "unreadable" };
@@ -5359,24 +5810,46 @@ async function read_observations(request) {
5359
5810
  return { kind: "observed", observations };
5360
5811
  }
5361
5812
  var run_progress_read = {
5362
- PROGRESS_PREFIX,
5363
5813
  has_run_started,
5364
5814
  live_target,
5365
5815
  log_target,
5366
- mark,
5367
- parse_stamp,
5816
+ mark: mark2,
5817
+ parse_stamp: parse_stamp2,
5368
5818
  read_children,
5369
- read_last_report,
5819
+ read_last_report: read_last_report2,
5370
5820
  read_lanes,
5371
5821
  read_observations,
5372
5822
  read_record_age,
5373
5823
  stamp_target
5374
5824
  };
5375
5825
 
5826
+ // scripts/run/run-watcher-guard.ts
5827
+ var WATCHER_TICK_MS = 3e4;
5828
+ var TICK_MULTIPLIER = 3;
5829
+ var MS_PER_SECOND3 = 1e3;
5830
+ var STALE_THRESHOLD_MS = WATCHER_TICK_MS * TICK_MULTIPLIER;
5831
+ var STALE_THRESHOLD_S = STALE_THRESHOLD_MS / MS_PER_SECOND3;
5832
+ var STALE_NOTE = `Lane children are in-flight but the progress watcher has not pinged in the last ${String(STALE_THRESHOLD_S)}s \u2014 run \`pnpm josh run:progress --wait\` in the background before proceeding`;
5833
+ var OK_RESULT = { kind: "ok" };
5834
+ async function owes_watcher() {
5835
+ if (!await run_headless.is_backlog_parent()) return false;
5836
+ return await lane_registry.has_lanes_in_flight();
5837
+ }
5838
+ async function check3(life_target) {
5839
+ if (!await owes_watcher()) return OK_RESULT;
5840
+ if (run_progress_clock.is_life_fresh(life_target, STALE_THRESHOLD_MS)) return OK_RESULT;
5841
+ return { kind: "stale", note: STALE_NOTE };
5842
+ }
5843
+ var run_watcher_guard = {
5844
+ STALE_NOTE,
5845
+ STALE_THRESHOLD_MS,
5846
+ check: check3
5847
+ };
5848
+
5376
5849
  // scripts/run/run-watcher-hook.ts
5377
5850
  var SWITCH_ENV_KEY2 = "JOSH_WATCHER_GUARD";
5378
5851
  var STAMP_PREFIX2 = "josh-watcher-guard-";
5379
- var payload_schema = z17.object({ transcript_path: z17.string().min(1) });
5852
+ var payload_schema = z19.object({ transcript_path: z19.string().min(1) });
5380
5853
  function transcript_of(raw_payload) {
5381
5854
  try {
5382
5855
  const parsed = payload_schema.safeParse(JSON.parse(raw_payload));
@@ -5405,7 +5878,7 @@ async function watcher_hook_reason(raw_payload, now_ms = Date.now()) {
5405
5878
  if (transcript === void 0) return void 0;
5406
5879
  return await stale_reason(transcript, now_ms);
5407
5880
  }
5408
- var run_watcher_hook = { SWITCH_ENV_KEY: SWITCH_ENV_KEY2, STAMP_PREFIX: STAMP_PREFIX2, transcript_of, watcher_hook_reason };
5881
+ var run_watcher_hook = { transcript_of, watcher_hook_reason };
5409
5882
 
5410
5883
  // scripts/run/run-parent-cut-hook.ts
5411
5884
  var SWITCH_ENV_KEY3 = "JOSH_PARENT_CUT_GUARD";
@@ -5453,11 +5926,48 @@ async function parent_cut_reason(raw_payload, now_ms = Date.now(), state = curre
5453
5926
  var run_parent_cut_hook = {
5454
5927
  PARENT_CUT_REASON,
5455
5928
  QUIET_WINDOW_MS,
5456
- STAMP_PREFIX: STAMP_PREFIX3,
5457
5929
  SWITCH_ENV_KEY: SWITCH_ENV_KEY3,
5458
5930
  parent_cut_reason
5459
5931
  };
5460
5932
 
5933
+ // scripts/hooks/step-zero-notice.ts
5934
+ import path9 from "node:path";
5935
+ var STAMP_PREFIX4 = "josh-step-zero-notice-";
5936
+ var EDIT_TOOLS3 = /* @__PURE__ */ new Set(["Edit", "Write"]);
5937
+ var PARENT_PREFIX = "..";
5938
+ var NOTICE = "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.";
5939
+ var STAMP = hook_decision.create_refusal_stamp(STAMP_PREFIX4);
5940
+ function edited_paths(tool_input) {
5941
+ if (!json_value.is_record(tool_input)) return [];
5942
+ const { file_path, file_paths } = tool_input;
5943
+ const listed = Array.isArray(file_paths) ? file_paths : [];
5944
+ return [file_path, ...listed].filter(
5945
+ (entry) => typeof entry === "string" && entry.length > 0
5946
+ );
5947
+ }
5948
+ function is_runtime_file(file_path, root) {
5949
+ const relative = path9.relative(root, path9.resolve(root, file_path));
5950
+ if (relative.startsWith(PARENT_PREFIX) || path9.isAbsolute(relative)) return false;
5951
+ return !test_declared_logic.is_exempt(relative.split(path9.sep).join("/"));
5952
+ }
5953
+ function is_candidate(raw_payload, root) {
5954
+ const payload = hook_decision.parse_hook_payload(raw_payload);
5955
+ if (payload === void 0 || !EDIT_TOOLS3.has(payload.tool_name)) return void 0;
5956
+ const has_runtime_file = edited_paths(payload.tool_input).some(
5957
+ (file_path) => is_runtime_file(file_path, root)
5958
+ );
5959
+ return has_runtime_file ? payload.transcript_path : void 0;
5960
+ }
5961
+ function notice(raw_payload, root = process.cwd()) {
5962
+ const transcript = is_candidate(raw_payload, root);
5963
+ if (transcript === void 0) return void 0;
5964
+ const target = STAMP.path(transcript);
5965
+ if (STAMP.last_ms(target) !== hook_decision.NEVER_MS) return void 0;
5966
+ if (!STAMP.record(target, Date.now())) return void 0;
5967
+ return NOTICE;
5968
+ }
5969
+ var step_zero_notice = { NOTICE, notice, stamp_path: STAMP.path };
5970
+
5461
5971
  // scripts/hooks/pretool-guard.ts
5462
5972
  function combine_outcomes(batch, extra_reason) {
5463
5973
  if (batch.reason !== void 0) return batch;
@@ -5469,11 +5979,16 @@ function combine_outcomes(batch, extra_reason) {
5469
5979
  function is_clear(outcome) {
5470
5980
  return outcome.reason === void 0 && outcome.notice === void 0 && outcome.fault === void 0;
5471
5981
  }
5472
- function with_duplicate_notice(combined, notice) {
5473
- if (notice === void 0 || !is_clear(combined)) return combined;
5474
- return { reason: void 0, notice, fault: void 0 };
5982
+ function with_duplicate_notice(combined, notice2) {
5983
+ if (notice2 === void 0 || !is_clear(combined)) return combined;
5984
+ return { reason: void 0, notice: notice2, fault: void 0 };
5475
5985
  }
5476
- function pretool_outcome(raw_payload) {
5986
+ function with_step_zero_notice(outcome, raw_payload) {
5987
+ if (!is_clear(outcome)) return outcome;
5988
+ const notice2 = step_zero_notice.notice(raw_payload);
5989
+ return notice2 === void 0 ? outcome : { reason: void 0, notice: notice2, fault: void 0 };
5990
+ }
5991
+ function guard_outcome(raw_payload) {
5477
5992
  const batch = batch_outcome(raw_payload);
5478
5993
  const investigation = investigation_refusal(raw_payload);
5479
5994
  const duplicate = duplicate_read_outcome(raw_payload);
@@ -5482,17 +5997,21 @@ function pretool_outcome(raw_payload) {
5482
5997
  const combined = combine_outcomes(batch, investigation ?? duplicate_refusal ?? rule);
5483
5998
  return with_duplicate_notice(combined, duplicate.notice);
5484
5999
  }
6000
+ function pretool_outcome(raw_payload) {
6001
+ return with_step_zero_notice(guard_outcome(raw_payload), raw_payload);
6002
+ }
5485
6003
  async function async_reason(raw_payload) {
5486
6004
  const watcher = await run_watcher_hook.watcher_hook_reason(raw_payload);
5487
6005
  return watcher ?? await run_parent_cut_hook.parent_cut_reason(raw_payload);
5488
6006
  }
5489
6007
  async function pretool_outcome_async(raw_payload) {
5490
- const base = pretool_outcome(raw_payload);
6008
+ const base = guard_outcome(raw_payload);
5491
6009
  if (!is_clear(base)) return base;
5492
6010
  const reason = await async_reason(raw_payload);
5493
- return reason === void 0 ? base : { reason, notice: void 0, fault: void 0 };
6011
+ if (reason !== void 0) return { reason, notice: void 0, fault: void 0 };
6012
+ return with_step_zero_notice(base, raw_payload);
5494
6013
  }
5495
- var pretool_guard = { combine_outcomes, pretool_outcome, pretool_outcome_async };
6014
+ var pretool_guard = { combine_outcomes, pretool_outcome };
5496
6015
 
5497
6016
  export {
5498
6017
  pretool_outcome_async,