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

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 (220) hide show
  1. package/README.md +4 -4
  2. package/dist/bin.js +41 -158
  3. package/dist/bin.js.map +1 -1
  4. package/dist/command-loaders.d.ts +2 -2
  5. package/dist/command-loaders.d.ts.map +1 -1
  6. package/dist/command-loaders.js +4 -2
  7. package/dist/command-loaders.js.map +1 -1
  8. package/dist/commands/ard/emit.d.ts +104 -0
  9. package/dist/commands/ard/emit.d.ts.map +1 -0
  10. package/dist/commands/ard/emit.js +223 -0
  11. package/dist/commands/ard/emit.js.map +1 -0
  12. package/dist/commands/ard/index.d.ts +12 -0
  13. package/dist/commands/ard/index.d.ts.map +1 -0
  14. package/dist/commands/ard/index.js +79 -0
  15. package/dist/commands/ard/index.js.map +1 -0
  16. package/dist/commands/ard/surfaces.d.ts +56 -0
  17. package/dist/commands/ard/surfaces.d.ts.map +1 -0
  18. package/dist/commands/ard/surfaces.js +150 -0
  19. package/dist/commands/ard/surfaces.js.map +1 -0
  20. package/dist/commands/audit.d.ts +75 -8
  21. package/dist/commands/audit.d.ts.map +1 -1
  22. package/dist/commands/audit.js +726 -127
  23. package/dist/commands/audit.js.map +1 -1
  24. package/dist/commands/claude/budget.d.ts +13 -0
  25. package/dist/commands/claude/budget.d.ts.map +1 -1
  26. package/dist/commands/claude/budget.js +80 -28
  27. package/dist/commands/claude/budget.js.map +1 -1
  28. package/dist/commands/claude/claude-config.d.ts.map +1 -1
  29. package/dist/commands/claude/claude-config.js +6 -0
  30. package/dist/commands/claude/claude-config.js.map +1 -1
  31. package/dist/commands/claude/context.js +1 -1
  32. package/dist/commands/claude/context.js.map +1 -1
  33. package/dist/commands/claude/marketplace/validate.d.ts +55 -22
  34. package/dist/commands/claude/marketplace/validate.d.ts.map +1 -1
  35. package/dist/commands/claude/marketplace/validate.js +380 -75
  36. package/dist/commands/claude/marketplace/validate.js.map +1 -1
  37. package/dist/commands/claude/org/helpers.d.ts +59 -1
  38. package/dist/commands/claude/org/helpers.d.ts.map +1 -1
  39. package/dist/commands/claude/org/helpers.js +58 -7
  40. package/dist/commands/claude/org/helpers.js.map +1 -1
  41. package/dist/commands/claude/org/index.d.ts.map +1 -1
  42. package/dist/commands/claude/org/index.js +24 -16
  43. package/dist/commands/claude/org/index.js.map +1 -1
  44. package/dist/commands/claude/org/skills.d.ts +509 -0
  45. package/dist/commands/claude/org/skills.d.ts.map +1 -1
  46. package/dist/commands/claude/org/skills.js +1364 -94
  47. package/dist/commands/claude/org/skills.js.map +1 -1
  48. package/dist/commands/claude/org/users.d.ts.map +1 -1
  49. package/dist/commands/claude/org/users.js +3 -1
  50. package/dist/commands/claude/org/users.js.map +1 -1
  51. package/dist/commands/claude/org/workspaces.d.ts.map +1 -1
  52. package/dist/commands/claude/org/workspaces.js +5 -2
  53. package/dist/commands/claude/org/workspaces.js.map +1 -1
  54. package/dist/commands/claude/plugin/build.d.ts +8 -0
  55. package/dist/commands/claude/plugin/build.d.ts.map +1 -1
  56. package/dist/commands/claude/plugin/build.js +16 -2
  57. package/dist/commands/claude/plugin/build.js.map +1 -1
  58. package/dist/commands/claude/plugin/tree-copy.d.ts +72 -0
  59. package/dist/commands/claude/plugin/tree-copy.d.ts.map +1 -1
  60. package/dist/commands/claude/plugin/tree-copy.js +215 -10
  61. package/dist/commands/claude/plugin/tree-copy.js.map +1 -1
  62. package/dist/commands/corpus/index.d.ts.map +1 -1
  63. package/dist/commands/corpus/index.js +3 -0
  64. package/dist/commands/corpus/index.js.map +1 -1
  65. package/dist/commands/corpus/report.d.ts +0 -1
  66. package/dist/commands/corpus/report.d.ts.map +1 -1
  67. package/dist/commands/corpus/report.js +0 -1
  68. package/dist/commands/corpus/report.js.map +1 -1
  69. package/dist/commands/corpus/runner.d.ts +58 -1
  70. package/dist/commands/corpus/runner.d.ts.map +1 -1
  71. package/dist/commands/corpus/runner.js +90 -15
  72. package/dist/commands/corpus/runner.js.map +1 -1
  73. package/dist/commands/corpus/scan.d.ts.map +1 -1
  74. package/dist/commands/corpus/scan.js +0 -1
  75. package/dist/commands/corpus/scan.js.map +1 -1
  76. package/dist/commands/doctor.d.ts +14 -0
  77. package/dist/commands/doctor.d.ts.map +1 -1
  78. package/dist/commands/doctor.js +96 -18
  79. package/dist/commands/doctor.js.map +1 -1
  80. package/dist/commands/okf/index.d.ts +11 -0
  81. package/dist/commands/okf/index.d.ts.map +1 -0
  82. package/dist/commands/okf/index.js +102 -0
  83. package/dist/commands/okf/index.js.map +1 -0
  84. package/dist/commands/okf/validate.d.ts +82 -0
  85. package/dist/commands/okf/validate.d.ts.map +1 -0
  86. package/dist/commands/okf/validate.js +157 -0
  87. package/dist/commands/okf/validate.js.map +1 -0
  88. package/dist/commands/phase-utils.d.ts +19 -3
  89. package/dist/commands/phase-utils.d.ts.map +1 -1
  90. package/dist/commands/phase-utils.js +26 -5
  91. package/dist/commands/phase-utils.js.map +1 -1
  92. package/dist/commands/rag/index-command.d.ts +27 -2
  93. package/dist/commands/rag/index-command.d.ts.map +1 -1
  94. package/dist/commands/rag/index-command.js +44 -7
  95. package/dist/commands/rag/index-command.js.map +1 -1
  96. package/dist/commands/rag/index.d.ts.map +1 -1
  97. package/dist/commands/rag/index.js +2 -0
  98. package/dist/commands/rag/index.js.map +1 -1
  99. package/dist/commands/resources/check-progress.d.ts +3 -0
  100. package/dist/commands/resources/check-progress.d.ts.map +1 -1
  101. package/dist/commands/resources/check-progress.js +6 -0
  102. package/dist/commands/resources/check-progress.js.map +1 -1
  103. package/dist/commands/resources/check.d.ts +33 -4
  104. package/dist/commands/resources/check.d.ts.map +1 -1
  105. package/dist/commands/resources/check.js +131 -44
  106. package/dist/commands/resources/check.js.map +1 -1
  107. package/dist/commands/resources/index.d.ts.map +1 -1
  108. package/dist/commands/resources/index.js +41 -9
  109. package/dist/commands/resources/index.js.map +1 -1
  110. package/dist/commands/resources/query.d.ts +18 -1
  111. package/dist/commands/resources/query.d.ts.map +1 -1
  112. package/dist/commands/resources/query.js +29 -4
  113. package/dist/commands/resources/query.js.map +1 -1
  114. package/dist/commands/resources/validate.d.ts +29 -0
  115. package/dist/commands/resources/validate.d.ts.map +1 -1
  116. package/dist/commands/resources/validate.js +116 -13
  117. package/dist/commands/resources/validate.js.map +1 -1
  118. package/dist/commands/skill/review-checklist.d.ts.map +1 -1
  119. package/dist/commands/skill/review-checklist.js +35 -0
  120. package/dist/commands/skill/review-checklist.js.map +1 -1
  121. package/dist/commands/skill/review.d.ts.map +1 -1
  122. package/dist/commands/skill/review.js +9 -2
  123. package/dist/commands/skill/review.js.map +1 -1
  124. package/dist/commands/skill/test/configure.d.ts +37 -0
  125. package/dist/commands/skill/test/configure.d.ts.map +1 -1
  126. package/dist/commands/skill/test/configure.js +57 -12
  127. package/dist/commands/skill/test/configure.js.map +1 -1
  128. package/dist/commands/skill/test/run.d.ts.map +1 -1
  129. package/dist/commands/skill/test/run.js +21 -6
  130. package/dist/commands/skill/test/run.js.map +1 -1
  131. package/dist/commands/skills/build.d.ts.map +1 -1
  132. package/dist/commands/skills/build.js +16 -3
  133. package/dist/commands/skills/build.js.map +1 -1
  134. package/dist/commands/skills/list.d.ts +2 -1
  135. package/dist/commands/skills/list.d.ts.map +1 -1
  136. package/dist/commands/skills/list.js +31 -9
  137. package/dist/commands/skills/list.js.map +1 -1
  138. package/dist/commands/skills/skill-discovery.d.ts +40 -1
  139. package/dist/commands/skills/skill-discovery.d.ts.map +1 -1
  140. package/dist/commands/skills/skill-discovery.js +32 -3
  141. package/dist/commands/skills/skill-discovery.js.map +1 -1
  142. package/dist/commands/skills/validate-command.d.ts.map +1 -1
  143. package/dist/commands/skills/validate-command.js +11 -3
  144. package/dist/commands/skills/validate-command.js.map +1 -1
  145. package/dist/commands/skills/validate.d.ts +66 -7
  146. package/dist/commands/skills/validate.d.ts.map +1 -1
  147. package/dist/commands/skills/validate.js +133 -29
  148. package/dist/commands/skills/validate.js.map +1 -1
  149. package/dist/commands/verify.d.ts +94 -3
  150. package/dist/commands/verify.d.ts.map +1 -1
  151. package/dist/commands/verify.js +192 -45
  152. package/dist/commands/verify.js.map +1 -1
  153. package/dist/skill-resolution/packaging-config.d.ts +49 -5
  154. package/dist/skill-resolution/packaging-config.d.ts.map +1 -1
  155. package/dist/skill-resolution/packaging-config.js +59 -19
  156. package/dist/skill-resolution/packaging-config.js.map +1 -1
  157. package/dist/skill-resolution/resolve-skill-reference.d.ts.map +1 -1
  158. package/dist/skill-resolution/resolve-skill-reference.js +6 -3
  159. package/dist/skill-resolution/resolve-skill-reference.js.map +1 -1
  160. package/dist/utils/command-error.d.ts +31 -0
  161. package/dist/utils/command-error.d.ts.map +1 -1
  162. package/dist/utils/command-error.js +45 -0
  163. package/dist/utils/command-error.js.map +1 -1
  164. package/dist/utils/config-loader.d.ts.map +1 -1
  165. package/dist/utils/config-loader.js +22 -6
  166. package/dist/utils/config-loader.js.map +1 -1
  167. package/dist/utils/edge-lens-evaluation.d.ts +83 -0
  168. package/dist/utils/edge-lens-evaluation.d.ts.map +1 -0
  169. package/dist/utils/edge-lens-evaluation.js +110 -0
  170. package/dist/utils/edge-lens-evaluation.js.map +1 -0
  171. package/dist/utils/optional-backend.d.ts +5 -4
  172. package/dist/utils/optional-backend.d.ts.map +1 -1
  173. package/dist/utils/optional-backend.js +5 -4
  174. package/dist/utils/optional-backend.js.map +1 -1
  175. package/dist/utils/project-root-policy.d.ts +20 -0
  176. package/dist/utils/project-root-policy.d.ts.map +1 -1
  177. package/dist/utils/project-root-policy.js +32 -0
  178. package/dist/utils/project-root-policy.js.map +1 -1
  179. package/dist/utils/projection-query.d.ts +41 -4
  180. package/dist/utils/projection-query.d.ts.map +1 -1
  181. package/dist/utils/projection-query.js +44 -10
  182. package/dist/utils/projection-query.js.map +1 -1
  183. package/dist/utils/projection-store.d.ts +41 -15
  184. package/dist/utils/projection-store.d.ts.map +1 -1
  185. package/dist/utils/projection-store.js +65 -18
  186. package/dist/utils/projection-store.js.map +1 -1
  187. package/dist/utils/repeatable-option.d.ts +37 -0
  188. package/dist/utils/repeatable-option.d.ts.map +1 -0
  189. package/dist/utils/repeatable-option.js +39 -0
  190. package/dist/utils/repeatable-option.js.map +1 -0
  191. package/dist/utils/resource-loader.d.ts +4 -3
  192. package/dist/utils/resource-loader.d.ts.map +1 -1
  193. package/dist/utils/resource-loader.js +61 -30
  194. package/dist/utils/resource-loader.js.map +1 -1
  195. package/dist/utils/root-argv.d.ts +53 -0
  196. package/dist/utils/root-argv.d.ts.map +1 -0
  197. package/dist/utils/root-argv.js +215 -0
  198. package/dist/utils/root-argv.js.map +1 -0
  199. package/dist/utils/run-integrity.d.ts +95 -0
  200. package/dist/utils/run-integrity.d.ts.map +1 -0
  201. package/dist/utils/run-integrity.js +102 -0
  202. package/dist/utils/run-integrity.js.map +1 -0
  203. package/dist/utils/sqlite-experimental-warning.d.ts +69 -0
  204. package/dist/utils/sqlite-experimental-warning.d.ts.map +1 -0
  205. package/dist/utils/sqlite-experimental-warning.js +144 -0
  206. package/dist/utils/sqlite-experimental-warning.js.map +1 -0
  207. package/dist/utils/user-context-scanner.d.ts +8 -0
  208. package/dist/utils/user-context-scanner.d.ts.map +1 -1
  209. package/dist/utils/user-context-scanner.js +4 -0
  210. package/dist/utils/user-context-scanner.js.map +1 -1
  211. package/dist/utils/validate-help-files.d.ts.map +1 -1
  212. package/dist/utils/validate-help-files.js +9 -2
  213. package/dist/utils/validate-help-files.js.map +1 -1
  214. package/docs/audit.md +120 -7
  215. package/docs/doctor.md +6 -6
  216. package/docs/index.md +1 -1
  217. package/docs/rag.md +3 -1
  218. package/docs/resources.md +5 -1
  219. package/docs/skills.md +47 -62
  220. package/package.json +18 -18
