@vibe-agent-toolkit/cli 0.2.0-rc.7 → 0.2.0-rc.9

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 (395) hide show
  1. package/README.md +0 -1
  2. package/dist/bin/vat +34 -19
  3. package/dist/bin/vat.js +34 -19
  4. package/dist/bin/vat.js.map +1 -1
  5. package/dist/bin.js +5 -2
  6. package/dist/bin.js.map +1 -1
  7. package/dist/commands/agent/build.d.ts.map +1 -1
  8. package/dist/commands/agent/build.js +2 -1
  9. package/dist/commands/agent/build.js.map +1 -1
  10. package/dist/commands/agent/import.d.ts.map +1 -1
  11. package/dist/commands/agent/import.js +3 -2
  12. package/dist/commands/agent/import.js.map +1 -1
  13. package/dist/commands/agent/install-path.d.ts +36 -0
  14. package/dist/commands/agent/install-path.d.ts.map +1 -0
  15. package/dist/commands/agent/install-path.js +44 -0
  16. package/dist/commands/agent/install-path.js.map +1 -0
  17. package/dist/commands/agent/install.d.ts.map +1 -1
  18. package/dist/commands/agent/install.js +22 -10
  19. package/dist/commands/agent/install.js.map +1 -1
  20. package/dist/commands/agent/installed.d.ts.map +1 -1
  21. package/dist/commands/agent/installed.js +22 -12
  22. package/dist/commands/agent/installed.js.map +1 -1
  23. package/dist/commands/agent/list.d.ts.map +1 -1
  24. package/dist/commands/agent/list.js +2 -1
  25. package/dist/commands/agent/list.js.map +1 -1
  26. package/dist/commands/agent/run.d.ts.map +1 -1
  27. package/dist/commands/agent/run.js +2 -1
  28. package/dist/commands/agent/run.js.map +1 -1
  29. package/dist/commands/agent/uninstall.d.ts.map +1 -1
  30. package/dist/commands/agent/uninstall.js +13 -6
  31. package/dist/commands/agent/uninstall.js.map +1 -1
  32. package/dist/commands/agent/validate.d.ts.map +1 -1
  33. package/dist/commands/agent/validate.js +3 -2
  34. package/dist/commands/agent/validate.js.map +1 -1
  35. package/dist/commands/ard/emit.d.ts +72 -23
  36. package/dist/commands/ard/emit.d.ts.map +1 -1
  37. package/dist/commands/ard/emit.js +109 -56
  38. package/dist/commands/ard/emit.js.map +1 -1
  39. package/dist/commands/ard/index.d.ts +1 -1
  40. package/dist/commands/ard/index.d.ts.map +1 -1
  41. package/dist/commands/ard/index.js +4 -3
  42. package/dist/commands/ard/index.js.map +1 -1
  43. package/dist/commands/audit/distributed-tree.d.ts.map +1 -1
  44. package/dist/commands/audit/distributed-tree.js +9 -6
  45. package/dist/commands/audit/distributed-tree.js.map +1 -1
  46. package/dist/commands/audit/provenance.d.ts.map +1 -1
  47. package/dist/commands/audit/provenance.js +4 -3
  48. package/dist/commands/audit/provenance.js.map +1 -1
  49. package/dist/commands/audit/scan-population.d.ts +158 -0
  50. package/dist/commands/audit/scan-population.d.ts.map +1 -0
  51. package/dist/commands/audit/scan-population.js +292 -0
  52. package/dist/commands/audit/scan-population.js.map +1 -0
  53. package/dist/commands/audit-settings.d.ts.map +1 -1
  54. package/dist/commands/audit-settings.js +6 -5
  55. package/dist/commands/audit-settings.js.map +1 -1
  56. package/dist/commands/audit.d.ts +16 -14
  57. package/dist/commands/audit.d.ts.map +1 -1
  58. package/dist/commands/audit.js +304 -389
  59. package/dist/commands/audit.js.map +1 -1
  60. package/dist/commands/build.d.ts.map +1 -1
  61. package/dist/commands/build.js +25 -24
  62. package/dist/commands/build.js.map +1 -1
  63. package/dist/commands/cache/clear.d.ts +17 -3
  64. package/dist/commands/cache/clear.d.ts.map +1 -1
  65. package/dist/commands/cache/clear.js +34 -13
  66. package/dist/commands/cache/clear.js.map +1 -1
  67. package/dist/commands/cache/index.d.ts.map +1 -1
  68. package/dist/commands/cache/index.js +19 -10
  69. package/dist/commands/cache/index.js.map +1 -1
  70. package/dist/commands/claude/context.d.ts +2 -2
  71. package/dist/commands/claude/context.d.ts.map +1 -1
  72. package/dist/commands/claude/context.js +7 -6
  73. package/dist/commands/claude/context.js.map +1 -1
  74. package/dist/commands/claude/index.d.ts +12 -11
  75. package/dist/commands/claude/index.d.ts.map +1 -1
  76. package/dist/commands/claude/index.js +14 -16
  77. package/dist/commands/claude/index.js.map +1 -1
  78. package/dist/commands/claude/marketplace/changelog-utils.d.ts +1 -1
  79. package/dist/commands/claude/marketplace/changelog-utils.d.ts.map +1 -1
  80. package/dist/commands/claude/marketplace/changelog-utils.js +1 -2
  81. package/dist/commands/claude/marketplace/changelog-utils.js.map +1 -1
  82. package/dist/commands/claude/marketplace/git-publish.d.ts.map +1 -1
  83. package/dist/commands/claude/marketplace/git-publish.js +22 -12
  84. package/dist/commands/claude/marketplace/git-publish.js.map +1 -1
  85. package/dist/commands/claude/marketplace/license-utils.d.ts.map +1 -1
  86. package/dist/commands/claude/marketplace/license-utils.js +0 -1
  87. package/dist/commands/claude/marketplace/license-utils.js.map +1 -1
  88. package/dist/commands/claude/marketplace/publish-tree.d.ts.map +1 -1
  89. package/dist/commands/claude/marketplace/publish-tree.js +0 -6
  90. package/dist/commands/claude/marketplace/publish-tree.js.map +1 -1
  91. package/dist/commands/claude/marketplace/publish.d.ts.map +1 -1
  92. package/dist/commands/claude/marketplace/publish.js +2 -1
  93. package/dist/commands/claude/marketplace/publish.js.map +1 -1
  94. package/dist/commands/claude/marketplace/validate.d.ts.map +1 -1
  95. package/dist/commands/claude/marketplace/validate.js +26 -16
  96. package/dist/commands/claude/marketplace/validate.js.map +1 -1
  97. package/dist/commands/claude/org/api-keys.d.ts +0 -3
  98. package/dist/commands/claude/org/api-keys.d.ts.map +1 -1
  99. package/dist/commands/claude/org/api-keys.js +2 -1
  100. package/dist/commands/claude/org/api-keys.js.map +1 -1
  101. package/dist/commands/claude/org/helpers.d.ts +17 -22
  102. package/dist/commands/claude/org/helpers.d.ts.map +1 -1
  103. package/dist/commands/claude/org/helpers.js +6 -22
  104. package/dist/commands/claude/org/helpers.js.map +1 -1
  105. package/dist/commands/claude/org/invites.d.ts +0 -3
  106. package/dist/commands/claude/org/invites.d.ts.map +1 -1
  107. package/dist/commands/claude/org/invites.js +3 -2
  108. package/dist/commands/claude/org/invites.js.map +1 -1
  109. package/dist/commands/claude/org/skills.d.ts +19 -1
  110. package/dist/commands/claude/org/skills.d.ts.map +1 -1
  111. package/dist/commands/claude/org/skills.js +147 -111
  112. package/dist/commands/claude/org/skills.js.map +1 -1
  113. package/dist/commands/claude/org/users.d.ts +0 -3
  114. package/dist/commands/claude/org/users.d.ts.map +1 -1
  115. package/dist/commands/claude/org/users.js +3 -2
  116. package/dist/commands/claude/org/users.js.map +1 -1
  117. package/dist/commands/claude/org/workspaces.d.ts +0 -3
  118. package/dist/commands/claude/org/workspaces.d.ts.map +1 -1
  119. package/dist/commands/claude/org/workspaces.js +6 -5
  120. package/dist/commands/claude/org/workspaces.js.map +1 -1
  121. package/dist/commands/claude/plugin/build.d.ts.map +1 -1
  122. package/dist/commands/claude/plugin/build.js +23 -52
  123. package/dist/commands/claude/plugin/build.js.map +1 -1
  124. package/dist/commands/claude/plugin/helpers.d.ts.map +1 -1
  125. package/dist/commands/claude/plugin/helpers.js +0 -6
  126. package/dist/commands/claude/plugin/helpers.js.map +1 -1
  127. package/dist/commands/claude/plugin/install.d.ts +12 -0
  128. package/dist/commands/claude/plugin/install.d.ts.map +1 -1
  129. package/dist/commands/claude/plugin/install.js +71 -60
  130. package/dist/commands/claude/plugin/install.js.map +1 -1
  131. package/dist/commands/claude/plugin/list.d.ts.map +1 -1
  132. package/dist/commands/claude/plugin/list.js +3 -2
  133. package/dist/commands/claude/plugin/list.js.map +1 -1
  134. package/dist/commands/claude/plugin/plugin-changelog.d.ts.map +1 -1
  135. package/dist/commands/claude/plugin/plugin-changelog.js +0 -2
  136. package/dist/commands/claude/plugin/plugin-changelog.js.map +1 -1
  137. package/dist/commands/claude/plugin/plugin-files.d.ts.map +1 -1
  138. package/dist/commands/claude/plugin/plugin-files.js +3 -6
  139. package/dist/commands/claude/plugin/plugin-files.js.map +1 -1
  140. package/dist/commands/claude/plugin/plugin-validators.d.ts.map +1 -1
  141. package/dist/commands/claude/plugin/plugin-validators.js +3 -6
  142. package/dist/commands/claude/plugin/plugin-validators.js.map +1 -1
  143. package/dist/commands/claude/plugin/tree-copy.d.ts +2 -1
  144. package/dist/commands/claude/plugin/tree-copy.d.ts.map +1 -1
  145. package/dist/commands/claude/plugin/tree-copy.js +15 -14
  146. package/dist/commands/claude/plugin/tree-copy.js.map +1 -1
  147. package/dist/commands/claude/plugin/uninstall.d.ts.map +1 -1
  148. package/dist/commands/claude/plugin/uninstall.js +4 -4
  149. package/dist/commands/claude/plugin/uninstall.js.map +1 -1
  150. package/dist/commands/consistency-check.d.ts +17 -15
  151. package/dist/commands/consistency-check.d.ts.map +1 -1
  152. package/dist/commands/consistency-check.js +149 -104
  153. package/dist/commands/consistency-check.js.map +1 -1
  154. package/dist/commands/corpus/report.d.ts.map +1 -1
  155. package/dist/commands/corpus/report.js +1 -2
  156. package/dist/commands/corpus/report.js.map +1 -1
  157. package/dist/commands/corpus/runner.d.ts.map +1 -1
  158. package/dist/commands/corpus/runner.js +2 -6
  159. package/dist/commands/corpus/runner.js.map +1 -1
  160. package/dist/commands/corpus/scan.d.ts.map +1 -1
  161. package/dist/commands/corpus/scan.js +2 -3
  162. package/dist/commands/corpus/scan.js.map +1 -1
  163. package/dist/commands/corpus/seed.d.ts +4 -4
  164. package/dist/commands/corpus/seed.d.ts.map +1 -1
  165. package/dist/commands/corpus/seed.js +1 -3
  166. package/dist/commands/corpus/seed.js.map +1 -1
  167. package/dist/commands/doctor.d.ts.map +1 -1
  168. package/dist/commands/doctor.js +55 -37
  169. package/dist/commands/doctor.js.map +1 -1
  170. package/dist/commands/inventory.d.ts.map +1 -1
  171. package/dist/commands/inventory.js +6 -7
  172. package/dist/commands/inventory.js.map +1 -1
  173. package/dist/commands/mcp/list-collections.d.ts.map +1 -1
  174. package/dist/commands/mcp/list-collections.js +2 -1
  175. package/dist/commands/mcp/list-collections.js.map +1 -1
  176. package/dist/commands/mcp/serve.d.ts.map +1 -1
  177. package/dist/commands/mcp/serve.js +3 -2
  178. package/dist/commands/mcp/serve.js.map +1 -1
  179. package/dist/commands/okf/index.d.ts.map +1 -1
  180. package/dist/commands/okf/index.js +14 -2
  181. package/dist/commands/okf/index.js.map +1 -1
  182. package/dist/commands/okf/validate.d.ts +157 -48
  183. package/dist/commands/okf/validate.d.ts.map +1 -1
  184. package/dist/commands/okf/validate.js +109 -76
  185. package/dist/commands/okf/validate.js.map +1 -1
  186. package/dist/commands/phase-utils.d.ts +11 -10
  187. package/dist/commands/phase-utils.d.ts.map +1 -1
  188. package/dist/commands/phase-utils.js +30 -14
  189. package/dist/commands/phase-utils.js.map +1 -1
  190. package/dist/commands/positional-args.d.ts.map +1 -1
  191. package/dist/commands/positional-args.js +2 -1
  192. package/dist/commands/positional-args.js.map +1 -1
  193. package/dist/commands/rag/clear-command.d.ts.map +1 -1
  194. package/dist/commands/rag/clear-command.js +2 -1
  195. package/dist/commands/rag/clear-command.js.map +1 -1
  196. package/dist/commands/rag/index-command.d.ts.map +1 -1
  197. package/dist/commands/rag/index-command.js +4 -1
  198. package/dist/commands/rag/index-command.js.map +1 -1
  199. package/dist/commands/rag/query-command.d.ts.map +1 -1
  200. package/dist/commands/rag/query-command.js +2 -1
  201. package/dist/commands/rag/query-command.js.map +1 -1
  202. package/dist/commands/rag/stats-command.d.ts.map +1 -1
  203. package/dist/commands/rag/stats-command.js +2 -1
  204. package/dist/commands/rag/stats-command.js.map +1 -1
  205. package/dist/commands/resources/check-progress.d.ts +6 -0
  206. package/dist/commands/resources/check-progress.d.ts.map +1 -1
  207. package/dist/commands/resources/check-progress.js +15 -4
  208. package/dist/commands/resources/check-progress.js.map +1 -1
  209. package/dist/commands/resources/check-supervisor.d.ts.map +1 -1
  210. package/dist/commands/resources/check-supervisor.js +14 -7
  211. package/dist/commands/resources/check-supervisor.js.map +1 -1
  212. package/dist/commands/resources/check.d.ts +315 -205
  213. package/dist/commands/resources/check.d.ts.map +1 -1
  214. package/dist/commands/resources/check.js +368 -327
  215. package/dist/commands/resources/check.js.map +1 -1
  216. package/dist/commands/resources/index.d.ts.map +1 -1
  217. package/dist/commands/resources/index.js +159 -39
  218. package/dist/commands/resources/index.js.map +1 -1
  219. package/dist/commands/resources/query.d.ts +2 -2
  220. package/dist/commands/resources/query.d.ts.map +1 -1
  221. package/dist/commands/resources/query.js +24 -18
  222. package/dist/commands/resources/query.js.map +1 -1
  223. package/dist/commands/resources/scan.d.ts.map +1 -1
  224. package/dist/commands/resources/scan.js +4 -8
  225. package/dist/commands/resources/scan.js.map +1 -1
  226. package/dist/commands/resources/validate.d.ts +1 -1
  227. package/dist/commands/resources/validate.d.ts.map +1 -1
  228. package/dist/commands/resources/validate.js +0 -1
  229. package/dist/commands/resources/validate.js.map +1 -1
  230. package/dist/commands/skill/review-checklist.d.ts +3 -2
  231. package/dist/commands/skill/review-checklist.d.ts.map +1 -1
  232. package/dist/commands/skill/review-checklist.js +4 -2
  233. package/dist/commands/skill/review-checklist.js.map +1 -1
  234. package/dist/commands/skill/review.d.ts +247 -0
  235. package/dist/commands/skill/review.d.ts.map +1 -1
  236. package/dist/commands/skill/review.js +90 -60
  237. package/dist/commands/skill/review.js.map +1 -1
  238. package/dist/commands/skill/test/configure.d.ts.map +1 -1
  239. package/dist/commands/skill/test/configure.js +0 -1
  240. package/dist/commands/skill/test/configure.js.map +1 -1
  241. package/dist/commands/skill/test/run.d.ts +12 -6
  242. package/dist/commands/skill/test/run.d.ts.map +1 -1
  243. package/dist/commands/skill/test/run.js +120 -65
  244. package/dist/commands/skill/test/run.js.map +1 -1
  245. package/dist/commands/skills/build.d.ts +83 -3
  246. package/dist/commands/skills/build.d.ts.map +1 -1
  247. package/dist/commands/skills/build.js +162 -40
  248. package/dist/commands/skills/build.js.map +1 -1
  249. package/dist/commands/skills/install.d.ts +2 -1
  250. package/dist/commands/skills/install.d.ts.map +1 -1
  251. package/dist/commands/skills/install.js +20 -30
  252. package/dist/commands/skills/install.js.map +1 -1
  253. package/dist/commands/skills/list.d.ts.map +1 -1
  254. package/dist/commands/skills/list.js +14 -18
  255. package/dist/commands/skills/list.js.map +1 -1
  256. package/dist/commands/skills/package.d.ts +1 -1
  257. package/dist/commands/skills/package.d.ts.map +1 -1
  258. package/dist/commands/skills/package.js +6 -8
  259. package/dist/commands/skills/package.js.map +1 -1
  260. package/dist/commands/skills/scope-guard.d.ts.map +1 -1
  261. package/dist/commands/skills/scope-guard.js +2 -4
  262. package/dist/commands/skills/scope-guard.js.map +1 -1
  263. package/dist/commands/skills/shared.d.ts.map +1 -1
  264. package/dist/commands/skills/shared.js +2 -4
  265. package/dist/commands/skills/shared.js.map +1 -1
  266. package/dist/commands/skills/skill-discovery.d.ts +15 -13
  267. package/dist/commands/skills/skill-discovery.d.ts.map +1 -1
  268. package/dist/commands/skills/skill-discovery.js +23 -5
  269. package/dist/commands/skills/skill-discovery.js.map +1 -1
  270. package/dist/commands/skills/source-resolvers.d.ts +15 -0
  271. package/dist/commands/skills/source-resolvers.d.ts.map +1 -1
  272. package/dist/commands/skills/source-resolvers.js +25 -4
  273. package/dist/commands/skills/source-resolvers.js.map +1 -1
  274. package/dist/commands/validate.d.ts +1 -1
  275. package/dist/commands/validate.d.ts.map +1 -1
  276. package/dist/commands/validate.js +39 -14
  277. package/dist/commands/validate.js.map +1 -1
  278. package/dist/commands/verify.d.ts +17 -5
  279. package/dist/commands/verify.d.ts.map +1 -1
  280. package/dist/commands/verify.js +161 -104
  281. package/dist/commands/verify.js.map +1 -1
  282. package/dist/index.d.ts +0 -1
  283. package/dist/index.d.ts.map +1 -1
  284. package/dist/index.js +5 -1
  285. package/dist/index.js.map +1 -1
  286. package/dist/report-schemas.d.ts +45 -0
  287. package/dist/report-schemas.d.ts.map +1 -0
  288. package/dist/report-schemas.js +100 -0
  289. package/dist/report-schemas.js.map +1 -0
  290. package/dist/skill-resolution/classify.js +2 -2
  291. package/dist/skill-resolution/classify.js.map +1 -1
  292. package/dist/skill-resolution/resolve-skill-reference.d.ts.map +1 -1
  293. package/dist/skill-resolution/resolve-skill-reference.js +50 -55
  294. package/dist/skill-resolution/resolve-skill-reference.js.map +1 -1
  295. package/dist/utils/agent-discovery.d.ts.map +1 -1
  296. package/dist/utils/agent-discovery.js +22 -11
  297. package/dist/utils/agent-discovery.js.map +1 -1
  298. package/dist/utils/agent-runner.d.ts.map +1 -1
  299. package/dist/utils/agent-runner.js +0 -1
  300. package/dist/utils/agent-runner.js.map +1 -1
  301. package/dist/utils/claude-context-lens.d.ts +34 -0
  302. package/dist/utils/claude-context-lens.d.ts.map +1 -0
  303. package/dist/utils/claude-context-lens.js +39 -0
  304. package/dist/utils/claude-context-lens.js.map +1 -0
  305. package/dist/utils/command-error.d.ts +63 -62
  306. package/dist/utils/command-error.d.ts.map +1 -1
  307. package/dist/utils/command-error.js +80 -76
  308. package/dist/utils/command-error.js.map +1 -1
  309. package/dist/utils/config-loader.d.ts +2 -1
  310. package/dist/utils/config-loader.d.ts.map +1 -1
  311. package/dist/utils/config-loader.js +3 -6
  312. package/dist/utils/config-loader.js.map +1 -1
  313. package/dist/utils/corpus-target.d.ts +5 -27
  314. package/dist/utils/corpus-target.d.ts.map +1 -1
  315. package/dist/utils/corpus-target.js +7 -33
  316. package/dist/utils/corpus-target.js.map +1 -1
  317. package/dist/utils/help-loader.d.ts.map +1 -1
  318. package/dist/utils/help-loader.js +0 -1
  319. package/dist/utils/help-loader.js.map +1 -1
  320. package/dist/utils/issue-rendering.d.ts +2 -2
  321. package/dist/utils/issue-rendering.js +2 -2
  322. package/dist/utils/optional-backend.d.ts.map +1 -1
  323. package/dist/utils/optional-backend.js +2 -1
  324. package/dist/utils/optional-backend.js.map +1 -1
  325. package/dist/utils/output.d.ts +9 -0
  326. package/dist/utils/output.d.ts.map +1 -1
  327. package/dist/utils/output.js +16 -0
  328. package/dist/utils/output.js.map +1 -1
  329. package/dist/utils/package-json.d.ts +24 -0
  330. package/dist/utils/package-json.d.ts.map +1 -0
  331. package/dist/utils/package-json.js +49 -0
  332. package/dist/utils/package-json.js.map +1 -0
  333. package/dist/utils/project-root-policy.d.ts.map +1 -1
  334. package/dist/utils/project-root-policy.js +0 -2
  335. package/dist/utils/project-root-policy.js.map +1 -1
  336. package/dist/utils/projection-lenses.d.ts +98 -0
  337. package/dist/utils/projection-lenses.d.ts.map +1 -0
  338. package/dist/utils/projection-lenses.js +203 -0
  339. package/dist/utils/projection-lenses.js.map +1 -0
  340. package/dist/utils/projection-query.d.ts +38 -14
  341. package/dist/utils/projection-query.d.ts.map +1 -1
  342. package/dist/utils/projection-query.js +78 -17
  343. package/dist/utils/projection-query.js.map +1 -1
  344. package/dist/utils/projection-store.d.ts +61 -42
  345. package/dist/utils/projection-store.d.ts.map +1 -1
  346. package/dist/utils/projection-store.js +155 -59
  347. package/dist/utils/projection-store.js.map +1 -1
  348. package/dist/utils/relation-limits.d.ts +50 -0
  349. package/dist/utils/relation-limits.d.ts.map +1 -0
  350. package/dist/utils/relation-limits.js +50 -0
  351. package/dist/utils/relation-limits.js.map +1 -0
  352. package/dist/utils/resource-loader.js +2 -2
  353. package/dist/utils/resource-loader.js.map +1 -1
  354. package/dist/utils/skill-discovery.d.ts.map +1 -1
  355. package/dist/utils/skill-discovery.js +2 -1
  356. package/dist/utils/skill-discovery.js.map +1 -1
  357. package/dist/utils/skill-packaging-config.d.ts +63 -1
  358. package/dist/utils/skill-packaging-config.d.ts.map +1 -1
  359. package/dist/utils/skill-packaging-config.js +56 -1
  360. package/dist/utils/skill-packaging-config.js.map +1 -1
  361. package/dist/utils/url-redact.d.ts.map +1 -1
  362. package/dist/utils/url-redact.js +4 -6
  363. package/dist/utils/url-redact.js.map +1 -1
  364. package/dist/utils/user-context-scanner.d.ts.map +1 -1
  365. package/dist/utils/user-context-scanner.js +0 -2
  366. package/dist/utils/user-context-scanner.js.map +1 -1
  367. package/dist/utils/validate-help-files.d.ts.map +1 -1
  368. package/dist/utils/validate-help-files.js +3 -4
  369. package/dist/utils/validate-help-files.js.map +1 -1
  370. package/dist/utils/vat-bin-path.d.ts.map +1 -1
  371. package/dist/utils/vat-bin-path.js +0 -1
  372. package/dist/utils/vat-bin-path.js.map +1 -1
  373. package/dist/version.d.ts.map +1 -1
  374. package/dist/version.js +1 -3
  375. package/dist/version.js.map +1 -1
  376. package/docs/audit.md +44 -53
  377. package/docs/doctor.md +1 -0
  378. package/docs/index.md +18 -10
  379. package/docs/rag.md +0 -1
  380. package/docs/resources.md +0 -1
  381. package/docs/skill-test.md +10 -9
  382. package/docs/skills.md +6 -7
  383. package/package.json +23 -28
  384. package/schemas/ard-emit.json +149 -0
  385. package/schemas/okf-validate.json +170 -0
  386. package/schemas/resources-check.json +229 -0
  387. package/schemas/skill-review.json +230 -0
  388. package/dist/commands/claude/budget.d.ts +0 -170
  389. package/dist/commands/claude/budget.d.ts.map +0 -1
  390. package/dist/commands/claude/budget.js +0 -464
  391. package/dist/commands/claude/budget.js.map +0 -1
  392. package/dist/utils/context-budget-issues.d.ts +0 -108
  393. package/dist/utils/context-budget-issues.d.ts.map +0 -1
  394. package/dist/utils/context-budget-issues.js +0 -280
  395. package/dist/utils/context-budget-issues.js.map +0 -1
