@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
@@ -1,9 +1,5 @@
1
1
  #!/usr/bin/env tsx
2
- import { existsSync, readFileSync } from 'node:fs'
3
- import path from 'node:path'
4
2
  import { fileURLToPath } from 'node:url'
5
- import { git_command } from '#scripts/git/git-command'
6
- import { error_text } from '#scripts/lib/error-message'
7
3
  import { managed_config_scope } from '#scripts/sync/managed-config-scope'
8
4
  import { z } from 'zod'
9
5
  import {
@@ -12,6 +8,7 @@ import {
12
8
  type HotspotDisposition,
13
9
  type HotspotFetch,
14
10
  } from './sonar-hotspots'
11
+ import { sonar_project } from './sonar-project'
15
12
 
16
13
  // `josh sonar:hotspots <PR>` — fetch the SonarCloud hotspots on a pull request and print the Step B
17
14
  // disposition of each (joshuafolkken/kit#2182).
@@ -24,11 +21,7 @@ import {
24
21
 
25
22
  const ARGV_OFFSET = 2
26
23
  const USAGE = 'Usage: josh sonar:hotspots <PR>'
27
- const SONAR_HOST = 'https://sonarcloud.io'
28
24
  const HOTSPOTS_PATH = '/api/hotspots/search'
29
- const PROPERTIES_FILE = 'sonar-project.properties'
30
- const PROJECT_KEY_PREFIX = 'sonar.projectKey='
31
- const FETCH_TIMEOUT_MS = 10_000
32
25
  const FAILURE_EXIT_CODE = 1
33
26
  const UNKNOWN_LINE = '?'
34
27
 
@@ -44,34 +37,17 @@ const hotspot_schema = z.looseObject({
44
37
  })
45
38
  const response_schema = z.looseObject({ hotspots: z.array(hotspot_schema).optional() })
46
39
 
47
- function read_project_key(root: string): string | undefined {
48
- const file = path.join(root, PROPERTIES_FILE)
49
- if (!existsSync(file)) return undefined
50
-
51
- const line = readFileSync(file, 'utf8')
52
- .split('\n')
53
- .find((entry) => entry.startsWith(PROJECT_KEY_PREFIX))
54
-
55
- return line?.slice(PROJECT_KEY_PREFIX.length).trim()
56
- }
57
-
58
40
  function hotspots_url(project_key: string, pull_request: string): string {
59
- const query = new URLSearchParams({ projectKey: project_key, pullRequest: pull_request })
60
-
61
- return `${SONAR_HOST}${HOTSPOTS_PATH}?${query.toString()}`
41
+ return sonar_project.api_url(HOTSPOTS_PATH, {
42
+ projectKey: project_key,
43
+ pullRequest: pull_request,
44
+ })
62
45
  }
63
46
 
64
47
  async function fetch_hotspots(url: string): Promise<HotspotFetch> {
65
- try {
66
- const response = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) })
67
- if (!response.ok) return { error: `HTTP ${String(response.status)}` }
68
-
69
- const parsed = response_schema.parse(await response.json())
48
+ const read = await sonar_project.fetch_json(url, response_schema)
70
49
 
71
- return { hotspots: parsed.hotspots ?? [] }
72
- } catch (error) {
73
- return { error: error_text.message_of(error) }
74
- }
50
+ return 'error' in read ? read : { hotspots: read.data.hotspots ?? [] }
75
51
  }
76
52
 
77
53
  function is_managed(component: string): boolean {
@@ -108,23 +84,10 @@ async function fetch_and_print(project_key: string, pull_request: string): Promi
108
84
  }
109
85
 
110
86
  async function run(argv: ReadonlyArray<string>): Promise<number> {
111
- const [pull_request] = argv
112
-
113
- if (pull_request === undefined || pull_request.startsWith('-')) {
114
- console.error(USAGE)
115
-
116
- return FAILURE_EXIT_CODE
117
- }
118
-
119
- const project_key = read_project_key(await git_command.repository_root())
120
-
121
- if (project_key === undefined) {
122
- console.error(`no ${PROJECT_KEY_PREFIX} found in ${PROPERTIES_FILE}`)
123
-
124
- return FAILURE_EXIT_CODE
125
- }
87
+ const target = await sonar_project.resolve_target(argv, USAGE)
88
+ if (target === undefined) return FAILURE_EXIT_CODE
126
89
 
127
- await fetch_and_print(project_key, pull_request)
90
+ await fetch_and_print(target.project_key, target.pull_request)
128
91
 
129
92
  return 0
130
93
  }
@@ -136,12 +99,7 @@ async function main(argv: ReadonlyArray<string>): Promise<void> {
136
99
  const sonar_hotspots_cli = {
137
100
  fetch_hotspots,
138
101
  format_hotspot,
139
- hotspots_url,
140
- is_managed,
141
- main,
142
102
  print_disposition,
143
- read_project_key,
144
- run,
145
103
  USAGE,
146
104
  }
147
105
 
@@ -95,7 +95,6 @@ const sonar_hotspots = {
95
95
  classify_fetch,
96
96
  classify_hotspot,
97
97
  component_path,
98
- HOTSPOT_BRANCHES,
99
98
  UNREADABLE,
100
99
  }
101
100
 
@@ -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,
@@ -6,6 +6,7 @@ import { init_logic } from '#scripts/init/init-logic'
6
6
  import { PACKAGE_DIR, PROJECT_ROOT } from '#scripts/init/init-paths'
7
7
  import type { ProjectShape } from '#scripts/init/project-profile'
8
8
  import { file_reader } from '#scripts/lib/read-file'
9
+ import { pack_hook } from '#scripts/safe-chain/pack-hook'
9
10
  import { copy_directory_failure, directory_copy_blocker } from './directory-copy-guard'
10
11
  import { file_content } from './file-content'
11
12
  import { REMOVED_SKILL_MANIFEST } from './removed-skill-manifest'
@@ -189,6 +190,9 @@ function sync_ai_copy_all(is_force: boolean, shape?: ProjectShape): void {
189
190
  }
190
191
 
191
192
  migrate_removed_skills()
193
+ // Both profiles write the Safe Chain `preinstall`, so both get the hook that keeps it out of a
194
+ // published package (joshuafolkken/kit#3110).
195
+ pack_hook.sync_pack_hook(PROJECT_ROOT, PACKAGE_DIR)
192
196
  }
193
197
 
194
198
  const sync_ai_files = {
@@ -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