@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
@@ -159,11 +159,7 @@ function resolve_targets(
159
159
  }
160
160
 
161
161
  const propagate_targets = {
162
- has_checkout,
163
162
  read_manifest,
164
- classify_manifest_absence,
165
- classify_before_dependency,
166
- declared_range,
167
163
  installed_version,
168
164
  classify_target,
169
165
  resolve_targets,
@@ -279,16 +279,12 @@ async function main(argv: ReadonlyArray<string>): Promise<void> {
279
279
  }
280
280
 
281
281
  const propagate = {
282
- DRY_RUN_REASON,
283
282
  KNOWN_FLAGS,
284
283
  TARGET_FLAG,
285
284
  parse_options,
286
285
  refuse_outside_source_repository,
287
286
  resolve_target_version,
288
287
  resolve_run_version,
289
- announce_run_version,
290
- run,
291
- main,
292
288
  }
293
289
 
294
290
  if (process.argv[1] === fileURLToPath(import.meta.url)) await main(process.argv.slice(ARGV_OFFSET))
@@ -173,7 +173,6 @@ const import_graph = {
173
173
  expand,
174
174
  expand_scope,
175
175
  invert,
176
- neighbors_of,
177
176
  parse_imports,
178
177
  resolve_spec,
179
178
  MAX_STAGES,
@@ -241,8 +241,6 @@ const refactor_lint = {
241
241
  parse_results,
242
242
  scan_categories,
243
243
  CATEGORIES,
244
- HIGH,
245
- MEDIUM,
246
244
  LOW,
247
245
  }
248
246
 
@@ -111,7 +111,6 @@ const refactor_scan = {
111
111
  render,
112
112
  render_result,
113
113
  run_scan,
114
- scan,
115
114
  convergence_candidates,
116
115
  verdict_line,
117
116
  verdict_token,
@@ -95,7 +95,6 @@ const refactor_targets = {
95
95
  collect_targets,
96
96
  has_ignore_marker,
97
97
  is_path_excluded,
98
- keep_target,
99
98
  scripts_files,
100
99
  select_scope,
101
100
  }
@@ -221,8 +221,6 @@ const migrate_logic = {
221
221
  github_tarballs,
222
222
  is_github_tarball,
223
223
  rewrite_kit_lockfile,
224
- registry_of,
225
- scoped_packages,
226
224
  scoped_versions,
227
225
  }
228
226
 
@@ -2,6 +2,8 @@ import { existsSync, rmSync, writeFileSync } from 'node:fs'
2
2
  import path from 'node:path'
3
3
  import { fileURLToPath } from 'node:url'
4
4
  import { file_reader } from '#scripts/lib/read-file'
5
+ import { timed_fetch } from '#scripts/lib/timed-fetch'
6
+ import { COMMAND_TIMEOUT_MS, INSTALL_TIMEOUT_MS } from '#scripts/lib/timeouts'
5
7
  import { execa } from 'execa'
6
8
  import { z } from 'zod'
7
9
  import { migrate_logic, type MigrationPlan } from './migrate-logic'
@@ -11,7 +13,6 @@ const NPMRC = '.npmrc'
11
13
  const LOCKFILE = 'pnpm-lock.yaml'
12
14
  const WORKSPACE = 'pnpm-workspace.yaml'
13
15
  const PUBLIC_REGISTRY = 'https://registry.npmjs.org/'
14
- const FETCH_TIMEOUT_MS = 10_000
15
16
  const SCOPE = '@joshuafolkken/'
16
17
  const manifest_schema = z.looseObject({
17
18
  dependencies: z.record(z.string(), z.string()).optional(),
@@ -104,11 +105,16 @@ async function verify_public_versions(
104
105
  lockfile: string,
105
106
  probe_version: MigrationDependencies['fetch_version'],
106
107
  ): Promise<VersionCheck> {
108
+ const versions = migrate_logic.scoped_versions(lockfile)
109
+ // Each probe reads its own package, so they run together; the report keeps the lockfile's order.
110
+ const probed = await Promise.all(
111
+ versions.map(async ([name, version]) => await probe_integrity(name, version, probe_version)),
112
+ )
107
113
  const missing: Array<string> = []
108
114
  const integrities = new Map<string, string>()
109
115
 
110
- for (const [name, version] of migrate_logic.scoped_versions(lockfile)) {
111
- const integrity = await probe_integrity(name, version, probe_version)
116
+ for (const [index, [name, version]] of versions.entries()) {
117
+ const integrity = probed[index]
112
118
  if (integrity === undefined) missing.push(`${name}@${version}`)
113
119
  else integrities.set(version, integrity)
114
120
  }
@@ -238,9 +244,7 @@ async function migrate(cwd: string, dependencies: MigrationDependencies): Promis
238
244
 
239
245
  async function fetch_version(name: string, version: string): Promise<string | undefined> {
240
246
  const encoded = encodeURIComponent(name)
241
- const response = await fetch(`${PUBLIC_REGISTRY}${encoded}/${encodeURIComponent(version)}`, {
242
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
243
- })
247
+ const response = await timed_fetch(`${PUBLIC_REGISTRY}${encoded}/${encodeURIComponent(version)}`)
244
248
 
245
249
  if (!response.ok) return undefined
246
250
  const parsed = version_schema.safeParse(await response.json())
@@ -250,11 +254,17 @@ async function fetch_version(name: string, version: string): Promise<string | un
250
254
  }
251
255
 
252
256
  async function install(cwd: string): Promise<void> {
253
- await execa('pnpm', ['install', '--lockfile-only', '--ignore-scripts', '--force'], { cwd })
257
+ await execa('pnpm', ['install', '--lockfile-only', '--ignore-scripts', '--force'], {
258
+ cwd,
259
+ timeout: INSTALL_TIMEOUT_MS,
260
+ })
254
261
  }
255
262
 
256
263
  async function effective_registry(cwd: string): Promise<string> {
257
- const result = await execa('pnpm', ['config', 'get', '@joshuafolkken:registry'], { cwd })
264
+ const result = await execa('pnpm', ['config', 'get', '@joshuafolkken:registry'], {
265
+ cwd,
266
+ timeout: COMMAND_TIMEOUT_MS,
267
+ })
258
268
 
259
269
  return result.stdout.trim()
260
270
  }
@@ -275,7 +285,7 @@ async function main(): Promise<void> {
275
285
 
276
286
  if (process.argv[1] === fileURLToPath(import.meta.url)) await main()
277
287
 
278
- const registry_migration = { migrate }
288
+ const registry_migration = { migrate, install, effective_registry }
279
289
 
280
290
  export { registry_migration }
281
291
  export type { MigrationDependencies }
@@ -1,11 +1,13 @@
1
1
  import { execFileSync } from 'node:child_process'
2
+ import { fileURLToPath } from 'node:url'
2
3
  import { github_release } from './github-release'
4
+ import { github_release_environment } from './github-release-environment'
3
5
 
4
- const token = process.env['GH_TOKEN']
5
- const tag = process.env['RELEASE_TAG']
6
+ async function main(): Promise<void> {
7
+ const { token, tag, settings } = github_release_environment.read_release_input(process.env)
8
+ const tags = execFileSync('git', ['tag', '--list'], { encoding: 'utf8' }).trim().split('\n')
6
9
 
7
- if (!token || !tag) throw new Error('GH_TOKEN and RELEASE_TAG are required')
10
+ console.info(await github_release.publish(fetch, token, tag, { ...settings, tags }))
11
+ }
8
12
 
9
- const tags = execFileSync('git', ['tag', '--list'], { encoding: 'utf8' }).trim().split('\n')
10
-
11
- console.info(await github_release.publish(fetch, token, tag, { tags }))
13
+ if (process.argv[1] === fileURLToPath(import.meta.url)) await main()
@@ -0,0 +1,46 @@
1
+ import type { ReleaseSettings } from './github-release'
2
+
3
+ interface ReleaseInput {
4
+ token: string
5
+ tag: string
6
+ settings: ReleaseSettings
7
+ }
8
+
9
+ type Environment = Readonly<Record<string, string | undefined>>
10
+
11
+ // A workflow expression renders an unset input as the empty string, so empty means "not given".
12
+ function optional(value: string | undefined): string | undefined {
13
+ return value === undefined || value === '' ? undefined : value
14
+ }
15
+
16
+ function job_names(value: string | undefined): ReadonlyArray<string> {
17
+ return (optional(value) ?? '')
18
+ .split(',')
19
+ .map((name) => name.trim())
20
+ .filter((name) => name !== '')
21
+ }
22
+
23
+ function read_release_input(environment: Environment): ReleaseInput {
24
+ const token = optional(environment['GH_TOKEN'])
25
+ const tag = optional(environment['RELEASE_TAG'])
26
+ const repository = optional(environment['GITHUB_REPOSITORY'])
27
+
28
+ if (!token || !tag || !repository) {
29
+ throw new Error('GH_TOKEN, RELEASE_TAG and GITHUB_REPOSITORY are required')
30
+ }
31
+
32
+ return {
33
+ token,
34
+ tag,
35
+ settings: {
36
+ repository,
37
+ start_tag: optional(environment['RELEASE_START_TAG']),
38
+ workflow: optional(environment['RELEASE_WORKFLOW']),
39
+ jobs: job_names(environment['RELEASE_JOBS']),
40
+ },
41
+ }
42
+ }
43
+
44
+ const github_release_environment = { read_release_input }
45
+
46
+ export { github_release_environment }
@@ -2,15 +2,15 @@ import { setTimeout } from 'node:timers/promises'
2
2
  import semver from 'semver'
3
3
  import { z } from 'zod'
4
4
 
5
- const API_URL = 'https://api.github.com/repos/joshuafolkken/kit/releases'
6
- const WORKFLOW_RUNS_URL =
7
- 'https://api.github.com/repos/joshuafolkken/kit/actions/workflows/publish.yml/runs?per_page=100'
8
- const WORKFLOW_JOBS_URL = 'https://api.github.com/repos/joshuafolkken/kit/actions/runs'
5
+ const API_ROOT = 'https://api.github.com/repos'
6
+ const LATEST_PATH = '/releases/latest'
7
+ const REPOSITORY_PATTERN = /^[\w.-]+\/[\w.-]+$/u
9
8
  const TAG_PATTERN = /^v\d+\.\d+\.\d+(?:[.-][0-9A-Za-z.-]+)?$/u
10
9
  const REQUEST_TIMEOUT_MS = 30_000
11
10
  const NOT_FOUND_STATUS = 404
12
- // Tags through v1.887.0 predate automatic GitHub Releases and must not block the first new release.
13
- const AUTOMATION_START_TAG = 'v1.887.0'
11
+ // A job skipped by its `if:` (or neutral) belongs to a run that succeeded; counting it would skip a
12
+ // lower tag whose release is still on its way.
13
+ const FAILED_CONCLUSIONS = new Set(['failure', 'cancelled', 'timed_out', 'startup_failure'])
14
14
  const POLL_INTERVAL_MS = 30_000
15
15
  const MAX_WAIT_ATTEMPTS = 120
16
16
  const RELEASE_SCHEMA = z.object({ tag_name: z.string().min(1) })
@@ -23,16 +23,42 @@ const JOB_SCHEMA = z.object({
23
23
  })
24
24
  const RUNS_SCHEMA = z.object({ workflow_runs: z.array(RUN_SCHEMA) })
25
25
  const JOBS_SCHEMA = z.object({ jobs: z.array(JOB_SCHEMA) })
26
- const PREREQUISITES = ['publish-github', 'publish-npm', 'update-production']
27
26
 
28
27
  type ReleaseRequest = (url: string, init: RequestInit) => Promise<Response>
29
28
  type Wait = () => Promise<void>
30
29
 
31
- interface PublishOptions {
30
+ // What differs between repositories. `start_tag` is the last tag that predates automatic releases;
31
+ // without it the latest existing release is the floor. `workflow` names the publish workflow whose
32
+ // failed run lets a lower tag be skipped, and `jobs` the jobs in it that count (empty: every job).
33
+ interface ReleaseSettings {
34
+ repository: string
35
+ start_tag?: string | undefined
36
+ workflow?: string | undefined
37
+ jobs?: ReadonlyArray<string> | undefined
38
+ }
39
+
40
+ interface PublishOptions extends ReleaseSettings {
32
41
  tags?: ReadonlyArray<string>
33
42
  wait?: Wait
34
43
  }
35
44
 
45
+ interface Client {
46
+ request: ReleaseRequest
47
+ token: string
48
+ url: string
49
+ workflow: string | undefined
50
+ jobs: ReadonlyArray<string>
51
+ }
52
+
53
+ // `fallback` answers when no tag sits between the floor and the target; without one the floor itself
54
+ // is the latest release and the answer.
55
+ interface Ladder {
56
+ tags: ReadonlyArray<string>
57
+ floor: string | undefined
58
+ fallback?: () => Promise<string>
59
+ wait: Wait
60
+ }
61
+
36
62
  function request_options(token: string, method: string, body?: object): RequestInit {
37
63
  return {
38
64
  method,
@@ -46,21 +72,22 @@ function request_options(token: string, method: string, body?: object): RequestI
46
72
  }
47
73
  }
48
74
 
75
+ async function api_get(client: Client, path: string): Promise<Response> {
76
+ return await client.request(`${client.url}${path}`, request_options(client.token, 'GET'))
77
+ }
78
+
79
+ async function api_post(client: Client, path: string, body: object): Promise<Response> {
80
+ return await client.request(`${client.url}${path}`, request_options(client.token, 'POST', body))
81
+ }
82
+
49
83
  async function read_response(response: Response): Promise<unknown> {
50
84
  if (!response.ok) throw new Error(`GitHub Releases API returned HTTP ${String(response.status)}`)
51
85
 
52
86
  return await response.json()
53
87
  }
54
88
 
55
- async function existing_release(
56
- request: ReleaseRequest,
57
- token: string,
58
- tag: string,
59
- ): Promise<boolean> {
60
- const response = await request(
61
- `${API_URL}/tags/${encodeURIComponent(tag)}`,
62
- request_options(token, 'GET'),
63
- )
89
+ async function existing_release(client: Client, tag: string): Promise<boolean> {
90
+ const response = await api_get(client, `/releases/tags/${encodeURIComponent(tag)}`)
64
91
  if (response.status === NOT_FOUND_STATUS) return false
65
92
 
66
93
  RELEASE_SCHEMA.parse(await read_response(response))
@@ -68,153 +95,183 @@ async function existing_release(
68
95
  return true
69
96
  }
70
97
 
71
- async function previous_tag(request: ReleaseRequest, token: string): Promise<string> {
72
- const response = await request(`${API_URL}/latest`, request_options(token, 'GET'))
73
- const release = RELEASE_SCHEMA.parse(await read_response(response))
98
+ async function previous_tag(client: Client): Promise<string> {
99
+ const response = await api_get(client, LATEST_PATH)
74
100
 
75
- return release.tag_name
101
+ return RELEASE_SCHEMA.parse(await read_response(response)).tag_name
76
102
  }
77
103
 
78
- function predecessor(tags: ReadonlyArray<string>, target: string): string | undefined {
104
+ async function latest_release(client: Client): Promise<string | undefined> {
105
+ const response = await api_get(client, LATEST_PATH)
106
+ if (response.status === NOT_FOUND_STATUS) return undefined
107
+
108
+ return RELEASE_SCHEMA.parse(await read_response(response)).tag_name
109
+ }
110
+
111
+ function predecessor(
112
+ tags: ReadonlyArray<string>,
113
+ target: string,
114
+ floor: string | undefined,
115
+ ): string | undefined {
79
116
  return tags
80
117
  .filter(
81
- (tag) => semver.valid(tag) && semver.gt(tag, AUTOMATION_START_TAG) && semver.lt(tag, target),
118
+ (tag) =>
119
+ semver.valid(tag) &&
120
+ (floor === undefined || semver.gt(tag, floor)) &&
121
+ semver.lt(tag, target),
82
122
  )
83
123
  .toSorted((left, right) => semver.compare(right, left))[0]
84
124
  }
85
125
 
86
- function is_failed_job(job: z.infer<typeof JOB_SCHEMA>): boolean {
87
- if (job.status !== 'completed' || job.conclusion === 'success') return false
126
+ function is_failed_job(job: z.infer<typeof JOB_SCHEMA>, names: ReadonlyArray<string>): boolean {
127
+ if (job.status !== 'completed' || !FAILED_CONCLUSIONS.has(job.conclusion ?? '')) return false
128
+ if (names.length === 0) return true
88
129
 
89
- return PREREQUISITES.some((name) => job.name === name || job.name.startsWith(`${name} /`))
130
+ return names.some((name) => job.name === name || job.name.startsWith(`${name} /`))
90
131
  }
91
132
 
92
- function publication_failed(jobs: Array<z.infer<typeof JOB_SCHEMA>>): boolean {
93
- return jobs.some((job) => is_failed_job(job))
94
- }
133
+ async function failed_publication(client: Client, tag: string): Promise<boolean> {
134
+ if (client.workflow === undefined) return false
95
135
 
96
- async function failed_publication(
97
- request: ReleaseRequest,
98
- token: string,
99
- tag: string,
100
- ): Promise<boolean> {
101
- const runs_response = await request(WORKFLOW_RUNS_URL, request_options(token, 'GET'))
136
+ const workflow = encodeURIComponent(client.workflow)
137
+ const runs_response = await api_get(client, `/actions/workflows/${workflow}/runs?per_page=100`)
102
138
  const runs = RUNS_SCHEMA.parse(await read_response(runs_response)).workflow_runs
103
139
  const run = runs.find((item) => item.display_title === `Publish ${tag}`)
104
140
  if (!run) return false
105
141
 
106
- const url = `${WORKFLOW_JOBS_URL}/${String(run.id)}/jobs?per_page=100`
107
- const jobs_response = await request(url, request_options(token, 'GET'))
142
+ const jobs_response = await api_get(client, `/actions/runs/${String(run.id)}/jobs?per_page=100`)
143
+ const { jobs } = JOBS_SCHEMA.parse(await read_response(jobs_response))
108
144
 
109
- return publication_failed(JOBS_SCHEMA.parse(await read_response(jobs_response)).jobs)
145
+ return jobs.some((job) => is_failed_job(job, client.jobs))
110
146
  }
111
147
 
112
148
  async function default_wait(): Promise<void> {
113
149
  await setTimeout(POLL_INTERVAL_MS)
114
150
  }
115
151
 
116
- async function release_state(
117
- request: ReleaseRequest,
118
- token: string,
119
- tag: string,
120
- ): Promise<'ready' | 'failed' | 'pending'> {
121
- if (await existing_release(request, token, tag)) return 'ready'
122
- if (await failed_publication(request, token, tag)) return 'failed'
152
+ async function release_state(client: Client, tag: string): Promise<'ready' | 'failed' | 'pending'> {
153
+ if (await existing_release(client, tag)) return 'ready'
154
+ if (await failed_publication(client, tag)) return 'failed'
123
155
 
124
156
  return 'pending'
125
157
  }
126
158
 
127
- async function wait_for_release(
128
- request: ReleaseRequest,
129
- token: string,
130
- tag: string,
131
- wait: Wait,
132
- ): Promise<boolean> {
159
+ async function wait_for_release(client: Client, tag: string, wait: Wait): Promise<boolean> {
133
160
  for (let attempt = 0; attempt < MAX_WAIT_ATTEMPTS; attempt += 1) {
134
- const state = await release_state(request, token, tag)
161
+ // eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
162
+ const state = await release_state(client, tag)
135
163
  if (state !== 'pending') return state === 'ready'
136
164
 
165
+ // eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
137
166
  await wait()
138
167
  }
139
168
 
140
169
  throw new Error(`Timed out waiting for previous GitHub Release ${tag}`)
141
170
  }
142
171
 
172
+ async function ladder_end(ladder: Ladder): Promise<string | undefined> {
173
+ return ladder.fallback ? await ladder.fallback() : ladder.floor
174
+ }
175
+
176
+ // With no floor the repository has no release at all, so no lower tag will ever gain one: the
177
+ // nearest lower tag is the baseline as it stands, and none means notes without a baseline.
143
178
  async function baseline_tag(
144
- request: ReleaseRequest,
145
- token: string,
179
+ client: Client,
146
180
  tag: string,
147
- options: PublishOptions,
148
- ): Promise<string> {
149
- const prior = predecessor(options.tags ?? [], tag)
150
- if (!prior) return await previous_tag(request, token)
181
+ ladder: Ladder,
182
+ ): Promise<string | undefined> {
183
+ const prior = predecessor(ladder.tags, tag, ladder.floor)
184
+ if (ladder.floor === undefined) return prior
185
+ if (!prior) return await ladder_end(ladder)
186
+
187
+ return (await wait_for_release(client, prior, ladder.wait))
188
+ ? prior
189
+ : await baseline_tag(client, prior, ladder)
190
+ }
151
191
 
152
- if (!(await wait_for_release(request, token, prior, options.wait ?? default_wait))) {
153
- return await baseline_tag(request, token, prior, options)
192
+ function assert_older(previous: string | undefined, tag: string): void {
193
+ if (previous !== undefined && !semver.lt(previous, tag)) {
194
+ throw new Error(`Latest release ${previous} is not older than ${tag}`)
195
+ }
196
+ }
197
+
198
+ async function build_ladder(client: Client, options: PublishOptions): Promise<Ladder> {
199
+ const tags = options.tags ?? []
200
+ const wait = options.wait ?? default_wait
201
+ const { start_tag } = options
202
+
203
+ if (start_tag !== undefined) {
204
+ return { tags, wait, floor: start_tag, fallback: async () => await previous_tag(client) }
154
205
  }
155
206
 
156
- return prior
207
+ return { tags, wait, floor: await latest_release(client) }
157
208
  }
158
209
 
159
210
  async function generate_notes(
160
- request: ReleaseRequest,
161
- token: string,
211
+ client: Client,
162
212
  tag: string,
163
- previous: string,
213
+ previous: string | undefined,
164
214
  ): Promise<z.infer<typeof NOTES_SCHEMA>> {
165
- const response = await request(
166
- `${API_URL}/generate-notes`,
167
- request_options(token, 'POST', {
168
- tag_name: tag,
169
- previous_tag_name: previous,
170
- configuration_file_path: '.github/release.yml',
171
- }),
172
- )
215
+ const response = await api_post(client, '/releases/generate-notes', {
216
+ tag_name: tag,
217
+ ...(previous !== undefined && { previous_tag_name: previous }),
218
+ configuration_file_path: '.github/release.yml',
219
+ })
173
220
 
174
221
  return NOTES_SCHEMA.parse(await read_response(response))
175
222
  }
176
223
 
177
224
  async function create_release(
178
- request: ReleaseRequest,
179
- token: string,
225
+ client: Client,
180
226
  tag: string,
181
- previous: string,
227
+ previous: string | undefined,
182
228
  ): Promise<void> {
183
- const notes = await generate_notes(request, token, tag, previous)
184
- const response = await request(
185
- API_URL,
186
- request_options(token, 'POST', {
187
- tag_name: tag,
188
- name: notes.name,
189
- body: notes.body,
190
- draft: false,
191
- prerelease: false,
192
- }),
193
- )
229
+ const notes = await generate_notes(client, tag, previous)
230
+ const response = await api_post(client, '/releases', {
231
+ tag_name: tag,
232
+ name: notes.name,
233
+ body: notes.body,
234
+ draft: false,
235
+ prerelease: false,
236
+ })
194
237
 
195
238
  RELEASE_SCHEMA.parse(await read_response(response))
196
239
  }
197
240
 
241
+ function create_client(request: ReleaseRequest, token: string, settings: ReleaseSettings): Client {
242
+ if (!REPOSITORY_PATTERN.test(settings.repository)) {
243
+ throw new Error(`Invalid repository: ${settings.repository}`)
244
+ }
245
+
246
+ return {
247
+ request,
248
+ token,
249
+ url: `${API_ROOT}/${settings.repository}`,
250
+ workflow: settings.workflow,
251
+ jobs: settings.jobs ?? [],
252
+ }
253
+ }
254
+
198
255
  async function publish(
199
256
  request: ReleaseRequest,
200
257
  token: string,
201
258
  tag: string,
202
- options: PublishOptions = {},
259
+ options: PublishOptions,
203
260
  ): Promise<string> {
204
261
  if (!TAG_PATTERN.test(tag)) throw new Error(`Invalid release tag: ${tag}`)
205
- if (await existing_release(request, token, tag)) return 'already-published'
206
262
 
207
- const previous = await baseline_tag(request, token, tag, options)
263
+ const client = create_client(request, token, options)
264
+ if (await existing_release(client, tag)) return 'already-published'
208
265
 
209
- if (!semver.lt(previous, tag)) {
210
- throw new Error(`Latest release ${previous} is not older than ${tag}`)
211
- }
266
+ const previous = await baseline_tag(client, tag, await build_ladder(client, options))
212
267
 
213
- await create_release(request, token, tag, previous)
268
+ assert_older(previous, tag)
269
+ await create_release(client, tag, previous)
214
270
 
215
- return `published ${tag} from ${previous}`
271
+ return `published ${tag} from ${previous ?? 'the first commit'}`
216
272
  }
217
273
 
218
274
  const github_release = { publish }
219
275
 
276
+ export type { ReleaseSettings }
220
277
  export { github_release }
@@ -125,7 +125,6 @@ const release_history = {
125
125
  read_current_version,
126
126
  read_release_plan,
127
127
  BASE_SEARCH_LIMIT,
128
- DEFAULT_TIP,
129
128
  }
130
129
 
131
130
  export { release_history }
@@ -123,7 +123,6 @@ const release_plan = {
123
123
  format_plan,
124
124
  next_version,
125
125
  short_sha,
126
- PENDING_ICON,
127
126
  }
128
127
 
129
128
  export { release_plan }
@@ -1,6 +1,6 @@
1
+ import { git_gh_command } from '#scripts/gh/git-gh-command'
2
+ import { git_pr_checks } from '#scripts/gh/git-pr-checks'
1
3
  import { git_command } from '#scripts/git/git-command'
2
- import { git_gh_command } from '#scripts/git/git-gh-command'
3
- import { git_pr_checks } from '#scripts/git/git-pr-checks'
4
4
  import { git_remote_branch } from '#scripts/git/git-remote-branch'
5
5
  import { write_version } from '#scripts/version/bump-version'
6
6
  import { version_targets } from '#scripts/version/version-targets'
@@ -150,7 +150,6 @@ const release_publish = {
150
150
  publish,
151
151
  pull_request_body,
152
152
  unreachable_remote_message,
153
- FAILURE_EXIT_CODE,
154
153
  SUCCESS_EXIT_CODE,
155
154
  }
156
155
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env tsx
2
2
  import { fileURLToPath } from 'node:url'
3
- import { git_followup_pending } from '#scripts/git/git-followup-pending'
3
+ import { git_followup_pending } from '#scripts/followup/git-followup-pending'
4
4
  import { path_decision } from '#scripts/josh/path-decision'
5
5
  import { release_plan } from './release-plan'
6
6
 
@@ -87,7 +87,6 @@ const release_scope_cli = {
87
87
  main,
88
88
  run,
89
89
  JSON_KEY,
90
- KNOWN_FLAGS,
91
90
  NOTHING_PENDING_REASON,
92
91
  RELEASE_HINT,
93
92
  REQUIRED_SCOPE,
@@ -1,5 +1,5 @@
1
- import { git_gh_api_path } from '#scripts/git/git-gh-api-path'
2
- import { git_gh_exec } from '#scripts/git/git-gh-exec'
1
+ import { git_gh_api_path } from '#scripts/gh/git-gh-api-path'
2
+ import { git_gh_exec } from '#scripts/gh/git-gh-exec'
3
3
  import { poll, type PollOptions } from '#scripts/lib/poll'
4
4
 
5
5
  // **The release is not finished when the pull request merges — it is finished when the tag exists.**
@@ -82,12 +82,10 @@ const release_tag = {
82
82
  attempts_for,
83
83
  configured_timeout_seconds,
84
84
  format_result,
85
- tag_exists,
86
85
  tag_name,
87
86
  wait_for_tag,
88
87
  DEFAULT_TIMEOUT_SECONDS,
89
88
  TAG_POLL_INTERVAL_MS,
90
- TIMEOUT_ENV,
91
89
  }
92
90
 
93
91
  export { release_tag }