plumbbob 0.9.3 → 0.10.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 (320) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +92 -89
  3. package/dist/cli-core.js +25 -8
  4. package/dist/cli.js +1 -1
  5. package/dist/lib/agents.js +26 -26
  6. package/dist/lib/buildlog.js +11 -11
  7. package/dist/lib/buildlogsync.js +8 -8
  8. package/dist/lib/check.js +55 -22
  9. package/dist/lib/commitbody.js +72 -0
  10. package/dist/lib/commitmsg.js +7 -7
  11. package/dist/lib/git.js +44 -15
  12. package/dist/lib/intent.js +21 -20
  13. package/dist/lib/latch.js +19 -19
  14. package/dist/lib/orient.js +36 -17
  15. package/dist/lib/reentry.js +70 -0
  16. package/dist/lib/settings.js +16 -16
  17. package/dist/lib/sidecar.js +54 -54
  18. package/dist/lib/templates.js +1 -1
  19. package/dist/verbs/agent.js +27 -27
  20. package/dist/verbs/build.js +9 -9
  21. package/dist/verbs/check.js +6 -6
  22. package/dist/verbs/checkpoint.js +48 -47
  23. package/dist/verbs/doctor.js +31 -30
  24. package/dist/verbs/finish.js +28 -41
  25. package/dist/verbs/handoff.js +9 -8
  26. package/dist/verbs/init.js +9 -9
  27. package/dist/verbs/park.js +3 -3
  28. package/dist/verbs/recover.js +297 -0
  29. package/dist/verbs/revert.js +13 -13
  30. package/dist/verbs/spike.js +25 -19
  31. package/dist/verbs/start.js +49 -19
  32. package/dist/verbs/status.js +8 -8
  33. package/dist/verbs/turn.js +16 -16
  34. package/dist/verbs/use.js +4 -4
  35. package/hooks/post-edit.sh +4 -4
  36. package/hooks/pre-bash-commit.sh +3 -3
  37. package/node_modules/checkride/.claude-plugin/plugin.json +11 -0
  38. package/node_modules/checkride/CHANGELOG.md +1404 -0
  39. package/node_modules/checkride/LICENSE +201 -21
  40. package/node_modules/checkride/README.md +197 -38
  41. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.d.ts +15 -0
  42. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.d.ts.map +1 -0
  43. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.js +17 -0
  44. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.js.map +1 -0
  45. package/node_modules/checkride/dist/adapters.d.ts +30 -10
  46. package/node_modules/checkride/dist/adapters.d.ts.map +1 -1
  47. package/node_modules/checkride/dist/adapters.js +62 -23
  48. package/node_modules/checkride/dist/adapters.js.map +1 -1
  49. package/node_modules/checkride/dist/agent-setup/claude.d.ts +88 -0
  50. package/node_modules/checkride/dist/agent-setup/claude.d.ts.map +1 -0
  51. package/node_modules/checkride/dist/agent-setup/claude.js +305 -0
  52. package/node_modules/checkride/dist/agent-setup/claude.js.map +1 -0
  53. package/node_modules/checkride/dist/agent-setup/command.d.ts +43 -0
  54. package/node_modules/checkride/dist/agent-setup/command.d.ts.map +1 -0
  55. package/node_modules/checkride/dist/agent-setup/command.js +77 -0
  56. package/node_modules/checkride/dist/agent-setup/command.js.map +1 -0
  57. package/node_modules/checkride/dist/agent-setup/cursor.d.ts +69 -0
  58. package/node_modules/checkride/dist/agent-setup/cursor.d.ts.map +1 -0
  59. package/node_modules/checkride/dist/agent-setup/cursor.js +247 -0
  60. package/node_modules/checkride/dist/agent-setup/cursor.js.map +1 -0
  61. package/node_modules/checkride/dist/agent-setup/files.d.ts +50 -0
  62. package/node_modules/checkride/dist/agent-setup/files.d.ts.map +1 -0
  63. package/node_modules/checkride/dist/agent-setup/files.js +80 -0
  64. package/node_modules/checkride/dist/agent-setup/files.js.map +1 -0
  65. package/node_modules/checkride/dist/agent-setup/harness.d.ts +101 -0
  66. package/node_modules/checkride/dist/agent-setup/harness.d.ts.map +1 -0
  67. package/node_modules/checkride/dist/agent-setup/harness.js +93 -0
  68. package/node_modules/checkride/dist/agent-setup/harness.js.map +1 -0
  69. package/node_modules/checkride/dist/agent-setup/hook.d.ts +45 -52
  70. package/node_modules/checkride/dist/agent-setup/hook.d.ts.map +1 -1
  71. package/node_modules/checkride/dist/agent-setup/hook.js +64 -95
  72. package/node_modules/checkride/dist/agent-setup/hook.js.map +1 -1
  73. package/node_modules/checkride/dist/agent-setup/index.d.ts +10 -4
  74. package/node_modules/checkride/dist/agent-setup/index.d.ts.map +1 -1
  75. package/node_modules/checkride/dist/agent-setup/index.js +9 -4
  76. package/node_modules/checkride/dist/agent-setup/index.js.map +1 -1
  77. package/node_modules/checkride/dist/agent-setup/scripts.d.ts +81 -0
  78. package/node_modules/checkride/dist/agent-setup/scripts.d.ts.map +1 -0
  79. package/node_modules/checkride/dist/agent-setup/scripts.js +604 -0
  80. package/node_modules/checkride/dist/agent-setup/scripts.js.map +1 -0
  81. package/node_modules/checkride/dist/agent-setup/skills.d.ts +31 -0
  82. package/node_modules/checkride/dist/agent-setup/skills.d.ts.map +1 -0
  83. package/node_modules/checkride/dist/agent-setup/skills.js +56 -0
  84. package/node_modules/checkride/dist/agent-setup/skills.js.map +1 -0
  85. package/node_modules/checkride/dist/artifacts/configured.d.ts +30 -0
  86. package/node_modules/checkride/dist/artifacts/configured.d.ts.map +1 -0
  87. package/node_modules/checkride/dist/artifacts/configured.js +45 -0
  88. package/node_modules/checkride/dist/artifacts/configured.js.map +1 -0
  89. package/node_modules/checkride/dist/artifacts/format.d.ts +33 -0
  90. package/node_modules/checkride/dist/artifacts/format.d.ts.map +1 -0
  91. package/node_modules/checkride/dist/artifacts/format.js +56 -0
  92. package/node_modules/checkride/dist/artifacts/format.js.map +1 -0
  93. package/node_modules/checkride/dist/artifacts/freshness.d.ts +32 -0
  94. package/node_modules/checkride/dist/artifacts/freshness.d.ts.map +1 -0
  95. package/node_modules/checkride/dist/artifacts/freshness.js +37 -0
  96. package/node_modules/checkride/dist/artifacts/freshness.js.map +1 -0
  97. package/node_modules/checkride/dist/artifacts/index.d.ts +22 -0
  98. package/node_modules/checkride/dist/artifacts/index.d.ts.map +1 -0
  99. package/node_modules/checkride/dist/artifacts/index.js +19 -0
  100. package/node_modules/checkride/dist/artifacts/index.js.map +1 -0
  101. package/node_modules/checkride/dist/artifacts/json.d.ts +31 -0
  102. package/node_modules/checkride/dist/artifacts/json.d.ts.map +1 -0
  103. package/node_modules/checkride/dist/artifacts/json.js +47 -0
  104. package/node_modules/checkride/dist/artifacts/json.js.map +1 -0
  105. package/node_modules/checkride/dist/artifacts/raw.d.ts +60 -0
  106. package/node_modules/checkride/dist/artifacts/raw.d.ts.map +1 -0
  107. package/node_modules/checkride/dist/artifacts/raw.js +91 -0
  108. package/node_modules/checkride/dist/artifacts/raw.js.map +1 -0
  109. package/node_modules/checkride/dist/artifacts/summary.d.ts +69 -0
  110. package/node_modules/checkride/dist/artifacts/summary.d.ts.map +1 -0
  111. package/node_modules/checkride/dist/artifacts/summary.js +108 -0
  112. package/node_modules/checkride/dist/artifacts/summary.js.map +1 -0
  113. package/node_modules/checkride/dist/atomic.d.ts +16 -1
  114. package/node_modules/checkride/dist/atomic.d.ts.map +1 -1
  115. package/node_modules/checkride/dist/atomic.js +25 -3
  116. package/node_modules/checkride/dist/atomic.js.map +1 -1
  117. package/node_modules/checkride/dist/baseline/fallow.d.ts +9 -5
  118. package/node_modules/checkride/dist/baseline/fallow.d.ts.map +1 -1
  119. package/node_modules/checkride/dist/baseline/fallow.js +163 -60
  120. package/node_modules/checkride/dist/baseline/fallow.js.map +1 -1
  121. package/node_modules/checkride/dist/baseline/fingerprint.d.ts +20 -11
  122. package/node_modules/checkride/dist/baseline/fingerprint.d.ts.map +1 -1
  123. package/node_modules/checkride/dist/baseline/fingerprint.js +73 -23
  124. package/node_modules/checkride/dist/baseline/fingerprint.js.map +1 -1
  125. package/node_modules/checkride/dist/baseline/history.d.ts +98 -0
  126. package/node_modules/checkride/dist/baseline/history.d.ts.map +1 -0
  127. package/node_modules/checkride/dist/baseline/history.js +232 -0
  128. package/node_modules/checkride/dist/baseline/history.js.map +1 -0
  129. package/node_modules/checkride/dist/baseline/index.d.ts +7 -5
  130. package/node_modules/checkride/dist/baseline/index.d.ts.map +1 -1
  131. package/node_modules/checkride/dist/baseline/index.js +5 -4
  132. package/node_modules/checkride/dist/baseline/index.js.map +1 -1
  133. package/node_modules/checkride/dist/baseline/store.d.ts +41 -10
  134. package/node_modules/checkride/dist/baseline/store.d.ts.map +1 -1
  135. package/node_modules/checkride/dist/baseline/store.js +65 -24
  136. package/node_modules/checkride/dist/baseline/store.js.map +1 -1
  137. package/node_modules/checkride/dist/baseline-command.d.ts +5 -5
  138. package/node_modules/checkride/dist/baseline-command.js +7 -7
  139. package/node_modules/checkride/dist/baseline-command.js.map +1 -1
  140. package/node_modules/checkride/dist/cli.d.ts +21 -4
  141. package/node_modules/checkride/dist/cli.d.ts.map +1 -1
  142. package/node_modules/checkride/dist/cli.js +350 -36
  143. package/node_modules/checkride/dist/cli.js.map +1 -1
  144. package/node_modules/checkride/dist/config.d.ts +114 -9
  145. package/node_modules/checkride/dist/config.d.ts.map +1 -1
  146. package/node_modules/checkride/dist/config.js +142 -23
  147. package/node_modules/checkride/dist/config.js.map +1 -1
  148. package/node_modules/checkride/dist/digest/digest.d.ts +5 -5
  149. package/node_modules/checkride/dist/digest/digest.js +6 -6
  150. package/node_modules/checkride/dist/digest/index.d.ts +2 -2
  151. package/node_modules/checkride/dist/digest/index.js +2 -2
  152. package/node_modules/checkride/dist/doctor.d.ts +27 -6
  153. package/node_modules/checkride/dist/doctor.d.ts.map +1 -1
  154. package/node_modules/checkride/dist/doctor.js +231 -27
  155. package/node_modules/checkride/dist/doctor.js.map +1 -1
  156. package/node_modules/checkride/dist/gate.d.ts +180 -0
  157. package/node_modules/checkride/dist/gate.d.ts.map +1 -0
  158. package/node_modules/checkride/dist/gate.js +617 -0
  159. package/node_modules/checkride/dist/gate.js.map +1 -0
  160. package/node_modules/checkride/dist/init.d.ts +79 -12
  161. package/node_modules/checkride/dist/init.d.ts.map +1 -1
  162. package/node_modules/checkride/dist/init.js +385 -81
  163. package/node_modules/checkride/dist/init.js.map +1 -1
  164. package/node_modules/checkride/dist/json.d.ts +21 -0
  165. package/node_modules/checkride/dist/json.d.ts.map +1 -0
  166. package/node_modules/checkride/dist/json.js +21 -0
  167. package/node_modules/checkride/dist/json.js.map +1 -0
  168. package/node_modules/checkride/dist/links.d.ts +31 -5
  169. package/node_modules/checkride/dist/links.d.ts.map +1 -1
  170. package/node_modules/checkride/dist/links.js +141 -32
  171. package/node_modules/checkride/dist/links.js.map +1 -1
  172. package/node_modules/checkride/dist/node-pin.d.ts +129 -0
  173. package/node_modules/checkride/dist/node-pin.d.ts.map +1 -0
  174. package/node_modules/checkride/dist/node-pin.js +211 -0
  175. package/node_modules/checkride/dist/node-pin.js.map +1 -0
  176. package/node_modules/checkride/dist/orchestrator.d.ts +53 -10
  177. package/node_modules/checkride/dist/orchestrator.d.ts.map +1 -1
  178. package/node_modules/checkride/dist/orchestrator.js +312 -113
  179. package/node_modules/checkride/dist/orchestrator.js.map +1 -1
  180. package/node_modules/checkride/dist/pack.d.ts +8 -9
  181. package/node_modules/checkride/dist/pack.d.ts.map +1 -1
  182. package/node_modules/checkride/dist/pack.js +53 -17
  183. package/node_modules/checkride/dist/pack.js.map +1 -1
  184. package/node_modules/checkride/dist/pm/detect.d.ts +6 -1
  185. package/node_modules/checkride/dist/pm/detect.d.ts.map +1 -1
  186. package/node_modules/checkride/dist/pm/detect.js +6 -1
  187. package/node_modules/checkride/dist/pm/detect.js.map +1 -1
  188. package/node_modules/checkride/dist/pm/index.d.ts +7 -2
  189. package/node_modules/checkride/dist/pm/index.d.ts.map +1 -1
  190. package/node_modules/checkride/dist/pm/index.js +6 -2
  191. package/node_modules/checkride/dist/pm/index.js.map +1 -1
  192. package/node_modules/checkride/dist/pm/launch.d.ts +72 -0
  193. package/node_modules/checkride/dist/pm/launch.d.ts.map +1 -0
  194. package/node_modules/checkride/dist/pm/launch.js +108 -0
  195. package/node_modules/checkride/dist/pm/launch.js.map +1 -0
  196. package/node_modules/checkride/dist/pm/tools.d.ts +73 -0
  197. package/node_modules/checkride/dist/pm/tools.d.ts.map +1 -0
  198. package/node_modules/checkride/dist/pm/tools.js +124 -0
  199. package/node_modules/checkride/dist/pm/tools.js.map +1 -0
  200. package/node_modules/checkride/dist/pm/translate.d.ts +35 -9
  201. package/node_modules/checkride/dist/pm/translate.d.ts.map +1 -1
  202. package/node_modules/checkride/dist/pm/translate.js +78 -18
  203. package/node_modules/checkride/dist/pm/translate.js.map +1 -1
  204. package/node_modules/checkride/dist/proc.d.ts +30 -0
  205. package/node_modules/checkride/dist/proc.d.ts.map +1 -0
  206. package/node_modules/checkride/dist/proc.js +42 -0
  207. package/node_modules/checkride/dist/proc.js.map +1 -0
  208. package/node_modules/checkride/dist/qa/cli.d.ts +20 -0
  209. package/node_modules/checkride/dist/qa/cli.d.ts.map +1 -0
  210. package/node_modules/checkride/dist/qa/cli.js +24 -0
  211. package/node_modules/checkride/dist/qa/cli.js.map +1 -0
  212. package/node_modules/checkride/dist/qa/dead.d.ts +39 -0
  213. package/node_modules/checkride/dist/qa/dead.d.ts.map +1 -0
  214. package/node_modules/checkride/dist/qa/dead.js +88 -0
  215. package/node_modules/checkride/dist/qa/dead.js.map +1 -0
  216. package/node_modules/checkride/dist/qa/dupes.d.ts +45 -0
  217. package/node_modules/checkride/dist/qa/dupes.d.ts.map +1 -0
  218. package/node_modules/checkride/dist/qa/dupes.js +62 -0
  219. package/node_modules/checkride/dist/qa/dupes.js.map +1 -0
  220. package/node_modules/checkride/dist/qa/health.d.ts +85 -0
  221. package/node_modules/checkride/dist/qa/health.d.ts.map +1 -0
  222. package/node_modules/checkride/dist/qa/health.js +109 -0
  223. package/node_modules/checkride/dist/qa/health.js.map +1 -0
  224. package/node_modules/checkride/dist/qa/index.d.ts +23 -0
  225. package/node_modules/checkride/dist/qa/index.d.ts.map +1 -0
  226. package/node_modules/checkride/dist/qa/index.js +22 -0
  227. package/node_modules/checkride/dist/qa/index.js.map +1 -0
  228. package/node_modules/checkride/dist/qa/mutation.d.ts +80 -0
  229. package/node_modules/checkride/dist/qa/mutation.d.ts.map +1 -0
  230. package/node_modules/checkride/dist/qa/mutation.js +195 -0
  231. package/node_modules/checkride/dist/qa/mutation.js.map +1 -0
  232. package/node_modules/checkride/dist/qa/qa.d.ts +71 -0
  233. package/node_modules/checkride/dist/qa/qa.d.ts.map +1 -0
  234. package/node_modules/checkride/dist/qa/qa.js +158 -0
  235. package/node_modules/checkride/dist/qa/qa.js.map +1 -0
  236. package/node_modules/checkride/dist/qa/read.d.ts +40 -0
  237. package/node_modules/checkride/dist/qa/read.d.ts.map +1 -0
  238. package/node_modules/checkride/dist/qa/read.js +47 -0
  239. package/node_modules/checkride/dist/qa/read.js.map +1 -0
  240. package/node_modules/checkride/dist/qa/render.d.ts +26 -0
  241. package/node_modules/checkride/dist/qa/render.d.ts.map +1 -0
  242. package/node_modules/checkride/dist/qa/render.js +310 -0
  243. package/node_modules/checkride/dist/qa/render.js.map +1 -0
  244. package/node_modules/checkride/dist/recover.d.ts +48 -0
  245. package/node_modules/checkride/dist/recover.d.ts.map +1 -0
  246. package/node_modules/checkride/dist/recover.js +220 -0
  247. package/node_modules/checkride/dist/recover.js.map +1 -0
  248. package/node_modules/checkride/dist/security.d.ts +45 -0
  249. package/node_modules/checkride/dist/security.d.ts.map +1 -0
  250. package/node_modules/checkride/dist/security.js +86 -0
  251. package/node_modules/checkride/dist/security.js.map +1 -0
  252. package/node_modules/checkride/dist/smoke.d.ts +6 -6
  253. package/node_modules/checkride/dist/smoke.js +6 -6
  254. package/node_modules/checkride/dist/snippets.d.ts +27 -30
  255. package/node_modules/checkride/dist/snippets.d.ts.map +1 -1
  256. package/node_modules/checkride/dist/snippets.js +26 -30
  257. package/node_modules/checkride/dist/snippets.js.map +1 -1
  258. package/node_modules/checkride/dist/tool-json.d.ts +33 -0
  259. package/node_modules/checkride/dist/tool-json.d.ts.map +1 -0
  260. package/node_modules/checkride/dist/tool-json.js +58 -0
  261. package/node_modules/checkride/dist/tool-json.js.map +1 -0
  262. package/node_modules/checkride/dist/triage/cli.d.ts +21 -0
  263. package/node_modules/checkride/dist/triage/cli.d.ts.map +1 -0
  264. package/node_modules/checkride/dist/triage/cli.js +26 -0
  265. package/node_modules/checkride/dist/triage/cli.js.map +1 -0
  266. package/node_modules/checkride/dist/triage/doctor-fold.d.ts +51 -0
  267. package/node_modules/checkride/dist/triage/doctor-fold.d.ts.map +1 -0
  268. package/node_modules/checkride/dist/triage/doctor-fold.js +88 -0
  269. package/node_modules/checkride/dist/triage/doctor-fold.js.map +1 -0
  270. package/node_modules/checkride/dist/triage/env.d.ts +54 -0
  271. package/node_modules/checkride/dist/triage/env.d.ts.map +1 -0
  272. package/node_modules/checkride/dist/triage/env.js +81 -0
  273. package/node_modules/checkride/dist/triage/env.js.map +1 -0
  274. package/node_modules/checkride/dist/triage/gate.d.ts +61 -0
  275. package/node_modules/checkride/dist/triage/gate.d.ts.map +1 -0
  276. package/node_modules/checkride/dist/triage/gate.js +121 -0
  277. package/node_modules/checkride/dist/triage/gate.js.map +1 -0
  278. package/node_modules/checkride/dist/triage/index.d.ts +22 -0
  279. package/node_modules/checkride/dist/triage/index.d.ts.map +1 -0
  280. package/node_modules/checkride/dist/triage/index.js +20 -0
  281. package/node_modules/checkride/dist/triage/index.js.map +1 -0
  282. package/node_modules/checkride/dist/triage/render.d.ts +19 -0
  283. package/node_modules/checkride/dist/triage/render.d.ts.map +1 -0
  284. package/node_modules/checkride/dist/triage/render.js +419 -0
  285. package/node_modules/checkride/dist/triage/render.js.map +1 -0
  286. package/node_modules/checkride/dist/triage/triage.d.ts +83 -0
  287. package/node_modules/checkride/dist/triage/triage.d.ts.map +1 -0
  288. package/node_modules/checkride/dist/triage/triage.js +131 -0
  289. package/node_modules/checkride/dist/triage/triage.js.map +1 -0
  290. package/node_modules/checkride/package.json +18 -15
  291. package/node_modules/checkride/schema/checkride.config.schema.json +70 -5
  292. package/node_modules/checkride/schema/checkride.summary.schema.json +1 -1
  293. package/node_modules/checkride/skills/check/SKILL.md +265 -0
  294. package/node_modules/checkride/skills/qa/SKILL.md +231 -0
  295. package/node_modules/checkride/templates/shared/cspell.json +1 -0
  296. package/node_modules/checkride/templates/shared/oxlintrc.json +1 -1
  297. package/node_modules/checkride/templates/shared/styles/Repo/Drift.yml +41 -0
  298. package/node_modules/checkride/templates/shared/styles/Repo/Latin.yml +14 -0
  299. package/node_modules/checkride/templates/shared/styles/Repo/LyHyphen.yml +28 -0
  300. package/node_modules/checkride/templates/shared/styles/Repo/Minted.yml +33 -0
  301. package/node_modules/checkride/templates/shared/styles/Repo/ThereIs.yml +16 -0
  302. package/node_modules/checkride/templates/shared/styles/Repo/Weasel.yml +26 -0
  303. package/node_modules/checkride/templates/shared/vale.ini +34 -0
  304. package/package.json +10 -9
  305. package/skills/build/SKILL.md +85 -76
  306. package/skills/doctor/SKILL.md +11 -11
  307. package/skills/finish/SKILL.md +21 -18
  308. package/skills/harvest/SKILL.md +13 -11
  309. package/skills/park/SKILL.md +10 -10
  310. package/skills/plan/SKILL.md +69 -59
  311. package/skills/recover/SKILL.md +28 -0
  312. package/skills/refine/SKILL.md +21 -18
  313. package/skills/revert/SKILL.md +6 -6
  314. package/skills/spike/SKILL.md +9 -9
  315. package/skills/status/SKILL.md +5 -5
  316. package/skills/step/SKILL.md +20 -15
  317. package/skills/verify/SKILL.md +56 -46
  318. package/templates/build-log.md +7 -7
  319. package/templates/intent.md +52 -41
  320. package/templates/spike-report.md +10 -10