@@ -1,181 +1,134 @@
1
1
  /**
2
- * `vat resources check` — run the project's own SQL assertions over its
3
- * resource projection.
4
- *
5
- * ## Why this verb exists when `vat resources query` already runs SQL
6
- *
7
- * A query answers a question once. A question worth asking twice is a rule, and
8
- * a rule that lives in someone's shell history is not enforced — it decays into
9
- * a comment. This verb runs the statements a project wrote into
10
- * `resources.checks`, turns each violating row into an ordinary validation
11
- * finding, and exits non-zero when any of them is an error. That is the whole
12
- * difference, and it is the difference between a tool and a gate.
13
- *
14
- * ## 🔑 A broken check is an ERROR, never a skip
15
- *
16
- * VAT ships no schema version, so a renamed column simply breaks a check's SQL.
17
- * The tempting handling — log it and carry on — is the one thing this must never
18
- * do: a check that stopped running looks exactly like a check that passed, and
19
- * the project keeps reporting green over an assertion nobody is making any more.
20
- * So a statement that will not run is reported as a finding at **error**
21
- * severity, with the columns the projection actually has, and it fails the run.
22
- *
23
- * That report carries its OWN code (`RESOURCE_CHECK_BROKEN`), which no
24
- * `validation.severity` entry can reach. A check's severity override is about how
25
- * bad a VIOLATION is; while the two shared the code `CUSTOM:<name>`, the
26
- * documented way to stand down an inherited check also silenced the news that it
27
- * had stopped checking. See the `catch` in `runChecks`.
28
- *
29
- * ## 🔑 An empty CORPUS is a refusal too, not a pass
30
- *
31
- * The same class one level further out, and the one that shipped. `checksRun` is
32
- * the denominator of RULES; nothing counted the ROWS, so a repository whose
33
- * enumeration came back empty — a broad `.gitignore`, a shallow or sparse CI
34
- * checkout, a root that resolved somewhere else — ran every declared check over
35
- * nothing and reported `status: success` on exit 0 with empty stderr. Population
36
- * declines ignored members rather than flagging them, so the tables held no
37
- * trace of it either.
38
- *
39
- * So the population's size is published (`membersEnumerated`), and a run whose
40
- * checks executed over zero members is an ERROR under the same non-overridable
41
- * code as a broken statement — see {@link emptyCorpusFinding}. A gate that
42
- * asserts nothing over nothing has not passed.
43
- *
44
- * ## 🔑 An unknown `--check` name is a refusal, not an empty pass
45
- *
46
- * The same failure class one flag over: a filter that matched nothing ran nothing
47
- * and exited 0. `requireDeclaredCheck` refuses it before the crawl, naming the
48
- * declared set. A gate that cannot fail is worse than no gate.
49
- *
50
- * ## 🔑 NO checks at all is the same refusal, and the one that shipped longest
51
- *
52
- * A project with a valid config and no `checks:` block reported `status:
53
- * success`, `checksRun: 0`, exit 0 — so DELETING the `checks:` block silently
54
- * deleted the gate and nothing anywhere said so. A gate that checked nothing is
55
- * indistinguishable from a gate that was removed, and the entire argument for
56
- * having these gates is that you never let those two look alike. It is now a
57
- * `RESOURCE_CHECK_BROKEN` error like the other three — see
58
- * {@link noCheckRanFinding}, and `RUN_INTEGRITY_CODE` for why one code
59
- * covers all four. Declaring no checks is a legitimate CHOICE; running a gate
60
- * that can only pass is not, so the remedy is to take the command out of the
61
- * pipeline.
62
- *
63
- * ## 🔑 SQL is the surface a user OPTED IN to, so no BUILT-IN check may be SQL
64
- *
65
- * Every check this verb runs is adopter-declared: {@link checkCommand} reads
66
- * `config?.resources?.checks` and nothing else, and warns loudly when a project
67
- * declares none. There are no built-ins, and the one way to end that quietly is
68
- * to author the first one as SQL. A default-on rule written as a statement makes
69
- * the engine, the projection and the population mandatory for everyone who
70
- * inherits it, without anybody deciding that. So: **built-ins are TypeScript
71
- * predicates over the projection's row model.** SQL stays the two places a user
72
- * asked for it — this verb's declared checks, and `vat resources query`.
73
- *
74
- * ⚠️ The engine today is `node:sqlite`, built into Node, so the thing at stake is
75
- * not an install — it is the POPULATION. On an ~11,700-member adopter tree
76
- * building the projection is **>99.9%** of a check run (16.5 s cold, ~1.3 s from
77
- * the store) against **0.0008–0.004 s** for the statements themselves; see
78
- * `vat-knowledge-resources.md`, which carries that measurement. That is exactly
79
- * the cost "What this does NOT do" below refuses to put on every adopter's
80
- * pre-commit path, and a default-on SQL check would put it there without the
81
- * decision. The INSTALL cost is deferred rather than gone: the open question
82
- * about a columnar engine is a 108 MB platform binding on a published toolkit,
83
- * and this invariant is what keeps that question still answerable either way.
84
- *
85
- * ## 🔑 The DEFAULT check set belongs to the pipeline, not to the config file
86
- *
87
- * A directory with no `vibe-agent-toolkit.config.yaml` must run exactly the same
88
- * default-on checks as one with a config; config only ADDS to that set or
89
- * OVERRIDES a severity in it. This is load-bearing rather than a convenience:
90
- * *"'default-on error' is meaningless as a category if being default-on requires
91
- * a config file to say so."*
92
- *
93
- * It is therefore a constraint on WHERE the defaults live in code, not only on
94
- * what they are. They cannot be defaulted into the parsed config object, because
95
- * an absent config is `undefined` and every default would vanish with it — for
96
- * the project that never wrote one, which is the population the category exists
97
- * for. The rest of VAT already behaves this way and is the shape to match:
98
- * `vat audit` completes its entire scan first and reads config only to apply
99
- * severity overrides, warning and CONTINUING when the file cannot be read; and
100
- * `loadResourcesWithConfig` hands `vat resources validate` a registry whose
101
- * built-in validators run whether `loadConfig` returned a config or nothing.
102
- * This verb has no defaults yet, so the invariant is a rule for the first one —
103
- * and the day it is written is the easiest day to break it.
104
- *
105
- * ## Keeping a TypeScript check and its SQL twin: two good reasons, one trap
106
- *
107
- * The proposal was "write the predicate twice, in TypeScript and in SQL, and run
108
- * whichever is faster". Two thirds of it are worth having.
109
- *
110
- * ✅ **As documentation.** An SQL twin is executable documentation of the row
111
- * model, and strictly better than prose about it: prose can describe a column
112
- * that no longer exists and never say so, while a statement stops compiling —
113
- * which this verb reports as `RESOURCE_CHECK_BROKEN` rather than as a skip.
114
- *
115
- * ✅ **As a differential oracle.** Run both over the frozen corpus and assert
116
- * IDENTICAL findings. That is the only thing which makes a dual implementation
117
- * better than a single one rather than worse: two implementations with no
118
- * mandatory differential test are simply two places for one rule to be wrong.
119
- * Apply it selectively, to genuinely relational checks — done by default, every
120
- * new rule costs three artifacts instead of one.
121
- *
122
- * ⛔ **As a runtime optimizer — rejected, on two INDEPENDENT grounds.** It would
123
- * essentially never choose SQL: `buildResourceProjection` hands the rows back in
124
- * memory before the ephemeral database exists at all, so the TypeScript arm is a
125
- * for-loop over data already in hand, and the SQL arm's whole measured share of a
126
- * run is the 0.0008–0.004 s above. A scheduler would be choosing between two
127
- * arms of the 0.1%. And it reintroduces the dependency through the back door: an
128
- * optimizer that MAY choose SQL means SQL MAY be needed at check time, which for
129
- * anyone shipping the thing is the same as needed. **Optionality is not a
130
- * property you can keep while also letting a scheduler reach for the optional
131
- * thing.**
132
- *
133
- * ## 🔑 Adopter SQL runs UNSANDBOXED on purpose — and contributed SQL is not adopter SQL
134
- *
135
- * What a statement may BE is gated hard, and documented where it is enforced:
136
- * `assertIsQuery` and `detachForeignSchemas` in
137
- * `packages/projection-sqlite/src/store.ts` refuse `ATTACH` and `PRAGMA`, with
138
- * the measured cross-repository leak that motivated both, and CHANGELOG.md's
139
- * `--budget` entry carries why nothing inside this process can interrupt a
140
- * runaway statement. Read those; do not restate them here.
141
- *
142
- * What is written down nowhere else is that everything PAST those gates is
143
- * unsandboxed deliberately. A `.sql` file the adopter points their own config at
144
- * is adopter code, at the same trust boundary as their eslint config: they wrote
145
- * it or they chose to inherit it, and VAT is not the thing standing between a
146
- * project and its own repository.
147
- *
148
- * 🚨 That reasoning covers exactly ONE trust domain, and the rule scoping it is
149
- * the other half: **contributed SQL is a reviewed EXAMPLE, never an
150
- * auto-executed check.** A contribution channel is third-party text, and a
151
- * statement arriving through one has none of the "they chose it" the paragraph
152
- * above rests on. Ship it as documentation an adopter copies into their own
153
- * `resources.checks` deliberately. One paragraph must not be stretched to cover
154
- * both domains.
155
- *
156
- * ## What this does NOT do
157
- *
158
- * It does not fold into `vat resources validate`. That command is on every
159
- * adopter's pre-commit path, and adding a store-backed population to it is a
160
- * cost and a risk that deserves its own decision with its own evidence. Wiring
161
- * this into CI is one line in a workflow; making it unavoidable is not this
162
- * change's call to make.
2
+ * `vat resources check` — run the project's own assertions over its resource
3
+ * projection, as a gate.
4
+ *
5
+ * The invariants this file implements are written down once, in
6
+ * `docs/architecture/cli.md` under "`vat resources check [path]`". Read that
7
+ * before changing anything here; the headlines, so a reader knows when to:
8
+ *
9
+ * - 🔑 **Four ways to check nothing are all refusals**, at error severity under
10
+ * the non-overridable `RESOURCE_CHECK_BROKEN`: a statement that will not run
11
+ * (the `catch` in `runUnits`), a corpus that enumerated empty
12
+ * ({@link emptyCorpusFinding}), a `--check` name nothing declares
13
+ * (`requireKnownCheck`), and not one check executed at all
14
+ * ({@link noCheckRanFinding}, derived in {@link buildCheckOutputData} so an
15
+ * emptied `BUILTIN_CHECKS` cannot publish a clean document).
16
+ * - ⚠️ That last one does NOT make the step always able to fail: the only
17
+ * built-in ships at `info`. Do not invent a second refusal for it — that
18
+ * would refuse the no-config run the default set exists to serve.
19
+ * - 🔑 **No built-in check may be SQL.** {@link checkCommand} reads
20
+ * `config?.resources?.checks` and nothing else for statements; built-ins are
21
+ * TypeScript predicates over the row model, and a built-in's `sqlTwin` is
22
+ * documentation an adopter copies, never executed here.
23
+ * - 🔑 **The default set belongs to the pipeline, not the config file.**
24
+ * `BUILTIN_CHECKS` reaches {@link runProjectChecks} as a REQUIRED `builtins`
25
+ * argument via {@link runOutcome}; nothing on that path reads `config`.
26
+ * - 🚨 **Adopter SQL runs unsandboxed on purpose, and contributed SQL is not
27
+ * adopter SQL** — a contributed statement ships as a reviewed example.
28
+ * - ⛔ A TypeScript/SQL twin is documentation and a differential oracle, never
29
+ * a runtime optimizer to schedule between.
163
30
  */