@@ -0,0 +1,102 @@
1
+ /**
2
+ * The run-integrity refusal: ONE mechanism for every gate that must never
3
+ * answer `success` after checking nothing.
4
+ *
5
+ * ## The class this closes
6
+ *
7
+ * A gate that checked nothing produces the same document as a gate that was
8
+ * removed. `vat resources check` shipped it (no `checks:` block → `status:
9
+ * success`, exit 0), then `vat claude budget` (a path matching no working
10
+ * location), then the repo's own audit quality gate (a green path over zero
11
+ * parsed findings), then `vat resources validate` (a `--collection` matching
12
+ * nothing → `filesScanned: 0`, exit 0), `vat claude marketplace validate` (no
13
+ * `plugins/` to walk, no count published), `vat corpus scan` (an empty tree
14
+ * "audits cleanly"), `vat verify`'s `packaged-content` phase (a typo'd glob
15
+ * discovers no bundle and the phase reports `success`), then `vat skills
16
+ * validate` (the same typo'd glob: one info line, no document, exit 0 — and
17
+ * `vat validate` folded that into `success`) and `vat audit` (an existing tree
18
+ * with nothing auditable: `status: success` over `filesScanned: 0`). Nine
19
+ * instances of one shape, and each was first fixed by hand at its own site.
20
+ * This module is where that hand-fixing stops: every site derives its refusal
21
+ * through the same three functions, so the invariants below are properties of
22
+ * the mechanism rather than of each author's memory.
23
+ *
24
+ * ## The invariants
25
+ *
26
+ * 1. **Code {@link RUN_INTEGRITY_CODE} — `RESOURCE_CHECK_BROKEN` — and never a
27
+ * sibling per site.** It is the registry's one run-integrity claim — *these
28
+ * assertions did not execute meaningfully, so the green means nothing* — and
29
+ * `ValidationConfigSchema` refuses it as a `severity` key, which is what makes
30
+ * it non-overridable by construction. A code per site would buy a consumer
31
+ * nothing the message does not already say while adding one more thing an
32
+ * adopter's CI has to know to look for.
33
+ * 2. **Severity `error`, and not a parameter.** The one thing that must never be
34
+ * configurable about "the gate did not do its job" is whether it gates.
35
+ * 3. **Derived inside the DOCUMENT builder, never asserted in a handler.** The
36
+ * builder is the one function every lane's document passes through, so
37
+ * deriving the refusal there lands it after `resolveIssueSeverity` and
38
+ * `applyAllowFilter` and makes "denominator zero, status clean"
39
+ * unrepresentable rather than merely unwritten. A pure function, unit-testable
40
+ * without I/O.
41
+ * 4. **ONE finding per run**, however many things went unmatched. The claim is
42
+ * about the RUN; one per argument is per-finding duplication.
43
+ * 5. **The message says what did not run and what the operator can do.** It
44
+ * must not claim the corpus is broken — it claims the run is not a verdict.
45
+ * 6. **stderr may still carry a human warning; the document and the exit code
46
+ * must agree with it.** The human channel and the machine channel were what
47
+ * disagreed in every shipped instance, and only the machine channel gates.
48
+ */
49
+ /**
50
+ * The code every run-integrity refusal carries.
51
+ *
52
+ * 🔑 **One code for every refusal, on purpose.** A statement that would not
53
+ * compile, a corpus with no members, a run with no rules, a run that was killed,
54
+ * a scan that matched no file, a walk that missed a declared plugin, a phase that
55
+ * found no bundle — all are the same claim to a consumer, and they need the
56
+ * identical non-overridability, which
57
+ * `ValidationConfigSchema` grants by refusing this code as a `severity` key.
58
+ */
59
+ export const RUN_INTEGRITY_CODE = 'RESOURCE_CHECK_BROKEN';
60
+ /**
61
+ * A run-integrity refusal: the non-overridable code, at `error`, always.
62
+ *
63
+ * The severity is not a parameter and must not become one. Every caller is
64
+ * reporting that the gate did not do its job, and the one thing that must never
65
+ * be configurable about that report is whether it gates.
66
+ *
67
+ * @param message - What did not run, and what the operator can do about it
68
+ * @returns The finding
69
+ */
70
+ export function runIntegrityFinding(message) {
71
+ return { code: RUN_INTEGRITY_CODE, severity: 'error', message };
72
+ }
73
+ /**
74
+ * The refusal for a run whose denominator is zero — nothing was checked.
75
+ *
76
+ * 🪤 **It asks the DENOMINATOR, never the config.** A builder cannot see why
77
+ * nothing ran and deliberately does not ask. An absent config block, a filter
78
+ * that matched nothing, a glob with a typo, a directory that was never built —
79
+ * all arrive as the same document, and all of them are a gate that asserted
80
+ * nothing. The message is where a site names the likely causes and the remedy.
81
+ *
82
+ * 🪤 **One report per situation.** A run that already carries a run-integrity
83
+ * finding (an interrupted run, say) has the more specific of the two claims on
84
+ * the document, so this stands down rather than handing the operator two reports
85
+ * about one situation. Nothing weaker is needed: every such finding is `error`,
86
+ * so the status is already refused.
87
+ *
88
+ * @param denominator - How many things the run actually checked
89
+ * @param issues - What the run already found, so an existing run-integrity
90
+ * report is not duplicated
91
+ * @param message - The site's own account of what did not run and what to do;
92
+ * evaluated lazily so a populated run pays nothing for it
93
+ * @returns The one finding, or nothing when at least one thing was checked
94
+ */
95
+ export function nothingCheckedFinding(denominator, issues, message) {
96
+ if (denominator > 0)
97
+ return [];
98
+ if (issues.some((issue) => issue.code === RUN_INTEGRITY_CODE))
99
+ return [];
100
+ return [runIntegrityFinding(message())];
101
+ }
102
+ //# sourceMappingURL=run-integrity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-integrity.js","sourceRoot":"","sources":["../../src/utils/run-integrity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAIH;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,uBAAuB,CAAC;AAE1D;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAClE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,qBAAqB,CACnC,WAAmB,EACnB,MAAkC,EAClC,OAAqB;IAErB,IAAI,WAAW,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAC/B,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,kBAAkB,CAAC;QAAE,OAAO,EAAE,CAAC;IACzE,OAAO,CAAC,mBAAmB,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Filter for the one `ExperimentalWarning` `node:sqlite` emits at load.
3
+ *
4
+ * ## Whose obligation this is, and why it lands here
5
+ *
6
+ * `@vibe-agent-toolkit/projection-sqlite` imports `node:sqlite`, which loads
7
+ * without a flag from Node 22.13.0 — but **unflagged is not silent**: Node
8
+ * still emits one `ExperimentalWarning` per process. That package deliberately
9
+ * does not suppress it, and says why in its own header: a blanket
10
+ * `NODE_NO_WARNINGS` would hide real ones. It assigns the work instead —
11
+ * *"any caller that turns this backend on by default has to filter that one
12
+ * warning by name at its own boundary."*
13
+ *
14
+ * The CLI is that caller. `openEphemeralQueryStore()` is the query lane's
15
+ * fallback when no store is selected, which is the default, so a user running
16
+ * `vat resources query` gets the warning on a perfectly ordinary run with no
17
+ * way to silence it short of silencing everything.
18
+ *
19
+ * Measured on Node v24.13.1 against the built CLI, before this filter existed:
20
+ *
21
+ * | Command | `ExperimentalWarning`s printed |
22
+ * |---|---|
23
+ * | `vat resources query "SELECT …"` | **1** |
24
+ * | `vat resources check`, no checks declared | **0** |
25
+ *
26
+ * ⚠️ That second row corrects a claim in `projection-store.ts`, which says
27
+ * `node:sqlite` is required "on every default run of those two commands".
28
+ * True of `query`; too strong for `check`, which never opens a store when the
29
+ * project declares no checks for it to evaluate. The obligation is real either
30
+ * way — it just fires on one command rather than two.
31
+ *
32
+ * ## Why the predicate is deliberately narrow
33
+ *
34
+ * The failure being avoided is not "a warning printed"; it is "a warning
35
+ * suppressed that someone needed to see". So the match requires BOTH the
36
+ * `ExperimentalWarning` type and SQLite's own message, and every near miss —
37
+ * another experimental builtin, a `DeprecationWarning` that mentions SQLite, an
38
+ * untyped string — is passed straight through. The test suite spends most of
39
+ * its assertions on what this does *not* swallow, because that is the property
40
+ * worth defending.
41
+ *
42
+ * ⛔ Do not widen this to "any ExperimentalWarning". The next experimental
43
+ * builtin VAT starts loading is one a maintainer should be told about.
44
+ */
45
+ /**
46
+ * Does this warning look like the `node:sqlite` load warning, and nothing else?
47
+ *
48
+ * @param warning - The warning value `process.emitWarning` was called with
49
+ * @param type - The `type` argument, when the caller passed a bare string
50
+ * @returns `true` only for SQLite's experimental-load warning
51
+ */
52
+ export declare function isSqliteExperimentalWarning(warning: unknown, type?: unknown): boolean;
53
+ /** Restores the emitter this filter replaced. */
54
+ export type RestoreWarningEmitter = () => void;
55
+ /**
56
+ * Wrap `process.emitWarning` so SQLite's load warning is dropped and every
57
+ * other warning is emitted unchanged.
58
+ *
59
+ * Patching the emitter is what makes this filter *by name*. The alternatives
60
+ * are both worse: `NODE_NO_WARNINGS` is global and hides real warnings, and
61
+ * replacing the `'warning'` listener means re-implementing Node's default
62
+ * formatting, which then drifts from it silently.
63
+ *
64
+ * @param host - The process-like object to patch; injected so the behaviour is
65
+ * testable without mutating the real process
66
+ * @returns A function restoring the previous emitter
67
+ */
68
+ export declare function installSqliteWarningFilter(host?: Pick<NodeJS.Process, 'emitWarning'>): RestoreWarningEmitter;
69
+ //# sourceMappingURL=sqlite-experimental-warning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-experimental-warning.d.ts","sourceRoot":"","sources":["../../src/utils/sqlite-experimental-warning.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAQH;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAOrF;AAED,iDAAiD;AACjD,MAAM,MAAM,qBAAqB,GAAG,MAAM,IAAI,CAAC;AAwC/C;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,GAAE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,aAAa,CAAW,GAClD,qBAAqB,CAwBvB"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Filter for the one `ExperimentalWarning` `node:sqlite` emits at load.
3
+ *
4
+ * ## Whose obligation this is, and why it lands here
5
+ *
6
+ * `@vibe-agent-toolkit/projection-sqlite` imports `node:sqlite`, which loads
7
+ * without a flag from Node 22.13.0 — but **unflagged is not silent**: Node
8
+ * still emits one `ExperimentalWarning` per process. That package deliberately
9
+ * does not suppress it, and says why in its own header: a blanket
10
+ * `NODE_NO_WARNINGS` would hide real ones. It assigns the work instead —
11
+ * *"any caller that turns this backend on by default has to filter that one
12
+ * warning by name at its own boundary."*
13
+ *
14
+ * The CLI is that caller. `openEphemeralQueryStore()` is the query lane's
15
+ * fallback when no store is selected, which is the default, so a user running
16
+ * `vat resources query` gets the warning on a perfectly ordinary run with no
17
+ * way to silence it short of silencing everything.
18
+ *
19
+ * Measured on Node v24.13.1 against the built CLI, before this filter existed:
20
+ *
21
+ * | Command | `ExperimentalWarning`s printed |
22
+ * |---|---|
23
+ * | `vat resources query "SELECT …"` | **1** |
24
+ * | `vat resources check`, no checks declared | **0** |
25
+ *
26
+ * ⚠️ That second row corrects a claim in `projection-store.ts`, which says
27
+ * `node:sqlite` is required "on every default run of those two commands".
28
+ * True of `query`; too strong for `check`, which never opens a store when the
29
+ * project declares no checks for it to evaluate. The obligation is real either
30
+ * way — it just fires on one command rather than two.
31
+ *
32
+ * ## Why the predicate is deliberately narrow
33
+ *
34
+ * The failure being avoided is not "a warning printed"; it is "a warning
35
+ * suppressed that someone needed to see". So the match requires BOTH the
36
+ * `ExperimentalWarning` type and SQLite's own message, and every near miss —
37
+ * another experimental builtin, a `DeprecationWarning` that mentions SQLite, an
38
+ * untyped string — is passed straight through. The test suite spends most of
39
+ * its assertions on what this does *not* swallow, because that is the property
40
+ * worth defending.
41
+ *
42
+ * ⛔ Do not widen this to "any ExperimentalWarning". The next experimental
43
+ * builtin VAT starts loading is one a maintainer should be told about.
44
+ */
45
+ /** Node's own text for the SQLite warning, matched as a substring. */
46
+ const SQLITE_WARNING_FRAGMENT = 'SQLite is an experimental feature';
47
+ /** The warning type Node tags it with. */
48
+ const EXPERIMENTAL_WARNING_NAME = 'ExperimentalWarning';
49
+ /**
50
+ * Does this warning look like the `node:sqlite` load warning, and nothing else?
51
+ *
52
+ * @param warning - The warning value `process.emitWarning` was called with
53
+ * @param type - The `type` argument, when the caller passed a bare string
54
+ * @returns `true` only for SQLite's experimental-load warning
55
+ */
56
+ export function isSqliteExperimentalWarning(warning, type) {
57
+ const isError = warning instanceof Error;
58
+ const name = isError ? warning.name : type;
59
+ if (name !== EXPERIMENTAL_WARNING_NAME)
60
+ return false;
61
+ const message = isError ? warning.message : warning;
62
+ return typeof message === 'string' && message.includes(SQLITE_WARNING_FRAGMENT);
63
+ }
64
+ /** Marks a function as one of this module's filters, so a chain can be walked. */
65
+ const FILTER_BRAND = Symbol('sqliteWarningFilter');
66
+ /** Is this one of our filters, rather than the host's own emitter? */
67
+ function isFilterEmitter(value) {
68
+ return typeof value === 'function' && FILTER_BRAND in value;
69
+ }
70
+ /**
71
+ * Wrap `process.emitWarning` so SQLite's load warning is dropped and every
72
+ * other warning is emitted unchanged.
73
+ *
74
+ * Patching the emitter is what makes this filter *by name*. The alternatives
75
+ * are both worse: `NODE_NO_WARNINGS` is global and hides real warnings, and
76
+ * replacing the `'warning'` listener means re-implementing Node's default
77
+ * formatting, which then drifts from it silently.
78
+ *
79
+ * @param host - The process-like object to patch; injected so the behaviour is
80
+ * testable without mutating the real process
81
+ * @returns A function restoring the previous emitter
82
+ */
83
+ export function installSqliteWarningFilter(host = process) {
84
+ const filtered = ((...args) => {
85
+ if (!filtered.retired && isSqliteExperimentalWarning(args[0], args[1]))
86
+ return;
87
+ // Read through the node, not through a captured local: `previous` is
88
+ // rewritten when a filter below this one is spliced out.
89
+ Reflect.apply(filtered.previous, host, args);
90
+ });
91
+ // Stored UNBOUND so chain identity survives — a `.bind()` here would make each
92
+ // filter delegate to a fresh wrapper, and no restore could then recognise the
93
+ // node it needs to splice out.
94
+ filtered.previous = host.emitWarning;
95
+ filtered.retired = false;
96
+ Object.defineProperty(filtered, FILTER_BRAND, { value: true });
97
+ host.emitWarning = filtered;
98
+ return () => {
99
+ // Retire FIRST, and unconditionally. Splicing is the tidy outcome; ceasing
100
+ // to filter is the one the caller actually asked for, and it is the only one
101
+ // that can always be delivered.
102
+ filtered.retired = true;
103
+ removeFromChain(host, filtered);
104
+ };
105
+ }
106
+ /**
107
+ * Take one filter out of the emitter chain, wherever it currently sits.
108
+ *
109
+ * Doing nothing when the filter is already gone is the correct answer, not a
110
+ * swallowed failure: a second `restore()` call, or a host whose emitter was
111
+ * replaced wholesale by something else, both mean this filter is no longer
112
+ * reached at all — which is exactly what the caller asked for.
113
+ *
114
+ * ⚠️ **There is a third case, and it is NOT covered here.** The walk can only
115
+ * step through nodes carrying {@link FILTER_BRAND}, so any *delegating* wrapper
116
+ * installed above us — an APM shim, another library's warning filter, an
117
+ * unrestored spy — ends the walk with our node still in the chain. That is not
118
+ * an oversight that can be fixed: the foreign wrapper holds its link to the
119
+ * emitter beneath it in a closure, and nothing outside it can rewrite that link.
120
+ * Splicing through it is genuinely impossible, not merely unimplemented.
121
+ *
122
+ * So the leak is closed at the other end: `restore()` sets `retired` before
123
+ * calling this, and a retired node forwards everything. The chain may keep a
124
+ * dead link in it — harmless — but no unreachable filter goes on eating the
125
+ * warning it was installed to hide, which was the real defect (a
126
+ * `vat resources query` run under an APM agent would have lost SQLite's
127
+ * experimental warning permanently, with no way to get it back short of
128
+ * restarting the process).
129
+ */
130
+ function removeFromChain(host, filter) {
131
+ if (host.emitWarning === filter) {
132
+ host.emitWarning = filter.previous;
133
+ return;
134
+ }
135
+ let node = host.emitWarning;
136
+ while (isFilterEmitter(node)) {
137
+ if (node.previous === filter) {
138
+ node.previous = filter.previous;
139
+ return;
140
+ }
141
+ node = node.previous;
142
+ }
143
+ }
144
+ //# sourceMappingURL=sqlite-experimental-warning.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-experimental-warning.js","sourceRoot":"","sources":["../../src/utils/sqlite-experimental-warning.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,sEAAsE;AACtE,MAAM,uBAAuB,GAAG,mCAAmC,CAAC;AAEpE,0CAA0C;AAC1C,MAAM,yBAAyB,GAAG,qBAAqB,CAAC;AAExD;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,CAAC,OAAgB,EAAE,IAAc;IAC1E,MAAM,OAAO,GAAG,OAAO,YAAY,KAAK,CAAC;IACzC,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3C,IAAI,IAAI,KAAK,yBAAyB;QAAE,OAAO,KAAK,CAAC;IAErD,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IACpD,OAAO,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC;AAClF,CAAC;AAQD,kFAAkF;AAClF,MAAM,YAAY,GAAG,MAAM,CAAC,qBAAqB,CAAC,CAAC;AA6BnD,sEAAsE;AACtE,SAAS,eAAe,CAAC,KAAc;IACrC,OAAO,OAAO,KAAK,KAAK,UAAU,IAAI,YAAY,IAAI,KAAK,CAAC;AAC9D,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAA4C,OAAO;IAEnD,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,IAAe,EAAQ,EAAE;QAC7C,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,2BAA2B,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO;QAC/E,qEAAqE;QACrE,yDAAyD;QACzD,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/C,CAAC,CAAkB,CAAC;IAEpB,+EAA+E;IAC/E,8EAA8E;IAC9E,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC,WAA0B,CAAC;IACpD,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC;IACzB,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAE/D,IAAI,CAAC,WAAW,GAAG,QAAoD,CAAC;IAExE,OAAO,GAAG,EAAE;QACV,2EAA2E;QAC3E,6EAA6E;QAC7E,gCAAgC;QAChC,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;QACxB,eAAe,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAClC,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAS,eAAe,CAAC,IAAyC,EAAE,MAAqB;IACvF,IAAK,IAAI,CAAC,WAAuB,KAAK,MAAM,EAAE,CAAC;QAC7C,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,QAAyC,CAAC;QACpE,OAAO;IACT,CAAC;IAED,IAAI,IAAI,GAAY,IAAI,CAAC,WAAW,CAAC;IACrC,OAAO,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,QAAQ,KAAM,MAAiC,EAAE,CAAC;YACzD,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;YAChC,OAAO;QACT,CAAC;QACD,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;AACH,CAAC"}
@@ -4,6 +4,7 @@
4
4
  * Scan user-level Claude directories for plugins, skills, and marketplaces.
