@vibe-agent-toolkit/cli 0.2.0-rc.11 → 0.2.0-rc.12

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 (755) hide show
  1. package/README.md +3 -3
  2. package/dist/bin/supervise-cli.d.ts +45 -0
  3. package/dist/bin/supervise-cli.d.ts.map +1 -0
  4. package/dist/bin/supervise-cli.js +83 -0
  5. package/dist/bin/supervise-cli.js.map +1 -0
  6. package/dist/bin/vat +95 -43
  7. package/dist/bin/vat.d.ts +15 -4
  8. package/dist/bin/vat.d.ts.map +1 -1
  9. package/dist/bin/vat.js +95 -43
  10. package/dist/bin/vat.js.map +1 -1
  11. package/dist/bin.js +21 -29
  12. package/dist/bin.js.map +1 -1
  13. package/dist/command-tree.d.ts +45 -0
  14. package/dist/command-tree.d.ts.map +1 -0
  15. package/dist/command-tree.js +60 -0
  16. package/dist/command-tree.js.map +1 -0
  17. package/dist/commands/agent/build-schema.d.ts +100 -0
  18. package/dist/commands/agent/build-schema.d.ts.map +1 -0
  19. package/dist/commands/agent/build-schema.js +32 -0
  20. package/dist/commands/agent/build-schema.js.map +1 -0
  21. package/dist/commands/agent/build.d.ts +1 -0
  22. package/dist/commands/agent/build.d.ts.map +1 -1
  23. package/dist/commands/agent/build.js +63 -33
  24. package/dist/commands/agent/build.js.map +1 -1
  25. package/dist/commands/agent/import-schema.d.ts +75 -0
  26. package/dist/commands/agent/import-schema.d.ts.map +1 -0
  27. package/dist/commands/agent/import-schema.js +25 -0
  28. package/dist/commands/agent/import-schema.js.map +1 -0
  29. package/dist/commands/agent/import.d.ts.map +1 -1
  30. package/dist/commands/agent/import.js +33 -27
  31. package/dist/commands/agent/import.js.map +1 -1
  32. package/dist/commands/agent/index.d.ts.map +1 -1
  33. package/dist/commands/agent/index.js +132 -37
  34. package/dist/commands/agent/index.js.map +1 -1
  35. package/dist/commands/agent/install-path.d.ts.map +1 -1
  36. package/dist/commands/agent/install-path.js +2 -1
  37. package/dist/commands/agent/install-path.js.map +1 -1
  38. package/dist/commands/agent/install-schema.d.ts +89 -0
  39. package/dist/commands/agent/install-schema.d.ts.map +1 -0
  40. package/dist/commands/agent/install-schema.js +29 -0
  41. package/dist/commands/agent/install-schema.js.map +1 -0
  42. package/dist/commands/agent/install.d.ts +7 -1
  43. package/dist/commands/agent/install.d.ts.map +1 -1
  44. package/dist/commands/agent/install.js +78 -108
  45. package/dist/commands/agent/install.js.map +1 -1
  46. package/dist/commands/agent/installed-schema.d.ts +140 -0
  47. package/dist/commands/agent/installed-schema.d.ts.map +1 -0
  48. package/dist/commands/agent/installed-schema.js +36 -0
  49. package/dist/commands/agent/installed-schema.js.map +1 -0
  50. package/dist/commands/agent/installed.d.ts +1 -1
  51. package/dist/commands/agent/installed.d.ts.map +1 -1
  52. package/dist/commands/agent/installed.js +104 -75
  53. package/dist/commands/agent/installed.js.map +1 -1
  54. package/dist/commands/agent/list-schema.d.ts +128 -0
  55. package/dist/commands/agent/list-schema.d.ts.map +1 -0
  56. package/dist/commands/agent/list-schema.js +34 -0
  57. package/dist/commands/agent/list-schema.js.map +1 -0
  58. package/dist/commands/agent/list.d.ts +4 -3
  59. package/dist/commands/agent/list.d.ts.map +1 -1
  60. package/dist/commands/agent/list.js +50 -37
  61. package/dist/commands/agent/list.js.map +1 -1
  62. package/dist/commands/agent/run.d.ts +3 -0
  63. package/dist/commands/agent/run.d.ts.map +1 -1
  64. package/dist/commands/agent/run.js +8 -3
  65. package/dist/commands/agent/run.js.map +1 -1
  66. package/dist/commands/agent/uninstall-schema.d.ts +89 -0
  67. package/dist/commands/agent/uninstall-schema.d.ts.map +1 -0
  68. package/dist/commands/agent/uninstall-schema.js +29 -0
  69. package/dist/commands/agent/uninstall-schema.js.map +1 -0
  70. package/dist/commands/agent/uninstall.d.ts +5 -1
  71. package/dist/commands/agent/uninstall.d.ts.map +1 -1
  72. package/dist/commands/agent/uninstall.js +50 -38
  73. package/dist/commands/agent/uninstall.js.map +1 -1
  74. package/dist/commands/agent/validate-schema.d.ts +129 -0
  75. package/dist/commands/agent/validate-schema.d.ts.map +1 -0
  76. package/dist/commands/agent/validate-schema.js +35 -0
  77. package/dist/commands/agent/validate-schema.js.map +1 -0
  78. package/dist/commands/agent/validate.d.ts +6 -0
  79. package/dist/commands/agent/validate.d.ts.map +1 -1
  80. package/dist/commands/agent/validate.js +64 -36
  81. package/dist/commands/agent/validate.js.map +1 -1
  82. package/dist/commands/ard/emit-schema.d.ts +108 -0
  83. package/dist/commands/ard/emit-schema.d.ts.map +1 -0
  84. package/dist/commands/ard/emit-schema.js +37 -0
  85. package/dist/commands/ard/emit-schema.js.map +1 -0
  86. package/dist/commands/ard/emit.d.ts +21 -65
  87. package/dist/commands/ard/emit.d.ts.map +1 -1
  88. package/dist/commands/ard/emit.js +68 -74
  89. package/dist/commands/ard/emit.js.map +1 -1
  90. package/dist/commands/ard/index.d.ts.map +1 -1
  91. package/dist/commands/ard/index.js +14 -11
  92. package/dist/commands/ard/index.js.map +1 -1
  93. package/dist/commands/audit/compat-lane-findings.d.ts +65 -0
  94. package/dist/commands/audit/compat-lane-findings.d.ts.map +1 -0
  95. package/dist/commands/audit/compat-lane-findings.js +72 -0
  96. package/dist/commands/audit/compat-lane-findings.js.map +1 -0
  97. package/dist/commands/audit/distributed-tree.d.ts +2 -2
  98. package/dist/commands/audit/distributed-tree.d.ts.map +1 -1
  99. package/dist/commands/audit/distributed-tree.js +23 -12
  100. package/dist/commands/audit/distributed-tree.js.map +1 -1
  101. package/dist/commands/audit/git-url-clone.d.ts +15 -7
  102. package/dist/commands/audit/git-url-clone.d.ts.map +1 -1
  103. package/dist/commands/audit/git-url-clone.js +85 -42
  104. package/dist/commands/audit/git-url-clone.js.map +1 -1
  105. package/dist/commands/audit/hierarchical-output.d.ts +28 -4
  106. package/dist/commands/audit/hierarchical-output.d.ts.map +1 -1
  107. package/dist/commands/audit/hierarchical-output.js +44 -27
  108. package/dist/commands/audit/hierarchical-output.js.map +1 -1
  109. package/dist/commands/audit/scan-population.d.ts.map +1 -1
  110. package/dist/commands/audit/scan-population.js +2 -1
  111. package/dist/commands/audit/scan-population.js.map +1 -1
  112. package/dist/commands/audit-schema.d.ts +1247 -0
  113. package/dist/commands/audit-schema.d.ts.map +1 -0
  114. package/dist/commands/audit-schema.js +139 -0
  115. package/dist/commands/audit-schema.js.map +1 -0
  116. package/dist/commands/audit-settings-schema.d.ts +417 -0
  117. package/dist/commands/audit-settings-schema.d.ts.map +1 -0
  118. package/dist/commands/audit-settings-schema.js +77 -0
  119. package/dist/commands/audit-settings-schema.js.map +1 -0
  120. package/dist/commands/audit-settings.d.ts +28 -9
  121. package/dist/commands/audit-settings.d.ts.map +1 -1
  122. package/dist/commands/audit-settings.js +215 -151
  123. package/dist/commands/audit-settings.js.map +1 -1
  124. package/dist/commands/audit.d.ts +72 -33
  125. package/dist/commands/audit.d.ts.map +1 -1
  126. package/dist/commands/audit.js +405 -411
  127. package/dist/commands/audit.js.map +1 -1
  128. package/dist/commands/build.d.ts +61 -4
  129. package/dist/commands/build.d.ts.map +1 -1
  130. package/dist/commands/build.js +176 -190
  131. package/dist/commands/build.js.map +1 -1
  132. package/dist/commands/cache/clear-schema.d.ts +111 -0
  133. package/dist/commands/cache/clear-schema.d.ts.map +1 -0
  134. package/dist/commands/cache/clear-schema.js +37 -0
  135. package/dist/commands/cache/clear-schema.js.map +1 -0
  136. package/dist/commands/cache/clear.d.ts +28 -26
  137. package/dist/commands/cache/clear.d.ts.map +1 -1
  138. package/dist/commands/cache/clear.js +108 -103
  139. package/dist/commands/cache/clear.js.map +1 -1
  140. package/dist/commands/cache/index.d.ts.map +1 -1
  141. package/dist/commands/cache/index.js +13 -7
  142. package/dist/commands/cache/index.js.map +1 -1
  143. package/dist/commands/claude/claude-config.d.ts +23 -6
  144. package/dist/commands/claude/claude-config.d.ts.map +1 -1
  145. package/dist/commands/claude/claude-config.js +29 -15
  146. package/dist/commands/claude/claude-config.js.map +1 -1
  147. package/dist/commands/claude/context.d.ts +55 -2
  148. package/dist/commands/claude/context.d.ts.map +1 -1
  149. package/dist/commands/claude/context.js +74 -50
  150. package/dist/commands/claude/context.js.map +1 -1
  151. package/dist/commands/claude/marketplace/changelog-utils.js +2 -2
  152. package/dist/commands/claude/marketplace/changelog-utils.js.map +1 -1
  153. package/dist/commands/claude/marketplace/git-publish.d.ts +14 -1
  154. package/dist/commands/claude/marketplace/git-publish.d.ts.map +1 -1
  155. package/dist/commands/claude/marketplace/git-publish.js +135 -68
  156. package/dist/commands/claude/marketplace/git-publish.js.map +1 -1
  157. package/dist/commands/claude/marketplace/license-utils.d.ts +3 -5
  158. package/dist/commands/claude/marketplace/license-utils.d.ts.map +1 -1
  159. package/dist/commands/claude/marketplace/license-utils.js +16 -7
  160. package/dist/commands/claude/marketplace/license-utils.js.map +1 -1
  161. package/dist/commands/claude/marketplace/publish-schema.d.ts +137 -0
  162. package/dist/commands/claude/marketplace/publish-schema.d.ts.map +1 -0
  163. package/dist/commands/claude/marketplace/publish-schema.js +32 -0
  164. package/dist/commands/claude/marketplace/publish-schema.js.map +1 -0
  165. package/dist/commands/claude/marketplace/publish-tree.d.ts +6 -0
  166. package/dist/commands/claude/marketplace/publish-tree.d.ts.map +1 -1
  167. package/dist/commands/claude/marketplace/publish-tree.js +75 -17
  168. package/dist/commands/claude/marketplace/publish-tree.js.map +1 -1
  169. package/dist/commands/claude/marketplace/publish.d.ts +27 -0
  170. package/dist/commands/claude/marketplace/publish.d.ts.map +1 -1
  171. package/dist/commands/claude/marketplace/publish.js +84 -50
  172. package/dist/commands/claude/marketplace/publish.js.map +1 -1
  173. package/dist/commands/claude/marketplace/validate-schema.d.ts +362 -0
  174. package/dist/commands/claude/marketplace/validate-schema.d.ts.map +1 -0
  175. package/dist/commands/claude/marketplace/validate-schema.js +67 -0
  176. package/dist/commands/claude/marketplace/validate-schema.js.map +1 -0
  177. package/dist/commands/claude/marketplace/validate.d.ts +40 -53
  178. package/dist/commands/claude/marketplace/validate.d.ts.map +1 -1
  179. package/dist/commands/claude/marketplace/validate.js +358 -214
  180. package/dist/commands/claude/marketplace/validate.js.map +1 -1
  181. package/dist/commands/claude/org/api-keys.d.ts +3 -0
  182. package/dist/commands/claude/org/api-keys.d.ts.map +1 -1
  183. package/dist/commands/claude/org/api-keys.js +4 -5
  184. package/dist/commands/claude/org/api-keys.js.map +1 -1
  185. package/dist/commands/claude/org/code-analytics.js +1 -1
  186. package/dist/commands/claude/org/code-analytics.js.map +1 -1
  187. package/dist/commands/claude/org/cost.d.ts.map +1 -1
  188. package/dist/commands/claude/org/cost.js +11 -33
  189. package/dist/commands/claude/org/cost.js.map +1 -1
  190. package/dist/commands/claude/org/helpers.d.ts +40 -27
  191. package/dist/commands/claude/org/helpers.d.ts.map +1 -1
  192. package/dist/commands/claude/org/helpers.js +61 -66
  193. package/dist/commands/claude/org/helpers.js.map +1 -1
  194. package/dist/commands/claude/org/index.d.ts.map +1 -1
  195. package/dist/commands/claude/org/index.js +10 -4
  196. package/dist/commands/claude/org/index.js.map +1 -1
  197. package/dist/commands/claude/org/info.d.ts.map +1 -1
  198. package/dist/commands/claude/org/info.js +2 -3
  199. package/dist/commands/claude/org/info.js.map +1 -1
  200. package/dist/commands/claude/org/invites.d.ts +3 -0
  201. package/dist/commands/claude/org/invites.d.ts.map +1 -1
  202. package/dist/commands/claude/org/invites.js +5 -7
  203. package/dist/commands/claude/org/invites.js.map +1 -1
  204. package/dist/commands/claude/org/skills.d.ts +76 -21
  205. package/dist/commands/claude/org/skills.d.ts.map +1 -1
  206. package/dist/commands/claude/org/skills.js +273 -246
  207. package/dist/commands/claude/org/skills.js.map +1 -1
  208. package/dist/commands/claude/org/stubs-schema.d.ts +56 -0
  209. package/dist/commands/claude/org/stubs-schema.d.ts.map +1 -0
  210. package/dist/commands/claude/org/stubs-schema.js +23 -0
  211. package/dist/commands/claude/org/stubs-schema.js.map +1 -0
  212. package/dist/commands/claude/org/stubs.d.ts +8 -3
  213. package/dist/commands/claude/org/stubs.d.ts.map +1 -1
  214. package/dist/commands/claude/org/stubs.js +9 -9
  215. package/dist/commands/claude/org/stubs.js.map +1 -1
  216. package/dist/commands/claude/org/usage.d.ts.map +1 -1
  217. package/dist/commands/claude/org/usage.js +1 -2
  218. package/dist/commands/claude/org/usage.js.map +1 -1
  219. package/dist/commands/claude/org/users.d.ts +3 -0
  220. package/dist/commands/claude/org/users.d.ts.map +1 -1
  221. package/dist/commands/claude/org/users.js +6 -8
  222. package/dist/commands/claude/org/users.js.map +1 -1
  223. package/dist/commands/claude/org/workspaces.d.ts +3 -0
  224. package/dist/commands/claude/org/workspaces.d.ts.map +1 -1
  225. package/dist/commands/claude/org/workspaces.js +10 -15
  226. package/dist/commands/claude/org/workspaces.js.map +1 -1
  227. package/dist/commands/claude/plugin/build-schema.d.ts +642 -0
  228. package/dist/commands/claude/plugin/build-schema.d.ts.map +1 -0
  229. package/dist/commands/claude/plugin/build-schema.js +51 -0
  230. package/dist/commands/claude/plugin/build-schema.js.map +1 -0
  231. package/dist/commands/claude/plugin/build.d.ts +220 -45
  232. package/dist/commands/claude/plugin/build.d.ts.map +1 -1
  233. package/dist/commands/claude/plugin/build.js +466 -249
  234. package/dist/commands/claude/plugin/build.js.map +1 -1
  235. package/dist/commands/claude/plugin/helpers.d.ts +186 -24
  236. package/dist/commands/claude/plugin/helpers.d.ts.map +1 -1
  237. package/dist/commands/claude/plugin/helpers.js +110 -68
  238. package/dist/commands/claude/plugin/helpers.js.map +1 -1
  239. package/dist/commands/claude/plugin/install-schema.d.ts +144 -0
  240. package/dist/commands/claude/plugin/install-schema.d.ts.map +1 -0
  241. package/dist/commands/claude/plugin/install-schema.js +36 -0
  242. package/dist/commands/claude/plugin/install-schema.js.map +1 -0
  243. package/dist/commands/claude/plugin/install.d.ts +191 -11
  244. package/dist/commands/claude/plugin/install.d.ts.map +1 -1
  245. package/dist/commands/claude/plugin/install.js +688 -628
  246. package/dist/commands/claude/plugin/install.js.map +1 -1
  247. package/dist/commands/claude/plugin/kept-findings.d.ts +19 -0
  248. package/dist/commands/claude/plugin/kept-findings.d.ts.map +1 -0
  249. package/dist/commands/claude/plugin/kept-findings.js +24 -0
  250. package/dist/commands/claude/plugin/kept-findings.js.map +1 -0
  251. package/dist/commands/claude/plugin/list-schema.d.ts +223 -0
  252. package/dist/commands/claude/plugin/list-schema.d.ts.map +1 -0
  253. package/dist/commands/claude/plugin/list-schema.js +34 -0
  254. package/dist/commands/claude/plugin/list-schema.js.map +1 -0
  255. package/dist/commands/claude/plugin/list.d.ts +18 -0
  256. package/dist/commands/claude/plugin/list.d.ts.map +1 -1
  257. package/dist/commands/claude/plugin/list.js +53 -45
  258. package/dist/commands/claude/plugin/list.js.map +1 -1
  259. package/dist/commands/claude/plugin/npm-pack.d.ts +15 -0
  260. package/dist/commands/claude/plugin/npm-pack.d.ts.map +1 -0
  261. package/dist/commands/claude/plugin/npm-pack.js +39 -0
  262. package/dist/commands/claude/plugin/npm-pack.js.map +1 -0
  263. package/dist/commands/claude/plugin/plugin-changelog.d.ts +5 -1
  264. package/dist/commands/claude/plugin/plugin-changelog.d.ts.map +1 -1
  265. package/dist/commands/claude/plugin/plugin-changelog.js +9 -5
  266. package/dist/commands/claude/plugin/plugin-changelog.js.map +1 -1
  267. package/dist/commands/claude/plugin/plugin-files.d.ts +21 -2
  268. package/dist/commands/claude/plugin/plugin-files.d.ts.map +1 -1
  269. package/dist/commands/claude/plugin/plugin-files.js +65 -32
  270. package/dist/commands/claude/plugin/plugin-files.js.map +1 -1
  271. package/dist/commands/claude/plugin/plugin-validators.d.ts +13 -0
  272. package/dist/commands/claude/plugin/plugin-validators.d.ts.map +1 -1
  273. package/dist/commands/claude/plugin/plugin-validators.js +64 -16
  274. package/dist/commands/claude/plugin/plugin-validators.js.map +1 -1
  275. package/dist/commands/claude/plugin/tree-copy.d.ts.map +1 -1
  276. package/dist/commands/claude/plugin/tree-copy.js +63 -37
  277. package/dist/commands/claude/plugin/tree-copy.js.map +1 -1
  278. package/dist/commands/claude/plugin/uninstall-schema.d.ts +112 -0
  279. package/dist/commands/claude/plugin/uninstall-schema.d.ts.map +1 -0
  280. package/dist/commands/claude/plugin/uninstall-schema.js +28 -0
  281. package/dist/commands/claude/plugin/uninstall-schema.js.map +1 -0
  282. package/dist/commands/claude/plugin/uninstall.d.ts +57 -0
  283. package/dist/commands/claude/plugin/uninstall.d.ts.map +1 -1
  284. package/dist/commands/claude/plugin/uninstall.js +176 -64
  285. package/dist/commands/claude/plugin/uninstall.js.map +1 -1
  286. package/dist/commands/consistency-check.d.ts.map +1 -1
  287. package/dist/commands/consistency-check.js +8 -6
  288. package/dist/commands/consistency-check.js.map +1 -1
  289. package/dist/commands/corpus/index.d.ts.map +1 -1
  290. package/dist/commands/corpus/index.js +26 -10
  291. package/dist/commands/corpus/index.js.map +1 -1
  292. package/dist/commands/corpus/report.d.ts +34 -16
  293. package/dist/commands/corpus/report.d.ts.map +1 -1
  294. package/dist/commands/corpus/report.js +36 -18
  295. package/dist/commands/corpus/report.js.map +1 -1
  296. package/dist/commands/corpus/runner.d.ts +25 -20
  297. package/dist/commands/corpus/runner.d.ts.map +1 -1
  298. package/dist/commands/corpus/runner.js +123 -67
  299. package/dist/commands/corpus/runner.js.map +1 -1
  300. package/dist/commands/corpus/scan-schema.d.ts +127 -0
  301. package/dist/commands/corpus/scan-schema.d.ts.map +1 -0
  302. package/dist/commands/corpus/scan-schema.js +31 -0
  303. package/dist/commands/corpus/scan-schema.js.map +1 -0
  304. package/dist/commands/corpus/scan.d.ts +31 -0
  305. package/dist/commands/corpus/scan.d.ts.map +1 -1
  306. package/dist/commands/corpus/scan.js +124 -50
  307. package/dist/commands/corpus/scan.js.map +1 -1
  308. package/dist/commands/corpus/seed.d.ts +11 -8
  309. package/dist/commands/corpus/seed.d.ts.map +1 -1
  310. package/dist/commands/corpus/seed.js +29 -11
  311. package/dist/commands/corpus/seed.js.map +1 -1
  312. package/dist/commands/doctor-render.d.ts +52 -0
  313. package/dist/commands/doctor-render.d.ts.map +1 -0
  314. package/dist/commands/doctor-render.js +110 -0
  315. package/dist/commands/doctor-render.js.map +1 -0
  316. package/dist/commands/doctor-schema.d.ts +191 -0
  317. package/dist/commands/doctor-schema.d.ts.map +1 -0
  318. package/dist/commands/doctor-schema.js +44 -0
  319. package/dist/commands/doctor-schema.js.map +1 -0
  320. package/dist/commands/doctor.d.ts +7 -62
  321. package/dist/commands/doctor.d.ts.map +1 -1
  322. package/dist/commands/doctor.js +126 -165
  323. package/dist/commands/doctor.js.map +1 -1
  324. package/dist/commands/inventory-schema.d.ts +7297 -0
  325. package/dist/commands/inventory-schema.d.ts.map +1 -0
  326. package/dist/commands/inventory-schema.js +28 -0
  327. package/dist/commands/inventory-schema.js.map +1 -0
  328. package/dist/commands/inventory.d.ts +1 -1
  329. package/dist/commands/inventory.d.ts.map +1 -1
  330. package/dist/commands/inventory.js +89 -41
  331. package/dist/commands/inventory.js.map +1 -1
  332. package/dist/commands/mcp/index.d.ts.map +1 -1
  333. package/dist/commands/mcp/index.js +15 -0
  334. package/dist/commands/mcp/index.js.map +1 -1
  335. package/dist/commands/mcp/list-collections-schema.d.ts +101 -0
  336. package/dist/commands/mcp/list-collections-schema.d.ts.map +1 -0
  337. package/dist/commands/mcp/list-collections-schema.js +22 -0
  338. package/dist/commands/mcp/list-collections-schema.js.map +1 -0
  339. package/dist/commands/mcp/list-collections.d.ts +1 -1
  340. package/dist/commands/mcp/list-collections.d.ts.map +1 -1
  341. package/dist/commands/mcp/list-collections.js +19 -17
  342. package/dist/commands/mcp/list-collections.js.map +1 -1
  343. package/dist/commands/mcp/serve.d.ts +5 -0
  344. package/dist/commands/mcp/serve.d.ts.map +1 -1
  345. package/dist/commands/mcp/serve.js +29 -15
  346. package/dist/commands/mcp/serve.js.map +1 -1
  347. package/dist/commands/okf/index.d.ts.map +1 -1
  348. package/dist/commands/okf/index.js +6 -5
  349. package/dist/commands/okf/index.js.map +1 -1
  350. package/dist/commands/okf/validate-schema.d.ts +171 -0
  351. package/dist/commands/okf/validate-schema.d.ts.map +1 -0
  352. package/dist/commands/okf/validate-schema.js +44 -0
  353. package/dist/commands/okf/validate-schema.js.map +1 -0
  354. package/dist/commands/okf/validate.d.ts +16 -149
  355. package/dist/commands/okf/validate.d.ts.map +1 -1
  356. package/dist/commands/okf/validate.js +64 -62
  357. package/dist/commands/okf/validate.js.map +1 -1
  358. package/dist/commands/orchestrator-schema.d.ts +419 -0
  359. package/dist/commands/orchestrator-schema.d.ts.map +1 -0
  360. package/dist/commands/orchestrator-schema.js +91 -0
  361. package/dist/commands/orchestrator-schema.js.map +1 -0
  362. package/dist/commands/phase-utils.d.ts +188 -220
  363. package/dist/commands/phase-utils.d.ts.map +1 -1
  364. package/dist/commands/phase-utils.js +210 -258
  365. package/dist/commands/phase-utils.js.map +1 -1
  366. package/dist/commands/positional-args.d.ts +13 -11
  367. package/dist/commands/positional-args.d.ts.map +1 -1
  368. package/dist/commands/positional-args.js +16 -15
  369. package/dist/commands/positional-args.js.map +1 -1
  370. package/dist/commands/rag/admin-schema.d.ts +152 -0
  371. package/dist/commands/rag/admin-schema.d.ts.map +1 -0
  372. package/dist/commands/rag/admin-schema.js +31 -0
  373. package/dist/commands/rag/admin-schema.js.map +1 -0
  374. package/dist/commands/rag/clear-command.d.ts.map +1 -1
  375. package/dist/commands/rag/clear-command.js +30 -15
  376. package/dist/commands/rag/clear-command.js.map +1 -1
  377. package/dist/commands/rag/command-helpers.d.ts +31 -7
  378. package/dist/commands/rag/command-helpers.d.ts.map +1 -1
  379. package/dist/commands/rag/command-helpers.js +41 -21
  380. package/dist/commands/rag/command-helpers.js.map +1 -1
  381. package/dist/commands/rag/index-command.d.ts +37 -48
  382. package/dist/commands/rag/index-command.d.ts.map +1 -1
  383. package/dist/commands/rag/index-command.js +80 -65
  384. package/dist/commands/rag/index-command.js.map +1 -1
  385. package/dist/commands/rag/index-schema.d.ts +107 -0
  386. package/dist/commands/rag/index-schema.d.ts.map +1 -0
  387. package/dist/commands/rag/index-schema.js +34 -0
  388. package/dist/commands/rag/index-schema.js.map +1 -0
  389. package/dist/commands/rag/index.d.ts.map +1 -1
  390. package/dist/commands/rag/index.js +88 -41
  391. package/dist/commands/rag/index.js.map +1 -1
  392. package/dist/commands/rag/query-command.d.ts +18 -4
  393. package/dist/commands/rag/query-command.d.ts.map +1 -1
  394. package/dist/commands/rag/query-command.js +42 -27
  395. package/dist/commands/rag/query-command.js.map +1 -1
  396. package/dist/commands/rag/query-schema.d.ts +363 -0
  397. package/dist/commands/rag/query-schema.d.ts.map +1 -0
  398. package/dist/commands/rag/query-schema.js +59 -0
  399. package/dist/commands/rag/query-schema.js.map +1 -0
  400. package/dist/commands/rag/stats-command.d.ts.map +1 -1
  401. package/dist/commands/rag/stats-command.js +19 -18
  402. package/dist/commands/rag/stats-command.js.map +1 -1
  403. package/dist/commands/resources/check-progress.d.ts +64 -11
  404. package/dist/commands/resources/check-progress.d.ts.map +1 -1
  405. package/dist/commands/resources/check-progress.js +77 -4
  406. package/dist/commands/resources/check-progress.js.map +1 -1
  407. package/dist/commands/resources/check-schema.d.ts +335 -0
  408. package/dist/commands/resources/check-schema.d.ts.map +1 -0
  409. package/dist/commands/resources/check-schema.js +104 -0
  410. package/dist/commands/resources/check-schema.js.map +1 -0
  411. package/dist/commands/resources/check-supervisor.d.ts +315 -71
  412. package/dist/commands/resources/check-supervisor.d.ts.map +1 -1
  413. package/dist/commands/resources/check-supervisor.js +493 -107
  414. package/dist/commands/resources/check-supervisor.js.map +1 -1
  415. package/dist/commands/resources/check.d.ts +56 -249
  416. package/dist/commands/resources/check.d.ts.map +1 -1
  417. package/dist/commands/resources/check.js +416 -276
  418. package/dist/commands/resources/check.js.map +1 -1
  419. package/dist/commands/resources/index.d.ts.map +1 -1
  420. package/dist/commands/resources/index.js +165 -91
  421. package/dist/commands/resources/index.js.map +1 -1
  422. package/dist/commands/resources/query-schema.d.ts +188 -0
  423. package/dist/commands/resources/query-schema.d.ts.map +1 -0
  424. package/dist/commands/resources/query-schema.js +48 -0
  425. package/dist/commands/resources/query-schema.js.map +1 -0
  426. package/dist/commands/resources/query.d.ts +17 -12
  427. package/dist/commands/resources/query.d.ts.map +1 -1
  428. package/dist/commands/resources/query.js +60 -48
  429. package/dist/commands/resources/query.js.map +1 -1
  430. package/dist/commands/resources/scan-schema.d.ts +195 -0
  431. package/dist/commands/resources/scan-schema.d.ts.map +1 -0
  432. package/dist/commands/resources/scan-schema.js +53 -0
  433. package/dist/commands/resources/scan-schema.js.map +1 -0
  434. package/dist/commands/resources/scan.d.ts +26 -3
  435. package/dist/commands/resources/scan.d.ts.map +1 -1
  436. package/dist/commands/resources/scan.js +51 -53
  437. package/dist/commands/resources/scan.js.map +1 -1
  438. package/dist/commands/resources/validate-schema.d.ts +326 -0
  439. package/dist/commands/resources/validate-schema.d.ts.map +1 -0
  440. package/dist/commands/resources/validate-schema.js +60 -0
  441. package/dist/commands/resources/validate-schema.js.map +1 -0
  442. package/dist/commands/resources/validate.d.ts +45 -169
  443. package/dist/commands/resources/validate.d.ts.map +1 -1
  444. package/dist/commands/resources/validate.js +221 -485
  445. package/dist/commands/resources/validate.js.map +1 -1
  446. package/dist/commands/skill/review-checklist.d.ts.map +1 -1
  447. package/dist/commands/skill/review-checklist.js +0 -1
  448. package/dist/commands/skill/review-checklist.js.map +1 -1
  449. package/dist/commands/skill/review-schema.d.ts +278 -0
  450. package/dist/commands/skill/review-schema.d.ts.map +1 -0
  451. package/dist/commands/skill/review-schema.js +46 -0
  452. package/dist/commands/skill/review-schema.js.map +1 -0
  453. package/dist/commands/skill/review.d.ts +8 -234
  454. package/dist/commands/skill/review.d.ts.map +1 -1
  455. package/dist/commands/skill/review.js +54 -78
  456. package/dist/commands/skill/review.js.map +1 -1
  457. package/dist/commands/skill/test/auth-flags.d.ts +3 -0
  458. package/dist/commands/skill/test/auth-flags.d.ts.map +1 -1
  459. package/dist/commands/skill/test/auth-flags.js +6 -2
  460. package/dist/commands/skill/test/auth-flags.js.map +1 -1
  461. package/dist/commands/skill/test/configure-schema.d.ts +67 -0
  462. package/dist/commands/skill/test/configure-schema.d.ts.map +1 -0
  463. package/dist/commands/skill/test/configure-schema.js +27 -0
  464. package/dist/commands/skill/test/configure-schema.js.map +1 -0
  465. package/dist/commands/skill/test/configure.d.ts +12 -5
  466. package/dist/commands/skill/test/configure.d.ts.map +1 -1
  467. package/dist/commands/skill/test/configure.js +101 -31
  468. package/dist/commands/skill/test/configure.js.map +1 -1
  469. package/dist/commands/skill/test/run-schema.d.ts +107 -0
  470. package/dist/commands/skill/test/run-schema.d.ts.map +1 -0
  471. package/dist/commands/skill/test/run-schema.js +36 -0
  472. package/dist/commands/skill/test/run-schema.js.map +1 -0
  473. package/dist/commands/skill/test/run.d.ts +3 -2
  474. package/dist/commands/skill/test/run.d.ts.map +1 -1
  475. package/dist/commands/skill/test/run.js +316 -155
  476. package/dist/commands/skill/test/run.js.map +1 -1
  477. package/dist/commands/skills/build-schema.d.ts +199 -0
  478. package/dist/commands/skills/build-schema.d.ts.map +1 -0
  479. package/dist/commands/skills/build-schema.js +55 -0
  480. package/dist/commands/skills/build-schema.js.map +1 -0
  481. package/dist/commands/skills/build.d.ts +95 -298
  482. package/dist/commands/skills/build.d.ts.map +1 -1
  483. package/dist/commands/skills/build.js +415 -818
  484. package/dist/commands/skills/build.js.map +1 -1
  485. package/dist/commands/skills/command-helpers.d.ts +5 -11
  486. package/dist/commands/skills/command-helpers.d.ts.map +1 -1
  487. package/dist/commands/skills/command-helpers.js +7 -17
  488. package/dist/commands/skills/command-helpers.js.map +1 -1
  489. package/dist/commands/skills/index.js +12 -6
  490. package/dist/commands/skills/index.js.map +1 -1
  491. package/dist/commands/skills/install-schema.d.ts +153 -0
  492. package/dist/commands/skills/install-schema.d.ts.map +1 -0
  493. package/dist/commands/skills/install-schema.js +44 -0
  494. package/dist/commands/skills/install-schema.js.map +1 -0
  495. package/dist/commands/skills/install.d.ts +76 -8
  496. package/dist/commands/skills/install.d.ts.map +1 -1
  497. package/dist/commands/skills/install.js +230 -194
  498. package/dist/commands/skills/install.js.map +1 -1
  499. package/dist/commands/skills/list-schema.d.ts +145 -0
  500. package/dist/commands/skills/list-schema.d.ts.map +1 -0
  501. package/dist/commands/skills/list-schema.js +37 -0
  502. package/dist/commands/skills/list-schema.js.map +1 -0
  503. package/dist/commands/skills/list.d.ts +39 -8
  504. package/dist/commands/skills/list.d.ts.map +1 -1
  505. package/dist/commands/skills/list.js +110 -122
  506. package/dist/commands/skills/list.js.map +1 -1
  507. package/dist/commands/skills/package-schema.d.ts +98 -0
  508. package/dist/commands/skills/package-schema.d.ts.map +1 -0
  509. package/dist/commands/skills/package-schema.js +32 -0
  510. package/dist/commands/skills/package-schema.js.map +1 -0
  511. package/dist/commands/skills/package.d.ts +85 -14
  512. package/dist/commands/skills/package.d.ts.map +1 -1
  513. package/dist/commands/skills/package.js +288 -207
  514. package/dist/commands/skills/package.js.map +1 -1
  515. package/dist/commands/skills/scope-guard.d.ts +27 -20
  516. package/dist/commands/skills/scope-guard.d.ts.map +1 -1
  517. package/dist/commands/skills/scope-guard.js +43 -32
  518. package/dist/commands/skills/scope-guard.js.map +1 -1
  519. package/dist/commands/skills/skill-discovery.d.ts +1 -1
  520. package/dist/commands/skills/skill-discovery.d.ts.map +1 -1
  521. package/dist/commands/skills/skill-discovery.js +40 -19
  522. package/dist/commands/skills/skill-discovery.js.map +1 -1
  523. package/dist/commands/skills/source-resolvers.d.ts +58 -8
  524. package/dist/commands/skills/source-resolvers.d.ts.map +1 -1
  525. package/dist/commands/skills/source-resolvers.js +113 -38
  526. package/dist/commands/skills/source-resolvers.js.map +1 -1
  527. package/dist/commands/skills/validate-command.d.ts.map +1 -1
  528. package/dist/commands/skills/validate-command.js +31 -51
  529. package/dist/commands/skills/validate-command.js.map +1 -1
  530. package/dist/commands/skills/validate-schema.d.ts +199 -0
  531. package/dist/commands/skills/validate-schema.d.ts.map +1 -0
  532. package/dist/commands/skills/validate-schema.js +44 -0
  533. package/dist/commands/skills/validate-schema.js.map +1 -0
  534. package/dist/commands/skills/validate.d.ts +100 -136
  535. package/dist/commands/skills/validate.d.ts.map +1 -1
  536. package/dist/commands/skills/validate.js +257 -343
  537. package/dist/commands/skills/validate.js.map +1 -1
  538. package/dist/commands/validate.d.ts +17 -5
  539. package/dist/commands/validate.d.ts.map +1 -1
  540. package/dist/commands/validate.js +139 -94
  541. package/dist/commands/validate.js.map +1 -1
  542. package/dist/commands/verify.d.ts +121 -110
  543. package/dist/commands/verify.d.ts.map +1 -1
  544. package/dist/commands/verify.js +230 -294
  545. package/dist/commands/verify.js.map +1 -1
  546. package/dist/index.d.ts +1 -1
  547. package/dist/index.d.ts.map +1 -1
  548. package/dist/index.js +1 -1
  549. package/dist/index.js.map +1 -1
  550. package/dist/report-schemas.d.ts +12398 -35
  551. package/dist/report-schemas.d.ts.map +1 -1
  552. package/dist/report-schemas.js +624 -66
  553. package/dist/report-schemas.js.map +1 -1
  554. package/dist/skill-resolution/packaging-config.js +2 -2
  555. package/dist/skill-resolution/packaging-config.js.map +1 -1
  556. package/dist/skill-resolution/resolve-skill-reference.d.ts.map +1 -1
  557. package/dist/skill-resolution/resolve-skill-reference.js +20 -13
  558. package/dist/skill-resolution/resolve-skill-reference.js.map +1 -1
  559. package/dist/utils/agent-discovery.d.ts +34 -1
  560. package/dist/utils/agent-discovery.d.ts.map +1 -1
  561. package/dist/utils/agent-discovery.js +80 -38
  562. package/dist/utils/agent-discovery.js.map +1 -1
  563. package/dist/utils/claude-context-lens.d.ts +13 -6
  564. package/dist/utils/claude-context-lens.d.ts.map +1 -1
  565. package/dist/utils/claude-context-lens.js +11 -12
  566. package/dist/utils/claude-context-lens.js.map +1 -1
  567. package/dist/utils/command-error-codes.d.ts +12 -0
  568. package/dist/utils/command-error-codes.d.ts.map +1 -0
  569. package/dist/utils/command-error-codes.js +12 -0
  570. package/dist/utils/command-error-codes.js.map +1 -0
  571. package/dist/utils/command-refusal.d.ts +58 -0
  572. package/dist/utils/command-refusal.d.ts.map +1 -0
  573. package/dist/utils/command-refusal.js +170 -0
  574. package/dist/utils/command-refusal.js.map +1 -0
  575. package/dist/utils/commander-ending.d.ts +40 -0
  576. package/dist/utils/commander-ending.d.ts.map +1 -0
  577. package/dist/utils/commander-ending.js +42 -0
  578. package/dist/utils/commander-ending.js.map +1 -0
  579. package/dist/utils/config-loader.d.ts +13 -8
  580. package/dist/utils/config-loader.d.ts.map +1 -1
  581. package/dist/utils/config-loader.js +84 -45
  582. package/dist/utils/config-loader.js.map +1 -1
  583. package/dist/utils/corpus-target.d.ts +1 -1
  584. package/dist/utils/corpus-target.d.ts.map +1 -1
  585. package/dist/utils/corpus-target.js +6 -4
  586. package/dist/utils/corpus-target.js.map +1 -1
  587. package/dist/utils/debug-diagnostics.d.ts +18 -0
  588. package/dist/utils/debug-diagnostics.d.ts.map +1 -0
  589. package/dist/utils/debug-diagnostics.js +23 -0
  590. package/dist/utils/debug-diagnostics.js.map +1 -0
  591. package/dist/utils/document-writer.d.ts +191 -0
  592. package/dist/utils/document-writer.d.ts.map +1 -0
  593. package/dist/utils/document-writer.js +319 -0
  594. package/dist/utils/document-writer.js.map +1 -0
  595. package/dist/utils/help-loader.d.ts +2 -2
  596. package/dist/utils/help-loader.js +2 -2
  597. package/dist/utils/install-plan.d.ts +99 -0
  598. package/dist/utils/install-plan.d.ts.map +1 -0
  599. package/dist/utils/install-plan.js +146 -0
  600. package/dist/utils/install-plan.js.map +1 -0
  601. package/dist/utils/issue-anchor.d.ts +1 -1
  602. package/dist/utils/issue-anchor.d.ts.map +1 -1
  603. package/dist/utils/issue-anchor.js.map +1 -1
  604. package/dist/utils/issue-rendering.d.ts +8 -3
  605. package/dist/utils/issue-rendering.d.ts.map +1 -1
  606. package/dist/utils/issue-rendering.js +4 -0
  607. package/dist/utils/issue-rendering.js.map +1 -1
  608. package/dist/utils/lens-population.d.ts +20 -0
  609. package/dist/utils/lens-population.d.ts.map +1 -0
  610. package/dist/utils/lens-population.js +15 -0
  611. package/dist/utils/lens-population.js.map +1 -0
  612. package/dist/utils/marketplace-io.d.ts +63 -0
  613. package/dist/utils/marketplace-io.d.ts.map +1 -0
  614. package/dist/utils/marketplace-io.js +63 -0
  615. package/dist/utils/marketplace-io.js.map +1 -0
  616. package/dist/utils/operator-notices.d.ts +97 -0
  617. package/dist/utils/operator-notices.d.ts.map +1 -0
  618. package/dist/utils/operator-notices.js +115 -0
  619. package/dist/utils/operator-notices.js.map +1 -0
  620. package/dist/utils/optional-backend.d.ts +18 -15
  621. package/dist/utils/optional-backend.d.ts.map +1 -1
  622. package/dist/utils/optional-backend.js +22 -33
  623. package/dist/utils/optional-backend.js.map +1 -1
  624. package/dist/utils/output.d.ts +5 -43
  625. package/dist/utils/output.d.ts.map +1 -1
  626. package/dist/utils/output.js +8 -63
  627. package/dist/utils/output.js.map +1 -1
  628. package/dist/utils/package-json.d.ts +3 -4
  629. package/dist/utils/package-json.d.ts.map +1 -1
  630. package/dist/utils/package-json.js +8 -8
  631. package/dist/utils/package-json.js.map +1 -1
  632. package/dist/utils/population-wiring.d.ts +31 -38
  633. package/dist/utils/population-wiring.d.ts.map +1 -1
  634. package/dist/utils/population-wiring.js +38 -32
  635. package/dist/utils/population-wiring.js.map +1 -1
  636. package/dist/utils/project-root-policy.d.ts +74 -1
  637. package/dist/utils/project-root-policy.d.ts.map +1 -1
  638. package/dist/utils/project-root-policy.js +146 -8
  639. package/dist/utils/project-root-policy.js.map +1 -1
  640. package/dist/utils/projection-lenses.d.ts +25 -7
  641. package/dist/utils/projection-lenses.d.ts.map +1 -1
  642. package/dist/utils/projection-lenses.js +20 -6
  643. package/dist/utils/projection-lenses.js.map +1 -1
  644. package/dist/utils/projection-query.d.ts +17 -10
  645. package/dist/utils/projection-query.d.ts.map +1 -1
  646. package/dist/utils/projection-query.js +47 -28
  647. package/dist/utils/projection-query.js.map +1 -1
  648. package/dist/utils/projection-store.d.ts +2 -2
  649. package/dist/utils/projection-store.d.ts.map +1 -1
  650. package/dist/utils/projection-store.js +74 -45
  651. package/dist/utils/projection-store.js.map +1 -1
  652. package/dist/utils/rag-database.d.ts +61 -0
  653. package/dist/utils/rag-database.d.ts.map +1 -0
  654. package/dist/utils/rag-database.js +178 -0
  655. package/dist/utils/rag-database.js.map +1 -0
  656. package/dist/utils/relation-limits.d.ts +7 -2
  657. package/dist/utils/relation-limits.d.ts.map +1 -1
  658. package/dist/utils/relation-limits.js +6 -1
  659. package/dist/utils/relation-limits.js.map +1 -1
  660. package/dist/utils/relativize-paths.d.ts +23 -0
  661. package/dist/utils/relativize-paths.d.ts.map +1 -1
  662. package/dist/utils/relativize-paths.js +32 -1
  663. package/dist/utils/relativize-paths.js.map +1 -1
  664. package/dist/utils/resource-loader.d.ts +76 -32
  665. package/dist/utils/resource-loader.d.ts.map +1 -1
  666. package/dist/utils/resource-loader.js +132 -66
  667. package/dist/utils/resource-loader.js.map +1 -1
  668. package/dist/utils/run-integrity.d.ts +64 -31
  669. package/dist/utils/run-integrity.d.ts.map +1 -1
  670. package/dist/utils/run-integrity.js +76 -35
  671. package/dist/utils/run-integrity.js.map +1 -1
  672. package/dist/utils/scope-locations.d.ts +7 -5
  673. package/dist/utils/scope-locations.d.ts.map +1 -1
  674. package/dist/utils/scope-locations.js +37 -12
  675. package/dist/utils/scope-locations.js.map +1 -1
  676. package/dist/utils/staging-dir.d.ts +7 -0
  677. package/dist/utils/staging-dir.d.ts.map +1 -0
  678. package/dist/utils/staging-dir.js +12 -0
  679. package/dist/utils/staging-dir.js.map +1 -0
  680. package/dist/utils/url-redact.d.ts +9 -0
  681. package/dist/utils/url-redact.d.ts.map +1 -1
  682. package/dist/utils/url-redact.js +13 -0
  683. package/dist/utils/url-redact.js.map +1 -1
  684. package/dist/utils/user-context-scanner.d.ts +3 -2
  685. package/dist/utils/user-context-scanner.d.ts.map +1 -1
  686. package/dist/utils/user-context-scanner.js +24 -4
  687. package/dist/utils/user-context-scanner.js.map +1 -1
  688. package/dist/utils/validate-help-files.d.ts.map +1 -1
  689. package/dist/utils/validate-help-files.js +8 -14
  690. package/dist/utils/validate-help-files.js.map +1 -1
  691. package/dist/utils/vat-bin-path.d.ts.map +1 -1
  692. package/dist/utils/vat-bin-path.js +3 -3
  693. package/dist/utils/vat-bin-path.js.map +1 -1
  694. package/dist/utils/verdict-helpers.d.ts.map +1 -1
  695. package/dist/utils/verdict-helpers.js +5 -5
  696. package/dist/utils/verdict-helpers.js.map +1 -1
  697. package/docs/agent.md +347 -2
  698. package/docs/audit.md +312 -89
  699. package/docs/doctor.md +65 -19
  700. package/docs/index.md +571 -20
  701. package/docs/mcp.md +64 -12
  702. package/docs/rag.md +176 -48
  703. package/docs/resources.md +257 -71
  704. package/docs/skill-test.md +148 -19
  705. package/docs/skills.md +459 -174
  706. package/package.json +16 -19
  707. package/schemas/agent-build.json +268 -0
  708. package/schemas/agent-import.json +252 -0
  709. package/schemas/agent-install.json +260 -0
  710. package/schemas/agent-installed.json +287 -0
  711. package/schemas/agent-list.json +279 -0
  712. package/schemas/agent-uninstall.json +260 -0
  713. package/schemas/agent-validate.json +279 -0
  714. package/schemas/ard-emit.json +224 -106
  715. package/schemas/audit-settings.json +472 -0
  716. package/schemas/audit.json +635 -0
  717. package/schemas/cache-clear.json +273 -0
  718. package/schemas/claude-marketplace-publish.json +286 -0
  719. package/schemas/claude-marketplace-validate.json +352 -0
  720. package/schemas/claude-org-not-implemented.json +239 -0
  721. package/schemas/claude-plugin-build.json +446 -0
  722. package/schemas/claude-plugin-install.json +291 -0
  723. package/schemas/claude-plugin-list.json +326 -0
  724. package/schemas/claude-plugin-uninstall.json +272 -0
  725. package/schemas/corpus-audit.json +635 -0
  726. package/schemas/corpus-scan.json +293 -0
  727. package/schemas/doctor.json +299 -0
  728. package/schemas/inventory.json +982 -0
  729. package/schemas/mcp-list-collections.json +268 -0
  730. package/schemas/okf-validate.json +224 -106
  731. package/schemas/orchestrator.json +299 -0
  732. package/schemas/rag-clear.json +253 -0
  733. package/schemas/rag-index.json +273 -0
  734. package/schemas/rag-query.json +365 -0
  735. package/schemas/rag-stats.json +269 -0
  736. package/schemas/resources-check.json +242 -108
  737. package/schemas/resources-query.json +333 -0
  738. package/schemas/resources-scan.json +321 -0
  739. package/schemas/resources-validate.json +332 -0
  740. package/schemas/skill-review.json +224 -106
  741. package/schemas/skill-test-configure.json +256 -0
  742. package/schemas/skill-test-run.json +296 -0
  743. package/schemas/skills-build.json +325 -0
  744. package/schemas/skills-install.json +287 -0
  745. package/schemas/skills-list.json +283 -0
  746. package/schemas/skills-package.json +270 -0
  747. package/schemas/skills-validate.json +285 -0
  748. package/dist/commands/skills/shared.d.ts +0 -29
  749. package/dist/commands/skills/shared.d.ts.map +0 -1
  750. package/dist/commands/skills/shared.js +0 -33
  751. package/dist/commands/skills/shared.js.map +0 -1
  752. package/dist/utils/command-error.d.ts +0 -194
  753. package/dist/utils/command-error.d.ts.map +0 -1
  754. package/dist/utils/command-error.js +0 -237
  755. package/dist/utils/command-error.js.map +0 -1