164
31
  import { performance } from 'node:perf_hooks';
165
- import { issuesFromCheckRows } from '@vibe-agent-toolkit/resources';
166
- import { calculateValidationStatus, countBySeverity, CUSTOM_CHECK_CODE_PREFIX, isCustomCheckCode, } from '@vibe-agent-toolkit/schema';
32
+ import { bindBuiltinChecks, BUILTIN_CHECK_NAMES, issuesFromCheckRows, LIMIT_DIRECTIONS, } from '@vibe-agent-toolkit/resources';
33
+ import { buildReport, CUSTOM_CHECK_CODE_PREFIX, ExitCode, isCustomCheckCode, reportSchema, toFindings, } from '@vibe-agent-toolkit/schema';
167
34
  import { safePath } from '@vibe-agent-toolkit/utils';
168
- import { handleCommandError } from '../../utils/command-error.js';
35
+ import { z } from 'zod';
36
+ import { handleReportCommandError } from '../../utils/command-error.js';
169
37
  import { loadConfigCached } from '../../utils/config-loader.js';
170
38
  import { formatDurationSecs } from '../../utils/duration.js';
171
39
  import { resolveIssueSeverity } from '../../utils/issue-severity.js';
172
40
  import { createLogger } from '../../utils/logger.js';
173
- import { writeJsonOutput, writeStdoutSync, writeYamlOutput } from '../../utils/output.js';
41
+ import { writeStdoutSync, writeStructuredOutput } from '../../utils/output.js';
174
42
  import { assertDirectoryArgument, projectRootOrLoudCwd, projectRootOrNull } from '../../utils/project-root-policy.js';
