plumbbob 0.9.3 → 0.9.5

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 (278) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +15 -13
  3. package/dist/cli-core.js +19 -2
  4. package/dist/lib/check.js +46 -13
  5. package/dist/lib/intent.js +1 -1
  6. package/dist/lib/latch.js +3 -3
  7. package/dist/lib/reentry.js +70 -0
  8. package/dist/verbs/agent.js +2 -2
  9. package/dist/verbs/doctor.js +4 -4
  10. package/dist/verbs/finish.js +1 -1
  11. package/dist/verbs/recover.js +297 -0
  12. package/dist/verbs/revert.js +2 -2
  13. package/dist/verbs/spike.js +8 -2
  14. package/hooks/post-edit.sh +4 -4
  15. package/hooks/pre-bash-commit.sh +3 -3
  16. package/node_modules/checkride/.claude-plugin/plugin.json +11 -0
  17. package/node_modules/checkride/CHANGELOG.md +1003 -0
  18. package/node_modules/checkride/LICENSE +201 -21
  19. package/node_modules/checkride/README.md +171 -30
  20. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.d.ts +15 -0
  21. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.d.ts.map +1 -0
  22. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.js +17 -0
  23. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.js.map +1 -0
  24. package/node_modules/checkride/dist/adapters.d.ts +18 -6
  25. package/node_modules/checkride/dist/adapters.d.ts.map +1 -1
  26. package/node_modules/checkride/dist/adapters.js +42 -23
  27. package/node_modules/checkride/dist/adapters.js.map +1 -1
  28. package/node_modules/checkride/dist/agent-setup/claude.d.ts +88 -0
  29. package/node_modules/checkride/dist/agent-setup/claude.d.ts.map +1 -0
  30. package/node_modules/checkride/dist/agent-setup/claude.js +305 -0
  31. package/node_modules/checkride/dist/agent-setup/claude.js.map +1 -0
  32. package/node_modules/checkride/dist/agent-setup/command.d.ts +43 -0
  33. package/node_modules/checkride/dist/agent-setup/command.d.ts.map +1 -0
  34. package/node_modules/checkride/dist/agent-setup/command.js +77 -0
  35. package/node_modules/checkride/dist/agent-setup/command.js.map +1 -0
  36. package/node_modules/checkride/dist/agent-setup/cursor.d.ts +61 -0
  37. package/node_modules/checkride/dist/agent-setup/cursor.d.ts.map +1 -0
  38. package/node_modules/checkride/dist/agent-setup/cursor.js +189 -0
  39. package/node_modules/checkride/dist/agent-setup/cursor.js.map +1 -0
  40. package/node_modules/checkride/dist/agent-setup/files.d.ts +50 -0
  41. package/node_modules/checkride/dist/agent-setup/files.d.ts.map +1 -0
  42. package/node_modules/checkride/dist/agent-setup/files.js +80 -0
  43. package/node_modules/checkride/dist/agent-setup/files.js.map +1 -0
  44. package/node_modules/checkride/dist/agent-setup/harness.d.ts +101 -0
  45. package/node_modules/checkride/dist/agent-setup/harness.d.ts.map +1 -0
  46. package/node_modules/checkride/dist/agent-setup/harness.js +84 -0
  47. package/node_modules/checkride/dist/agent-setup/harness.js.map +1 -0
  48. package/node_modules/checkride/dist/agent-setup/hook.d.ts +45 -52
  49. package/node_modules/checkride/dist/agent-setup/hook.d.ts.map +1 -1
  50. package/node_modules/checkride/dist/agent-setup/hook.js +64 -95
  51. package/node_modules/checkride/dist/agent-setup/hook.js.map +1 -1
  52. package/node_modules/checkride/dist/agent-setup/index.d.ts +10 -4
  53. package/node_modules/checkride/dist/agent-setup/index.d.ts.map +1 -1
  54. package/node_modules/checkride/dist/agent-setup/index.js +9 -4
  55. package/node_modules/checkride/dist/agent-setup/index.js.map +1 -1
  56. package/node_modules/checkride/dist/agent-setup/scripts.d.ts +58 -0
  57. package/node_modules/checkride/dist/agent-setup/scripts.d.ts.map +1 -0
  58. package/node_modules/checkride/dist/agent-setup/scripts.js +299 -0
  59. package/node_modules/checkride/dist/agent-setup/scripts.js.map +1 -0
  60. package/node_modules/checkride/dist/agent-setup/skills.d.ts +31 -0
  61. package/node_modules/checkride/dist/agent-setup/skills.d.ts.map +1 -0
  62. package/node_modules/checkride/dist/agent-setup/skills.js +56 -0
  63. package/node_modules/checkride/dist/agent-setup/skills.js.map +1 -0
  64. package/node_modules/checkride/dist/artifacts/configured.d.ts +30 -0
  65. package/node_modules/checkride/dist/artifacts/configured.d.ts.map +1 -0
  66. package/node_modules/checkride/dist/artifacts/configured.js +45 -0
  67. package/node_modules/checkride/dist/artifacts/configured.js.map +1 -0
  68. package/node_modules/checkride/dist/artifacts/format.d.ts +33 -0
  69. package/node_modules/checkride/dist/artifacts/format.d.ts.map +1 -0
  70. package/node_modules/checkride/dist/artifacts/format.js +56 -0
  71. package/node_modules/checkride/dist/artifacts/format.js.map +1 -0
  72. package/node_modules/checkride/dist/artifacts/freshness.d.ts +32 -0
  73. package/node_modules/checkride/dist/artifacts/freshness.d.ts.map +1 -0
  74. package/node_modules/checkride/dist/artifacts/freshness.js +37 -0
  75. package/node_modules/checkride/dist/artifacts/freshness.js.map +1 -0
  76. package/node_modules/checkride/dist/artifacts/index.d.ts +22 -0
  77. package/node_modules/checkride/dist/artifacts/index.d.ts.map +1 -0
  78. package/node_modules/checkride/dist/artifacts/index.js +19 -0
  79. package/node_modules/checkride/dist/artifacts/index.js.map +1 -0
  80. package/node_modules/checkride/dist/artifacts/json.d.ts +31 -0
  81. package/node_modules/checkride/dist/artifacts/json.d.ts.map +1 -0
  82. package/node_modules/checkride/dist/artifacts/json.js +47 -0
  83. package/node_modules/checkride/dist/artifacts/json.js.map +1 -0
  84. package/node_modules/checkride/dist/artifacts/raw.d.ts +60 -0
  85. package/node_modules/checkride/dist/artifacts/raw.d.ts.map +1 -0
  86. package/node_modules/checkride/dist/artifacts/raw.js +91 -0
  87. package/node_modules/checkride/dist/artifacts/raw.js.map +1 -0
  88. package/node_modules/checkride/dist/artifacts/summary.d.ts +69 -0
  89. package/node_modules/checkride/dist/artifacts/summary.d.ts.map +1 -0
  90. package/node_modules/checkride/dist/artifacts/summary.js +108 -0
  91. package/node_modules/checkride/dist/artifacts/summary.js.map +1 -0
  92. package/node_modules/checkride/dist/atomic.d.ts +16 -1
  93. package/node_modules/checkride/dist/atomic.d.ts.map +1 -1
  94. package/node_modules/checkride/dist/atomic.js +25 -3
  95. package/node_modules/checkride/dist/atomic.js.map +1 -1
  96. package/node_modules/checkride/dist/baseline/fallow.d.ts +9 -5
  97. package/node_modules/checkride/dist/baseline/fallow.d.ts.map +1 -1
  98. package/node_modules/checkride/dist/baseline/fallow.js +161 -58
  99. package/node_modules/checkride/dist/baseline/fallow.js.map +1 -1
  100. package/node_modules/checkride/dist/baseline/fingerprint.d.ts +7 -7
  101. package/node_modules/checkride/dist/baseline/fingerprint.d.ts.map +1 -1
  102. package/node_modules/checkride/dist/baseline/fingerprint.js +16 -19
  103. package/node_modules/checkride/dist/baseline/fingerprint.js.map +1 -1
  104. package/node_modules/checkride/dist/baseline/index.d.ts +4 -4
  105. package/node_modules/checkride/dist/baseline/index.d.ts.map +1 -1
  106. package/node_modules/checkride/dist/baseline/index.js +4 -4
  107. package/node_modules/checkride/dist/baseline/index.js.map +1 -1
  108. package/node_modules/checkride/dist/baseline/store.d.ts +12 -4
  109. package/node_modules/checkride/dist/baseline/store.d.ts.map +1 -1
  110. package/node_modules/checkride/dist/baseline/store.js +16 -9
  111. package/node_modules/checkride/dist/baseline/store.js.map +1 -1
  112. package/node_modules/checkride/dist/baseline-command.d.ts +5 -5
  113. package/node_modules/checkride/dist/baseline-command.js +7 -7
  114. package/node_modules/checkride/dist/baseline-command.js.map +1 -1
  115. package/node_modules/checkride/dist/cli.d.ts +17 -4
  116. package/node_modules/checkride/dist/cli.d.ts.map +1 -1
  117. package/node_modules/checkride/dist/cli.js +259 -18
  118. package/node_modules/checkride/dist/cli.js.map +1 -1
  119. package/node_modules/checkride/dist/config.d.ts +84 -8
  120. package/node_modules/checkride/dist/config.d.ts.map +1 -1
  121. package/node_modules/checkride/dist/config.js +122 -18
  122. package/node_modules/checkride/dist/config.js.map +1 -1
  123. package/node_modules/checkride/dist/digest/digest.d.ts +5 -5
  124. package/node_modules/checkride/dist/digest/digest.js +5 -5
  125. package/node_modules/checkride/dist/digest/index.d.ts +2 -2
  126. package/node_modules/checkride/dist/digest/index.js +2 -2
  127. package/node_modules/checkride/dist/doctor.d.ts +25 -6
  128. package/node_modules/checkride/dist/doctor.d.ts.map +1 -1
  129. package/node_modules/checkride/dist/doctor.js +193 -27
  130. package/node_modules/checkride/dist/doctor.js.map +1 -1
  131. package/node_modules/checkride/dist/gate.d.ts +135 -0
  132. package/node_modules/checkride/dist/gate.d.ts.map +1 -0
  133. package/node_modules/checkride/dist/gate.js +490 -0
  134. package/node_modules/checkride/dist/gate.js.map +1 -0
  135. package/node_modules/checkride/dist/init.d.ts +72 -12
  136. package/node_modules/checkride/dist/init.d.ts.map +1 -1
  137. package/node_modules/checkride/dist/init.js +324 -81
  138. package/node_modules/checkride/dist/init.js.map +1 -1
  139. package/node_modules/checkride/dist/json.d.ts +21 -0
  140. package/node_modules/checkride/dist/json.d.ts.map +1 -0
  141. package/node_modules/checkride/dist/json.js +21 -0
  142. package/node_modules/checkride/dist/json.js.map +1 -0
  143. package/node_modules/checkride/dist/links.d.ts +31 -5
  144. package/node_modules/checkride/dist/links.d.ts.map +1 -1
  145. package/node_modules/checkride/dist/links.js +141 -32
  146. package/node_modules/checkride/dist/links.js.map +1 -1
  147. package/node_modules/checkride/dist/node-pin.d.ts +129 -0
  148. package/node_modules/checkride/dist/node-pin.d.ts.map +1 -0
  149. package/node_modules/checkride/dist/node-pin.js +211 -0
  150. package/node_modules/checkride/dist/node-pin.js.map +1 -0
  151. package/node_modules/checkride/dist/orchestrator.d.ts +40 -10
  152. package/node_modules/checkride/dist/orchestrator.d.ts.map +1 -1
  153. package/node_modules/checkride/dist/orchestrator.js +196 -102
  154. package/node_modules/checkride/dist/orchestrator.js.map +1 -1
  155. package/node_modules/checkride/dist/pack.d.ts +8 -9
  156. package/node_modules/checkride/dist/pack.d.ts.map +1 -1
  157. package/node_modules/checkride/dist/pack.js +53 -17
  158. package/node_modules/checkride/dist/pack.js.map +1 -1
  159. package/node_modules/checkride/dist/pm/detect.d.ts +6 -1
  160. package/node_modules/checkride/dist/pm/detect.d.ts.map +1 -1
  161. package/node_modules/checkride/dist/pm/detect.js +6 -1
  162. package/node_modules/checkride/dist/pm/detect.js.map +1 -1
  163. package/node_modules/checkride/dist/pm/index.d.ts +6 -2
  164. package/node_modules/checkride/dist/pm/index.d.ts.map +1 -1
  165. package/node_modules/checkride/dist/pm/index.js +6 -2
  166. package/node_modules/checkride/dist/pm/index.js.map +1 -1
  167. package/node_modules/checkride/dist/pm/launch.d.ts +51 -0
  168. package/node_modules/checkride/dist/pm/launch.d.ts.map +1 -0
  169. package/node_modules/checkride/dist/pm/launch.js +92 -0
  170. package/node_modules/checkride/dist/pm/launch.js.map +1 -0
  171. package/node_modules/checkride/dist/pm/tools.d.ts +73 -0
  172. package/node_modules/checkride/dist/pm/tools.d.ts.map +1 -0
  173. package/node_modules/checkride/dist/pm/tools.js +124 -0
  174. package/node_modules/checkride/dist/pm/tools.js.map +1 -0
  175. package/node_modules/checkride/dist/pm/translate.d.ts +35 -9
  176. package/node_modules/checkride/dist/pm/translate.d.ts.map +1 -1
  177. package/node_modules/checkride/dist/pm/translate.js +78 -18
  178. package/node_modules/checkride/dist/pm/translate.js.map +1 -1
  179. package/node_modules/checkride/dist/proc.d.ts +30 -0
  180. package/node_modules/checkride/dist/proc.d.ts.map +1 -0
  181. package/node_modules/checkride/dist/proc.js +42 -0
  182. package/node_modules/checkride/dist/proc.js.map +1 -0
  183. package/node_modules/checkride/dist/qa/cli.d.ts +20 -0
  184. package/node_modules/checkride/dist/qa/cli.d.ts.map +1 -0
  185. package/node_modules/checkride/dist/qa/cli.js +24 -0
  186. package/node_modules/checkride/dist/qa/cli.js.map +1 -0
  187. package/node_modules/checkride/dist/qa/dead.d.ts +39 -0
  188. package/node_modules/checkride/dist/qa/dead.d.ts.map +1 -0
  189. package/node_modules/checkride/dist/qa/dead.js +88 -0
  190. package/node_modules/checkride/dist/qa/dead.js.map +1 -0
  191. package/node_modules/checkride/dist/qa/dupes.d.ts +45 -0
  192. package/node_modules/checkride/dist/qa/dupes.d.ts.map +1 -0
  193. package/node_modules/checkride/dist/qa/dupes.js +62 -0
  194. package/node_modules/checkride/dist/qa/dupes.js.map +1 -0
  195. package/node_modules/checkride/dist/qa/health.d.ts +85 -0
  196. package/node_modules/checkride/dist/qa/health.d.ts.map +1 -0
  197. package/node_modules/checkride/dist/qa/health.js +109 -0
  198. package/node_modules/checkride/dist/qa/health.js.map +1 -0
  199. package/node_modules/checkride/dist/qa/index.d.ts +23 -0
  200. package/node_modules/checkride/dist/qa/index.d.ts.map +1 -0
  201. package/node_modules/checkride/dist/qa/index.js +22 -0
  202. package/node_modules/checkride/dist/qa/index.js.map +1 -0
  203. package/node_modules/checkride/dist/qa/mutation.d.ts +80 -0
  204. package/node_modules/checkride/dist/qa/mutation.d.ts.map +1 -0
  205. package/node_modules/checkride/dist/qa/mutation.js +195 -0
  206. package/node_modules/checkride/dist/qa/mutation.js.map +1 -0
  207. package/node_modules/checkride/dist/qa/qa.d.ts +71 -0
  208. package/node_modules/checkride/dist/qa/qa.d.ts.map +1 -0
  209. package/node_modules/checkride/dist/qa/qa.js +158 -0
  210. package/node_modules/checkride/dist/qa/qa.js.map +1 -0
  211. package/node_modules/checkride/dist/qa/read.d.ts +40 -0
  212. package/node_modules/checkride/dist/qa/read.d.ts.map +1 -0
  213. package/node_modules/checkride/dist/qa/read.js +47 -0
  214. package/node_modules/checkride/dist/qa/read.js.map +1 -0
  215. package/node_modules/checkride/dist/qa/render.d.ts +26 -0
  216. package/node_modules/checkride/dist/qa/render.d.ts.map +1 -0
  217. package/node_modules/checkride/dist/qa/render.js +310 -0
  218. package/node_modules/checkride/dist/qa/render.js.map +1 -0
  219. package/node_modules/checkride/dist/security.d.ts +45 -0
  220. package/node_modules/checkride/dist/security.d.ts.map +1 -0
  221. package/node_modules/checkride/dist/security.js +86 -0
  222. package/node_modules/checkride/dist/security.js.map +1 -0
  223. package/node_modules/checkride/dist/smoke.d.ts +5 -5
  224. package/node_modules/checkride/dist/smoke.js +5 -5
  225. package/node_modules/checkride/dist/snippets.d.ts +26 -29
  226. package/node_modules/checkride/dist/snippets.d.ts.map +1 -1
  227. package/node_modules/checkride/dist/snippets.js +26 -30
  228. package/node_modules/checkride/dist/snippets.js.map +1 -1
  229. package/node_modules/checkride/dist/tool-json.d.ts +33 -0
  230. package/node_modules/checkride/dist/tool-json.d.ts.map +1 -0
  231. package/node_modules/checkride/dist/tool-json.js +58 -0
  232. package/node_modules/checkride/dist/tool-json.js.map +1 -0
  233. package/node_modules/checkride/dist/triage/cli.d.ts +21 -0
  234. package/node_modules/checkride/dist/triage/cli.d.ts.map +1 -0
  235. package/node_modules/checkride/dist/triage/cli.js +26 -0
  236. package/node_modules/checkride/dist/triage/cli.js.map +1 -0
  237. package/node_modules/checkride/dist/triage/doctor-fold.d.ts +51 -0
  238. package/node_modules/checkride/dist/triage/doctor-fold.d.ts.map +1 -0
  239. package/node_modules/checkride/dist/triage/doctor-fold.js +88 -0
  240. package/node_modules/checkride/dist/triage/doctor-fold.js.map +1 -0
  241. package/node_modules/checkride/dist/triage/env.d.ts +54 -0
  242. package/node_modules/checkride/dist/triage/env.d.ts.map +1 -0
  243. package/node_modules/checkride/dist/triage/env.js +81 -0
  244. package/node_modules/checkride/dist/triage/env.js.map +1 -0
  245. package/node_modules/checkride/dist/triage/gate.d.ts +61 -0
  246. package/node_modules/checkride/dist/triage/gate.d.ts.map +1 -0
  247. package/node_modules/checkride/dist/triage/gate.js +121 -0
  248. package/node_modules/checkride/dist/triage/gate.js.map +1 -0
  249. package/node_modules/checkride/dist/triage/index.d.ts +22 -0
  250. package/node_modules/checkride/dist/triage/index.d.ts.map +1 -0
  251. package/node_modules/checkride/dist/triage/index.js +20 -0
  252. package/node_modules/checkride/dist/triage/index.js.map +1 -0
  253. package/node_modules/checkride/dist/triage/render.d.ts +19 -0
  254. package/node_modules/checkride/dist/triage/render.d.ts.map +1 -0
  255. package/node_modules/checkride/dist/triage/render.js +419 -0
  256. package/node_modules/checkride/dist/triage/render.js.map +1 -0
  257. package/node_modules/checkride/dist/triage/triage.d.ts +83 -0
  258. package/node_modules/checkride/dist/triage/triage.d.ts.map +1 -0
  259. package/node_modules/checkride/dist/triage/triage.js +131 -0
  260. package/node_modules/checkride/dist/triage/triage.js.map +1 -0
  261. package/node_modules/checkride/package.json +17 -15
  262. package/node_modules/checkride/schema/checkride.config.schema.json +62 -5
  263. package/node_modules/checkride/schema/checkride.summary.schema.json +1 -1
  264. package/node_modules/checkride/skills/check/SKILL.md +257 -0
  265. package/node_modules/checkride/skills/qa/SKILL.md +231 -0
  266. package/node_modules/checkride/templates/shared/cspell.json +1 -0
  267. package/node_modules/checkride/templates/shared/oxlintrc.json +1 -1
  268. package/package.json +2 -2
  269. package/skills/build/SKILL.md +23 -19
  270. package/skills/finish/SKILL.md +3 -1
  271. package/skills/harvest/SKILL.md +2 -1
  272. package/skills/plan/SKILL.md +8 -7
  273. package/skills/recover/SKILL.md +28 -0
  274. package/skills/refine/SKILL.md +5 -4
  275. package/skills/spike/SKILL.md +1 -1
  276. package/skills/step/SKILL.md +4 -4
  277. package/skills/verify/SKILL.md +19 -14
  278. package/templates/intent.md +8 -7
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Slot-tool resolution — where a check's tool has to be for the gate to run it,
3
+ * and how to install it when it isn't.
4
+ *
5
+ * `translate.ts` decides *how* a tool is spawned; this decides *whether it may
6
+ * be*. The two are deliberately separate. `--no-install` bounds the download
7
+ * but not the launcher's per-user cache, so the spawn alone cannot promise the
8
+ * tool came from this repo: a copy an unrelated `npx` left behind months ago
9
+ * satisfies the launcher just as well as a declared dependency. Resolving the
10
+ * binary in the local tree first is what makes a slot's verdict depend on the
11
+ * committed lockfile rather than on one machine's accumulated cache — the
12
+ * property that lets a green run mean the same thing locally and in CI.
13
+ */
14
+ import { existsSync } from 'node:fs';
15
+ import { dirname, join } from 'node:path';
16
+ import { LOCKFILE_NAMES } from './detect.js';
17
+ /**
18
+ * The `<tool>` in a canonical `pnpm exec <tool> …` adapter invocation, or `null`
19
+ * for anything else — `pnpm audit`, `pnpm run <script>`, a built-in, or a config
20
+ * custom check's own command. Those either have no tool to resolve or resolve it
21
+ * themselves, so they are never pre-flighted.
22
+ *
23
+ * This is the same prefix test {@link translateExec} keys on, named once so the
24
+ * run path, the fix path and `doctor` cannot drift on what counts as a tool.
25
+ */
26
+ export function execTool(command, args) {
27
+ if (command !== 'pnpm' || args[0] !== 'exec')
28
+ return null;
29
+ return args[1] ?? null;
30
+ }
31
+ /**
32
+ * How each PM installs a tool as a dev dependency — the remediation a missing
33
+ * tool points at. `bun` spells the flag `-d`; the rest take `-D`.
34
+ */
35
+ const INSTALL = {
36
+ pnpm: 'pnpm add -D',
37
+ npm: 'npm install -D',
38
+ yarn: 'yarn add -D',
39
+ bun: 'bun add -d',
40
+ };
41
+ /** The command that would declare `tool` as a dev dependency under `pm`. */
42
+ export function installCommand(pm, tool) {
43
+ return `${INSTALL[pm]} ${tool}`;
44
+ }
45
+ /**
46
+ * What marks the top of a repository: its VCS directory, or a lockfile. `.git`
47
+ * is a file rather than a directory inside a worktree, which `existsSync`
48
+ * answers the same either way.
49
+ */
50
+ const ROOT_MARKERS = ['.git', ...LOCKFILE_NAMES];
51
+ /** Is `dir` the top of a repository — the last directory a tool search may look in? */
52
+ function isRepoRoot(dir, exists) {
53
+ return ROOT_MARKERS.some((m) => exists(join(dir, m)));
54
+ }
55
+ /**
56
+ * Find `tool`'s binary in the local tree, walking `cwd` upward the way the
57
+ * package managers themselves do — and stopping at the repo root.
58
+ *
59
+ * The walk is what makes this correct in a workspace: pnpm and npm both hoist a
60
+ * shared tool's bin to the workspace root, so a check running in
61
+ * `packages/web` finds it two directories up and a root-only check finds it
62
+ * immediately. Checking `cwd` alone would report every hoisted tool missing in
63
+ * every monorepo — which is most of the repos with a workspace preset.
64
+ *
65
+ * The boundary matters as much as the walk. An unbounded search would accept a
66
+ * `node_modules/.bin/<tool>` sitting in some parent of the checkout — a stray
67
+ * install in a home or projects directory — and that is the same defect as
68
+ * trusting the launcher cache, reached by a different route: the slot passes for
69
+ * whoever happens to have that directory above their clone and fails on the
70
+ * clean checkout. Stopping at the root keeps the verdict a property of the repo.
71
+ * The root itself is searched before the walk ends; a tree with no marker at all
72
+ * (a synthetic one, or a directory outside any repo) walks to the filesystem
73
+ * root as before.
74
+ *
75
+ * `exists` is injected so the walk is testable against a synthetic tree.
76
+ */
77
+ export function resolveSlotTool(cwd, tool, exists = existsSync) {
78
+ let dir = cwd;
79
+ for (;;) {
80
+ const bin = join(dir, 'node_modules', '.bin', tool);
81
+ if (exists(bin))
82
+ return bin;
83
+ if (isRepoRoot(dir, exists))
84
+ return null;
85
+ const parent = dirname(dir);
86
+ if (parent === dir)
87
+ return null;
88
+ dir = parent;
89
+ }
90
+ }
91
+ /**
92
+ * The artifacts a Yarn Plug'n'Play install writes in place of `node_modules/`.
93
+ * `.pnp.cjs` is the current name, `.pnp.js` the Yarn 2 one; `.pnp.data.json`
94
+ * rides alongside the loader when the manifest is split out.
95
+ */
96
+ const PNP_FILES = ['.pnp.cjs', '.pnp.js', '.pnp.data.json'];
97
+ /**
98
+ * Whether this project is installed under Yarn PnP, where there is no
99
+ * `node_modules/` tree at all.
100
+ *
101
+ * Every path-based test for "is it installed" is wrong here: a healthy PnP repo
102
+ * has no `node_modules/` and no `node_modules/.bin/<tool>`, so asserting either
103
+ * reports a correctly installed project as broken. Callers use this to pick a
104
+ * different question — the install artifact rather than the directory, and the
105
+ * package manager's own resolution rather than a path — instead of guessing.
106
+ */
107
+ export function isPnPInstall(cwd, exists = existsSync) {
108
+ return PNP_FILES.some((f) => exists(join(cwd, f)));
109
+ }
110
+ /**
111
+ * Whether `pm`'s exec launcher can supply a tool this repo never declared.
112
+ *
113
+ * True for exactly the two launchers that keep a per-user package cache: `npx`
114
+ * and `bunx` will run a cached copy even under `--no-install`. `pnpm exec` and
115
+ * `yarn` resolve from the project tree only, so they already give the stronger
116
+ * guarantee and need no pre-flight — and Yarn PnP has no `node_modules/.bin`
117
+ * to resolve against at all, so pre-flighting it would report every tool
118
+ * missing. Kept in lockstep with `translate.ts`'s `EXEC` table by a test: any
119
+ * PM carrying `--no-install` must be listed here.
120
+ */
121
+ export function execUsesGlobalCache(pm) {
122
+ return pm === 'npm' || pm === 'bun';
123
+ }
124
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/pm/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAG1C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;;;;;GAQG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAe,EAAE,IAAuB;IAC/D,IAAI,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAC1D,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,GAAmC;IAC9C,IAAI,EAAE,aAAa;IACnB,GAAG,EAAE,gBAAgB;IACrB,IAAI,EAAE,aAAa;IACnB,GAAG,EAAE,YAAY;CAClB,CAAC;AAEF,4EAA4E;AAC5E,MAAM,UAAU,cAAc,CAAC,EAAkB,EAAE,IAAY;IAC7D,OAAO,GAAG,OAAO,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,YAAY,GAAsB,CAAC,MAAM,EAAE,GAAG,cAAc,CAAC,CAAC;AAEpE,uFAAuF;AACvF,SAAS,UAAU,CAAC,GAAW,EAAE,MAA8B;IAC7D,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW,EAAE,IAAY,EAAE,SAAiC,UAAU;IACpG,IAAI,GAAG,GAAG,GAAG,CAAC;IACd,SAAS,CAAC;QACR,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QACpD,IAAI,MAAM,CAAC,GAAG,CAAC;YAAE,OAAO,GAAG,CAAC;QAC5B,IAAI,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QAChC,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,SAAS,GAAG,CAAC,UAAU,EAAE,SAAS,EAAE,gBAAgB,CAAU,CAAC;AAErE;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,SAAiC,UAAU;IACnF,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAkB;IACpD,OAAO,EAAE,KAAK,KAAK,IAAI,EAAE,KAAK,KAAK,CAAC;AACtC,CAAC"}
@@ -2,11 +2,11 @@
2
2
  * Exec-prefix translation.