@@ -3,32 +3,33 @@
3
3
  * Top-level command: vat audit [path]
4
4
  */
5
5
  import * as fs from 'node:fs';
6
- import { existsSync as fsExistsSync } from 'node:fs';
7
6
  import { basename } from 'node:path';
8
- import { conventionalSuiteProbe, crawlAndResolveRegistry, detectDeclaredButMissing, detectMarketplacePluginSourceMissing, resetPackagingRegistryCache, detectPresentButUndeclared, detectReferenceTargetMissing, detectResourceFormat, enumerateSurfaces, materializeIssue, validate, validateMarketplace, validateSkill, validateSkillForPackaging, } from '@vibe-agent-toolkit/agent-skills';
7
+ import { conventionalSuiteProbe, crawlAndResolveRegistry, detectDeclaredButMissing, detectMarketplacePluginSourceMissing, resetPackagingRegistryCache, detectPresentButUndeclared, detectReferenceTargetMissing, describeIssues, detectResourceFormat, enumerateSurfaces, materializeIssue, validate, validateMarketplace, validateSkill, validateSkillForPackaging, } from '@vibe-agent-toolkit/agent-skills';
9
8
  import { analyzeCompatibility, checkSettingsCompatibility, detectSkillClaudePluginNameMismatch, crawlSkillLinkRegistry, extractClaudeMarketplaceInventory, extractClaudePluginInventory, getClaudeUserPaths, readEffectiveSettings, validatePlugin, } from '@vibe-agent-toolkit/claude-marketplace';
