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
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAQH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAInD,OAAO,KAAK,EAAY,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAI7C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAE7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEnD,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,oEAAoE;IACpE,KAAK,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC5B;;;;OAIG;IACH,WAAW,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IAClC,iFAAiF;IACjF,SAAS,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;IACnC,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,KAAK,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IAC9B,4EAA4E;IAC5E,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACpE;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iFAAiF;IACjF,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,KAAK,GAAG,UAAU,CAAC;IACzB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,wCAAwC;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,mFAAmF;IACnF,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAWF,MAAM,MAAM,cAAc,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAkFnG;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEzE,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAaxE;AAsBD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,GAAE,cAAuB,GAAG,MAAM,CAsC/F;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAkBjE;AAMD,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,KAAK,EAAE;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACxC,GAAG,cAAc,EAAE,CAcnB;AA24BD,gEAAgE;AAChE,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,GAAG,UAAU,CAE1D;AAED,0CAA0C;AAC1C,wBAAsB,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAGvE;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oEAAoE;IACpE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,oEAAoE;IACpE,KAAK,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC5B;;;;OAIG;IACH,WAAW,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IAClC,iFAAiF;IACjF,SAAS,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;IACnC;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,KAAK,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,wCAAwC;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA6BzF"}
@@ -11,18 +11,19 @@
11
11
  * Generation, not transformation: every file is written once; the project owns
12
12
  * it afterward.
13
13
  */
14
+ import { createHash } from 'node:crypto';
14
15
  import { existsSync, readFileSync } from 'node:fs';
15
16
  import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
16
17
  import { basename, dirname, join } from 'node:path';
17
18
  import { fileURLToPath } from 'node:url';
18
19
  import { ADAPTERS, SLOTS } from './adapters.js';
19
20
  import { planSnippets, selectDocFiles } from './snippets.js';
20
- import { CLAUDE_SETTINGS_FILE, writeStopHook } from './agent-setup/index.js';
21
+ import { detectHarnesses, writeCursorSkills, writeHooks } from './agent-setup/index.js';
21
22
  import { BASELINE_FILE, isFingerprintable } from './baseline/index.js';
22
23
  import { runBaseline } from './baseline-command.js';
23
- import { configSchemaUrl, resolveChecks } from './config.js';
24
- import { runChecks } from './orchestrator.js';
25
- import { detectPackageManager } from './pm/index.js';
24
+ import { configSchemaUrl, loadConfig, resolveChecks } from './config.js';
25
+ import { runChecks, selectChecks } from './orchestrator.js';
26
+ import { detectPackageManager, execCommand, runScript } from './pm/index.js';
26
27
  const NULL_OUT = { write: () => true };
27
28
  /** Run the adopted checks once; a failing (non-skipped) check marks its slot. */
