@joshuafolkken/kit 1.1471.0 → 1.1784.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 (895) hide show
  1. package/.claude/agents/investigator.md +1 -1
  2. package/.claude/settings.json +6 -6
  3. package/.claude/skills/epic-commands/SKILL.md +26 -77
  4. package/.claude/skills/epic-commands/epic-bundle.md +12 -6
  5. package/.claude/skills/epic-commands/execution-waves.md +1 -2
  6. package/.claude/skills/verify-ui/SKILL.md +1 -2
  7. package/.claude/skills/workflow-commands/SKILL.md +12 -14
  8. package/.claude/skills/workflow-commands/background-commands.md +8 -12
  9. package/.claude/skills/workflow-commands/backlogrun-child.md +13 -18
  10. package/.claude/skills/workflow-commands/backlogrun-handoff-report.md +7 -25
  11. package/.claude/skills/workflow-commands/backlogrun-lanes.md +23 -28
  12. package/.claude/skills/workflow-commands/backlogrun-park.md +16 -31
  13. package/.claude/skills/workflow-commands/backlogrun-progress.md +12 -21
  14. package/.claude/skills/workflow-commands/backlogrun-recovery.md +12 -12
  15. package/.claude/skills/workflow-commands/backlogrun-steps.md +12 -20
  16. package/.claude/skills/workflow-commands/backlogrun.md +32 -51
  17. package/.claude/skills/workflow-commands/chain-rule.md +18 -11
  18. package/.claude/skills/workflow-commands/delegation.md +13 -8
  19. package/.claude/skills/workflow-commands/entry-sequence.md +10 -12
  20. package/.claude/skills/workflow-commands/followup.md +10 -35
  21. package/.claude/skills/workflow-commands/fullrun-steps.md +38 -49
  22. package/.claude/skills/workflow-commands/fullrun.md +6 -8
  23. package/.claude/skills/workflow-commands/halfrun.md +20 -32
  24. package/.claude/skills/workflow-commands/into-target.md +1 -2
  25. package/.claude/skills/workflow-commands/issue-comments.md +19 -15
  26. package/.claude/skills/workflow-commands/issue-scout.md +5 -4
  27. package/.claude/skills/workflow-commands/kickoff.md +24 -23
  28. package/.claude/skills/workflow-commands/latest-gate.md +9 -18
  29. package/.claude/skills/workflow-commands/needs-human-review.md +11 -19
  30. package/.claude/skills/workflow-commands/observation-filing.md +4 -50
  31. package/.claude/skills/workflow-commands/observation-ledger.md +5 -10
  32. package/.claude/skills/workflow-commands/pre-gate-cut.md +22 -44
  33. package/.claude/skills/workflow-commands/prerequisite.md +11 -18
  34. package/.claude/skills/workflow-commands/progress-watcher.md +3 -8
  35. package/.claude/skills/workflow-commands/prrun.md +6 -12
  36. package/.claude/skills/workflow-commands/retrospective.md +5 -5
  37. package/.claude/skills/workflow-commands/split-assessment.md +14 -4
  38. package/.claude/skills/workflow-commands/target-repository.md +1 -2
  39. package/.claude/skills/workflow-commands/working-tree-hold.md +11 -13
  40. package/.codex/hooks.json +6 -6
  41. package/.github/actions/setup-node/action.yml +10 -1
  42. package/.github/actions/setup-pnpm/action.yml +1 -1
  43. package/.github/dependabot.yml +16 -0
  44. package/.github/release.yml +0 -2
  45. package/.github/workflows/ci.yml +121 -11
  46. package/.github/workflows/publish.yml +10 -3
  47. package/.github/workflows/sonar-qube.yml +1 -0
  48. package/.prettierignore +2 -0
  49. package/.vscode/tasks.json +1 -2
  50. package/CLAUDE.md +4 -8
  51. package/README.md +4 -2
  52. package/SECURITY.md +1 -1
  53. package/cspell/index.yaml +7 -0
  54. package/dist/CLAUDE.md +4 -8
  55. package/dist/commands/document-read-cli.js +882 -0
  56. package/dist/commands/{document-section-cli.js → document-section-main.js} +137 -62
  57. package/dist/commands/read-set-cli.js +1867 -0
  58. package/dist/commands/run-prep-main.js +21653 -0
  59. package/dist/commands/run-step-cli.js +23880 -0
  60. package/dist/config-merge/index.js +5 -1
  61. package/dist/hooks/audit-provision.js +20 -35
  62. package/dist/hooks/{chunk-DGT54IH5.js → chunk-AZX4FGQ3.js} +63 -17
  63. package/dist/hooks/chunk-CWMBGKYW.js +6483 -0
  64. package/dist/hooks/chunk-O2YBIDSI.js +4306 -0
  65. package/dist/hooks/{chunk-AS74OU3D.js → chunk-PT5R6UJD.js} +4582 -2118
  66. package/dist/hooks/chunk-TUIFS5E7.js +72 -0
  67. package/dist/hooks/{chunk-723HKZO5.js → chunk-VWWCFGWK.js} +1 -1
  68. package/dist/hooks/{chunk-E7OIKX5Z.js → chunk-WR2KQAYZ.js} +1863 -382
  69. package/dist/hooks/{chunk-KC5AK2GF.js → chunk-XGBNSWEI.js} +248 -46
  70. package/dist/hooks/chunk-YCDOIR3I.js +3456 -0
  71. package/dist/hooks/codex-hook-adapter.js +10 -19
  72. package/dist/hooks/format-edited.js +5 -5
  73. package/dist/hooks/inputs.json +436 -257
  74. package/dist/hooks/pretool-guard.js +7 -22
  75. package/dist/hooks/session-lang.js +380 -42
  76. package/dist/hooks/stop-guard.js +8711 -782
  77. package/dist/josh.js +5263 -997
  78. package/dist/self-sync-guard/index.js +74 -10
  79. package/dist/version/index.js +115 -406
  80. package/eslint/base.js +1 -1
  81. package/lefthook/base.yml +8 -4
  82. package/package.json +17 -53
  83. package/pnpm-workspace.yaml +4 -2
  84. package/prompts/coding-standards.md +1 -1
  85. package/prompts/collaboration-workflow/file-edits.md +1 -9
  86. package/prompts/collaboration-workflow/gh-rest.md +1 -2
  87. package/prompts/collaboration-workflow/issue-citation.md +2 -4
  88. package/prompts/collaboration-workflow/issue-template.md +42 -17
  89. package/prompts/collaboration-workflow/lane-instructions.md +34 -0
  90. package/prompts/collaboration-workflow/measurement.md +37 -0
  91. package/prompts/collaboration-workflow/operating-rules.md +6 -12
  92. package/prompts/collaboration-workflow/output-bounds.md +4 -9
  93. package/prompts/collaboration-workflow/overview.md +1 -1
  94. package/prompts/collaboration-workflow/plan-comment.md +3 -42
  95. package/prompts/collaboration-workflow/principles.md +19 -8
  96. package/prompts/collaboration-workflow/report-format.md +37 -57
  97. package/prompts/collaboration-workflow/residency.md +12 -8
  98. package/prompts/collaboration-workflow/rule-delivery.md +3 -11
  99. package/prompts/collaboration-workflow/shell-body.md +8 -18
  100. package/prompts/collaboration-workflow/turn-batching.md +4 -6
  101. package/prompts/collaboration-workflow/upstream-interrupt.md +16 -6
  102. package/prompts/collaboration-workflow/wip-cap.md +7 -7
  103. package/prompts/collaboration-workflow.md +4 -7
  104. package/prompts/refactoring.md +1 -1
  105. package/prompts/review-rubric.md +1 -2
  106. package/prompts/review.md +45 -26
  107. package/prompts/testing-guide.md +10 -45
  108. package/scripts/agent/agent-argv.ts +20 -4
  109. package/scripts/agent/agent-event.ts +15 -15
  110. package/scripts/agent/agent-exit-record.ts +13 -1
  111. package/scripts/agent/agent-role-profile.ts +101 -45
  112. package/scripts/agent/agent-safe-text.ts +60 -0
  113. package/scripts/agent/api-auth.ts +41 -0
  114. package/scripts/agent/api-outage.ts +1 -1
  115. package/scripts/agent/claude-agent-argv.ts +14 -0
  116. package/scripts/agent/codex-agent-argv.ts +2 -0
  117. package/scripts/agent/lane-instructions.ts +144 -0
  118. package/scripts/auto-ok/auto-ok-cli.ts +14 -16
  119. package/scripts/auto-ok/auto-ok-judge-read.ts +12 -3
  120. package/scripts/auto-ok/auto-ok-judge-write.ts +46 -19
  121. package/scripts/auto-ok/auto-ok-judge.ts +13 -2
  122. package/scripts/auto-ok/auto-ok-main.ts +17 -0
  123. package/scripts/backlog/backlog-arrival.ts +14 -3
  124. package/scripts/backlog/backlog-budget-cli.ts +7 -33
  125. package/scripts/backlog/backlog-budget-main.ts +16 -0
  126. package/scripts/backlog/backlog-budget.ts +6 -7
  127. package/scripts/backlog/backlog-defect-priority.ts +4 -3
  128. package/scripts/backlog/backlog-drive-adopt.ts +67 -0
  129. package/scripts/backlog/backlog-drive-args.ts +4 -5
  130. package/scripts/backlog/backlog-drive-cli.ts +113 -28
  131. package/scripts/backlog/backlog-drive-hold.ts +162 -0
  132. package/scripts/backlog/backlog-drive-idle.ts +151 -0
  133. package/scripts/backlog/backlog-drive-judge.ts +25 -0
  134. package/scripts/backlog/backlog-drive-memory.ts +126 -0
  135. package/scripts/backlog/backlog-drive-named-offer.ts +5 -10
  136. package/scripts/backlog/backlog-drive-named.ts +54 -7
  137. package/scripts/backlog/backlog-drive-offer-argv.ts +3 -8
  138. package/scripts/backlog/backlog-drive-paused.ts +169 -0
  139. package/scripts/backlog/backlog-drive-restore.ts +39 -8
  140. package/scripts/backlog/backlog-drive-seats.ts +18 -8
  141. package/scripts/backlog/backlog-drive-token-handling.ts +38 -0
  142. package/scripts/backlog/backlog-drive.ts +79 -75
  143. package/scripts/backlog/backlog-next-main.ts +16 -0
  144. package/scripts/backlog/backlog-next-shared.ts +73 -0
  145. package/scripts/backlog/backlog-next.ts +48 -16
  146. package/scripts/backlog/backlog-occupied.ts +69 -0
  147. package/scripts/backlog/backlog-offer-cli.ts +6 -21
  148. package/scripts/backlog/backlog-offer-exclude.ts +15 -0
  149. package/scripts/backlog/backlog-offer-main.ts +12 -0
  150. package/scripts/backlog/backlog-offer.ts +36 -3
  151. package/scripts/backlog/backlog-overlap.ts +22 -4
  152. package/scripts/backlog/backlog-plan-read.ts +6 -2
  153. package/scripts/backlog/backlog-plan.ts +18 -4
  154. package/scripts/backlog/backlog-pool.ts +10 -10
  155. package/scripts/backlog/backlog-rank.ts +10 -2
  156. package/scripts/backlog/backlog-ready.ts +137 -18
  157. package/scripts/backlog/backlog-stalled-detect.ts +109 -36
  158. package/scripts/backlog/backlog-stalled.ts +52 -16
  159. package/scripts/backlog/backlog-wait-cause.ts +86 -0
  160. package/scripts/backlog/backlog-waves.ts +39 -13
  161. package/scripts/backlog/backlogrun-args.ts +19 -7
  162. package/scripts/backlog/backlogrun-cli.ts +19 -5
  163. package/scripts/backlog/backlogrun-launch.ts +6 -0
  164. package/scripts/backlog/backlogrun-restart.ts +97 -0
  165. package/scripts/backlog/backlogrun-stop.ts +79 -7
  166. package/scripts/behavior/behavior-cli.ts +2 -2
  167. package/scripts/behavior/behavior-rules.ts +47 -24
  168. package/scripts/build/build-bin.ts +2 -16
  169. package/scripts/build/build-claude-md.ts +0 -7
  170. package/scripts/build/build-commands.ts +0 -13
  171. package/scripts/build/build-hooks.ts +49 -48
  172. package/scripts/build/hook-bundle-stamp.ts +29 -11
  173. package/scripts/build/local-bin.ts +1 -1
  174. package/scripts/cases/cases-cli.ts +25 -13
  175. package/scripts/cases/cases-interaction-scan.ts +134 -0
  176. package/scripts/cases/cases-interaction.ts +183 -0
  177. package/scripts/cases/cases-logic.ts +39 -6
  178. package/scripts/ci/pr-classification-main.ts +18 -0
  179. package/scripts/ci/pr-classification.ts +10 -17
  180. package/scripts/clone/clone-scan.ts +1 -1
  181. package/scripts/cost-runtime/cost-blocks.ts +22 -37
  182. package/scripts/cost-runtime/cost-cli.ts +31 -14
  183. package/scripts/cost-runtime/cost-main.ts +12 -0
  184. package/scripts/cost-runtime/cost-transcript.ts +1 -0
  185. package/scripts/delegation/delegation-policy.ts +17 -4
  186. package/scripts/delegation/duplicate-read-guard.ts +2 -10
  187. package/scripts/delegation/investigation-guard.ts +15 -73
  188. package/scripts/delegation/investigation-reads.ts +3 -5
  189. package/scripts/dependabot/dependabot-cooldown.ts +194 -0
  190. package/scripts/discovery/repo-discovery.ts +24 -6
  191. package/scripts/doctor/doctor-consumer.ts +2 -5
  192. package/scripts/document/document-byte-budget.ts +9 -6
  193. package/scripts/document/document-scan.ts +1 -1
  194. package/scripts/document/document-section-cli.ts +17 -13
  195. package/scripts/document/document-section-main.ts +12 -0
  196. package/scripts/document/entry-read-budget.ts +2 -2
  197. package/scripts/document/read-set-cli.ts +4 -1
  198. package/scripts/epic/epic-audit-cli.ts +12 -6
  199. package/scripts/epic/epic-audit-orphans.ts +5 -8
  200. package/scripts/epic/epic-audit.ts +52 -1
  201. package/scripts/epic/epic-bundle-apply.ts +137 -0
  202. package/scripts/epic/epic-bundle-cli.ts +32 -121
  203. package/scripts/epic/epic-bundle-evidence.ts +49 -26
  204. package/scripts/epic/epic-bundle-format.ts +116 -0
  205. package/scripts/epic/epic-bundle-main.ts +17 -0
  206. package/scripts/epic/epic-bundle-referenced.ts +14 -3
  207. package/scripts/epic/epic-bundle.ts +17 -9
  208. package/scripts/epic/epic-busy.ts +5 -12
  209. package/scripts/epic/epic-classify.ts +24 -15
  210. package/scripts/epic/epic-cli-argv.ts +31 -0
  211. package/scripts/epic/epic-cli-decide.ts +42 -0
  212. package/scripts/epic/epic-cli.ts +6 -38
  213. package/scripts/epic/epic-close.ts +112 -55
  214. package/scripts/epic/epic-cross-repo.ts +4 -7
  215. package/scripts/epic/epic-decide.ts +119 -0
  216. package/scripts/epic/epic-decision.ts +9 -0
  217. package/scripts/epic/epic-fetch.ts +4 -0
  218. package/scripts/epic/epic-graph.ts +2 -0
  219. package/scripts/epic/epic-issue.ts +5 -1
  220. package/scripts/epic/epic-label-age.ts +1 -1
  221. package/scripts/epic/epic-lane-offer.ts +39 -4
  222. package/scripts/epic/epic-next-main.ts +24 -0
  223. package/scripts/epic/epic-next.ts +6 -24
  224. package/scripts/epic/epic-outside-blocker.ts +6 -2
  225. package/scripts/epic/epic-parse.ts +9 -3
  226. package/scripts/epic/epic-read.ts +1 -0
  227. package/scripts/epic/epic-reconcile.ts +39 -0
  228. package/scripts/epic/epic-run.ts +10 -1
  229. package/scripts/epic/epic-solo.ts +50 -14
  230. package/scripts/epic/epic.ts +41 -7
  231. package/scripts/exports/unused-members-cli.ts +2 -2
  232. package/scripts/followup/followup-checks-event.ts +8 -3
  233. package/scripts/followup/followup-coderabbit-wait.ts +82 -0
  234. package/scripts/followup/followup-review-gates.ts +81 -0
  235. package/scripts/followup/git-followup-stages.ts +13 -3
  236. package/scripts/followup/git-followup-workflow.ts +31 -60
  237. package/scripts/followup/git-pr-followup-wrapup.ts +9 -14
  238. package/scripts/followup/git-pr-followup.ts +36 -8
  239. package/scripts/fresh-machine/fresh-machine-cli.ts +1 -1
  240. package/scripts/fresh-machine/fresh-machine-run.ts +8 -8
  241. package/scripts/fresh-machine/specs/kit-test-backlogrun.json +1 -1
  242. package/scripts/gate/busy-average.ts +58 -0
  243. package/scripts/gate/check-cpu.ts +60 -0
  244. package/scripts/gate/check-inputs.ts +73 -0
  245. package/scripts/gate/check-reuse.ts +141 -0
  246. package/scripts/gate/command-memory.ts +192 -0
  247. package/scripts/gate/core-admission.ts +218 -28
  248. package/scripts/gate/core-budget-timing.ts +37 -0
  249. package/scripts/gate/core-budget.ts +150 -119
  250. package/scripts/gate/core-wait-record.ts +48 -0
  251. package/scripts/gate/core-wait.ts +162 -0
  252. package/scripts/gate/core-weights.ts +86 -0
  253. package/scripts/gate/free-cores.ts +72 -0
  254. package/scripts/gate/gate-ledger.ts +49 -7
  255. package/scripts/gate/gate-plan.ts +44 -15
  256. package/scripts/gate/gate-report.ts +29 -4
  257. package/scripts/gate/gate-run-steps.ts +195 -0
  258. package/scripts/gate/gate-skip.ts +12 -2
  259. package/scripts/gate/gate-steps.ts +12 -1
  260. package/scripts/gate/held-mark.ts +55 -0
  261. package/scripts/gate/input-fingerprint.ts +42 -0
  262. package/scripts/gate/machine-capacity.ts +124 -31
  263. package/scripts/gate/moved-paths.ts +67 -0
  264. package/scripts/gate/pre-commit-type-check.ts +14 -1
  265. package/scripts/gate/project-checks.ts +5 -12
  266. package/scripts/gate/scoped-green.ts +12 -8
  267. package/scripts/gate/since-green.ts +62 -0
  268. package/scripts/gate/toolchain-inputs.ts +115 -0
  269. package/scripts/gate/verification-gate.ts +65 -129
  270. package/scripts/gate/verification-inputs.ts +250 -0
  271. package/scripts/gh/gh-author-association.ts +96 -9
  272. package/scripts/gh/git-ai-review-scan.ts +4 -2
  273. package/scripts/gh/git-gh-api-path.ts +15 -0
  274. package/scripts/gh/git-gh-branch-rules.ts +73 -0
  275. package/scripts/gh/git-gh-conditional.ts +5 -2
  276. package/scripts/gh/git-gh-issue-read.ts +5 -1
  277. package/scripts/gh/git-gh-issue-rest.ts +1 -0
  278. package/scripts/gh/git-gh-issue-write.ts +77 -17
  279. package/scripts/gh/git-gh-issue.ts +7 -3
  280. package/scripts/gh/git-gh-poll-read.ts +89 -0
  281. package/scripts/gh/git-gh-pr-auto-merge.ts +8 -3
  282. package/scripts/gh/git-gh-pr-rest.ts +1 -1
  283. package/scripts/gh/git-gh-pr-snapshot.ts +33 -20
  284. package/scripts/gh/git-gh-pr.ts +27 -15
  285. package/scripts/gh/git-pr-checks-eval.ts +39 -7
  286. package/scripts/gh/git-pr-checks-parse.ts +39 -9
  287. package/scripts/gh/git-pr-merge-checked.ts +80 -0
  288. package/scripts/gh/git-pr.ts +13 -1
  289. package/scripts/git/base-tree.ts +19 -2
  290. package/scripts/git/changed-file-scope.ts +6 -4
  291. package/scripts/git/changed-paths.ts +18 -1
  292. package/scripts/git/git-diff-reads.ts +27 -2
  293. package/scripts/git/git-grep-hits.ts +85 -0
  294. package/scripts/git/git-location-environment.ts +1 -1
  295. package/scripts/git/git-merge-conflicts.ts +83 -0
  296. package/scripts/git/git-preflight.ts +37 -12
  297. package/scripts/git/git-push-transport.ts +1 -2
  298. package/scripts/git/git-schemas.ts +17 -7
  299. package/scripts/git/git-spawn.ts +1 -2
  300. package/scripts/git/git-status.ts +4 -4
  301. package/scripts/git/main-merge-main.ts +12 -0
  302. package/scripts/git/main-merge-regenerate.ts +78 -0
  303. package/scripts/git/main-merge.ts +39 -14
  304. package/scripts/git/main-sync-main.ts +12 -0
  305. package/scripts/git/main-sync.ts +0 -9
  306. package/scripts/git/stash/git-stash.ts +27 -4
  307. package/scripts/git/stash/{stash-pop-args.ts → stash-args.ts} +13 -10
  308. package/scripts/git/stash/stash-pop-cli.ts +6 -12
  309. package/scripts/git/stash/stash-pop-main.ts +12 -0
  310. package/scripts/git/stash/stash-push-cli.ts +76 -0
  311. package/scripts/git/stash/stash-push-main.ts +12 -0
  312. package/scripts/hooks/batch-guard.ts +5 -16
  313. package/scripts/hooks/check-commit-message-main.ts +8 -0
  314. package/scripts/hooks/check-commit-message.ts +4 -7
  315. package/scripts/hooks/format-edited-file.ts +8 -24
  316. package/scripts/hooks/pre-commit-lint.ts +118 -0
  317. package/scripts/hooks/pre-push-unit.ts +4 -2
  318. package/scripts/hooks/pretool-guard-cli.ts +1 -8
  319. package/scripts/hooks/pretool-guard.ts +57 -69
  320. package/scripts/hooks/reserved-run.ts +67 -8
  321. package/scripts/hooks/run-hook.sh +18 -11
  322. package/scripts/hooks/shell-rules-notice.ts +37 -0
  323. package/scripts/hooks/stop-actions.ts +185 -0
  324. package/scripts/hooks/stop-guard.ts +72 -27
  325. package/scripts/init/hook-command-rewrite.ts +19 -5
  326. package/scripts/init/hook-launch.ts +15 -12
  327. package/scripts/init/init-actions.ts +0 -6
  328. package/scripts/init/init-ai-copy.ts +10 -36
  329. package/scripts/init/init-bootstrap.ts +9 -8
  330. package/scripts/init/init-dry-run-report.ts +1 -1
  331. package/scripts/init/init-dry-run.ts +1 -1
  332. package/scripts/init/init-file-action.ts +7 -9
  333. package/scripts/init/init-logic-json-merge.ts +2 -2
  334. package/scripts/init/init-logic-migrate.ts +9 -82
  335. package/scripts/init/init-logic.ts +3 -2
  336. package/scripts/init/init-main.ts +12 -0
  337. package/scripts/init/init.ts +5 -12
  338. package/scripts/init/kit-development-versions.ts +3 -7
  339. package/scripts/init/kit-written-paths.ts +2 -2
  340. package/scripts/init/project-profile.ts +5 -4
  341. package/scripts/init/tsconfig-preset-migration.ts +2 -1
  342. package/scripts/init/vscode-tasks.ts +1 -1
  343. package/scripts/issue/defect-origin-cli.ts +106 -0
  344. package/scripts/issue/defect-origin-line.ts +60 -0
  345. package/scripts/issue/defect-origin-main.ts +11 -0
  346. package/scripts/issue/defect-origin.ts +114 -0
  347. package/scripts/issue/defect-rate-cli.ts +34 -78
  348. package/scripts/issue/defect-rate.ts +0 -16
  349. package/scripts/issue/defect-report-cli.ts +128 -0
  350. package/scripts/issue/defect-report-format.ts +56 -0
  351. package/scripts/issue/defect-report-main.ts +11 -0
  352. package/scripts/issue/defect-report.ts +160 -0
  353. package/scripts/issue/expected-effect-lint.ts +60 -0
  354. package/scripts/issue/issue-already-done-cli.ts +62 -0
  355. package/scripts/issue/issue-body-or-comment.ts +40 -0
  356. package/scripts/issue/issue-cite-cli.ts +33 -22
  357. package/scripts/issue/issue-cite-main.ts +12 -0
  358. package/scripts/issue/issue-classification.ts +13 -8
  359. package/scripts/issue/issue-comment-cli.ts +10 -24
  360. package/scripts/issue/issue-comment-main.ts +12 -0
  361. package/scripts/issue/issue-evidence-exit.ts +100 -0
  362. package/scripts/issue/issue-file-cli.ts +29 -7
  363. package/scripts/issue/issue-file.ts +19 -19
  364. package/scripts/issue/issue-fold-cli.ts +2 -11
  365. package/scripts/issue/issue-fold-main.ts +12 -0
  366. package/scripts/issue/issue-labels.ts +81 -90
  367. package/scripts/issue/issue-lint-cli.ts +7 -13
  368. package/scripts/issue/issue-lint-main.ts +12 -0
  369. package/scripts/issue/issue-measured-cli.ts +56 -0
  370. package/scripts/issue/issue-merged.ts +19 -2
  371. package/scripts/issue/issue-not-before-label.ts +135 -0
  372. package/scripts/issue/issue-not-before.ts +111 -0
  373. package/scripts/issue/issue-number-shape.ts +15 -1
  374. package/scripts/issue/issue-park.ts +28 -0
  375. package/scripts/issue/issue-plan-cli.ts +151 -0
  376. package/scripts/issue/issue-priority.ts +151 -0
  377. package/scripts/issue/issue-rank.ts +7 -1
  378. package/scripts/issue/issue-read-cli.ts +3 -10
  379. package/scripts/issue/issue-read-main.ts +12 -0
  380. package/scripts/issue/issue-read.ts +29 -5
  381. package/scripts/issue/issue-release-cli.ts +0 -10
  382. package/scripts/issue/issue-release-main.ts +13 -0
  383. package/scripts/issue/issue-release.ts +7 -12
  384. package/scripts/issue/issue-sample-gate.ts +192 -0
  385. package/scripts/issue/issue-sample-source.ts +76 -0
  386. package/scripts/issue/issue-scout-cli.ts +19 -25
  387. package/scripts/issue/issue-scout-main.ts +14 -0
  388. package/scripts/issue/issue-state-cli.ts +0 -10
  389. package/scripts/issue/issue-state-main.ts +12 -0
  390. package/scripts/issue/issue-watch-diff.ts +56 -15
  391. package/scripts/issue/issue-watch.ts +2 -1
  392. package/scripts/issue/issue-wip.ts +2 -7
  393. package/scripts/issue/markdown-section.ts +19 -5
  394. package/scripts/issue/measure-rerun-cli.ts +13 -8
  395. package/scripts/issue/plan-consumers-cli.ts +39 -0
  396. package/scripts/issue/plan-consumers-main.ts +11 -0
  397. package/scripts/issue/plan-consumers-section.ts +55 -0
  398. package/scripts/issue/plan-consumers.ts +127 -0
  399. package/scripts/josh/agent-session-environment.ts +1 -1
  400. package/scripts/josh/command-usage.ts +82 -0
  401. package/scripts/josh/file-map-stamp.ts +49 -16
  402. package/scripts/josh/hook-decision.ts +32 -20
  403. package/scripts/josh/josh-command-map.ts +6 -1
  404. package/scripts/josh/josh-command-types.ts +65 -13
  405. package/scripts/josh/josh-commands-agent-hooks.ts +83 -0
  406. package/scripts/josh/josh-commands-ai.ts +169 -157
  407. package/scripts/josh/josh-commands-backlog.ts +82 -16
  408. package/scripts/josh/josh-commands-clone.ts +1 -0
  409. package/scripts/josh/josh-commands-development.ts +111 -71
  410. package/scripts/josh/josh-commands-document.ts +43 -1
  411. package/scripts/josh/josh-commands-epic.ts +171 -0
  412. package/scripts/josh/josh-commands-hooks.ts +31 -2
  413. package/scripts/josh/josh-commands-issue-write.ts +181 -0
  414. package/scripts/josh/josh-commands-issue.ts +124 -24
  415. package/scripts/josh/josh-commands-lane.ts +112 -2
  416. package/scripts/josh/josh-commands-lint.ts +19 -8
  417. package/scripts/josh/josh-commands-maintenance.ts +112 -4
  418. package/scripts/josh/josh-commands-pause.ts +29 -0
  419. package/scripts/josh/josh-commands-progress.ts +87 -0
  420. package/scripts/josh/josh-commands-project.ts +138 -9
  421. package/scripts/josh/josh-commands-review.ts +124 -0
  422. package/scripts/josh/josh-commands-run.ts +211 -23
  423. package/scripts/josh/josh-commands-ship.ts +169 -0
  424. package/scripts/josh/josh-commands-split.ts +9 -0
  425. package/scripts/josh/josh-commands-versioning.ts +49 -2
  426. package/scripts/josh/josh-commands-workflow.ts +149 -6
  427. package/scripts/josh/josh-logic.ts +11 -27
  428. package/scripts/josh/josh.ts +14 -5
  429. package/scripts/josh/package-directory.ts +18 -0
  430. package/scripts/josh/process-identity.ts +13 -4
  431. package/scripts/josh/session-language-cli.ts +4 -8
  432. package/scripts/josh/session-language-main.ts +13 -0
  433. package/scripts/josh/session-language.ts +6 -1
  434. package/scripts/josh/shared-cache.ts +90 -0
  435. package/scripts/josh/stamp-file.ts +9 -15
  436. package/scripts/lane/lane-await.ts +51 -12
  437. package/scripts/lane/lane-cache.ts +5 -30
  438. package/scripts/lane/lane-capacity.ts +19 -22
  439. package/scripts/lane/lane-check-stats.ts +97 -0
  440. package/scripts/lane/lane-child-invocation.ts +43 -4
  441. package/scripts/lane/lane-cli.ts +15 -5
  442. package/scripts/lane/lane-close.ts +86 -18
  443. package/scripts/lane/lane-core-wait-stats.ts +66 -0
  444. package/scripts/lane/lane-dispatch.ts +27 -6
  445. package/scripts/lane/lane-gap-stats.ts +156 -0
  446. package/scripts/lane/lane-guard-policy.ts +2 -2
  447. package/scripts/lane/lane-handoff.ts +76 -1
  448. package/scripts/lane/lane-held-stats.ts +129 -0
  449. package/scripts/lane/lane-install.ts +16 -15
  450. package/scripts/lane/lane-launch-cli.ts +0 -9
  451. package/scripts/lane/lane-launch-main.ts +12 -0
  452. package/scripts/lane/lane-ledger-schema.ts +266 -0
  453. package/scripts/lane/lane-ledger.ts +108 -97
  454. package/scripts/lane/lane-limit-cli.ts +19 -9
  455. package/scripts/lane/lane-measure-cli.ts +58 -10
  456. package/scripts/lane/lane-open.ts +9 -1
  457. package/scripts/lane/lane-parked.ts +3 -3
  458. package/scripts/lane/lane-pause-cli.ts +130 -0
  459. package/scripts/lane/lane-pause.ts +158 -0
  460. package/scripts/lane/lane-preserve.ts +29 -1
  461. package/scripts/lane/lane-process-table.ts +166 -0
  462. package/scripts/lane/lane-reap-settle.ts +124 -0
  463. package/scripts/lane/lane-reap.ts +50 -15
  464. package/scripts/lane/lane-registry.ts +33 -10
  465. package/scripts/lane/lane-residents.ts +162 -0
  466. package/scripts/lane/lane-restart.ts +26 -27
  467. package/scripts/lane/lane-round-two-stats.ts +49 -0
  468. package/scripts/lane/lane-sampler.ts +4 -0
  469. package/scripts/lane/lane-session-action.ts +160 -0
  470. package/scripts/lane/lane-session-broker.ts +134 -134
  471. package/scripts/lane/lane-snapshot-trace.ts +84 -0
  472. package/scripts/lane/lane-spans.ts +51 -0
  473. package/scripts/lane/lane-spent.ts +6 -3
  474. package/scripts/lane/lane-stage-stats.ts +7 -2
  475. package/scripts/lane/lane-state.ts +302 -0
  476. package/scripts/lane/lane-stats.ts +58 -4
  477. package/scripts/lane/lane-stop-stats.ts +113 -37
  478. package/scripts/lane/lane-test-related-stats.ts +127 -0
  479. package/scripts/lane/lane-transcript-calls.ts +145 -0
  480. package/scripts/lane/lane-transcript-stats.ts +168 -0
  481. package/scripts/lane/lane-vacant.ts +13 -3
  482. package/scripts/lane/lane-withdraw-cli.ts +72 -0
  483. package/scripts/lane/lane-withdraw.ts +183 -0
  484. package/scripts/lane/process-directories.ts +70 -0
  485. package/scripts/lane/process-lane-marks.ts +94 -0
  486. package/scripts/lib/atomic-write.ts +62 -0
  487. package/scripts/lib/buffered-process.ts +12 -5
  488. package/scripts/lib/cli-flags.ts +53 -0
  489. package/scripts/lib/figure-format.ts +63 -0
  490. package/scripts/lib/json-value.ts +9 -1
  491. package/scripts/lib/package-manifest.ts +35 -0
  492. package/scripts/lib/read-file.ts +3 -1
  493. package/scripts/lib/stamped-memo.ts +63 -0
  494. package/scripts/lib/stdout-on-stderr.ts +24 -0
  495. package/scripts/lib/timeouts.ts +9 -0
  496. package/scripts/lib/transcript-record.ts +91 -0
  497. package/scripts/lines/effective-limit.ts +1 -1
  498. package/scripts/lint/eslint-cache-dependencies.ts +145 -0
  499. package/scripts/lint/eslint-daemon.ts +265 -0
  500. package/scripts/lint/format.ts +14 -5
  501. package/scripts/lint/import-graph.ts +279 -0
  502. package/scripts/lint/lint-gate-scope.ts +102 -0
  503. package/scripts/lint/lint-parallel-main.ts +19 -0
  504. package/scripts/lint/lint-parallel.ts +72 -33
  505. package/scripts/lint/lint-related-scope.ts +33 -24
  506. package/scripts/lint/lint-related.ts +38 -6
  507. package/scripts/notify/confirmation-options.ts +1 -2
  508. package/scripts/notify/telegram-notify.ts +20 -20
  509. package/scripts/notify/telegram-test-logic.ts +0 -1
  510. package/scripts/notify/telegram-test-main.ts +8 -0
  511. package/scripts/notify/telegram-test.ts +12 -11
  512. package/scripts/observations/observation-ledger.ts +13 -0
  513. package/scripts/observations/observations-flush-landing.ts +5 -3
  514. package/scripts/observations/observations-flush.ts +6 -1
  515. package/scripts/overrides/overrides-check.ts +2 -5
  516. package/scripts/overrides/overrides-files.ts +2 -1
  517. package/scripts/overrides/overrides-logic.ts +3 -6
  518. package/scripts/package/verify-optional-eslint-install.ts +8 -6
  519. package/scripts/propagate/propagate-publish.ts +2 -7
  520. package/scripts/propagate/propagate-targets.ts +4 -12
  521. package/scripts/refactor/import-graph.ts +9 -7
  522. package/scripts/release/github-release-runs.ts +17 -6
  523. package/scripts/release/release-approval-prune.ts +18 -0
  524. package/scripts/release/release-history.ts +1 -3
  525. package/scripts/release/release-progress.ts +42 -22
  526. package/scripts/release/release-publish-run.ts +39 -0
  527. package/scripts/release/release-publish.ts +6 -6
  528. package/scripts/release/release-scope-cli.ts +0 -10
  529. package/scripts/release/release-scope-main.ts +12 -0
  530. package/scripts/repo/repo-setting.ts +3 -6
  531. package/scripts/repo/required-checks-logic.ts +6 -15
  532. package/scripts/report/report-format-reference.ts +4 -0
  533. package/scripts/report/report-labels.ts +155 -0
  534. package/scripts/report/report-lint-cli.ts +3 -0
  535. package/scripts/report/report-lint.ts +85 -110
  536. package/scripts/report/report-template-cli.ts +59 -0
  537. package/scripts/report/report-template.ts +112 -0
  538. package/scripts/review/acceptance-map-check.ts +61 -0
  539. package/scripts/review/acceptance-map.ts +206 -0
  540. package/scripts/review/removed-tests-check.ts +86 -0
  541. package/scripts/review/removed-tests.ts +149 -0
  542. package/scripts/review/review-brief-cli.ts +82 -16
  543. package/scripts/review/review-brief-main.ts +12 -0
  544. package/scripts/review/review-brief.ts +31 -3
  545. package/scripts/review/review-code-tree.ts +10 -6
  546. package/scripts/review/review-comment-round.ts +26 -8
  547. package/scripts/review/review-finding-ledger.ts +30 -15
  548. package/scripts/review/review-interaction.ts +94 -0
  549. package/scripts/review/review-readers-scan.ts +163 -0
  550. package/scripts/review/review-record-cli.ts +69 -30
  551. package/scripts/review/review-record-main.ts +12 -0
  552. package/scripts/review/review-round-one-blobs.ts +221 -0
  553. package/scripts/review/review-round2-cli.ts +49 -12
  554. package/scripts/review/review-round2.ts +80 -12
  555. package/scripts/review/review-stamps.ts +19 -1
  556. package/scripts/review/review-stop-log.ts +96 -0
  557. package/scripts/review/review-stops-cli.ts +85 -0
  558. package/scripts/review/review-tree.ts +6 -17
  559. package/scripts/review/review-untouched-readers.ts +146 -0
  560. package/scripts/review/test-titles.ts +118 -0
  561. package/scripts/rules/agent-model.ts +67 -0
  562. package/scripts/rules/bash-triggers.ts +46 -3
  563. package/scripts/rules/decision-oracle-batch.ts +9 -1
  564. package/scripts/rules/decision-oracle.ts +2 -2
  565. package/scripts/rules/delivered-rules.ts +90 -3
  566. package/scripts/rules/destructive-command.ts +8 -1
  567. package/scripts/rules/direct-filing.ts +10 -2
  568. package/scripts/rules/direct-issue-comment.ts +117 -0
  569. package/scripts/rules/direct-pr-create.ts +69 -3
  570. package/scripts/rules/early-heartbeat.ts +2 -1
  571. package/scripts/rules/file-body.ts +7 -0
  572. package/scripts/rules/filing-cap.ts +8 -0
  573. package/scripts/rules/firing-point.ts +6 -5
  574. package/scripts/rules/git-argv.ts +72 -14
  575. package/scripts/rules/git-force.ts +12 -2
  576. package/scripts/rules/guard-remedy.ts +121 -0
  577. package/scripts/rules/implementation-cut-verdict.ts +1 -1
  578. package/scripts/rules/implementation-cut.ts +11 -3
  579. package/scripts/rules/index-guard.ts +8 -1
  580. package/scripts/rules/issue-comments.ts +76 -7
  581. package/scripts/rules/josh-git-bare.ts +7 -0
  582. package/scripts/rules/lane-background.ts +67 -25
  583. package/scripts/rules/lane-carry-conflict.ts +6 -0
  584. package/scripts/rules/lane-direct-tool.ts +74 -0
  585. package/scripts/rules/lane-interactive-ask.ts +9 -2
  586. package/scripts/rules/lane-park.ts +45 -23
  587. package/scripts/rules/lane-split-park.ts +10 -2
  588. package/scripts/rules/lane-switch-main.ts +7 -0
  589. package/scripts/rules/last-prompt.ts +50 -5
  590. package/scripts/rules/oracle-consulted.ts +10 -0
  591. package/scripts/rules/oracle-firing.ts +1 -0
  592. package/scripts/rules/oracle-list-cli.ts +7 -0
  593. package/scripts/rules/permission-guards.ts +3 -0
  594. package/scripts/rules/piped-verification.ts +4 -2
  595. package/scripts/rules/poll-loop.ts +7 -0
  596. package/scripts/rules/pr-merge.ts +123 -0
  597. package/scripts/rules/protected-files.ts +32 -5
  598. package/scripts/rules/raw-field-body.ts +6 -0
  599. package/scripts/rules/rule-body-guard.ts +8 -0
  600. package/scripts/rules/rule-list.ts +12 -28
  601. package/scripts/rules/rule-rewrite.ts +114 -0
  602. package/scripts/rules/rule-value-cache.ts +4 -9
  603. package/scripts/rules/rule-value-cli.ts +51 -32
  604. package/scripts/rules/rule-value.ts +8 -2
  605. package/scripts/rules/shell-segments.ts +50 -0
  606. package/scripts/rules/stop-decision.ts +77 -0
  607. package/scripts/rules/stop-rule-rows.ts +64 -0
  608. package/scripts/rules/stop-rules.ts +150 -51
  609. package/scripts/rules/tail-commands.ts +15 -1
  610. package/scripts/rules/test-declared-commit.ts +11 -1
  611. package/scripts/rules/third-party-write.ts +7 -0
  612. package/scripts/rules/timed-rerun.ts +69 -0
  613. package/scripts/rules/worktree-guard.ts +13 -3
  614. package/scripts/run/board/run-board-app-name.ts +23 -0
  615. package/scripts/run/board/run-board-cli.ts +65 -30
  616. package/scripts/run/board/run-board-closed.ts +8 -2
  617. package/scripts/run/board/run-board-earlier.ts +94 -0
  618. package/scripts/run/board/run-board-ending-reason.ts +67 -0
  619. package/scripts/run/board/run-board-estimate-schedule.ts +103 -0
  620. package/scripts/run/board/run-board-estimate.ts +98 -0
  621. package/scripts/run/board/run-board-fit.ts +153 -36
  622. package/scripts/run/board/run-board-fold.ts +123 -0
  623. package/scripts/run/board/run-board-fresh.ts +2 -2
  624. package/scripts/run/board/run-board-gather-live.ts +29 -0
  625. package/scripts/run/board/run-board-gather-thread.ts +189 -0
  626. package/scripts/run/board/run-board-gather-worker.ts +29 -0
  627. package/scripts/run/board/run-board-gather.ts +187 -0
  628. package/scripts/run/board/run-board-github.ts +119 -31
  629. package/scripts/run/board/run-board-header.ts +86 -21
  630. package/scripts/run/board/run-board-keys.ts +58 -0
  631. package/scripts/run/board/run-board-kind.ts +20 -6
  632. package/scripts/run/board/run-board-labels.ts +118 -71
  633. package/scripts/run/board/run-board-lane-state.ts +109 -0
  634. package/scripts/run/board/run-board-lane-time.ts +122 -0
  635. package/scripts/run/board/run-board-layout.ts +240 -61
  636. package/scripts/run/board/run-board-length.ts +52 -0
  637. package/scripts/run/board/run-board-machine.ts +8 -4
  638. package/scripts/run/board/run-board-main.ts +12 -0
  639. package/scripts/run/board/run-board-notes.ts +52 -31
  640. package/scripts/run/board/run-board-now.ts +1 -1
  641. package/scripts/run/board/run-board-operation.ts +15 -33
  642. package/scripts/run/board/run-board-phase.ts +1 -1
  643. package/scripts/run/board/run-board-plan-shared.ts +115 -0
  644. package/scripts/run/board/run-board-plan.ts +55 -3
  645. package/scripts/run/board/run-board-planning.ts +45 -0
  646. package/scripts/run/board/run-board-priority.ts +44 -0
  647. package/scripts/run/board/run-board-process-groups.ts +195 -0
  648. package/scripts/run/board/run-board-read.ts +153 -13
  649. package/scripts/run/board/run-board-reason.ts +238 -45
  650. package/scripts/run/board/run-board-released.ts +35 -0
  651. package/scripts/run/board/run-board-render-checks.ts +39 -5
  652. package/scripts/run/board/run-board-render-condition.ts +96 -0
  653. package/scripts/run/board/run-board-render-drawn.ts +67 -0
  654. package/scripts/run/board/run-board-render-foot.ts +59 -0
  655. package/scripts/run/board/run-board-render-icon.ts +35 -0
  656. package/scripts/run/board/run-board-render-lanes.ts +145 -0
  657. package/scripts/run/board/run-board-render-lead.ts +80 -0
  658. package/scripts/run/board/run-board-render-legend.ts +117 -47
  659. package/scripts/run/board/run-board-render-notes.ts +156 -29
  660. package/scripts/run/board/run-board-render-processes.ts +196 -0
  661. package/scripts/run/board/run-board-render-section.ts +119 -0
  662. package/scripts/run/board/run-board-render-slot.ts +3 -36
  663. package/scripts/run/board/run-board-render-tail.ts +115 -48
  664. package/scripts/run/board/run-board-render-time.ts +56 -0
  665. package/scripts/run/board/run-board-render-title.ts +117 -24
  666. package/scripts/run/board/run-board-render-waits.ts +125 -0
  667. package/scripts/run/board/run-board-render.ts +206 -259
  668. package/scripts/run/board/run-board-roots.ts +54 -0
  669. package/scripts/run/board/run-board-row-yield.ts +10 -4
  670. package/scripts/run/board/run-board-setup.ts +1 -12
  671. package/scripts/run/board/run-board-snapshot.ts +111 -0
  672. package/scripts/run/board/run-board-spin.ts +2 -2
  673. package/scripts/run/board/run-board-state.ts +23 -29
  674. package/scripts/run/board/run-board-status.ts +206 -79
  675. package/scripts/run/board/run-board-thanks-read.ts +2 -2
  676. package/scripts/run/board/run-board-tick.ts +123 -104
  677. package/scripts/run/board/run-board-usage-board.ts +78 -0
  678. package/scripts/run/board/run-board-usage-lanes.ts +113 -0
  679. package/scripts/run/board/run-board-usage-listing.ts +93 -0
  680. package/scripts/run/board/run-board-usage-read.ts +120 -150
  681. package/scripts/run/board/run-board-usage-rusage.ts +19 -7
  682. package/scripts/run/board/run-board-usage-text.ts +139 -51
  683. package/scripts/run/board/run-board-usage-top.ts +102 -0
  684. package/scripts/run/board/run-board-usage.ts +89 -72
  685. package/scripts/run/board/run-board-usual.ts +20 -9
  686. package/scripts/run/carry/run-carry-args.ts +4 -7
  687. package/scripts/run/carry/run-carry-conversation.ts +1 -1
  688. package/scripts/run/carry/run-carry.ts +9 -4
  689. package/scripts/run/cut/run-cut-cli.ts +3 -2
  690. package/scripts/run/cut/run-cut-handoff.ts +2 -2
  691. package/scripts/run/cut/run-cut-report.ts +16 -0
  692. package/scripts/run/detached-launch.ts +23 -4
  693. package/scripts/run/entry/run-entry-cli.ts +8 -1
  694. package/scripts/run/event/run-event-cli.ts +1 -5
  695. package/scripts/run/event/run-event-filed.ts +12 -6
  696. package/scripts/run/event/run-event-follow.ts +2 -3
  697. package/scripts/run/event/run-event-render.ts +7 -10
  698. package/scripts/run/event/run-event-scope.ts +20 -2
  699. package/scripts/run/event/run-event-stream-emit.ts +78 -11
  700. package/scripts/run/event/run-event-stream.ts +37 -7
  701. package/scripts/run/hold/run-hold-adopt.ts +65 -0
  702. package/scripts/run/hold/run-hold-cli.ts +93 -22
  703. package/scripts/run/hold/run-hold-main.ts +12 -0
  704. package/scripts/run/hold/run-hold-member.ts +37 -0
  705. package/scripts/run/hold/run-hold-session.ts +46 -0
  706. package/scripts/run/hold/run-hold.ts +7 -1
  707. package/scripts/run/hold/run-stop-notify.ts +183 -0
  708. package/scripts/run/launch-priority.ts +32 -0
  709. package/scripts/run/merge/run-merge-auth.ts +31 -0
  710. package/scripts/run/merge/run-merge-cli.ts +72 -107
  711. package/scripts/run/merge/run-merge-close.ts +74 -0
  712. package/scripts/run/merge/run-merge-collect.ts +6 -13
  713. package/scripts/run/merge/run-merge-driver.ts +71 -0
  714. package/scripts/run/merge/run-merge-main.ts +12 -0
  715. package/scripts/run/merge/run-merge-outcome.ts +23 -0
  716. package/scripts/run/merge/run-merge-restart.ts +39 -0
  717. package/scripts/run/merge/run-merge-ship.ts +20 -4
  718. package/scripts/run/merge/run-merge-signals.ts +123 -0
  719. package/scripts/run/merge/run-merge-steps.ts +128 -83
  720. package/scripts/run/merge/run-merge.ts +53 -40
  721. package/scripts/run/park/run-park-cli.ts +91 -0
  722. package/scripts/run/park/run-park.ts +88 -0
  723. package/scripts/run/park/run-stalled.ts +68 -0
  724. package/scripts/run/pause/run-pause-cli.ts +73 -0
  725. package/scripts/run/pause/run-pause.ts +251 -0
  726. package/scripts/run/progress/run-progress-cli.ts +4 -12
  727. package/scripts/run/progress/run-progress-clock.ts +1 -1
  728. package/scripts/run/progress/run-progress-config.ts +6 -14
  729. package/scripts/run/progress/run-progress-main.ts +12 -0
  730. package/scripts/run/progress/run-progress.ts +1 -4
  731. package/scripts/run/review/run-review.ts +2 -1
  732. package/scripts/run/run-ending.ts +1 -0
  733. package/scripts/run/run-invocation.ts +5 -6
  734. package/scripts/run/run-liveness-cli.ts +6 -8
  735. package/scripts/run/run-liveness.ts +61 -30
  736. package/scripts/run/run-next.ts +1 -1
  737. package/scripts/run/run-parent-cut-hook.ts +2 -2
  738. package/scripts/run/run-poll-hook.ts +157 -0
  739. package/scripts/run/run-preflight.ts +18 -3
  740. package/scripts/run/run-prep-cli.ts +1 -10
  741. package/scripts/run/run-prep-locate.ts +7 -50
  742. package/scripts/run/run-prep-main.ts +12 -0
  743. package/scripts/run/run-prep.ts +6 -0
  744. package/scripts/run/run-report-cli.ts +101 -13
  745. package/scripts/run/run-report-handoff.ts +114 -0
  746. package/scripts/run/run-step-cli.ts +22 -15
  747. package/scripts/run/run-step-section.ts +85 -0
  748. package/scripts/run/run-step.ts +1 -1
  749. package/scripts/run/run-stranded-detect.ts +13 -0
  750. package/scripts/run/run-watcher-guard-cli.ts +1 -1
  751. package/scripts/run/run-watcher-guard.ts +1 -1
  752. package/scripts/run/ship/run-ship-args.ts +121 -0
  753. package/scripts/run/ship/run-ship-body-draft.ts +110 -0
  754. package/scripts/run/ship/run-ship-cli.ts +67 -151
  755. package/scripts/run/ship/run-ship-detach.ts +27 -7
  756. package/scripts/run/ship/run-ship-infra-retry.ts +59 -0
  757. package/scripts/run/ship/run-ship-next.ts +27 -3
  758. package/scripts/run/ship/run-ship-overlap.ts +232 -0
  759. package/scripts/run/ship/run-ship-place.ts +96 -0
  760. package/scripts/run/ship/run-ship-pre-detach-timed.ts +43 -0
  761. package/scripts/run/ship/run-ship-pre-detach.ts +102 -27
  762. package/scripts/run/ship/run-ship-preflight.ts +161 -30
  763. package/scripts/run/ship/run-ship-probe.ts +11 -3
  764. package/scripts/run/ship/run-ship-relaunch-cap.ts +70 -0
  765. package/scripts/run/ship/run-ship-removed-rows.ts +61 -0
  766. package/scripts/run/ship/run-ship-return.ts +123 -15
  767. package/scripts/run/ship/run-ship-review-steps.ts +105 -149
  768. package/scripts/run/ship/run-ship-review.ts +73 -6
  769. package/scripts/run/ship/run-ship-reviewer.ts +207 -0
  770. package/scripts/run/ship/run-ship-stage.ts +55 -6
  771. package/scripts/run/ship/run-ship-steps.ts +46 -15
  772. package/scripts/run/ship/run-ship-stop-cause.ts +135 -0
  773. package/scripts/run/ship/run-ship-stop-context.ts +206 -0
  774. package/scripts/run/ship/run-ship-stop-text.ts +11 -6
  775. package/scripts/run/ship/run-ship-sync.ts +57 -12
  776. package/scripts/run/ship/run-ship.ts +30 -2
  777. package/scripts/run/tidy/run-tidy-cli.ts +0 -4
  778. package/scripts/run/tidy/run-tidy-lanes.ts +3 -0
  779. package/scripts/run/tidy/run-tidy-main.ts +8 -0
  780. package/scripts/run/wake/run-wake-cli.ts +119 -100
  781. package/scripts/run/wake/run-wake-code.ts +83 -0
  782. package/scripts/run/wake/run-wake-driver.ts +19 -8
  783. package/scripts/run/wake/run-wake-loop.ts +34 -3
  784. package/scripts/run/wake/run-wake-main.ts +13 -0
  785. package/scripts/run/wake/run-wake-ports.ts +90 -0
  786. package/scripts/run/wake/run-wake-takeover.ts +66 -0
  787. package/scripts/run/wake/run-wake.ts +2 -1
  788. package/scripts/safe-chain/pack-hook.ts +2 -2
  789. package/scripts/safe-chain/preinstall-command.ts +2 -1
  790. package/scripts/safe-chain/project-config.ts +3 -9
  791. package/scripts/security/security-audit-main.ts +8 -0
  792. package/scripts/security/security-audit-provision-logic.ts +0 -11
  793. package/scripts/security/security-audit-provision-main.ts +12 -0
  794. package/scripts/security/security-audit-provision.ts +11 -26
  795. package/scripts/security/security-audit.ts +6 -7
  796. package/scripts/self-sync-guard/self-sync-guard-logic.ts +6 -13
  797. package/scripts/split/split-assess-cli.ts +2 -2
  798. package/scripts/split/split-assess.ts +15 -0
  799. package/scripts/split/split-measure.ts +65 -0
  800. package/scripts/sync/claude-settings-merge.ts +8 -15
  801. package/scripts/sync/directory-copy-guard.ts +4 -9
  802. package/scripts/sync/file-content.ts +78 -8
  803. package/scripts/sync/sync-ai-files.ts +3 -5
  804. package/scripts/sync/sync-configs.ts +11 -23
  805. package/scripts/sync/sync-hook-safety.ts +4 -10
  806. package/scripts/sync/sync-main.ts +11 -0
  807. package/scripts/sync/sync.ts +25 -37
  808. package/scripts/test/test-declared-changed.ts +2 -2
  809. package/scripts/test/test-declared.ts +1 -1
  810. package/scripts/test/test-e2e-guard.ts +55 -6
  811. package/scripts/test/test-e2e-stamp.ts +38 -0
  812. package/scripts/test/test-pinned-logic.ts +145 -0
  813. package/scripts/test/test-pinned-main.ts +78 -0
  814. package/scripts/test/test-pinned.ts +100 -0
  815. package/scripts/test/test-read-map.ts +264 -0
  816. package/scripts/test/test-read-recording.ts +91 -0
  817. package/scripts/test/test-read-trace.ts +148 -0
  818. package/scripts/test/test-red-main.ts +12 -0
  819. package/scripts/test/test-red.ts +12 -30
  820. package/scripts/test/test-related-main.ts +18 -0
  821. package/scripts/test/test-related-record.ts +119 -0
  822. package/scripts/test/test-related-scope.ts +229 -43
  823. package/scripts/test/test-related.ts +300 -22
  824. package/scripts/test/test-unit-guard-main.ts +15 -0
  825. package/scripts/test/test-unit-guard.ts +54 -21
  826. package/scripts/test/unit-count-file.ts +37 -0
  827. package/scripts/test/unit-run-marker.ts +162 -0
  828. package/scripts/test/unit-setup-files.ts +51 -0
  829. package/scripts/test/unit-worker-share.ts +71 -137
  830. package/scripts/test/whole-suite-files.ts +63 -0
  831. package/scripts/time-runtime/time-background.ts +20 -2
  832. package/scripts/time-runtime/time-bundles.ts +4 -3
  833. package/scripts/time-runtime/time-density-hook.ts +8 -6
  834. package/scripts/time-runtime/time-followup-stage.ts +1 -3
  835. package/scripts/time-runtime/time-format.ts +5 -28
  836. package/scripts/time-runtime/time-markers.ts +10 -1
  837. package/scripts/time-runtime/time-shell.ts +126 -14
  838. package/scripts/time-runtime/time-spans.ts +1 -0
  839. package/scripts/time-runtime/time-tool-call.ts +7 -0
  840. package/scripts/time-runtime/time-transcript-line.ts +49 -62
  841. package/scripts/uninstall/uninstall.ts +1 -1
  842. package/scripts/version/bump-version-main.ts +12 -0
  843. package/scripts/version/bump-version.ts +25 -25
  844. package/scripts/version/effective-upstream.ts +6 -12
  845. package/scripts/version/latest-corepack.ts +17 -32
  846. package/scripts/version/latest-if-required-cli.ts +93 -0
  847. package/scripts/version/latest-lane-guard-main.ts +8 -0
  848. package/scripts/version/latest-lane-guard.ts +0 -4
  849. package/scripts/version/latest-scope-cli.ts +0 -9
  850. package/scripts/version/latest-scope-main.ts +12 -0
  851. package/scripts/version/latest-update.ts +5 -5
  852. package/scripts/version/npm-registry.ts +44 -6
  853. package/scripts/version/publishable-range-check.ts +5 -16
  854. package/scripts/version/release-age.ts +1 -1
  855. package/scripts/version/release-hold.ts +1 -1
  856. package/scripts/version/release-window.ts +38 -0
  857. package/scripts/version/running-binary.ts +1 -1
  858. package/scripts/version/safe-chain-version-update.ts +3 -8
  859. package/scripts/version/version-targets.ts +6 -28
  860. package/templates/dependabot.yml +29 -0
  861. package/templates/gitignore +10 -3
  862. package/templates/pnpm-workspace.basic.yaml +1 -1
  863. package/templates/sonar-project.properties +3 -2
  864. package/templates/workflows/ci.yml +12 -4
  865. package/templates/workflows/github-release.yml +4 -0
  866. package/tsconfig.sonar.json +1 -1
  867. package/.ncurc.json +0 -3
  868. package/dist/hooks/batch-guard.js +0 -29
  869. package/dist/hooks/chunk-43ZHT22P.js +0 -3495
  870. package/dist/hooks/chunk-CDY4NFQG.js +0 -15
  871. package/dist/hooks/chunk-EUMACUK2.js +0 -2038
  872. package/dist/hooks/chunk-H5HVWYXK.js +0 -359
  873. package/dist/hooks/chunk-IIGFYXKC.js +0 -7104
  874. package/dist/hooks/chunk-IX6TTTI6.js +0 -95
  875. package/dist/hooks/chunk-J47HU5H5.js +0 -237
  876. package/dist/hooks/chunk-K4EOONYM.js +0 -45
  877. package/dist/hooks/chunk-K4LMBQC2.js +0 -68
  878. package/dist/hooks/chunk-SHGPANFB.js +0 -56
  879. package/dist/hooks/chunk-YHBZAJSV.js +0 -79
  880. package/dist/hooks/chunk-YYPI7SJZ.js +0 -131
  881. package/dist/hooks/duplicate-read-guard.js +0 -30
  882. package/dist/hooks/investigation-guard.js +0 -32
  883. package/scripts/backlog/backlog-stalled-cli.ts +0 -30
  884. package/scripts/cost-runtime/cost-format.ts +0 -29
  885. package/scripts/init/basic-path-migration.ts +0 -24
  886. package/scripts/issue/issue-backlinks-cli.ts +0 -93
  887. package/scripts/josh/josh-commands-guard.ts +0 -38
  888. package/scripts/lint/cross-file-recheck.ts +0 -155
  889. package/scripts/registry-migration/migrate-logic.ts +0 -237
  890. package/scripts/registry-migration/migrate.ts +0 -292
  891. package/scripts/registry-migration/user-npmrc.ts +0 -15
  892. package/scripts/rules/rule-guard.ts +0 -23
  893. package/scripts/rules/rule-registry-rows.ts +0 -282
  894. package/scripts/rules/rule-registry.ts +0 -109
  895. package/scripts/run/run-stranded-cli.ts +0 -27