10
9
  import { detectFormat } from '@vibe-agent-toolkit/discovery';
11
10
  import { listingRefusalRemedy } from '@vibe-agent-toolkit/resources';
12
- import { calculateValidationStatus, countBySeverity, ExitCode, } from '@vibe-agent-toolkit/schema';
13
- import { findProjectRoot, isFilesystemAccessError, isPathAbsentError, issueLocation, relativeEscapesRoot, resetProjectRootCaches, safePath, toForwardSlash, } from '@vibe-agent-toolkit/utils';
11
+ import { buildReport, countBySeverity, exitCodeForReport, summarizeIssues, toFindings, withAddedFindings, } from '@vibe-agent-toolkit/schema';
12
+ import { everywhere, findProjectRoot, followedKind, followedKindSync, forEachInOrder, fsFaultOf, isPathAbsentError, issueLocation, mapInOrder, pathPresent, relativeEscapesRoot, resetProjectRootCaches, safePath, toForwardSlash, } from '@vibe-agent-toolkit/utils';
14
13
  import { DirectoryListingRefusedError } from '@vibe-agent-toolkit/utils/crawl';
15
14
  import { gitFindRoot, isGitUrl, parseGitUrl, } from '@vibe-agent-toolkit/utils/git';
16
15
  import { Command } from 'commander';