28
29
  async function defaultProbe(slots, cwd) {
@@ -33,22 +34,131 @@ async function defaultProbe(slots, cwd) {
33
34
  }
34
35
  const HERE = dirname(fileURLToPath(import.meta.url));
35
36
  const TEMPLATES_DIR = join(HERE, '..', 'templates');
36
- const STANZA_BEGIN = '<!-- checkride:begin -->';
37
+ const STANZA_BEGIN_PREFIX = '<!-- checkride:begin';
37
38
  const STANZA_END = '<!-- checkride:end -->';
39
+ /** The block, capturing its stamp (absent on stanzas written before v0.10.1) and its body. */
40
+ const STANZA_RE = /<!-- checkride:begin(?: hash=([0-9a-z]+))? -->([\s\S]*?)<!-- checkride:end -->/;
41
+ const STANZA_BEGIN_RE = /<!-- checkride:begin(?: hash=[0-9a-z]+)? -->/;
38
42
  // ----------------------------------------------------------------------------
39
43
  // AGENTS.md stanza (gate: idempotent)
40
44
  // ----------------------------------------------------------------------------
41
- function escapeRegex(text) {
42
- return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
45
+ /**
46
+ * Compare two stanza bodies the way a reader would: line endings and trailing
47
+ * whitespace are not edits. Deliberately minimal — one checkride version stamps
48
+ * a block and a later one verifies that stamp, so every rule here has to keep
49
+ * holding across versions or a pristine stanza starts reading as an edited one.
50
+ */
51
+ function normalizeStanza(text) {
52
+ return text.replace(/\r\n/g, '\n').replace(/[ \t]+$/gm, '').trim();
53
+ }
54
+ /**
55
+ * The stamp written into the begin marker: a digest of the body checkride
56
+ * generated. A later run recomputes it from what is on disk — a match means the
57
+ * block is still checkride's own output and is safe to refresh; a mismatch means
58
+ * someone edited it and refreshing would destroy their work.
59
+ *
60
+ * The `v1` prefix earns its place twice: it dates the normalization rules above
61
+ * (change them and bump it, so old stamps read as unverifiable rather than
62
+ * edited), and it guarantees the token contains a digit. cspell ignores words
63
+ * with digits, so a digest that happened to come up all `a`-`f` cannot fail the
64
+ * `spell` check of the repo checkride wrote it into.
65
+ */
66
+ function stanzaStamp(body) {
67
+ return `v1${createHash('sha256').update(normalizeStanza(body)).digest('hex').slice(0, 16)}`;
68
+ }
69
+ /**
70
+ * A stanza body without its trailing generated `Active checks in this repo: …`
71
+ * line — the part that is pure wording, identical in every repo running a given
72
+ * checkride version.
73
+ *
74
+ * The active-checks line is what makes two stanzas from the same release differ,
75
+ * so a registry of released wordings has to compare everything but that. If the
76
+ * line is missing, or something follows it inside the markers, nothing is
77
+ * stripped and the digest simply fails to match — which is the safe answer.
78
+ */
79
+ function stanzaPreamble(body) {
80
+ return normalizeStanza(normalizeStanza(body).replace(/\nActive checks in this repo:[^\n]*$/, ''));
81
+ }
82
+ /**
83
+ * The wording of every stanza checkride released before it stamped them, keyed
84
+ * by {@link stanzaPreamble} digest. Four distinct texts across v0.1.1–v0.10.0.
85
+ *
86
+ * This is what makes the stamp's arrival a non-event for repos that never
87
+ * touched their stanza. Without it, every upgrading repo looked `unstamped` —
88
+ * an older version's wording is not distinguishable from a customization by
89
+ * comparison alone — so the first run after upgrading refused and wrote
90
+ * *nothing*, hooks and config included. That is how the 0.10.1 gate-timeout fix
91
+ * failed to reach the repos that most needed it: the guard protecting AGENTS.md
92
+ * prose was also withholding a fix for a gate that had silently stopped gating.
93
+ *
94
+ * Recognizing the wording collapses that to the case it was always meant to
95
+ * cover. A pre-stamp stanza whose preamble is one of these is checkride's own
96
+ * output, untouched, and refreshing it loses nothing; one that has been edited
97
+ * still fails to match and is still refused.
98
+ *
99
+ * The list is closed. Every release from 0.10.1 stamps what it writes, so no
100
+ * future version can add an unstamped wording — nothing here needs maintaining.
101
+ */
102
+ const LEGACY_STANZA_PREAMBLES = new Set([
103
+ 'v16da2ec6a25e24085', // v0.1.1–v0.1.6
104
+ 'v190c2d48a280ff92c', // v0.2.0–v0.7.0
105
+ 'v1d4b4eaeeccb5faa2', // v0.8.0–v0.9.6
106
+ 'v17a3a1a85e3c3123e', // v0.10.0 (0.10.1 shares the wording but stamps it)
107
+ ]);
108
+ /** Classify the stanza in `content` against the `body` checkride would write. */
109
+ export function inspectStanza(content, body) {
110
+ const match = STANZA_RE.exec(content);
111
+ if (!match) {
112
+ // A begin marker with no end is a stanza someone edited badly, not an absent
113
+ // one: appending a second block would be the same data loss in another form.
114
+ return content.includes(STANZA_BEGIN_PREFIX) ? 'edited' : 'absent';
115
+ }
116
+ const [, stamp, found = ''] = match;
117
+ if (stamp === undefined) {
118
+ if (normalizeStanza(found) === normalizeStanza(body))
119
+ return 'pristine';
120
+ return LEGACY_STANZA_PREAMBLES.has(stanzaStamp(stanzaPreamble(found))) ? 'pristine' : 'unstamped';
121
+ }
122
+ return stamp === stanzaStamp(found) ? 'pristine' : 'edited';
43
123
  }
44
- /** The agent-facing contract block, parameterized by the active checks. */
45
- export function buildStanza(activeSlots) {
124
+ /**
125
+ * The `struct` slot's section: where the boundary rules live, not what they say.
126
+ *
127
+ * checkride ships opinionated ast-grep defaults (`no-class.yml` and friends),
128
+ * but it does not own the repo's architecture, and the stanza is the one place
129
+ * a repo cannot talk back — editing it blocks the next refresh. So this points
130
+ * at the rule files and stops. A repo that allows classes, default exports, or
131
+ * bundler-style extensionless imports deletes those rules and this stays true.
132
+ */
133
+ function structSection() {
134
+ return [
135
+ '### Module boundaries',
136
+ '',
137
+ 'The `struct` check runs whatever ast-grep rules `sgconfig.yml` points at',
138
+ "(`rules/` by default). Those files are this repo's boundary convention —",
139
+ 'read them rather than assuming one.',
140
+ '',
141
+ ];
142
+ }
143
+ /**
144
+ * The agent-facing contract block, parameterized by the active checks and the
145
+ * repo's package manager.
146
+ *
147
+ * `pm` is not cosmetic. The stanza is a list of commands an agent is told to
148
+ * run, and `pnpm check` in an npm repo is an instruction that cannot succeed —
149
+ * the agent either invents a substitute or reports the pipeline as broken.
150
+ * Everything here routes through {@link runScript}/{@link execCommand} for that
151
+ * reason; nothing spells a launcher literally.
152
+ */
153
+ export function buildStanza(activeSlots, pm = 'pnpm') {
154
+ const check = runScript(pm, 'check');
155
+ const triage = execCommand(pm, ['checkride', 'triage']);
46
156
  return [
47
157
  '## Checkride: the definition of done',
48
158
  '',
49
- '`pnpm check` is the single source of truth for "done". Exit 0 means the work is',
159
+ `\`${check}\` is the single source of truth for "done". Exit 0 means the work is`,
50
160
  'complete; any other exit code means it is not. Never claim a task is finished while',
51
- '`pnpm check` is red.',
161
+ `\`${check}\` is red.`,
52
162
  '',
53
163
  'When it fails:',
54
164
  '',
@@ -56,13 +166,16 @@ export function buildStanza(activeSlots) {
56
166
  "2. Read that check's raw output (`.check/<slot>.json` or `.check/<slot>.stdout.txt`).",
57
167
  '3. Fix the root cause, then re-run.',
58
168
  '',
59
- 'Tight feedback loops: `pnpm check --bail`, `pnpm check --only types,lint`, and',
60
- '`pnpm check --changed`.',
169
+ `\`${triage}\` runs this procedure in full and reads \`.check/\` for you`,
170
+ '(`/checkride:check` and `/checkride-check` are the same thing as a skill).',
61
171
  '',
62
- 'If a Claude Code Stop hook is configured (`.claude/settings.json`), it runs the full',
63
- '`pnpm check` as the final gate — so while iterating, prefer the narrow commands above',
64
- 'and let the hook run the authoritative pipeline once at the end rather than running',
65
- 'the full check yourself every loop.',
172
+ `Tight feedback loops: \`${check} --bail\`, \`${check} --only types,lint\`, and`,
173
+ `\`${check} --changed\`.`,
174
+ '',
175
+ 'If a stop-gate hook is configured (`.claude/settings.json` or `.cursor/hooks.json`),',
176
+ `it runs the full \`${check}\` as the final gate — so while iterating, prefer the narrow`,
177
+ 'commands above and let the hook run the authoritative pipeline once at the end rather',
178
+ 'than running the full check yourself every loop.',
66
179
  '',
67
180
  '### Baseline',
68
181
  '',
@@ -72,27 +185,28 @@ export function buildStanza(activeSlots) {
72
185
  'the ratchet, so the baseline only ever shrinks. Never add to the baseline to make a',
73
186
  'check pass; fix the finding.',
74
187
  '',
75
- '### Module boundaries',
76
- '',
77
- 'A module is a unit of encapsulation. A single file is a module; promote it to a',
78
- 'folder with a barrel `index.ts` when it grows internals worth hiding. A folder',
79
- "module's `index.ts` is its only public surface — re-exports only, no logic. Import",
80
- "siblings through `'../<sibling>/index.js'`, never their internals.",
81
- '',
82
- 'Named exports only; no classes; `.js` extensions on relative imports.',
83
- '',
188
+ ...(activeSlots.includes('struct') ? structSection() : []),
84
189
  `Active checks in this repo: ${activeSlots.join(', ')}.`,
85
190
  ].join('\n');
86
191
  }
87
192
  /**
88
193
  * Insert or refresh the checkride stanza in an AGENTS.md body. Idempotent:
89
- * applying twice yields identical output.
194
+ * applying twice yields identical output. It rewrites the marked region without
195
+ * looking at what was there — callers gate on {@link inspectStanza} first.
90
196
  */
91
197
  export function applyStanza(content, body) {
92
- const block = `${STANZA_BEGIN}\n\n${body}\n\n${STANZA_END}`;
93
- const re = new RegExp(`${escapeRegex(STANZA_BEGIN)}[\\s\\S]*?${escapeRegex(STANZA_END)}`);
94
- if (re.test(content)) {
95
- return content.replace(re, block);
198
+ // A replacer function, not the string: a `$&` in the stanza would otherwise be
199
+ // read as a backreference.
200
+ const block = `${STANZA_BEGIN_PREFIX} hash=${stanzaStamp(body)} -->\n\n${body}\n\n${STANZA_END}`;
201
+ if (STANZA_RE.test(content)) {
202
+ return content.replace(STANZA_RE, () => block);
203
+ }
204
+ if (STANZA_BEGIN_RE.test(content)) {
205
+ // A begin marker with no end: replace the marker in place rather than
206
+ // appending a second block, which would leave two begins and make the next
207
+ // refresh swallow everything between them. What followed the orphaned marker
208
+ // stays where it is — now outside the markers, so nothing rewrites it again.
209
+ return content.replace(STANZA_BEGIN_RE, () => block);
96
210
  }
97
211
  if (content.trim().length === 0) {
98
212
  return `${block}\n`;
@@ -312,18 +426,57 @@ async function writePackage(w, dir, pkgName, value) {
312
426
  await put(w, join(dir, 'src', 'index.test.ts'), smokeTest(value));
313
427
  }
314
428
  /**
315
- * Write/refresh the Claude Code Stop hook unless opted out (`hook === false`),
316
- * using the repo's detected package manager (b7). Records the file when it
317
- * changed, else a no-op note in `skipped` when one is provided.
429
+ * Write/refresh the agent hooks unless opted out (`hook === false`), remove any
430
+ * named for removal, for the selected harnesses (default: detected) and the
431
+ * repo's detected package manager. Records each file when it changed, else a
432
+ * no-op note in `skipped` when one is provided.
433
+ *
434
+ * `--no-hook` and `--remove-hook` compose rather than conflict: the first says
435
+ * "write nothing", the second "take this one out", and together they mean
436
+ * "remove the gate and leave the rest of the setup untouched" — which is the
437
+ * whole point of being able to drop a hook after the fact.
438
+ */
439
+ async function writeHook(w, options, skipped) {
440
+ const remove = options.removeHooks ?? [];
441
+ if (options.hook === false && remove.length === 0)
442
+ return;
443
+ const hooks = options.hook === false ? [] : options.hooks;
444
+ const result = await writeHooks(w.cwd, {
445
+ dryRun: w.dryRun,
446
+ ...(hooks ? { hooks } : {}),
447
+ ...(remove.length > 0 ? { remove } : {}),
448
+ ...(options.harnesses ? { harnesses: options.harnesses } : {}),
449
+ });
450
+ record(w, result.files, skipped);
451
+ }
452
+ /**
453
+ * Write the bundled skills for every selected harness that cannot install them
454
+ * as a plugin. Only Cursor needs this today; Claude Code gets the same two
455
+ * skills from `.claude-plugin/`, installed once for every repo.
456
+ *
457
+ * Unlike the hooks this is not covered by `--no-hook`: that flag turns off the
458
+ * mechanical gate, and a skill gates nothing.
318
459
  */
319
- async function writeHook(w, hook, skipped) {
320
- if (hook === false)
460
+ async function writeSkills(w, options, skipped) {
461
+ const harnesses = options.harnesses ?? detectHarnesses(w.cwd);
462
+ if (!harnesses.includes('cursor'))
321
463
  return;
322
- const result = await writeStopHook(w.cwd, { dryRun: w.dryRun });
323
- if (result.changed)
324
- w.written.push(result.path);
325
- else
326
- skipped?.push(`${CLAUDE_SETTINGS_FILE} (Stop hook unchanged)`);
464
+ record(w, await writeCursorSkills(w.cwd, { dryRun: w.dryRun }), skipped);
465
+ }
466
+ /**
467
+ * Fold a writer's file list into the run's written/removed/skipped report. A
468
+ * deleted file is a change, but not a *write* — counting it as one would have
469
+ * `--remove-hook gate` report that it wrote a file it actually took away.
470
+ */
471
+ function record(w, files, skipped) {
472
+ for (const f of files) {
473
+ if (!f.changed)
474
+ skipped?.push(`${f.path} (${f.removed === true ? 'absent' : 'unchanged'})`);
475
+ else if (f.removed === true)
476
+ w.removed.push(f.path);
477
+ else
478
+ w.written.push(f.path);
479
+ }
327
480
  }
328
481
  // ----------------------------------------------------------------------------
329
482
  // New-project mode
@@ -361,7 +514,7 @@ async function writeNewScaffold(w, s) {
361
514
  * into `.claude/settings.json` idempotently rather than overwriting.
362
515
  */
363
516
  async function planCollisions(s, cwd) {
364
- const plan = { cwd, dryRun: true, written: [] };
517
+ const plan = { cwd, dryRun: true, written: [], removed: [] };
365
518
  await writeNewScaffold(plan, s);
366
519
  return plan.written.filter((rel) => existsSync(join(cwd, rel)));
367
520
  }
@@ -388,7 +541,7 @@ function resolveNewScaffold(options, cwd) {
388
541
  };
389
542
  }
390
543
  /**
391
- * Overwrite protection (D4): unless `force`, refuse rather than clobber any file
544
+ * Overwrite protection: unless `force`, refuse rather than clobber any file
392
545
  * the scaffold would write. Planning on a dry writer first means a collision
393
546
  * bails before a single real byte is written — the refusal writes nothing.
394
547
  */
@@ -412,14 +565,24 @@ function reportNew(stdout, shape, w, cwd) {
412
565
  async function initNew(options, cwd) {
413
566
  const scaffold = resolveNewScaffold(options, cwd);
414
567
  await assertNoCollisions(scaffold, cwd, options.force ?? false);
415
- const w = { cwd, dryRun: options.dryRun ?? false, written: [] };
568
+ const w = { cwd, dryRun: options.dryRun ?? false, written: [], removed: [] };
416
569
  await writeNewScaffold(w, scaffold);
417
- // Claude Code Stop hook (opt-out; step 12). A fresh project has no PM lockfile
570
+ // Claude Code Stop hook (opt-out). A fresh project has no PM lockfile
418
571
  // yet, so it resolves to the `pnpm` default — matching the generated scripts.
419
- await writeHook(w, options.hook);
572
+ await writeHook(w, options);
573
+ await writeSkills(w, options);
420
574
  if (options.stdout)
421
575
  reportNew(options.stdout, scaffold.shape, w, cwd);
422
- return { mode: 'new', shape: scaffold.shape, written: w.written, skipped: [], disabled: [], grandfathered: [], exitCode: 0 };
576
+ return {
577
+ mode: 'new',
578
+ shape: scaffold.shape,
579
+ written: w.written,
580
+ removed: w.removed,
581
+ skipped: [],
582
+ disabled: [],
583
+ grandfathered: [],
584
+ exitCode: 0,
585
+ };
423
586
  }
424
587
  // ----------------------------------------------------------------------------
425
588
  // Existing-project mode
@@ -433,9 +596,9 @@ async function readIfExists(path) {
433
596
  }
434
597
  }
435
598
  // ----------------------------------------------------------------------------
436
- // Publish-ready bundle (step 9): the library path scaffolds the opt-in artifact
599
+ // Publish-ready bundle: the library path scaffolds the opt-in artifact
437
600
  // checks into `checkride.config.json` so a buildable library orders itself out
438
- // of the box (build → pack/smoke/attw/publint/snippets, D4).
601
+ // of the box (build → pack/smoke/attw/publint/snippets).
439
602
  // ----------------------------------------------------------------------------
440
603
  /**
441
604
  * The publish-ready bundle, in wave order. Each slot's value is the adapter
@@ -446,7 +609,7 @@ async function readIfExists(path) {
446
609
  const PUBLISH_BUNDLE_SLOTS = ['build', 'publint', 'attw', 'pack', 'smoke', 'snippets'];
447
610
  /** `--add` values that expand to the whole bundle. */
448
611
  const PUBLISH_BUNDLE_ALIASES = new Set(['publish', 'bundle']);
449
- /** Printed (and recorded in `skipped`) when snippets is requested but no tagged fence exists (Q12). */
612
+ /** Printed (and recorded in `skipped`) when snippets is requested but no tagged fence exists. */
450
613
  const SNIPPETS_POINTER = 'snippets-dist: no tagged fences found — add a `<!-- snippet: check -->` marker above a ' +
451
614
  'ts/typescript fence in README.md or docs/*.md to enable the doc-snippet typecheck';
452
615
  /**
@@ -465,9 +628,9 @@ function readInitManifest(cwd) {
465
628
  }
466
629
  /**
467
630
  * True when README.md or a non-recursive docs/*.md carries at least one tagged
468
- * snippet fence — the signal that gates scaffolding `snippets-dist` (Q12).
469
- * Reuses step 7's pure discovery/plan primitives so the detection matches what
470
- * the slot itself checks.
631
+ * snippet fence — the signal that gates scaffolding `snippets-dist`.
632
+ * Reuses the snippets module's pure discovery/plan primitives so the detection
633
+ * matches what the slot itself checks.
471
634
  */
472
635
  async function hasTaggedSnippets(cwd) {
473
636
  let docsEntries = [];
@@ -488,7 +651,7 @@ async function hasTaggedSnippets(cwd) {
488
651
  }
489
652
  /**
490
653
  * Fold the requested publish slots into config entries, gating `build` on a
491
- * build script and `snippets` (→ `snippets-dist`) on a tagged fence (Q12) — the
654
+ * build script and `snippets` (→ `snippets-dist`) on a tagged fence — the
492
655
  * two slots that would otherwise stand down as a skip (`build`) or hard-error on
493
656
  * zero snippets (`snippets`).
494
657
  */
@@ -540,16 +703,67 @@ function splitAdd(add, manifest) {
540
703
  }
541
704
  return { publishRequested, fileAdds };
542
705
  }
706
+ /**
707
+ * The stanza's active-check list: the selection a default `checkride` run
708
+ * makes, resolved config-aware from disk. `inventory()` is the wrong input
709
+ * here — it has detection semantics and never reads checkride.config.json, so
710
+ * it under-reports the gate (opt-in slots the config opts in, custom checks)
711
+ * to the exact audience the stanza exists to inform. Mirrors `doctor`'s
712
+ * `defaultActive` derivation.
713
+ */
714
+ function activeCheckSlots(cwd, slots, adapters) {
715
+ const resolved = resolveChecks({ slots, adapters, config: loadConfig(cwd), cwd });
716
+ return selectChecks(resolved, {})
717
+ .filter((r) => r.adapter !== null)
718
+ .map((r) => r.slot);
719
+ }
720
+ const STANZA_REFUSALS = {
721
+ edited: 'it has been edited since checkride wrote it',
722
+ unstamped: 'it predates the stanza stamp and matches no wording checkride has released, so it has been changed since it was written',
723
+ };
724
+ /**
725
+ * Refuse to refresh a stanza that is not checkride's own output, so a repo's
726
+ * edge-case additions survive the next `init`/`agent-setup` instead of being
727
+ * silently overwritten. `opts.force` overrides.
728
+ *
729
+ * Called before either entry point writes anything, so a refusal leaves the repo
730
+ * exactly as it found it (the same rule `assertNoCollisions` follows in new
731
+ * mode). In existing mode that puts it ahead of the config write, so `body` here
732
+ * reflects the config as it is on disk now rather than as this run will leave
733
+ * it — which no longer costs anything: a stamped stanza is checked against its
734
+ * own stamp, and an unstamped one against a registry of released wordings that
735
+ * ignores the active-checks line entirely. Neither reads `body`'s slot list.
736
+ *
737
+ * Hook management deliberately does not come through here — see the `hooks`
738
+ * command, which never touches AGENTS.md and so has nothing to refuse.
739
+ */
740
+ async function assertStanzaUnedited(cwd, body, opts) {
741
+ if (opts.force === true)
742
+ return;
743
+ const existing = await readIfExists(join(cwd, 'AGENTS.md'));
744
+ if (existing === null)
745
+ return;
746
+ const state = inspectStanza(existing, body);
747
+ if (state === 'absent' || state === 'pristine')
748
+ return;
749
+ const remedy = state === 'edited'
750
+ ? 'Move your additions outside the markers — checkride never rewrites what is outside them — or re-run with --force to discard them and refresh.'
751
+ : 'If you have not edited it, re-run with --force: the refreshed stanza carries a stamp, and later runs tell an edit from a refresh on their own.';
752
+ throw new Error(`refusing to overwrite the checkride stanza in AGENTS.md: ${STANZA_REFUSALS[state]}.\n ${remedy}`);
753
+ }
543
754
  /**
544
755
  * Write (or refresh) the AGENTS.md stanza for `slots`, idempotently: it writes
545
756
  * only when the applied stanza differs from the current file, records the outcome
546
757
  * on `w`/`skipped`, and honours dry-run. Shared by `initExisting` and
547
758
  * `runAgentSetup` (both create-or-refresh the same stanza).
759
+ *
760
+ * It rewrites the marked region unconditionally; whether that is allowed is
761
+ * {@link assertStanzaUnedited}'s call, made before either caller writes anything.
548
762
  */
549
- async function writeAgentsStanza(w, cwd, slots, skipped) {
763
+ async function writeAgentsStanza(w, cwd, slots, pm, skipped) {
550
764
  const agentsPath = join(cwd, 'AGENTS.md');
551
765
  const existing = await readIfExists(agentsPath);
552
- const nextAgents = applyStanza(existing ?? '', buildStanza(slots));
766
+ const nextAgents = applyStanza(existing ?? '', buildStanza(slots, pm));
553
767
  if (nextAgents !== existing) {
554
768
  if (!w.dryRun)
555
769
  await writeFile(agentsPath, nextAgents);
@@ -566,12 +780,19 @@ const ADD_CONFIGS = {
566
780
  types: [['shared/tsconfig.base.json', 'tsconfig.base.json'], ['flat/tsconfig.json', 'tsconfig.json']],
567
781
  format: [['shared/prettierrc.json', '.prettierrc.json']],
568
782
  lint: [['shared/oxlintrc.json', '.oxlintrc.json']],
783
+ // `struct` scaffolds the boundary rule and stops. New-mode `init` writes all
784
+ // four (`writeSharedStatic`), and that is a different bargain: there checkride
785
+ // is creating the package, so its house style has nobody to override. Here the
786
+ // repo already exists and has already decided. `no-class`, `no-default-export`
787
+ // and `require-js-extension` are style and module-system opinions — a repo
788
+ // with classes, default exports, or bundler resolution goes red on adoption
789
+ // for writing the code it always wrote, which reads as checkride being broken.
790
+ // `no-deep-sibling-import` is the one that makes `struct` the slot it is, and
791
+ // failing it means what it says. The other three stay one copy away, in
792
+ // `docs/deep-modules.md`.
569
793
  struct: [
570
794
  ['shared/sgconfig.yml', 'sgconfig.yml'],
571
- ['shared/rules/no-class.yml', 'rules/no-class.yml'],
572
- ['shared/rules/no-default-export.yml', 'rules/no-default-export.yml'],
573
795
  ['shared/rules/no-deep-sibling-import.yml', 'rules/no-deep-sibling-import.yml'],
574
- ['shared/rules/require-js-extension.yml', 'rules/require-js-extension.yml'],
575
796
  ],
576
797
  dead: [['flat/fallow.toml', 'fallow.toml']],
577
798
  // dupes/health are the same fallow tool + config as `dead`, just other slots.
@@ -625,7 +846,7 @@ async function addCheckAlias(w, skipped) {
625
846
  w.written.push('package.json (added check script)');
626
847
  }
627
848
  /**
628
- * Classify each failing adopted slot. `--baseline` (step 6 / c10) grandfathers a
849
+ * Classify each failing adopted slot. `--baseline` grandfathers a
629
850
  * failing *fingerprintable* slot (kept enabled; the baseline masks its debt and
630
851
  * the ratchet carries the cleanup); a failing slot with no extractor can't be
631
852
  * grandfathered, so it still falls back to a `false` disable. Without
@@ -652,7 +873,7 @@ async function captureBaselineIfNeeded(options, cwd, grandfathered, dryRun) {
652
873
  }
653
874
  /**
654
875
  * Write checkride.config.json for the adopted tools (disabled failures as
655
- * `false`) plus the publish-ready bundle (step 9); never clobber an existing one.
876
+ * `false`) plus the publish-ready bundle; never clobber an existing one.
656
877
  */
657
878
  async function writeExistingConfig(w, cwd, adopted, disabledSet, bundleChecks, skipped) {
658
879
  if (existsSync(join(cwd, 'checkride.config.json'))) {
@@ -667,7 +888,7 @@ async function writeExistingConfig(w, cwd, adopted, disabledSet, bundleChecks, s
667
888
  checks[i.slot] = i.adapter;
668
889
  }
669
890
  // The opt-in publish bundle follows the adopted default slots; explicit
670
- // entries opt these slots into the run (D4 — the library orders itself).
891
+ // entries opt these slots into the run (the library orders itself).
671
892
  for (const [slot, adapter] of Object.entries(bundleChecks))
672
893
  checks[slot] = adapter;
673
894
  const config = { $schema: configSchemaUrl(productVersion()), checks };
@@ -708,7 +929,7 @@ function reportExisting(stdout, adopted, w, grandfathered, disabled) {
708
929
  }
709
930
  }
710
931
  /**
711
- * Plan the publish-ready bundle (step 9) for existing-repo init. Only meaningful
932
+ * Plan the publish-ready bundle for existing-repo init. Only meaningful
712
933
  * when a config will actually be written: `writeExistingConfig` never clobbers an
713
934
  * existing `checkride.config.json`, so an existing config means the bundle has
714
935
  * nowhere to land. The bundle is scaffolded *enabled* — not probed/disabled like
@@ -733,8 +954,12 @@ async function initExisting(options, cwd) {
733
954
  const adapters = options.adapters ?? ADAPTERS;
734
955
  const slots = options.slots ?? SLOTS;
735
956
  const manifest = readInitManifest(cwd);
736
- const w = { cwd, dryRun: options.dryRun ?? false, written: [] };
957
+ const w = { cwd, dryRun: options.dryRun ?? false, written: [], removed: [] };
737
958
  const skipped = [];
959
+ const pm = detectPackageManager({ cwd });
960
+ // Before the first write: a stanza this repo has customized stops the run
961
+ // rather than being clobbered by the refresh below.
962
+ await assertStanzaUnedited(cwd, buildStanza(activeCheckSlots(cwd, slots, adapters), pm), options);
738
963
  // Route --add: publish slots (and the library path) opt into the bundle; the
739
964
  // rest scaffold blessed configs before inventory, so they're detected this run.
740
965
  const { publishRequested, fileAdds } = splitAdd(options.add ?? [], manifest);
@@ -746,24 +971,35 @@ async function initExisting(options, cwd) {
746
971
  const failing = new Set(await probe(adopted.map((i) => i.slot), cwd));
747
972
  const { grandfathered, disabled } = resolveAdoptionPlan(adopted, failing, options.baseline ?? false);
748
973
  await captureBaselineIfNeeded(options, cwd, grandfathered, w.dryRun);
749
- // Publish-ready bundle (step 9): planned only when a config will be written.
974
+ // Publish-ready bundle: planned only when a config will be written.
750
975
  const bundle = await planInitBundle(publishRequested, manifest, cwd);
751
976
  if (bundle.snippetsPointer)
752
977
  skipped.push(bundle.snippetsPointer);
753
978
  await writeExistingConfig(w, cwd, adopted, new Set(disabled), bundle.checks, skipped);
754
979
  await ensureGitignore(w, cwd, skipped);
755
- // package.json: add the `check: checkride` alias (decision 8) if missing.
980
+ // package.json: add the `check: checkride` alias if missing.
756
981
  await addCheckAlias(w, skipped);
757
- // AGENTS.md stanza (create or refresh, idempotent).
758
- await writeAgentsStanza(w, cwd, adopted.map((i) => i.slot), skipped);
982
+ // AGENTS.md stanza (create or refresh, idempotent), derived from the config
983
+ // written above so it reports the gate as configured, not as detected.
984
+ await writeAgentsStanza(w, cwd, activeCheckSlots(cwd, slots, adapters), pm, skipped);
759
985
  await writeClaudePointer(w, cwd, skipped);
760
- // Claude Code Stop hook (opt-out; step 12), using the repo's detected PM (b7).
761
- await writeHook(w, options.hook, skipped);
986
+ // Claude Code Stop hook (opt-out), using the repo's detected PM.
987
+ await writeHook(w, options, skipped);
988
+ await writeSkills(w, options, skipped);
762
989
  if (options.stdout) {
763
990
  reportExisting(options.stdout, adopted, w, grandfathered, disabled);
764
991
  reportInitBundle(options.stdout, bundle);
765
992
  }
766
- return { mode: 'existing', shape: null, written: w.written, skipped, disabled, grandfathered, exitCode: 0 };
993
+ return {
994
+ mode: 'existing',
995
+ shape: null,
996
+ written: w.written,
997
+ removed: w.removed,
998
+ skipped,
999
+ disabled,
1000
+ grandfathered,
1001
+ exitCode: 0,
1002
+ };
767
1003
  }
768
1004
  // ----------------------------------------------------------------------------
769
1005
  // Entry
@@ -780,25 +1016,32 @@ export async function runInit(options) {
780
1016
  /**
781
1017
  * `checkride agent-setup` — wire the agent contract into an *existing* repo
782
1018
  * without a full `init`: the `check` alias the hook resolves to, the AGENTS.md
783
- * stanza (the human-readable contract), and the Claude Code Stop hook (the
784
- * mechanical gate). Every write is additive and idempotent — a second run is a
785
- * no-op — and the hook is opt-out (`hook: false`).
1019
+ * stanza (the human-readable contract), the stop-gate hooks for every detected
1020
+ * harness (the mechanical gate), and the skills a harness cannot get from the
1021
+ * bundled plugin. Every write is additive and idempotent — a second run is a
1022
+ * no-op — and the hooks are opt-out (`hook: false`).
786
1023
  */
787
1024
  export async function runAgentSetup(options) {
788
1025
  const cwd = options.cwd ?? process.cwd();
789
1026
  const slots = options.slots ?? SLOTS;
790
1027
  const adapters = options.adapters ?? ADAPTERS;
791
- const w = { cwd, dryRun: options.dryRun ?? false, written: [] };
1028
+ const w = { cwd, dryRun: options.dryRun ?? false, written: [], removed: [] };
792
1029
  const skipped = [];
1030
+ const stanzaSlots = activeCheckSlots(cwd, slots, adapters);
1031
+ const pm = detectPackageManager({ cwd });
1032
+ // Before the first write: a stanza this repo has customized stops the run
1033
+ // rather than being clobbered by the refresh below.
1034
+ await assertStanzaUnedited(cwd, buildStanza(stanzaSlots, pm), options);
793
1035
  // The `check` alias the hook's `<pm> run check` resolves to (never clobbers).
794
1036
  await addCheckAlias(w, skipped);
795
- // AGENTS.md stanza for the currently-adopted slots (create or refresh).
796
- const adopted = inventory({ cwd, slots, adapters }).filter((i) => i.status === 'adopted');
797
- await writeAgentsStanza(w, cwd, adopted.map((i) => i.slot), skipped);
798
- await writeHook(w, options.hook, skipped);
1037
+ // AGENTS.md stanza for the checks the default run selects (create or refresh).
1038
+ await writeAgentsStanza(w, cwd, stanzaSlots, pm, skipped);
1039
+ await writeHook(w, options, skipped);
1040
+ await writeSkills(w, options, skipped);
799
1041
  if (options.stdout) {
800
- options.stdout.write(`checkride agent-setup: wrote ${w.written.length} file(s)${w.dryRun ? ' [dry run]' : ''}.\n`);
1042
+ const removed = w.removed.length > 0 ? `, removed ${w.removed.length}` : '';
1043
+ options.stdout.write(`checkride agent-setup: wrote ${w.written.length} file(s)${removed}${w.dryRun ? ' [dry run]' : ''}.\n`);
801
1044
  }
802
- return { written: w.written, skipped, exitCode: 0 };
1045
+ return { written: w.written, removed: w.removed, skipped, exitCode: 0 };
803
1046
  }
804
1047
  //# sourceMappingURL=init.js.map