@vibe-agent-toolkit/cli 0.2.0-rc.10 → 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 +94 -40
  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 +94 -40
  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 +31 -63
  87. package/dist/commands/ard/emit.d.ts.map +1 -1
  88. package/dist/commands/ard/emit.js +124 -68
  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 +17 -10
  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 +415 -397
  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 +87 -2
  148. package/dist/commands/claude/context.d.ts.map +1 -1
  149. package/dist/commands/claude/context.js +116 -57
  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 +13 -10
  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 -145
  355. package/dist/commands/okf/validate.d.ts.map +1 -1
  356. package/dist/commands/okf/validate.js +63 -52
  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 +79 -13
  404. package/dist/commands/resources/check-progress.d.ts.map +1 -1
  405. package/dist/commands/resources/check-progress.js +112 -11
  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 +329 -71
  412. package/dist/commands/resources/check-supervisor.d.ts.map +1 -1
  413. package/dist/commands/resources/check-supervisor.js +507 -107
  414. package/dist/commands/resources/check-supervisor.js.map +1 -1
  415. package/dist/commands/resources/check.d.ts +88 -254
  416. package/dist/commands/resources/check.d.ts.map +1 -1
  417. package/dist/commands/resources/check.js +537 -310
  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 +189 -103
  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 +18 -13
  427. package/dist/commands/resources/query.d.ts.map +1 -1
  428. package/dist/commands/resources/query.js +61 -49
  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 -77
  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 -28
  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 +44 -5
  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 +18 -11
  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 +78 -32
  665. package/dist/utils/resource-loader.d.ts.map +1 -1
  666. package/dist/utils/resource-loader.js +134 -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 +17 -20
  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 +228 -107
  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 +280 -118
  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 -189
  753. package/dist/utils/command-error.d.ts.map +0 -1
  754. package/dist/utils/command-error.js +0 -230
  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 (so
691
- a root with nothing readable is a zero-files refusal).
692
- 2 - The audit could not run at all: the path does not exist or is a file
693
- no audit lane 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,42 +1214,49 @@ 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.
1141
1223
  *
1142
- * ONLY the root, and only these two conditions. A root the OS refuses to stat
1143
- * is not answered here — the scan degrades it to `SCAN_PATH_UNREADABLE`, which
1144
- * is not counted as a scanned file, so a tree with nothing readable ends on the
1145
- * zero-files refusal (exit 1) like any other tree that yielded nothing. A
1146
- * sub-path inside a readable tree is never the invocation's fault and stays a
1147
- * finding. Pinned by the `audit → error` rows of `exit-codes.system.test.ts`.
1224
+ * 🚨 **And a root DIRECTORY the OS refuses to list.** It used to be left to
1225
+ * the scan, which degraded it to `SCAN_PATH_UNREADABLE` and ended on the
1226
+ * zero-files refusal at exit 1 — while `vat resources validate`, `check`,
1227
+ * `query` and `scan` all end the same argument at exit 2. One outcome, two
1228
+ * codes. Nothing under an unlistable root can be examined, so the audit could
1229
+ * not do its job: an `INPUT_UNREADABLE` refusal, exit 2 like a missing path.
1230
+ *
1231
+ * ONLY the root. A sub-path inside a readable tree is never the invocation's
1232
+ * fault and stays a finding. Pinned by the `audit → error` rows of
1233
+ * `exit-codes.system.test.ts` and the `audit` row of
1234
+ * `exit-code-matrix-path-unlistable.system.test.ts`.
1148
1235
  */
1149
- async function unusableRootReason(scanPath) {
1236
+ async function unusableRootRefusal(scanPath) {
1150
1237
  let isDirectory;
1151
1238
  try {
1152
1239
  isDirectory = fs.lstatSync(scanPath).isDirectory();
1153
1240
  }
1154
1241
  catch (error) {
1155
- if (isPathAbsentError(error))
1156
- return `Path does not exist: ${scanPath}`;
1157
- 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}` });
1158
1245
  }
1159
- if (isDirectory || detectFormat(scanPath) === RESOURCE_TYPE_AGENT_SKILL)
1246
+ if (isDirectory)
1247
+ return unlistableDirectoryRefusal(scanPath);
1248
+ if (detectFormat(scanPath) === RESOURCE_TYPE_AGENT_SKILL)
1160
1249
  return undefined;
1161
1250
  if ((await detectResourceFormat(scanPath)).type !== 'unknown')
1162
1251
  return undefined;
1163
- return `Path is not a resource this command can audit (a SKILL.md, a plugin or marketplace directory, or a Claude registry file): ${scanPath}`;
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}`);
1164
1253
  }