17
16
  import { resetSkillDiscoveryCache, resolveProjectDeclaredEvalSuites, resolveSkillPackagingConfig, stripValidationAllowForDisplay, } from '../skill-resolution/packaging-config.js';
18
- import { handleCommandError, handleExpectedFailure } from '../utils/command-error.js';
17
+ import { CommandRefusalError, errorMessageOf, refusalCodeOf } from '../utils/command-refusal.js';
19
18
  import { ConfigLoadError, loadConfig, resetLoadedConfigCache, } from '../utils/config-loader.js';
20
- import { countCollapsedFindings, formatCollapsedFindingsHint, formatIssueLines, formatSeverityBreakdown, issuesToRenderAtVerbosity, sumSeverityCounts, } from '../utils/issue-rendering.js';
19
+ import { endWithRefusal, leftoverIssueOf, NOTHING_FINISHED, writeDocument } from '../utils/document-writer.js';
20
+ import { countCollapsedFindings, formatCollapsedFindingsHint, formatIssueLines, formatSeverityBreakdown, issuesToRenderAtVerbosity, } from '../utils/issue-rendering.js';
21
21
  import { resolveIssueSeverity } from '../utils/issue-severity.js';
22
22
  import { createLogger } from '../utils/logger.js';
23
- import { writeYamlOutput } from '../utils/output.js';
24
- import { relativizePathEntries } from '../utils/relativize-paths.js';
25
- import { nothingCheckedFinding } from '../utils/run-integrity.js';
23
+ import { classifyInputFault, readInputFile, unlistableDirectoryRefusal } from '../utils/project-root-policy.js';
24
+ import { relativizePath } from '../utils/relativize-paths.js';
25
+ import { RUN_INTEGRITY_CODE } from '../utils/run-integrity.js';
26
26
  import { mergeSkillPackagingConfig } from '../utils/skill-packaging-config.js';
27
27
  import { renderSkillQualityFooter } from '../utils/skill-quality-footer.js';
28
28
  import { computeConfigVerdicts } from '../utils/verdict-helpers.js';
29
+ import { compatLaneIssues } from './audit/compat-lane-findings.js';
29
30
  import { crawlOwnsSubtree, distributedTreeFindings, getOrCreateGitTracker, gitTrackerForProjectRoot, isWithin, resetGitTrackerCache, } from './audit/distributed-tree.js';
30
31
  import { withClonedRepo } from './audit/git-url-clone.js';
31
- import { buildHierarchicalOutput } from './audit/hierarchical-output.js';
32
+ import { addMisconfigurationIssues, buildHierarchicalOutput } from './audit/hierarchical-output.js';
32
33
  import { renderProvenanceHeader, rewritePathsInResults, } from './audit/provenance.js';
33
34
  import { enumerateAuditPopulation, resolveProjectExcludes, VAT_CONFIG_FILENAME, } from './audit/scan-population.js';
34
35
  import { createAuditSettingsCommand } from './audit-settings.js';
@@ -55,12 +56,13 @@ const RESOURCE_TYPE_CLAUDE_PLUGIN = 'claude-plugin';
55
56
  */