175
43
  import { withQueriedProjection, } from '../../utils/projection-query.js';
44
+ import { relationBoundsFor } from '../../utils/relation-limits.js';
176
45
  import { nothingCheckedFinding, runIntegrityFinding } from '../../utils/run-integrity.js';
177
46
  import { createProgressWriter, parseProgressLog, unitInFlight, } from './check-progress.js';
178
47
  import { parseBudgetSeconds, requireSupervisableFlags, runsInThisProcess, superviseCheck, withProgressLog, } from './check-supervisor.js';
48
+ /** What one rule cost, as the document publishes it. */
49
+ const PublishedCheckCostSchema = z.object({
50
+ name: z.string(),
51
+ /** Three significant figures, so a 0.4 ms rule serializes as 0.0004 rather than a zero that reads as "not measured". */
52
+ durationSecs: z.number().nonnegative(),
53
+ /** Rows the statement returned. ABSENT, never 0, when the statement did not complete. */
54
+ rows: z.number().int().nonnegative().optional(),
55
+ broken: z.literal(true).optional(),
56
+ /** Present and `true` only for a rule VAT supplied — see {@link CheckCost.builtin}. */
57
+ builtin: z.literal(true).optional(),
58
+ }).strict();
59
+ /**
60
+ * The published copy of {@link relationBoundsFor}'s answer.
61
+ *
62
+ * The registry lists are `readonly` and this document is handed to a serializer,
63
+ * so the arrays are copied rather than referenced — the same rule
64
+ * `lensesEvaluated` follows one field above: a published document owns no
65
+ * reference into the run's own state.
66
+ *
67
+ * @param lensesEvaluated - The lenses this run evaluated
68
+ * @returns The bounds keys to spread, or nothing
69
+ */
70
+ function structuredBounds(lensesEvaluated) {
71
+ const bounds = relationBoundsFor(lensesEvaluated);
72
+ if (bounds.boundsStatement === undefined || bounds.limits === undefined)
73
+ return {};
74
+ return { boundsStatement: bounds.boundsStatement, limits: bounds.limits.map((limit) => ({ ...limit })) };
75
+ }
76
+ /**
77
+ * A signed bound on what the derived rows settle, as `@vibe-agent-toolkit/resources`
78
+ * states it.
79
+ *
80
+ * ⛔ The direction vocabulary is IMPORTED, never respelled: `LIMIT_DIRECTIONS`
81
+ * is the one list, tied to `StatedLimit['direction']` by `satisfies`, so a
82
+ * fifth direction cannot leave this schema quietly rejecting it.
83
+ */
84
+ const StatedLimitSchema = z.object({
85
+ id: z.string(),
86
+ direction: z.enum(LIMIT_DIRECTIONS),
87
+ statement: z.string(),
88
+ }).strict();
89
+ /**
90
+ * What the check run reports beyond its findings.
91
+ *
92
+ * The envelope's `examined` is `membersEnumerated` — what the rules ran
93
+ * AGAINST. `checksRun` is the other denominator, the number of RULES, and both
94
+ * are needed: zero findings is the pass condition and either number at zero
95
+ * makes that pass vacuous.
96
+ */
97
+ export const CheckDataSchema = z.object({
98
+ root: z.string(),
99
+ /** Whether the projection was derived this run or read from the store. */
100
+ population: z.enum(['derived', 'store']),
101
+ /** What the population cost — charged to no check, see `CheckCost`. */
102
+ populationSecs: z.number().nonnegative(),
103
+ /** What evaluating the lenses cost, paid before the first statement ran. */
104
+ lensSecs: z.number().nonnegative(),
105
+ /**
106
+ * Which lenses that covers — the derived relations this run's checks could
107
+ * actually read. 🔑 An empty list says "no check asked for a derived relation"
108
+ * rather than "a lens stopped running"; without it `lensSecs: 0` is the same
109
+ * document either way, and a gate whose rules silently read empty relations is
110
+ * a gate that cannot fail.
111
+ */
112
+ lensesEvaluated: z.array(z.string()),
113
+ /**
114
+ * The prose frame {@link CheckDataSchema.limits} is read under. Present
115
+ * exactly when a lens with stated bounds was evaluated.
116
+ */
117
+ boundsStatement: z.string().optional(),
118
+ /**
119
+ * What the derived rows this run could read do NOT settle — signed and
120
+ * directional, the same list `vat claude context` publishes beside its own
121
+ * answer. Absent when no bounded lens ran: an empty list would claim nothing
122
+ * bounds the answer, which is stronger than "the answer holds no such row".
123
+ */
124
+ limits: z.array(StatedLimitSchema).optional(),
125
+ /** The number of rules that EXECUTED. Derived from `checks`, never carried beside it. */
126
+ checksRun: z.number().int().nonnegative(),
127
+ /** What each rule cost, directly under the denominator it is the breakdown of. */
128
+ checks: z.array(PublishedCheckCostSchema),
129
+ }).strict();
130
+ /** The document this command publishes. */
131
+ export const CHECK_REPORT_SCHEMA = reportSchema(CheckDataSchema);
179
132
  /**
180
133
  * The refusal for a run in which NO check executed.
181
134
  *
@@ -209,22 +162,28 @@ import { parseBudgetSeconds, requireSupervisableFlags, runsInThisProcess, superv
209
162
  * stand-down matters here for an interrupted run, which recovers zero costs when
210
163
  * the kill landed before the first statement finished and already carries
211
164
  * {@link interruptedRunFinding}, the more specific of the two claims. A `--check`
212
- * filter that matched nothing is refused earlier by {@link requireDeclaredCheck},
165
+ * filter that matched nothing is refused earlier by {@link requireKnownCheck},
213
166
  * and must stay refused even if that guard is ever widened.
214
167
  *
168
+ * 🔑 **An absent `checks:` block does not empty the denominator** — the built-in
169
+ * set is in the pipeline, so reaching zero here means not even a default ran and
170
+ * the remedy is not "declare some checks". The guard stays because it is the
171
+ * mechanism-level guarantee that `checksRun: 0` can never be published clean,
172
+ * whatever empties it.
173
+ *
215
174
  * @param costs - One record per check that EXECUTED; its length is `checksRun`
216
175
  * @param issues - What the run already found, so an existing run-integrity
217
176
  * report is not duplicated
218
177
  * @returns The finding, or nothing when at least one check ran
219
178
  */