1165
1254
  /**
1166
1255
  * Dispatch a single surface to the matching validator. Keeps the multi-surface
1167
1256
  * branch of {@link getValidationResults} focused so cognitive complexity stays
1168
1257
  * within the ESLint budget.
1169
1258
  */
1170
- async function validateSurface(surface, options, logger, locationRoot) {
1259
+ function validateSurface(surface, options, logger, locationRoot) {
1171
1260
  if (surface.type === RESOURCE_TYPE_AGENT_SKILL) {
1172
1261
  // No crawl: this arm only runs for a MULTI-surface root, which in practice is
1173
1262
  // skill-claude-plugin (SKILL.md beside .claude-plugin/plugin.json). The plugin
@@ -1184,13 +1273,10 @@ async function validateSurface(surface, options, logger, locationRoot) {
1184
1273
  * Validate every surface enumerated at a directory root (used when
1185
1274
  * `enumerateSurfaces` returns more than one — e.g., skill-claude-plugin).
1186
1275
  */
1187
- async function validateMultipleSurfaces(surfaces, scanPath, options, logger, locationRoot) {
1276
+ function validateMultipleSurfaces(surfaces, scanPath, options, logger, locationRoot) {
1188
1277
  logger.debug(`Detected ${surfaces.length.toString()} surfaces at ${scanPath}: ${surfaces.map((s) => s.type).join(', ')}`);
1189
- const results = [];
1190
- for (const surface of surfaces) {
1191
- results.push(await validateSurface(surface, options, logger, locationRoot));
1192
- }
1193
- return results;
1278
+ // In order: the surfaces share the population cache and the logger.
1279
+ return mapInOrder(surfaces, (surface) => validateSurface(surface, options, logger, locationRoot));
1194
1280
  }
1195
1281
  /**
1196
1282
  * Additive inventory-detector pass — runs the pure-function detectors
@@ -1234,18 +1320,19 @@ async function recurseIntoMarketplacePlugins(marketplaceInv, recursive, options,
1234
1320
  const marketplaceRoot = safePath.resolve(marketplaceInv.path);
1235
1321
  const seen = new Set([marketplaceRoot]);
1236
1322
  const results = [];
1237
- 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) => {
1238
1325
  const pluginPath = safePath.resolve(plugin.path);
1239
1326
  if (seen.has(pluginPath)) {
1240
1327
  logger.debug(` Skipping marketplace-recurse into already-visited path: ${pluginPath}`);
1241
- continue;
1328
+ return;
1242
1329
  }
1243
1330
  seen.add(pluginPath);
1244
1331
  logger.debug(` Recursing into marketplace path-source plugin: ${pluginPath}`);
1245
1332
  // Same run root — recursing into a co-located plugin must NOT re-anchor.
1246
1333
  const pluginResults = await getValidationResults(pluginPath, recursive, options, logger, locationRoot);
1247
1334
  results.push(...pluginResults);
1248
- }
1335
+ });
1249
1336
  return results;
1250
1337
  }
1251
1338
  /**
@@ -1309,7 +1396,7 @@ function appendInventoryParseErrors(result, inv, locationRoot) {
1309
1396
  refusalsFiled.add(location);
1310
1397
  parseIssues.push(materializeIssue('SCAN_PATH_UNREADABLE', { location, detail: `${location}: ${message}` }));
1311
1398
  }
1312
- // 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
1313
1400
  // describing the pre-append list. One appender derives all three.
1314
1401
  appendIssues(result, parseIssues);
1315
1402
  }
@@ -1352,7 +1439,7 @@ export async function getValidationResults(scanPath, recursive, options, logger,
1352
1439
  catch (error) {
1353
1440
  // Only the filesystem refusing the subject degrades; a defect in a validator
1354
1441
  // must still fail loudly rather than be reported as a permissions problem.
1355
- if (!isFilesystemAccessError(error))
1442
+ if (fsFaultOf(error) === undefined)
1356
1443
  throw error;
1357
1444
  logger.debug(`Unreadable audit subject: ${scanPath}`);
1358
1445
  return [unreadablePathResult(scanPath, error, locationRoot)];
@@ -1426,13 +1513,10 @@ function withoutHostedRefusals(result, hosted) {
1426
1513
  return [];
1427
1514
  if (issues.length === result.issues.length)
1428
1515
  return [result];
1429
- const issueCounts = countBySeverity(issues);
1430
1516
  return [{
1431
1517
  ...result,
1432
- status: calculateValidationStatus(issues),
1433
- summary: formatCountsSummary(issueCounts),
1518
+ ...describeIssues(issues, result.type),
1434
1519
  issues,
1435
- issueCounts,
1436
1520
  }];
1437
1521
  }
1438
1522
  async function validateAuditSubject(scanPath, recursive, options, logger, locationRoot) {
@@ -1499,7 +1583,7 @@ async function validateAuditSubject(scanPath, recursive, options, logger, locati
1499
1583
  return [result];
1500
1584
  }
1501
1585
  // If unknown format, check if it's a directory we can scan
1502
- if (await isScannableDirectory(scanPath)) {
1586
+ if (await isScannableDirectory(scanPath, locationRoot)) {
1503
1587
  logger.debug('Scanning directory for resources');
1504
1588
  // The project's `resources.exclude` is applied by the scan context,
1505
1589
  // on the project-root basis its globs were written against — NOT
@@ -1527,10 +1611,10 @@ async function validateAuditSubject(scanPath, recursive, options, logger, locati
1527
1611
  * `validate()` then reported the directory as an unknown resource format. A
1528
1612
  * scan that examined nothing was reported as a directory that was nothing.
1529
1613
  */
1530
- async function isScannableDirectory(scanPath) {
1531
- const fsp = await import('node:fs/promises');
1614
+ async function isScannableDirectory(scanPath, locationRoot) {
1532
1615
  try {
1533
- 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';
1534
1618
  }
1535
1619
  catch (error) {
1536
1620
  if (isPathAbsentError(error))
@@ -1550,11 +1634,12 @@ async function isScannableDirectory(scanPath) {
1550
1634
  async function validatePluginSkillsViaInventory(scanPath, options, logger, locationRoot, excludeSkillPaths = new Set()) {
1551
1635
  const inv = await pluginInventoryAt(scanPath);
1552
1636
  const results = [];
1553
- 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) => {
1554
1639
  const resolvedPath = safePath.resolve(skill.files.skillMd);
1555
1640
  if (excludeSkillPaths.has(resolvedPath)) {
1556
1641
  logger.debug(` Skipping already-validated skill (inventory): ${skill.files.skillMd}`);
1557
- continue;
1642
+ return;
1558
1643
  }
1559
1644
  logger.debug(` Validating plugin-bundled skill (inventory): ${skill.files.skillMd}`);
1560
1645
  // Guarded PER SKILL, not left to the boundary. The boundary guard answers at
@@ -1572,12 +1657,12 @@ async function validatePluginSkillsViaInventory(scanPath, options, logger, locat
1572
1657
  results.push(await validateSingleSkill(skill.files.skillMd, options, logger, locationRoot, false));
1573
1658
  }
1574
1659
  catch (error) {
1575
- if (!isFilesystemAccessError(error))
1660
+ if (fsFaultOf(error) === undefined)
1576
1661
  throw error;
1577
1662
  logger.debug(` Unreadable plugin-bundled skill: ${skill.files.skillMd}`);
1578
1663
  results.push(unreadablePathResult(skill.files.skillMd, error, locationRoot));
1579
1664
  }
1580
- }
1665
+ });
1581
1666
  return results;
1582
1667
  }
1583
1668
  /**
@@ -1643,9 +1728,10 @@ function withRelativePath(message, absolutePath, locationRoot) {
1643
1728
  */
1644
1729
  export async function runCompatAnalysis(results, logger, locationRoot, effectiveSettings, vatContext = null) {
1645
1730
  const compatMap = new Map();
1646
- 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) => {
1647
1733
  if (result.type !== RESOURCE_TYPE_CLAUDE_PLUGIN)
1648
- continue;
1734
+ return;
1649
1735
  const entry = {
1650
1736
  compat: await analyzeOrExplain(result.path, locationRoot, vatContext, logger),
1651
1737
  };
@@ -1653,9 +1739,31 @@ export async function runCompatAnalysis(results, logger, locationRoot, effective
1653
1739
  entry.settings = await settingsVerdict(result.path, effectiveSettings, locationRoot, logger);
1654
1740
  }
1655
1741
  compatMap.set(result.path, entry);
1656
- }
1742
+ });
1743
+ fileLaneFindings(results, compatMap, locationRoot);
1657
1744
  return compatMap;
1658
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
+ }
1659
1767
  /**
1660
1768
  * The analyzer's result for one plugin, or — when it threw — the reason, said
1661
1769
  * on stderr and carried into the document. Compat analysis is best-effort:
@@ -1743,45 +1851,65 @@ function applyCompatMap(results, compatMap, locationRoot) {
1743
1851
  return results;
1744
1852
  }
1745
1853
  /**
1746
- * Strip `evidence` from per-file results and `compatibility.evidence` when
1747
- * the audit is not running in --verbose mode. Producing the field at all
1748
- * (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.
1749
1856
  */
1750
1857
  function stripCompatEvidence(compat) {
1751
1858
  const out = { ...compat };
1752
1859
  delete out['evidence'];
1753
1860
  return out;
1754
1861
  }
1755
- function applyVerboseFilter(results, verbose) {
1756
- if (verbose)
1757
- return results;
1758
- return results.map(r => {
1759
- const stripped = { ...r };
1760
- delete stripped['evidence'];
1761
- if (r.compatibility !== undefined) {
1762
- stripped['compatibility'] = stripCompatEvidence(r.compatibility);
1763
- }
1764
- return stripped;
1765
- });
1766
- }
1767
1862
  /**
1768
- * Nested carriers inside a file entry that publish their own `path`.
1769
- *
1770
- * `linkedFiles[].path` sat absolute in every document while every sibling
1771
- * `path` and `location` beside it was root-relative — 532 of them in a single
1772
- * `vat audit --user` run. Naming the carrier here is what re-bases it; a new
1773
- * carrier that is not named keeps shipping absolute paths.
1774
- */
1775
- const NESTED_PATH_CARRIERS = ['linkedFiles'];
1776
- function calculateSummary(results, startTime, compatMap, verbose, root) {
1777
- const { entries, ...base } = buildBaseSummary(results, startTime);
1778
- const withCompat = applyCompatMap(entries, compatMap, root);
1779
- return {
1780
- // Stated once, first, and the only absolute path in the document.
1781
- root,
1782
- ...base,
1783
- files: relativizePathEntries(applyVerboseFilter(withCompat, verbose), root, NESTED_PATH_CARRIERS),
1784
- };
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
+ });
1785
1913
  }
1786
1914
  /**
1787
1915
  * Maps a CAPABILITY_* observation code to the family of pattern IDs whose
@@ -1879,21 +2007,22 @@ function renderVerboseEvidence(results, root, logger) {
1879
2007
  }
1880
2008
  }
1881
2009
  /**
1882
- * The stderr half of a run-level refusal, so the human channel says what the
1883
- * document says. The document is derived in `buildBaseSummary`; this only
1884
- * RENDERS it. Both stderr lanes call it first, because "Audit successful: 0
1885
- * file(s) passed" over `status: error` is the exact disagreement the refusal
1886
- * exists to end (invariant 6 of `run-integrity.ts`). The run ends on
1887
- * `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`).
1888
2016
  *
1889
2017
  * @returns Whether a refusal was rendered, so the caller skips its verdict line
1890
2018
  */
1891
- function logRunIntegrity(runIssues, logger) {
1892
- 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)
1893
2022
  return false;
1894
- logger.error('Audit is not a verdict: it audited 0 files');
1895
- for (const issue of runIssues) {
1896
- 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, ' '))
1897
2026
  logger.error(line);
