@joshuafolkken/kit 1.1035.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 (605) hide show
  1. package/.claude/settings.json +9 -8
  2. package/.claude/skills/epic-commands/SKILL.md +5 -7
  3. package/.claude/skills/verify-ui/SKILL.md +1 -1
  4. package/.claude/skills/workflow-commands/SKILL.md +21 -13
  5. package/.claude/skills/workflow-commands/background-commands.md +5 -4
  6. package/.claude/skills/workflow-commands/backlogrun-child.md +3 -3
  7. package/.claude/skills/workflow-commands/backlogrun-lanes.md +9 -7
  8. package/.claude/skills/workflow-commands/backlogrun-park.md +6 -0
  9. package/.claude/skills/workflow-commands/backlogrun-progress.md +31 -37
  10. package/.claude/skills/workflow-commands/backlogrun-steps.md +25 -25
  11. package/.claude/skills/workflow-commands/backlogrun.md +2 -2
  12. package/.claude/skills/workflow-commands/chain-rule.md +6 -4
  13. package/.claude/skills/workflow-commands/delegation.md +3 -3
  14. package/.claude/skills/workflow-commands/followup-reference.md +3 -3
  15. package/.claude/skills/workflow-commands/followup.md +7 -3
  16. package/.claude/skills/workflow-commands/fullrun-steps.md +3 -2
  17. package/.claude/skills/workflow-commands/fullrun.md +3 -2
  18. package/.claude/skills/workflow-commands/halfrun.md +16 -19
  19. package/.claude/skills/workflow-commands/issue-comments.md +2 -2
  20. package/.claude/skills/workflow-commands/issue-fold-existing.md +10 -10
  21. package/.claude/skills/workflow-commands/issue-scout.md +1 -1
  22. package/.claude/skills/workflow-commands/kickoff.md +9 -4
  23. package/.claude/skills/workflow-commands/latest-gate.md +1 -1
  24. package/.claude/skills/workflow-commands/needs-human-review.md +1 -1
  25. package/.claude/skills/workflow-commands/observation-filing.md +44 -89
  26. package/.claude/skills/workflow-commands/pre-gate-cut.md +33 -36
  27. package/.claude/skills/workflow-commands/prerequisite.md +1 -1
  28. package/.claude/skills/workflow-commands/prrun.md +36 -0
  29. package/.claude/skills/workflow-commands/retrospective.md +1 -1
  30. package/.claude/skills/workflow-commands/working-tree-hold.md +24 -4
  31. package/.codex/hooks.json +16 -20
  32. package/.github/actions/setup-pnpm/action.yml +93 -0
  33. package/.github/dependabot.yml +5 -1
  34. package/.github/workflows/auto-tag.yml +21 -0
  35. package/.github/workflows/ci.yml +26 -128
  36. package/.github/workflows/pr-classification.yml +5 -41
  37. package/.github/workflows/publish.yml +42 -48
  38. package/.github/workflows/sonar-qube.yml +37 -4
  39. package/AGENTS.md +12 -2
  40. package/CLAUDE.md +15 -16
  41. package/GEMINI.md +14 -2
  42. package/README.md +59 -18
  43. package/SECURITY.md +36 -6
  44. package/cspell/index.yaml +2 -1
  45. package/dist/CLAUDE.md +15 -16
  46. package/dist/config-merge/index.js +15 -3
  47. package/dist/hooks/batch-guard.js +4 -4
  48. package/dist/hooks/{chunk-Y27M6A7X.js → chunk-3C4YCCEF.js} +5 -13
  49. package/dist/hooks/{chunk-D67KVGGY.js → chunk-7ZPFAVR7.js} +17 -88
  50. package/dist/hooks/{chunk-HOYJU5RM.js → chunk-E54KGFEQ.js} +11 -4
  51. package/dist/hooks/{chunk-KG6PZD72.js → chunk-IL27YTPH.js} +2 -2
  52. package/dist/hooks/{chunk-GJT4BNVE.js → chunk-KHWHKJOM.js} +3 -3
  53. package/dist/hooks/{chunk-HU66PWWL.js → chunk-M2XDCUKD.js} +1076 -509
  54. package/dist/hooks/{chunk-GLBDBJOK.js → chunk-NKOG3XAV.js} +199 -304
  55. package/dist/hooks/{chunk-ZXNE6NY3.js → chunk-O4LL4HTI.js} +2 -7
  56. package/dist/hooks/{chunk-XPLP27WA.js → chunk-OIZUHPJI.js} +5 -27
  57. package/dist/hooks/{chunk-EIFCAJRB.js → chunk-UD24EAIL.js} +2546 -1636
  58. package/dist/hooks/codex-hook-adapter.js +10 -11
  59. package/dist/hooks/duplicate-read-guard.js +5 -5
  60. package/dist/hooks/format-edited.js +15 -34
  61. package/dist/hooks/inputs.json +279 -0
  62. package/dist/hooks/investigation-guard.js +5 -5
  63. package/dist/hooks/pretool-guard.js +23 -16
  64. package/dist/hooks/session-lang.js +0 -1
  65. package/dist/hooks/stop-guard.js +188 -509
  66. package/dist/josh.js +166 -225
  67. package/dist/managed-marker/index.js +2 -1
  68. package/dist/version/index.js +412 -64
  69. package/eslint/rules/promise.js +5 -0
  70. package/package.json +13 -8
  71. package/prompts/collaboration-workflow/file-edits.md +6 -53
  72. package/prompts/collaboration-workflow/issue-citation.md +5 -5
  73. package/prompts/collaboration-workflow/operating-rules.md +4 -4
  74. package/prompts/collaboration-workflow/overview.md +13 -1
  75. package/prompts/collaboration-workflow/report-format.md +1 -1
  76. package/prompts/collaboration-workflow/residency.md +4 -4
  77. package/prompts/collaboration-workflow/rule-delivery.md +5 -36
  78. package/prompts/collaboration-workflow/shell-body.md +7 -9
  79. package/prompts/collaboration-workflow/turn-batching.md +21 -37
  80. package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
  81. package/prompts/collaboration-workflow/wip-cap.md +36 -36
  82. package/prompts/collaboration-workflow.md +5 -8
  83. package/prompts/review-rubric.md +1 -1
  84. package/prompts/review.md +3 -3
  85. package/prompts/sonar-hotspot-handling.md +12 -4
  86. package/prompts/testing-guide.md +3 -3
  87. package/scripts/adopt/adopt-toolkits.ts +2 -2
  88. package/scripts/adopt/adopt.ts +0 -2
  89. package/scripts/agent/agent-argv.ts +0 -2
  90. package/scripts/agent/agent-diagnostics.ts +1 -1
  91. package/scripts/agent/agent-role-profile.ts +0 -7
  92. package/scripts/agent/claude-agent-argv.ts +0 -2
  93. package/scripts/agent/codex-agent-argv.ts +1 -1
  94. package/scripts/agent/codex-hooks.ts +92 -0
  95. package/scripts/agent/interactive-ask.ts +1 -1
  96. package/scripts/auto-ok/auto-ok-cli.ts +15 -25
  97. package/scripts/backlog/backlog-budget.ts +0 -2
  98. package/scripts/backlog/backlog-defect-priority.ts +2 -2
  99. package/scripts/backlog/backlog-drive-cli.ts +10 -8
  100. package/scripts/backlog/backlog-drive-named-offer.ts +16 -3
  101. package/scripts/backlog/backlog-drive-named.ts +2 -1
  102. package/scripts/backlog/backlog-drive.ts +76 -16
  103. package/scripts/backlog/backlog-named.ts +0 -3
  104. package/scripts/backlog/backlog-next.ts +32 -22
  105. package/scripts/backlog/backlog-offer-cli.ts +0 -5
  106. package/scripts/backlog/backlog-plan-cli.ts +6 -8
  107. package/scripts/backlog/backlog-plan.ts +1 -1
  108. package/scripts/backlog/backlog-pool.ts +34 -17
  109. package/scripts/backlog/backlog-rank.ts +106 -0
  110. package/scripts/backlog/backlog-ready.ts +19 -3
  111. package/scripts/backlog/backlog-scope.ts +1 -3
  112. package/scripts/backlog/backlog-stalled-detect.ts +2 -2
  113. package/scripts/backlog/backlog-stalled.ts +0 -1
  114. package/scripts/backlog/backlog-waves.ts +47 -31
  115. package/scripts/behavior/behavior-cli.ts +1 -1
  116. package/scripts/build/build-codex-hooks.ts +26 -0
  117. package/scripts/build/build-hooks.ts +92 -11
  118. package/scripts/build/hook-bundle-stamp.ts +111 -0
  119. package/scripts/cases/cases-cli.ts +1 -1
  120. package/scripts/cases/cases-logic.ts +1 -1
  121. package/scripts/ci/composite-actions.ts +30 -0
  122. package/scripts/ci/pr-classification.ts +3 -3
  123. package/scripts/claude/workflow-destination.ts +10 -1
  124. package/scripts/clone/clone-fingerprint.ts +0 -1
  125. package/scripts/clone/clone-scan-cli.ts +1 -1
  126. package/scripts/clone/clone-scan.ts +1 -1
  127. package/scripts/config-merge/json-format.ts +0 -1
  128. package/scripts/config-merge/patch-yaml-list.ts +1 -1
  129. package/scripts/cost-runtime/codex-usage.ts +2 -9
  130. package/scripts/cost-runtime/cost-attribute.ts +0 -1
  131. package/scripts/cost-runtime/cost-cli.ts +0 -3
  132. package/scripts/cost-runtime/cost-corpus.ts +0 -2
  133. package/scripts/cost-runtime/cost-format.ts +0 -3
  134. package/scripts/cost-runtime/cost-pricing.ts +0 -1
  135. package/scripts/cost-runtime/cost-tokens.ts +0 -1
  136. package/scripts/delegation/delegation-cli.ts +1 -1
  137. package/scripts/delegation/delegation-policy.ts +11 -1
  138. package/scripts/delegation/duplicate-read-guard.ts +0 -8
  139. package/scripts/delegation/fanout-cli.ts +1 -1
  140. package/scripts/delegation/fanout.ts +0 -2
  141. package/scripts/delegation/investigation-reads.ts +1 -164
  142. package/scripts/discovery/repo-map-logic.ts +0 -1
  143. package/scripts/discovery/repo-party-cli.ts +1 -1
  144. package/scripts/doctor/doctor-consumer.ts +4 -6
  145. package/scripts/doctor/doctor-logic.ts +0 -4
  146. package/scripts/doctor/doctor.ts +14 -9
  147. package/scripts/document/document-byte-budget.ts +8 -9
  148. package/scripts/document/document-byte-check.ts +0 -1
  149. package/scripts/document/document-read-cli.ts +0 -2
  150. package/scripts/document/document-section-cli.ts +1 -1
  151. package/scripts/document/document-section.ts +0 -3
  152. package/scripts/document/edit-files-cli.ts +0 -1
  153. package/scripts/document/entry-read-budget.ts +13 -4
  154. package/scripts/document/lane-child-read-set.ts +1 -6
  155. package/scripts/document/read-files-cli.ts +0 -4
  156. package/scripts/document/read-set-cli.ts +0 -2
  157. package/scripts/document/read-set-point-of-use.ts +1 -0
  158. package/scripts/document/read-set-pricing.ts +0 -1
  159. package/scripts/document/read-set-trim.ts +1 -1
  160. package/scripts/epic/epic-add.ts +1 -1
  161. package/scripts/epic/epic-audit-cli.ts +1 -4
  162. package/scripts/epic/epic-audit-orphans.ts +1 -3
  163. package/scripts/epic/epic-audit-rationale.ts +0 -1
  164. package/scripts/epic/epic-audit-report.ts +0 -2
  165. package/scripts/epic/epic-audit.ts +5 -4
  166. package/scripts/epic/epic-bundle-cli.ts +1 -1
  167. package/scripts/epic/epic-bundle-evidence.ts +0 -1
  168. package/scripts/epic/epic-bundle-referenced.ts +1 -5
  169. package/scripts/epic/epic-bundle.ts +0 -4
  170. package/scripts/epic/epic-busy.ts +4 -5
  171. package/scripts/epic/epic-candidate-confirm.ts +0 -5
  172. package/scripts/epic/epic-classify.ts +2 -2
  173. package/scripts/epic/epic-cli-argv.ts +0 -1
  174. package/scripts/epic/epic-close-comment.ts +1 -1
  175. package/scripts/epic/epic-close.ts +5 -2
  176. package/scripts/epic/epic-cross-repo.ts +2 -4
  177. package/scripts/epic/epic-decision.ts +0 -1
  178. package/scripts/epic/epic-fetch.ts +2 -2
  179. package/scripts/epic/epic-index.ts +2 -3
  180. package/scripts/epic/epic-issue.ts +1 -15
  181. package/scripts/epic/epic-lane-offer.ts +20 -30
  182. package/scripts/epic/epic-nested.ts +1 -1
  183. package/scripts/epic/epic-next-read.ts +1 -3
  184. package/scripts/epic/epic-next-views.ts +0 -1
  185. package/scripts/epic/epic-next.ts +1 -10
  186. package/scripts/epic/epic-parse.ts +0 -1
  187. package/scripts/epic/epic-promote.ts +0 -9
  188. package/scripts/epic/epic-rank.ts +37 -0
  189. package/scripts/epic/epic-read.ts +1 -2
  190. package/scripts/epic/epic-reconcile.ts +1 -1
  191. package/scripts/epic/epic-reference.ts +1 -13
  192. package/scripts/epic/epic-relation-recheck.ts +1 -1
  193. package/scripts/epic/epic-relations.ts +1 -1
  194. package/scripts/epic/epic-remove.ts +1 -1
  195. package/scripts/epic/epic-report.ts +0 -1
  196. package/scripts/epic/epic-run.ts +2 -3
  197. package/scripts/epic/epic-shape.ts +1 -1
  198. package/scripts/epic/epic-solo-stale.ts +107 -0
  199. package/scripts/epic/epic-solo.ts +32 -30
  200. package/scripts/epic/epic-triage.ts +1 -1
  201. package/scripts/epic/epic-validate.ts +1 -1
  202. package/scripts/epic/epic.ts +1 -1
  203. package/scripts/exports/unused-members-cli.ts +53 -0
  204. package/scripts/{git → followup}/followup-issue-number.ts +1 -6
  205. package/scripts/{git → followup}/git-followup-cleanup.ts +2 -1
  206. package/scripts/{git → followup}/git-followup-finish.ts +1 -3
  207. package/scripts/{git → followup}/git-followup-flush.ts +2 -2
  208. package/scripts/{git → followup}/git-followup-issue-close.ts +2 -2
  209. package/scripts/{git → followup}/git-followup-label.ts +4 -4
  210. package/scripts/followup/git-followup-merged.ts +112 -0
  211. package/scripts/{git → followup}/git-followup-pending.ts +1 -1
  212. package/scripts/{git → followup}/git-followup-workflow.ts +19 -11
  213. package/scripts/{git → followup}/git-pr-followup-wrapup.ts +9 -3
  214. package/scripts/{git → followup}/git-pr-followup.ts +53 -16
  215. package/scripts/gate/core-budget.ts +3 -9
  216. package/scripts/gate/gate-plan.ts +7 -4
  217. package/scripts/gate/gate-report.ts +0 -6
  218. package/scripts/gate/gate-tree.ts +1 -1
  219. package/scripts/gate/pre-commit-type-check.ts +0 -6
  220. package/scripts/gate/project-checks.ts +7 -8
  221. package/scripts/gate/scoped-green.ts +0 -1
  222. package/scripts/gate/type-check-step.ts +1 -1
  223. package/scripts/gate/verification-gate.ts +0 -2
  224. package/scripts/gh/fix-gh-packages.ts +15 -12
  225. package/scripts/gh/gh-spawn.ts +2 -2
  226. package/scripts/{git → gh}/git-ai-review-scan.ts +1 -5
  227. package/scripts/{git → gh}/git-gh-check.ts +2 -1
  228. package/scripts/{git → gh}/git-gh-exec.ts +1 -1
  229. package/scripts/{git → gh}/git-gh-failure.ts +1 -1
  230. package/scripts/{git → gh}/git-gh-helpers.ts +0 -1
  231. package/scripts/{git → gh}/git-gh-issue-list.ts +2 -0
  232. package/scripts/{git → gh}/git-gh-issue-read.ts +1 -1
  233. package/scripts/{git → gh}/git-gh-issue-rest.ts +6 -3
  234. package/scripts/{git → gh}/git-gh-pr-read.ts +24 -0
  235. package/scripts/{git → gh}/git-gh-pr-rest.ts +5 -2
  236. package/scripts/{git → gh}/git-gh-pr-review.ts +2 -2
  237. package/scripts/{git → gh}/git-gh-pr-rollup.ts +1 -3
  238. package/scripts/{git → gh}/git-gh-pr.ts +3 -1
  239. package/scripts/{git → gh}/git-pr-ai-review.ts +2 -5
  240. package/scripts/{git → gh}/git-pr-checks-eval.ts +0 -10
  241. package/scripts/{git → gh}/git-pr-checks-parse.ts +4 -20
  242. package/scripts/{git → gh}/git-pr-checks.ts +2 -1
  243. package/scripts/{git → gh}/git-pr-coderabbit.ts +2 -5
  244. package/scripts/{git → gh}/git-pr-confirmation.ts +1 -3
  245. package/scripts/{git → gh}/git-pr-managed-config.ts +2 -3
  246. package/scripts/{git → gh}/git-pr.ts +3 -3
  247. package/scripts/git/changed-file-scope.ts +0 -1
  248. package/scripts/git/git-branch.ts +3 -6
  249. package/scripts/git/git-command.ts +1 -1
  250. package/scripts/git/git-commit.ts +1 -1
  251. package/scripts/git/git-common-directory.ts +80 -24
  252. package/scripts/git/git-error.ts +66 -9
  253. package/scripts/git/git-execa-error.ts +6 -1
  254. package/scripts/git/git-issue.ts +1 -1
  255. package/scripts/git/git-preflight.ts +24 -6
  256. package/scripts/git/git-prompt.ts +6 -31
  257. package/scripts/git/git-push-transport.ts +12 -69
  258. package/scripts/git/git-push.ts +1 -1
  259. package/scripts/git/git-spawn.ts +79 -3
  260. package/scripts/git/git-ssh-keepalive.ts +74 -0
  261. package/scripts/git/git-staging.ts +1 -0
  262. package/scripts/git/git-status.ts +1 -1
  263. package/scripts/git/git-workflow.ts +1 -1
  264. package/scripts/git/gone-branch.ts +4 -2
  265. package/scripts/git/listing-cutoff.ts +1 -1
  266. package/scripts/git/main-merge.ts +1 -1
  267. package/scripts/git/main-sync.ts +19 -1
  268. package/scripts/git/parse-json-array.ts +0 -3
  269. package/scripts/git/repository-lock.ts +16 -16
  270. package/scripts/git/{git-stash.ts → stash/git-stash.ts} +1 -1
  271. package/scripts/git/{stash-pop-args.ts → stash/stash-pop-args.ts} +1 -1
  272. package/scripts/git/{stash-pop-cli.ts → stash/stash-pop-cli.ts} +0 -1
  273. package/scripts/git/{stash-sweep-lock.ts → stash/stash-sweep-lock.ts} +3 -3
  274. package/scripts/hooks/codex-hook-adapter.ts +0 -1
  275. package/scripts/hooks/edited-cspell.ts +1 -1
  276. package/scripts/hooks/format-edited-cli.ts +15 -0
  277. package/scripts/hooks/format-edited-file.ts +4 -9
  278. package/scripts/hooks/pre-push-unit.ts +0 -4
  279. package/scripts/hooks/pretool-guard-cli.ts +21 -0
  280. package/scripts/hooks/pretool-guard.ts +36 -19
  281. package/scripts/hooks/reserved-run.ts +1 -1
  282. package/scripts/hooks/step-zero-notice.ts +76 -0
  283. package/scripts/hooks/stop-guard.ts +47 -21
  284. package/scripts/init/claude-plugin-config.ts +4 -5
  285. package/scripts/init/hook-command-rewrite.ts +16 -8
  286. package/scripts/init/hook-launch.ts +41 -15
  287. package/scripts/init/init-basic.ts +2 -5
  288. package/scripts/init/init-logic.ts +7 -0
  289. package/scripts/init/init.ts +0 -3
  290. package/scripts/init/project-profile.ts +6 -11
  291. package/scripts/init/start-exec.ts +8 -2
  292. package/scripts/init/start-plan.ts +18 -5
  293. package/scripts/init/start-setup-pr.ts +52 -25
  294. package/scripts/init/start-steps.ts +42 -9
  295. package/scripts/init/start.ts +40 -10
  296. package/scripts/issue/behavior-change-lint.ts +0 -1
  297. package/scripts/issue/defect-rate-cli.ts +3 -3
  298. package/scripts/issue/defect-rate.ts +1 -2
  299. package/scripts/{git → issue}/git-next-issues.ts +37 -8
  300. package/scripts/issue/issue-backlinks-cli.ts +1 -5
  301. package/scripts/issue/issue-cite-cli.ts +2 -6
  302. package/scripts/issue/issue-cite.ts +19 -3
  303. package/scripts/issue/issue-classification.ts +1 -9
  304. package/scripts/issue/issue-closing-pr.ts +4 -4
  305. package/scripts/issue/issue-comment-cli.ts +2 -2
  306. package/scripts/issue/issue-file-cli.ts +5 -5
  307. package/scripts/issue/issue-file.ts +2 -2
  308. package/scripts/issue/issue-fold-cli.ts +1 -1
  309. package/scripts/issue/issue-fold-existing-cli.ts +1 -1
  310. package/scripts/{git → issue}/issue-labels.ts +20 -0
  311. package/scripts/issue/issue-lint-cli.ts +1 -1
  312. package/scripts/issue/issue-merged.ts +2 -2
  313. package/scripts/issue/issue-rank.ts +89 -0
  314. package/scripts/issue/issue-read-cli.ts +8 -47
  315. package/scripts/issue/issue-read.ts +0 -2
  316. package/scripts/issue/issue-report-failures.ts +80 -0
  317. package/scripts/issue/issue-scout-cli.ts +1 -7
  318. package/scripts/issue/issue-scout-closed.ts +2 -2
  319. package/scripts/issue/issue-scout.ts +0 -2
  320. package/scripts/issue/issue-state-cli.ts +5 -46
  321. package/scripts/issue/issue-state.ts +1 -5
  322. package/scripts/issue/markdown-section.ts +1 -1
  323. package/scripts/issue/measure-rerun-cli.ts +1 -1
  324. package/scripts/issue/reproduction-measure.ts +1 -1
  325. package/scripts/josh/cli-body.ts +1 -1
  326. package/scripts/josh/file-map-stamp.ts +0 -3
  327. package/scripts/josh/josh-command-map.ts +2 -102
  328. package/scripts/josh/josh-commands-ai.ts +9 -102
  329. package/scripts/josh/josh-commands-backlog.ts +5 -1
  330. package/scripts/josh/josh-commands-development.ts +10 -3
  331. package/scripts/josh/josh-commands-issue.ts +2 -2
  332. package/scripts/josh/josh-commands-maintenance.ts +7 -0
  333. package/scripts/josh/josh-commands-project.ts +7 -1
  334. package/scripts/josh/josh-commands-run.ts +114 -0
  335. package/scripts/josh/josh-commands-versioning.ts +8 -0
  336. package/scripts/josh/josh-commands-workflow.ts +2 -2
  337. package/scripts/josh/path-decision.ts +0 -3
  338. package/scripts/josh/process-owner.ts +16 -0
  339. package/scripts/josh/session-language-cli.ts +0 -1
  340. package/scripts/lane/lane-await.ts +3 -6
  341. package/scripts/lane/lane-capacity.ts +6 -3
  342. package/scripts/lane/lane-child-invocation.ts +20 -7
  343. package/scripts/lane/lane-child-marker.ts +16 -2
  344. package/scripts/lane/lane-cli.ts +33 -18
  345. package/scripts/lane/lane-close.ts +1 -3
  346. package/scripts/lane/lane-dispatch.ts +3 -4
  347. package/scripts/lane/lane-environment.ts +0 -9
  348. package/scripts/lane/lane-handoff.ts +38 -0
  349. package/scripts/lane/lane-launch-cli.ts +21 -11
  350. package/scripts/lane/lane-open.ts +0 -3
  351. package/scripts/lane/lane-output.ts +0 -1
  352. package/scripts/lane/lane-registry.ts +9 -0
  353. package/scripts/lane/lane-report.ts +10 -4
  354. package/scripts/lane/openai-lane-ship.ts +2 -0
  355. package/scripts/lane/openai-lane-supervisor-decision.ts +2 -1
  356. package/scripts/lane/openai-lane-supervisor.ts +6 -4
  357. package/scripts/lane/openai-review-broker.ts +3 -0
  358. package/scripts/lib/bounded-pool.ts +1 -0
  359. package/scripts/lib/json-value.ts +5 -4
  360. package/scripts/lib/poll.ts +3 -1
  361. package/scripts/lib/timed-fetch.ts +15 -0
  362. package/scripts/lib/timeouts.ts +13 -0
  363. package/scripts/{yaml → lib}/yaml-document.ts +3 -1
  364. package/scripts/{bytes → lines}/bytes-command.ts +0 -2
  365. package/scripts/lines/lines-command.ts +0 -1
  366. package/scripts/lint/lint-related-scope.ts +0 -1
  367. package/scripts/lint/lint-related.ts +1 -1
  368. package/scripts/{git → notify}/telegram-notify.ts +2 -2
  369. package/scripts/{git → notify}/telegram-test.ts +4 -4
  370. package/scripts/observations/observation-ledger-home.ts +0 -1
  371. package/scripts/observations/observation-ledger-line.ts +0 -1
  372. package/scripts/observations/observation-ledger-migrate.ts +1 -1
  373. package/scripts/observations/observations-flush-landing.ts +3 -3
  374. package/scripts/observations/observations-flush.ts +2 -2
  375. package/scripts/overrides/lockfile-overrides.ts +1 -1
  376. package/scripts/overrides/overrides-logic.ts +1 -1
  377. package/scripts/package/package-scout-cli.ts +2 -7
  378. package/scripts/package/package-scout.ts +0 -2
  379. package/scripts/propagate/propagate-git-failure.ts +0 -1
  380. package/scripts/propagate/propagate-git.ts +0 -2
  381. package/scripts/propagate/propagate-plan.ts +185 -0
  382. package/scripts/propagate/propagate-publish.ts +2 -3
  383. package/scripts/propagate/propagate-run.ts +5 -3
  384. package/scripts/propagate/propagate-steps.ts +19 -6
  385. package/scripts/propagate/propagate-targets.ts +13 -6
  386. package/scripts/propagate/propagate.ts +60 -46
  387. package/scripts/refactor/import-graph.ts +0 -1
  388. package/scripts/refactor/refactor-lint.ts +0 -2
  389. package/scripts/refactor/refactor-scan.ts +0 -1
  390. package/scripts/refactor/refactor-targets.ts +0 -1
  391. package/scripts/registry-migration/migrate-logic.ts +1 -2
  392. package/scripts/registry-migration/migrate.ts +19 -9
  393. package/scripts/release/github-release-cli.ts +8 -6
  394. package/scripts/release/github-release-environment.ts +46 -0
  395. package/scripts/release/github-release.ts +151 -94
  396. package/scripts/release/release-history.ts +0 -1
  397. package/scripts/release/release-plan.ts +0 -1
  398. package/scripts/release/release-publish.ts +2 -3
  399. package/scripts/release/release-scope-cli.ts +1 -2
  400. package/scripts/release/release-tag.ts +2 -4
  401. package/scripts/repo/auto-merge-setting-logic.ts +1 -4
  402. package/scripts/repo/repo-setting.ts +1 -1
  403. package/scripts/repo/repository-labels.ts +3 -3
  404. package/scripts/repo/required-checks-logic.ts +206 -0
  405. package/scripts/repo/required-checks-report.ts +71 -0
  406. package/scripts/repo/ruleset-check-cli.ts +53 -0
  407. package/scripts/repo/ruleset-check.ts +147 -0
  408. package/scripts/report/report-lint-cli.ts +0 -4
  409. package/scripts/review/disposition-cli.ts +1 -1
  410. package/scripts/review/live-evidence.ts +1 -1
  411. package/scripts/review/review-attest-cli.ts +0 -6
  412. package/scripts/review/review-attest.ts +48 -16
  413. package/scripts/review/review-brief-cli.ts +72 -8
  414. package/scripts/review/review-brief.ts +67 -9
  415. package/scripts/review/review-diff-parts.ts +89 -0
  416. package/scripts/review/review-diff-write.ts +97 -0
  417. package/scripts/review/review-finding-ledger.ts +0 -1
  418. package/scripts/review/review-record-cli.ts +1 -1
  419. package/scripts/review/review-record.ts +0 -1
  420. package/scripts/review/review-round2-cli.ts +1 -1
  421. package/scripts/review/review-stamps.ts +6 -2
  422. package/scripts/review/review-tree.ts +14 -2
  423. package/scripts/rules/decision-oracle-stage.ts +18 -0
  424. package/scripts/rules/decision-oracle.ts +10 -7
  425. package/scripts/rules/delivered-rules.ts +9 -1
  426. package/scripts/rules/destructive-command.ts +119 -0
  427. package/scripts/rules/direct-filing.ts +1 -1
  428. package/scripts/rules/file-body.ts +0 -3
  429. package/scripts/rules/filing-cap.ts +0 -2
  430. package/scripts/rules/gh-api.ts +7 -2
  431. package/scripts/rules/git-argv.ts +18 -7
  432. package/scripts/rules/git-force.ts +0 -2
  433. package/scripts/rules/implementation-cut.ts +1 -2
  434. package/scripts/rules/index-guard.ts +71 -0
  435. package/scripts/rules/issue-citation.ts +50 -25
  436. package/scripts/rules/issue-fold.ts +1 -2
  437. package/scripts/rules/lane-background.ts +15 -7
  438. package/scripts/rules/lane-carry-conflict.ts +1 -2
  439. package/scripts/rules/lane-park.ts +14 -8
  440. package/scripts/rules/last-prompt.ts +1 -0
  441. package/scripts/rules/oracle-consulted.ts +1 -1
  442. package/scripts/rules/oracle-firing.ts +1 -0
  443. package/scripts/rules/oracle-list-cli.ts +0 -3
  444. package/scripts/rules/permission-guards.ts +14 -0
  445. package/scripts/rules/pre-gate-cut.ts +2 -2
  446. package/scripts/rules/protected-files.ts +74 -0
  447. package/scripts/rules/reply-language.ts +1 -1
  448. package/scripts/rules/rule-body-guard.ts +0 -3
  449. package/scripts/rules/rule-value-cli.ts +0 -1
  450. package/scripts/rules/shell-body-trigger.ts +0 -1
  451. package/scripts/rules/shell-segments.ts +0 -1
  452. package/scripts/rules/stop-rules.ts +13 -5
  453. package/scripts/rules/tail-commands.ts +1 -1
  454. package/scripts/rules/test-declared-commit.ts +1 -1
  455. package/scripts/rules/third-party-write.ts +0 -1
  456. package/scripts/rules/worktree-guard.ts +26 -9
  457. package/scripts/run/run-carry-cli.ts +0 -2
  458. package/scripts/run/run-carry-stash.ts +2 -2
  459. package/scripts/run/run-carry-streak.ts +1 -1
  460. package/scripts/run/run-cut-cli.ts +0 -7
  461. package/scripts/run/run-cut.ts +8 -54
  462. package/scripts/run/run-ending-cli.ts +1 -1
  463. package/scripts/run/run-ending.ts +1 -4
  464. package/scripts/run/run-entry-cli.ts +101 -24
  465. package/scripts/run/run-entry.ts +0 -1
  466. package/scripts/run/run-event-cli.ts +0 -2
  467. package/scripts/run/run-event-follow.ts +1 -0
  468. package/scripts/run/run-event-render.ts +1 -1
  469. package/scripts/run/run-event-scope.ts +53 -4
  470. package/scripts/run/run-event-stream.ts +0 -3
  471. package/scripts/run/run-event-watch.ts +1 -0
  472. package/scripts/run/run-halfrun-resume.ts +20 -7
  473. package/scripts/run/run-headless.ts +24 -8
  474. package/scripts/run/run-hold-cli.ts +33 -10
  475. package/scripts/run/run-hold.ts +25 -5
  476. package/scripts/run/run-issue-number.ts +1 -1
  477. package/scripts/run/run-liveness-cli.ts +1 -1
  478. package/scripts/run/run-liveness.ts +2 -3
  479. package/scripts/run/run-merge-cli.ts +5 -13
  480. package/scripts/run/run-merge-steps.ts +5 -5
  481. package/scripts/run/run-merge.ts +1 -1
  482. package/scripts/run/run-next-cli.ts +1 -1
  483. package/scripts/run/run-parent-cut-hook.ts +143 -0
  484. package/scripts/run/run-preflight.ts +2 -9
  485. package/scripts/run/run-prep-cli.ts +2 -2
  486. package/scripts/run/run-prep-locate.ts +1 -1
  487. package/scripts/run/run-progress-cli.ts +4 -7
  488. package/scripts/run/run-progress-clock.ts +6 -34
  489. package/scripts/run/run-progress-config.ts +0 -4
  490. package/scripts/run/run-progress-read.ts +3 -3
  491. package/scripts/run/run-progress.ts +22 -10
  492. package/scripts/run/run-prrun-resume.ts +117 -0
  493. package/scripts/run/run-report-cli.ts +1 -2
  494. package/scripts/run/run-report.ts +0 -1
  495. package/scripts/run/run-retrospective.ts +1 -1
  496. package/scripts/run/run-review-cli.ts +0 -3
  497. package/scripts/run/run-review-steps.ts +2 -0
  498. package/scripts/run/run-review.ts +0 -2
  499. package/scripts/run/run-ship-cli.ts +27 -77
  500. package/scripts/run/run-ship-detach.ts +1 -0
  501. package/scripts/run/run-ship-next.ts +106 -0
  502. package/scripts/run/run-ship-preflight.ts +87 -0
  503. package/scripts/run/run-ship-return.ts +8 -3
  504. package/scripts/run/run-ship-review-steps.ts +23 -30
  505. package/scripts/run/run-ship-review.ts +20 -0
  506. package/scripts/run/run-ship-scoped.ts +45 -0
  507. package/scripts/run/run-ship-stage.ts +5 -1
  508. package/scripts/run/run-ship-steps.ts +105 -0
  509. package/scripts/run/run-ship.ts +2 -1
  510. package/scripts/run/run-stage-read.ts +62 -0
  511. package/scripts/run/run-stage.ts +160 -0
  512. package/scripts/run/run-status-cli.ts +1 -1
  513. package/scripts/run/run-step-cli.ts +21 -14
  514. package/scripts/run/run-step.ts +1 -1
  515. package/scripts/run/run-stop-notify.ts +1 -3
  516. package/scripts/run/run-stranded-cli.ts +0 -4
  517. package/scripts/run/run-stranded-detect.ts +2 -2
  518. package/scripts/run/run-tail-cli.ts +17 -11
  519. package/scripts/run/run-tail.ts +2 -0
  520. package/scripts/run/run-tidy-lanes.ts +2 -1
  521. package/scripts/run/run-tidy-stashes.ts +12 -12
  522. package/scripts/run/run-wake-cli.ts +4 -5
  523. package/scripts/run/run-wake-describe.ts +19 -1
  524. package/scripts/run/run-wake-loop.ts +2 -2
  525. package/scripts/run/run-wake.ts +2 -4
  526. package/scripts/run/run-watcher-guard-cli.ts +0 -4
  527. package/scripts/run/run-watcher-guard.ts +9 -7
  528. package/scripts/run/run-watcher-hook.ts +1 -1
  529. package/scripts/safe-chain/ci-installer-pin.ts +11 -5
  530. package/scripts/safe-chain/project-config.ts +1 -1
  531. package/scripts/security/security-audit-provision-logic.ts +0 -1
  532. package/scripts/security/security-audit-provision.ts +3 -2
  533. package/scripts/security/security-audit.ts +0 -1
  534. package/scripts/security/security-updates-logic.ts +0 -1
  535. package/scripts/sonar/sonar-hotspots-cli.ts +10 -52
  536. package/scripts/sonar/sonar-hotspots.ts +0 -1
  537. package/scripts/sonar/sonar-new-code-cli.ts +150 -0
  538. package/scripts/sonar/sonar-new-code.ts +79 -0
  539. package/scripts/sonar/sonar-project.ts +97 -0
  540. package/scripts/split/split-assess-cli.ts +1 -1
  541. package/scripts/split/split-assess.ts +2 -5
  542. package/scripts/sync/managed-config-scope-cli.ts +1 -1
  543. package/scripts/sync/skill-migration.ts +0 -1
  544. package/scripts/sync/sync-hook-safety.ts +2 -3
  545. package/scripts/sync/sync.ts +1 -8
  546. package/scripts/sync/template-source-logic.ts +0 -1
  547. package/scripts/sync/workflow-pin-logic.ts +16 -28
  548. package/scripts/test/test-declared-logic.ts +0 -1
  549. package/scripts/test/test-declared.ts +0 -2
  550. package/scripts/test/test-red-commit.ts +2 -2
  551. package/scripts/test/test-red.ts +14 -7
  552. package/scripts/test/test-type-logic.ts +1 -1
  553. package/scripts/test/unit-worker-share.ts +7 -16
  554. package/scripts/time-runtime/time-batch-guard.ts +1 -2
  555. package/scripts/time-runtime/time-bundle-call.ts +2 -3
  556. package/scripts/time-runtime/time-bundles.ts +0 -4
  557. package/scripts/time-runtime/time-density-hook.ts +0 -2
  558. package/scripts/time-runtime/time-followup-stage.ts +1 -1
  559. package/scripts/time-runtime/time-format.ts +0 -73
  560. package/scripts/time-runtime/time-round-trips.ts +0 -4
  561. package/scripts/time-runtime/time-single-check.ts +1 -1
  562. package/scripts/time-runtime/time-spans.ts +1 -1
  563. package/scripts/time-runtime/time-transcript-line.ts +1 -2
  564. package/scripts/ui/ui-routes-cli.ts +0 -5
  565. package/scripts/ui/ui-routes.ts +0 -5
  566. package/scripts/version/effective-upstream.ts +2 -2
  567. package/scripts/version/latest-corepack.ts +7 -9
  568. package/scripts/version/latest-scope-cli.ts +0 -2
  569. package/scripts/version/latest-update.ts +0 -2
  570. package/scripts/version/npm-registry.ts +97 -0
  571. package/scripts/version/publishable-range-check.ts +1 -1
  572. package/scripts/version/release-hold.ts +0 -4
  573. package/scripts/version/running-binary.ts +2 -2
  574. package/scripts/version/version-check-logic.ts +0 -2
  575. package/scripts/version/version-commands.ts +5 -4
  576. package/scripts/version/version-remote.ts +28 -14
  577. package/scripts/version/version-targets.ts +4 -4
  578. package/templates/sonar-project.properties +28 -1
  579. package/templates/workflows/dependabot-auto-merge.yml +5 -3
  580. package/templates/workflows/github-release.yml +81 -0
  581. package/prompts/collaboration-workflow/cross-repo-epic.md +0 -5
  582. package/prompts/collaboration-workflow/epic-audit.md +0 -5
  583. package/prompts/collaboration-workflow/epic-bundle.md +0 -5
  584. package/scripts/init/plugin-install-hint.ts +0 -47
  585. package/scripts/version/parse-json.ts +0 -13
  586. /package/scripts/{git → followup}/git-followup-stages.ts +0 -0
  587. /package/scripts/{git → gh}/git-gh-api-path.ts +0 -0
  588. /package/scripts/{git → gh}/git-gh-command.ts +0 -0
  589. /package/scripts/{git → gh}/git-gh-issue-write.ts +0 -0
  590. /package/scripts/{git → gh}/git-gh-issue.ts +0 -0
  591. /package/scripts/{git → gh}/git-gh-pr-auto-merge.ts +0 -0
  592. /package/scripts/{git → gh}/git-gh-pr-snapshot.ts +0 -0
  593. /package/scripts/{git → gh}/git-gh-reachability.ts +0 -0
  594. /package/scripts/{git → gh}/git-gh-repo.ts +0 -0
  595. /package/scripts/{git → gh}/git-gh-rest-state.ts +0 -0
  596. /package/scripts/{git → gh}/git-pr-checks-watch.ts +0 -0
  597. /package/scripts/{git → gh}/git-pr-error.ts +0 -0
  598. /package/scripts/{git → gh}/git-pr-messages.ts +0 -0
  599. /package/scripts/{git → gh}/github-issue-url.ts +0 -0
  600. /package/scripts/git/{stash-orphans.ts → stash/stash-orphans.ts} +0 -0
  601. /package/scripts/{git → issue}/issue-reference.ts +0 -0
  602. /package/scripts/{git → lib}/animation-helpers.ts +0 -0
  603. /package/scripts/{git → lib}/git-animation.ts +0 -0
  604. /package/scripts/{git → notify}/git-notify.ts +0 -0
  605. /package/scripts/{git → notify}/telegram-test-logic.ts +0 -0
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env tsx
2
+ import { fileURLToPath } from 'node:url'
3
+ import { z } from 'zod'
4
+ import {
5
+ CLEAN,
6
+ FINDINGS,
7
+ sonar_new_code,
8
+ UNREADABLE,
9
+ type NewCodeFetch,
10
+ type NewCodeIssue,
11
+ type NewCodeReading,
12
+ } from './sonar-new-code'
13
+ import { sonar_project } from './sonar-project'
14
+
15
+ // `josh sonar:new-code <PR>` — fail when a pull request adds any new SonarCloud issue or duplicated
16
+ // block (joshuafolkken/kit#3045).
17
+ //
18
+ // `sonar-qube.yml` runs it after the scan on every pull request, so the `SonarQube` check turns red on
19
+ // a single finding instead of only when the Quality Gate's ratios tip over. The verdict lives in
20
+ // `sonar-new-code.ts`; this file is the I/O around it: two SonarCloud API reads, one line per issue,
21
+ // and the verdict line. A read that fails is `unreadable` and fails the check too, so an outage never
22
+ // passes a pull request as clean.
23
+
24
+ const ARGV_OFFSET = 2
25
+ const USAGE = 'Usage: josh sonar:new-code <PR>'
26
+ const ISSUES_PATH = '/api/issues/search'
27
+ const MEASURES_PATH = '/api/measures/component'
28
+ const DUPLICATED_BLOCKS_METRIC = 'new_duplicated_blocks'
29
+ // The most issues one page carries; the verdict reads the API's own total, so a longer list only
30
+ // shortens what is printed.
31
+ const ISSUE_PAGE_SIZE = '100'
32
+ const FAILURE_EXIT_CODE = 1
33
+ const UNKNOWN = '?'
34
+
35
+ // `looseObject` so a field SonarCloud adds later does not fail the parse; only the fields the report
36
+ // prints are declared.
37
+ const issue_schema = z.looseObject({
38
+ rule: z.string(),
39
+ severity: z.string().optional(),
40
+ type: z.string().optional(),
41
+ component: z.string(),
42
+ line: z.number().optional(),
43
+ message: z.string(),
44
+ })
45
+ const issues_schema = z.looseObject({ total: z.number(), issues: z.array(issue_schema) })
46
+ const period_schema = z.looseObject({ value: z.string().optional() })
47
+ const measure_schema = z.looseObject({
48
+ metric: z.string(),
49
+ value: z.string().optional(),
50
+ periods: z.array(period_schema).optional(),
51
+ })
52
+ const measures_schema = z.looseObject({
53
+ component: z.looseObject({ measures: z.array(measure_schema) }),
54
+ })
55
+
56
+ function issues_url(project_key: string, pull_request: string): string {
57
+ return sonar_project.api_url(ISSUES_PATH, {
58
+ componentKeys: project_key,
59
+ pullRequest: pull_request,
60
+ resolved: 'false',
61
+ ps: ISSUE_PAGE_SIZE,
62
+ })
63
+ }
64
+
65
+ function measures_url(project_key: string, pull_request: string): string {
66
+ return sonar_project.api_url(MEASURES_PATH, {
67
+ component: project_key,
68
+ pullRequest: pull_request,
69
+ metricKeys: DUPLICATED_BLOCKS_METRIC,
70
+ })
71
+ }
72
+
73
+ function duplicated_blocks_of(measures: z.infer<typeof measures_schema>): NewCodeFetch {
74
+ const measure = measures.component.measures.find(
75
+ (entry) => entry.metric === DUPLICATED_BLOCKS_METRIC,
76
+ )
77
+ const blocks = sonar_new_code.measure_value(measure)
78
+
79
+ return blocks === undefined
80
+ ? { error: `${DUPLICATED_BLOCKS_METRIC} is not a number` }
81
+ : { issues: [], issue_total: 0, duplicated_blocks: blocks }
82
+ }
83
+
84
+ async function fetch_new_code(project_key: string, pull_request: string): Promise<NewCodeFetch> {
85
+ const [issues, measures] = await Promise.all([
86
+ sonar_project.fetch_json(issues_url(project_key, pull_request), issues_schema),
87
+ sonar_project.fetch_json(measures_url(project_key, pull_request), measures_schema),
88
+ ])
89
+ if ('error' in issues) return { error: `issues: ${issues.error}` }
90
+ if ('error' in measures) return { error: `measures: ${measures.error}` }
91
+
92
+ const blocks = duplicated_blocks_of(measures.data)
93
+
94
+ return 'error' in blocks
95
+ ? blocks
96
+ : { ...blocks, issues: issues.data.issues, issue_total: issues.data.total }
97
+ }
98
+
99
+ function format_issue(issue: NewCodeIssue): string {
100
+ const line = issue.line === undefined ? UNKNOWN : String(issue.line)
101
+ const kind = `${issue.severity ?? UNKNOWN} ${issue.type ?? UNKNOWN}`
102
+
103
+ return `${kind}\t${issue.component}:${line}\t${issue.rule}\t${issue.message}`
104
+ }
105
+
106
+ function findings_line(reading: NewCodeReading): string {
107
+ const counts = `${String(reading.issue_total)} new issue(s), ${String(reading.duplicated_blocks)} new duplicated block(s)`
108
+
109
+ return `${FINDINGS}: ${counts} — fix them, or resolve a deliberate exception in SonarCloud`
110
+ }
111
+
112
+ // The report, and whether it passes: one line per issue, then the verdict line.
113
+ function report(fetched: NewCodeFetch): { lines: ReadonlyArray<string>; is_clean: boolean } {
114
+ const verdict = sonar_new_code.verdict_of(fetched)
115
+
116
+ if ('error' in fetched) return { lines: [`${UNREADABLE}: ${fetched.error}`], is_clean: false }
117
+ if (verdict === CLEAN) return { lines: [CLEAN], is_clean: true }
118
+
119
+ const issue_lines = fetched.issues.map((issue) => format_issue(issue))
120
+
121
+ return { lines: [...issue_lines, findings_line(fetched)], is_clean: false }
122
+ }
123
+
124
+ async function run(argv: ReadonlyArray<string>): Promise<number> {
125
+ const target = await sonar_project.resolve_target(argv, USAGE)
126
+ if (target === undefined) return FAILURE_EXIT_CODE
127
+
128
+ const { lines, is_clean } = report(await fetch_new_code(target.project_key, target.pull_request))
129
+
130
+ for (const line of lines) console.info(line)
131
+
132
+ return is_clean ? 0 : FAILURE_EXIT_CODE
133
+ }
134
+
135
+ async function main(argv: ReadonlyArray<string>): Promise<void> {
136
+ process.exitCode = await run(argv)
137
+ }
138
+
139
+ const sonar_new_code_cli = {
140
+ fetch_new_code,
141
+ issues_url,
142
+ measures_url,
143
+ report,
144
+ run,
145
+ USAGE,
146
+ }
147
+
148
+ if (process.argv[1] === fileURLToPath(import.meta.url)) await main(process.argv.slice(ARGV_OFFSET))
149
+
150
+ export { sonar_new_code_cli }
@@ -0,0 +1,79 @@
1
+ // Whether a pull request adds any new SonarCloud finding — computed from the counts rather than from
2
+ // the Quality Gate (joshuafolkken/kit#3045).
3
+ //
4
+ // The built-in `Sonar way` gate judges a ratio and a rating, not a count: a few MINOR code smells keep
5
+ // the maintainability rating at A, and a copied block in a large pull request stays under the 3%
6
+ // duplication threshold. So a pull request could add both and the `SonarQube` check stayed green. The
7
+ // verdict here is a count: one new issue of any type or severity, or one new duplicated block, is a
8
+ // finding. An issue resolved in SonarCloud (accepted, false positive) is not counted — the fetch asks
9
+ // for unresolved issues only — so that resolution stays the escape hatch for a deliberate exception.
10
+
11
+ const CLEAN = 'clean'
12
+ const FINDINGS = 'findings'
13
+ // The fetch could not be read — told apart from a clean read so a failed request never passes the
14
+ // check as "no findings".
15
+ const UNREADABLE = 'unreadable'
16
+
17
+ const NEW_CODE_VERDICTS = [CLEAN, FINDINGS, UNREADABLE] as const
18
+
19
+ type NewCodeVerdict = (typeof NEW_CODE_VERDICTS)[number]
20
+
21
+ // One issue as `api/issues/search` returns it; only the fields the report prints are declared.
22
+ // The optional fields carry `| undefined` explicitly so the zod-parsed shape assigns to this type
23
+ // under `exactOptionalPropertyTypes`.
24
+ interface NewCodeIssue {
25
+ rule: string
26
+ severity?: string | undefined
27
+ type?: string | undefined
28
+ component: string
29
+ line?: number | undefined
30
+ message: string
31
+ }
32
+
33
+ // What the pull request's analysis holds: the unresolved issues (`issue_total` is the API's own count,
34
+ // which can exceed the page `issues` carries) and the `new_duplicated_blocks` measure.
35
+ interface NewCodeReading {
36
+ issues: ReadonlyArray<NewCodeIssue>
37
+ issue_total: number
38
+ duplicated_blocks: number
39
+ }
40
+
41
+ type NewCodeFetch = NewCodeReading | { error: string }
42
+
43
+ // A measure as `api/measures/component` returns it. A `new_*` metric carries its value under
44
+ // `periods`; any other metric carries a top-level `value`.
45
+ interface SonarMeasure {
46
+ value?: string | undefined
47
+ periods?: ReadonlyArray<{ value?: string | undefined }> | undefined
48
+ }
49
+
50
+ function to_count(raw: string | undefined): number | undefined {
51
+ if (raw === undefined) return undefined
52
+
53
+ const value = Number(raw)
54
+
55
+ return Number.isFinite(value) ? value : undefined
56
+ }
57
+
58
+ // The numeric value of a measure, or `undefined` when it is present but not a number. A measure the
59
+ // response leaves out is 0: SonarCloud omits a metric it has nothing to count on, such as a pull
60
+ // request that changes no analyzable file.
61
+ function measure_value(measure: SonarMeasure | undefined): number | undefined {
62
+ if (measure === undefined) return 0
63
+
64
+ return to_count(measure.periods?.[0]?.value ?? measure.value)
65
+ }
66
+
67
+ function verdict_of(fetch: NewCodeFetch): NewCodeVerdict {
68
+ if ('error' in fetch) return UNREADABLE
69
+
70
+ return fetch.issue_total > 0 || fetch.duplicated_blocks > 0 ? FINDINGS : CLEAN
71
+ }
72
+
73
+ const sonar_new_code = {
74
+ measure_value,
75
+ verdict_of,
76
+ }
77
+
78
+ export { sonar_new_code, CLEAN, FINDINGS, UNREADABLE, NEW_CODE_VERDICTS }
79
+ export type { NewCodeFetch, NewCodeIssue, NewCodeReading, NewCodeVerdict, SonarMeasure }
@@ -0,0 +1,97 @@
1
+ import { existsSync, readFileSync } from 'node:fs'
2
+ import path from 'node:path'
3
+ import { git_command } from '#scripts/git/git-command'
4
+ import { error_text } from '#scripts/lib/error-message'
5
+ import { timed_fetch } from '#scripts/lib/timed-fetch'
6
+ import type { z } from 'zod'
7
+
8
+ // The SonarCloud project a `josh sonar:*` command reads, shared by every command that calls the
9
+ // SonarCloud API (joshuafolkken/kit#3045): the host, the project key `sonar-project.properties`
10
+ // records — the file `josh init` / `josh sync` generate from the GitHub repository name — and the
11
+ // `<PR>` positional each command takes.
12
+
13
+ const SONAR_HOST = 'https://sonarcloud.io'
14
+ const PROPERTIES_FILE = 'sonar-project.properties'
15
+ const PROJECT_KEY_PREFIX = 'sonar.projectKey='
16
+ const TOKEN_VARIABLE = 'SONAR_TOKEN'
17
+ const AUTHORIZATION_HEADER = 'Authorization'
18
+
19
+ interface SonarTarget {
20
+ project_key: string
21
+ pull_request: string
22
+ }
23
+
24
+ type SonarRead<T> = { data: T } | { error: string }
25
+
26
+ function read_project_key(root: string): string | undefined {
27
+ const file = path.join(root, PROPERTIES_FILE)
28
+ if (!existsSync(file)) return undefined
29
+
30
+ const line = readFileSync(file, 'utf8')
31
+ .split('\n')
32
+ .find((entry) => entry.startsWith(PROJECT_KEY_PREFIX))
33
+
34
+ return line?.slice(PROJECT_KEY_PREFIX.length).trim()
35
+ }
36
+
37
+ function api_url(api_path: string, query: Record<string, string>): string {
38
+ return `${SONAR_HOST}${api_path}?${new URLSearchParams(query).toString()}`
39
+ }
40
+
41
+ // A public project reads without a token; a private one needs it. CI lifts `SONAR_TOKEN` into the
42
+ // job env, so it is sent when present and the request is anonymous otherwise.
43
+ function request_init(): RequestInit {
44
+ const token = process.env[TOKEN_VARIABLE] ?? ''
45
+
46
+ return token === '' ? {} : { headers: [[AUTHORIZATION_HEADER, `Bearer ${token}`]] }
47
+ }
48
+
49
+ // One SonarCloud API read: the parsed body on success, or the reason the read failed — rate-limited,
50
+ // offline, a non-OK response or an unexpected shape — so a caller cannot mistake a failed read for an
51
+ // empty success.
52
+ async function fetch_json<T>(url: string, schema: z.ZodType<T>): Promise<SonarRead<T>> {
53
+ try {
54
+ const response = await timed_fetch(url, request_init())
55
+ if (!response.ok) return { error: `HTTP ${String(response.status)}` }
56
+
57
+ return { data: schema.parse(await response.json()) }
58
+ } catch (error) {
59
+ return { error: error_text.message_of(error) }
60
+ }
61
+ }
62
+
63
+ // The pull request named on the command line and this repository's project key, or `undefined`
64
+ // after printing why the command cannot run — the usage line, or the missing project key.
65
+ async function resolve_target(
66
+ argv: ReadonlyArray<string>,
67
+ usage: string,
68
+ ): Promise<SonarTarget | undefined> {
69
+ const [pull_request] = argv
70
+
71
+ if (pull_request === undefined || pull_request.startsWith('-')) {
72
+ console.error(usage)
73
+
74
+ return undefined
75
+ }
76
+
77
+ const project_key = read_project_key(await git_command.repository_root())
78
+
79
+ if (project_key === undefined) {
80
+ console.error(`no ${PROJECT_KEY_PREFIX} found in ${PROPERTIES_FILE}`)
81
+
82
+ return undefined
83
+ }
84
+
85
+ return { project_key, pull_request }
86
+ }
87
+
88
+ const sonar_project = {
89
+ api_url,
90
+ fetch_json,
91
+ read_project_key,
92
+ request_init,
93
+ resolve_target,
94
+ }
95
+
96
+ export { sonar_project }
97
+ export type { SonarRead, SonarTarget }
@@ -45,7 +45,7 @@ async function main(argv: ReadonlyArray<string>): Promise<void> {
45
45
  process.exitCode = await run(argv)
46
46
  }