220
179
  function noCheckRanFinding(costs, issues) {
221
- return nothingCheckedFinding(costs.length, issues, () => 'No check ran, so this document is not a verdict: a gate that checked nothing'
180
+ return nothingCheckedFinding(costs.length, issues, () => 'No check ran at all, so this document is not a verdict: a gate that checked nothing'
222
181
  + ' produces the same report as a gate that was removed, and this run cannot tell'
223
182
  + ' you which happened.'
224
- + ' Declare checks under `resources.checks` in vibe-agent-toolkit.config.yaml —'
225
- + ' each is a description plus one SQL statement selecting the rows that VIOLATE it —'
226
- + ' and if this project deliberately has none, take `vat resources check` out of the'
227
- + ' pipeline rather than leaving a step that can only pass.');
183
+ + ' This is not an absent `resources.checks` block — VAT\'s own built-in checks run'
184
+ + ' whether or not a project declares any, so reaching zero means not even those'
185
+ + ' executed. Re-run with --debug and report it; if the run was filtered, check that'
186
+ + ' --check named a rule this build still ships.');
228
187
  }
229
188
  /**
230
189
  * Build the check report.
@@ -241,7 +200,7 @@ function noCheckRanFinding(costs, issues) {
241
200
  * account for it cannot disagree.
242
201
  *
243
202
  * 🚨 `populationSecs` and the per-check `durationSecs` do not overlap and do not
244
- * sum to `durationSecs`. The population is paid once and shared by every check;
203
+ * sum to `durationMs`. The population is paid once and shared by every check;
245
204
  * see {@link CheckCost} for why it is charged to none of them.
246
205
  *
247
206
  * 🔑 A denominator of zero is refused HERE rather than published — see
@@ -249,77 +208,76 @@ function noCheckRanFinding(costs, issues) {
249
208
  * passes through, so deriving the refusal in it is what makes "checked nothing,
250
209
  * status clean" unrepresentable rather than merely unwritten.
251
210
  *
211
+ * 🪤 The findings are NOT run through `relativizePathEntries`. Every other
212
+ * payload builder re-bases here because its producer keeps absolute paths
213
+ * internally; these arrive project-relative instead, and re-basing an
214
+ * already-relative path would resolve it against the wrong base and silently
215
+ * corrupt it. The guarantee is `locationOf` in `sql-checks.ts` — the one place
216
+ * a projection column becomes a finding's `location`, and which refuses an
217
+ * absolute or backslashed value there. Nothing on this path parses findings
218
+ * through the schema at runtime, and do not "fix" that by parsing at this
219
+ * boundary: it would convert a slip in `locationOf` from "this finding loses
220
+ * its anchor" into "the whole run throws", which is strictly worse for a gate.
221
+ *
252
222
  * @param input - The findings and the provenance of the run behind them
253
223
  * @returns The document to serialize
254
224
  */