@@ -1,9 +1,5 @@
1
- import {
2
- ALREADY_DONE_LABEL,
3
- has_label_name,
4
- IN_PROGRESS_LABEL,
5
- NEEDS_DECISION_LABEL,
6
- } from '#scripts/issue/issue-labels'
1
+ import { has_label_name, has_parked_label, IN_PROGRESS_LABEL } from '#scripts/issue/issue-labels'
2
+ import { issue_not_before } from '#scripts/issue/issue-not-before'
7
3
  import { epic_graph, type EpicChild, type IssueReference } from './epic-graph'
8
4
  import { epic_nested } from './epic-nested'
9
5
  import {
@@ -48,14 +44,18 @@ function has_label(child: EpicChild, label: string): boolean {
48
44
  return has_label_name(child.labels, label)
49
45
  }
50
46
 
51
- // The labels that put a child in `human` on their own. `needs-decision` waits for an answer nobody
52
- // has given; `already-done` has its answer — the work is merged, and the close that is left is Tier C
53
- // and so a person's. Neither is resolved by waiting, which is what separates
54
- // them from `in-progress` below.
55
- const HUMAN_LABELS: ReadonlyArray<string> = [NEEDS_DECISION_LABEL, ALREADY_DONE_LABEL]
56
-
47
+ // The park labels (`PARKED_LABELS`) put a child in `human` on their own. `needs-decision` waits for an
48
+ // answer nobody has given; `already-done` has its answer — the work is merged, and the close that is
49
+ // left is Tier C and so a person's; `run:stalled` waits on a person fixing a mechanical cause. None is
50
+ // resolved by waiting, which is what separates them from `in-progress` below.
57
51
  function has_human_label(child: EpicChild): boolean {
58
- return HUMAN_LABELS.some((label) => has_label(child, label))
52
+ return has_parked_label(child.labels)
53
+ }
54
+
55
+ // A child someone else's session is finishing, or one held until its declared start time
56
+ // (joshuafolkken/kit#4007). Either way waiting resolves it.
57
+ function is_waiting(child: EpicChild): boolean {
58
+ return has_label(child, IN_PROGRESS_LABEL) || !issue_not_before.is_due(child.body)
59
59
  }
60
60
 
61
61
  // What a child is before its dependencies are considered. A parked child is `human` whatever blocks
@@ -71,7 +71,7 @@ function has_human_label(child: EpicChild): boolean {
71
71
  function local_category(child: EpicChild): ChildCategory | undefined {
72
72
  if (child.state === CLOSED) return 'done'
73
73
  if (epic_nested.is_nested_epic(child) || has_human_label(child)) return 'human'
74
- if (has_label(child, IN_PROGRESS_LABEL)) return 'time'
74
+ if (is_waiting(child)) return 'time'
75
75
 
76
76
  return undefined
77
77
  }
@@ -117,8 +117,16 @@ function reset_reported(): void {
117
117
  reported.clear()
118
118
  }
119
119
 
120
+ // Silenced for a process that draws the withheld blocker itself: `run:board` leads its row with 🙋
121
+ // (joshuafolkken/kit#4292), so the notice would only scribble over the board.
122
+ const silence = { is_muted: false }
123
+
124
+ function mute_notices(): void {
125
+ silence.is_muted = true
126
+ }
127
+
120
128
  function report_notice(notice: OutsideNotice): void {
121
- if (reported.has(notice.key)) return
129
+ if (silence.is_muted || reported.has(notice.key)) return
122
130
 
123
131
  reported.add(notice.key)
124
132
  console.warn(notice.message)
@@ -282,6 +290,7 @@ function classify_children(
282
290
 
283
291
  const epic_classify = {
284
292
  resolve_by_state,
293
+ mute_notices,
285
294
  reset_reported,
286
295
  local_category,
287
296
  classify_children,
@@ -1,4 +1,5 @@
1
1
  import type { ParseArgsOptionsConfig } from 'node:util'
2
+ import { issue_number_shape } from '#scripts/issue/issue-number-shape'
2
3
  import { cli_flags } from '#scripts/lib/cli-flags'
3
4
 
4
5
  // The argument reading every `josh epic` form shares, on top of `cli_flags`.
@@ -94,7 +95,37 @@ function is_value_unusable(argv: ReadonlyArray<string>, flag: string): boolean {
94
95
  )
95
96
  }
96
97
 
98
+ // Deduplicated because a repeated number would render a duplicate task-list row, and with
99
+ // `--ordered` would ask GitHub to make an issue block itself.
100
+ function to_child_numbers(raw_children: ReadonlyArray<string>): Array<number> {
101
+ const numbers = raw_children
102
+ .filter((raw) => issue_number_shape.is_issue_number(raw))
103
+ .map(Number)
104
+ .filter((value) => Number.isSafeInteger(value))
105
+
106
+ return [...new Set(numbers)]
107
+ }
108
+
109
+ // `<E> <N1> <N2> …` — the shape `--promote`, `--add` and `--decide` share: an existing issue, then at
110
+ // least one child other than itself.
111
+ function read_epic_children(
112
+ parsed: EpicArgv,
113
+ ): { epic_number: number; children: Array<number> } | undefined {
114
+ const [raw_epic, ...raw_children] = parsed.positionals
115
+
116
+ if (raw_epic === undefined || !issue_number_shape.ISSUE_NUMBER_PATTERN.test(raw_epic)) {
117
+ return undefined
118
+ }
119
+
120
+ const epic_number = Number(raw_epic)
121
+ const children = to_child_numbers(raw_children).filter((child) => child !== epic_number)
122
+
123
+ return children.length === 0 ? undefined : { epic_number, children }
124
+ }
125
+
97
126
  const epic_cli_argv = {
127
+ to_child_numbers,
128
+ read_epic_children,
98
129
  read_form,
99
130
  positionals_of,
100
131
  read_flag_value,
@@ -0,0 +1,42 @@
1
+ import { epic_cli_argv, type FormFlags } from './epic-cli-argv'
2
+
3
+ // `josh epic --decide <E> <N...> --decision-file <path|->`'s argument rules — a decision about children
4
+ // the epic already tracks, which `--add --decision-file` refuses as an insertion with nothing to add.
5
+ //
6
+ // Its own module for the reason `--remove` has one: `epic-cli.ts` sits at its line ceiling.
7
+
8
+ const DECIDE_FLAG = '--decide'
9
+ const DECISION_FLAG = '--decision-file'
10
+ const DECIDE_FORM: FormFlags = { switches: [DECIDE_FLAG], value_flags: [DECISION_FLAG] }
11
+
12
+ interface DecideArguments {
13
+ epic_number: number
14
+ children: Array<number>
15
+ decision_path: string
16
+ }
17
+
18
+ // Whether the invocation records a decision rather than creating, promoting or editing the epic.
19
+ function is_decision_entry(argv: ReadonlyArray<string>): boolean {
20
+ return argv.includes(DECIDE_FLAG)
21
+ }
22
+
23
+ // The record is the whole point of the form, so a missing or unusable `--decision-file` refuses it
24
+ // rather than reading as "nothing to record".
25
+ function parse_decide_arguments(argv: ReadonlyArray<string>): DecideArguments | undefined {
26
+ if (epic_cli_argv.is_value_unusable(argv, DECISION_FLAG)) return undefined
27
+ const parsed = epic_cli_argv.read_form(argv, DECIDE_FORM)
28
+ if (parsed === undefined) return undefined
29
+ const subject = epic_cli_argv.read_epic_children(parsed)
30
+ const decision_path = epic_cli_argv.read_flag_value(parsed, DECISION_FLAG)
31
+ if (subject === undefined || decision_path === undefined) return undefined
32
+
33
+ return { ...subject, decision_path }
34
+ }
35
+
36
+ const epic_cli_decide = {
37
+ is_decision_entry,
38
+ parse_decide_arguments,
39
+ }
40
+
41
+ export { epic_cli_decide, DECIDE_FLAG }
42
+ export type { DecideArguments }
@@ -3,6 +3,7 @@ import { session_cite } from '#scripts/issue/session-cite'
3
3
  import { cli_body } from '#scripts/josh/cli-body'
4
4
  import type { InsertKind, InsertPosition } from './epic-chains'
5
5
  import { epic_cli_argv, type EpicArgv, type FormFlags } from './epic-cli-argv'
6
+ import { epic_cli_decide } from './epic-cli-decide'
6
7
  import { epic_cli_remove } from './epic-cli-remove'
7
8
  import { epic_parse, type ExternalChild } from './epic-parse'
8
9
 
@@ -64,17 +65,6 @@ interface PromoteArguments {
64
65
  origin?: string | undefined
65
66
  }
66
67
 
67
- // Deduplicated because a repeated number would render a duplicate task-list row, and with
68
- // `--ordered` would ask GitHub to make an issue block itself.
69
- function to_child_numbers(raw_children: ReadonlyArray<string>): Array<number> {
70
- const numbers = raw_children
71
- .filter((raw) => issue_number_shape.is_issue_number(raw))
72
- .map(Number)
73
- .filter((value) => Number.isSafeInteger(value))
74
-
75
- return [...new Set(numbers)]
76
- }
77
-
78
68
  // The flags a creation and a promotion share, read the same way for both.
79
69
  function read_batch_flags(
80
70
  parsed: EpicArgv,
@@ -90,7 +80,7 @@ function to_create_arguments(parsed: EpicArgv): CreateArguments | undefined {
90
80
  const [title, ...raw_children] = parsed.positionals
91
81
  if (title === undefined || title.length === 0) return undefined
92
82
 
93
- const children = to_child_numbers(raw_children)
83
+ const children = epic_cli_argv.to_child_numbers(raw_children)
94
84
  if (children.length === 0) return undefined
95
85
 
96
86
  return { title, children, ...read_batch_flags(parsed) }
@@ -134,17 +124,9 @@ function parse_reconcile_arguments(argv: ReadonlyArray<string>): ReconcileArgume
134
124
  // positional is a child. Refused when the epic would also be listed as its own child, which would
135
125
  // have it block itself under `--ordered`.
136
126
  function to_promote_arguments(parsed: EpicArgv): PromoteArguments | undefined {
137
- const [raw_epic, ...raw_children] = parsed.positionals
138
-
139
- if (raw_epic === undefined || !issue_number_shape.ISSUE_NUMBER_PATTERN.test(raw_epic)) {
140
- return undefined
141
- }
142
-
143
- const epic_number = Number(raw_epic)
144
- const children = to_child_numbers(raw_children).filter((child) => child !== epic_number)
145
- if (children.length === 0) return undefined
127
+ const subject = epic_cli_argv.read_epic_children(parsed)
146
128
 
147
- return { epic_number, children, ...read_batch_flags(parsed) }
129
+ return subject === undefined ? undefined : { ...subject, ...read_batch_flags(parsed) }
148
130
  }
149
131
 
150
132
  function parse_promote_arguments(argv: ReadonlyArray<string>): PromoteArguments | undefined {
@@ -250,23 +232,8 @@ function is_decision_path_unusable(argv: ReadonlyArray<string>): boolean {
250
232
  return is_value_unusable(argv, DECISION_FLAG)
251
233
  }
252
234
 
253
- function read_add_subject(
254
- parsed: EpicArgv,
255
- ): { epic_number: number; children: Array<number> } | undefined {
256
- const [raw_epic, ...raw_children] = parsed.positionals
257
-
258
- if (raw_epic === undefined || !issue_number_shape.ISSUE_NUMBER_PATTERN.test(raw_epic)) {
259
- return undefined
260
- }
261
-
262
- const epic_number = Number(raw_epic)
263
- const children = to_child_numbers(raw_children).filter((child) => child !== epic_number)
264
-
265
- return children.length === 0 ? undefined : { epic_number, children }
266
- }
267
-
268
235
  function to_add_arguments(parsed: EpicArgv): AddArguments | undefined {
269
- const subject = read_add_subject(parsed)
236
+ const subject = epic_cli_argv.read_epic_children(parsed)
270
237
  if (subject === undefined) return undefined
271
238
  const outcome = parse_position(parsed)
272
239
  if (outcome.is_refused) return undefined
@@ -394,6 +361,7 @@ const epic_cli = {
394
361
  is_addition,
395
362
  is_reconciliation,
396
363
  ...epic_cli_remove,
364
+ ...epic_cli_decide,
397
365
  find_cross_repo_add_target,
398
366
  is_decision_path_unusable,
399
367
  resolve_local_add,
@@ -1,5 +1,10 @@
1
1
  import { git_gh_command } from '#scripts/gh/git-gh-command'
2
- import { epic_child_schema, epic_issue_schema, type EpicChildData } from '#scripts/git/git-schemas'
2
+ import {
3
+ epic_child_schema,
4
+ epic_issue_schema,
5
+ type EpicChildData,
6
+ type EpicIssueData,
7
+ } from '#scripts/git/git-schemas'
3
8
  import { cutoff_cause, cutoff_of, type ScanCutoff } from '#scripts/git/listing-cutoff'
4
9
  import {
5
10
  parse_json_array_or_undefined,
@@ -37,6 +42,7 @@ interface EpicIssue {
37
42
  children: Array<number>
38
43
  external_children: Array<ExternalChild>
39
44
  has_declared_order: boolean
45
+ is_reopened: boolean
40
46
  }
41
47
 
42
48
  interface SiblingState {
@@ -44,8 +50,12 @@ interface SiblingState {
44
50
  has_blocked_by: boolean
45
51
  }
46
52
 
47
- function to_epic_issue(raw: { number: number; body?: string | undefined }): EpicIssue {
53
+ // GitHub's `state_reason` for an open issue that was closed once and reopened.
54
+ const REOPENED = 'reopened'
55
+
56
+ function to_epic_issue(raw: EpicIssueData): EpicIssue {
48
57
  return {
58
+ is_reopened: raw.stateReason === REOPENED,
49
59
  number: raw.number,
50
60
  children: epic_parse.parse_task_list_issue_numbers(raw.body),
51
61
  external_children: epic_parse.parse_external_task_list_children(raw.body),
@@ -98,30 +108,32 @@ function to_sibling_state(raw_json: string | undefined): SiblingState {
98
108
  }
99
109
  }
100
110
 
101
- async function inspect_sibling(sibling: number, repo?: string): Promise<SiblingState> {
102
- return to_sibling_state(await git_gh_command.issue_get_state_and_relations(String(sibling), repo))
103
- }
111
+ type ChildRead = SiblingState & { is_readable: boolean }
104
112
 
105
- // A cross-repository child, read by naming its repository in the read's REST path. `is_readable`
106
- // is what decides whether the epic may close at all: closing while a child's state is unknown is
107
- // exactly what the old refusal prevented, and reading them is the only thing that changed.
108
- async function inspect_external(
109
- child: ExternalChild,
110
- ): Promise<SiblingState & { is_readable: boolean }> {
113
+ // A same-repository child carries no `repo`; a cross-repository one names it.
114
+ type ChildReference = Omit<ExternalChild, 'repo'> & { repo?: string | undefined }
115
+
116
+ // A child read by number, naming its repository in the REST path when it lives in another one.
117
+ // `is_readable` is what decides whether the epic may close at all: closing while a child's state is
118
+ // unknown is exactly what the refusal prevents. A failed read is told apart from an open child
119
+ // rather than read as one, which left a finished epic open with nothing in the output (#4560). A
120
+ // read whose answer carries no state is a failed read too.
121
+ async function inspect_child(child: ChildReference): Promise<ChildRead> {
111
122
  const raw = await git_gh_command.issue_get_state_and_relations(String(child.number), child.repo)
112
123
 
113
- return { ...to_sibling_state(raw), is_readable: raw !== undefined }
124
+ return { ...to_sibling_state(raw), is_readable: parse_child(raw)?.state !== undefined }
114
125
  }
115
126
 
116
127
  // The merged Issue is excluded rather than queried: GitHub applies `closes #N` asynchronously, so
117
128
  // reading its state immediately after the merge races with that propagation.
118
- async function inspect_siblings(
119
- epic: EpicIssue,
120
- merged_number: number,
121
- ): Promise<Array<SiblingState>> {
122
- const siblings = epic.children.filter((child) => child !== merged_number)
129
+ async function inspect_children(epic: EpicIssue, merged_number: number): Promise<Array<ChildRead>> {
130
+ const siblings: Array<ChildReference> = epic.children
131
+ .filter((child) => child !== merged_number)
132
+ .map((number) => ({ number }))
123
133
 
124
- return await Promise.all(siblings.map(async (sibling) => await inspect_sibling(sibling)))
134
+ return await Promise.all(
135
+ [...siblings, ...epic.external_children].map(async (child) => await inspect_child(child)),
136
+ )
125
137
  }
126
138
 
127
139
  // `pnpm josh epic --ordered` and `--add` record the declared chain themselves, through the REST
@@ -165,9 +177,8 @@ const CASCADE_DEPTH_NOTE = `⚠️ Epic auto-close cascade reached its ${String
165
177
 
166
178
  // **An unreadable comment listing does not stop the close.** It is announced and closed exactly as
167
179
  // it was before the duplicate check existed, because refusing here would strand the epic: nothing
168
- // re-triggers the auto-close once every child is closed — `resolve_and_close` only evaluates epics
169
- // holding the issue that just merged, and that merge has already happened. One rate-limited read
170
- // would leave a finished epic open until somebody noticed.
180
+ // re-triggers the auto-close until some later child close sweeps the open epics, and that close may
181
+ // never come. One rate-limited read would leave a finished epic open until somebody noticed.
171
182
  //
172
183
  // The direction is chosen on what each mistake costs, and they are not symmetric. Announcing twice
173
184
  // costs one redundant comment and nothing else, because the epic *closes* — which is what ends a loop
@@ -209,38 +220,26 @@ async function close_epic(epic: EpicIssue): Promise<boolean> {
209
220
  return await close_epic_with(epic_number, comment)
210
221
  }
211
222
 
212
- // The cross-repository children's states, and whether every one of them could be read. An epic with
213
- // a child whose state is unknown keeps the old handling — left open for manual closing.
214
- async function inspect_external_children(
215
- epic: EpicIssue,
216
- ): Promise<{ states: Array<SiblingState>; is_complete: boolean }> {
217
- if (epic.external_children.length === 0) return { states: [], is_complete: true }
218
- const results = await Promise.all(
219
- epic.external_children.map(async (child) => await inspect_external(child)),
220
- )
223
+ // The manual-close request is made only when every child that was read is closed: while one is still
224
+ // open the batch is unfinished anyway, and asking for a manual close would invite closing it early.
225
+ function warn_when_unread_blocks_close(epic: EpicIssue, states: ReadonlyArray<ChildRead>): void {
226
+ if (states.some((state) => state.is_readable && !state.is_closed)) return
221
227
 
222
- return {
223
- states: results.map((result) => ({
224
- is_closed: result.is_closed,
225
- has_blocked_by: result.has_blocked_by,
226
- })),
227
- is_complete: results.every((result) => result.is_readable),
228
- }
228
+ console.info(
229
+ `⚠️ Epic ${session_cite.issue(epic.number)} has a child whose state could not be read; ${CLOSE_MANUALLY}`,
230
+ )
229
231
  }
230
232
 
233
+ // An epic with a child whose state is unknown is left open for manual closing, and says so.
231
234
  async function close_epic_when_complete(epic: EpicIssue, merged_number: number): Promise<boolean> {
232
- const external = await inspect_external_children(epic)
235
+ const states = await inspect_children(epic, merged_number)
233
236
 
234
- if (!external.is_complete) {
235
- console.info(
236
- `ℹ️ Epic ${session_cite.issue(epic.number)} has a child in another repository whose state could not be read; ${CLOSE_MANUALLY}`,
237
- )
237
+ if (states.some((state) => !state.is_readable)) {
238
+ warn_when_unread_blocks_close(epic, states)
238
239
 
239
240
  return false
240
241
  }
241
242
 
242
- const states = [...(await inspect_siblings(epic, merged_number)), ...external.states]
243
-
244
243
  warn_when_order_unrecorded(epic, states)
245
244
 
246
245
  if (states.some((state) => !state.is_closed)) return false
@@ -315,22 +314,74 @@ async function close_next_level(
315
314
  return next
316
315
  }
317
316
 
318
- // Breadth-first up the nesting: level 0 closes the epics holding the merged issue, and each closed
319
- // epic becomes the next level's completed child, so a fully-finished parent closes in the same pass.
320
- async function cascade_close(
317
+ // Breadth-first up the nesting: each closed epic becomes the next level's completed child, so a
318
+ // fully-finished parent closes in the same pass. `false` when the depth cap stopped the walk.
319
+ async function cascade_from(
321
320
  open_epics: ReadonlyArray<EpicIssue>,
322
- merged_number: number,
323
- ): Promise<void> {
324
- const evaluated = new Set<number>()
325
- let frontier: ReadonlyArray<number> = [merged_number]
321
+ start: ReadonlyArray<number>,
322
+ evaluated: Set<number>,
323
+ ): Promise<boolean> {
324
+ let frontier = start
326
325
 
327
326
  for (let depth = 0; depth < MAX_CASCADE_DEPTH; depth++) {
328
- if (frontier.length === 0) return
327
+ if (frontier.length === 0) return true
329
328
  // eslint-disable-next-line no-await-in-loop -- the cascade closes one level before reading the next
330
329
  frontier = await close_next_level(open_epics, frontier, evaluated)
331
330
  }
332
331
 
333
332
  if (frontier.length > 0) console.info(CASCADE_DEPTH_NOTE)
333
+
334
+ return frontier.length === 0
335
+ }
336
+
337
+ // An epic listing no child has nothing to be complete: with no state to read, the completion check
338
+ // would close it — a prose epic, or one whose task list is not written yet.
339
+ function tracks_children(epic: EpicIssue): boolean {
340
+ return epic.children.length + epic.external_children.length > 0
341
+ }
342
+
343
+ // Every open epic the cascade did not reach, closed when each child is: an epic whose last child
344
+ // closed outside every josh path — an `already-done` child `run:merge` parked and a person closed by
345
+ // hand (#4564) — is found by the next close of any child. An epic is marked evaluated only once it
346
+ // closes, so a parent read before its child epic closed here is evaluated again by that cascade.
347
+ //
348
+ // A reopened epic is left out: a person reopening a finished epic has said it is not done, and only
349
+ // a close of one of its own children — the cascade above — may close it again.
350
+ function is_sweep_target(epic: EpicIssue, evaluated: ReadonlySet<number>): boolean {
351
+ return !evaluated.has(epic.number) && !epic.is_reopened && tracks_children(epic)
352
+ }
353
+
354
+ async function sweep_unreached(
355
+ open_epics: ReadonlyArray<EpicIssue>,
356
+ merged_number: number,
357
+ evaluated: Set<number>,
358
+ ): Promise<Array<number>> {
359
+ const closed: Array<number> = []
360
+ const unreached = open_epics.filter((epic) => is_sweep_target(epic, evaluated))
361
+
362
+ for (const epic of unreached) {
363
+ // eslint-disable-next-line no-await-in-loop -- a closed epic joins the evaluated set the cascade reads
364
+ if (await close_epic_isolated(epic, merged_number)) closed.push(epic.number)
365
+ }
366
+
367
+ for (const number of closed) evaluated.add(number)
368
+
369
+ return closed
370
+ }
371
+
372
+ // Level 0 closes the epics holding the merged issue; the sweep then closes any other finished epic.
373
+ // A cascade stopped at the depth cap asks for a manual close, so the sweep does not run past it.
374
+ async function cascade_close(
375
+ open_epics: ReadonlyArray<EpicIssue>,
376
+ merged_number: number,
377
+ ): Promise<void> {
378
+ const evaluated = new Set<number>()
379
+
380
+ if (!(await cascade_from(open_epics, [merged_number], evaluated))) return
381
+
382
+ const swept = await sweep_unreached(open_epics, merged_number, evaluated)
383
+
384
+ await cascade_from(open_epics, swept, evaluated)
334
385
  }
335
386
 
336
387
  const UNREADABLE_EPIC_LIST_MESSAGE =
@@ -363,9 +414,15 @@ async function resolve_and_close_safely(merged_number: number): Promise<void> {
363
414
  /**
364
415
  * Close every open epic whose task list is fully complete once `issue_number` closed.
365
416
  *
366
- * Requires `is_merged`: the linked Issue is treated as closed without being queried, which only
367
- * holds once the PR actually merged. On a `--no-merge` run that Issue is still open, so skipping
368
- * this guard would close an epic whose batch is not finished.
417
+ * **The one entry every child close goes through** (#4560): `followup` after its merge,
418
+ * `josh issue:measured` after its own close, and `run:merge` for every child it counts as merged —
419
+ * which also catches a merge GitHub left OPEN. Running it
420
+ * twice for one child is harmless: a closed epic is no longer in the open listing. Every other open
421
+ * epic is swept too, so one whose last child closed outside these paths closes here (#4564).
422
+ *
423
+ * Requires `is_merged` — the child is known closed: the linked Issue is treated as closed without
424
+ * being queried. On a `--no-merge` run that Issue is still open, so skipping this guard would close
425
+ * an epic whose batch is not finished.
369
426
  */
370
427
  async function close_completed_epics(input: {
371
428
  issue_number: string | undefined
@@ -2,6 +2,7 @@ import { repo_map_logic } from '#scripts/discovery/repo-map-logic'
2
2
  import { repo_origin } from '#scripts/discovery/repo-origin'
3
3
  import { git_gh_api_path } from '#scripts/gh/git-gh-api-path'
4
4
  import { git_gh_exec } from '#scripts/gh/git-gh-exec'
5
+ import { json_value } from '#scripts/lib/json-value'
5
6
  import { GH_API_TIMEOUT_MS } from '#scripts/lib/timeouts'
6
7
  import { propagate_publish } from '#scripts/propagate/propagate-publish'
7
8
  import { derive_versions_endpoint } from '#scripts/version/version-command-config'
@@ -209,14 +210,10 @@ function to_answer(repo: string, fields: ManifestFields): ManifestAnswer {
209
210
  }
210
211
 
211
212
  function to_manifest(repo: string, stdout: string): ManifestAnswer {
212
- try {
213
- const parsed: unknown = JSON.parse(stdout.trim())
214
- if (typeof parsed !== 'object' || parsed === null) return { kind: 'unreadable' }
213
+ const parsed = json_value.parse_or_undefined(stdout.trim())
214
+ if (typeof parsed !== 'object' || parsed === null) return { kind: 'unreadable' }
215
215
 
216
- return to_answer(repo, parsed)
217
- } catch {
218
- return { kind: 'unreadable' }
219
- }
216
+ return to_answer(repo, parsed)
220
217
  }
221
218
 
222
219
  // Why the read failed, asked only when it did. The status line is the protocol rather than prose, so
@@ -0,0 +1,119 @@
1
+ import { git_gh_command } from '#scripts/gh/git-gh-command'
2
+ import { NEEDS_DECISION_LABEL } from '#scripts/issue/issue-labels'
3
+ import { issue_read } from '#scripts/issue/issue-read'
4
+ import { session_cite } from '#scripts/issue/session-cite'
5
+ import { epic_decision } from './epic-decision'
6
+ import { epic_parse } from './epic-parse'
7
+ import { epic_read } from './epic-read'
8
+ import type { EpicSubject } from './epic-validate'
9
+
10
+ // `josh epic --decide <E> <N...> --decision-file <path|->` — record a decision about children the epic
11
+ // already tracks: the epic's `## Decisions` entry, a comment on each child, and each child's
12
+ // `needs-decision` label removed. The text is the caller's; placing it is this command's.
13
+ //
14
+ // **A rerun writes nothing twice.** The entry and each comment are looked for before they are
15
+ // written, so a run that stopped half way is finished by running it again.
16
+
17
+ const SUCCESS_EXIT_CODE = 0
18
+ const FAILURE_EXIT_CODE = 1
19
+
20
+ interface DecideInput {
21
+ epic_number: number
22
+ children: ReadonlyArray<number>
23
+ decision: string
24
+ }
25
+
26
+ function format_list(numbers: ReadonlyArray<number>): string {
27
+ return numbers.map((issue_number) => session_cite.issue(issue_number)).join(', ')
28
+ }
29
+
30
+ // A child the epic does not track is refused before anything is written: placing it is `--add`'s,
31
+ // which records the same decision in the same call.
32
+ function untracked_error(epic_number: number, untracked: ReadonlyArray<number>): string {
33
+ return `${format_list(untracked)} not tracked by ${session_cite.issue(epic_number)}; place it with \`pnpm josh epic --add ${String(epic_number)} <N> --decision-file <path>\`. Nothing was written.`
34
+ }
35
+
36
+ // The epic the decision goes to, or why nothing is written: a record `append_decision` would refuse
37
+ // (checked before any read), an unreadable epic, or a child it does not track.
38
+ async function read_decision_target(input: DecideInput): Promise<EpicSubject | { error: string }> {
39
+ const record_error = epic_decision.find_decision_error(input.decision)
40
+ if (record_error !== undefined) return { error: record_error }
41
+ const subject = await epic_read.read_subject(input.epic_number)
42
+
43
+ if (subject === undefined) {
44
+ return { error: `Could not read issue ${session_cite.issue(input.epic_number)}.` }
45
+ }
46
+
47
+ const tracked = epic_parse.parse_task_list_issue_numbers(subject.body)
48
+ const untracked = input.children.filter((child) => !tracked.includes(child))
49
+
50
+ return untracked.length === 0 ? subject : { error: untracked_error(input.epic_number, untracked) }
51
+ }
52
+
53
+ async function record_on_epic(subject: EpicSubject, decision: string): Promise<string> {
54
+ const epic = session_cite.issue(subject.number)
55
+
56
+ if (epic_decision.has_decision(subject.body, decision)) {
57
+ return `📝 ${epic} already records this decision.`
58
+ }
59
+
60
+ const body = epic_decision.append_decision(subject.body ?? '', decision)
61
+
62
+ await git_gh_command.issue_edit_body(String(subject.number), body)
63
+
64
+ return `📝 Decision recorded in ${epic}'s \`## Decisions\`.`
65
+ }
66
+
67
+ // `undefined` when the comments could not be read: posting then risks the duplicate this exists to
68
+ // prevent, so the child is reported as not recorded and a rerun finishes it.
69
+ async function has_comment(child: number, decision: string): Promise<boolean | undefined> {
70
+ const comments = await issue_read.parse_comments(
71
+ await git_gh_command.issue_list_comments(String(child)),
72
+ )
73
+
74
+ return comments?.some((comment) => comment.body.trim() === decision.trim())
75
+ }
76
+
77
+ // The label goes only once the child carries the record, so a failed comment leaves it parked.
78
+ async function record_on_child(child: number, decision: string): Promise<boolean> {
79
+ const has_record = await has_comment(child, decision)
80
+ if (has_record === undefined) return false
81
+ const is_commented =
82
+ has_record || (await git_gh_command.issue_try_comment(String(child), decision))
83
+ if (!is_commented) return false
84
+
85
+ return await git_gh_command.issue_clear_label(String(child), NEEDS_DECISION_LABEL)
86
+ }
87
+
88
+ function format_child_report(total: number, failures: number): string {
89
+ if (failures === 0) return epic_decision.format_decision_report({ total, failures })
90
+
91
+ return `⚠️ ${String(failures)} of ${String(total)} child issue(s) could not be given the comment or lose \`${NEEDS_DECISION_LABEL}\`; rerun the same command — nothing is written twice.`
92
+ }
93
+
94
+ async function decide(input: DecideInput): Promise<number> {
95
+ const epic = await read_decision_target(input)
96
+
97
+ if ('error' in epic) {
98
+ console.error(`✖ ${epic.error}`)
99
+
100
+ return FAILURE_EXIT_CODE
101
+ }
102
+
103
+ console.info(await record_on_epic(epic, input.decision))
104
+ const recorded = await Promise.all(
105
+ input.children.map(async (child) => await record_on_child(child, input.decision)),
106
+ )
107
+ const failures = recorded.filter((is_recorded) => !is_recorded).length
108
+
109
+ console.info(format_child_report(input.children.length, failures))
110
+
111
+ return failures === 0 ? SUCCESS_EXIT_CODE : FAILURE_EXIT_CODE
112
+ }
113
+
114
+ const epic_decide = {
115
+ decide,
116
+ }
117
+
118
+ export { epic_decide }
119
+ export type { DecideInput }
@@ -153,8 +153,17 @@ function read_recorded_reasons(body: string | undefined): string {
153
153
  ].join('\n')
154
154
  }
155
155
 
156
+ // Whether `## Decisions` already carries this record, compared as `append_decision` writes it — so a
157
+ // rerun of `epic --decide` after a partial failure appends nothing a second time.
158
+ function has_decision(body: string | undefined, record: string): boolean {
159
+ if (body === undefined) return false
160
+
161
+ return read_section(body, DECISIONS_HEADING_PATTERN).includes(record.trimEnd())
162
+ }
163
+
156
164
  const epic_decision = {
157
165
  append_decision,
166
+ has_decision,
158
167
  append_replacements,
159
168
  read_recorded_reasons,
160
169
  find_decision_error,