1898
2027
  }
1899
2028
  return true;
@@ -1933,36 +2062,34 @@ function logSettingsTotals(files, logger) {
1933
2062
  logger.error(`⚠ ${compatUnchecked} path(s) the compatibility analysis could not read — see 'compatibility.unchecked' in YAML output`);
1934
2063
  }
1935
2064
  }
1936
- function handleAuditResults(results, summary, logger, verbose) {
1937
- const { filesWithErrors: errorCount, filesWithWarnings: warningCount, filesPassed: successCount, } = summary.summary;
1938
- logSettingsTotals(summary.files ?? [], logger);
1939
- // The exit code follows the document's `status`, as it does in every other
1940
- // command of this CLI: `status: error` — an error-severity finding, or a run
1941
- // that audited zero files — ends on `FINDINGS`. This used to be the one
1942
- // command that exited 0 over `status: error` ("advisory"), and an adopter
1943
- // wiring it into CI read "Audit failed" on stderr beside a green step.
1944
- const refused = logRunIntegrity(summary.issues, logger);
1945
- 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)) {
1946
2074
  // Rendered above; there is no file verdict to print over zero files.
1947
2075
  }
1948
2076
  else if (errorCount > 0) {
1949
2077
  logger.error(`Audit found ${errorCount} file(s) with errors`);
1950
- logFindingsForStatus(results, 'error', summary.root, logger.error.bind(logger), verbose);
2078
+ logFindingsForStatus(results, hasErrors, root, logger.error.bind(logger), verbose);
1951
2079
  }