@@ -0,0 +1,604 @@
1
+ /**
2
+ * The hook scripts checkride generates into a consumer repo.
3
+ *
4
+ * checkride owns these files and overwrites them on every `agent-setup`/`init`,
5
+ * so consumer customization belongs beside them, never in them. That is also why
6
+ * the settings entry each harness gets is a stable one-liner invoking a script
7
+ * rather than the behavior inline: a refresh rewrites the script freely without
8
+ * ever clobbering an entry a human may have edited.
9
+ *
10
+ * **Every script here is one a harness's configuration could not express.** A
11
+ * generated file in someone's repo is a standing cost — reviewed, kept in sync,
12
+ * wondered about — so it is written only where config falls short. Claude Code
13
+ * takes just the gate: its `protect` is a `permissions.deny` rule and its
14
+ * `dirty` an inline command. Cursor, whose config is hooks and nothing else,
15
+ * still takes all three. The gate is the one both need, because it alone has a
16
+ * branch neither config can carry (see {@link gateTail}).
17
+ */
18
+ import { DIRTY_MARKER, GATE_RETRY_ENV } from '../gate.js';
19
+ import { execCommand, runScript } from '../pm/index.js';
20
+ /**
21
+ * The repo root, however the calling harness spells it. Cursor sets
22
+ * `CURSOR_PROJECT_DIR` (and `CLAUDE_PROJECT_DIR` as an alias); Claude Code sets
23
+ * only the latter. The final `.` fallback keeps the script working under an
24
+ * older harness that sets neither, where the cwd is already the project.
25
+ */
26
+ const PROJECT_DIR = '"${CURSOR_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"';
27
+ /**
28
+ * `<pm> exec checkride <args…>`, spelled for `pm`'s launcher. Quieted: the gate
29
+ * parses this command's stdout, so pnpm's narration must not lead it.
30
+ */
31
+ function checkrideCommand(pm, args) {
32
+ return execCommand(pm, ['checkride', ...args], { quiet: true });
33
+ }
34
+ /**
35
+ * Every message this script can emit is passed to `printf` as an *argument*,
36
+ * never inlined into a double-quoted format string, so its backticks survive:
37
+ * `sh` runs a backtick span inside double quotes as a command, but it does not
38
+ * re-scan the result of a variable expansion. An early draft used `echo "…"`
39
+ * with the text inline and the shell silently ate two quoted command names.
40
+ *
41
+ * Two characters are therefore banned from every message here, and a test
42
+ * enforces both. A single quote would end the `'…'` the call site wraps it in. A
43
+ * double quote (or a backslash) would break {@link standDown}, which builds its
44
+ * JSON body with `printf '{"systemMessage":"%s"}'` rather than carrying a
45
+ * second, pre-encoded copy of the same sentence out of step with the first.
46
+ */
47
+ const NOTHING_RAN = 'Nothing ran: no check executed and no artifact was written, so `.check/` holds nothing from this turn.';
48
+ /** `<pm> install`, which is how all four package managers spell it. */
49
+ const installFix = (pm) => `Run \`${pm} install\` (checkride is a devDependency of this repo), then run \`${runScript(pm, 'check')}\`.`;
50
+ /**
51
+ * The repo has no checkride to run, because its dependencies were never
52
+ * installed — someone pulled a branch that added checkride, or cloned fresh, and
53
+ * started a session before installing.
54
+ *
55
+ * This stands the gate down instead of blocking, and it is the one case where
56
+ * that is clearly right. Blocking exists to make an agent fix what it broke; an
57
+ * absent toolchain is not something the turn broke, and the remedy is an install
58
+ * rather than an edit. Blocking on it re-asks the same agent every turn, forever,
59
+ * for a change that cannot clear it — the loop that ends with a contributor
60
+ * removing the gate. See `../gate.ts` {@link reportStandDown} for the same
61
+ * judgement one layer down.
62
+ */
63
+ const notInstalled = (pm) => [
64
+ 'checkride: the gate could not run — checkride is not installed in this repo.',
65
+ NOTHING_RAN,
66
+ installFix(pm),
67
+ 'Not blocking: the fix is an install rather than an edit, so blocking would only repeat this ' +
68
+ 'message. Nothing was verified this turn.',
69
+ ].join(' ');
70
+ /**
71
+ * checkride *is* installed and still did not answer with one of its own two gate
72
+ * codes — a broken launcher, a corrupt install, a crash. This one blocks: it is
73
+ * rare, it is not self-explanatory, and unlike a missing install there is no
74
+ * known remedy to name, so the honest move is to stop and be looked at. The
75
+ * retry guard in {@link gatePreamble} still bounds it.
76
+ */
77
+ const notAnswering = (pm, harness) => [
78
+ 'checkride: the gate could not run — checkride is installed here but `checkride gate` did not answer.',
79
+ NOTHING_RAN,
80
+ `Run \`${execCommand(pm, ['checkride', 'gate', '--harness', harness])}\` in a terminal to see the failure directly.`,
81
+ ].join(' ');
82
+ /** The harness pointed the hook at a directory that is not there. */
83
+ const noRepo = 'checkride: the gate could not run — the project directory the harness named does not exist or ' +
84
+ 'cannot be entered, so there is no repo to check.';
85
+ /**
86
+ * The shell functions every branch below answers through: one for a verdict that
87
+ * blocks, one for a verdict that gives up on blocking.
88
+ *
89
+ * `block` consults `retry` first, which is what bounds *every* could-not-run
90
+ * cause rather than only the ones enumerated here. Claude Code sends
91
+ * `stop_hook_active` on the Stop payload and Cursor sends `loop_count`; either
92
+ * one says the harness has already auto-submitted a turn on this hook, and a
93
+ * second identical block has been demonstrated not to help. A red pipeline never
94
+ * reaches this — that loop is the gate working, and is deliberately unbounded.
95
+ *
96
+ * Under Cursor `stand_down` consults it too, for a different reason. Blocking
97
+ * there is a `followup_message`, and so is the only way to reach a *user*, so
98
+ * the same guard has to serve both: it stops `block` repeating itself, and it
99
+ * rations `stand_down` to the single message that names the fix. `retry` is
100
+ * conservative in exactly the direction that keeps that safe — Cursor's
101
+ * `loop_count` counts every follow-up in the conversation rather than the
102
+ * consecutive ones, so an over-count costs a quiet stand-down, never a loop.
103
+ */
104
+ function gatePreamble(harness) {
105
+ const cursor = harness === 'cursor';
106
+ return [
107
+ '# The Stop payload arrives as JSON on stdin and says whether the harness has',
108
+ '# already been round this loop once. Read it before anything else can consume',
109
+ '# it, and only from a pipe: `cat` on a terminal would hang a hand-run forever.',
110
+ "payload=''",
111
+ '[ -t 0 ] || payload=$(cat)',
112
+ '',
113
+ '# True once the harness has already auto-submitted a turn on this hook.',
114
+ 'retry() {',
115
+ ' printf %s "$payload" |',
116
+ ` grep -Eq '"stop_hook_active"[[:space:]]*:[[:space:]]*true|"loop_count"[[:space:]]*:[[:space:]]*[1-9]'`,
117
+ '}',
118
+ '',
119
+ '# Give up on blocking, and say so. Nothing here is silent: a turn that ended',
120
+ '# unverified must never look like one that passed.',
121
+ 'stand_down() {',
122
+ ...(cursor
123
+ ? [
124
+ ' # Cursor names no channel that shows hook stderr to a user — only a Hooks',
125
+ ' # output panel under Customize — so stderr alone would hide this from the',
126
+ ' # one party who can fix an environment. `followup_message` does reach the',
127
+ ' # chat, and it also *submits a new turn*, so it goes out exactly once:',
128
+ ' # `loop_count` says a follow-up already went, and a second is the loop.',
129
+ ' retry || printf \'{"followup_message":"%s"}\\n\' "$1"',
130
+ ' printf \'%s\\n\' "$1" >&2',
131
+ ]
132
+ : [
133
+ ' # `systemMessage` reaches the user — the one party who can fix an',
134
+ ' # environment. With no `decision` in the body, Claude Code does not block.',
135
+ ' printf \'{"systemMessage":"%s"}\\n\' "$1"',
136
+ ' printf \'%s\\n\' "$1" >&2',
137
+ ]),
138
+ ' exit 0',
139
+ '}',
140
+ '',
141
+ '# Block the turn — unless this is the second consecutive attempt, in which',
142
+ '# case blocking is the thing already shown not to work.',
143
+ 'block() {',
144
+ ' retry && stand_down "$1 Standing down rather than blocking a second time on the same verdict."',
145
+ ...(cursor
146
+ ? [
147
+ ' # Cursor reads any non-zero stop hook as a *broken* hook and ends the turn,',
148
+ ' # so the block has to ride in the body with an exit of 0.',
149
+ ' printf \'{"followup_message":"%s"}\\n\' "$1"',
150
+ ' exit 0',
151
+ ]
152
+ : [' printf \'%s\\n\' "$1" >&2', ' exit 2']),
153
+ '}',
154
+ ...(cursor
155
+ ? [
156
+ '',
157
+ '# checkride also stands *itself* down, for a refusal it detects from inside',
158
+ '# (an `engines` pin the hook Node fails, a corepack it cannot verify) — and',
159
+ '# it never sees the stop payload, so hand it the one fact that bounds that',
160
+ '# message to a single turn the same way. It sends a followup only on a 0.',
161
+ `if retry; then ${GATE_RETRY_ENV}=1; else ${GATE_RETRY_ENV}=0; fi`,
162
+ `export ${GATE_RETRY_ENV}`,
163
+ ]
164
+ : []),
165
+ ];
166
+ }
167
+ /**
168
+ * Translate the gate's exit status into `harness`'s protocol.
169
+ *
170
+ * `checkride gate` exits 0 or 2 by design, and only on those two is its stdout a
171
+ * hook body worth forwarding. Anything else means checkride never ran, and
172
+ * whatever is on stdout then is the *launcher's* error — pnpm writes
173
+ * `ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL` there, ahead of a stray `undefined` on
174
+ * pnpm 11. Forwarding that puts unparseable text on the one channel a harness
175
+ * reads as protocol, so the status is checked first and the body is forwarded
176
+ * only when checkride is the one that wrote it. That is why {@link invokeGate}
177
+ * captures under both harnesses: output already streamed past the script cannot
178
+ * be withheld by it.
179
+ */
180
+ function gateTail(harness, pm) {
181
+ const answered = harness === 'cursor'
182
+ ? [
183
+ '# On 0 checkride has already written its JSON body, and on 2 the followup',
184
+ '# body. Either way it answered, so hand back what it wrote, unchanged.',
185
+ '# A green that had nothing to do writes nothing, and that is a body too.',
186
+ 'case "$status" in',
187
+ ' 0|2)',
188
+ ' [ -n "$body" ] && printf \'%s\\n\' "$body"',
189
+ ' exit 0',
190
+ ' ;;',
191
+ 'esac',
192
+ ]
193
+ : [
194
+ '# Claude Code parses a hook body only on exit 0, and only a body can carry a',
195
+ '# user-visible message alongside the block. So when checkride produced one,',
196
+ '# forward it and exit 0: the verdict rides in `decision`, not in the status.',
197
+ 'case "$status" in',
198
+ ' 0|2)',
199
+ ' if [ -n "$body" ]; then',
200
+ " printf '%s\\n' \"$body\"",
201
+ ' exit 0',
202
+ ' fi',
203
+ ' # No body — an older checkride that reports only through the exit code.',
204
+ ' exit "$status"',
205
+ ' ;;',
206
+ 'esac',
207
+ ];
208
+ return [
209
+ ...answered,
210
+ '',
211
+ "# Neither of checkride's two gate codes: checkride itself never ran. Which of",
212
+ '# the two reasons it was decides whether blocking could accomplish anything.',
213
+ 'if [ -e node_modules/.bin/checkride ] || [ -e .pnp.cjs ] || [ -e .pnp.js ]; then',
214
+ ` block '${notAnswering(pm, harness)}'`,
215
+ 'fi',
216
+ `stand_down '${notInstalled(pm)}'`,
217
+ ];
218
+ }
219
+ /**
220
+ * Characters a `gate.preflight` path may not contain, because the generated
221
+ * script embeds it inside `'…'` and inside a message that later becomes a JSON
222
+ * string field.
223
+ *
224
+ * Rejected loudly rather than escaped or stripped. Every one of these in a
225
+ * repo-relative script path is a mistake, and a mangled path would fail later as
226
+ * "preflight not found", pointing at the wrong thing.
227
+ */
228
+ const PREFLIGHT_HOSTILE = /['"\\`\n]/;
229
+ /**
230
+ * The repo-owned preflight, run from the repo root before checkride is started.
231
+ *
232
+ * Its exit code is read in the gate's own vocabulary — 0 runs the gate, 2 blocks
233
+ * the turn, anything else stands it down — so there is one meaning per code
234
+ * across the whole system rather than a second convention to learn. Both
235
+ * non-zero branches use the script's own output as the message and never start
236
+ * checkride, which is what lets a preflight answer for a repo where checkride
237
+ * *cannot* start.
238
+ *
239
+ * A configured path that is not there **blocks**, and deliberately: treating it
240
+ * as a stand-down would mean a typo in one config key silently disarms the gate
241
+ * forever. A missing file is repo-fixable, so blocking is the consistent answer.
242
+ */
243
+ function preflight(path) {
244
+ if (PREFLIGHT_HOSTILE.test(path)) {
245
+ throw new Error(`checkride.config.json: gate.preflight '${path}' contains a quote, backslash, backtick or newline. ` +
246
+ 'Use a plain repo-relative path.');
247
+ }
248
+ // `sh` resolves a command with no `/` against PATH, which is never what a
249
+ // repo-relative config value means.
250
+ const target = path.includes('/') ? path : `./${path}`;
251
+ return [
252
+ '# The repo-owned preflight, from `gate.preflight` in checkride.config.json.',
253
+ '# checkride owns this script and overwrites it; the preflight is where a repo',
254
+ '# says something before the gate and keeps it across every refresh.',
255
+ `if [ ! -e '${target}' ]; then`,
256
+ ` block 'checkride: the gate could not run — checkride.config.json names a gate.preflight (${target}) that is not there. Add the script, or drop the key.'`,
257
+ 'fi',
258
+ '',
259
+ '# A preflight prints for humans; this has to survive a JSON string field. The',
260
+ '# two characters that would break one are dropped and newlines folded.',
261
+ 'say() {',
262
+ ` printf %s "$1" | tr -d '"\\\\' | tr '\\n' ' '`,
263
+ '}',
264
+ '',
265
+ '# Honour the shebang when the file is executable, and fall back to `sh` when it',
266
+ '# is not — a checked-in script routinely arrives without its exec bit.',
267
+ `if [ -x '${target}' ]; then`,
268
+ ` said=$('${target}' 2>&1)`,
269
+ 'else',
270
+ ` said=$(sh '${target}' 2>&1)`,
271
+ 'fi',
272
+ 'code=$?',
273
+ `[ "$code" -eq 0 ] || [ -n "$said" ] ||`,
274
+ ` said='checkride: the gate could not run — the preflight ${target} exited non-zero and printed nothing.'`,
275
+ '',
276
+ '# 0 runs the gate; 2 blocks; anything else stands down. checkride is never',
277
+ '# started on a non-zero branch.',
278
+ 'case "$code" in',
279
+ ' 0) ;;',
280
+ ' 2) block "$(say "$said")" ;;',
281
+ ' *) stand_down "$(say "$said")" ;;',
282
+ 'esac',
283
+ ];
284
+ }
285
+ /**
286
+ * Enter the repo, or report a verdict rather than a bare status.
287
+ *
288
+ * Spelled as a block rather than `cd … || exit 2` for two reasons: a bare status
289
+ * tells the agent nothing, and under Cursor a non-zero stop hook is a *broken*
290
+ * hook, so the one branch that used to exit 2 there was the one branch that
291
+ * silently let a turn end.
292
+ */
293
+ function enterRepo() {
294
+ return [`if ! cd ${PROJECT_DIR}; then`, ` block '${noRepo}'`, 'fi'];
295
+ }
296
+ /**
297
+ * How the gate's stdout is taken: captured, under both harnesses.
298
+ *
299
+ * Letting it stream through is tempting under Cursor, which reads the hook's own
300
+ * stdout and would need no forwarding — but a *failed launch* writes there too,
301
+ * and a script that never held that output cannot keep it off a channel with
302
+ * defined semantics. Capturing is what gives {@link gateTail} the choice, and
303
+ * `block`/`stand_down` sole ownership of stdout on the paths where checkride
304
+ * never answered.
305
+ *
306
+ * It costs nothing visible: the pipeline's human-readable progress is on stderr
307
+ * and streams live either way, and stdout carries only the one-line JSON
308
+ * verdict, written at the very end.
309
+ */
310
+ function invokeGate(pm, args) {
311
+ return [`body=$(${checkrideCommand(pm, args)})`, 'status=$?'];
312
+ }
313
+ /**
314
+ * The gate script: `cd` to the repo, hand off to `checkride gate`, and translate
315
+ * the result into the harness's protocol.
316
+ *
317
+ * `dirtyGuard` (on when the `dirty` hook is written alongside — the default)
318
+ * makes the gate conditional on the edit marker, so pure-conversation turns
319
+ * don't pay for a full pipeline run. Without the marker hook the guard would
320
+ * disarm the gate entirely, so a `--hook gate` selection writes it unguarded.
321
+ *
322
+ * `preflight` is the repo's own script, from `gate.preflight` in
323
+ * checkride.config.json, baked in here rather than looked up at run time — see
324
+ * {@link preflight} and `../gate.ts` `gatePreflight`. It runs *before* the edit
325
+ * marker is consulted, because a repo that cannot run the gate at all wants to
326
+ * say so on every turn, not only on the ones that edited a file.
327
+ */
328
+ export function gateScript(pm, opts) {
329
+ const args = ['gate', '--harness', opts.harness, ...((opts.dirtyGuard ?? true) ? ['--if-dirty'] : [])];
330
+ return [
331
+ '#!/bin/sh',
332
+ `# checkride-gate.sh — the ${opts.harness} stop-hook gate.`,
333
+ '#',
334
+ '# checkride owns this file: `checkride agent-setup` (and `checkride init`)',
335
+ '# overwrite it on every run. Customize through checkride.config.json (a `gate`',
336
+ '# key narrows what runs) or the environment (CHECKRIDE_NODE_BIN), not by',
337
+ '# editing here — edits are lost on the next refresh.',
338
+ '#',
339
+ "# Runs the repo's `check` script as a hard gate, and reports the verdict in",
340
+ `# ${opts.harness}'s hook protocol. See \`checkride gate --help\`.`,
341
+ '',
342
+ ...gatePreamble(opts.harness),
343
+ '',
344
+ ...enterRepo(),
345
+ '',
346
+ ...(opts.preflight === undefined ? [] : [...preflight(opts.preflight), '']),
347
+ ...invokeGate(pm, args),
348
+ ...gateTail(opts.harness, pm),
349
+ '',
350
+ ].join('\n');
351
+ }
352
+ /**
353
+ * The dirty script: mark that this turn edited a file. A stop hook fires on
354
+ * every turn, including pure-conversation ones; the marker is what lets the gate
355
+ * skip those instead of taxing every reply with a full pipeline run.
356
+ *
357
+ * It exits 0 unconditionally. A failure to record an edit must never block the
358
+ * edit itself — the cost of a missed marker is one skipped gate, and the cost of
359
+ * a hard failure here is a repo where no file can be written.
360
+ */
361
+ export function dirtyScript() {
362
+ return [
363
+ '#!/bin/sh',
364
+ '# checkride-dirty.sh — record that this turn edited a file.',
365
+ '#',
366
+ '# checkride owns this file: `checkride agent-setup` (and `checkride init`)',
367
+ '# overwrite it on every run.',
368
+ '#',
369
+ '# The gate reads this marker under `--if-dirty` and clears it on green.',
370
+ '',
371
+ `cd ${PROJECT_DIR} || exit 0`,
372
+ `mkdir -p "$(dirname ${DIRTY_MARKER})" && touch ${DIRTY_MARKER}`,
373
+ 'exit 0',
374
+ '',
375
+ ].join('\n');
376
+ }
377
+ /**
378
+ * Keys Cursor may use for the target path in a tool call's `tool_input`.
379
+ *
380
+ * Cursor documents the shape for `Shell` but not for `Write`/`Delete`, so the
381
+ * list is deliberately broad and order-independent: the script takes the first
382
+ * string it finds. It keeps Claude Code's documented `file_path` and
383
+ * `notebook_path` too, since a harness that borrowed the schema would send
384
+ * those. An unrecognized shape yields no target and the script fails open, which
385
+ * is the correct failure — a protect hook that cannot read its input must not
386
+ * become a repo where nothing can be written.
387
+ *
388
+ * **The Cursor half of this list is a guess, and a wrong guess is silent**: an
389
+ * unmatched shape allows the write with no output, so `protect` would simply
390
+ * stop protecting and nothing would say so. The tests here can only assert the
391
+ * keys checkride *chose*, never the ones Cursor sends, so this is settled by one
392
+ * live `preToolUse` payload and not by anything in this repo. Until it is,
393
+ * `protect` is best-effort under Cursor — see docs/cursor.md. (Neither harness
394
+ * matches its shell tool, so a redirect writes the baseline under both; that gap
395
+ * is older and accepted.)
396
+ */
397
+ const PATH_KEYS = ['file_path', 'notebook_path', 'path', 'target_file', 'filePath', 'relative_workspace_path'];
398
+ /**
399
+ * Shell verbs that can destroy *any* path they are handed, so every positional
400
+ * argument is a write target. `mv` belongs here rather than with the
401
+ * destination-only verbs because moving an accounting file away removes it just
402
+ * as effectively as overwriting it.
403
+ */
404
+ const ALL_ARGS_VERBS = ['rm', 'unlink', 'shred', 'mv', 'truncate', 'tee', 'rmdir'];
405
+ /**
406
+ * Shell verbs whose sources are *read* and whose last positional argument is the
407
+ * only thing written. `cp .check/summary.json /tmp/x` has to stay allowed — it
408
+ * is a backup, not an edit — and treating its source as a target would deny it.
409
+ */
410
+ const DEST_ONLY_VERBS = ['cp', 'install', 'ln', 'rsync'];
411
+ /** The deny message, shared by both harnesses. */
412
+ const DENY_MESSAGE = "'checkride: ' + rel + ' is checkride-owned accounting. Never edit the baseline or .check ' +\n" +
413
+ " 'artifacts to make a check pass — fix the finding instead (the ratchet prunes the baseline on its own).'";
414
+ /**
415
+ * How Cursor spells "deny this tool call": a JSON body on stdout with exit 0. It
416
+ * reads a non-zero hook as a *broken* hook and proceeds, so the denial has to
417
+ * travel in the body, where `agent_message` is what the model sees.
418
+ */
419
+ function denyTail() {
420
+ return [
421
+ ' const message = ' + DENY_MESSAGE + ';',
422
+ ' process.stdout.write(JSON.stringify({',
423
+ " permission: 'deny',",
424
+ ' user_message: message,',
425
+ ' agent_message: message,',
426
+ ' }));',
427
+ ' process.exit(0);',
428
+ ];
429
+ }
430
+ /**
431
+ * The `protect` deny script: "never add to the baseline to make a check pass" as
432
+ * enforcement, not README advice. A Node script (not sh) because the hook
433
+ * protocol is JSON on stdin, and every checkride repo has node by construction;
434
+ * `.cjs` so it runs regardless of the repo's module type. Only edit tools are
435
+ * matched — reads are never denied, because triage depends on reading `.check/`
436
+ * artifacts.
437
+ *
438
+ * Two Cursor events land here. `preToolUse` carries a file-tool call, whose
439
+ * target is read from {@link PATH_KEYS}. `beforeShellExecution` carries a
440
+ * command line, which is scanned for a write *to* an accounting path — the gap
441
+ * a tool-name matcher cannot close, since `echo … > checkride.baseline.json` is
442
+ * a shell call and not a `Write`.
443
+ *
444
+ * The command scan is deliberately timid, because a guard that fires on a wrong
445
+ * parse is worse than a known hole. It denies only on demonstrated write intent
446
+ * — a `>`/`>>` redirect target, or a positional argument of a known mutating
447
+ * verb — and anything it cannot read that way is allowed. `cat`, `grep`, `jq`
448
+ * and `cp … /tmp/x` over `.check/` all pass, which they must: triage reads those
449
+ * artifacts. The hook's own `matcher` narrows the input further, so a command
450
+ * that never names an accounting path is not parsed at all.
451
+ *
452
+ * **Cursor only.** Claude Code enforces the same paths through
453
+ * `permissions.deny`, which is checked below the hook layer and costs nothing
454
+ * per tool call, so it needs no script. Cursor has no documented equivalent —
455
+ * its config is hooks — so the script survives for the harness that still
456
+ * requires one. If Cursor grows a file-path deny list, this file goes away.
457
+ * (Claude Code's deny rules have the same shell-redirect hole and no script to
458
+ * close it with; that half of the gap is still open. See docs/cursor.md.)
459
+ */
460
+ export function protectScript() {
461
+ return [
462
+ '#!/usr/bin/env node',
463
+ "// checkride-protect.cjs — deny agent edits to checkride's accounting files.",
464
+ '// checkride owns this file: `checkride agent-setup` (and `checkride init`)',
465
+ '// overwrite it on every run.',
466
+ '//',
467
+ '// Guard hook for Cursor. Reads the hook payload as JSON on stdin and denies',
468
+ '// the call when it *writes* to the baseline or .check/. Reads are never',
469
+ '// denied — triage depends on reading .check artifacts.',
470
+ "'use strict';",
471
+ "const { realpathSync } = require('node:fs');",
472
+ "const { basename, dirname, isAbsolute, relative, resolve, sep } = require('node:path');",
473
+ '',
474
+ `const PATH_KEYS = ${JSON.stringify(PATH_KEYS)};`,
475
+ `const ALL_ARGS_VERBS = ${JSON.stringify(ALL_ARGS_VERBS)};`,
476
+ `const DEST_ONLY_VERBS = ${JSON.stringify(DEST_ONLY_VERBS)};`,
477
+ '',
478
+ '// Resolve symlinks in `p`, so a symlinked prefix cannot make an in-repo path',
479
+ '// look external. On macOS the repo root routinely arrives in two spellings —',
480
+ '// the harness passes /var/…, the environment reports /private/var/… — and a',
481
+ '// raw string comparison across the two rejects every path in the repo.',
482
+ '//',
483
+ '// `p` need not exist: this hook runs *before* the write, and the target is',
484
+ '// often a file (or a whole directory) that is about to be created. So walk up',
485
+ '// to the first ancestor that does exist, resolve that, and re-append the rest.',
486
+ 'function canon(p) {',
487
+ ' let dir = resolve(p);',
488
+ ' const rest = [];',
489
+ ' for (;;) {',
490
+ ' try {',
491
+ ' return resolve(realpathSync(dir), ...rest);',
492
+ ' } catch {',
493
+ ' const up = dirname(dir);',
494
+ ' if (up === dir) return resolve(p);',
495
+ ' rest.unshift(basename(dir));',
496
+ ' dir = up;',
497
+ ' }',
498
+ ' }',
499
+ '}',
500
+ '',
501
+ '// Split a command line into tokens, keeping quoted spans whole and emitting',
502
+ '// each unquoted operator as a token of its own — so `echo x>f` and `echo x > f`',
503
+ '// tokenize alike, and a `>` inside quotes is never mistaken for a redirect.',
504
+ 'function tokenize(command) {',
505
+ ' const tokens = [];',
506
+ " let cur = '';",
507
+ ' let quote = null;',
508
+ " const flush = () => { if (cur !== '') { tokens.push(cur); cur = ''; } };",
509
+ ' for (let i = 0; i < command.length; i += 1) {',
510
+ ' const c = command[i];',
511
+ ' if (quote !== null) {',
512
+ ' if (c === quote) quote = null;',
513
+ ' else cur += c;',
514
+ ' } else if (/["\']/.test(c)) {',
515
+ ' quote = c;',
516
+ " } else if (c === '\\\\') {",
517
+ " i += 1; cur += command[i] || '';",
518
+ ' } else if (/\\s/.test(c)) {',
519
+ ' flush();',
520
+ ' } else if (/[<>|&;]/.test(c)) {',
521
+ ' flush();',
522
+ ' let op = c;',
523
+ ' while (command[i + 1] === c) { op += c; i += 1; }',
524
+ ' tokens.push(op);',
525
+ ' } else {',
526
+ ' cur += c;',
527
+ ' }',
528
+ ' }',
529
+ ' flush();',
530
+ ' return tokens;',
531
+ '}',
532
+ '',
533
+ 'const isOperator = (t) => /^[<>|&;]+$/.test(t);',
534
+ '',
535
+ '// Break a token stream at the operators that start a new command, so the verb',
536
+ '// of `cat x | tee .check/f` is read as `tee` and not as `cat`.',
537
+ 'function segments(tokens) {',
538
+ ' const out = [[]];',
539
+ ' for (const t of tokens) {',
540
+ ' if (/^[|&;]+$/.test(t)) out.push([]);',
541
+ ' else out[out.length - 1].push(t);',
542
+ ' }',
543
+ ' return out;',
544
+ '}',
545
+ '',
546
+ '// Every path a command line demonstrably writes to. Anything this cannot read',
547
+ '// as a write yields nothing, and the caller then allows the command.',
548
+ 'function commandTargets(command) {',
549
+ ' const targets = [];',
550
+ ' for (const segment of segments(tokenize(command))) {',
551
+ ' for (let i = 0; i < segment.length; i += 1) {',
552
+ " if (segment[i] !== '>' && segment[i] !== '>>') continue;",
553
+ ' const next = segment[i + 1];',
554
+ ' if (next !== undefined && !isOperator(next)) targets.push(next);',
555
+ ' }',
556
+ ' const words = segment.filter((t) => !isOperator(t));',
557
+ ' // Step over any leading `VAR=value` assignments to reach the verb itself.',
558
+ ' let i = 0;',
559
+ ' while (i < words.length && /^[A-Za-z_][A-Za-z0-9_]*=/.test(words[i])) i += 1;',
560
+ " const verb = (words[i] || '').split('/').pop();",
561
+ ' const rest = words.slice(i + 1);',
562
+ " const args = rest.filter((a) => !a.startsWith('-'));",
563
+ ' if (ALL_ARGS_VERBS.indexOf(verb) >= 0) targets.push(...args);',
564
+ ' else if (DEST_ONLY_VERBS.indexOf(verb) >= 0 && args.length > 0) targets.push(args[args.length - 1]);',
565
+ " else if ((verb === 'sed' || verb === 'perl') && rest.some((a) => /^-[a-zA-Z]*i/.test(a))) targets.push(...args);",
566
+ " else if (verb === 'dd') targets.push(...rest.filter((a) => a.startsWith('of=')).map((a) => a.slice(3)));",
567
+ ' }',
568
+ ' return targets;',
569
+ '}',
570
+ '',
571
+ "// `target`'s repo-relative path when it is checkride accounting, else undefined.",
572
+ 'function accounting(target, root, base) {',
573
+ ' const abs = canon(isAbsolute(target) ? target : resolve(base, target));',
574
+ " const rel = relative(root, abs).split(sep).join('/');",
575
+ " if (rel === 'checkride.baseline.json' || rel === '.check' || rel.startsWith('.check/')) return rel;",
576
+ ' return undefined;',
577
+ '}',
578
+ '',
579
+ "let raw = '';",
580
+ "process.stdin.on('data', (chunk) => { raw += chunk; });",
581
+ "process.stdin.on('end', () => {",
582
+ ' let input;',
583
+ ' try {',
584
+ ' input = JSON.parse(raw);',
585
+ ' } catch {',
586
+ ' process.exit(0); // fail open: a broken hook must not brick every edit',
587
+ ' }',
588
+ " if (input === null || typeof input !== 'object') process.exit(0);",
589
+ ' const root = canon(process.env.CURSOR_PROJECT_DIR || process.env.CLAUDE_PROJECT_DIR || process.cwd());',
590
+ " // A shell command resolves against the shell's own cwd, which Cursor sends;",
591
+ ' // a file-tool path has always been resolved against the repo root.',
592
+ " const base = typeof input.cwd === 'string' && input.cwd.length > 0 ? canon(input.cwd) : root;",
593
+ ' const tool = input.tool_input || {};',
594
+ " const targets = input.hook_event_name === 'beforeShellExecution'",
595
+ " ? commandTargets(typeof input.command === 'string' ? input.command : '')",
596
+ " : PATH_KEYS.map((k) => tool[k]).filter((v) => typeof v === 'string' && v.length > 0);",
597
+ ' const rel = targets.map((t) => accounting(t, root, base)).find((r) => r !== undefined);',
598
+ ' if (rel === undefined) process.exit(0);',
599
+ ...denyTail(),
600
+ '});',
601
+ '',
602
+ ].join('\n');
603
+ }
604
+ //# sourceMappingURL=scripts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scripts.js","sourceRoot":"","sources":["../../src/agent-setup/scripts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Skill delivery for harnesses that have no plugin system.
3
+ *
4
+ * Claude Code gets `check` and `qa` from the bundled plugin
5
+ * (`.claude-plugin/plugin.json`), installed once and shared across every repo.
6
+ * Cursor has no equivalent — it discovers skills from directories on disk — so
7
+ * for Cursor the same two skills are written into the repo, from the same source
8
+ * files the plugin ships. One authored copy, two delivery mechanisms.
9
+ *
10
+ * The only edit made on the way through is the frontmatter `name`: a bare
11
+ * `check` would take the `/check` slash command in every repo it lands in, which
12
+ * is not a name checkride should be squatting. The plugin gets namespacing for
13
+ * free (`/checkride:check`); here it has to be spelled out.
14
+ */
15
+ import type { HookFile } from './files.js';
16
+ /** Where Cursor discovers project skills, relative to the repo root. */
17
+ export declare const CURSOR_SKILLS_DIR = ".cursor/skills";
18
+ /**
19
+ * Rewrite the `name:` field inside the leading frontmatter block, and only
20
+ * there — a `name:` further down is prose in the skill body, not metadata.
21
+ */
22
+ export declare function renameSkill(body: string, name: string): string;
23
+ /**
24
+ * Write the bundled skills into `cwd`'s Cursor skills directory. A source skill
25
+ * that cannot be read is skipped rather than fatal: a broken or trimmed install
26
+ * should cost the skills, not the whole `agent-setup`.
27
+ */
28
+ export declare function writeCursorSkills(cwd: string, opts?: {
29
+ dryRun?: boolean;
30
+ }): Promise<HookFile[]>;
31
+ //# sourceMappingURL=skills.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/agent-setup/skills.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3C,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,mBAAmB,CAAC;AAalD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAWzG"}