255
225
  export function buildCheckOutputData(input) {
256
226
  const issues = [...noCheckRanFinding(input.costs, input.issues), ...input.issues];
257
- return {
258
- status: calculateValidationStatus(issues),
259
- root: input.root,
260
- population: input.population,
261
- // Beside the origin, because a `population: store` a reader cannot price is
262
- // a label taken on faith. Charged to no check — see {@link CheckCost}.
263
- populationSecs: formatDurationSecs(input.populationMs),
264
- // Published here too, and not only by `query`, because this verb pays it
265
- // identically — the lens is evaluated before the first statement runs. A
266
- // document that priced the population but not the lens would attribute the
267
- // lens's cost to whichever rule the reader happened to be looking at, which
268
- // is the same defect `populationSecs` exists to prevent.
269
- lensSecs: formatDurationSecs(input.lensMs),
270
- // The denominator. See above: without it an empty findings list is
271
- // ambiguous. Derived from `checks`, never carried beside it.
272
- checksRun: input.costs.length,
227
+ return buildReport({
273
228
  // The OTHER denominator, and the one whose absence shipped a green gate over
274
229
  // an empty repository. `checksRun` counts rules; this counts what they ran
275
- // against. Both are needed, because zero findings is the pass condition and
276
- // either number at zero makes that pass vacuous.
277
- membersEnumerated: input.membersEnumerated,
278
- issueCounts: countBySeverity(issues),
279
- durationSecs: formatDurationSecs(input.durationMs),
280
- // What each rule cost, directly under the total it is a breakdown of. A SQL
281
- // surface is an unbounded cost — a project can declare a statement that
282
- // scans every row of every table — and a single total attributes nothing:
283
- // ten seconds is one expensive rule, a slow population, or forty cheap
284
- // rules, and only this list tells them apart.
285
- //
286
- // 🪤 `rows` and `broken` are spread conditionally rather than defaulted.
287
- // `rows: 0` on a statement that never returned would read as a clean pass,
288
- // which is the exact confusion `RESOURCE_CHECK_BROKEN` exists to prevent —
289
- // so a check that threw publishes no row count at all.
290
- checks: input.costs.map((cost) => ({
291
- name: cost.name,
292
- // Three significant figures, so a 0.4 ms rule serializes as 0.0004 rather
293
- // than rounding to a zero that reads as "not measured".
294
- durationSecs: formatDurationSecs(cost.durationMs),
295
- ...(cost.rows === undefined ? {} : { rows: cost.rows }),
296
- ...(cost.broken === undefined ? {} : { broken: cost.broken }),
297
- })),
298
- // 🪤 NOT run through `relativizePathEntries`. Every other payload builder
299
- // re-bases here because its producer keeps absolute paths internally; these
300
- // arrive project-relative instead, and re-basing an already-relative path
301
- // would resolve it against the wrong base and silently corrupt it.
302
- //
303
- // 🪤 The guarantee is `locationOf` in `sql-checks.ts` — the one place a
304
- // projection column becomes a finding's `location`, and which refuses an
305
- // absolute or backslashed value there. It is NOT the type: nothing on this
306
- // path parses issues through `ValidationIssueSchema` (this module imports the
307
- // `ValidationIssue` TYPE only, and the schema's sole consumers are in
308
- // `packages/schema/test/`), so the refinement is documentation here rather
309
- // than enforcement. Do not "fix" that by parsing at this boundary: it would
310
- // convert a slip in `locationOf` from "this finding loses its anchor" into
311
- // "the whole run throws", which is strictly worse for a gate.
312
- //
313
- // A finding may also carry no path at all (an aggregate check has no file to
314
- // name), which `PathEntry` cannot represent — one more reason this list is
315
- // not that shape.
316
- issues: issues.map((issue) => ({
317
- code: issue.code,
318
- severity: issue.severity,
319
- message: issue.message,
320
- ...(issue.location === undefined ? {} : { path: issue.location }),
321
- })),
322
- };
230
+ // against.
231
+ examined: input.membersEnumerated,
232
+ findings: toFindings(issues),
233
+ durationMs: input.durationMs,
234
+ data: {
235
+ root: input.root,
236
+ population: input.population,
237
+ // Beside the origin, because a `population: store` a reader cannot price is
238
+ // a label taken on faith. Charged to no check — see {@link CheckCost}.
239
+ populationSecs: formatDurationSecs(input.populationMs),
240
+ // Published here too, and not only by `query`, because this verb pays it
241
+ // identically — the lens is evaluated before the first statement runs. A
242
+ // document that priced the population but not the lens would attribute the
243
+ // lens's cost to whichever rule the reader happened to be looking at, which
244
+ // is the same defect `populationSecs` exists to prevent.
245
+ lensSecs: formatDurationSecs(input.lensMs),
246
+ // What that number covers — see `CheckDataSchema.lensesEvaluated`. Copied
247
+ // into a plain array so the published document owns no reference into the
248
+ // run's own state.
249
+ lensesEvaluated: [...input.lensesEvaluated],
250
+ // The bounds of the rows those lenses produced, stated ONCE and only when
251
+ // a bounded lens ran. This is the verb an adopter makes GATE, so it is the
252
+ // one that most owes them — `utils/relation-limits.ts` carries why.
253
+ // Copied out of the readonly registry lists: the published document owns
254
+ // no reference into module state a later render could mutate.
255
+ ...structuredBounds(input.lensesEvaluated),
256
+ // The denominator of rules. Derived from `checks`, never carried beside it.
257
+ checksRun: input.costs.length,
258
+ // What each rule cost, directly under the denominator it is a breakdown
259
+ // of. A SQL surface is an unbounded cost — a project can declare a
260
+ // statement that scans every row of every table — and a single total
261
+ // attributes nothing: ten seconds is one expensive rule, a slow
262
+ // population, or forty cheap rules, and only this list tells them apart.
263
+ //
264
+ // 🪤 `rows` and `broken` are spread conditionally rather than defaulted.
265
+ // `rows: 0` on a statement that never returned would read as a clean pass,
266
+ // which is the exact confusion `RESOURCE_CHECK_BROKEN` exists to prevent —
267
+ // so a check that threw publishes no row count at all.
268
+ checks: input.costs.map((cost) => ({
269
+ name: cost.name,
270
+ // Three significant figures, so a 0.4 ms rule serializes as 0.0004 rather
271
+ // than rounding to a zero that reads as "not measured".
272
+ durationSecs: formatDurationSecs(cost.durationMs),
273
+ ...(cost.rows === undefined ? {} : { rows: cost.rows }),
274
+ ...(cost.broken === undefined ? {} : { broken: cost.broken }),
275
+ // Absent, never `false`, on a declared rule — so the key's presence is
276
+ // the whole claim and a reader never has to tell `false` from unset.
277
+ ...(cost.builtin === undefined ? {} : { builtin: cost.builtin }),
278
+ })),
279
+ },
280
+ });
323
281
  }
324
282
  /**
325
283
  * Run a thunk between two readings of the clock, and report both.
@@ -380,7 +338,7 @@ function timed(now, run) {
380
338
  *
381
339
  * 🪤 Only `ask` reaches this. Turning the selected rows INTO findings is not a
382
340
  * statement failure, and reporting it as one told the operator a working rule
383
- * was broken — see the append in {@link runChecks}.
341
+ * was broken — see the append in {@link runUnits}.
384
342
  *
385
343
  * @param name - The check's key in `resources.checks`
386
344
  * @param error - Whatever the statement threw
@@ -391,48 +349,85 @@ function brokenCheckFinding(name, error) {
391
349
  + (error instanceof Error ? error.message : String(error)));
392
350
  }
393
351
  /**
394
- * Run every declared check, collect its findings, and price it.
395
- *
396
- * ## What the clock measures, and what it must not
397
- *
398
- * The span is `ask(check.sql)` and nothing else — structurally, because it is
399
- * the thunk handed to {@link timed}, which exists for that reason and documents
400
- * the mutation that proved an inline stopwatch unguardable. Everything before
401
- * the loop — the git tracker, `buildResourceProjection`, loading the ephemeral
402
- * database — is paid ONCE for all of them and reaches the document as
403
- * `populationSecs`; see {@link CheckCost} for why charging it here would be a
404
- * lie in N places.
405
- *
406
- * ⚠️ `performance.now()`, never `Date.now()`. A rule over a small projection is
407
- * routinely sub-millisecond, and a millisecond-granularity clock reports every
408
- * one of them as `0` — which reads as "not measured" and makes the whole
409
- * attribution worthless exactly where it is cheapest to get right.
410
- *
411
- * 🪤 Exactly one cost record per executed check, on both paths, because
412
- * `checksRun` is this list's length. The record is filed before the rows become
413
- * findings, so nothing between the two can leave a check unpriced.
414
- *
415
- * ## 🚨 Why the loop announces itself before it can be stopped
416
- *
417
- * {@link ProgressSink} is told a check is about to run, and told again when it
418
- * is priced. That ordering is not decoration: this verb runs adopter-authored
419
- * SQL unattended, an accidental cross join or an unterminated `WITH RECURSIVE`
420
- * runs forever, and NOTHING in-process can interrupt it — the query is
421
- * synchronous, it holds the event loop, and `node:sqlite` exposes no interrupt.
422
- * The supervisor's only lever is an external `SIGKILL`, which publishes nothing
423
- * of the killed process's memory. So the name of the rule that hangs has to be
424
- * on disk BEFORE it is entered, or it is not recoverable at all.
352
+ * One declared statement, as a unit.
425
353
  *
354
+ * @param name - The check's key in `resources.checks`
355
+ * @param check - Its declaration
356
+ * @param ask - Runs one statement against the populated projection
357
+ * @returns The runnable unit
358
+ */
359
+ function sqlCheckUnit(name, check, ask) {
360
+ return {
361
+ name,
362
+ select: () => {
363
+ const rows = ask(check.sql);
364
+ return { rows: rows.length, report: () => issuesFromCheckRows(name, check, rows) };
365
+ },
366
+ };
367
+ }
368
+ /**
369
+ * One built-in predicate, as a unit.
370
+ *
371
+ * 🪤 Its `rows` is the finding count, and that is the same quantity a statement
372
+ * reports: one finding per violating row. There is no conversion step to leave
373
+ * outside the clock, so the whole predicate is timed.
374
+ *
375
+ * @param builtin - The built-in, already bound to this run's projection
376
+ * @returns The runnable unit
377
+ */
378
+ function builtinCheckUnit(builtin) {
379
+ return {
380
+ name: builtin.name,
381
+ builtin: true,
382
+ select: () => {
383
+ const issues = builtin.run();
384
+ return { rows: issues.length, report: () => issues };
385
+ },
386
+ };
387
+ }
388
+ /**
389
+ * Every check this run will attempt, in the order it will attempt them.
390
+ *
391
+ * 🔑 **Built-ins FIRST, and never interleaved with the declared ones**, so the
392
+ * document's `checks[]` opens with the same rules in the same order for every
393
+ * project and a reader comparing two runs compares like with like.
394
+ *
395
+ * 🪤 A project MAY declare a check whose key equals a built-in's name. Both run,
396
+ * both are priced, `builtin` on the cost record tells them apart, and
397
+ * `--check <name>` selects both. Not refused: a new config error is a breaking
398
+ * change and nothing about the collision is unsafe.
399
+ *
400
+ * @param builtins - The default set, bound to this run's projection
426
401
  * @param checks - The project's `resources.checks`
427
- * @param only - A single check key to run, or undefined for all of them
428
402
  * @param ask - Runs one statement against the populated projection
403
+ * @returns The units, built-ins first
404
+ */
405
+ function checkUnits(builtins, checks, ask) {
406
+ return [
407
+ ...builtins.map((builtin) => builtinCheckUnit(builtin)),
408
+ ...Object.entries(checks).map(([name, check]) => sqlCheckUnit(name, check, ask)),
409
+ ];
410
+ }
411
+ /**
412
+ * Run every unit, collect its findings, and price it.
413
+ *
414
+ * 🚨 **The timed span is `unit.select()` and nothing else** — structurally,
415
+ * because it is the thunk handed to {@link timed}. 🚨 **And the loop announces a
416
+ * check BEFORE it can be stopped**, because a runaway statement can only be
417
+ * ended by an external `SIGKILL` that publishes nothing of the killed process's
418
+ * memory. Both, with the clock-granularity and one-record-per-check rules they
419
+ * rest on: `docs/architecture/cli.md`, "The population is charged to NOBODY" and
420
+ * "Why the loop announces a check before it can be stopped".
421
+ *
422
+ * @param units - Every check this run will attempt, built-ins first
423
+ * @param only - A single check name to run, or undefined for all of them
429
424
  * @param now - The clock, in milliseconds; injected so a test can assert an
430
425
  * exact duration rather than a range that passes on a timer that never started
431
426
  * @param onProgress - Told what is about to run and what it cost, or undefined
432
427
  * when nothing is watching (the in-process lane, and `--budget 0`)
433
428
  * @returns The findings, and one cost record per check that ran
434
429
  */