56
57
  async function buildVATProjectContext(scanRoot, logger, locationRoot) {
57
58
  const configPath = safePath.join(scanRoot, VAT_CONFIG_FILENAME);
58
- if (!fs.existsSync(configPath)) {
59
+ // A probe the OS refuses is the config's source fault, never "no config here".
60
+ if (!pathPresent(configPath, { follow: scanRoot }, everywhere('source'), 'probe')) {
59
61
  return null;
60
62
  }
61
63
  let config;
62
64
  try {
63
- config = loadConfig(scanRoot);
65
+ config = loadConfig(scanRoot, 'source');
64
66
  }
65
67
  catch (error) {
66
68
  logger.debug(`Config-aware audit: skipping invalid config in ${scanRoot}: ${String(error)}`);
@@ -96,23 +98,17 @@ async function buildVATProjectContext(scanRoot, logger, locationRoot) {
96
98
  }
97
99
  return { skillConfigs };
98
100
  }
99
- /**
100
- * Convert PackagingValidationResult to ValidationResult for consistent audit output.
101
- * In audit mode, we merge allErrors (which includes both errors and warnings after
102
- * severity resolution but WITHOUT allow suppression) into the standard issues array.
103
- *
104
- * Compat verdicts (COMPAT_TARGET_*) are computed from the result's observations
105
- * and the config-level targets, then merged into the issue list.
106
- */
107
- /**
108
- * The one-line human summary of a severity distribution.
109
- *
110
- * Every result that carries findings renders its counts the same way, so a reader
111
- * comparing two entries is comparing the same sentence.
112
- */
113
- function formatCountsSummary(counts) {
114
- return `${counts.errors} errors, ${counts.warnings} warnings, ${counts.info} info`;
101
+ /** A file carries an error-severity finding — the `filesWithErrors` bucket. */
102
+ function hasErrors(result) {
103
+ return countBySeverity(result.issues).errors > 0;
104
+ }
105
+ /** A file's worst actionable finding is a warning — the `filesWithWarnings` bucket. */
106
+ function hasOnlyWarnings(result) {
107
+ const { errors, warnings } = countBySeverity(result.issues);
108
+ return errors === 0 && warnings > 0;
115
109
  }
110
+ /** `vat audit` has no `--strict`: warnings never move its exit code. */
111
+ const AUDIT_GATE = { strict: false };
116
112
  /**
117
113
  * Append findings to a result and re-derive everything that describes them.
118
114
  *
@@ -124,17 +120,25 @@ function formatCountsSummary(counts) {
124
120
  *
125
121
  * Mutates in place, because the audit pipeline hands these results around by
126
122
  * reference and there is no single place a rebuilt copy could be swapped in.
123
+ * The sentence comes from the same `describeIssues` the producer used, so the
124
+ * re-derived one is exactly what the producer says for the grown list — never a
125
+ * second wording, and never a stale "Valid plugin" beside a warning.
127
126
  */
128
127
  function appendIssues(result, issues) {
129
128
  if (issues.length === 0) {
130
129
  return;
131
130
  }
132
131
  result.issues.push(...issues);
133
- const counts = countBySeverity(result.issues);
134
- result.status = calculateValidationStatus(result.issues);
135
- result.issueCounts = counts;
136
- result.summary = formatCountsSummary(counts);
132
+ Object.assign(result, describeIssues(result.issues, result.type));
137
133
  }
134
+ /**
135
+ * Convert PackagingValidationResult to ValidationResult for consistent audit output.
136
+ * In audit mode, we merge allErrors (which includes both errors and warnings after
137
+ * severity resolution but WITHOUT allow suppression) into the standard issues array.
138
+ *
139
+ * Compat verdicts (COMPAT_TARGET_*) are computed from the result's observations
140
+ * and the config-level targets, then merged into the issue list.
141
+ */
138
142
  function packagingResultToValidationResult(skillPath, result, configTargets, locationRoot) {
139
143
  // allErrors contains all emitted issues (errors + warnings) after severity resolution
140
144
  // but without allow suppression — exactly what audit wants. Verdicts are
@@ -143,14 +147,11 @@ function packagingResultToValidationResult(skillPath, result, configTargets, loc
143
147
  const issues = verdictIssues.length > 0
144
148
  ? [...result.allErrors, ...verdictIssues]
145
149
  : result.allErrors;
146
- const issueCounts = countBySeverity(issues);
147
150
  const out = {
148
151
  path: skillPath,
149
152
  type: RESOURCE_TYPE_AGENT_SKILL,
150
- status: calculateValidationStatus(issues),
151
- summary: formatCountsSummary(issueCounts),
153
+ ...describeIssues(issues, RESOURCE_TYPE_AGENT_SKILL),
152
154
  issues,
153
- issueCounts,
154
155
  metadata: {
155
156
  lineCount: result.metadata.skillLines,
156
157
  name: result.skillName,
@@ -196,7 +197,7 @@ function packagingResultToValidationResult(skillPath, result, configTargets, loc
196
197
  *
197
198
  * ⚠️ The filesystem question IS asked, and the answer changes what the operator
198
199
  * is told. `config-loader.ts` preserves `cause` specifically so callers can ask
199
- * `isFilesystemAccessError` and "decide whether to degrade or abort"; catching
200
+ * `fsFaultOf` and "decide whether to degrade or abort"; catching
200
201
  * `ConfigLoadError` unconditionally never asked at all, so a `chmod 000` config
201
202
  * and a typo produced the same sentence — and a permissions problem is not a
202
203
  * broken config.
@@ -317,7 +318,7 @@ function recordUnloadableConfig(err, logger, locationRoot) {
317
318
  // different actions from the operator: `chmod`/ownership on one side, an edit
318
319
  // to the file on the other. Collapsing them into one sentence was the whole
319
320
  // cost of never asking.
320
- const why = isFilesystemAccessError(err) ? 'unreadable' : 'unloadable';
321
+ const why = fsFaultOf(err) === undefined ? 'unloadable' : 'unreadable';
321
322
  logger.warn(`Ignoring ${why} config at ${configPath}; skills it governs are validated`
322
323
  + ` config-free: ${err.message}`);
323
324
  }
@@ -340,7 +341,7 @@ function recordUnloadableConfig(err, logger, locationRoot) {
340
341
  function degradingDiscovery(configRoot, logger, locationRoot) {
341
342
  return {
342
343
  degrade: (refusal) => {
343
- recordRefusedDiscovery(new DirectoryListingRefusedError(refusal, { root: configRoot, remedy: SKILLS_INCLUDE_REMEDY }), configRoot, logger, locationRoot);
344
+ recordRefusedDiscovery(new DirectoryListingRefusedError(refusal, { root: configRoot, remedy: SKILLS_INCLUDE_REMEDY, side: 'source' }), configRoot, logger, locationRoot);
344
345
  },
345
346
  };
346
347
  }
@@ -372,7 +373,7 @@ function degradingDiscovery(configRoot, logger, locationRoot) {
372
373
  function degradingRegistry(projectRoot, logger, locationRoot) {
373
374
  return {
374
375
  degrade: (refusal) => {
375
- const err = new DirectoryListingRefusedError(refusal, { root: projectRoot, remedy: listingRefusalRemedy(projectRoot) });
376
+ const err = new DirectoryListingRefusedError(refusal, { root: projectRoot, remedy: listingRefusalRemedy(projectRoot), side: 'source' });
376
377
  recordRefusedListing(err, logger, locationRoot, () => `The link graph under ${projectRoot} skipped an unreadable directory; every document beneath it`
377
378
  + ` is missing from this audit's link and reference checks: ${err.message}`);
378
379
  },
@@ -469,8 +470,10 @@ async function validateSingleSkill(skillPath, options, logger, locationRoot, cra
469
470
  // makes when this registry does not cover the skill: one ruling, both crawls.
470
471
  const unreadable = degradingRegistry(projectRoot, logger, locationRoot);
471
472
  const sharedCtx = {
472
- registry: await crawlAndResolveRegistry(projectRoot, { unreadable }),
473
+ registry: await crawlAndResolveRegistry(projectRoot, { outputs: [], unreadable }),
473
474
  unreadable,
475
+ // An audit only reads the trees it scans.
476
+ outputs: [],
474
477
  locationRoot,
475
478
  projectSkills: await resolveProjectDeclaredEvalSuites(skillPath, degradingDiscovery(projectRoot, logger, locationRoot)),
476
479
  // The RUN's probe, not this call's — see {@link runSuiteProbe}. This lane
@@ -486,7 +489,8 @@ async function validateSingleSkill(skillPath, options, logger, locationRoot, cra
486
489
  return configAware;
487
490
  }
488
491
  // Fallback: basic validation. Severity is applied by `applySeverityFilter`.
489
- const validateOptions = { skillPath, locationRoot, validation: {} };
492
+ // The audited skill is the verb's input.
493
+ const validateOptions = { skillPath, locationRoot, validation: {}, side: 'source' };
490
494
  if (options.warnUnreferencedFiles) {
491
495
  validateOptions.checkUnreferencedFiles = true;
492
496
  }
@@ -533,13 +537,13 @@ function collect(value, previous) {
533
537
  * Create audit command
534
538
  * Top-level command: vat audit [path]
535
539
  *
536
- * The exit code follows the document's `status`, under the one exit-code
537
- * contract every verb shares: `OK` when nothing is at error severity,
538
- * `FINDINGS` when something is (or the run audited zero files), `ERROR` when
539
- * the audit could not run at all. This command used to be the one exception —
540
- * "advisory", exit 0 over `status: error` — which a CI author reading the
541
- * shared contract got wrong on exactly this verb. Warnings never move the
542
- * exit code; `validation.severity` is the dial that decides what counts.
540
+ * Publishes the report envelope through the one writer, and ends on the code
541
+ * the written document derives — the rule every report verb shares: `OK` when
542
+ * no finding is at error severity, `FINDINGS` when one is (a run that audited
543
+ * zero files carries the writer's `RESOURCE_CHECK_BROKEN`), `ERROR` only when
544
+ * the audit did not finish (`status: error`, with the refusal in `error.code`).
545
+ * Warnings never move the exit code — audit has no `--strict`;
546
+ * `validation.severity` is the dial that decides what counts.
543
547
  */
544
548
  export function createAuditCommand() {
545
549
  const audit = new Command('audit');
@@ -607,12 +611,19 @@ Description:
607
611
  (See packages/cli/docs/audit.md for details.)
608
612
 
609
613
  Output:
610
- The YAML 'status' describes the findings, and the exit code follows it, as
611
- in every other command of this CLI.
614
+ The report envelope every report verb publishes (YAML on stdout):
615
+ - status: ok (no findings) | findings (at least one) | error (did not finish)
616
+ - examined: files read; summary: findings by severity; gate: { strict: false }
617
+ - findings: every finding, each with the file to open as 'location'
618
+ - data.root: the scan root every path is relative to (null for a git URL,
619
+ whose data.provenance names the source instead)
620
+ - data.counts: filesPassed / filesWithWarnings / filesWithErrors /
621
+ pathsUnreadable; data.files: one row per file (status, summary,
622
+ compatibility, settings); data.hierarchical: the --user grouping
623
+ - error: { code, message } when status is error
612
624
 
613
- A run that audited ZERO files is refused, not passed: 'status: error' with one
614
- non-overridable RESOURCE_CHECK_BROKEN under a top-level 'issues:' (the claim is
615
- about the run, so it is not a files[] row), and exit 1.
625
+ A run that audited ZERO files is not a pass: the report carries one
626
+ non-overridable RESOURCE_CHECK_BROKEN finding and ends on exit 1.
616
627
 
617
628
  Validation Behavior:
618
629
  Audit surfaces all validation issues for inspection.
@@ -620,9 +631,8 @@ Validation Behavior:
620
631
  - NEVER applies validation.allow (allowed codes are always shown)
621
632
  - Respects validation.severity: a code set to 'ignore' is hidden; warnings
622
633
  and errors are both reported, each at its configured severity
623
- - ALWAYS exits 0 for validation results (never gates on errors)
624
634
 
625
- For gated validation (CI/CD), use: vat skills validate
635
+ For gated validation that honours validation.allow, use: vat skills validate
626
636
  For the full list of codes and severity defaults, see: docs/validation-codes.md
627
637
 
628
638
  Default: Validates SKILL.md and all transitively linked markdown files
@@ -640,7 +650,10 @@ Validation Checks:
640
650
  Warnings (should fix):
641
651
  - Skill exceeds recommended length (>5000 lines)
642
652
  - With --compat: a declared target cannot or may not run the skill
643
- (COMPAT_TARGET_INCOMPATIBLE, COMPAT_TARGET_NEEDS_REVIEW)
653
+ (COMPAT_TARGET_INCOMPATIBLE, COMPAT_TARGET_NEEDS_REVIEW); a plugin or a
654
+ path the analysis could not look at (COMPAT_NOT_CHECKED)
655
+ - With --compat --settings: something the plugin declares that the settings
656
+ block (SETTINGS_POLICY_CONFLICT)
644
657
  - Unreferenced files detected (with --warn-unreferenced-files)
645
658
 
646
659
  Info (observations):
@@ -679,20 +692,23 @@ Config-Aware Validation:
679
692
  skills.config.<name>.validation... that one skill
680
693
 
681
694
  Exit Codes:
682
- 0 - The audit completed with nothing at error severity (warnings and
695
+ 0 - The audit finished and no finding is at error severity (warnings and
683
696
  informational findings are in the report, not the exit code).
684
- 1 - The audit completed and reports 'status: error': at least one
685
- error-severity finding, or zero files audited. A path inside the tree
686
- the scan could not read, or a governing config that cannot be loaded
687
- or whose skills.include reaches an unreadable directory, is
688
- SCAN_PATH_UNREADABLE (warning): the run is degraded, not failed —
689
- readable siblings are still validated, the config's skills
690
- config-free, and the refused path is not counted in filesScanned.
691
- 2 - The audit could not run at all: the path does not exist, is a
692
- directory the OS will not list, or is a file no audit lane
693
- recognises, --user with no Claude config dir, a git URL
694
- that would not clone, an unknown flag, an internal failure. There is
695
- no report to read.
697
+ 1 - The audit finished with at least one error-severity finding
698
+ ('status: findings'), including zero files audited. A path inside the
699
+ tree the scan could not read, or a governing config that cannot be
700
+ loaded, is SCAN_PATH_UNREADABLE (warning): the run is degraded, not
701
+ failed, and the refused path is counted in data.counts.pathsUnreadable,
702
+ never in 'examined'.
703
+ 2 - The audit did not finish ('status: error', the reason in error.code):
704
+ USAGE_INVALID for a path that does not exist, a file no audit lane
705
+ recognises, a git URL that does not parse, --user with no Claude
706
+ config dir, --settings without --compat or together with --user, or a
707
+ --settings file that does not exist; INPUT_UNREADABLE for a root
708
+ directory the OS will not list, a git URL that would not clone, or a
709
+ settings file (named or auto-discovered) the OS refuses, that does not
710
+ parse, or that fails the settings schema; INTERNAL_ERROR for a defect
711
+ in VAT.
696
712
 
697
713
  Examples:
698
714
  $ vat audit ./plugins/ # Audit recursively (default)
@@ -739,23 +755,22 @@ export function userScanTargets(candidates, recursive) {
739
755
  }
740
756
  /**
741
757
  * Handle --user audit: scans ~/.claude/plugins, ~/.claude/skills, ~/.claude/marketplaces
742
- * and outputs hierarchical YAML. Calls process.exit() when done.
758
+ * and publishes the report with its `data.hierarchical` view. Calls process.exit() when done.
743
759
  */
744
760
  async function auditUserDirectories(recursive, options, startTime, logger) {
745
761
  const { claudeDir, pluginsDir, skillsDir, marketplacesDir } = getClaudeUserPaths();
746
762
  // --user scans three sibling directories; they share ONE enclosing Claude
747
763
  // config dir, so that is the run's single stated root.
748
764
  const scanRoot = safePath.resolve(claudeDir);
749
- const pluginsDirExists = fs.existsSync(pluginsDir);
750
- const skillsDirExists = fs.existsSync(skillsDir);
751
- const marketplacesDirExists = fs.existsSync(marketplacesDir);
765
+ // Each install root is the operator's own configuration (`CLAUDE_CONFIG_DIR`/`HOME`), so it is
766
+ // its own `within`; a probe the OS refuses is that root's source fault, never "not installed".
767
+ const userRootPresent = (dir) => pathPresent(dir, { follow: dir }, everywhere('source'), 'probe');
768
+ const pluginsDirExists = userRootPresent(pluginsDir);
769
+ const skillsDirExists = userRootPresent(skillsDir);
770
+ const marketplacesDirExists = userRootPresent(marketplacesDir);
752
771
  if (!pluginsDirExists && !skillsDirExists && !marketplacesDirExists) {
753
- logger.error(`No user-level Claude directories found:`);
754
- logger.error(` Plugins: ${pluginsDir}`);
755
- logger.error(` Skills: ${skillsDir}`);
756
- logger.error(` Marketplaces: ${marketplacesDir}`);
757
- logger.error('Claude plugins/skills/marketplaces have not been installed yet.');
758
- process.exit(ExitCode.ERROR);
772
+ throw new CommandRefusalError('USAGE_INVALID', `No user-level Claude directories found (plugins: ${pluginsDir}, skills: ${skillsDir}, marketplaces: ${marketplacesDir}). `
773
+ + 'Claude plugins, skills and marketplaces have not been installed yet — set CLAUDE_CONFIG_DIR to the config dir to audit.');
759
774
  }
760
775
  const scanned = [];
761
776
  // The roots that exist, minus any one another already covers — see
@@ -765,27 +780,36 @@ async function auditUserDirectories(recursive, options, startTime, logger) {
765
780
  ...(skillsDirExists ? [skillsDir] : []),
766
781
  ...(marketplacesDirExists ? [marketplacesDir] : []),
767
782
  ];
768
- for (const target of userScanTargets(present, recursive)) {
783
+ // In order: the targets share the population cache and the logger.
784
+ await forEachInOrder(userScanTargets(present, recursive), async (target) => {
769
785
  logger.debug(`Auditing user-level resources at: ${target}`);
770
786
  scanned.push(...await getValidationResults(target, recursive, options, logger, scanRoot));
771
- }
787
+ });
772
788
  // The `--user` report is assembled here rather than by `buildAuditReport`, so
773
789
  // it needs its own append or the config findings would reach stderr and not the
774
- // document — see the same call in `buildAuditReport`.
775
- const results = withDegradedConfigFindings(scanned);
790
+ // document — see the same call in `buildAuditReport`. The misconfiguration
791
+ // findings join the RESULTS, not only the hierarchy, so the envelope counts them.
792
+ const results = addMisconfigurationIssues(withDegradedConfigFindings(scanned), scanRoot);
776
793
  // Run compatibility analysis if --compat flag is set
777
794
  const compatMap = options.compat
778
- ? await runCompatAnalysis(results, logger, scanRoot) // --settings not supported in --user mode
795
+ ? await runCompatAnalysis(results, logger, scanRoot) // --settings is refused under --user
779
796
  : undefined;
780
797
  const verbose = options.verbose ?? false;
781
798
  const skillResults = results.filter((r) => SKILL_RESULT_TYPES.has(r.type));
782
799
  const hierarchical = buildHierarchicalOutput(skillResults, verbose, scanRoot);
783
- const summary = calculateHierarchicalSummary(results, hierarchical, startTime, compatMap, verbose, scanRoot);
784
- writeYamlOutput(summary);
800
+ const report = buildAuditDocument(results, {
801
+ root: scanRoot,
802
+ compatMap,
803
+ verbose,
804
+ hierarchical,
805
+ durationMs: Date.now() - startTime,
806
+ });
807
+ const written = writeDocument('audit', report, 'yaml');
785
808
  if (verbose) {
786
809
  renderVerboseEvidence(results, scanRoot, logger);
787
810
  }
788
- logHierarchicalSummary(results, summary.issues, logger);
811
+ logHierarchicalSummary({ results, written, data: report.data, root: scanRoot, verbose }, logger);
812
+ process.exit(exitCodeForReport(written));
789
813
  }
790
814
  /** Skill resource types that can have per-skill validation config. */
791
815
  const SKILL_RESULT_TYPES = new Set([RESOURCE_TYPE_AGENT_SKILL, 'vat-agent']);
@@ -809,7 +833,8 @@ const SKILL_RESULT_TYPES = new Set([RESOURCE_TYPE_AGENT_SKILL, 'vat-agent']);
809
833
  */
810
834
  export function deriveScanRoot(targetPath) {
811
835
  const resolved = safePath.resolve(targetPath);
812
- const isDirectory = fs.existsSync(resolved) && fs.statSync(resolved).isDirectory();
836
+ // The operator's own target: its own `within`.
837
+ const isDirectory = followedKindSync(resolved, resolved) === 'directory';
813
838
  return isDirectory ? resolved : safePath.resolve(resolved, '..');
814
839
  }
815
840
  /**
@@ -841,15 +866,12 @@ function deriveConfigRoot(targetPath) {
841
866
  * Build the recalculated status and summary after issues have been filtered.
842
867
  */
843
868
  function buildFilteredResult(result, filteredIssues) {
844
- const counts = countBySeverity(filteredIssues);
845
869
  return {
846
870
  ...result,
847
- status: calculateValidationStatus(filteredIssues),
848
- // Spreading `result` carried the PRE-filter `issueCounts` forward, so a
871
+ // Spreading `result` carried the PRE-filter counts forward, so a
849
872
  // `severity: ignore` config left the counts describing findings the report
850
873
  // no longer contained. The counts are re-derived, never inherited.
851
- issueCounts: counts,
852
- summary: formatCountsSummary(counts),
874
+ ...describeIssues(filteredIssues, result.type),
853
875
  issues: filteredIssues,
854
876
  };
855
877
  }
@@ -970,29 +992,57 @@ function isEmptiedUnreadablePathResult(result) {
970
992
  && result.metadata === undefined;
971
993
  }
972
994
  /**
973
- * Resolve `--settings`-driven EffectiveSettings if both --settings and
974
- * --compat flags are present. Logs warnings for misconfiguration paths.
995
+ * Refuse a `--settings` the run would otherwise ignore, before any scan or clone.
996
+ *
997
+ * Every arm used to be a stderr line and exit 0: without `--compat` a warning
998
+ * and no settings check; under `--user` nothing at all; and a named file that
999
+ * is absent read as "no settings", so `--compat --settings /typo.json` printed
1000
+ * `findings: []` for a check that never compared anything. The sibling verb
1001
+ * `audit settings --file <missing>` refuses the same path.
1002
+ *
1003
+ * @throws {CommandRefusalError} `USAGE_INVALID` for a flag the run cannot honour
1004
+ * or a named file that is absent; `INPUT_UNREADABLE` for one the OS refuses
975
1005
  */
976
- async function resolveEffectiveSettings(options, scanPath, logger) {
977
- if (!options.settings)
978
- return undefined;
1006
+ function refuseUnusableSettingsFlag(options) {
1007
+ if (options.settings === undefined || options.settings === false)
1008
+ return;
979
1009
  if (!options.compat) {
980
- logger.error('Warning: --settings requires --compat to be effective');
981
- return undefined;
1010
+ throw new CommandRefusalError('USAGE_INVALID', '--settings requires --compat: the settings check runs inside the compatibility analysis. Add --compat, or drop --settings.');
1011
+ }
1012
+ if (options.user) {
1013
+ throw new CommandRefusalError('USAGE_INVALID', '--settings is not supported with --user. Audit the plugin directory with --compat --settings instead, or drop --settings.');
982
1014
  }
1015
+ if (typeof options.settings !== 'string')
1016
+ return;
1017
+ readInputFile(safePath.resolve(options.settings), { origin: 'argument', message: `Path does not exist: ${safePath.resolve(options.settings)}` });
1018
+ }
1019
+ /**
1020
+ * The EffectiveSettings `--settings` asks the compat analysis to check against.
1021
+ * Called only under `--compat`; {@link refuseUnusableSettingsFlag} has already
1022
+ * refused every combination the run cannot honour.
1023
+ *
1024
+ * @throws {CommandRefusalError} `INPUT_UNREADABLE` when a settings file (named
1025
+ * or auto-discovered) the OS refuses, does not parse, or fails its schema — the check cannot run, and a warning beside
1026
+ * an unchecked report was how it used to pass silently
1027
+ */
1028
+ async function resolveEffectiveSettings(options, scanPath) {
1029
+ if (!options.settings)
1030
+ return undefined;
983
1031
  const settingsFile = typeof options.settings === 'string' ? options.settings : undefined;
984
1032
  try {
985
1033
  return await readEffectiveSettings({ settingsFile, projectDir: scanPath });
986
1034
  }
987
- catch (err) {
988
- logger.error(`Warning: could not load settings: ${String(err)}`);
989
- return undefined;
1035
+ catch (error) {
1036
+ throw new CommandRefusalError('INPUT_UNREADABLE', `Claude settings could not be loaded for --settings: ${errorMessageOf(error)}`, { cause: error });
990
1037
  }
991
1038
  }
992
1039
  /**
993
- * Run the audit pipeline at `scanPath` and assemble the report document,
994
- * without writing anything. The document states its coordinate system once
995
- * (`root`) and every `path`/`location` beneath it is relative to that root.
1040
+ * Run the audit pipeline at `scanPath` and assemble the report, without
1041
+ * writing anything. The report states its coordinate system once
1042
+ * (`data.root`) and every `path`/`location` beneath it is relative to that root.
1043
+ *
1044
+ * The zero-files refusal is NOT here: the writer adds it from the registry's
1045
+ * denominator on the way out, as it does for every report verb.
996
1046
  *
997
1047
  * @internal Exported for integration testing only — not part of the public CLI API.
998
1048
  */
@@ -1026,7 +1076,7 @@ export async function buildAuditReport(scanPath, options, startTime, logger) {
1026
1076
  // only show more than the adopter asked for, never less.
1027
1077
  let config;
1028
1078
  try {
1029
- config = loadConfig(deriveConfigRoot(scanPath));
1079
+ config = loadConfig(deriveConfigRoot(scanPath), 'source');
1030
1080
  }
1031
1081
  catch (err) {
1032
1082
  // `warn`, not `debug`. Falling back to no config is the safe direction — it
@@ -1040,60 +1090,95 @@ export async function buildAuditReport(scanPath, options, startTime, logger) {
1040
1090
  // Apply severity filtering: hide codes whose effective severity is 'ignore'.
1041
1091
  // Allow is deliberately NOT applied — audit shows every finding.
1042
1092
  const results = applySeverityFilter(rawResults, config);
1043
- const effectiveSettings = await resolveEffectiveSettings(options, scanPath, logger);
1044
1093
  // Run compatibility analysis if --compat flag is set
1045
1094
  const compatMap = options.compat
1046
- ? await runCompatAnalysis(results, logger, scanRoot, effectiveSettings, vatContextForCompat)
1095
+ ? await runCompatAnalysis(results, logger, scanRoot, await resolveEffectiveSettings(options, scanPath), vatContextForCompat)
1047
1096
  : undefined;
1048
1097
  const verbose = options.verbose ?? false;
1049
1098
  return {
1050
1099
  results,
1051
- document: calculateSummary(results, startTime, compatMap, verbose, scanRoot),
1100
+ report: buildAuditDocument(results, {
1101
+ root: scanRoot,
1102
+ compatMap,
1103
+ verbose,
1104
+ hierarchical: null,
1105
+ durationMs: Date.now() - startTime,
1106
+ }),
1052
1107
  };
1053
1108
  }
1054
- /** Strip the run root from a report whose base cannot be named as a path. */
1055
- function withoutRoot(document) {
1056
- const copy = { ...document };
1057
- delete copy['root'];
1058
- return copy;
1109
+ /**
1110
+ * A URL audit's report: its run root is a random tempdir — not reproducible and
1111
+ * useless to a reader — so `data.root` is `null`, `data.provenance` states the
1112
+ * base instead (url @ ref @ commit), and any string still spelling the tempdir
1113
+ * is rewritten relative to the clone.
1114
+ */
1115
+ export function urlAuditReport(report, provenance, tempRoot) {
1116
+ const rewritten = rewritePathsInResults(report, tempRoot);
1117
+ return { ...rewritten, data: { ...rewritten.data, root: null, provenance } };
1059
1118
  }
1060
- async function runAuditAtPath(scanPath, options, overrides = {}) {
1119
+ /**
1120
+ * Audit `scanPath` and build the report, without publishing it: a URL audit publishes it only
1121
+ * once its clone is disposed of, so a clone left behind is a warning IN the document.
1122
+ */
1123
+ async function buildAuditAtPath(scanPath, options, overrides = {}) {
1061
1124
  const logger = createLogger(options.debug ? { debug: true } : {});
1062
1125
  const startTime = Date.now();
1063
1126
  const verbose = options.verbose ?? false;
1064
- const { results, document } = await buildAuditReport(scanPath, options, startTime, logger);
1065
- // A URL audit's run root is a random tempdir: not reproducible and useless to
1066
- // a reader. The provenance header states the base instead (url @ ref @ commit)
1067
- // and every path below is already relative to the clone, so drop `root`
1068
- // rather than print a path nobody can resolve.
1069
- const finalDocument = overrides.tempRoot === undefined ? document : rewritePathsInResults(withoutRoot(document), overrides.tempRoot);
1070
- if (overrides.provenance) {
1071
- process.stdout.write(renderProvenanceHeader(overrides.provenance));
1072
- }
1073
- writeYamlOutput(finalDocument);
1127
+ const { results, report } = await buildAuditReport(scanPath, options, startTime, logger);
1128
+ const scanRoot = deriveScanRoot(scanPath);
1129
+ if (overrides.provenance !== undefined) {
1130
+ // The human half of the provenance: the machine half is `data.provenance`.
1131
+ logger.info(renderProvenanceHeader(overrides.provenance).trimEnd());
1132
+ }
1133
+ const published = overrides.provenance === undefined || overrides.tempRoot === undefined
1134
+ ? report
1135
+ : urlAuditReport(report, overrides.provenance, overrides.tempRoot);
1136
+ return { results, report: published, scanRoot, logger, verbose, startTime };
1137
+ }
1138
+ /**
1139
+ * Publish a built audit, with `added` findings the run learned of after building it.
1140
+ *
1141
+ * @returns What was published. The caller exits with the code it calls for.
1142
+ */
1143
+ function publishAudit(built, added) {
1144
+ const { results, scanRoot, logger, verbose } = built;
1145
+ const report = withAddedFindings(built.report, added);
1146
+ const written = writeDocument('audit', report, 'yaml');
1074
1147
  if (verbose) {
1075
- renderVerboseEvidence(results, document.root, logger);
1148
+ renderVerboseEvidence(results, scanRoot, logger);
1076
1149
  }
1077
- handleAuditResults(results, document, logger, verbose);
1078
- logger.debug(`Audit complete in ${Date.now() - startTime}ms`);
1150
+ handleAuditResults({ results, written, data: report.data, root: scanRoot, verbose }, logger);
1151
+ logger.debug(`Audit complete in ${Date.now() - built.startTime}ms`);
1152
+ return written;
1079
1153
  }
1080
1154
  async function runUrlAudit(rawInput, options) {
1081
- const parsed = parseGitUrl(rawInput);
1082
- await withClonedRepo(parsed, { keepTempForDebug: options.debug === true }, async ({ targetDir, tempdir, provenance }) => {
1155
+ let parsed;
1156
+ try {
1157
+ parsed = parseGitUrl(rawInput);
1158
+ }
1159
+ catch (error) {
1160
+ // The argument is the operator's, and it does not name a source.
1161
+ throw new CommandRefusalError('USAGE_INVALID', errorMessageOf(error), { cause: error });
1162
+ }
1163
+ const { value: built, leftover } = await withClonedRepo(parsed, { keepTempForDebug: options.debug === true }, ({ targetDir, tempdir, provenance }) => {
1083
1164
  // Re-enter the audit pipeline against the cloned target. Strip --user
1084
1165
  // (it doesn't apply to URL audits).
1085
1166
  const innerOptions = { ...options, user: false };
1086
- await runAuditAtPath(targetDir, innerOptions, {
1167
+ return buildAuditAtPath(targetDir, innerOptions, {
1087
1168
  provenance,
1088
1169
  tempRoot: tempdir,
1089
1170
  });
1090
1171
  });
1172
+ // Only now, the clone disposed of: one it left behind is a warning in the document.
1173
+ const written = publishAudit(built, leftover === undefined ? [] : toFindings([leftoverIssueOf(leftover)]));
1174
+ process.exit(exitCodeForReport(written));
1091
1175
  }
1092
1176
  export async function auditCommand(targetPath, options) {
1093
1177
  const logger = createLogger(options.debug ? { debug: true } : {});
1094
1178
  const startTime = Date.now();
1095
1179
  resetAuditCaches();
1096
1180
  try {
1181
+ refuseUnusableSettingsFlag(options);
1097
1182
  // A local path always wins. `isGitUrl` accepts bare `owner/repo` GitHub
1098
1183
  // shorthand, which is indistinguishable from an ordinary two-segment
1099
1184
  // relative path (`plugins/arc`, `docs/guides`, `packages/cli`). Asking
@@ -1101,7 +1186,9 @@ export async function auditCommand(targetPath, options) {
1101
1186
  // cloned https://github.com/<that>.git instead, reaching out to the
1102
1187
  // network with a name derived from the caller's own directory layout.
1103
1188
  // Shorthand is a fallback for arguments that name nothing on disk.
1104
- if (targetPath !== undefined && !fsExistsSync(targetPath) && isGitUrl(targetPath)) {
1189
+ // The operator's own argument: its own `within`. A probe the OS refuses is its source fault,
1190
+ // never "names nothing on disk" — that would send a local path to the network.
1191
+ if (targetPath !== undefined && !pathPresent(targetPath, { follow: targetPath }, everywhere('source'), 'probe') && isGitUrl(targetPath)) {
1105
1192
  await runUrlAudit(targetPath, options);
1106
1193
  return;
1107
1194
  }
@@ -1112,19 +1199,14 @@ export async function auditCommand(targetPath, options) {
1112
1199
  return;
1113
1200
  }
1114
1201
  const scanPath = targetPath ? safePath.resolve(targetPath) : process.cwd();
1115
- const unusable = await unusableRootReason(scanPath);
1116
- if (unusable !== undefined) {
1117
- // `return` the call though its type is `never`: under test `process.exit`
1118
- // is a spy that returns, and a bare call would fall through into the scan.
1119
- return handleExpectedFailure(unusable, ExitCode.ERROR, startTime);
1120
- }
1121
- await runAuditAtPath(scanPath, options);
1202
+ const unusable = await unusableRootRefusal(scanPath);
1203
+ if (unusable !== undefined)
1204
+ throw unusable;
1205
+ process.exit(exitCodeForReport(publishAudit(await buildAuditAtPath(scanPath, options), [])));
1122
1206
  }
1123
1207
  catch (error) {
1124
- // 'Audit', not 'AgentAudit'. The old name was copy-pasted from the agent
1125
- // command family and named a command that does not exist, so the one line an
1126
- // operator has to search for did not match what they typed.
1127
- handleCommandError(error, logger, startTime, 'Audit');
1208
+ logger.debug(`Audit did not finish after ${Date.now() - startTime}ms`);
1209
+ endWithRefusal('audit', refusalCodeOf(error), error, 'yaml', AUDIT_GATE, NOTHING_FINISHED);
1128
1210
  }
1129
1211
  }
1130
1212
  /**
@@ -1132,9 +1214,9 @@ export async function auditCommand(targetPath, options) {
1132
1214
  * may start.
1133
1215
  *
1134
1216
  * The exit-code contract every verb shares: a path that does not exist, or a
1135
- * file no audit lane recognises, is the INVOCATION's mistake — `ExitCode.ERROR`
1136
- * (2) before any scan, the same ending `vat resources validate` and `vat skill
1137
- * review` give the same argument. Until this check the audit ran anyway and
1217
+ * file no audit lane recognises, is the INVOCATION's mistake — a `USAGE_INVALID`
1218
+ * refusal (exit 2) before any scan, the same ending `vat resources validate` and
1219
+ * `vat skill review` give the same argument. Until this check the audit ran anyway and
1138
1220
  * published `UNKNOWN_FORMAT` as a finding at exit 1 with `filesScanned: 1`: a
1139
1221
  * typo in a CI step read as "the tree failed its gate", and the denominator
1140
1222
  * counted a file that was never there.
@@ -1144,54 +1226,37 @@ export async function auditCommand(targetPath, options) {
1144
1226
  * zero-files refusal at exit 1 — while `vat resources validate`, `check`,
1145
1227
  * `query` and `scan` all end the same argument at exit 2. One outcome, two
1146
1228
  * codes. Nothing under an unlistable root can be examined, so the audit could
1147
- * not do its job: that is the INVOCATION's ending, the same as a missing path.
1229
+ * not do its job: an `INPUT_UNREADABLE` refusal, exit 2 like a missing path.
1148
1230
  *
1149
1231
  * ONLY the root. A sub-path inside a readable tree is never the invocation's
1150
1232
  * fault and stays a finding. Pinned by the `audit → error` rows of
1151
- * `exit-codes.system.test.ts` and the unreadable-root row of
1152
- * `exit-code-matrix.system.test.ts`.
1233
+ * `exit-codes.system.test.ts` and the `audit` row of
1234
+ * `exit-code-matrix-path-unlistable.system.test.ts`.
1153
1235
  */
1154
- async function unusableRootReason(scanPath) {
1236
+ async function unusableRootRefusal(scanPath) {
1155
1237
  let isDirectory;
1156
1238
  try {
1157
1239
  isDirectory = fs.lstatSync(scanPath).isDirectory();
1158
1240
  }
1159
1241
  catch (error) {
1160
- if (isPathAbsentError(error))
1161
- return `Path does not exist: ${scanPath}`;
1162
- return undefined;
1242
+ // Absent is the invocation's mistake; any other error (an `EACCES` parent) is
1243
+ // the input's refusal — never a scan that starts anyway.
1244
+ return classifyInputFault(scanPath, error, { origin: 'argument', message: `Path does not exist: ${scanPath}` });
1163
1245
  }
1164
1246
  if (isDirectory)
1165
- return unlistableRootReason(scanPath);
1247
+ return unlistableDirectoryRefusal(scanPath);
1166
1248
  if (detectFormat(scanPath) === RESOURCE_TYPE_AGENT_SKILL)
1167
1249
  return undefined;
1168
1250
  if ((await detectResourceFormat(scanPath)).type !== 'unknown')
1169
1251
  return undefined;
1170
- return `Path is not a resource this command can audit (a SKILL.md, a plugin or marketplace directory, or a Claude registry file): ${scanPath}`;
1171
- }
1172
- /**
1173
- * Why a root DIRECTORY cannot be audited, or `undefined` when it can be listed.
1174
- *
1175
- * @param scanPath - The root the operator named, known to be a directory
1176
- * @returns The refusal, or undefined
1177
- */
1178
- function unlistableRootReason(scanPath) {
1179
- try {
1180
- // A probe, not a listing: the crawl owns enumeration, this only asks whether it can start.
1181
- fs.accessSync(scanPath, fs.constants.R_OK | fs.constants.X_OK);
1182
- return undefined;
1183
- }
1184
- catch (error) {
1185
- const code = error.code ?? 'unknown error';
1186
- return `Path cannot be read (${code}): ${scanPath}`;
1187
- }
1252
+ return new CommandRefusalError('USAGE_INVALID', `Path is not a resource this command can audit (a SKILL.md, a plugin or marketplace directory, or a Claude registry file): ${scanPath}`);
1188
1253
  }
1189
1254
  /**
1190
1255
  * Dispatch a single surface to the matching validator. Keeps the multi-surface
1191
1256
  * branch of {@link getValidationResults} focused so cognitive complexity stays
1192
1257
  * within the ESLint budget.
1193
1258
  */
1194
- async function validateSurface(surface, options, logger, locationRoot) {
1259
+ function validateSurface(surface, options, logger, locationRoot) {
1195
1260
  if (surface.type === RESOURCE_TYPE_AGENT_SKILL) {
1196
1261
  // No crawl: this arm only runs for a MULTI-surface root, which in practice is
1197
1262
  // skill-claude-plugin (SKILL.md beside .claude-plugin/plugin.json). The plugin
@@ -1208,13 +1273,10 @@ async function validateSurface(surface, options, logger, locationRoot) {
1208
1273
  * Validate every surface enumerated at a directory root (used when
1209
1274
  * `enumerateSurfaces` returns more than one — e.g., skill-claude-plugin).
1210
1275
  */
1211
- async function validateMultipleSurfaces(surfaces, scanPath, options, logger, locationRoot) {
1276
+ function validateMultipleSurfaces(surfaces, scanPath, options, logger, locationRoot) {
1212
1277
  logger.debug(`Detected ${surfaces.length.toString()} surfaces at ${scanPath}: ${surfaces.map((s) => s.type).join(', ')}`);
1213
- const results = [];
1214
- for (const surface of surfaces) {
1215
- results.push(await validateSurface(surface, options, logger, locationRoot));
1216
- }
1217
- return results;
1278
+ // In order: the surfaces share the population cache and the logger.
1279
+ return mapInOrder(surfaces, (surface) => validateSurface(surface, options, logger, locationRoot));
1218
1280
  }
1219
1281
  /**
1220
1282
  * Additive inventory-detector pass — runs the pure-function detectors
@@ -1258,18 +1320,19 @@ async function recurseIntoMarketplacePlugins(marketplaceInv, recursive, options,
1258
1320
  const marketplaceRoot = safePath.resolve(marketplaceInv.path);
1259
1321
  const seen = new Set([marketplaceRoot]);
1260
1322
  const results = [];
1261
- for (const plugin of marketplaceInv.discovered.plugins) {
1323
+ // In order: the `seen` dedupe must see each plugin before the next one starts.
1324
+ await forEachInOrder(marketplaceInv.discovered.plugins, async (plugin) => {
1262
1325
  const pluginPath = safePath.resolve(plugin.path);
1263
1326
  if (seen.has(pluginPath)) {
1264
1327
  logger.debug(` Skipping marketplace-recurse into already-visited path: ${pluginPath}`);
1265
- continue;
1328
+ return;
1266
1329
  }
1267
1330
  seen.add(pluginPath);
1268
1331
  logger.debug(` Recursing into marketplace path-source plugin: ${pluginPath}`);
1269
1332
  // Same run root — recursing into a co-located plugin must NOT re-anchor.
1270
1333
  const pluginResults = await getValidationResults(pluginPath, recursive, options, logger, locationRoot);
1271
1334
  results.push(...pluginResults);
1272
- }
1335
+ });
1273
1336
  return results;
1274
1337
  }
1275
1338
  /**
@@ -1333,7 +1396,7 @@ function appendInventoryParseErrors(result, inv, locationRoot) {
1333
1396
  refusalsFiled.add(location);
1334
1397
  parseIssues.push(materializeIssue('SCAN_PATH_UNREADABLE', { location, detail: `${location}: ${message}` }));
1335
1398
  }
1336
- // Status was hand-set to 'error' here while `issueCounts` and `summary` kept
1399
+ // Status was hand-set to 'error' here while the counts and description kept
1337
1400
  // describing the pre-append list. One appender derives all three.
1338
1401
  appendIssues(result, parseIssues);
1339
1402
  }
@@ -1376,7 +1439,7 @@ export async function getValidationResults(scanPath, recursive, options, logger,
1376
1439
  catch (error) {
1377
1440
  // Only the filesystem refusing the subject degrades; a defect in a validator
1378
1441
  // must still fail loudly rather than be reported as a permissions problem.
1379
- if (!isFilesystemAccessError(error))
1442
+ if (fsFaultOf(error) === undefined)
1380
1443
  throw error;
1381
1444
  logger.debug(`Unreadable audit subject: ${scanPath}`);
1382
1445
  return [unreadablePathResult(scanPath, error, locationRoot)];
@@ -1450,13 +1513,10 @@ function withoutHostedRefusals(result, hosted) {
1450
1513
  return [];
1451
1514
  if (issues.length === result.issues.length)
1452
1515
  return [result];
1453
- const issueCounts = countBySeverity(issues);
1454
1516
  return [{
1455
1517
  ...result,
1456
- status: calculateValidationStatus(issues),
1457
- summary: formatCountsSummary(issueCounts),
1518
+ ...describeIssues(issues, result.type),
1458
1519
  issues,
1459
- issueCounts,
1460
1520
  }];
1461
1521
  }
1462
1522
  async function validateAuditSubject(scanPath, recursive, options, logger, locationRoot) {
@@ -1523,7 +1583,7 @@ async function validateAuditSubject(scanPath, recursive, options, logger, locati
1523
1583
  return [result];
1524
1584
  }
1525
1585
  // If unknown format, check if it's a directory we can scan
1526
- if (await isScannableDirectory(scanPath)) {
1586
+ if (await isScannableDirectory(scanPath, locationRoot)) {
1527
1587
  logger.debug('Scanning directory for resources');
1528
1588
  // The project's `resources.exclude` is applied by the scan context,
1529
1589
  // on the project-root basis its globs were written against — NOT
@@ -1551,10 +1611,10 @@ async function validateAuditSubject(scanPath, recursive, options, logger, locati
1551
1611
  * `validate()` then reported the directory as an unknown resource format. A
1552
1612
  * scan that examined nothing was reported as a directory that was nothing.
1553
1613
  */
1554
- async function isScannableDirectory(scanPath) {
1555
- const fsp = await import('node:fs/promises');
1614
+ async function isScannableDirectory(scanPath, locationRoot) {
1556
1615
  try {
1557
- return (await fsp.stat(scanPath)).isDirectory();
1616
+ // `scanPath` is crawled beneath the run's scan root: its links are read before the kernel follows them.
1617
+ return (await followedKind(scanPath, locationRoot)) === 'directory';
1558
1618
  }
1559
1619
  catch (error) {
1560
1620
  if (isPathAbsentError(error))
@@ -1574,11 +1634,12 @@ async function isScannableDirectory(scanPath) {
1574
1634
  async function validatePluginSkillsViaInventory(scanPath, options, logger, locationRoot, excludeSkillPaths = new Set()) {
1575
1635
  const inv = await pluginInventoryAt(scanPath);
1576
1636
  const results = [];
1577
- for (const skill of inv.discovered.skills) {
1637
+ // In order: the skills share the population cache and the logger.
1638
+ await forEachInOrder(inv.discovered.skills, async (skill) => {
1578
1639
  const resolvedPath = safePath.resolve(skill.files.skillMd);
1579
1640
  if (excludeSkillPaths.has(resolvedPath)) {
1580
1641
  logger.debug(` Skipping already-validated skill (inventory): ${skill.files.skillMd}`);
1581
- continue;
1642
+ return;
1582
1643
  }
1583
1644
  logger.debug(` Validating plugin-bundled skill (inventory): ${skill.files.skillMd}`);
1584
1645
  // Guarded PER SKILL, not left to the boundary. The boundary guard answers at
@@ -1596,12 +1657,12 @@ async function validatePluginSkillsViaInventory(scanPath, options, logger, locat
1596
1657
  results.push(await validateSingleSkill(skill.files.skillMd, options, logger, locationRoot, false));
1597
1658
  }
1598
1659
  catch (error) {
1599
- if (!isFilesystemAccessError(error))
1660
+ if (fsFaultOf(error) === undefined)
1600
1661
  throw error;
1601
1662
  logger.debug(` Unreadable plugin-bundled skill: ${skill.files.skillMd}`);
1602
1663
  results.push(unreadablePathResult(skill.files.skillMd, error, locationRoot));
1603
1664
  }
1604
- }
1665
+ });
1605
1666
  return results;
1606
1667
  }
1607
1668
  /**
@@ -1667,9 +1728,10 @@ function withRelativePath(message, absolutePath, locationRoot) {
1667
1728
  */
1668
1729
  export async function runCompatAnalysis(results, logger, locationRoot, effectiveSettings, vatContext = null) {
1669
1730
  const compatMap = new Map();
1670
- for (const result of results) {
1731
+ // In order: each plugin's explanations go to the logger as it is analyzed.
1732
+ await forEachInOrder(results, async (result) => {
1671
1733
  if (result.type !== RESOURCE_TYPE_CLAUDE_PLUGIN)
1672
- continue;
1734
+ return;
1673
1735
  const entry = {
1674
1736
  compat: await analyzeOrExplain(result.path, locationRoot, vatContext, logger),
1675
1737
  };
@@ -1677,9 +1739,31 @@ export async function runCompatAnalysis(results, logger, locationRoot, effective
1677
1739
  entry.settings = await settingsVerdict(result.path, effectiveSettings, locationRoot, logger);
1678
1740
  }
1679
1741
  compatMap.set(result.path, entry);
1680
- }
1742
+ });
1743
+ fileLaneFindings(results, compatMap, locationRoot);
1681
1744
  return compatMap;
1682
1745
  }
1746
+ /**
1747
+ * File what the lanes found, and what they could not look at, as findings on each plugin's own
1748
+ * result — so the envelope's status, the row's status and the file counts say what the
1749
+ * `compatibility:` and `settings:` blocks say. A path whose refusal the document already carries
1750
+ * (by its code: `compatLaneIssues` decides which) is not filed a second time.
1751
+ */
1752
+ function fileLaneFindings(results, compatMap, locationRoot) {
1753
+ const locationOf = (absolutePath) => issueLocation(absolutePath, locationRoot) || '.';
1754
+ const filed = results.flatMap((result) => result.issues.map((issue) => ({ code: issue.code, location: issue.location ?? locationOf(result.path) })));
1755
+ for (const result of results) {
1756
+ const entry = compatMap.get(result.path);
1757
+ if (entry === undefined)
1758
+ continue;
1759
+ const issues = compatLaneIssues(locationOf(result.path), {
1760
+ compatibility: entry.compat,
1761
+ ...(entry.settings !== undefined && { settings: renderSettingsBlock(entry.settings, locationRoot) }),
1762
+ }, filed);
1763
+ appendIssues(result, issues);
1764
+ filed.push(...issues.map((issue) => ({ code: issue.code, location: issue.location ?? locationOf(result.path) })));
1765
+ }
1766
+ }
1683
1767
  /**
1684
1768
  * The analyzer's result for one plugin, or — when it threw — the reason, said
1685
1769
  * on stderr and carried into the document. Compat analysis is best-effort:
@@ -1767,45 +1851,65 @@ function applyCompatMap(results, compatMap, locationRoot) {
1767
1851
  return results;
1768
1852
  }
1769
1853
  /**
1770
- * Strip `evidence` from per-file results and `compatibility.evidence` when
1771
- * the audit is not running in --verbose mode. Producing the field at all
1772
- * (even as `[]`) would clutter terse YAML; we omit the key entirely.
1854
+ * `compatibility.evidence` is published only under `--verbose`. Producing the
1855
+ * field at all (even as `[]`) would clutter terse YAML; the key is omitted.
1773
1856
  */
1774
1857
  function stripCompatEvidence(compat) {
1775
1858
  const out = { ...compat };
1776
1859
  delete out['evidence'];
1777
1860
  return out;
1778
1861
  }
1779
- function applyVerboseFilter(results, verbose) {
1780
- if (verbose)
1781
- return results;
1782
- return results.map(r => {
1783
- const stripped = { ...r };
1784
- delete stripped['evidence'];
1785
- if (r.compatibility !== undefined) {
1786
- stripped['compatibility'] = stripCompatEvidence(r.compatibility);
1787
- }
1788
- return stripped;
1789
- });
1790
- }
1791
1862
  /**
1792
- * Nested carriers inside a file entry that publish their own `path`.
1793
- *
1794
- * `linkedFiles[].path` sat absolute in every document while every sibling
1795
- * `path` and `location` beside it was root-relative — 532 of them in a single
1796
- * `vat audit --user` run. Naming the carrier here is what re-bases it; a new
1797
- * carrier that is not named keeps shipping absolute paths.
1798
- */
1799
- const NESTED_PATH_CARRIERS = ['linkedFiles'];
1800
- function calculateSummary(results, startTime, compatMap, verbose, root) {
1801
- const { entries, ...base } = buildBaseSummary(results, startTime);
1802
- const withCompat = applyCompatMap(entries, compatMap, root);
1803
- return {
1804
- // Stated once, first, and the only absolute path in the document.
1805
- root,
1806
- ...base,
1807
- files: relativizePathEntries(applyVerboseFilter(withCompat, verbose), root, NESTED_PATH_CARRIERS),
1808
- };
1863
+ * A result's row. `status` and `summary` are re-derived from its FINAL issue
1864
+ * list here — a producer that appended findings after publishing its counts
1865
+ * cannot leave the row describing the list as it was.
1866
+ */
1867
+ function fileRow(result, root, verbose) {
1868
+ const row = { path: relativizePath(result.path, root), type: result.type, ...summarizeIssues(result.issues) };
1869
+ if (result.compatibility !== undefined)
1870
+ row.compatibility = verbose ? result.compatibility : stripCompatEvidence(result.compatibility);
1871
+ if (result.settings !== undefined)
1872
+ row.settings = result.settings;
1873
+ return row;
1874
+ }
1875
+ /**
1876
+ * Every file's findings, flattened, each naming the file to open. A finding a
1877
+ * validator published without a `location` inherits its file's row path, so a
1878
+ * consumer never has to join a finding back to the row it came from.
1879
+ */
1880
+ function auditFindings(results, root) {
1881
+ return toFindings(results.flatMap((result) => result.issues.map((issue) => issue.location === undefined ? { ...issue, location: relativizePath(result.path, root) } : issue)));
1882
+ }
1883
+ /**
1884
+ * Assemble the report envelope from the per-file results.
1885
+ *
1886
+ * ONE builder for the directory lane, the `--user` lane and the corpus scan's
1887
+ * per-plugin document, so none of them can publish a status or a count the
1888
+ * others would not. `examined` is the files READ — a refused path is counted
1889
+ * in `data.counts.pathsUnreadable` and nowhere else — and the writer turns a
1890
+ * zero into the run's `RESOURCE_CHECK_BROKEN` finding.
1891
+ *
1892
+ * @param results - One result per audited file or refused path
1893
+ * @param context - The root, the compat lanes' output and the `--user` view
1894
+ * @returns The report, before the writer's run-integrity pass
1895
+ */
1896
+ export function buildAuditDocument(results, context) {
1897
+ const { root, compatMap, verbose, hierarchical, durationMs } = context;
1898
+ const { examined, counts } = countFilesByStatus(results);
1899
+ return buildReport({
1900
+ examined,
1901
+ findings: auditFindings(results, root),
1902
+ data: {
1903
+ // Stated once, and the only absolute path in the document.
1904
+ root,
1905
+ provenance: null,
1906
+ counts,
1907
+ files: applyCompatMap([...results], compatMap, root).map((result) => fileRow(result, root, verbose)),
1908
+ hierarchical,
1909
+ },
1910
+ gate: AUDIT_GATE,
1911
+ durationMs,
1912
+ });
1809
1913
  }
1810
1914
  /**
1811
1915
  * Maps a CAPABILITY_* observation code to the family of pattern IDs whose
@@ -1903,21 +2007,22 @@ function renderVerboseEvidence(results, root, logger) {
1903
2007
  }
1904
2008
  }
1905
2009
  /**
1906
- * The stderr half of a run-level refusal, so the human channel says what the
1907
- * document says. The document is derived in `buildBaseSummary`; this only
1908
- * RENDERS it. Both stderr lanes call it first, because "Audit successful: 0
1909
- * file(s) passed" over `status: error` is the exact disagreement the refusal
1910
- * exists to end (invariant 6 of `run-integrity.ts`). The run ends on
1911
- * `FINDINGS`, like every other `status: error` this command publishes.
2010
+ * The stderr half of the run-level refusal, so the human channel says what the
2011
+ * document says. The writer derives it (the registry's denominator for `audit`
2012
+ * is files); this only RENDERS the finding the WRITTEN report carries. Both
2013
+ * stderr lanes call it first, because "Audit successful: 0 file(s) passed"
2014
+ * over a refused run is the exact disagreement the refusal exists to end
2015
+ * (invariant 6 of `run-integrity.ts`).
1912
2016
  *
1913
2017
  * @returns Whether a refusal was rendered, so the caller skips its verdict line
1914
2018
  */
1915
- function logRunIntegrity(runIssues, logger) {
1916
- if (runIssues === undefined || runIssues.length === 0)
2019
+ function logRunIntegrity(written, logger) {
2020
+ const refusals = written.findings.filter((finding) => finding.code === RUN_INTEGRITY_CODE);
2021
+ if (refusals.length === 0)
1917
2022
  return false;
1918
- logger.error('Audit is not a verdict: it audited 0 files');
1919
- for (const issue of runIssues) {
1920
- for (const line of formatIssueLines(issue, ' '))
2023
+ logger.error(`Audit is not a verdict: it audited ${written.examined} files`);
2024
+ for (const refusal of refusals) {
2025
+ for (const line of formatIssueLines(refusal, ' '))
1921
2026
  logger.error(line);
1922
2027
  }
1923
2028
  return true;
@@ -1957,36 +2062,34 @@ function logSettingsTotals(files, logger) {
1957
2062
  logger.error(`⚠ ${compatUnchecked} path(s) the compatibility analysis could not read — see 'compatibility.unchecked' in YAML output`);
1958
2063
  }
1959
2064
  }
1960
- function handleAuditResults(results, summary, logger, verbose) {
1961
- const { filesWithErrors: errorCount, filesWithWarnings: warningCount, filesPassed: successCount, } = summary.summary;
1962
- logSettingsTotals(summary.files ?? [], logger);
1963
- // The exit code follows the document's `status`, as it does in every other
1964
- // command of this CLI: `status: error` — an error-severity finding, or a run
1965
- // that audited zero files — ends on `FINDINGS`. This used to be the one
1966
- // command that exited 0 over `status: error` ("advisory"), and an adopter
1967
- // wiring it into CI read "Audit failed" on stderr beside a green step.
1968
- const refused = logRunIntegrity(summary.issues, logger);
1969
- if (refused) {
2065
+ /**
2066
+ * The human channel for the directory lane, read off the WRITTEN report — the
2067
+ * file counts, and the findings of the files that carry an actionable one. The
2068
+ * exit code is not decided here: the caller ends on `exitCodeForReport`.
2069
+ */
2070
+ function handleAuditResults({ results, written, data, root, verbose }, logger) {
2071
+ const { filesWithErrors: errorCount, filesWithWarnings: warningCount, filesPassed: successCount, } = data.counts;
2072
+ logSettingsTotals(data.files, logger);
2073
+ if (logRunIntegrity(written, logger)) {
1970
2074
  // Rendered above; there is no file verdict to print over zero files.
1971
2075
  }
1972
2076
  else if (errorCount > 0) {
1973
2077
  logger.error(`Audit found ${errorCount} file(s) with errors`);
1974
- logFindingsForStatus(results, 'error', summary.root, logger.error.bind(logger), verbose);
2078
+ logFindingsForStatus(results, hasErrors, root, logger.error.bind(logger), verbose);
1975
2079
  }
1976
2080
  else if (warningCount > 0) {
1977
2081
  logger.info(`Audit passed with warnings: ${warningCount} file(s)`);
1978
- logFindingsForStatus(results, 'warning', summary.root, logger.info.bind(logger), verbose);
2082
+ logFindingsForStatus(results, hasOnlyWarnings, root, logger.info.bind(logger), verbose);
1979
2083
  }
1980
2084
  else {
1981
- // `success` means "nothing actionable", NOT "nothing to see" — name the
1982
- // informational findings or the YAML and the stderr line disagree.
2085
+ // `ok` over info findings still means "nothing actionable", NOT "nothing
2086
+ // to see" — name them or the YAML and the stderr line disagree.
1983
2087
  const withFindings = countResultsWithFindings(results);
1984
2088
  logger.info(withFindings > 0
1985
2089
  ? `Audit successful: ${successCount} file(s) passed (${withFindings} with informational findings)`
1986
2090
  : `Audit successful: ${successCount} file(s) passed`);
1987
2091
  }
1988
2092
  renderAuditFooter(results, logger);
1989
- process.exit(refused || errorCount > 0 ? ExitCode.FINDINGS : ExitCode.OK);
1990
2093
  }
1991
2094
  /**
1992
2095
  * Render the skill-quality checklist footer when audit results contain
@@ -2039,7 +2142,7 @@ function renderAuditFooter(results, logger) {
2039
2142
  * cannot answer the question.
2040
2143
  *
2041
2144
  * Pure: takes results, returns lines. It reads `issues` and never rewrites it,
2042
- * because `runAuditAtPath` builds the YAML document from the very same array.
2145
+ * because `buildAuditAtPath` builds the YAML document from the very same array.
2043
2146
  *
2044
2147
  * @internal Exported for unit testing only — not part of the public CLI API.
2045
2148
  */
@@ -2075,8 +2178,8 @@ export function formatAuditFindingsLines(results, root, verbose) {
2075
2178
  * The banner counts FILES and the blocks below count FINDINGS; both are needed,
2076
2179
  * and `logFn` picks the channel the calling branch already established.
2077
2180
  */
2078
- function logFindingsForStatus(results, status, root, logFn, verbose) {
2079
- const selected = results.filter((r) => r.status === status);
2181
+ function logFindingsForStatus(results, inBucket, root, logFn, verbose) {
2182
+ const selected = results.filter(inBucket);
2080
2183
  for (const line of formatAuditFindingsLines(selected, root, verbose)) {
2081
2184
  logFn(line);
2082
2185
  }
@@ -2158,15 +2261,16 @@ async function handleFileEntry(entry, fullPath, options, logger, scanCtx) {
2158
2261
  const skillDir = safePath.resolve(fullPath, '..');
2159
2262
  const unreadable = degradingRegistry(findProjectRoot(skillDir) ?? skillDir, logger, locationRoot);
2160
2263
  const sharedCtx = scanCtx.gitTracker === null
2161
- ? { locationRoot, projectSkills, suiteProbe, unreadable }
2162
- : { gitTracker: scanCtx.gitTracker, locationRoot, projectSkills, suiteProbe, unreadable };
2264
+ ? { locationRoot, projectSkills, suiteProbe, unreadable, outputs: [] }
2265
+ : { gitTracker: scanCtx.gitTracker, locationRoot, projectSkills, suiteProbe, unreadable, outputs: [] };
2163
2266
  const packagingResult = await validateSkillForPackaging(fullPath, skillConfig, 'source', sharedCtx);
2164
2267
  const configAware = packagingResultToValidationResult(fullPath, packagingResult, skillConfig.targets, locationRoot);
2165
2268
  await appendDistributedTreeFindings(configAware, fullPath, locationRoot, ownsOwnCrawl(scanCtx, fullPath));
2166
2269
  return configAware;
2167
2270
  }
2168
2271
  // Wild mode: basic validation. Severity is applied by `applySeverityFilter`.
2169
- const validateOptions = { skillPath: fullPath, locationRoot, validation: {} };
2272
+ // The audited skill is the verb's input.
2273
+ const validateOptions = { skillPath: fullPath, locationRoot, validation: {}, side: 'source' };
2170
2274
  if (options.warnUnreferencedFiles) {
2171
2275
  validateOptions.checkUnreferencedFiles = true;
2172
2276
  }
@@ -2203,7 +2307,7 @@ async function validatePluginDirectory(dir, logger, locationRoot) {
2203
2307
  */
2204
2308
  const inventoryRegistryCache = new Map();
2205
2309
  /** Build (once per run, per root) the registry the plugin inventory link walk needs. */
2206
- async function getOrCreateInventoryRegistry(projectRoot) {
2310
+ function getOrCreateInventoryRegistry(projectRoot) {
2207
2311
  const cached = inventoryRegistryCache.get(projectRoot);
2208
2312
  if (cached !== undefined) {
2209
2313
  return cached;
@@ -2239,7 +2343,7 @@ async function getOrCreateInventoryRegistry(projectRoot) {
2239
2343
  * case to encode here. This is the call site that carried all 786 measured
2240
2344
  * `git check-ignore` spawns.
2241
2345
  */
2242
- async function pluginInventoryAt(dir) {
2346
+ function pluginInventoryAt(dir) {
2243
2347
  const projectRoot = findProjectRoot(dir);
2244
2348
  return extractClaudePluginInventory(dir, {
2245
2349
  ...(projectRoot === null
@@ -2304,11 +2408,11 @@ async function resolveScanContext(dirPath, locationRoot, logger) {
2304
2408
  * is no longer the ONLY thing the run says — the code, the location and the fix
2305
2409
  * come from the registry.
2306
2410
  *
2307
- * This result is a `files[]` row but NOT a scanned file: `countFilesByStatus`
2411
+ * This result is a `data.files[]` row but NOT a file read: `countFilesByStatus`
2308
2412
  * recognises it ({@link isUnreadablePathResult}) and reports it under
2309
- * `summary.pathsUnreadable`, outside `filesScanned` and the status counts. A
2310
- * root the OS refused therefore audits zero files and ends on the zero-files
2311
- * refusal, instead of `filesScanned: 1` over a path nothing read.
2413
+ * `data.counts.pathsUnreadable`, outside `examined` and the status counts. A
2414
+ * root the OS refused therefore examines zero files and ends on the zero-files
2415
+ * refusal, instead of `examined: 1` over a path nothing read.
2312
2416
  */
2313
2417
  function unreadablePathResult(dirPath, error, locationRoot) {
2314
2418
  // `issueLocation` is `path.relative`, so it answers `''` when the subject IS the
@@ -2329,14 +2433,11 @@ function unreadablePathResult(dirPath, error, locationRoot) {
2329
2433
  detail: `${location}: ${reason}`,
2330
2434
  }),
2331
2435
  ];
2332
- const issueCounts = countBySeverity(issues);
2333
2436
  return {
2334
2437
  path: dirPath,
2335
2438
  type: 'unknown',
2336
- status: calculateValidationStatus(issues),
2337
- summary: formatCountsSummary(issueCounts),
2439
+ ...describeIssues(issues, 'unknown'),
2338
2440
  issues,
2339
- issueCounts,
2340
2441
  };
2341
2442
  }
2342
2443
  /**
@@ -2366,7 +2467,7 @@ async function validateScanSubject(subject, options, logger, scanCtx, claims) {
2366
2467
  }
2367
2468
  const subjectCtx = { ...scanCtx, crawledRoot: claims.owner(subject.path) };
2368
2469
  const result = await handleFileEntry({ name: basename(subject.path) }, subject.path, options, logger, subjectCtx);
2369
- if (subject.kind === 'skill' && ownsOwnCrawl(subjectCtx, subject.path) && await crawlOwnsSubtree(subject.path)) {
2470
+ if (subject.kind === 'skill' && ownsOwnCrawl(subjectCtx, subject.path) && await crawlOwnsSubtree(subject.path, locationRoot)) {
2370
2471
  claims.claim(subject.dir);
2371
2472
  }
2372
2473
  return result === null ? [] : [result];
@@ -2376,7 +2477,7 @@ async function validateScanSubject(subject, options, logger, scanCtx, claims) {
2376
2477
  // turning a genuine VAT bug into a `warning` about the file it happened on is
2377
2478
  // the same "detector silently disables itself" shape this guard exists to
2378
2479
  // prevent — it would make the tool quietest exactly when it is most wrong.
2379
- if (!isFilesystemAccessError(error))
2480
+ if (fsFaultOf(error) === undefined)
2380
2481
  throw error;
2381
2482
  const path = subject.kind === 'plugin' ? subject.dir : subject.path;
2382
2483
  logger.debug(`Unreadable entry: ${path}`);
@@ -2427,29 +2528,16 @@ async function scanDirectory(dirPath, recursive, options, logger, scanCtx) {
2427
2528
  }
2428
2529
  const results = population.refusals.map((refusal) => {
2429
2530
  logger.debug(`Unreadable directory: ${refusal.directory}`);
2430
- const err = new DirectoryListingRefusedError(refusal, { root: dirPath, remedy: scanRefusalRemedy() });
2531
+ const err = new DirectoryListingRefusedError(refusal, { root: dirPath, remedy: scanRefusalRemedy(), side: 'source' });
2431
2532
  return unreadablePathResult(refusal.directory, err, scanCtx.locationRoot);
2432
2533
  });
2433
2534
  const claims = new SubtreeClaims();
2434
- for (const subject of population.subjects) {
2535
+ // In order: `claims` resolves each subtree against the subjects before it.
2536
+ await forEachInOrder(population.subjects, async (subject) => {
2435
2537
  results.push(...await validateScanSubject(subject, options, logger, scanCtx, claims));
2436
- }
2538
+ });
2437
2539
  return results;
2438
2540
  }
2439
- /**
2440
- * Calculate overall status from validation results
2441
- */
2442
- function calculateOverallStatus(results) {
2443
- const errorCount = results.filter((r) => r.status === 'error').length;
2444
- const warningCount = results.filter((r) => r.status === 'warning').length;
2445
- if (errorCount > 0) {
2446
- return 'error';
2447
- }
2448
- if (warningCount > 0) {
2449
- return 'warning';
2450
- }
2451
- return 'success';
2452
- }
2453
2541
  /**
2454
2542
  * How many results carry at least one finding.
2455
2543
  *
@@ -2473,147 +2561,53 @@ function isUnreadablePathResult(result) {
2473
2561
  && result.issues.every((issue) => issue.code === 'SCAN_PATH_UNREADABLE');
2474
2562
  }
2475
2563
  /**
2476
- * Count files by their own status.
2564
+ * Count files by their worst actionable severity, and the files read.
2477
2565
  *
2478
2566
  * A refused path is NOT a scanned file. It used to be counted as one, which
2479
2567
  * made the zero-files refusal unreachable for exactly the tree it exists for:
2480
- * `chmod 000` on the whole root gave `filesScanned: 1, filesPassed: 0`,
2481
- * `status: warning`, exit 0 — nothing read, gate green. Kept out of every
2482
- * status count too, or `filesWithWarnings` would exceed `filesScanned`.
2568
+ * `chmod 000` on the whole root gave one file scanned, none passed, a warning
2569
+ * status and exit 0 — nothing read, gate green. Kept out of every status count
2570
+ * too, or `filesWithWarnings` would exceed the files read.
2483
2571
  */
2484
2572
  function countFilesByStatus(results) {
2485
2573
  const scanned = results.filter((r) => !isUnreadablePathResult(r));
2574
+ const withErrors = scanned.filter(hasErrors).length;
2575
+ const withWarnings = scanned.filter(hasOnlyWarnings).length;
2486
2576
  return {
2487
- filesScanned: scanned.length,
2488
- filesPassed: scanned.filter((r) => r.status === 'success').length,
2489
- filesWithWarnings: scanned.filter((r) => r.status === 'warning').length,
2490
- filesWithErrors: scanned.filter((r) => r.status === 'error').length,
2491
- pathsUnreadable: results.length - scanned.length,
2492
- };
2493
- }
2494
- /**
2495
- * Build base summary structure (used by both flat and hierarchical), together
2496
- * with the entries the document will publish.
2497
- *
2498
- * `issueCounts` is named exactly as it is on every individual file entry, and
2499
- * means the same thing at both levels: findings, by severity. `summary` only ever
2500
- * counts files.
2501
- *
2502
- * The header total and every per-file total come from ONE traversal of the
2503
- * final issue set, and the entries carrying those per-file totals are returned
2504
- * from the same pass. Before that, the header was derived from the issue
2505
- * records while each file's `issueCounts` was whatever its producer had
2506
- * published — and a producer that appends findings after publishing (or never
2507
- * sets the counts at all: `validatePlugin` writes `status` and `summary` but
2508
- * not `issueCounts`) left the two disagreeing inside one document. A real
2509
- * `vat audit --user` run said 55/422/504 in the header over per-file counts
2510
- * summing to 55/360/405, with 91 of 614 entries declaring `{0,0,0}` above the
2511
- * findings they listed. Re-deriving here means the header and the sum are the
2512
- * same arithmetic on the same array, so they cannot drift again no matter what
2513
- * a producer forgets.
2514
- *
2515
- * `linkedFiles[].issues` are deliberately NOT added: every linked finding is
2516
- * also present in its owner's `issues`, so the nested list is a VIEW of records
2517
- * already counted, not extra records. `audit-report-coherence.integration.test.ts`
2518
- * pins that subset relation, because counting once is only correct while it holds.
2519
- *
2520
- * 🚨 **Zero files audited is an ERROR, not "an empty tree audits cleanly".**
2521
- * `calculateOverallStatus([])` is `success`, so an existing directory holding
2522
- * nothing auditable — moved plugins, a wrong subdirectory, an excluded tree, a
2523
- * tree of files no lane recognises — published `status: success` beside
2524
- * `filesScanned: 0`, and this command's own documentation tells CI to gate on
2525
- * that `status`. Derived HERE, in the one builder both the directory lane
2526
- * (`calculateSummary`) and the `--user` lane (`calculateHierarchicalSummary`)
2527
- * pass through, so neither can publish a clean status over a zero denominator.
2528
- * Through the shared mechanism in `run-integrity.ts`: one non-overridable
2529
- * `RESOURCE_CHECK_BROKEN` at `error`, published under a top-level `issues` —
2530
- * the claim is about the RUN, so it is not a `files[]` row and does not count
2531
- * toward `filesScanned` — and counted in the header `issueCounts`, so the
2532
- * identity becomes `issueCounts === Σ files[].issueCounts + Σ issues`.
2533
- *
2534
- * The exit code is NOT touched by this: `status` describes the findings and the
2535
- * exit code describes whether the run completed, and this run completed. See
2536
- * {@link createAuditCommand}.
2537
- */
2538
- function buildBaseSummary(results, startTime) {
2539
- const issueCounts = { errors: 0, warnings: 0, info: 0 };
2540
- const entries = results.map((result) => {
2541
- const counts = countBySeverity(result.issues);
2542
- issueCounts.errors += counts.errors;
2543
- issueCounts.warnings += counts.warnings;
2544
- issueCounts.info += counts.info;
2545
- return { ...result, issueCounts: counts };
2546
- });
2547
- const summary = countFilesByStatus(entries);
2548
- // The denominator is files READ: a tree whose every path was refused audited
2549
- // nothing, and says so through the same refusal as an empty tree.
2550
- const runIssues = nothingCheckedFinding(summary.filesScanned, entries.flatMap((entry) => entry.issues), () => 'The audit ran over 0 files, so this report is not a verdict: a tree with nothing'
2551
- + ' to audit produces the same counts as a clean one. The path resolved to a tree'
2552
- + ' holding no auditable file — usually a wrong subdirectory, plugins or skills that'
2553
- + ' have moved, an excluded tree, files no audit lane recognises, or `--no-recursive`'
2554
- + ' over a tree whose resources sit deeper. Point the command at the plugin,'
2555
- + ' marketplace, registry or SKILL.md tree it should read.');
2556
- return {
2557
- entries,
2558
- // Every run-integrity finding is `error` by construction (invariant 2 of
2559
- // `run-integrity.ts`), so a non-empty refusal IS the status; otherwise the
2560
- // files decide it, as before.
2561
- status: runIssues.length > 0 ? 'error' : calculateOverallStatus(entries),
2562
- summary,
2563
- issueCounts: sumSeverityCounts([issueCounts, countBySeverity(runIssues)]),
2564
- ...(runIssues.length === 0 ? {} : { issues: [...runIssues] }),
2565
- duration: `${Date.now() - startTime}ms`,
2566
- };
2567
- }
2568
- /**
2569
- * Calculate summary for hierarchical output
2570
- */
2571
- function calculateHierarchicalSummary(results, hierarchical, startTime, compatMap, verbose, root) {
2572
- const { entries, ...base } = buildBaseSummary(results, startTime);
2573
- const withCompat = applyCompatMap(entries, compatMap, root);
2574
- return {
2575
- root,
2576
- ...base,
2577
- summary: {
2578
- ...base.summary,
2579
- marketplaces: hierarchical.marketplaces.length,
2580
- cachedPlugins: hierarchical.cachedPlugins.length,
2581
- standalonePlugins: hierarchical.standalonePlugins.length,
2582
- standaloneSkills: hierarchical.standaloneSkills.length,
2577
+ examined: scanned.length,
2578
+ counts: {
2579
+ filesPassed: scanned.length - withErrors - withWarnings,
2580
+ filesWithWarnings: withWarnings,
2581
+ filesWithErrors: withErrors,
2582
+ pathsUnreadable: results.length - scanned.length,
2583
2583
  },
2584
- files: relativizePathEntries(applyVerboseFilter(withCompat, verbose), root, NESTED_PATH_CARRIERS),
2585
- hierarchical,
2586
2584
  };
2587
2585
  }
2588
2586
  /**
2589
- * Log hierarchical summary to stderr
2587
+ * The human channel for the `--user` lane, read off the WRITTEN report. The
2588
+ * exit code is not decided here: the caller ends on `exitCodeForReport`.
2590
2589
  */
2591
- function logHierarchicalSummary(results, runIssues, logger) {
2592
- const status = calculateOverallStatus(results);
2590
+ function logHierarchicalSummary({ results, written, data }, logger) {
2591
+ const { filesWithErrors, filesWithWarnings } = data.counts;
2593
2592
  const skillsWithIssues = countResultsWithFindings(results);
2594
2593
  const totalSkills = results.length;
2595
- // Same rule as the per-file lane: the exit code follows `status`.
2596
- const refused = logRunIntegrity(runIssues, logger);
2597
- if (refused) {
2594
+ if (logRunIntegrity(written, logger)) {
2598
2595
  // Rendered above; there is no skill verdict to print over zero skills.
2599
2596
  }
2600
- else if (status === 'error') {
2601
- const errorCount = results.filter((r) => r.status === 'error').length;
2602
- logger.error(`Audit found ${errorCount} skill(s) with errors (${totalSkills} scanned, ${skillsWithIssues} with issues)`);
2597
+ else if (filesWithErrors > 0) {
2598
+ logger.error(`Audit found ${filesWithErrors} skill(s) with errors (${totalSkills} scanned, ${skillsWithIssues} with issues)`);
2603
2599
  }
2604
- else if (status === 'warning') {
2605
- const warningCount = results.filter((r) => r.status === 'warning').length;
2606
- logger.info(`Audit passed with warnings: ${warningCount} skill(s) (${totalSkills} scanned, ${skillsWithIssues} with issues)`);
2600
+ else if (filesWithWarnings > 0) {
2601
+ logger.info(`Audit passed with warnings: ${filesWithWarnings} skill(s) (${totalSkills} scanned, ${skillsWithIssues} with issues)`);
2607
2602
  }
2608
2603
  else if (skillsWithIssues > 0) {
2609
- // `success` means "nothing actionable", NOT "nothing to see". Saying only
2610
- // "N passed" over a pile of info findings is how they stayed invisible.
2604
+ // Nothing actionable is NOT "nothing to see". Saying only "N passed" over
2605
+ // a pile of info findings is how they stayed invisible.
2611
2606
  logger.info(`Audit successful: ${totalSkills} skill(s) passed (${skillsWithIssues} with informational findings)`);
2612
2607
  }
2613
2608
  else {
2614
2609
  logger.info(`Audit successful: ${totalSkills} skill(s) passed`);
2615
2610
  }
2616
2611
  renderAuditFooter(results, logger);
2617
- process.exit(refused || status === 'error' ? ExitCode.FINDINGS : ExitCode.OK);
2618
2612
  }
2619
2613
  //# sourceMappingURL=audit.js.map