@joshuafolkken/kit 1.1050.0 → 1.1128.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (630) hide show
  1. package/.claude/settings.json +9 -8
  2. package/.claude/skills/epic-commands/SKILL.md +5 -7
  3. package/.claude/skills/workflow-commands/SKILL.md +20 -12
  4. package/.claude/skills/workflow-commands/background-commands.md +36 -84
  5. package/.claude/skills/workflow-commands/backlogrun-child.md +1 -1
  6. package/.claude/skills/workflow-commands/backlogrun-lanes.md +8 -6
  7. package/.claude/skills/workflow-commands/backlogrun-progress.md +30 -33
  8. package/.claude/skills/workflow-commands/backlogrun-steps.md +12 -12
  9. package/.claude/skills/workflow-commands/backlogrun.md +2 -2
  10. package/.claude/skills/workflow-commands/chain-rule.md +4 -2
  11. package/.claude/skills/workflow-commands/delegation.md +3 -3
  12. package/.claude/skills/workflow-commands/followup-reference.md +1 -1
  13. package/.claude/skills/workflow-commands/followup.md +7 -3
  14. package/.claude/skills/workflow-commands/fullrun-steps.md +3 -2
  15. package/.claude/skills/workflow-commands/fullrun.md +8 -6
  16. package/.claude/skills/workflow-commands/halfrun.md +19 -21
  17. package/.claude/skills/workflow-commands/issue-comments.md +1 -1
  18. package/.claude/skills/workflow-commands/issue-fold-existing.md +10 -10
  19. package/.claude/skills/workflow-commands/issue-scout.md +1 -1
  20. package/.claude/skills/workflow-commands/kickoff.md +9 -4
  21. package/.claude/skills/workflow-commands/latest-gate.md +8 -16
  22. package/.claude/skills/workflow-commands/needs-human-review.md +1 -1
  23. package/.claude/skills/workflow-commands/observation-filing.md +3 -3
  24. package/.claude/skills/workflow-commands/pre-gate-cut.md +4 -8
  25. package/.claude/skills/workflow-commands/prerequisite.md +1 -1
  26. package/.claude/skills/workflow-commands/prrun.md +36 -0
  27. package/.claude/skills/workflow-commands/retrospective.md +1 -1
  28. package/.claude/skills/workflow-commands/split-assessment.md +4 -18
  29. package/.claude/skills/workflow-commands/working-tree-hold.md +22 -2
  30. package/.codex/hooks.json +16 -20
  31. package/.github/actions/setup-node/action.yml +33 -0
  32. package/.github/actions/setup-pnpm/action.yml +93 -0
  33. package/.github/dependabot.yml +5 -1
  34. package/.github/workflows/auto-tag.yml +2 -3
  35. package/.github/workflows/ci.yml +31 -134
  36. package/.github/workflows/dependabot-auto-merge.yml +1 -0
  37. package/.github/workflows/pr-classification.yml +6 -44
  38. package/.github/workflows/production.yml +1 -0
  39. package/.github/workflows/publish.yml +43 -47
  40. package/.github/workflows/sonar-qube.yml +41 -4
  41. package/.pnpmfile.mjs +29 -0
  42. package/AGENTS.md +5 -2
  43. package/CLAUDE.md +33 -27
  44. package/GEMINI.md +5 -2
  45. package/README.md +66 -20
  46. package/SECURITY.md +37 -6
  47. package/cspell/index.yaml +6 -1
  48. package/dist/CLAUDE.basic.md +6 -6
  49. package/dist/CLAUDE.md +33 -27
  50. package/dist/CLAUDE.static.md +6 -6
  51. package/dist/config-merge/index.js +48 -12
  52. package/dist/hooks/batch-guard.js +4 -4
  53. package/dist/hooks/{chunk-7VPDUBRN.js → chunk-4JZDP5X5.js} +152 -155
  54. package/dist/hooks/{chunk-HJIISEAC.js → chunk-5SD2YM7Z.js} +5 -13
  55. package/dist/hooks/{chunk-NAS4C7GP.js → chunk-77J7IEQM.js} +2 -2
  56. package/dist/hooks/{chunk-DMQN45FN.js → chunk-7HVB7SZG.js} +3 -3
  57. package/dist/hooks/{chunk-RLDX5SOC.js → chunk-AIOIOMPX.js} +4413 -1970
  58. package/dist/hooks/{chunk-5BK3K7V4.js → chunk-M7QKEKWO.js} +873 -2049
  59. package/dist/hooks/{chunk-WQ4OSBSS.js → chunk-MKVGBQPA.js} +2 -2
  60. package/dist/hooks/{chunk-EJDX2TOB.js → chunk-NXYMNPUQ.js} +7 -88
  61. package/dist/hooks/{chunk-NJQOBE6L.js → chunk-QVLT52OV.js} +2 -7
  62. package/dist/hooks/{chunk-GQ7KP45M.js → chunk-XYUIQOW3.js} +2 -2
  63. package/dist/hooks/codex-hook-adapter.js +12 -48
  64. package/dist/hooks/duplicate-read-guard.js +5 -5
  65. package/dist/hooks/format-edited.js +2 -2
  66. package/dist/hooks/inputs.json +280 -0
  67. package/dist/hooks/investigation-guard.js +5 -5
  68. package/dist/hooks/pretool-guard.js +9 -9
  69. package/dist/hooks/session-lang.js +0 -1
  70. package/dist/hooks/stop-guard.js +192 -333
  71. package/dist/josh.js +240 -148
  72. package/dist/managed-marker/index.js +2 -1
  73. package/dist/version/index.js +70 -78
  74. package/eslint/rules/promise.js +5 -0
  75. package/eslint/rules/unicorn.js +3 -2
  76. package/package.json +26 -5
  77. package/pnpm-workspace.yaml +5 -7
  78. package/prompts/collaboration-workflow/glossary.md +17 -0
  79. package/prompts/collaboration-workflow/issue-citation.md +5 -5
  80. package/prompts/collaboration-workflow/issue-template.md +1 -1
  81. package/prompts/collaboration-workflow/operating-rules.md +5 -5
  82. package/prompts/collaboration-workflow/overview.md +13 -1
  83. package/prompts/collaboration-workflow/principles.md +9 -0
  84. package/prompts/collaboration-workflow/report-format.md +1 -1
  85. package/prompts/collaboration-workflow/residency.md +3 -3
  86. package/prompts/collaboration-workflow/rule-delivery.md +1 -1
  87. package/prompts/collaboration-workflow/turn-batching.md +3 -3
  88. package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
  89. package/prompts/collaboration-workflow/wip-cap.md +25 -22
  90. package/prompts/collaboration-workflow.md +6 -8
  91. package/prompts/review-rubric.md +1 -1
  92. package/prompts/review.md +3 -3
  93. package/prompts/sonar-hotspot-handling.md +11 -3
  94. package/prompts/testing-guide.md +3 -3
  95. package/scripts/adopt/adopt-toolkits.ts +0 -2
  96. package/scripts/adopt/adopt.ts +0 -2
  97. package/scripts/agent/agent-argv.ts +0 -2
  98. package/scripts/agent/agent-diagnostics.ts +1 -1
  99. package/scripts/agent/agent-role-profile.ts +0 -7
  100. package/scripts/agent/claude-agent-argv.ts +0 -2
  101. package/scripts/agent/codex-agent-argv.ts +1 -1
  102. package/scripts/agent/codex-hooks.ts +92 -0
  103. package/scripts/agent/interactive-ask.ts +1 -1
  104. package/scripts/auto-ok/auto-ok-cli.ts +6 -16
  105. package/scripts/backlog/backlog-arrival.ts +30 -10
  106. package/scripts/backlog/backlog-budget-cli.ts +15 -16
  107. package/scripts/backlog/backlog-budget.ts +0 -2
  108. package/scripts/backlog/backlog-defect-priority.ts +2 -2
  109. package/scripts/backlog/backlog-drive-cli.ts +10 -8
  110. package/scripts/backlog/backlog-drive-named-offer.ts +16 -3
  111. package/scripts/backlog/backlog-drive-named.ts +2 -1
  112. package/scripts/backlog/backlog-drive.ts +76 -16
  113. package/scripts/backlog/backlog-named.ts +0 -3
  114. package/scripts/backlog/backlog-next.ts +9 -15
  115. package/scripts/backlog/backlog-offer-cli.ts +6 -19
  116. package/scripts/backlog/backlog-plan-cli.ts +1 -7
  117. package/scripts/backlog/backlog-plan.ts +30 -19
  118. package/scripts/backlog/backlog-pool.ts +3 -6
  119. package/scripts/backlog/backlog-rank.ts +2 -2
  120. package/scripts/backlog/backlog-ready.ts +39 -10
  121. package/scripts/backlog/backlog-scope.ts +1 -3
  122. package/scripts/backlog/backlog-stalled-detect.ts +2 -2
  123. package/scripts/backlog/backlog-stalled.ts +0 -1
  124. package/scripts/backlog/backlog-waves.ts +5 -2
  125. package/scripts/behavior/behavior-cli.ts +1 -1
  126. package/scripts/build/build-codex-hooks.ts +26 -0
  127. package/scripts/build/build-hooks.ts +85 -9
  128. package/scripts/build/hook-bundle-stamp.ts +111 -0
  129. package/scripts/cases/cases-cli.ts +1 -1
  130. package/scripts/cases/cases-logic.ts +1 -1
  131. package/scripts/ci/composite-actions.ts +30 -0
  132. package/scripts/ci/pr-classification.ts +3 -3
  133. package/scripts/claude/workflow-destination.ts +10 -1
  134. package/scripts/clone/clone-fingerprint.ts +0 -1
  135. package/scripts/clone/clone-scan-cli.ts +1 -1
  136. package/scripts/clone/clone-scan.ts +1 -1
  137. package/scripts/config-merge/json-format.ts +0 -1
  138. package/scripts/config-merge/parse-jsonc.ts +33 -3
  139. package/scripts/config-merge/patch-json-key.ts +13 -6
  140. package/scripts/config-merge/patch-yaml-list.ts +1 -1
  141. package/scripts/cost-runtime/codex-usage.ts +2 -9
  142. package/scripts/cost-runtime/cost-attribute.ts +0 -1
  143. package/scripts/cost-runtime/cost-cli.ts +3 -10
  144. package/scripts/cost-runtime/cost-corpus.ts +0 -2
  145. package/scripts/cost-runtime/cost-format.ts +0 -3
  146. package/scripts/cost-runtime/cost-pricing.ts +0 -1
  147. package/scripts/cost-runtime/cost-tokens.ts +0 -1
  148. package/scripts/delegation/delegation-cli.ts +1 -1
  149. package/scripts/delegation/delegation-policy.ts +0 -1
  150. package/scripts/delegation/duplicate-read-guard.ts +0 -8
  151. package/scripts/delegation/fanout-cli.ts +1 -1
  152. package/scripts/delegation/fanout.ts +0 -2
  153. package/scripts/delegation/investigation-reads.ts +1 -164
  154. package/scripts/discovery/repo-map-logic.ts +0 -1
  155. package/scripts/discovery/repo-party-cli.ts +1 -1
  156. package/scripts/doctor/doctor-consumer.ts +6 -10
  157. package/scripts/doctor/doctor-io.ts +9 -13
  158. package/scripts/doctor/doctor-logic.ts +0 -4
  159. package/scripts/doctor/doctor.ts +14 -9
  160. package/scripts/document/backlogrun-parent-read-set.ts +12 -1
  161. package/scripts/document/document-byte-budget.ts +5 -5
  162. package/scripts/document/document-byte-check.ts +0 -1
  163. package/scripts/document/document-read-cli.ts +0 -2
  164. package/scripts/document/document-section-cli.ts +1 -1
  165. package/scripts/document/document-section.ts +0 -3
  166. package/scripts/document/edit-files-cli.ts +0 -1
  167. package/scripts/document/entry-read-budget.ts +21 -7
  168. package/scripts/document/entry-read-set.ts +32 -8
  169. package/scripts/document/lane-child-read-set.ts +8 -6
  170. package/scripts/document/read-files-cli.ts +0 -4
  171. package/scripts/document/read-set-cli.ts +0 -2
  172. package/scripts/document/read-set-point-of-use.ts +9 -3
  173. package/scripts/document/read-set-pricing.ts +0 -1
  174. package/scripts/document/read-set-trim.ts +4 -2
  175. package/scripts/epic/epic-add.ts +1 -1
  176. package/scripts/epic/epic-audit-cli.ts +1 -4
  177. package/scripts/epic/epic-audit-orphans.ts +1 -3
  178. package/scripts/epic/epic-audit-rationale.ts +0 -1
  179. package/scripts/epic/epic-audit-report.ts +0 -2
  180. package/scripts/epic/epic-audit.ts +8 -22
  181. package/scripts/epic/epic-bundle-cli.ts +1 -1
  182. package/scripts/epic/epic-bundle-evidence.ts +0 -1
  183. package/scripts/epic/epic-bundle-referenced.ts +1 -5
  184. package/scripts/epic/epic-bundle.ts +0 -4
  185. package/scripts/epic/epic-busy.ts +4 -5
  186. package/scripts/epic/epic-candidate-confirm.ts +0 -5
  187. package/scripts/epic/epic-classify.ts +2 -2
  188. package/scripts/epic/epic-cli-argv.ts +0 -1
  189. package/scripts/epic/epic-close-comment.ts +1 -1
  190. package/scripts/epic/epic-close.ts +5 -2
  191. package/scripts/epic/epic-cross-repo.ts +2 -4
  192. package/scripts/epic/epic-decision.ts +0 -1
  193. package/scripts/epic/epic-fetch.ts +2 -2
  194. package/scripts/epic/epic-index.ts +2 -3
  195. package/scripts/epic/epic-issue.ts +1 -15
  196. package/scripts/epic/epic-lane-offer.ts +9 -8
  197. package/scripts/epic/epic-nested.ts +1 -1
  198. package/scripts/epic/epic-next-read.ts +1 -3
  199. package/scripts/epic/epic-next-views.ts +0 -1
  200. package/scripts/epic/epic-next.ts +1 -10
  201. package/scripts/epic/epic-parse.ts +0 -1
  202. package/scripts/epic/epic-promote.ts +0 -9
  203. package/scripts/epic/epic-rank.ts +2 -2
  204. package/scripts/epic/epic-read.ts +1 -2
  205. package/scripts/epic/epic-reconcile.ts +1 -1
  206. package/scripts/epic/epic-reference.ts +1 -13
  207. package/scripts/epic/epic-relation-recheck.ts +1 -1
  208. package/scripts/epic/epic-relations.ts +1 -1
  209. package/scripts/epic/epic-remove.ts +1 -1
  210. package/scripts/epic/epic-report.ts +0 -1
  211. package/scripts/epic/epic-run.ts +2 -3
  212. package/scripts/epic/epic-shape.ts +1 -1
  213. package/scripts/epic/epic-solo-stale.ts +107 -0
  214. package/scripts/epic/epic-solo.ts +3 -2
  215. package/scripts/epic/epic-triage.ts +1 -1
  216. package/scripts/epic/epic-validate.ts +1 -1
  217. package/scripts/epic/epic.ts +1 -1
  218. package/scripts/exports/unused-members-cli.ts +53 -0
  219. package/scripts/{git → followup}/followup-issue-number.ts +1 -6
  220. package/scripts/{git → followup}/git-followup-cleanup.ts +2 -1
  221. package/scripts/{git → followup}/git-followup-finish.ts +1 -3
  222. package/scripts/{git → followup}/git-followup-flush.ts +2 -2
  223. package/scripts/{git → followup}/git-followup-issue-close.ts +2 -2
  224. package/scripts/{git → followup}/git-followup-label.ts +4 -4
  225. package/scripts/followup/git-followup-merged.ts +112 -0
  226. package/scripts/{git → followup}/git-followup-pending.ts +1 -1
  227. package/scripts/{git → followup}/git-followup-workflow.ts +19 -11
  228. package/scripts/{git → followup}/git-pr-followup-wrapup.ts +9 -3
  229. package/scripts/{git → followup}/git-pr-followup.ts +53 -16
  230. package/scripts/gate/core-budget.ts +3 -9
  231. package/scripts/gate/gate-plan.ts +7 -4
  232. package/scripts/gate/gate-report.ts +0 -6
  233. package/scripts/gate/gate-tree.ts +1 -1
  234. package/scripts/gate/pre-commit-type-check.ts +0 -6
  235. package/scripts/gate/project-checks.ts +7 -8
  236. package/scripts/gate/scoped-green.ts +0 -1
  237. package/scripts/gate/type-check-step.ts +1 -1
  238. package/scripts/gate/verification-gate.ts +0 -2
  239. package/scripts/gh/fix-gh-packages.ts +15 -12
  240. package/scripts/gh/gh-spawn.ts +2 -2
  241. package/scripts/{git → gh}/git-ai-review-scan.ts +1 -5
  242. package/scripts/{git → gh}/git-gh-check.ts +2 -1
  243. package/scripts/{git → gh}/git-gh-exec.ts +1 -1
  244. package/scripts/{git → gh}/git-gh-failure.ts +1 -1
  245. package/scripts/{git → gh}/git-gh-helpers.ts +0 -1
  246. package/scripts/{git → gh}/git-gh-issue-list.ts +13 -10
  247. package/scripts/{git → gh}/git-gh-issue-read.ts +1 -1
  248. package/scripts/{git → gh}/git-gh-issue-rest.ts +6 -3
  249. package/scripts/{git → gh}/git-gh-issue-write.ts +4 -1
  250. package/scripts/{git → gh}/git-gh-pr-auto-merge.ts +4 -1
  251. package/scripts/{git → gh}/git-gh-pr-read.ts +24 -0
  252. package/scripts/{git → gh}/git-gh-pr-rest.ts +5 -2
  253. package/scripts/{git → gh}/git-gh-pr-review.ts +2 -2
  254. package/scripts/{git → gh}/git-gh-pr-rollup.ts +1 -3
  255. package/scripts/{git → gh}/git-gh-pr.ts +3 -1
  256. package/scripts/{git → gh}/git-pr-ai-review.ts +2 -5
  257. package/scripts/{git → gh}/git-pr-checks-eval.ts +0 -10
  258. package/scripts/{git → gh}/git-pr-checks-parse.ts +4 -20
  259. package/scripts/{git → gh}/git-pr-checks.ts +2 -1
  260. package/scripts/{git → gh}/git-pr-coderabbit.ts +2 -5
  261. package/scripts/{git → gh}/git-pr-confirmation.ts +1 -3
  262. package/scripts/{git → gh}/git-pr-managed-config.ts +2 -3
  263. package/scripts/{git → gh}/git-pr.ts +3 -3
  264. package/scripts/git/changed-file-scope.ts +0 -1
  265. package/scripts/git/git-branch.ts +3 -6
  266. package/scripts/git/git-command.ts +6 -1
  267. package/scripts/git/git-commit.ts +1 -1
  268. package/scripts/git/git-common-directory.ts +80 -24
  269. package/scripts/git/git-error.ts +66 -9
  270. package/scripts/git/git-issue.ts +1 -1
  271. package/scripts/git/git-preflight.ts +2 -2
  272. package/scripts/git/git-prompt.ts +6 -31
  273. package/scripts/git/git-push.ts +1 -1
  274. package/scripts/git/git-spawn-sync.ts +65 -0
  275. package/scripts/git/git-spawn.ts +5 -4
  276. package/scripts/git/git-staging.ts +1 -0
  277. package/scripts/git/git-status.ts +1 -1
  278. package/scripts/git/git-workflow.ts +1 -1
  279. package/scripts/git/gone-branch.ts +1 -0
  280. package/scripts/git/listing-cutoff.ts +1 -1
  281. package/scripts/git/main-merge.ts +1 -1
  282. package/scripts/git/main-sync.ts +19 -1
  283. package/scripts/git/parse-json-array.ts +0 -3
  284. package/scripts/git/repository-lock.ts +16 -16
  285. package/scripts/git/{git-stash.ts → stash/git-stash.ts} +1 -1
  286. package/scripts/git/{stash-pop-args.ts → stash/stash-pop-args.ts} +2 -7
  287. package/scripts/git/{stash-pop-cli.ts → stash/stash-pop-cli.ts} +0 -1
  288. package/scripts/git/{stash-sweep-lock.ts → stash/stash-sweep-lock.ts} +3 -3
  289. package/scripts/hooks/codex-hook-adapter.ts +0 -1
  290. package/scripts/hooks/edited-cspell.ts +1 -1
  291. package/scripts/hooks/format-edited-file.ts +2 -0
  292. package/scripts/hooks/pre-push-unit.ts +0 -4
  293. package/scripts/hooks/pretool-guard.ts +22 -4
  294. package/scripts/hooks/reserved-run.ts +1 -1
  295. package/scripts/hooks/step-zero-notice.ts +76 -0
  296. package/scripts/hooks/stop-guard.ts +47 -21
  297. package/scripts/init/claude-plugin-config.ts +4 -5
  298. package/scripts/init/hook-command-rewrite.ts +16 -8
  299. package/scripts/init/hook-launch.ts +41 -15
  300. package/scripts/init/init-basic.ts +2 -5
  301. package/scripts/init/init-file-action.ts +54 -0
  302. package/scripts/init/init-logic-migrate.ts +35 -17
  303. package/scripts/init/init-logic-secretlint.ts +1 -1
  304. package/scripts/init/init-logic.ts +10 -19
  305. package/scripts/init/init.ts +11 -71
  306. package/scripts/init/kit-written-paths.ts +2 -0
  307. package/scripts/init/project-profile.ts +9 -17
  308. package/scripts/init/start-exec.ts +1 -1
  309. package/scripts/init/start-setup-pr.ts +6 -6
  310. package/scripts/init/start-steps.ts +3 -1
  311. package/scripts/issue/behavior-change-lint.ts +0 -1
  312. package/scripts/issue/defect-rate-cli.ts +64 -23
  313. package/scripts/issue/defect-rate.ts +1 -2
  314. package/scripts/{git → issue}/git-next-issues.ts +3 -3
  315. package/scripts/issue/issue-backlinks-cli.ts +1 -5
  316. package/scripts/issue/issue-backlinks.ts +7 -14
  317. package/scripts/issue/issue-cite-cli.ts +2 -6
  318. package/scripts/issue/issue-cite.ts +12 -8
  319. package/scripts/issue/issue-classification.ts +1 -9
  320. package/scripts/issue/issue-closing-pr.ts +4 -4
  321. package/scripts/issue/issue-comment-cli.ts +2 -2
  322. package/scripts/issue/issue-file-cli.ts +5 -5
  323. package/scripts/issue/issue-file.ts +7 -14
  324. package/scripts/issue/issue-fold-cli.ts +1 -1
  325. package/scripts/issue/issue-fold-existing-cli.ts +1 -1
  326. package/scripts/{git → issue}/issue-labels.ts +8 -0
  327. package/scripts/issue/issue-lint-cli.ts +1 -1
  328. package/scripts/issue/issue-merged.ts +2 -2
  329. package/scripts/{git → issue}/issue-rank.ts +1 -1
  330. package/scripts/issue/issue-read-cli.ts +8 -47
  331. package/scripts/issue/issue-read.ts +0 -2
  332. package/scripts/issue/issue-report-failures.ts +80 -0
  333. package/scripts/issue/issue-scout-cli.ts +1 -7
  334. package/scripts/issue/issue-scout-closed.ts +2 -2
  335. package/scripts/issue/issue-scout.ts +0 -2
  336. package/scripts/issue/issue-state-cli.ts +5 -46
  337. package/scripts/issue/issue-state.ts +1 -5
  338. package/scripts/issue/markdown-section.ts +21 -6
  339. package/scripts/issue/measure-rerun-cli.ts +74 -15
  340. package/scripts/issue/reproduction-measure.ts +1 -1
  341. package/scripts/josh/cli-body.ts +1 -1
  342. package/scripts/josh/file-map-stamp.ts +0 -3
  343. package/scripts/josh/josh-command-map.ts +2 -0
  344. package/scripts/josh/josh-commands-ai.ts +9 -102
  345. package/scripts/josh/josh-commands-backlog.ts +5 -1
  346. package/scripts/josh/josh-commands-development.ts +8 -1
  347. package/scripts/josh/josh-commands-issue.ts +2 -2
  348. package/scripts/josh/josh-commands-maintenance.ts +7 -0
  349. package/scripts/josh/josh-commands-project.ts +7 -1
  350. package/scripts/josh/josh-commands-run.ts +114 -0
  351. package/scripts/josh/josh-commands-versioning.ts +8 -0
  352. package/scripts/josh/josh-commands-workflow.ts +3 -3
  353. package/scripts/josh/path-decision.ts +0 -3
  354. package/scripts/josh/process-owner.ts +16 -0
  355. package/scripts/josh/run-github-prerequisite.ts +3 -6
  356. package/scripts/josh/session-language-cli.ts +0 -1
  357. package/scripts/lane/lane-await.ts +46 -19
  358. package/scripts/lane/lane-capacity.ts +6 -3
  359. package/scripts/lane/lane-child-invocation.ts +20 -7
  360. package/scripts/lane/lane-cli.ts +1 -4
  361. package/scripts/lane/lane-close.ts +5 -4
  362. package/scripts/lane/lane-dispatch.ts +3 -4
  363. package/scripts/lane/lane-environment.ts +0 -9
  364. package/scripts/lane/lane-handoff.ts +38 -0
  365. package/scripts/lane/lane-launch-cli.ts +31 -27
  366. package/scripts/lane/lane-open.ts +0 -3
  367. package/scripts/lane/lane-output.ts +0 -1
  368. package/scripts/lane/lane-registry.ts +9 -0
  369. package/scripts/lane/openai-lane-ship.ts +2 -0
  370. package/scripts/lane/openai-lane-supervisor-decision.ts +2 -1
  371. package/scripts/lane/openai-lane-supervisor.ts +6 -4
  372. package/scripts/lane/openai-review-broker.ts +7 -1
  373. package/scripts/lib/bounded-pool.ts +1 -0
  374. package/scripts/lib/cli-flags.ts +31 -2
  375. package/scripts/lib/error-message.ts +12 -1
  376. package/scripts/lib/json-value.ts +5 -4
  377. package/scripts/lib/poll.ts +3 -1
  378. package/scripts/lib/timed-fetch.ts +15 -0
  379. package/scripts/lib/timeouts.ts +13 -0
  380. package/scripts/{yaml → lib}/yaml-document.ts +3 -1
  381. package/scripts/{bytes → lines}/bytes-command.ts +0 -2
  382. package/scripts/lines/line-targets.ts +0 -11
  383. package/scripts/lines/lines-command.ts +5 -4
  384. package/scripts/lint/lint-related-scope.ts +0 -1
  385. package/scripts/lint/lint-related.ts +1 -1
  386. package/scripts/{git → notify}/telegram-notify.ts +2 -2
  387. package/scripts/{git → notify}/telegram-test.ts +4 -4
  388. package/scripts/observations/observation-ledger-home.ts +0 -1
  389. package/scripts/observations/observation-ledger-line.ts +0 -1
  390. package/scripts/observations/observation-ledger-migrate.ts +1 -1
  391. package/scripts/observations/observations-flush-landing.ts +3 -3
  392. package/scripts/observations/observations-flush.ts +2 -2
  393. package/scripts/overrides/lockfile-overrides.ts +1 -1
  394. package/scripts/overrides/overrides-logic.ts +1 -1
  395. package/scripts/package/package-scout-cli.ts +2 -7
  396. package/scripts/package/package-scout.ts +0 -2
  397. package/scripts/propagate/propagate-git-failure.ts +0 -1
  398. package/scripts/propagate/propagate-git.ts +3 -10
  399. package/scripts/propagate/propagate-publish.ts +2 -3
  400. package/scripts/propagate/propagate-run.ts +0 -2
  401. package/scripts/propagate/propagate-steps.ts +3 -5
  402. package/scripts/propagate/propagate-targets.ts +0 -4
  403. package/scripts/propagate/propagate.ts +0 -4
  404. package/scripts/refactor/import-graph.ts +0 -1
  405. package/scripts/refactor/refactor-lint.ts +0 -2
  406. package/scripts/refactor/refactor-scan.ts +2 -2
  407. package/scripts/refactor/refactor-targets.ts +0 -1
  408. package/scripts/registry-migration/migrate-logic.ts +28 -21
  409. package/scripts/registry-migration/migrate.ts +25 -14
  410. package/scripts/release/github-release-cli.ts +19 -6
  411. package/scripts/release/github-release-environment.ts +46 -0
  412. package/scripts/release/github-release.ts +151 -94
  413. package/scripts/release/release-history.ts +0 -1
  414. package/scripts/release/release-plan.ts +0 -1
  415. package/scripts/release/release-publish.ts +38 -5
  416. package/scripts/release/release-scope-cli.ts +1 -2
  417. package/scripts/release/release-tag.ts +2 -4
  418. package/scripts/release/release-worktree.ts +97 -2
  419. package/scripts/repo/auto-merge-setting-logic.ts +1 -4
  420. package/scripts/repo/repo-setting.ts +1 -1
  421. package/scripts/repo/repository-labels.ts +3 -3
  422. package/scripts/repo/required-checks-logic.ts +206 -0
  423. package/scripts/repo/required-checks-report.ts +71 -0
  424. package/scripts/repo/ruleset-check-cli.ts +53 -0
  425. package/scripts/repo/ruleset-check.ts +147 -0
  426. package/scripts/report/report-lint-cli.ts +0 -4
  427. package/scripts/review/disposition-cli.ts +1 -1
  428. package/scripts/review/live-evidence.ts +1 -1
  429. package/scripts/review/review-attest-cli.ts +0 -6
  430. package/scripts/review/review-attest.ts +4 -16
  431. package/scripts/review/review-brief-cli.ts +23 -6
  432. package/scripts/review/review-brief.ts +21 -8
  433. package/scripts/review/review-checkout.ts +3 -2
  434. package/scripts/review/review-diff-parts.ts +89 -0
  435. package/scripts/review/review-diff-write.ts +97 -0
  436. package/scripts/review/review-finding-ledger.ts +0 -1
  437. package/scripts/review/review-record-cli.ts +10 -17
  438. package/scripts/review/review-record.ts +0 -1
  439. package/scripts/review/review-round2-cli.ts +1 -1
  440. package/scripts/review/review-stamps.ts +0 -3
  441. package/scripts/review/review-tree.ts +14 -2
  442. package/scripts/rules/decision-oracle-stage.ts +18 -0
  443. package/scripts/rules/decision-oracle.ts +10 -7
  444. package/scripts/rules/delivered-rules.ts +9 -1
  445. package/scripts/rules/destructive-command.ts +119 -0
  446. package/scripts/rules/direct-filing.ts +1 -1
  447. package/scripts/rules/early-heartbeat.ts +4 -3
  448. package/scripts/rules/file-body.ts +0 -3
  449. package/scripts/rules/filing-cap.ts +0 -2
  450. package/scripts/rules/gh-api.ts +7 -2
  451. package/scripts/rules/git-argv.ts +18 -7
  452. package/scripts/rules/git-force.ts +0 -2
  453. package/scripts/rules/implementation-cut.ts +0 -1
  454. package/scripts/rules/index-guard.ts +71 -0
  455. package/scripts/rules/issue-citation.ts +50 -25
  456. package/scripts/rules/lane-background.ts +15 -7
  457. package/scripts/rules/lane-park.ts +22 -6
  458. package/scripts/rules/last-prompt.ts +1 -0
  459. package/scripts/rules/oracle-consulted.ts +1 -1
  460. package/scripts/rules/oracle-firing.ts +1 -0
  461. package/scripts/rules/oracle-list-cli.ts +0 -3
  462. package/scripts/rules/permission-guards.ts +14 -0
  463. package/scripts/rules/protected-files.ts +74 -0
  464. package/scripts/rules/reply-language.ts +1 -1
  465. package/scripts/rules/rule-body-guard.ts +0 -3
  466. package/scripts/rules/rule-value-cli.ts +0 -1
  467. package/scripts/rules/shell-body-trigger.ts +0 -1
  468. package/scripts/rules/shell-segments.ts +0 -1
  469. package/scripts/rules/stop-rules.ts +20 -9
  470. package/scripts/rules/tail-commands.ts +1 -1
  471. package/scripts/rules/test-declared-commit.ts +1 -1
  472. package/scripts/rules/third-party-write.ts +0 -1
  473. package/scripts/rules/worktree-guard.ts +26 -9
  474. package/scripts/run/run-carry-args.ts +8 -12
  475. package/scripts/run/run-carry-cli.ts +0 -2
  476. package/scripts/run/run-carry-stash.ts +2 -2
  477. package/scripts/run/run-carry-streak.ts +1 -1
  478. package/scripts/run/run-cut-args.ts +1 -6
  479. package/scripts/run/run-cut-cli.ts +0 -7
  480. package/scripts/run/run-cut.ts +8 -54
  481. package/scripts/run/run-ending-cli.ts +2 -6
  482. package/scripts/run/run-ending.ts +1 -4
  483. package/scripts/run/run-entry-cli.ts +133 -25
  484. package/scripts/run/run-entry-stop.ts +104 -0
  485. package/scripts/run/run-entry.ts +0 -1
  486. package/scripts/run/run-event-cli.ts +0 -2
  487. package/scripts/run/run-event-follow.ts +1 -0
  488. package/scripts/run/run-event-render.ts +1 -1
  489. package/scripts/run/run-event-scope.ts +53 -4
  490. package/scripts/run/run-event-stream-emit.ts +7 -2
  491. package/scripts/run/run-event-stream.ts +0 -3
  492. package/scripts/run/run-event-watch.ts +1 -0
  493. package/scripts/run/run-halfrun-resume.ts +20 -7
  494. package/scripts/run/run-headless.ts +2 -2
  495. package/scripts/run/run-hold-cli.ts +33 -10
  496. package/scripts/run/run-hold.ts +29 -6
  497. package/scripts/run/run-issue-number.ts +1 -1
  498. package/scripts/run/run-liveness-cli.ts +2 -6
  499. package/scripts/run/run-liveness.ts +2 -3
  500. package/scripts/run/run-merge-cli.ts +7 -23
  501. package/scripts/run/run-merge-steps.ts +5 -5
  502. package/scripts/run/run-merge.ts +1 -1
  503. package/scripts/run/run-next-cli.ts +1 -1
  504. package/scripts/run/run-parent-cut-hook.ts +4 -2
  505. package/scripts/run/run-preflight.ts +2 -9
  506. package/scripts/run/run-prep-cli.ts +6 -3
  507. package/scripts/run/run-prep-locate.ts +1 -1
  508. package/scripts/run/run-progress-args.ts +20 -4
  509. package/scripts/run/run-progress-cli.ts +35 -36
  510. package/scripts/run/run-progress-clock.ts +10 -35
  511. package/scripts/run/run-progress-config.ts +0 -4
  512. package/scripts/run/run-progress-read.ts +1 -2
  513. package/scripts/run/run-progress.ts +1 -2
  514. package/scripts/run/run-prrun-resume.ts +117 -0
  515. package/scripts/run/run-report-cli.ts +1 -2
  516. package/scripts/run/run-report.ts +0 -1
  517. package/scripts/run/run-retrospective.ts +1 -1
  518. package/scripts/run/run-review-cli.ts +0 -3
  519. package/scripts/run/run-review-steps.ts +2 -0
  520. package/scripts/run/run-review.ts +0 -2
  521. package/scripts/run/run-ship-cli.ts +29 -19
  522. package/scripts/run/run-ship-detach.ts +1 -0
  523. package/scripts/run/run-ship-next.ts +106 -0
  524. package/scripts/run/run-ship-preflight.ts +1 -1
  525. package/scripts/run/run-ship-probe.ts +4 -1
  526. package/scripts/run/run-ship-return.ts +8 -3
  527. package/scripts/run/run-ship-review-steps.ts +18 -4
  528. package/scripts/run/run-ship-review.ts +11 -0
  529. package/scripts/run/run-ship-scoped.ts +1 -0
  530. package/scripts/run/run-ship-steps.ts +1 -1
  531. package/scripts/run/run-ship.ts +0 -1
  532. package/scripts/run/run-stage-read.ts +62 -0
  533. package/scripts/run/run-stage.ts +160 -0
  534. package/scripts/run/run-status-cli.ts +3 -16
  535. package/scripts/run/run-step-cli.ts +21 -14
  536. package/scripts/run/run-step.ts +1 -1
  537. package/scripts/run/run-stop-notify.ts +1 -3
  538. package/scripts/run/run-stranded-cli.ts +0 -4
  539. package/scripts/run/run-stranded-detect.ts +2 -2
  540. package/scripts/run/run-tail-cli.ts +17 -11
  541. package/scripts/run/run-tail.ts +2 -0
  542. package/scripts/run/run-tidy-lanes.ts +6 -2
  543. package/scripts/run/run-tidy-stashes.ts +12 -12
  544. package/scripts/run/run-wake-cli.ts +4 -13
  545. package/scripts/run/run-wake-loop.ts +2 -2
  546. package/scripts/run/run-wake.ts +2 -4
  547. package/scripts/run/run-watcher-guard-cli.ts +0 -4
  548. package/scripts/run/run-watcher-guard.ts +18 -12
  549. package/scripts/run/run-watcher-hook.ts +1 -1
  550. package/scripts/safe-chain/ci-installer-pin.ts +11 -5
  551. package/scripts/safe-chain/pack-hook.ts +92 -0
  552. package/scripts/safe-chain/project-config.ts +1 -1
  553. package/scripts/security/security-audit-provision-logic.ts +0 -1
  554. package/scripts/security/security-audit-provision.ts +3 -2
  555. package/scripts/security/security-audit.ts +0 -1
  556. package/scripts/security/security-updates-logic.ts +0 -1
  557. package/scripts/sonar/sonar-hotspots-cli.ts +10 -52
  558. package/scripts/sonar/sonar-hotspots.ts +0 -1
  559. package/scripts/sonar/sonar-new-code-cli.ts +150 -0
  560. package/scripts/sonar/sonar-new-code.ts +79 -0
  561. package/scripts/sonar/sonar-project.ts +97 -0
  562. package/scripts/split/split-assess-cli.ts +1 -1
  563. package/scripts/split/split-assess.ts +2 -5
  564. package/scripts/sync/managed-config-scope-cli.ts +1 -1
  565. package/scripts/sync/skill-migration.ts +0 -1
  566. package/scripts/sync/sync-ai-files.ts +4 -0
  567. package/scripts/sync/sync-hook-safety.ts +2 -3
  568. package/scripts/sync/sync.ts +1 -8
  569. package/scripts/sync/template-source-logic.ts +0 -1
  570. package/scripts/sync/workflow-pin-logic.ts +16 -28
  571. package/scripts/test/test-declared-changed.ts +13 -16
  572. package/scripts/test/test-declared-logic.ts +0 -1
  573. package/scripts/test/test-declared.ts +3 -9
  574. package/scripts/test/test-red-commit.ts +2 -2
  575. package/scripts/test/test-red.ts +14 -7
  576. package/scripts/test/test-type-logic.ts +1 -1
  577. package/scripts/test/unit-worker-share.ts +7 -16
  578. package/scripts/time-runtime/time-batch-guard.ts +1 -2
  579. package/scripts/time-runtime/time-bundle-call.ts +0 -1
  580. package/scripts/time-runtime/time-bundles.ts +0 -4
  581. package/scripts/time-runtime/time-density-hook.ts +0 -2
  582. package/scripts/time-runtime/time-followup-stage.ts +1 -1
  583. package/scripts/time-runtime/time-format.ts +0 -73
  584. package/scripts/time-runtime/time-round-trips.ts +0 -4
  585. package/scripts/time-runtime/time-single-check.ts +1 -1
  586. package/scripts/time-runtime/time-spans.ts +1 -1
  587. package/scripts/time-runtime/time-transcript-line.ts +1 -2
  588. package/scripts/ui/ui-routes-cli.ts +0 -5
  589. package/scripts/ui/ui-routes.ts +0 -5
  590. package/scripts/version/effective-upstream.ts +2 -2
  591. package/scripts/version/latest-corepack.ts +7 -9
  592. package/scripts/version/latest-scope-cli.ts +0 -2
  593. package/scripts/version/latest-update.ts +0 -2
  594. package/scripts/version/npm-registry.ts +2 -2
  595. package/scripts/version/publishable-range-check.ts +1 -1
  596. package/scripts/version/release-hold.ts +0 -4
  597. package/scripts/version/running-binary.ts +2 -2
  598. package/scripts/version/version-check-logic.ts +0 -2
  599. package/scripts/version/version-commands.ts +11 -1
  600. package/scripts/version/version-remote.ts +3 -3
  601. package/scripts/version/version-targets.ts +4 -4
  602. package/templates/CLAUDE.basic.md +6 -6
  603. package/templates/sonar-project.properties +28 -1
  604. package/templates/workflows/ci.yml +16 -82
  605. package/templates/workflows/dependabot-auto-merge.yml +6 -3
  606. package/templates/workflows/github-release.yml +79 -0
  607. package/tsconfig.sonar.json +4 -22
  608. package/prompts/collaboration-workflow/cross-repo-epic.md +0 -5
  609. package/prompts/collaboration-workflow/epic-audit.md +0 -5
  610. package/prompts/collaboration-workflow/epic-bundle.md +0 -5
  611. package/scripts/init/plugin-install-hint.ts +0 -47
  612. package/scripts/version/parse-json.ts +0 -13
  613. /package/scripts/{git → followup}/git-followup-stages.ts +0 -0
  614. /package/scripts/{git → gh}/git-gh-api-path.ts +0 -0
  615. /package/scripts/{git → gh}/git-gh-command.ts +0 -0
  616. /package/scripts/{git → gh}/git-gh-issue.ts +0 -0
  617. /package/scripts/{git → gh}/git-gh-pr-snapshot.ts +0 -0
  618. /package/scripts/{git → gh}/git-gh-reachability.ts +0 -0
  619. /package/scripts/{git → gh}/git-gh-repo.ts +0 -0
  620. /package/scripts/{git → gh}/git-gh-rest-state.ts +0 -0
  621. /package/scripts/{git → gh}/git-pr-checks-watch.ts +0 -0
  622. /package/scripts/{git → gh}/git-pr-error.ts +0 -0
  623. /package/scripts/{git → gh}/git-pr-messages.ts +0 -0
  624. /package/scripts/{git → gh}/github-issue-url.ts +0 -0
  625. /package/scripts/git/{stash-orphans.ts → stash/stash-orphans.ts} +0 -0
  626. /package/scripts/{git → issue}/issue-reference.ts +0 -0
  627. /package/scripts/{git → lib}/animation-helpers.ts +0 -0
  628. /package/scripts/{git → lib}/git-animation.ts +0 -0
  629. /package/scripts/{git → notify}/git-notify.ts +0 -0
  630. /package/scripts/{git → notify}/telegram-test-logic.ts +0 -0
@@ -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,7 +1,8 @@
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
+ import { repository_lock } from '#scripts/git/repository-lock'
5
6
  import { write_version } from '#scripts/version/bump-version'
6
7
  import { version_targets } from '#scripts/version/version-targets'
7
8
  import type { ReleasePlan } from './release-plan'
@@ -20,6 +21,9 @@ const { PACKAGE_JSON } = version_targets
20
21
  const SUCCESS_EXIT_CODE = 0
21
22
  const FAILURE_EXIT_CODE = 1
22
23
  const IGNORE_FOR_RELEASE_LABEL = 'ignore-for-release'
24
+ const RELEASE_LOCK_PREFIX = 'josh-release-lock-'
25
+ // A release waits on CI for minutes, so a second run refuses rather than queueing behind it.
26
+ const RELEASE_LOCK_MAX_WAIT_MS = 0
23
27
 
24
28
  function branch_name_for(version: string): string {
25
29
  return `release/v${version}`
@@ -87,6 +91,14 @@ async function refuse_existing_branch(branch_name: string): Promise<void> {
87
91
  throw new Error(existing_branch_message(branch_name))
88
92
  }
89
93
 
94
+ // **The leftovers go before the guard asks** (joshuafolkken/kit#3058). A run cut off before its
95
+ // `finally`, or a `worktree add` that failed after creating its branch, leaves a local
96
+ // `release/v<version>` that the guard would otherwise refuse as a release already opened.
97
+ async function clear_the_way(branch_name: string): Promise<void> {
98
+ await release_worktree.clear_leftover()
99
+ await refuse_existing_branch(branch_name)
100
+ }
101
+
90
102
  // **No `checkout -b` and no branch guard here** (joshuafolkken/kit#2411). The work tree is already
91
103
  // sitting on the release branch — `release_worktree.create` cut it that way — and the guard ran
92
104
  // before that creation, because `worktree_add` makes the branch local and `branch_exists` would then
@@ -121,10 +133,10 @@ async function merge_and_tag(plan: ReleasePlan, branch_name: string): Promise<nu
121
133
  // branch guard runs before the tree exists, `process.chdir` points the version write and the git
122
134
  // commands at the tree, and the `finally` returns to the root and removes the tree — whichever way
123
135
  // the wait ended, so a failed tag watch cleans up rather than leaving debris behind.
124
- async function publish(plan: ReleasePlan): Promise<number> {
136
+ async function publish_locked(plan: ReleasePlan): Promise<number> {
125
137
  const branch_name = branch_name_for(plan.next_version)
126
138
 
127
- await refuse_existing_branch(branch_name)
139
+ await clear_the_way(branch_name)
128
140
 
129
141
  const directory = await release_worktree.create(branch_name)
130
142
  const previous_cwd = process.cwd()
@@ -140,6 +152,28 @@ async function publish(plan: ReleasePlan): Promise<number> {
140
152
  }
141
153
  }
142
154
 
155
+ function release_running_message(target: string): string {
156
+ return `Another \`pnpm josh release\` is running in this repository (lock \`${target}\`); wait for it to finish, then run it again.`
157
+ }
158
+
159
+ // **One release at a time per repository, held for the whole run** (joshuafolkken/kit#3058).
160
+ // `clear_leftover` removes an unpushed, commit-less release branch, which is also what a live run
161
+ // looks like while it installs dependencies — so it may only run once no other release is alive. The
162
+ // lock answers that: a run cut off before its `finally` leaves a record whose owner is gone, which
163
+ // `repository_lock` clears on the next claim, while a live owner makes this run refuse at once.
164
+ async function publish(plan: ReleasePlan): Promise<number> {
165
+ const target = repository_lock.lock_path(RELEASE_LOCK_PREFIX)
166
+ const exit_code = await repository_lock.with_lock(
167
+ async () => await publish_locked(plan),
168
+ target,
169
+ RELEASE_LOCK_MAX_WAIT_MS,
170
+ )
171
+
172
+ if (exit_code === undefined) throw new Error(release_running_message(target))
173
+
174
+ return exit_code
175
+ }
176
+
143
177
  const release_publish = {
144
178
  branch_name_for,
145
179
  commit_message,
@@ -150,7 +184,6 @@ const release_publish = {
150
184
  publish,
151
185
  pull_request_body,
152
186
  unreachable_remote_message,
153
- FAILURE_EXIT_CODE,
154
187
  SUCCESS_EXIT_CODE,
155
188
  }
156
189
 
@@ -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 }
@@ -1,7 +1,9 @@
1
1
  import path from 'node:path'
2
2
  import { git_command } from '#scripts/git/git-command'
3
+ import { git_remote_branch } from '#scripts/git/git-remote-branch'
3
4
  import { git_worktree } from '#scripts/git/git-worktree'
4
5
  import { lane_install } from '#scripts/lane/lane-install'
6
+ import { lane_leftover } from '#scripts/lane/lane-leftover'
5
7
  import { lane_paths } from '#scripts/lane/lane-paths'
6
8
 
7
9
  // The dedicated linked work tree `pnpm josh release` runs inside (joshuafolkken/kit#2411). The whole
@@ -51,18 +53,111 @@ async function install_or_clean(directory: string, branch_name: string): Promise
51
53
  // tree on the default branch, so the tree is created directly on the release branch — `git worktree
52
54
  // add --no-track -b release/v<version> <dir> origin/<default>`, which `worktree_add` already spells
53
55
  // when it is given a start point.
56
+ //
57
+ // **A failed add takes back the branch it made** (joshuafolkken/kit#3058). `git worktree add -b`
58
+ // creates the branch before it looks at the path, so an add refused for a path that already exists
59
+ // still leaves `release/v<version>` behind — and the next run's branch guard then refuses that name
60
+ // as a release already opened. The guard ran before this call and found no such branch, so one
61
+ // present now is this call's own.
62
+ async function add_or_take_back(directory: string, branch_name: string): Promise<void> {
63
+ const default_branch = await git_command.get_default_branch()
64
+
65
+ try {
66
+ await git_worktree.worktree_add(directory, branch_name, `origin/${default_branch}`)
67
+ } catch (error) {
68
+ if (await git_command.branch_exists(branch_name)) await git_worktree.branch_delete(branch_name)
69
+
70
+ throw error
71
+ }
72
+ }
73
+
54
74
  async function create(branch_name: string): Promise<string> {
55
75
  const directory = directory_for(process.cwd())
56
- const default_branch = await git_command.get_default_branch()
57
76
 
58
- await git_worktree.worktree_add(directory, branch_name, `origin/${default_branch}`)
77
+ await add_or_take_back(directory, branch_name)
59
78
  await install_or_clean(directory, branch_name)
60
79
 
61
80
  return directory
62
81
  }
63
82
 
83
+ // **A run that never reached its `finally` leaves its tree and branch behind** (joshuafolkken/kit#3058)
84
+ // — a Ctrl-C, a closed terminal — and every later release then fails on them until a person removes
85
+ // both by hand. They are cleared here only when clearing loses nothing: a release branch origin does
86
+ // not have and that carries no commit beyond `origin/<default>`. Uncommitted edits in the tree are
87
+ // the version bump the next run writes again, so they are not counted as a loss. A branch that was
88
+ // pushed, or that holds a commit, may be a release still in flight, so it is reported and kept. A
89
+ // live run with neither yet is excluded by the caller: `release_publish.publish` holds the release
90
+ // lock, so no other release is alive when this runs.
91
+ const RELEASE_BRANCH_PATTERN = 'release/v*'
92
+
93
+ async function leftover_reason(branch_name: string, base: string): Promise<string | undefined> {
94
+ const answer = await git_remote_branch.ask(branch_name)
95
+
96
+ if (answer !== 'absent') return `origin answers \`${answer}\` for it`
97
+
98
+ const ahead = await git_command.commit_count_beyond(base, branch_name)
99
+
100
+ return ahead === 0 ? undefined : `it holds ${String(ahead)} commit(s) not on \`${base}\``
101
+ }
102
+
103
+ function kept_message(directory: string, kept: ReadonlyArray<[string, string]>): string {
104
+ const lines = kept.map(([branch_name, reason]) => `- \`${branch_name}\`: ${reason}`)
105
+ const commands = [
106
+ `git worktree remove --force ${directory}`,
107
+ ...kept.map(([branch_name]) => `git branch -D ${branch_name}`),
108
+ ].join('; ')
109
+
110
+ return [
111
+ 'A previous `pnpm josh release` left release branches that may still be in use, so nothing was removed:',
112
+ ...lines,
113
+ `If no release is running, finish or close its pull request, delete the remote branch if it was pushed, then run \`${commands}\` and \`pnpm josh release\` again.`,
114
+ ].join('\n')
115
+ }
116
+
117
+ async function kept_branches(branches: ReadonlyArray<string>): Promise<Array<[string, string]>> {
118
+ const base = `origin/${await git_command.get_default_branch()}`
119
+ const reasons = await Promise.all(branches.map(async (name) => await leftover_reason(name, base)))
120
+
121
+ return branches.flatMap((name, index) => {
122
+ const reason = reasons[index]
123
+
124
+ return reason === undefined ? [] : [[name, reason] as [string, string]]
125
+ })
126
+ }
127
+
128
+ async function is_registered(directory: string): Promise<boolean> {
129
+ const listing = await git_worktree.worktree_list()
130
+
131
+ return listing.split('\n').includes(`worktree ${directory}`)
132
+ }
133
+
134
+ // The tree goes before the branches, for the reason `remove` gives. A directory git does not register
135
+ // is `lane_leftover.reclaim`'s to remove or refuse — the same test a lane's leftover path gets.
136
+ // Registration is asked before existence: a directory deleted by hand stays registered, and git
137
+ // refuses to delete a branch a registered tree holds until `worktree remove` drops the registration.
138
+ async function remove_leftover_tree(directory: string): Promise<void> {
139
+ if (await is_registered(directory)) await git_worktree.worktree_remove(directory)
140
+ else await lane_leftover.reclaim(directory)
141
+ }
142
+
143
+ async function clear_leftover(): Promise<void> {
144
+ const directory = directory_for(process.cwd())
145
+ const branches = await git_command.branch_names(RELEASE_BRANCH_PATTERN)
146
+ const kept = await kept_branches(branches)
147
+
148
+ if (kept.length > 0) throw new Error(kept_message(directory, kept))
149
+
150
+ await remove_leftover_tree(directory)
151
+
152
+ for (const branch_name of branches) {
153
+ // eslint-disable-next-line no-await-in-loop -- each `branch -D` takes the same ref lock
154
+ await git_worktree.branch_delete(branch_name)
155
+ }
156
+ }
157
+
64
158
  const release_worktree = {
65
159
  directory_for,
160
+ clear_leftover,
66
161
  create,
67
162
  remove,
68
163
  RELEASE_WORKTREE_NAME,
@@ -41,7 +41,7 @@ function format_disabled_detail(repo: string | undefined): ReadonlyArray<string>
41
41
  ` off, so ${WORKFLOW_PATH} fails with`,
42
42
  ' `Auto-merge is not allowed for this repository` and Dependabot pull requests stay open.',
43
43
  ` Enable: ${enable_command(repo)}`,
44
- ` ${ORIGIN_ISSUE} distributes the workflow; kit never changes a repository setting.`,
44
+ ` ${ORIGIN_ISSUE} distributes the workflow; kit never changes this setting.`,
45
45
  ]
46
46
  }
47
47
 
@@ -89,9 +89,6 @@ function format_auto_merge_report(
89
89
 
90
90
  const auto_merge_setting_logic = {
91
91
  SETTING_LABEL,
92
- ALLOW_AUTO_MERGE_FIELD,
93
- WORKFLOW_PATH,
94
- enable_command,
95
92
  classify_auto_merge,
96
93
  format_auto_merge_report,
97
94
  }
@@ -1,4 +1,4 @@
1
- import { git_gh_exec } from '#scripts/git/git-gh-exec'
1
+ import { git_gh_exec } from '#scripts/gh/git-gh-exec'
2
2
  import { PROJECT_ROOT } from '#scripts/init/init-paths'
3
3
 
4
4
  // The shared half of every "report a GitHub repository setting kit cannot write" check.
@@ -1,5 +1,5 @@
1
- import { git_gh_exec } from '#scripts/git/git-gh-exec'
2
- import { REPOSITORY_LABELS, type LabelDefinition } from '#scripts/git/issue-labels'
1
+ import { git_gh_exec } from '#scripts/gh/git-gh-exec'
2
+ import { REPOSITORY_LABELS, type LabelDefinition } from '#scripts/issue/issue-labels'
3
3
 
4
4
  // Creates the labels kit's workflow and the distributed `pr-classification.yml` rely on, and only
5
5
  // those the repository is missing (joshuafolkken/kit#2797). The one place labels are created: `josh
@@ -86,6 +86,6 @@ function ensure_labels(repo: string | undefined): ReadonlyArray<string> {
86
86
  return create_missing(missing_labels(existing), repo)
87
87
  }
88
88
 
89
- const repository_labels = { missing_labels, ensure_labels }
89
+ const repository_labels = { ensure_labels }
90
90
 
91
91
  export { repository_labels }