435
- function runChecks(checks, only, ask, now, onProgress) {
430
+ function runUnits(units, only, now, onProgress) {
436
431
  const issues = [];
437
432
  const costs = [];
438
433
  /** File the cost with the observer as well as with the caller — one place. */
@@ -440,23 +435,28 @@ function runChecks(checks, only, ask, now, onProgress) {
440
435
  costs.push(cost);
441
436
  onProgress?.({ kind: 'check', ...cost });
442
437
  };
443
- for (const [name, check] of Object.entries(checks)) {
438
+ for (const unit of units) {
439
+ const { name } = unit;
444
440
  if (only !== undefined && name !== only)
445
441
  continue;
442
+ // Spread onto every cost record this unit files, so the two arms below
443
+ // cannot disagree about which set the rule came from.
444
+ const origin = unit.builtin === undefined ? {} : { builtin: unit.builtin };
446
445
  // 🪤 BEFORE `timed`, and not one line later. `ask` is where a runaway
447
446
  // statement never returns from, so an announcement below it is filed by
448
447
  // every check except the one whose name the operator needs.
449
448
  onProgress?.({ kind: 'start', name });
450
- const outcome = timed(now, () => ask(check.sql));
449
+ const outcome = timed(now, unit.select);
451
450
  if (!outcome.ok) {
452
- // Priced up to the throw, and with NO row count: a statement that did not
451
+ // Priced up to the throw, and with NO row count: a check that did not
453
452
  // complete selected nothing, and `rows: 0` would say it selected nothing
454
- // and passed.
455
- price({ name, durationMs: outcome.durationMs, broken: true });
453
+ // and passed. A built-in reaches this arm too — a defect in VAT's own
454
+ // predicate must fail the gate rather than vanish.
455
+ price({ name, durationMs: outcome.durationMs, broken: true, ...origin });
456
456
  issues.push(brokenCheckFinding(name, outcome.error));
457
457
  continue;
458
458
  }
459
- price({ name, durationMs: outcome.durationMs, rows: outcome.value.length });
459
+ price({ name, durationMs: outcome.durationMs, rows: outcome.value.rows, ...origin });
460
460
  // 🪤 Appended one at a time, NEVER `issues.push(...findings)`. A spread
461
461
  // becomes an ARGUMENT LIST, which throws `RangeError: Maximum call stack
462
462
  // size exceeded` past roughly 125,000 elements on the main thread — and a
@@ -466,44 +466,49 @@ function runChecks(checks, only, ask, now, onProgress) {
466
466
  // the throw landed in the arm above: a rule that ran perfectly was reported
467
467
  // as one that "could not run, so it is asserting nothing". A loop does not
468
468
  // put the argument limit in play at all.
469
- for (const issue of issuesFromCheckRows(name, check, outcome.value))
469
+ for (const issue of outcome.value.report())
470
470
  issues.push(issue);
471
471
  }
472
472
  return { issues, costs };
473
473
  }
474
474
  /**
475
- * Refuse a `--check` name the project does not declare.
475
+ * Refuse a `--check` name that names neither a built-in nor a declared check.
476
476
  *
477
- * 🔑 **An unknown name used to be a silent green.** The filter was a bare
478
- * `if (only !== undefined && name !== only) continue;` and nothing compared the
479
- * flag against the declared keys, so `--check nope` filtered every check away,
480
- * ran none, and exited 0 with `checksRun: 0` and `issues: []` on empty stderr.
481
- * The loud "no checks are declared" warning never fired, because it asks whether
482
- * the `checks` MAP is empty, never whether the FILTER matched anything.
483
- *
484
- * That is not a hypothetical typo: `vat resources check --check orphan-skills`
485
- * is the example in this command's own help text. Rename or delete that check
486
- * and the CI step keeps passing forever while asserting nothing.
477
+ * 🔑 **An unknown name is otherwise a silent green.** With nothing comparing the
478
+ * flag against the known names, `--check nope` filters every check away, runs
479
+ * none, and exits 0 with `checksRun: 0` and `issues: []` on empty stderr — and
480
+ * the "no checks are declared" warning does not fire, because it asks whether
481
+ * the `checks` MAP is empty, never whether the FILTER matched anything. Not a
482
+ * hypothetical typo: rename or delete a check and the CI step keeps passing
483
+ * forever while asserting nothing.
487
484
  *
488
485
  * Thrown rather than reported as a finding, because it is an OPERATOR error and
489
486
  * not a content violation — the two have different exit codes in this command's
490
487
  * contract (2 versus 1) and different audiences. Thrown before the projection is
491
488
  * populated, so a mistyped flag costs no crawl.
492
489
  *
490
+ * 🔑 **A built-in is nameable here exactly like a declared one.** A guard that
491
+ * only knew the config would refuse the very rules that run when there is no
492
+ * config at all. The refusal names both sets.
493
+ *
494
+ * @param builtinNames - The default set's names — {@link BUILTIN_CHECK_NAMES} in
495
+ * production, and passed in rather than imported here so a test can prove the
496
+ * guard rather than restate the constant
493
497
  * @param checks - The project's `resources.checks`
494
498
  * @param only - The `--check` value, or undefined
495
- * @throws When `only` names no declared check
499
+ * @throws When `only` names no check this run would attempt
496
500
  */
497
- export function requireDeclaredCheck(checks, only) {
501
+ export function requireKnownCheck(builtinNames, checks, only) {
498
502
  // 🪤 `Object.hasOwn`, not `only in checks`. `in` walks the prototype chain, so
499
503
  // `--check toString` would have looked declared, matched nothing, and restored
500
504
  // the exact silent green this guard closes.
501
- if (only === undefined || Object.hasOwn(checks, only))
505
+ if (only === undefined || builtinNames.includes(only) || Object.hasOwn(checks, only))
502
506
  return;
503
507
  const declared = Object.keys(checks);
504
- throw new Error(`No check named "${only}" is declared. `
508
+ throw new Error(`No check named "${only}" exists. `
509
+ + `Built in: ${builtinNames.join(', ')}. `
505
510
  + (declared.length === 0
506
- ? 'This project declares none — add them under `resources.checks` in'
511
+ ? 'This project declares none of its own — add them under `resources.checks` in'
507
512
  + ' vibe-agent-toolkit.config.yaml.'
508
513
  : `Declared under \`resources.checks\`: ${declared.join(', ')}.`));
509
514
  }
@@ -511,7 +516,7 @@ export function requireDeclaredCheck(checks, only) {
511
516
  * Name every `CUSTOM:` severity override that overrides nothing.
512
517
  *
513
518
  * 🔑 **The same silent-green shape as an unknown `--check` name, one surface
514
- * over.** {@link requireDeclaredCheck} refuses `--check nope` because a filter
519
+ * over.** {@link requireKnownCheck} refuses `--check nope` because a filter
515
520
  * that matched nothing ran nothing and exited 0. A `validation.severity` entry
516
521
  * keyed `CUSTOM:<name>` for a check that is not declared is the mirror image: it
517
522
  * parses (the schema validates the KEY's shape and cannot see
@@ -544,7 +549,7 @@ export function requireDeclaredCheck(checks, only) {
544
549
  export function warnUndeclaredOverrides(checks, validation, logger) {
545
550
  const stale = Object.keys(validation?.severity ?? {})
546
551
  .filter((code) => isCustomCheckCode(code))
547
- // 🪤 `Object.hasOwn`, not `in` — same reason {@link requireDeclaredCheck}
552
+ // 🪤 `Object.hasOwn`, not `in` — same reason {@link requireKnownCheck}
548
553
  // uses it: `in` walks the prototype chain, so an override keyed
549
554
  // `CUSTOM:toString` would look declared and stay silent.
550
555
  .filter((code) => !Object.hasOwn(checks, code.slice(CUSTOM_CHECK_CODE_PREFIX.length)));
@@ -967,7 +972,7 @@ function noPopulationMessage(ending) {
967
972
  * honest value — and inventing `membersEnumerated: 0` would be worse than a
968
973
  * blank, because that value already MEANS "this gate ran over an empty corpus",
969
974
  * which is a different and wrong claim. The throw becomes an operator error
970
- * (exit 2) through the same `handleCommandError` path everything else here uses.
975
+ * (exit 2) through the same `handleReportCommandError` path everything else here uses.
971
976
  *
972
977
  * @param options - The wreckage
973
978
  * @param options.entries - What `parseProgressLog` recovered
@@ -988,6 +993,7 @@ export function buildInterruptedCheckInput(options) {
988
993
  population: population.population,
989
994
  populationMs: population.populationMs,
990
995
  lensMs: population.lensMs,
996
+ lensesEvaluated: population.lensesEvaluated,
991
997
  membersEnumerated: population.membersEnumerated,
992
998
  issues: [interruptedRunFinding(unitInFlight(entries), ending)],
993
999
  // 🪤 Rebuilt field by field rather than passed through. The log's check
@@ -1000,12 +1006,19 @@ export function buildInterruptedCheckInput(options) {
1000
1006
  durationMs: entry.durationMs,
1001
1007
  ...(entry.rows === undefined ? {} : { rows: entry.rows }),
1002
1008
  ...(entry.broken === undefined ? {} : { broken: entry.broken }),
1009
+ ...(entry.builtin === undefined ? {} : { builtin: entry.builtin }),
1003
1010
  })),
1004
1011
  };
1005
1012
  }
1006
1013
  /**
1007
- * Run the declared checks and resolve their severities — the whole of this
1008
- * verb's logic, with the database taken out.
1014
+ * Run this project's checks — VAT's default set plus whatever the project
1015
+ * declared — and resolve their severities: the whole of this verb's logic, with
1016
+ * the database taken out.
1017
+ *
1018
+ * 🔑 **`builtins` is a required argument beside `checks`, never a default inside
1019
+ * this function.** That is what makes "the default set belongs to the pipeline,
1020
+ * not to the config file" a property of the signature — nobody can get the
1021
+ * defaults by omitting an argument or lose them by supplying no config.
1009
1022
  *
1010
1023
  * Exported and pure so the loop is provable without a spawn. It was not: every
1011
1024
  * spawned case declared ONE check (the `--check` case declares two and filters
@@ -1018,8 +1031,11 @@ export function buildInterruptedCheckInput(options) {
1018
1031
  * trust.
1019
1032
  *
1020
1033
  * @param options - The run
1034
+ * @param options.builtins - The default set, already bound to this run's
1035
+ * projection. Required, and `[]` is a deliberate statement rather than an
1036
+ * omission
1021
1037
  * @param options.checks - The declared checks
1022
- * @param options.only - A single check key, or undefined for all
1038
+ * @param options.only - A single check name, or undefined for all
1023
1039
  * @param options.ask - Runs one statement against the populated projection
1024
1040
  * @param options.validation - The project's severity overrides, or undefined
1025
1041
  * @param options.membersEnumerated - How many members the population enumerated.
@@ -1034,9 +1050,9 @@ export function buildInterruptedCheckInput(options) {
1034
1050
  * unit case run with nobody watching
1035
1051
  * @returns The resolved findings, and one cost record per check that ran
1036
1052
  */
1037
- export function runDeclaredChecks(options) {
1053
+ export function runProjectChecks(options) {
1038
1054
  const now = options.now ?? (() => performance.now());
1039
- const { issues, costs } = runChecks(options.checks, options.only, options.ask, now, options.onProgress);
1055
+ const { issues, costs } = runUnits(checkUnits(options.builtins, options.checks, options.ask), options.only, now, options.onProgress);
1040
1056
  // 🚨 HERE, and this line moved to get here. `checks-complete` buys the phase
1041
1057
  // after the last statement a fresh watchdog window, and three places
1042
1058
  // documented that phase as "resolving severities and serialising". It was
@@ -1047,7 +1063,7 @@ export function runDeclaredChecks(options) {
1047
1063
  // which is the useful direction: the alternative was to weaken three docs.
1048
1064
  //
1049
1065
  // ⚠️ It does NOT cover the last check's row-to-issue conversion, which
1050
- // `runChecks` does after filing that check's cost — see {@link inFlightPhrase}
1066
+ // `runUnits` does after filing that check's cost — see {@link inFlightPhrase}
1051
1067
  // for why the `idle` sentence still has to hedge for that window.
1052
1068
  options.onProgress?.({ kind: 'checks-complete' });
1053
1069
  // The run-integrity report leads. An aggregate check selects a row whatever
@@ -1064,6 +1080,12 @@ export function runDeclaredChecks(options) {
1064
1080
  // It reaches a check's VIOLATIONS only. `RESOURCE_CHECK_BROKEN` is not an
1065
1081
  // overridable code, so the news that a check stopped checking survives every
1066
1082
  // override an adopter can write about the check itself.
1083
+ //
1084
+ // 🔑 A BUILT-IN's findings pass through the identical call, under their
1085
+ // ordinary registry code: `severity: { CLAUDE_RULE_GLOB_INERT: ignore }`
1086
+ // silences the default exactly as it silences any other code VAT emits, with
1087
+ // no `CUSTOM:` spelling and no second override surface. That the two lanes
1088
+ // share this one line is the reason there is nothing to keep in step.
1067
1089
  issues: resolveIssueSeverity(reported, options.validation),
1068
1090
  costs,
1069
1091
  };
@@ -1079,12 +1101,7 @@ export function runDeclaredChecks(options) {
1079
1101
  * @param format - `json`, or anything else for YAML
1080
1102
  */
1081
1103
  function emitCheckDocument(payload, format) {
1082
- if (format === 'json') {
1083
- writeJsonOutput(payload);
1084
- }
1085
- else {
1086
- writeYamlOutput(payload);
1087
- }
1104
+ writeStructuredOutput(payload, format);
1088
1105
  }
1089
1106
  /**
1090
1107
  * The child's argv — this very command, plus the hidden flag that stops it
@@ -1227,26 +1244,31 @@ export async function checkCommand(pathArg, options) {
1227
1244
  process.exit(ending.code);
1228
1245
  }
1229
1246
  emitCheckDocument(ending.payload, options.format);
1230
- // ⛔ Never 0. A run that did not finish — killed by the watchdog OR dead of
1231
- // its own memory — must not look like a pass.
1232
- process.exit(1);
1247
+ // ⛔ Never OK. A run that did not finish — killed by the watchdog OR dead of
1248
+ // its own memory — must not look like a pass. FINDINGS, because the
1249
+ // document it just published says `status: findings` with the killed
1250
+ // check named as one: the checks that completed are kept, and the exit
1251
+ // code follows the document, as everywhere else.
1252
+ process.exit(ExitCode.FINDINGS);
1233
1253
  }
1234
1254
  const projectRoot = projectRootOrLoudCwd(pathArg ?? process.cwd(), logger);
1235
1255
  const config = loadConfigCached(projectRoot);
1236
1256
  const checks = config?.resources?.checks;
1237
1257
  if (checks === undefined || Object.keys(checks).length === 0) {
1238
- // 🪤 Stderr only, and it decides NOTHING. The refusal lives in
1239
- // {@link noCheckRanFinding}, on the document, because the document is
1240
- // what the exit code is computed from and what CI parses; this warning is
1241
- // the same statement addressed to the human, and the two are one statement
1242
- // per audience. It used to be the ONLY channel, and the document said the
1243
- // opposite — `status: success`, exit 0 — which is the half that matters.
1244
- logger.warn('No checks are declared. Add them under `resources.checks` in'
1245
- + ' vibe-agent-toolkit.config.yaml; each is a description plus one SQL'
1246
- + ' statement selecting the rows that VIOLATE it.');
1258
+ // 🪤 Stderr only, and it decides NOTHING — the document is what the exit
1259
+ // code is computed from and what CI parses. ⚠️ It does not stand beside a
1260
+ // refusal: the built-in set runs here, so this run DID assert something.
1261
+ // What the operator needs to know is that the project is relying entirely
1262
+ // on VAT's defaults, which is what a deleted `checks:` block looks like.
1263
+ logger.warn(`No checks of this project's own are declared, so this run asserted only VAT's`
1264
+ + ` built-in set (${BUILTIN_CHECK_NAMES.join(', ')}).`
1265
+ + ' Add your own under `resources.checks` in vibe-agent-toolkit.config.yaml;'
1266
+ + ' each is a description plus one SQL statement selecting the rows that VIOLATE it.'
1267
+ + ' `vat resources check --help` prints the SQL each built-in is equivalent to,'
1268
+ + ' as a starting point.');
1247
1269
  }
1248
1270
  // Before the crawl: a mistyped flag is an operator error and pays nothing.
1249
- requireDeclaredCheck(checks ?? {}, options.check);
1271
+ requireKnownCheck(BUILTIN_CHECK_NAMES, checks ?? {}, options.check);
1250
1272
  // Also before the crawl, and for the same reason: an override that overrides
1251
1273
  // nothing is knowable from the config alone, and the operator should read it
1252
1274
  // beside the other config news rather than after a full population.
@@ -1267,10 +1289,10 @@ export async function checkCommand(pathArg, options) {
1267
1289
  durationMs: Date.now() - startTime,
1268
1290
  });
1269
1291
  emitCheckDocument(payload, options.format);
1270
- process.exit(payload['status'] === 'error' ? 1 : 0);
1292
+ process.exit(payload.summary.errors > 0 ? ExitCode.FINDINGS : ExitCode.OK);
1271
1293
  }
1272
1294
  catch (error) {
1273
- handleCommandError(error, logger, startTime, 'Check', options.format);
1295
+ handleReportCommandError(error, logger, startTime, 'Check', options.format);
1274
1296
  }
1275
1297
  }
1276
1298
  /**
@@ -1298,7 +1320,13 @@ async function runOutcome(options) {
1298
1320
  // bare throw, and the finding exists precisely so a renamed column cannot end a
1299
1321
  // gate quietly. The population is the price of an honest report, and it is
1300
1322
  // charged once for every check rather than per broken one.
1301
- return withQueriedProjection({ root, logger }, (ask, provenance, extent) => {
1323
+ // 🔑 `statements` IS passed, and it is a different question from `preflight`:
1324
+ // it only decides which derived relations are evaluated. Every declared
1325
+ // statement goes in, including one `--check` narrows away — the lens is per
1326
+ // RUN, and narrowing it would make `--check foo` and a full run disagree about
1327
+ // which relations exist.
1328
+ const statements = Object.values(checks).map((check) => check.sql);
1329
+ return withQueriedProjection({ root, logger, statements }, (ask, provenance, extent, projection) => {
1302
1330
  // 🔑 Emitted HERE, inside the callback, because this is the one place where
1303
1331
  // the provenance and the extent are both exactly in hand — and emitted the
1304
1332
  // INSTANT population completes, because its arrival is what tells a
@@ -1310,14 +1338,27 @@ async function runOutcome(options) {
1310
1338
  population: provenance.population,
1311
1339
  populationMs: provenance.populationMs,
1312
1340
  lensMs: provenance.lensMs,
1341
+ lensesEvaluated: [...provenance.lensesEvaluated],
1313
1342
  membersEnumerated: extent.membersEnumerated,
1314
1343
  });
1315
1344
  // 🪤 `checks-complete` is NOT emitted here. It used to be, and that put
1316
- // `resolveIssueSeverity` — which runs inside `runDeclaredChecks` — on the
1345
+ // `resolveIssueSeverity` — which runs inside `runProjectChecks` — on the
1317
1346
  // wrong side of the line, still charged to the last check's budget window
1318
1347
  // while three separate docs said otherwise. It is emitted by
1319
- // `runDeclaredChecks` itself now, the instant the last statement is done.
1320
- const ran = runDeclaredChecks({ checks, only, ask, validation, ...extent, onProgress });
1348
+ // `runProjectChecks` itself now, the instant the last statement is done.
1349
+ //
1350
+ // 🔑 The DEFAULT SET enters HERE, from a module constant bound to the
1351
+ // projection — never from `config`, which this line does not read. That is
1352
+ // the placement the "defaults belong to the pipeline" invariant is about.
1353
+ const ran = runProjectChecks({
1354
+ builtins: bindBuiltinChecks(projection),
1355
+ checks,
1356
+ only,
1357
+ ask,
1358
+ validation,
1359
+ ...extent,
1360
+ onProgress,
1361
+ });
1321
1362
  return { ...ran, ...provenance, ...extent };
1322
1363
  });
1323
1364
  }