3
3
  *
4
4
  * The adapter registry keeps its canonical `pnpm exec <tool>` / `pnpm run
5
- * <script>` form (D5/D13); this is the single seam that rewrites that prefix for
5
+ * <script>` form; this is the single seam that rewrites that prefix for
6
6
  * whichever package manager a repo actually uses. Only the `pnpm exec` and `pnpm
7
7
  * run` prefixes are translated — `pnpm audit`, custom-check commands, and
8
- * built-ins pass through untouched, so the default pnpm run is byte-identical to
9
- * before.
8
+ * built-ins pass through untouched. Under pnpm itself the prefix is unchanged
9
+ * and only {@link VERIFY_DEPS_OFF} is prepended.
10
10
  */
11
11
  import type { PackageManager } from './detect.js';
12
12
  /**
@@ -15,21 +15,47 @@ import type { PackageManager } from './detect.js';
15
15
  * check's own command, a built-in) is returned unchanged, and so is every
16
16
  * invocation under `pnpm` itself — the default stays exactly as it was.
17
17
  *
18
- * `exec` swaps the launcher and drops the keyword (`pnpm exec oxlint` → `npx
19
- * oxlint`); `run` keeps its keyword and only swaps the launcher, since all four
20
- * package managers spell it `<pm> run <script>` (`pnpm run build` → `npm run
21
- * build`).
18
+ * `exec` swaps the launcher, drops the keyword, and prepends the launcher's own
19
+ * flags (`pnpm exec oxlint` → `npx --no-install oxlint`); `run` keeps its
20
+ * keyword and only swaps the launcher, since all four package managers spell it
21
+ * `<pm> run <script>` (`pnpm run build` → `npm run build`). Under pnpm the
22
+ * invocation is unchanged but for `VERIFY_DEPS_OFF`, which keeps pnpm's
23
+ * dependency-check narration off the tool's stdout.
22
24
  */
23
25
  export declare function translateExec(command: string, args: readonly string[], pm: PackageManager): {
24
26
  command: string;
25
27
  args: string[];
26
28
  };
29
+ /**
30
+ * How `pm` invokes a package.json script, as a command line.
31
+ *
32
+ * Bare `pnpm <script>` is pnpm's own shorthand and the form checkride's docs
33
+ * use; the other three need the `run` keyword, and not merely for tidiness —
34
+ * `npm check` is not a command at all, and `yarn check` resolves to Yarn 1's
35
+ * built-in integrity checker rather than the repo's script, so both fail in a
36
+ * way that looks like checkride is broken. `<pm> run <script>` is correct
37
+ * everywhere, which is why it is the fallback for all of them.
38
+ */
39
+ export declare function runScript(pm: PackageManager, script: string): string;
40
+ /**
41
+ * A canonical `pnpm exec <tool> …` rendered as one command line for `pm`.
42
+ *
43
+ * `quiet` decides whether {@link VERIFY_DEPS_OFF} survives into the rendered
44
+ * string, and the two callers want opposite answers. A generated script whose
45
+ * stdout checkride parses needs it, or pnpm's narration lands in front of the
46
+ * JSON. Prose — the AGENTS.md stanza, a doc — does not: nothing parses that
47
+ * output, and a documented command carrying
48
+ * `--config.verify-deps-before-run=false` is a line nobody wants to retype.
49
+ */
50
+ export declare function execCommand(pm: PackageManager, args: readonly string[], opts?: {
51
+ quiet?: boolean;
52
+ }): string;
27
53
  /**
28
54
  * Can this adapter run under `pm`? Audit is package-manager-specific — its
29
55
  * flags and JSON shape don't port — so `pnpm audit` (the `security` slot) is
30
- * unavailable on a non-pnpm PM until a per-PM audit adapter lands (b5). The
56
+ * unavailable on a non-pnpm PM until a per-PM audit adapter lands. The
31
57
  * `pack` slot's built-in speaks only npm's and pnpm's `pack --dry-run --json`
32
- * (yarn/bun pack differently) — unavailable-until-adapter, same precedent (D10).
58
+ * (yarn/bun pack differently) — unavailable-until-adapter, same precedent.
33
59
  * Everything else is PM-agnostic once its exec prefix is translated.
34
60
  */
35
61
  export declare function isAvailableUnder(command: string, args: readonly string[], pm: PackageManager): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../src/pm/translate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AASlD;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,EAAE,cAAc,GACjB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAOrC;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,cAAc,GAAG,OAAO,CAItG"}
1
+ {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../src/pm/translate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AA6BlD;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,EAAE,cAAc,GACjB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAQrC;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAI/G;AAYD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,cAAc,GAAG,OAAO,CAItG"}
@@ -2,46 +2,106 @@
2
2
  * Exec-prefix translation.
3
3
  *
4
4
  * The adapter registry keeps its canonical `pnpm exec <tool>` / `pnpm run