5
5
  */
6
6
  import { type ScanResult } from '@vibe-agent-toolkit/discovery';
7
+ import type { DirectoryRefusal } from '@vibe-agent-toolkit/utils/crawl';
7
8
  /**
8
9
  * Scan user-level Claude directories for skills and plugins
9
10
  *
@@ -27,5 +28,12 @@ export declare function scanUserContext(): Promise<{
27
28
  plugins: ScanResult[];
28
29
  skills: ScanResult[];
29
30
  marketplaces: ScanResult[];
31
+ /**
32
+ * Directories under either tree that could not be listed — carried through
33
+ * from `ScanSummary.unreadable`, because a `~/.claude/plugins` with one
34
+ * root-owned directory is ordinary and every caller must say what it could
35
+ * not see rather than list fewer skills.
36
+ */
37
+ unreadable: DirectoryRefusal[];
30
38
  }>;
31
39
  //# sourceMappingURL=user-context-scanner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"user-context-scanner.d.ts","sourceRoot":"","sources":["../../src/utils/user-context-scanner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAGtE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC;IAC/C,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,YAAY,EAAE,UAAU,EAAE,CAAC;CAC5B,CAAC,CAmCD"}
1
+ {"version":3,"file":"user-context-scanner.d.ts","sourceRoot":"","sources":["../../src/utils/user-context-scanner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAGxE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC;IAC/C,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B;;;;;OAKG;IACH,UAAU,EAAE,gBAAgB,EAAE,CAAC;CAChC,CAAC,CAuCD"}
@@ -27,6 +27,7 @@ import { scan } from '@vibe-agent-toolkit/discovery';
27
27
  */
28
28
  export async function scanUserContext() {
29
29
  const { pluginsDir, skillsDir } = getClaudeUserPaths();
30
+ const unreadable = [];
30
31
  // Scan plugins directory (SKILL.md and .claude-plugin directories)
31
32
  let plugins = [];
32
33
  // eslint-disable-next-line security/detect-non-literal-fs-filename -- User's home directory is safe
@@ -37,6 +38,7 @@ export async function scanUserContext() {
37
38
  include: ['**/SKILL.md', '**/.claude-plugin/**'],
38
39
  });
39
40
  plugins = pluginsScan.results;
41
+ unreadable.push(...pluginsScan.unreadable);
40
42
  }