1952
2080
  else if (warningCount > 0) {
1953
2081
  logger.info(`Audit passed with warnings: ${warningCount} file(s)`);
1954
- logFindingsForStatus(results, 'warning', summary.root, logger.info.bind(logger), verbose);
2082
+ logFindingsForStatus(results, hasOnlyWarnings, root, logger.info.bind(logger), verbose);
1955
2083
  }
1956
2084
  else {
1957
- // `success` means "nothing actionable", NOT "nothing to see" — name the
1958
- // 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.
1959
2087
  const withFindings = countResultsWithFindings(results);
1960
2088
  logger.info(withFindings > 0
1961
2089
  ? `Audit successful: ${successCount} file(s) passed (${withFindings} with informational findings)`
1962
2090
  : `Audit successful: ${successCount} file(s) passed`);
1963
2091
  }
1964
2092
  renderAuditFooter(results, logger);
1965
- process.exit(refused || errorCount > 0 ? ExitCode.FINDINGS : ExitCode.OK);
1966
2093
  }
1967
2094
  /**
1968
2095
  * Render the skill-quality checklist footer when audit results contain
@@ -2015,7 +2142,7 @@ function renderAuditFooter(results, logger) {
2015
2142
  * cannot answer the question.
2016
2143
  *
2017
2144
  * Pure: takes results, returns lines. It reads `issues` and never rewrites it,
2018
- * because `runAuditAtPath` builds the YAML document from the very same array.
2145
+ * because `buildAuditAtPath` builds the YAML document from the very same array.
2019
2146
  *
2020
2147
  * @internal Exported for unit testing only — not part of the public CLI API.
2021
2148
  */