5
- * <script>` form (D5/D13); this is the single seam that rewrites that prefix for
5
+ * <script>` form; this is the single seam that rewrites that prefix for
6
6
  * whichever package manager a repo actually uses. Only the `pnpm exec` and `pnpm
7
7
  * run` prefixes are translated — `pnpm audit`, custom-check commands, and
8
- * built-ins pass through untouched, so the default pnpm run is byte-identical to
9
- * before.
10
- */
11
- /** The exec command each non-pnpm PM uses in place of `pnpm exec`. */
12
- const EXEC_COMMAND = {
13
- npm: 'npx',
14
- yarn: 'yarn',
15
- bun: 'bunx',
8
+ * built-ins pass through untouched. Under pnpm itself the prefix is unchanged
9
+ * and only {@link VERIFY_DEPS_OFF} is prepended.
10
+ */
11
+ /**
12
+ * What each non-pnpm PM uses in place of `pnpm exec`, and the flags that ride
13
+ * along. `--no-install` is load-bearing: `npx` and `bunx` otherwise fetch a
14
+ * missing tool from the registry and run it, and a check has no TTY to be
15
+ * prompted through — so the gate would silently execute an unpinned `latest`.
16
+ * It bounds the download, not every fallback: a copy already in the launcher's
17
+ * global cache still runs (see `docs/tools.md` §Package managers). `yarn`
18
+ * neither auto-installs nor accepts the flag.
19
+ */
20
+ const EXEC = {
21
+ npm: { command: 'npx', flags: ['--no-install'] },
22
+ yarn: { command: 'yarn', flags: [] },
23
+ bun: { command: 'bunx', flags: ['--no-install'] },
16
24
  };
25
+ /**
26
+ * Keeps pnpm's dependency-check narration (`Already up to date`) off **stdout**,
27
+ * where it would land in front of a tool's JSON and make it unparseable.
28
+ *
29
+ * This exact spelling, in this position, is the only form that works — not
30
+ * `--silent`, not the environment variable, and not after `exec`. Applied to
31
+ * every supported pnpm rather than version-gated. The full account, including
32
+ * the failure that found it, is in `docs/tools.md` §Launcher quirks; read it
33
+ * before touching this line.
34
+ */
35
+ const VERIFY_DEPS_OFF = '--config.verify-deps-before-run=false';
17
36
  /**
18
37
  * Rewrite a canonical `pnpm exec <tool> …` or `pnpm run <script>` invocation for
19
38
  * `pm`. Anything that is not one of those prefixes (a `pnpm audit`, a custom
20
39
  * check's own command, a built-in) is returned unchanged, and so is every
21
40
  * invocation under `pnpm` itself — the default stays exactly as it was.
22
41
  *
23
- * `exec` swaps the launcher and drops the keyword (`pnpm exec oxlint` → `npx
24
- * oxlint`); `run` keeps its keyword and only swaps the launcher, since all four
25
- * package managers spell it `<pm> run <script>` (`pnpm run build` → `npm run
26
- * build`).
42
+ * `exec` swaps the launcher, drops the keyword, and prepends the launcher's own
43
+ * flags (`pnpm exec oxlint` → `npx --no-install oxlint`); `run` keeps its
44
+ * keyword and only swaps the launcher, since all four package managers spell it
45
+ * `<pm> run <script>` (`pnpm run build` → `npm run build`). Under pnpm the
46
+ * invocation is unchanged but for `VERIFY_DEPS_OFF`, which keeps pnpm's
47
+ * dependency-check narration off the tool's stdout.
27
48
  */
28
49
  export function translateExec(command, args, pm) {
29
- if (command !== 'pnpm' || pm === 'pnpm')
50
+ if (command !== 'pnpm')
30
51
  return { command, args: [...args] };
31
- // Drop 'exec'; keep <tool> and its arguments, e.g. `npx oxlint --type-aware`.
52
+ if (pm === 'pnpm')
53
+ return { command, args: quieted(args) };
54
+ // Drop 'exec'; keep <tool> and its arguments, e.g. `npx --no-install oxlint --type-aware`.
32
55
  if (args[0] === 'exec')
33
- return { command: EXEC_COMMAND[pm], args: args.slice(1) };
56
+ return { command: EXEC[pm].command, args: [...EXEC[pm].flags, ...args.slice(1)] };
34
57
  // `<pm> run <script>` is universal; only the launcher changes.
35
58
  if (args[0] === 'run')
36
59
  return { command: pm, args: [...args] };
37
60
  return { command, args: [...args] };
38
61
  }
62
+ /**
63
+ * How `pm` invokes a package.json script, as a command line.
64
+ *
65
+ * Bare `pnpm <script>` is pnpm's own shorthand and the form checkride's docs
66
+ * use; the other three need the `run` keyword, and not merely for tidiness —
67
+ * `npm check` is not a command at all, and `yarn check` resolves to Yarn 1's
68
+ * built-in integrity checker rather than the repo's script, so both fail in a
69
+ * way that looks like checkride is broken. `<pm> run <script>` is correct
70
+ * everywhere, which is why it is the fallback for all of them.
71
+ */
72
+ export function runScript(pm, script) {
73
+ return pm === 'pnpm' ? `${pm} ${script}` : `${pm} run ${script}`;
74
+ }
75
+ /**
76
+ * A canonical `pnpm exec <tool> …` rendered as one command line for `pm`.
77
+ *
78
+ * `quiet` decides whether {@link VERIFY_DEPS_OFF} survives into the rendered
79
+ * string, and the two callers want opposite answers. A generated script whose
80
+ * stdout checkride parses needs it, or pnpm's narration lands in front of the
81
+ * JSON. Prose — the AGENTS.md stanza, a doc — does not: nothing parses that
82
+ * output, and a documented command carrying
83
+ * `--config.verify-deps-before-run=false` is a line nobody wants to retype.
84
+ */
85
+ export function execCommand(pm, args, opts = {}) {
86
+ const translated = translateExec('pnpm', ['exec', ...args], pm);
87
+ const rest = opts.quiet === true ? translated.args : translated.args.filter((a) => a !== VERIFY_DEPS_OFF);
88
+ return [translated.command, ...rest].join(' ');
89
+ }
90
+ /**
91
+ * Prepend `VERIFY_DEPS_OFF` to the two pnpm subcommands that verify first.
92
+ * `pnpm audit` and `pnpm pack` never do, so they are left exactly as written —
93
+ * the flag is added where it changes something, not everywhere it is harmless.
94
+ */
95
+ function quieted(args) {
96
+ const verifies = args[0] === 'exec' || args[0] === 'run';
97
+ return verifies ? [VERIFY_DEPS_OFF, ...args] : [...args];
98
+ }
39
99
  /**
40
100
  * Can this adapter run under `pm`? Audit is package-manager-specific — its
41
101
  * flags and JSON shape don't port — so `pnpm audit` (the `security` slot) is
42
- * unavailable on a non-pnpm PM until a per-PM audit adapter lands (b5). The
102
+ * unavailable on a non-pnpm PM until a per-PM audit adapter lands. The
43
103
  * `pack` slot's built-in speaks only npm's and pnpm's `pack --dry-run --json`
44
- * (yarn/bun pack differently) — unavailable-until-adapter, same precedent (D10).
104
+ * (yarn/bun pack differently) — unavailable-until-adapter, same precedent.
45
105
  * Everything else is PM-agnostic once its exec prefix is translated.
46
106
  */
47
107
  export function isAvailableUnder(command, args, pm) {
@@ -1 +1 @@
1
- {"version":3,"file":"translate.js","sourceRoot":"","sources":["../../src/pm/translate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,sEAAsE;AACtE,MAAM,YAAY,GAAoD;IACpE,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,MAAM;IACZ,GAAG,EAAE,MAAM;CACZ,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAC3B,OAAe,EACf,IAAuB,EACvB,EAAkB;IAElB,IAAI,OAAO,KAAK,MAAM,IAAI,EAAE,KAAK,MAAM;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;IAC7E,8EAA8E;IAC9E,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM;QAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAClF,+DAA+D;IAC/D,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK;QAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;IAC/D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;AACtC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe,EAAE,IAAuB,EAAE,EAAkB;IAC3F,IAAI,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO;QAAE,OAAO,EAAE,KAAK,MAAM,CAAC;IACpE,IAAI,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM;QAAE,OAAO,EAAE,KAAK,MAAM,IAAI,EAAE,KAAK,KAAK,CAAC;IACnF,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"translate.js","sourceRoot":"","sources":["../../src/pm/translate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Killing a spawned check, and everything it started.
3
+ *
4
+ * Every subprocess checkride spawns is `detached`, so it leads its own process
5
+ * group and a negated-pid signal reaches the whole tree — a wrapper's
6
+ * grandchildren included. That is the difference between a timed-out
7
+ * `sh -c 'slow-tool …'` leaving its real worker orphaned and alive, and taking
8
+ * the tree down with it.
9
+ *
10
+ * Both spawners need the same two-step escalation (SIGTERM, then SIGKILL after
11
+ * a grace), so it lives here rather than in either of them: the orchestrator's
12
+ * per-check timeout and fatal-signal reaping (`../orchestrator.ts`), and the
13
+ * triage reader's gate budget (`./triage/env.ts`).
14
+ */
15
+ /** Grace between SIGTERM and SIGKILL when a process group won't die politely. */
16
+ export declare const KILL_GRACE_SECONDS = 5;
17
+ /**
18
+ * Signal a spawned process's whole group. ESRCH is swallowed: the group racing
19
+ * to exit on its own before we signal is success, not an error (and `pid` is
20
+ * absent only when the spawn itself failed).
21
+ */
22
+ export declare function killGroup(pid: number | undefined, signal: NodeJS.Signals): void;
23
+ /**
24
+ * Ask a process group to stop, then insist. SIGTERM now; SIGKILL after
25
+ * {@link KILL_GRACE_SECONDS} if it is still there. Returns the escalation
26
+ * timer so the caller can clear it when the process closes first — a pending
27
+ * timer would otherwise hold the event loop open past the run.
28
+ */
29
+ export declare function killGroupEscalating(pid: number | undefined): ReturnType<typeof setTimeout>;
30
+ //# sourceMappingURL=proc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proc.d.ts","sourceRoot":"","sources":["../src/proc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,iFAAiF;AACjF,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAO/E;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAG1F"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Killing a spawned check, and everything it started.
3
+ *
4
+ * Every subprocess checkride spawns is `detached`, so it leads its own process
5
+ * group and a negated-pid signal reaches the whole tree — a wrapper's
6
+ * grandchildren included. That is the difference between a timed-out
7
+ * `sh -c 'slow-tool …'` leaving its real worker orphaned and alive, and taking
8
+ * the tree down with it.
9
+ *
10
+ * Both spawners need the same two-step escalation (SIGTERM, then SIGKILL after
11
+ * a grace), so it lives here rather than in either of them: the orchestrator's
12
+ * per-check timeout and fatal-signal reaping (`../orchestrator.ts`), and the
13
+ * triage reader's gate budget (`./triage/env.ts`).
14
+ */
15
+ /** Grace between SIGTERM and SIGKILL when a process group won't die politely. */
16
+ export const KILL_GRACE_SECONDS = 5;
17
+ /**
18
+ * Signal a spawned process's whole group. ESRCH is swallowed: the group racing
19
+ * to exit on its own before we signal is success, not an error (and `pid` is
20
+ * absent only when the spawn itself failed).
21
+ */
22
+ export function killGroup(pid, signal) {
23
+ if (pid === undefined)
24
+ return;
25
+ try {
26
+ process.kill(-pid, signal);
27
+ }
28
+ catch {
29
+ // Group already gone (raced with a clean exit) — nothing left to kill.
30
+ }
31
+ }
32
+ /**
33
+ * Ask a process group to stop, then insist. SIGTERM now; SIGKILL after
34
+ * {@link KILL_GRACE_SECONDS} if it is still there. Returns the escalation
35
+ * timer so the caller can clear it when the process closes first — a pending
36
+ * timer would otherwise hold the event loop open past the run.
37
+ */
38
+ export function killGroupEscalating(pid) {
39
+ killGroup(pid, 'SIGTERM');
40
+ return setTimeout(() => { killGroup(pid, 'SIGKILL'); }, KILL_GRACE_SECONDS * 1000);
41
+ }
42
+ //# sourceMappingURL=proc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proc.js","sourceRoot":"","sources":["../src/proc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,iFAAiF;AACjF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAEpC;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,GAAuB,EAAE,MAAsB;IACvE,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO;IAC9B,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,uEAAuE;IACzE,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAuB;IACzD,SAAS,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC1B,OAAO,UAAU,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC,CAAC;AACrF,CAAC"}
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Executable form of the quality reader — what the bundled `/checkride:qa`
4
+ * skill invokes:
5
+ *
6
+ * ```
7
+ * node <plugin-root>/dist/qa/cli.js [cwd]
8
+ * ```
9
+ *
10
+ * It ships in the package's existing `dist/`, so both the published tarball and
11
+ * an installed plugin cache already carry it and no consumer build step exists.
12
+ * It adds no CLI command, flag or config to checkride itself: `dist/cli.js`
13
+ * knows nothing about this file.
14
+ *
15
+ * Exit code 0 means *a report was rendered* — including one whose every
16
+ * artifact is missing, which is a legitimate answer about a repo and not a
17
+ * reader failure. Unlike the triage reader, this one spawns nothing at all.
18
+ */
19
+ export {};
20
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/qa/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;GAgBG"}
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Executable form of the quality reader — what the bundled `/checkride:qa`
4
+ * skill invokes:
5
+ *
6
+ * ```
7
+ * node <plugin-root>/dist/qa/cli.js [cwd]
8
+ * ```
9
+ *
10
+ * It ships in the package's existing `dist/`, so both the published tarball and
11
+ * an installed plugin cache already carry it and no consumer build step exists.
12
+ * It adds no CLI command, flag or config to checkride itself: `dist/cli.js`
13
+ * knows nothing about this file.
14
+ *
15
+ * Exit code 0 means *a report was rendered* — including one whose every
16
+ * artifact is missing, which is a legitimate answer about a repo and not a
17
+ * reader failure. Unlike the triage reader, this one spawns nothing at all.
18
+ */
19
+ import { qaExtract } from './qa.js';
20
+ import { renderQa } from './render.js';
21
+ const [, , cwdArg] = process.argv;
22
+ const report = await qaExtract(cwdArg ?? process.cwd());
23
+ process.stdout.write(`${renderQa(report)}\n`);
24
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/qa/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,CAAC,EAAE,AAAD,EAAG,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;AAClC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;AACxD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * `dead.json` — fallow's dead-code report, whose shape is ~35 top-level arrays
3
+ * of which almost all are empty almost always.
4
+ *
5
+ * That shape is the extraction problem: printing the report's own summary block
6
+ * means printing 35 zeroes to say "clean", and printing the arrays means
7
+ * printing whatever the biggest one holds. So the fold is "non-empty buckets
8
+ * only", discovered by iterating the arrays rather than matching a hand-kept
9
+ * list of category names — fallow adds categories in minor releases, and a
10
+ * reader with a fixed list would silently omit a new finding type.
11
+ *
12
+ * `total_issues` stays the authoritative count (it is what checkride gates on),
13
+ * and the buckets explain it. Each bucket carries a couple of sample labels so
14
+ * the finding has a location without the file being opened.
15
+ *
16
+ * The `../qa` barrel is this module's only public surface.
17
+ */
18
+ /** One non-empty finding category. */
19
+ export type DeadBucket = {
20
+ /** fallow's own key: `unused_exports`, `circular_dependencies`, … */
21
+ name: string;
22
+ count: number;
23
+ /** A few findings, labelled `path:symbol` where the shape allows. */
24
+ samples: string[];
25
+ };
26
+ export type DeadExtract = {
27
+ /** fallow's authoritative count — the number checkride gates the slot on. */
28
+ totalIssues: number | null;
29
+ entryPoints: number | null;
30
+ buckets: DeadBucket[];
31
+ omittedBuckets: number;
32
+ };
33
+ /**
34
+ * Fold a parsed `dead.json` into the report model, or `null` when it carries no
35
+ * issue count in either place fallow writes one — a report whose count cannot
36
+ * be read must not be summarized as clean.
37
+ */
38
+ export declare function extractDead(value: Record<string, unknown>): DeadExtract | null;
39
+ //# sourceMappingURL=dead.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dead.d.ts","sourceRoot":"","sources":["../../src/qa/dead.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,sCAAsC;AACtC,MAAM,MAAM,UAAU,GAAG;IACvB,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,6EAA6E;IAC7E,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAiDF;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,GAAG,IAAI,CAY9E"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * `dead.json` — fallow's dead-code report, whose shape is ~35 top-level arrays
3
+ * of which almost all are empty almost always.
4
+ *
5
+ * That shape is the extraction problem: printing the report's own summary block
6
+ * means printing 35 zeroes to say "clean", and printing the arrays means
7
+ * printing whatever the biggest one holds. So the fold is "non-empty buckets
8
+ * only", discovered by iterating the arrays rather than matching a hand-kept
9
+ * list of category names — fallow adds categories in minor releases, and a
10
+ * reader with a fixed list would silently omit a new finding type.
11
+ *
12
+ * `total_issues` stays the authoritative count (it is what checkride gates on),
13
+ * and the buckets explain it. Each bucket carries a couple of sample labels so
14
+ * the finding has a location without the file being opened.
15
+ *
16
+ * The `../qa` barrel is this module's only public surface.
17
+ */
18
+ import { asNumberOrNull, asRecord, asStringOrNull, isRecord } from '../artifacts/index.js';
19
+ /** Buckets listed; the rest are counted. */
20
+ const TOP_BUCKETS = 8;
21
+ /** Sample labels per bucket. */
22
+ const SAMPLES_PER_BUCKET = 3;
23
+ /**
24
+ * Arrays that are report metadata rather than findings. `next_steps` is
25
+ * fallow's advice list; it is not a finding and does not count toward
26
+ * `total_issues`.
27
+ */
28
+ const NON_FINDING_ARRAYS = new Set(['next_steps']);
29
+ /** Where a finding says it is, and what it says it is about. */
30
+ const FILE_FIELDS = ['path', 'file'];
31
+ const SYMBOL_FIELDS = ['export_name', 'name', 'dependency'];
32
+ /** The first of `fields` holding a non-empty string, or `''` when none does. */
33
+ function firstString(item, fields) {
34
+ for (const field of fields) {
35
+ const value = asStringOrNull(item[field]);
36
+ if (value !== null && value !== '')
37
+ return value;
38
+ }
39
+ return '';
40
+ }
41
+ /**
42
+ * A finding's display label: its file, plus whichever symbol field this
43
+ * category happens to use. Purely for reading — unlike the baseline's
44
+ * fingerprint it needs no stability across edits, so a finding with no symbol
45
+ * falls back to a line number rather than to a synthesized identity.
46
+ */
47
+ function label(item) {
48
+ if (!isRecord(item))
49
+ return '(unreadable finding)';
50
+ const file = firstString(item, FILE_FIELDS);
51
+ const symbol = firstString(item, SYMBOL_FIELDS);
52
+ const where = [file, symbol].filter(Boolean).join(':');
53
+ if (where === '')
54
+ return '(no location)';
55
+ if (symbol !== '')
56
+ return where;
57
+ const line = asNumberOrNull(item['line']);
58
+ return line === null ? where : `${where}:${line}`;
59
+ }
60
+ /** Every non-empty finding array, biggest first. */
61
+ function collectBuckets(value) {
62
+ const buckets = [];
63
+ for (const [name, entry] of Object.entries(value)) {
64
+ if (!Array.isArray(entry) || entry.length === 0 || NON_FINDING_ARRAYS.has(name))
65
+ continue;
66
+ buckets.push({ name, count: entry.length, samples: entry.slice(0, SAMPLES_PER_BUCKET).map(label) });
67
+ }
68
+ return buckets.toSorted((a, b) => b.count - a.count || a.name.localeCompare(b.name));
69
+ }
70
+ /**
71
+ * Fold a parsed `dead.json` into the report model, or `null` when it carries no
72
+ * issue count in either place fallow writes one — a report whose count cannot
73
+ * be read must not be summarized as clean.
74
+ */
75
+ export function extractDead(value) {
76
+ const summary = asRecord(value['summary']);
77
+ const totalIssues = asNumberOrNull(summary['total_issues']) ?? asNumberOrNull(value['total_issues']);
78
+ if (totalIssues === null)
79
+ return null;
80
+ const buckets = collectBuckets(value);
81
+ return {
82
+ totalIssues,
83
+ entryPoints: asNumberOrNull(asRecord(value['entry_points'])['total']),
84
+ buckets: buckets.slice(0, TOP_BUCKETS),
85
+ omittedBuckets: Math.max(0, buckets.length - TOP_BUCKETS),
86
+ };
87
+ }
88
+ //# sourceMappingURL=dead.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dead.js","sourceRoot":"","sources":["../../src/qa/dead.ts"],"names":[],"mappings":"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"}