41
43
  // Scan skills directory (SKILL.md files)
42
44
  let skills = [];
@@ -48,6 +50,7 @@ export async function scanUserContext() {
48
50
  include: ['**/SKILL.md'],
49
51
  });
50
52
  skills = skillsScan.results;
53
+ unreadable.push(...skillsScan.unreadable);
51
54
  }
52
55
  // Marketplaces reserved for future use
53
56
  const marketplaces = [];
@@ -55,6 +58,7 @@ export async function scanUserContext() {
55
58
  plugins,
56
59
  skills,
57
60
  marketplaces,
61
+ unreadable,
58
62
  };
59
63
  }
60
64
  //# sourceMappingURL=user-context-scanner.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"user-context-scanner.js","sourceRoot":"","sources":["../../src/utils/user-context-scanner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,IAAI,EAAmB,MAAM,+BAA+B,CAAC;AAGtE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IAKnC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,kBAAkB,EAAE,CAAC;IAEvD,mEAAmE;IACnE,IAAI,OAAO,GAAiB,EAAE,CAAC;IAC/B,oGAAoG;IACpG,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC;YAC7B,IAAI,EAAE,UAAU;YAChB,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,CAAC,aAAa,EAAE,sBAAsB,CAAC;SACjD,CAAC,CAAC;QACH,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;IAChC,CAAC;IAED,yCAAyC;IACzC,IAAI,MAAM,GAAiB,EAAE,CAAC;IAC9B,oGAAoG;IACpG,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC;YAC5B,IAAI,EAAE,SAAS;YACf,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,CAAC,aAAa,CAAC;SACzB,CAAC,CAAC;QACH,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC;IAC9B,CAAC;IAED,uCAAuC;IACvC,MAAM,YAAY,GAAiB,EAAE,CAAC;IAEtC,OAAO;QACL,OAAO;QACP,MAAM;QACN,YAAY;KACb,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"user-context-scanner.js","sourceRoot":"","sources":["../../src/utils/user-context-scanner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,IAAI,EAAmB,MAAM,+BAA+B,CAAC;AAItE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IAYnC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,kBAAkB,EAAE,CAAC;IACvD,MAAM,UAAU,GAAuB,EAAE,CAAC;IAE1C,mEAAmE;IACnE,IAAI,OAAO,GAAiB,EAAE,CAAC;IAC/B,oGAAoG;IACpG,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC;YAC7B,IAAI,EAAE,UAAU;YAChB,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,CAAC,aAAa,EAAE,sBAAsB,CAAC;SACjD,CAAC,CAAC;QACH,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;QAC9B,UAAU,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;IAC7C,CAAC;IAED,yCAAyC;IACzC,IAAI,MAAM,GAAiB,EAAE,CAAC;IAC9B,oGAAoG;IACpG,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC;YAC5B,IAAI,EAAE,SAAS;YACf,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,CAAC,aAAa,CAAC;SACzB,CAAC,CAAC;QACH,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC;QAC5B,UAAU,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IAC5C,CAAC;IAED,uCAAuC;IACvC,MAAM,YAAY,GAAiB,EAAE,CAAC;IAEtC,OAAO;QACL,OAAO;QACP,MAAM;QACN,YAAY;QACZ,UAAU;KACX,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"validate-help-files.d.ts","sourceRoot":"","sources":["../../src/utils/validate-help-files.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA0CH;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAkDxC"}