47
47
 
48
- const split_assess_cli = { JSON_KEY, USAGE, main, parse_is_json, run }
48
+ const split_assess_cli = { parse_is_json }
49
49
 
50
50
  if (process.argv[1] === fileURLToPath(import.meta.url)) await main(process.argv.slice(ARGV_OFFSET))
51
51
 
@@ -27,7 +27,8 @@ interface SizeMeasurement {
27
27
  verdict: SplitVerdict
28
28
  }
29
29
 
30
- // The guide from `split-assessment.md`. Strictly greater than: "about 10 changed files" and a change
30
+ // The guide's single source: `split-assessment.md` states these once and a test pins the two equal
31
+ // (joshuafolkken/kit#2996). Strictly greater than: "about 10 changed files" and a change
31
32
  // that "lands at 11 files is not thereby a split" put the bar above the round number, not at it.
32
33
  const FILE_GUIDE = 10
33
34
  const LINE_GUIDE = 400
@@ -112,12 +113,8 @@ const split_assess = {
112
113
  SPLIT_VERDICT,
113
114
  SINGLE_VERDICT,
114
115
  assess,
115
- measure,
116
- non_test_changes,
117
116
  parse_numstat,
118
- parse_row,
119
117
  reason,
120
- verdict_for,
121
118
  }
122
119
 
123
120
  export type { FileChange, SizeMeasurement, SplitVerdict }
@@ -54,7 +54,7 @@ async function main(argv: ReadonlyArray<string>): Promise<void> {
54
54
  process.exitCode = await run(argv)
55
55
  }
56
56
 
57
- const managed_config_scope_cli = { decide, format_reason, JSON_KEY, main, run, USAGE }
57
+ const managed_config_scope_cli = { decide, format_reason, run, USAGE }
58
58
 
59
59
  if (process.argv[1] === fileURLToPath(import.meta.url)) await main(process.argv.slice(ARGV_OFFSET))
60
60
 
@@ -180,7 +180,6 @@ function kept_note(source: MigrationSource): string {
180
180
  }
181
181
 
182
182
  const skill_migration = {
183
- is_unmodified_copy,
184
183
  migrate_removed_skill_directories,
185
184
  migrate_manifest_skills,
186
185
  expected_manifest,
@@ -1,8 +1,8 @@
1
1
  import { existsSync, readFileSync } from 'node:fs'
2
2
  import path from 'node:path'
3
+ import { json_value } from '#scripts/lib/json-value'
3
4
  import { package_version_schema } from '#scripts/lib/schemas'
4
5
  import { KIT_PACKAGE_NAME } from '#scripts/version/kit-descriptor'
5
- import { safe_json_parse } from '#scripts/version/parse-json'
6
6
  import semver from 'semver'
7
7
 
8
8
  // `josh sync` writes the consumer's Claude and Codex hook files, whose hooks invoke bundles under
@@ -21,7 +21,7 @@ const NODE_MODULES = 'node_modules'
21
21
  function read_version_at(package_json_path: string): string | undefined {
22
22
  if (!existsSync(package_json_path)) return undefined
23
23
  const parsed = package_version_schema.safeParse(
24
- safe_json_parse(readFileSync(package_json_path, 'utf8')),
24
+ json_value.parse_or_undefined(readFileSync(package_json_path, 'utf8')),
25
25
  )
26
26
 
27
27
  return parsed.success ? parsed.data.version : undefined
@@ -75,7 +75,6 @@ const sync_hook_safety = {
75
75
  hook_write_warning,
76
76
  installed_consumer_version,
77
77
  is_safe_to_write_hooks,
78
- outdated_install_warning,
79
78
  read_version_at,
80
79
  }
81
80
 
@@ -7,7 +7,6 @@ import { gh_spawn } from '#scripts/gh/gh-spawn'
7
7
  import { basic_path_migration } from '#scripts/init/basic-path-migration'
8
8
  import { init_logic } from '#scripts/init/init-logic'
9
9
  import { PACKAGE_DIR, PROJECT_ROOT } from '#scripts/init/init-paths'
10
- import { plugin_install_hint_module } from '#scripts/init/plugin-install-hint'
11
10
  import { project_profile } from '#scripts/init/project-profile'
12
11
  import { auto_merge_setting } from '#scripts/repo/auto-merge-setting'
13
12
  import { repository_labels } from '#scripts/repo/repository-labels'
@@ -247,11 +246,6 @@ function sync_basic_artifacts(is_force: boolean): void {
247
246
  sync_basic_prettier_config(path.join(PROJECT_ROOT, BASIC_PRETTIER_CONFIG))
248
247
  }
249
248
 
250
- function sync_full_artifacts(is_force: boolean): void {
251
- sync_project_artifacts(is_force)
252
- plugin_install_hint_module.report_plugin_install_hint()
253
- }
254
-
255
249
  // Checked before anything is written, never per file: the damage is the whole run, and a partial
256
250
  // sync that stopped halfway would leave the source repository in a state neither `git checkout` nor
257
251
  // a re-run describes (joshuafolkken/kit#868).
@@ -265,7 +259,7 @@ function main(): void {
265
259
 
266
260
  console.info('\n🔄 Syncing @joshuafolkken/kit AI files\n')
267
261
  if (project_checks.is_basic(PROJECT_ROOT)) sync_basic_artifacts(is_force)
268
- else sync_full_artifacts(is_force)
262
+ else sync_project_artifacts(is_force)
269
263
  console.info('\n✅ Done.\n')
270
264
  }
271
265
 
@@ -278,7 +272,6 @@ const sync = {
278
272
  sync_workspace_yaml: sync_ai_files.sync_workspace_yaml,
279
273
  sync_claude_md: sync_ai_files.sync_claude_md,
280
274
  sync_prettier_config,
281
- sync_basic_prettier_config,
282
275
  sync_playwright_config,
283
276
  sync_deploy_vps,
284
277
  sync_package_manager_version,
@@ -110,7 +110,6 @@ const template_source_logic = {
110
110
  TRIPWIRE_PAIRS,
111
111
  hash_text,
112
112
  find_copy_drift,
113
- build_tripwire_manifest,
114
113
  find_tripwire_drift,
115
114
  read_recorded_manifest,
116
115
  format_drift_message,
@@ -1,5 +1,6 @@
1
- import { readdirSync, readFileSync, writeFileSync } from 'node:fs'
1
+ import { readdirSync, readFileSync } from 'node:fs'
2
2
  import path from 'node:path'
3
+ import { composite_actions } from '#scripts/ci/composite-actions'
3
4
  import { is_workflow_destination } from '#scripts/claude/workflow-destination'
4
5
  import { package_path } from '#scripts/init/init-paths'
5
6
 
@@ -9,7 +10,8 @@ import { package_path } from '#scripts/init/init-paths'
9
10
  //
10
11
  // The refs committed in templates/workflows/* are NOT authoritative: every consumer
11
12
  // workflow is written through apply_pins_for_destination, which resolves the pins from
12
- // .github/workflows at write time. Dependabot only ever updates .github/workflows (its
13
+ // .github/workflows (and the composite actions under .github/actions) at write time. Dependabot
14
+ // only ever updates .github (its
13
15
  // github-actions ecosystem cannot scan templates/), so a stale template ref must not be
14
16
  // able to reach a consumer — and must not fail CI either. `josh sync-workflow-pins`
15
17
  // stays available to refresh the committed refs, but nothing depends on it having run.
@@ -144,8 +146,19 @@ function list_workflow_sources(relative_directory: string): Array<WorkflowSource
144
146
  .map((name) => read_source(relative_directory, name))
145
147
  }
146
148
 
149
+ // The local composite actions are runtime sources too: `.github/actions/setup-pnpm` is the only
150
+ // place kit's own workflows still pin pnpm/setup (joshuafolkken/kit#2982).
151
+ function list_composite_action_sources(): Array<WorkflowSource> {
152
+ return composite_actions
153
+ .list(package_path)
154
+ .map((file) => ({ file, text: readFileSync(package_path(file), 'utf8') }))
155
+ }
156
+
147
157
  function build_canonical_pins(): Map<string, string> {
148
- return collect_canonical(list_workflow_sources(RUNTIME_WORKFLOWS_DIR))
158
+ return collect_canonical([
159
+ ...list_workflow_sources(RUNTIME_WORKFLOWS_DIR),
160
+ ...list_composite_action_sources(),
161
+ ])
149
162
  }
150
163
 
151
164
  // An action the templates use but .github/workflows does not: write-time injection has no
@@ -181,32 +194,10 @@ function scan_templates<T>(
181
194
  return list_workflow_sources(TEMPLATE_WORKFLOWS_DIR).flatMap((source) => scan(source, canonical))
182
195
  }
183
196
 
184
- function find_pin_drift(): Array<PinDrift> {
185
- return scan_templates((source, canonical) =>
186
- find_drift_in_text(source.file, source.text, canonical),
187
- )
188
- }
189
-
190
197
  function find_unknown_template_actions(): Array<UnknownAction> {
191
198
  return scan_templates(unknown_actions_in_source)
192
199
  }
193
200
 
194
- function write_synced(source: WorkflowSource, canonical: ReadonlyMap<string, string>): void {
195
- const synced = apply_to_text(source.text, canonical)
196
- if (synced !== source.text) writeFileSync(package_path(source.file), synced)
197
- }
198
-
199
- function sync_pins(): Array<PinDrift> {
200
- const canonical = build_canonical_pins()
201
- const drifts = find_pin_drift()
202
-
203
- for (const source of list_workflow_sources(TEMPLATE_WORKFLOWS_DIR)) {
204
- write_synced(source, canonical)
205
- }
206
-
207
- return drifts
208
- }
209
-
210
201
  function format_drift_message(drifts: ReadonlyArray<PinDrift>): string {
211
202
  const lines = drifts.map(
212
203
  (drift) =>
@@ -222,7 +213,6 @@ function format_drift_message(drifts: ReadonlyArray<PinDrift>): string {
222
213
 
223
214
  const workflow_pin_logic = {
224
215
  RUNTIME_WORKFLOWS_DIR,
225
- TEMPLATE_WORKFLOWS_DIR,
226
216
  parse_uses_line,
227
217
  collect_canonical,
228
218
  find_drift_in_text,
@@ -230,9 +220,7 @@ const workflow_pin_logic = {
230
220
  is_workflow_destination,
231
221
  apply_pins_for_destination,
232
222
  build_canonical_pins,
233
- find_pin_drift,
234
223
  find_unknown_template_actions,
235
- sync_pins,
236
224
  format_drift_message,
237
225
  }
238
226
 
@@ -122,7 +122,6 @@ const test_declared_logic = {
122
122
  EXEMPT_PATHS,
123
123
  EXEMPT_PREFIXES,
124
124
  EXEMPT_SUFFIXES,
125
- TEST_SUFFIXES,
126
125
  exempt_files,
127
126
  is_basic_visual,
128
127
  is_exempt,
@@ -192,12 +192,10 @@ if (process.argv[1] === fileURLToPath(import.meta.url)) {
192
192
 
193
193
  const test_declared = {
194
194
  USAGE,
195
- detail_for,
196
195
  format_match,
197
196
  next_step,
198
197
  parse,
199
198
  report,
200
- run,
201
199
  run_match,
202
200
  }
203
201
 
@@ -1,4 +1,4 @@
1
- import { git_gh_issue_read } from '#scripts/git/git-gh-issue-read'
1
+ import { git_gh_issue_read } from '#scripts/gh/git-gh-issue-read'
2
2
  import { test_red, type RedRun } from './test-red'
3
3
  import { test_red_logic } from './test-red-logic'
4
4
 
@@ -45,7 +45,7 @@ async function assert_reproduces(
45
45
  if (test_red_logic.is_refused(body, verdict)) throw new Error(reason_for(issue_number, files))
46
46
  }
47
47
 
48
- const test_red_commit = { assert_reproduces, reason_for }
48
+ const test_red_commit = { assert_reproduces }
49
49
 
50
50
  export type { RedCommitPorts }
51
51
  export { test_red_commit }
@@ -40,13 +40,20 @@ async function changed_tests(): Promise<Array<string>> {
40
40
  return test_red_logic.unit_test_files(paths).filter((file) => existsSync(file))
41
41
  }
42
42
 
43
- async function copy_in(tree: string, files: ReadonlyArray<string>): Promise<void> {
44
- for (const file of files) {
45
- const target = path.join(tree, file)
43
+ async function copy_one(tree: string, file: string): Promise<void> {
44
+ const target = path.join(tree, file)
46
45
 
47
- await mkdir(path.dirname(target), { recursive: true })
48
- await copyFile(file, target)
49
- }
46
+ await mkdir(path.dirname(target), { recursive: true })
47
+ await copyFile(file, target)
48
+ }
49
+
50
+ // Each file has its own target, and a recursive `mkdir` tolerates a sibling creating the same parent.
51
+ async function copy_in(tree: string, files: ReadonlyArray<string>): Promise<void> {
52
+ await Promise.all(
53
+ files.map(async (file) => {
54
+ await copy_one(tree, file)
55
+ }),
56
+ )
50
57
  }
51
58
 
52
59
  async function prepare(tree: string, base: string, files: ReadonlyArray<string>): Promise<void> {
@@ -148,7 +155,7 @@ if (process.argv[1] === fileURLToPath(import.meta.url)) {
148
155
  process.exitCode = await main(process.argv.slice(ARGV_OFFSET))
149
156
  }
150
157
 
151
- const test_red = { USAGE, run }
158
+ const test_red = { run }
152
159
 
153
160
  export type { RedRun }
154
161
  export { test_red }
@@ -25,7 +25,7 @@ function test_type_for(path: string): TestType {
25
25
  return E2E_PREFIXES.some((prefix) => normalized.startsWith(prefix)) ? E2E : UNIT
26
26
  }
27
27
 
28
- const test_type_logic = { E2E, E2E_PREFIXES, UNIT, test_type_for }
28
+ const test_type_logic = { E2E, UNIT, test_type_for }
29
29
 
30
30
  export type { TestType }
31
31
  export { test_type_logic }