@@ -2051,8 +2178,8 @@ export function formatAuditFindingsLines(results, root, verbose) {
2051
2178
  * The banner counts FILES and the blocks below count FINDINGS; both are needed,
2052
2179
  * and `logFn` picks the channel the calling branch already established.
2053
2180
  */
2054
- function logFindingsForStatus(results, status, root, logFn, verbose) {
2055
- const selected = results.filter((r) => r.status === status);
2181
+ function logFindingsForStatus(results, inBucket, root, logFn, verbose) {
2182
+ const selected = results.filter(inBucket);
2056
2183
  for (const line of formatAuditFindingsLines(selected, root, verbose)) {
2057
2184
  logFn(line);
2058
2185
  }
@@ -2134,15 +2261,16 @@ async function handleFileEntry(entry, fullPath, options, logger, scanCtx) {
2134
2261
  const skillDir = safePath.resolve(fullPath, '..');
2135
2262
  const unreadable = degradingRegistry(findProjectRoot(skillDir) ?? skillDir, logger, locationRoot);
2136
2263
  const sharedCtx = scanCtx.gitTracker === null
2137
- ? { locationRoot, projectSkills, suiteProbe, unreadable }
2138
- : { gitTracker: scanCtx.gitTracker, locationRoot, projectSkills, suiteProbe, unreadable };
2264
+ ? { locationRoot, projectSkills, suiteProbe, unreadable, outputs: [] }
2265
+ : { gitTracker: scanCtx.gitTracker, locationRoot, projectSkills, suiteProbe, unreadable, outputs: [] };
2139
2266
  const packagingResult = await validateSkillForPackaging(fullPath, skillConfig, 'source', sharedCtx);
2140
2267
  const configAware = packagingResultToValidationResult(fullPath, packagingResult, skillConfig.targets, locationRoot);
2141
2268
  await appendDistributedTreeFindings(configAware, fullPath, locationRoot, ownsOwnCrawl(scanCtx, fullPath));
2142
2269
  return configAware;
2143
2270
  }
2144
2271
  // Wild mode: basic validation. Severity is applied by `applySeverityFilter`.
2145
- const validateOptions = { skillPath: fullPath, locationRoot, validation: {} };
2272
+ // The audited skill is the verb's input.
2273
+ const validateOptions = { skillPath: fullPath, locationRoot, validation: {}, side: 'source' };
2146
2274
  if (options.warnUnreferencedFiles) {
2147
2275
  validateOptions.checkUnreferencedFiles = true;
2148
2276
  }
@@ -2179,7 +2307,7 @@ async function validatePluginDirectory(dir, logger, locationRoot) {
2179
2307
  */
2180
2308
  const inventoryRegistryCache = new Map();
2181
2309
  /** Build (once per run, per root) the registry the plugin inventory link walk needs. */
2182
- async function getOrCreateInventoryRegistry(projectRoot) {
2310
+ function getOrCreateInventoryRegistry(projectRoot) {
2183
2311
  const cached = inventoryRegistryCache.get(projectRoot);
2184
2312
  if (cached !== undefined) {
2185
2313
  return cached;
@@ -2215,7 +2343,7 @@ async function getOrCreateInventoryRegistry(projectRoot) {
2215
2343
  * case to encode here. This is the call site that carried all 786 measured
2216
2344
  * `git check-ignore` spawns.
2217
2345
  */
2218
- async function pluginInventoryAt(dir) {
2346
+ function pluginInventoryAt(dir) {
2219
2347
  const projectRoot = findProjectRoot(dir);
2220
2348
  return extractClaudePluginInventory(dir, {
2221
2349
  ...(projectRoot === null
@@ -2280,11 +2408,11 @@ async function resolveScanContext(dirPath, locationRoot, logger) {
2280
2408
  * is no longer the ONLY thing the run says — the code, the location and the fix
2281
2409
  * come from the registry.
2282
2410
  *
2283
- * 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`
2284
2412
  * recognises it ({@link isUnreadablePathResult}) and reports it under
2285
- * `summary.pathsUnreadable`, outside `filesScanned` and the status counts. A
2286
- * root the OS refused therefore audits zero files and ends on the zero-files
2287
- * 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.
2288
2416
  */
2289
2417
  function unreadablePathResult(dirPath, error, locationRoot) {
2290
2418
  // `issueLocation` is `path.relative`, so it answers `''` when the subject IS the
@@ -2305,14 +2433,11 @@ function unreadablePathResult(dirPath, error, locationRoot) {
2305
2433
  detail: `${location}: ${reason}`,
2306
2434
  }),
2307
2435
  ];
2308
- const issueCounts = countBySeverity(issues);
2309
2436
  return {
2310
2437
  path: dirPath,
2311
2438
  type: 'unknown',
2312
- status: calculateValidationStatus(issues),
2313
- summary: formatCountsSummary(issueCounts),
2439
+ ...describeIssues(issues, 'unknown'),
2314
2440
  issues,
2315
- issueCounts,
2316
2441
  };
2317
2442
  }
2318
2443
  /**
@@ -2342,7 +2467,7 @@ async function validateScanSubject(subject, options, logger, scanCtx, claims) {
2342
2467
  }
2343
2468
  const subjectCtx = { ...scanCtx, crawledRoot: claims.owner(subject.path) };
2344
2469
  const result = await handleFileEntry({ name: basename(subject.path) }, subject.path, options, logger, subjectCtx);
2345
- 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)) {
2346
2471
  claims.claim(subject.dir);
2347
2472
  }
2348
2473
  return result === null ? [] : [result];
@@ -2352,7 +2477,7 @@ async function validateScanSubject(subject, options, logger, scanCtx, claims) {
2352
2477
  // turning a genuine VAT bug into a `warning` about the file it happened on is
2353
2478
  // the same "detector silently disables itself" shape this guard exists to
2354
2479
  // prevent — it would make the tool quietest exactly when it is most wrong.
2355
- if (!isFilesystemAccessError(error))
2480
+ if (fsFaultOf(error) === undefined)
2356
2481
  throw error;
2357
2482
  const path = subject.kind === 'plugin' ? subject.dir : subject.path;
2358
2483
  logger.debug(`Unreadable entry: ${path}`);
@@ -2403,29 +2528,16 @@ async function scanDirectory(dirPath, recursive, options, logger, scanCtx) {
2403
2528
  }
2404
2529
  const results = population.refusals.map((refusal) => {
2405
2530
  logger.debug(`Unreadable directory: ${refusal.directory}`);
2406
- const err = new DirectoryListingRefusedError(refusal, { root: dirPath, remedy: scanRefusalRemedy() });
2531
+ const err = new DirectoryListingRefusedError(refusal, { root: dirPath, remedy: scanRefusalRemedy(), side: 'source' });
2407
2532
  return unreadablePathResult(refusal.directory, err, scanCtx.locationRoot);
2408
2533
  });
2409
2534
  const claims = new SubtreeClaims();
2410
- 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) => {
2411
2537
  results.push(...await validateScanSubject(subject, options, logger, scanCtx, claims));
2412
- }
2538
+ });
2413
2539
  return results;
2414
2540
  }
2415
- /**
2416
- * Calculate overall status from validation results
2417
- */
2418
- function calculateOverallStatus(results) {
2419
- const errorCount = results.filter((r) => r.status === 'error').length;
2420
- const warningCount = results.filter((r) => r.status === 'warning').length;
2421
- if (errorCount > 0) {
2422
- return 'error';
2423
- }
2424
- if (warningCount > 0) {
2425
- return 'warning';
2426
- }
2427
- return 'success';
2428
- }
2429
2541
  /**
2430
2542
  * How many results carry at least one finding.
2431
2543
  *
@@ -2449,147 +2561,53 @@ function isUnreadablePathResult(result) {
2449
2561
  && result.issues.every((issue) => issue.code === 'SCAN_PATH_UNREADABLE');
2450
2562
  }
2451
2563
  /**
2452
- * Count files by their own status.
2564
+ * Count files by their worst actionable severity, and the files read.
2453
2565
  *
2454
2566
  * A refused path is NOT a scanned file. It used to be counted as one, which
2455
2567
  * made the zero-files refusal unreachable for exactly the tree it exists for:
2456
- * `chmod 000` on the whole root gave `filesScanned: 1, filesPassed: 0`,
2457
- * `status: warning`, exit 0 — nothing read, gate green. Kept out of every
2458
- * 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.
2459
2571
  */
2460
2572
  function countFilesByStatus(results) {
2461
2573
  const scanned = results.filter((r) => !isUnreadablePathResult(r));
2574
+ const withErrors = scanned.filter(hasErrors).length;
2575
+ const withWarnings = scanned.filter(hasOnlyWarnings).length;
2462
2576
  return {
2463
- filesScanned: scanned.length,
2464
- filesPassed: scanned.filter((r) => r.status === 'success').length,
2465
- filesWithWarnings: scanned.filter((r) => r.status === 'warning').length,
2466
- filesWithErrors: scanned.filter((r) => r.status === 'error').length,
2467
- pathsUnreadable: results.length - scanned.length,
2468
- };
2469
- }
2470
- /**
2471
- * Build base summary structure (used by both flat and hierarchical), together
2472
- * with the entries the document will publish.
2473
- *
2474
- * `issueCounts` is named exactly as it is on every individual file entry, and
2475
- * means the same thing at both levels: findings, by severity. `summary` only ever
2476
- * counts files.
2477
- *
2478
- * The header total and every per-file total come from ONE traversal of the
2479
- * final issue set, and the entries carrying those per-file totals are returned
2480
- * from the same pass. Before that, the header was derived from the issue
2481
- * records while each file's `issueCounts` was whatever its producer had
2482
- * published — and a producer that appends findings after publishing (or never
2483
- * sets the counts at all: `validatePlugin` writes `status` and `summary` but
2484
- * not `issueCounts`) left the two disagreeing inside one document. A real
2485
- * `vat audit --user` run said 55/422/504 in the header over per-file counts
2486
- * summing to 55/360/405, with 91 of 614 entries declaring `{0,0,0}` above the
2487
- * findings they listed. Re-deriving here means the header and the sum are the
2488
- * same arithmetic on the same array, so they cannot drift again no matter what
2489
- * a producer forgets.
2490
- *
2491
- * `linkedFiles[].issues` are deliberately NOT added: every linked finding is
2492
- * also present in its owner's `issues`, so the nested list is a VIEW of records
2493
- * already counted, not extra records. `audit-report-coherence.integration.test.ts`
2494
- * pins that subset relation, because counting once is only correct while it holds.
2495
- *
2496
- * 🚨 **Zero files audited is an ERROR, not "an empty tree audits cleanly".**
2497
- * `calculateOverallStatus([])` is `success`, so an existing directory holding
2498
- * nothing auditable — moved plugins, a wrong subdirectory, an excluded tree, a
2499
- * tree of files no lane recognises — published `status: success` beside
2500
- * `filesScanned: 0`, and this command's own documentation tells CI to gate on
2501
- * that `status`. Derived HERE, in the one builder both the directory lane
2502
- * (`calculateSummary`) and the `--user` lane (`calculateHierarchicalSummary`)
2503
- * pass through, so neither can publish a clean status over a zero denominator.
2504
- * Through the shared mechanism in `run-integrity.ts`: one non-overridable
2505
- * `RESOURCE_CHECK_BROKEN` at `error`, published under a top-level `issues` —
2506
- * the claim is about the RUN, so it is not a `files[]` row and does not count
2507
- * toward `filesScanned` — and counted in the header `issueCounts`, so the
2508
- * identity becomes `issueCounts === Σ files[].issueCounts + Σ issues`.
2509
- *
2510
- * The exit code is NOT touched by this: `status` describes the findings and the
2511
- * exit code describes whether the run completed, and this run completed. See
2512
- * {@link createAuditCommand}.
2513
- */
2514
- function buildBaseSummary(results, startTime) {
2515
- const issueCounts = { errors: 0, warnings: 0, info: 0 };
2516
- const entries = results.map((result) => {
2517
- const counts = countBySeverity(result.issues);
2518
- issueCounts.errors += counts.errors;
2519
- issueCounts.warnings += counts.warnings;
2520
- issueCounts.info += counts.info;
2521
- return { ...result, issueCounts: counts };
2522
- });
2523
- const summary = countFilesByStatus(entries);
2524
- // The denominator is files READ: a tree whose every path was refused audited
2525
- // nothing, and says so through the same refusal as an empty tree.
2526
- 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'
2527
- + ' to audit produces the same counts as a clean one. The path resolved to a tree'
2528
- + ' holding no auditable file — usually a wrong subdirectory, plugins or skills that'
2529
- + ' have moved, an excluded tree, files no audit lane recognises, or `--no-recursive`'
2530
- + ' over a tree whose resources sit deeper. Point the command at the plugin,'
2531
- + ' marketplace, registry or SKILL.md tree it should read.');
2532
- return {
2533
- entries,
2534
- // Every run-integrity finding is `error` by construction (invariant 2 of
2535
- // `run-integrity.ts`), so a non-empty refusal IS the status; otherwise the
2536
- // files decide it, as before.
2537
- status: runIssues.length > 0 ? 'error' : calculateOverallStatus(entries),
2538
- summary,
2539
- issueCounts: sumSeverityCounts([issueCounts, countBySeverity(runIssues)]),
2540
- ...(runIssues.length === 0 ? {} : { issues: [...runIssues] }),
2541
- duration: `${Date.now() - startTime}ms`,
2542
- };
2543
- }
2544
- /**
2545
- * Calculate summary for hierarchical output
2546
- */
2547
- function calculateHierarchicalSummary(results, hierarchical, startTime, compatMap, verbose, root) {
2548
- const { entries, ...base } = buildBaseSummary(results, startTime);
2549
- const withCompat = applyCompatMap(entries, compatMap, root);
2550
- return {
2551
- root,
2552
- ...base,
2553
- summary: {
2554
- ...base.summary,
2555
- marketplaces: hierarchical.marketplaces.length,
2556
- cachedPlugins: hierarchical.cachedPlugins.length,
2557
- standalonePlugins: hierarchical.standalonePlugins.length,
2558
- 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,
2559
2583
  },
2560
- files: relativizePathEntries(applyVerboseFilter(withCompat, verbose), root, NESTED_PATH_CARRIERS),
2561
- hierarchical,
2562
2584
  };
2563
2585
  }
2564
2586
  /**
2565
- * 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`.
2566
2589
  */
2567
- function logHierarchicalSummary(results, runIssues, logger) {
2568
- const status = calculateOverallStatus(results);
2590
+ function logHierarchicalSummary({ results, written, data }, logger) {
2591
+ const { filesWithErrors, filesWithWarnings } = data.counts;
2569
2592
  const skillsWithIssues = countResultsWithFindings(results);
2570
2593
  const totalSkills = results.length;
2571
- // Same rule as the per-file lane: the exit code follows `status`.
2572
- const refused = logRunIntegrity(runIssues, logger);
2573
- if (refused) {
2594
+ if (logRunIntegrity(written, logger)) {
2574
2595
  // Rendered above; there is no skill verdict to print over zero skills.
2575
2596
  }
2576
- else if (status === 'error') {
2577
- const errorCount = results.filter((r) => r.status === 'error').length;
2578
- 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)`);
2579
2599
  }
2580
- else if (status === 'warning') {
2581
- const warningCount = results.filter((r) => r.status === 'warning').length;
2582
- 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)`);
2583
2602
  }
2584
2603
  else if (skillsWithIssues > 0) {
2585
- // `success` means "nothing actionable", NOT "nothing to see". Saying only
2586
- // "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.
2587
2606
  logger.info(`Audit successful: ${totalSkills} skill(s) passed (${skillsWithIssues} with informational findings)`);
2588
2607
  }
2589
2608
  else {
2590
2609
  logger.info(`Audit successful: ${totalSkills} skill(s) passed`);
2591
2610
  }
2592
2611
  renderAuditFooter(results, logger);
2593
- process.exit(refused || status === 'error' ? ExitCode.FINDINGS : ExitCode.OK);
2594
2612
  }
2595
2613
  //# sourceMappingURL=audit.js.map