1
+ {"version":3,"file":"validate-help-files.d.ts","sourceRoot":"","sources":["../../src/utils/validate-help-files.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA2CH;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAkDxC"}
@@ -7,8 +7,9 @@
7
7
  */
8
8
  import { existsSync, readdirSync } from 'node:fs';
9
9
  import { dirname } from 'node:path';
10
- import { fileURLToPath, pathToFileURL } from 'node:url';
10
+ import { fileURLToPath } from 'node:url';
11
11
  import { safePath } from '@vibe-agent-toolkit/utils';
12
+ import { isEntrypoint } from '@vibe-agent-toolkit/utils/process';
12
13
  /**
13
14
  * Files `loadVerboseHelp()` is actually asked for by a command.
14
15
  *
@@ -89,8 +90,14 @@ export function validateHelpFiles() {
89
90
  /**
90
91
  * Run validation if this file is executed directly
91
92
  * (via tsx or node during build process)
93
+ *
94
+ * ⛔ NOT `import.meta.url === pathToFileURL(process.argv[1]).href`, which is what
95
+ * this used to be. That compare has no realpath pass, so it is false whenever
96
+ * the build reaches this script through a symlink — and a build-time validator
97
+ * whose guard is false does not fail the build, it exits 0 having validated
98
+ * nothing, which is the exact opposite of the "fail fast" this file exists for.
92
99
  */
93
- if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
100
+ if (isEntrypoint(import.meta.url)) {
94
101
  try {
95
102
  validateHelpFiles();
96
103
  console.log('✓ All required help documentation files exist');
@@ -1 +1 @@
1
- {"version":3,"file":"validate-help-files.js","sourceRoot":"","sources":["../../src/utils/validate-help-files.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validate-help-files.js","sourceRoot":"","sources":["../../src/utils/validate-help-files.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAEjE;;;;;;;GAOG;AACH,MAAM,mBAAmB,GAAG;IAC1B,UAAU,EAAO,iDAAiD;IAClE,cAAc,EAAG,kEAAkE;IACnF,QAAQ,EAAS,sDAAsD;IACvE,UAAU,EAAO,0DAA0D;CACnE,CAAC;AAEX;;;;;;;;;;GAUG;AACH,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC;IACpC,UAAU;IACV,WAAW;IACX,QAAQ;IACR,WAAW;IACX,eAAe;CAChB,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAEnD,MAAM,YAAY,GAAa,EAAE,CAAC;IAElC,KAAK,MAAM,QAAQ,IAAI,mBAAmB,EAAE,CAAC;QAC3C,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAClD,qHAAqH;QACrH,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnE,MAAM,IAAI,KAAK,CACb,+CAA+C,QAAQ,MAAM;YAC7D,uEAAuE;YACvE,8CAA8C,CAC/C,CAAC;IACJ,CAAC;IAED,gEAAgE;IAChE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAS,mBAAmB,CAAC,CAAC;IACtD,yHAAyH;IACzH,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IACpE,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAE5F,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnE,MAAM,IAAI,KAAK,CACb,2CAA2C,QAAQ,MAAM;YACzD,yEAAyE;YACzE,sEAAsE;YACtE,2EAA2E;YAC3E,8EAA8E;YAC9E,uEAAuE,CACxE,CAAC;IACJ,CAAC;IAED,MAAM,iBAAiB,GAAG,CAAC,GAAG,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACvF,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,2DAA2D;YAC3D,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YACtD,+BAA+B,CAChC,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,IAAI,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IAClC,IAAI,CAAC;QACH,iBAAiB,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;QAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QAChD,OAAO,CAAC,KAAK,CAAE,KAAe,CAAC,OAAO,CAAC,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
package/docs/audit.md CHANGED
@@ -29,6 +29,8 @@ vat audit [git-url-or-path] [options]
29
29
 
30
30
  - `--user` - Audit user-level Claude plugins installation (`~/.claude/plugins`)
31
31
  - `-r, --recursive` - Scan directories recursively for all resource types
32
+ - `--compat` - Run compatibility analysis for each plugin; adds a `compatibility:` block to its entry (see [Compatibility and settings blocks](#compatibility-and-settings-blocks))
33
+ - `--settings [file]` - Check each plugin against Claude settings (auto-discovered, or the given file); adds a `settings:` block. Requires `--compat`
32
34
  - `--debug` - Enable debug logging (outputs to stderr)
33
35
 
34
36
  ### Gitignore-aware scanning
@@ -205,25 +207,68 @@ hierarchical:
205
207
  message: Skill exceeds recommended length
206
208
  ```
207
209
 
210
+ ## Two verdicts: `status` and the exit code
211
+
212
+ `vat audit` publishes two verdicts, and they answer different questions.
213
+
214
+ | Verdict | Answers | Where to read it |
215
+ |---|---|---|
216
+ | `status` in the YAML report | **What was found** — the worst actionable severity across the findings | stdout |
217
+ | The process exit code | **Whether the run completed** | `$?` |
218
+
219
+ So a tree with errors produces `status: error` beside **exit 0**, and both are
220
+ correct. That pair surprises people because `status` means something wider
221
+ everywhere else in this CLI, where it moves with the exit code. Here it does not,
222
+ because this command is a report rather than a gate.
223
+
224
+ A run that audited **zero files** is refused, not passed. An existing directory
225
+ with nothing auditable in it — plugins that moved, a wrong subdirectory, an
226
+ excluded tree, files no lane recognises — used to publish `status: success`
227
+ beside `filesScanned: 0`, which is the same document a clean tree produces. It
228
+ now publishes `status: error` with one non-overridable `RESOURCE_CHECK_BROKEN`
229
+ finding under a top-level `issues:` key (the claim is about the run, so it is
230
+ not a `files[]` row and does not count toward `filesScanned`). The exit code is
231
+ still `0`: the run completed; it just is not a verdict.
232
+
233
+ **Gate CI on the report, never on this command's exit code** — read `status` and
234
+ `issueCounts` out of the YAML (see [CI/CD Integration](#cicd-integration) for a
235
+ worked example), or reach for a command whose exit code *is* the verdict:
236
+ `vat skills validate` and `vat skills build` exit `1` on validation errors, and
237
+ `vat skills validate` also exits `1` when its `skills.include` globs discover no
238
+ skill — so a typo'd glob fails the gate there instead of passing it.
239
+
208
240
  ## Exit Codes
209
241
 
210
242
  `vat audit` is **advisory by design** — it reports every issue it detects but does not block on validation severity. Use `vat skills validate` or `vat skills build` for gated checks (those commands exit `1` on validation errors).
211
243
 
212
- - **0** - Always, when the audit completes. The report may still contain errors and warnings; check `status` and `summary` in the YAML output to decide whether action is needed.
213
- - **2** - System error: Config invalid, path not found, permission denied, etc. The audit could not run.
244
+ - **0** - Always, when the audit completes — including when the report says `status: error`. The findings are in the report; check `status` and `summary` in the YAML output to decide whether action is needed. That includes the environment refusing part of the subject: a path that does not exist or is not a recognisable resource is reported as `UNKNOWN_FORMAT` (error), and a directory or file the scan could not read — permission denied, a vanished mount — as `SCAN_PATH_UNREADABLE` (warning), with every readable sibling still validated. A governing `vibe-agent-toolkit.config.yaml` that cannot be loaded, or whose `skills.include` reaches a directory the crawl cannot list, is warned about once on stderr and filed as `SCAN_PATH_UNREADABLE` on the config file or the directory; the skills it governs are validated config-free rather than dropped. Degrading beats destroying, and the report says where it degraded.
245
+ - **2** - The audit could not run at all, so there is no report to read: `--user` with no Claude config directory installed, a git URL that could not be cloned, or an internal failure (a validator defect). Invalid config, missing paths and permission problems are **not** exit 2 — they are findings, above.
214
246
 
215
247
  ## Validation Configuration
216
248
 
217
- Audit honors `validation.severity` from `vibe-agent-toolkit.config.yaml` for **display grouping only** — setting a code to `ignore` hides it from output, raising to `error` promotes it in the report's error count. Audit does **not** apply `validation.allow` (per-path allow entries); for that, use `vat skills validate` or `vat skills build`.
249
+ Audit honors `validation.severity` from `vibe-agent-toolkit.config.yaml`: setting a code to `ignore` hides it from the report, and every other level is applied as written — a code raised to `error` is reported as an error, a code lowered to `warning` as a warning. It changes **which findings are reported and at what severity**, never whether the command fails (see [Two verdicts](#two-verdicts-status-and-the-exit-code)). Audit does **not** apply `validation.allow` (per-path allow entries); for that, use `vat skills validate` or `vat skills build`.
250
+
251
+ Three scopes are read, least specific first — a more specific one naming the same code wins:
218
252
 
219
253
  ```yaml
220
254
  # In vibe-agent-toolkit.config.yaml
255
+ resources:
256
+ validation:
257
+ severity:
258
+ LINK_MISSING_TARGET: ignore # project-wide; the same dial
259
+ # `vat resources validate` reads
221
260
  skills:
222
261
  defaults:
223
262
  validation:
224
263
  severity:
225
- LINK_TO_NAVIGATION_FILE: ignore # hidden from audit output
226
- LINK_DROPPED_BY_DEPTH: error # elevated in the report
264
+ LINK_TO_NAVIGATION_FILE: ignore # project-wide: skills, plugins and
265
+ # marketplaces alike
266
+ LINK_DROPPED_BY_DEPTH: error # elevated in the report
267
+ config:
268
+ my-skill:
269
+ validation:
270
+ severity:
271
+ LINK_DROPPED_BY_DEPTH: info # just this skill
227
272
  ```
228
273
 
229
274
  See `docs/validation-codes.md` for the full code reference.
@@ -321,9 +366,13 @@ summary:
321
366
  filesWithWarnings: number # Files whose worst actionable severity is warning
322
367
  filesWithErrors: number # Files carrying at least one error
323
368
  issueCounts: # FINDINGS, not files — same field name and meaning
324
- errors: number # as the `issueCounts` on each entry below
325
- warnings: number
369
+ errors: number # as the `issueCounts` on each entry below,
370
+ warnings: number # plus the run-level `issues` when present
326
371
  info: number
372
+ issues: # Only when the RUN itself is refused — a run over
373
+ - code: RESOURCE_CHECK_BROKEN # zero files. Not a file, so not in `files[]`.
374
+ severity: error
375
+ message: ...
327
376
  duration: "123ms"
328
377
  files:
329
378
  - path: plugins/my-plugin # relative to `root`
@@ -357,6 +406,70 @@ say in how a path is spelled.
357
406
  lives in a random tempdir that nothing downstream can resolve, so the provenance
358
407
  header states the base instead and paths are relative to the cloned repo.
359
408
 
409
+ #### Compatibility and settings blocks
410
+
411
+ Under `--compat`, every `claude-plugin` entry carries a `compatibility:` block;
412
+ under `--compat --settings`, a `settings:` block beside it. **Both blocks are
413
+ always present for every plugin the run was asked about** — a lane that could
414
+ not run says so in its block rather than leaving it out, because a plugin the
415
+ check could not answer for must never look like one the operator never asked
416
+ about.
417
+
418
+ ```yaml
419
+ files:
420
+ - path: plugins/my-plugin
421
+ type: claude-plugin
422
+ compatibility: # the analyzer's verdicts…
423
+ plugin: my-plugin
424
+ declaredTargets: [claude-code]
425
+ observations: [...]
426
+ verdicts: [...]
427
+ unchecked: [] # files the analysis could not read; verdicts were computed without them
428
+ settings:
429
+ compatible: false # true ONLY when conflicts and unchecked are both empty
430
+ conflicts:
431
+ - type: tool-blocked
432
+ detail: Tool "Bash" in skills/deploy/SKILL.md blocked by org policy (permissions.deny)
433
+ blockedBy: permissions.deny
434
+ value: Bash
435
+ settingsFile: /etc/claude-code/managed-settings.json
436
+ settingsLevel: managed
437
+ unchecked: # present only when non-empty
438
+ - path: skills/locked/SKILL.md # relative to `root`
439
+ reason: "EACCES: permission denied, open 'skills/locked/SKILL.md'"
440
+ - path: plugins/other-plugin
441
+ type: claude-plugin
442
+ compatibility: # …or the reason there are none
443
+ analyzed: false
444
+ reason: "EACCES: permission denied, scandir 'plugins/other-plugin/skills/locked'"
445
+ settings:
446
+ compatible: false
447
+ conflicts: []
448
+ unchecked:
449
+ - path: plugins/other-plugin/skills/locked
450
+ reason: "EACCES: permission denied, scandir 'plugins/other-plugin/skills/locked'"
451
+ ```
452
+
453
+ `settings.unchecked` lists every path the settings check enumerated but could
454
+ not compare: a `SKILL.md` it could not read or whose frontmatter is not a YAML
455
+ mapping (the same file the validator reports as `SKILL_MISSING_FRONTMATTER`), or
456
+ a directory it could not list — in which case any skill beneath it is unseen
457
+ and unnamed. The check follows symlinks the way the validator lane does, so a
458
+ plugin whose `skills/` points at a shared tree is checked, not skipped.
459
+ `compatible` is `false` whenever anything is listed here: zero conflicts over a
460
+ skill that was never read is not compatibility. The two compat lanes are
461
+ independent — a plugin-wide analyzer failure (no valid `plugin.json`, or a root
462
+ that cannot be listed) does not stop the settings check. A single file the
463
+ analyzer cannot read, list or parse is listed under `compatibility.unchecked`
464
+ (root-relative, with the OS or parser reason) and every other file is still
465
+ analyzed; the verdicts are computed WITHOUT the unchecked files, so an empty
466
+ `verdicts` beside a non-empty `unchecked` is a verdict over fewer files than
467
+ the plugin ships.
468
+
469
+ Both outcomes are also said on stderr without `--debug`: a
470
+ `Compatibility analysis could not run for <plugin>: <reason>` line, and totals
471
+ for conflicts found and paths the settings check could not compare.
472
+
360
473
  ### Standard Error (stderr)
361
474
 
362
475
  Human-readable error messages and logs. Paths are root-relative here too: