@vibe-agent-toolkit/cli 0.2.0-rc.6 → 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 (194) 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 +605 -140
  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/context.js +1 -1
  29. package/dist/commands/claude/context.js.map +1 -1
  30. package/dist/commands/claude/marketplace/validate.d.ts +55 -22
  31. package/dist/commands/claude/marketplace/validate.d.ts.map +1 -1
  32. package/dist/commands/claude/marketplace/validate.js +380 -75
  33. package/dist/commands/claude/marketplace/validate.js.map +1 -1
  34. package/dist/commands/claude/org/skills.d.ts +84 -3
  35. package/dist/commands/claude/org/skills.d.ts.map +1 -1
  36. package/dist/commands/claude/org/skills.js +218 -46
  37. package/dist/commands/claude/org/skills.js.map +1 -1
  38. package/dist/commands/claude/plugin/build.d.ts +8 -0
  39. package/dist/commands/claude/plugin/build.d.ts.map +1 -1
  40. package/dist/commands/claude/plugin/build.js +16 -2
  41. package/dist/commands/claude/plugin/build.js.map +1 -1
  42. package/dist/commands/claude/plugin/tree-copy.d.ts +72 -0
  43. package/dist/commands/claude/plugin/tree-copy.d.ts.map +1 -1
  44. package/dist/commands/claude/plugin/tree-copy.js +215 -10
  45. package/dist/commands/claude/plugin/tree-copy.js.map +1 -1
  46. package/dist/commands/corpus/index.d.ts.map +1 -1
  47. package/dist/commands/corpus/index.js +3 -0
  48. package/dist/commands/corpus/index.js.map +1 -1
  49. package/dist/commands/corpus/report.d.ts +0 -1
  50. package/dist/commands/corpus/report.d.ts.map +1 -1
  51. package/dist/commands/corpus/report.js +0 -1
  52. package/dist/commands/corpus/report.js.map +1 -1
  53. package/dist/commands/corpus/runner.d.ts +58 -1
  54. package/dist/commands/corpus/runner.d.ts.map +1 -1
  55. package/dist/commands/corpus/runner.js +90 -15
  56. package/dist/commands/corpus/runner.js.map +1 -1
  57. package/dist/commands/corpus/scan.d.ts.map +1 -1
  58. package/dist/commands/corpus/scan.js +0 -1
  59. package/dist/commands/corpus/scan.js.map +1 -1
  60. package/dist/commands/doctor.d.ts +14 -0
  61. package/dist/commands/doctor.d.ts.map +1 -1
  62. package/dist/commands/doctor.js +96 -18
  63. package/dist/commands/doctor.js.map +1 -1
  64. package/dist/commands/okf/index.d.ts +11 -0
  65. package/dist/commands/okf/index.d.ts.map +1 -0
  66. package/dist/commands/okf/index.js +102 -0
  67. package/dist/commands/okf/index.js.map +1 -0
  68. package/dist/commands/okf/validate.d.ts +82 -0
  69. package/dist/commands/okf/validate.d.ts.map +1 -0
  70. package/dist/commands/okf/validate.js +157 -0
  71. package/dist/commands/okf/validate.js.map +1 -0
  72. package/dist/commands/phase-utils.d.ts +19 -3
  73. package/dist/commands/phase-utils.d.ts.map +1 -1
  74. package/dist/commands/phase-utils.js +26 -5
  75. package/dist/commands/phase-utils.js.map +1 -1
  76. package/dist/commands/rag/index-command.d.ts +27 -2
  77. package/dist/commands/rag/index-command.d.ts.map +1 -1
  78. package/dist/commands/rag/index-command.js +44 -7
  79. package/dist/commands/rag/index-command.js.map +1 -1
  80. package/dist/commands/rag/index.d.ts.map +1 -1
  81. package/dist/commands/rag/index.js +2 -0
  82. package/dist/commands/rag/index.js.map +1 -1
  83. package/dist/commands/resources/check-progress.d.ts +3 -0
  84. package/dist/commands/resources/check-progress.d.ts.map +1 -1
  85. package/dist/commands/resources/check-progress.js +6 -0
  86. package/dist/commands/resources/check-progress.js.map +1 -1
  87. package/dist/commands/resources/check.d.ts +33 -4
  88. package/dist/commands/resources/check.d.ts.map +1 -1
  89. package/dist/commands/resources/check.js +131 -44
  90. package/dist/commands/resources/check.js.map +1 -1
  91. package/dist/commands/resources/index.d.ts.map +1 -1
  92. package/dist/commands/resources/index.js +41 -9
  93. package/dist/commands/resources/index.js.map +1 -1
  94. package/dist/commands/resources/query.d.ts +18 -1
  95. package/dist/commands/resources/query.d.ts.map +1 -1
  96. package/dist/commands/resources/query.js +29 -4
  97. package/dist/commands/resources/query.js.map +1 -1
  98. package/dist/commands/resources/validate.d.ts +29 -0
  99. package/dist/commands/resources/validate.d.ts.map +1 -1
  100. package/dist/commands/resources/validate.js +116 -13
  101. package/dist/commands/resources/validate.js.map +1 -1
  102. package/dist/commands/skill/review.d.ts.map +1 -1
  103. package/dist/commands/skill/review.js +9 -2
  104. package/dist/commands/skill/review.js.map +1 -1
  105. package/dist/commands/skill/test/run.d.ts.map +1 -1
  106. package/dist/commands/skill/test/run.js +21 -6
  107. package/dist/commands/skill/test/run.js.map +1 -1
  108. package/dist/commands/skills/build.d.ts.map +1 -1
  109. package/dist/commands/skills/build.js +16 -3
  110. package/dist/commands/skills/build.js.map +1 -1
  111. package/dist/commands/skills/list.d.ts +2 -1
  112. package/dist/commands/skills/list.d.ts.map +1 -1
  113. package/dist/commands/skills/list.js +31 -9
  114. package/dist/commands/skills/list.js.map +1 -1
  115. package/dist/commands/skills/skill-discovery.d.ts +40 -1
  116. package/dist/commands/skills/skill-discovery.d.ts.map +1 -1
  117. package/dist/commands/skills/skill-discovery.js +32 -3
  118. package/dist/commands/skills/skill-discovery.js.map +1 -1
  119. package/dist/commands/skills/validate-command.d.ts.map +1 -1
  120. package/dist/commands/skills/validate-command.js +11 -3
  121. package/dist/commands/skills/validate-command.js.map +1 -1
  122. package/dist/commands/skills/validate.d.ts +66 -7
  123. package/dist/commands/skills/validate.d.ts.map +1 -1
  124. package/dist/commands/skills/validate.js +133 -29
  125. package/dist/commands/skills/validate.js.map +1 -1
  126. package/dist/commands/verify.d.ts +94 -3
  127. package/dist/commands/verify.d.ts.map +1 -1
  128. package/dist/commands/verify.js +192 -45
  129. package/dist/commands/verify.js.map +1 -1
  130. package/dist/skill-resolution/packaging-config.d.ts +49 -5
  131. package/dist/skill-resolution/packaging-config.d.ts.map +1 -1
  132. package/dist/skill-resolution/packaging-config.js +59 -19
  133. package/dist/skill-resolution/packaging-config.js.map +1 -1
  134. package/dist/skill-resolution/resolve-skill-reference.d.ts.map +1 -1
  135. package/dist/skill-resolution/resolve-skill-reference.js +6 -3
  136. package/dist/skill-resolution/resolve-skill-reference.js.map +1 -1
  137. package/dist/utils/command-error.d.ts +31 -0
  138. package/dist/utils/command-error.d.ts.map +1 -1
  139. package/dist/utils/command-error.js +45 -0
  140. package/dist/utils/command-error.js.map +1 -1
  141. package/dist/utils/edge-lens-evaluation.d.ts +83 -0
  142. package/dist/utils/edge-lens-evaluation.d.ts.map +1 -0
  143. package/dist/utils/edge-lens-evaluation.js +110 -0
  144. package/dist/utils/edge-lens-evaluation.js.map +1 -0
  145. package/dist/utils/optional-backend.d.ts +5 -4
  146. package/dist/utils/optional-backend.d.ts.map +1 -1
  147. package/dist/utils/optional-backend.js +5 -4
  148. package/dist/utils/optional-backend.js.map +1 -1
  149. package/dist/utils/project-root-policy.d.ts +20 -0
  150. package/dist/utils/project-root-policy.d.ts.map +1 -1
  151. package/dist/utils/project-root-policy.js +32 -0
  152. package/dist/utils/project-root-policy.js.map +1 -1
  153. package/dist/utils/projection-query.d.ts +41 -4
  154. package/dist/utils/projection-query.d.ts.map +1 -1
  155. package/dist/utils/projection-query.js +44 -10
  156. package/dist/utils/projection-query.js.map +1 -1
  157. package/dist/utils/projection-store.d.ts +41 -15
  158. package/dist/utils/projection-store.d.ts.map +1 -1
  159. package/dist/utils/projection-store.js +65 -18
  160. package/dist/utils/projection-store.js.map +1 -1
  161. package/dist/utils/repeatable-option.d.ts +37 -0
  162. package/dist/utils/repeatable-option.d.ts.map +1 -0
  163. package/dist/utils/repeatable-option.js +39 -0
  164. package/dist/utils/repeatable-option.js.map +1 -0
  165. package/dist/utils/resource-loader.d.ts +4 -3
  166. package/dist/utils/resource-loader.d.ts.map +1 -1
  167. package/dist/utils/resource-loader.js +61 -30
  168. package/dist/utils/resource-loader.js.map +1 -1
  169. package/dist/utils/root-argv.d.ts +53 -0
  170. package/dist/utils/root-argv.d.ts.map +1 -0
  171. package/dist/utils/root-argv.js +215 -0
  172. package/dist/utils/root-argv.js.map +1 -0
  173. package/dist/utils/run-integrity.d.ts +95 -0
  174. package/dist/utils/run-integrity.d.ts.map +1 -0
  175. package/dist/utils/run-integrity.js +102 -0
  176. package/dist/utils/run-integrity.js.map +1 -0
  177. package/dist/utils/sqlite-experimental-warning.d.ts +69 -0
  178. package/dist/utils/sqlite-experimental-warning.d.ts.map +1 -0
  179. package/dist/utils/sqlite-experimental-warning.js +144 -0
  180. package/dist/utils/sqlite-experimental-warning.js.map +1 -0
  181. package/dist/utils/user-context-scanner.d.ts +8 -0
  182. package/dist/utils/user-context-scanner.d.ts.map +1 -1
  183. package/dist/utils/user-context-scanner.js +4 -0
  184. package/dist/utils/user-context-scanner.js.map +1 -1
  185. package/dist/utils/validate-help-files.d.ts.map +1 -1
  186. package/dist/utils/validate-help-files.js +9 -2
  187. package/dist/utils/validate-help-files.js.map +1 -1
  188. package/docs/audit.md +120 -7
  189. package/docs/doctor.md +6 -6
  190. package/docs/index.md +1 -1
  191. package/docs/rag.md +3 -1
  192. package/docs/resources.md +5 -1
  193. package/docs/skills.md +47 -62
  194. package/package.json +18 -18
@@ -9,16 +9,64 @@
9
9
  * - anything the caller names in `exclude` (glob, or a bare/trailing-slash
10
10
  * directory name; a pattern matching nothing is returned to the caller)
11
11
  *
12
+ * Symlinks are judged before anything is copied, identically on both crawl
13
+ * routes: a FILE symlink whose target this copy ships is copied by content and
14
+ * reported; one that leaves the source, does not resolve, names a directory,
15
+ * or names a file the copy leaves out stops the copy by name
16
+ * ({@link PluginSymlinkRefusedError}) before the first byte lands.
17
+ *
12
18
  * Respects .gitignore via crawlDirectory (respectGitignore: true, the default).
13
19
  * Returns counts keyed to the spec's YAML summary extension.
14
20
  */
15
21
  import { existsSync } from 'node:fs';
16
- import { copyFile, mkdir } from 'node:fs/promises';
22
+ import { copyFile, lstat, mkdir, readdir, realpath, stat } from 'node:fs/promises';
17
23
  import { dirname } from 'node:path';
18
24
  import { AGENT_INSTRUCTION_FILE_PATTERNS, toAnyDepthGlobs } from '@vibe-agent-toolkit/agent-skills';
19
25
  import { isGlob, safePath, toForwardSlash } from '@vibe-agent-toolkit/utils';
20
- import { crawlDirectory } from '@vibe-agent-toolkit/utils/crawl';
26
+ import { crawlDirectory, crawlPathFilter } from '@vibe-agent-toolkit/utils/crawl';
27
+ import { gitFindRoot } from '@vibe-agent-toolkit/utils/git';
21
28
  import picomatch from 'picomatch';
29
+ function describeRefusal(entry) {
30
+ switch (entry.reason) {
31
+ case 'escapes-source':
32
+ return 'points outside the plugin source, so the bundle would carry a file from elsewhere on the build host';
33
+ case 'unresolvable':
34
+ return 'does not resolve to anything (dangling, or a loop)';
35
+ case 'directory':
36
+ return 'is a directory symlink; a bundle is a plain tree and cannot carry a directory alias';
37
+ case 'target-excluded':
38
+ return `resolves to '${entry.target}', which this copy leaves out (excluded, gitignored, untracked, or`
39
+ + ' packaged by another phase), so the bundle would carry the excluded bytes under the link\'s name';
40
+ }
41
+ }
42
+ /**
43
+ * The copy stopped because the plugin source holds symlinks that cannot ship.
44
+ *
45
+ * The sibling of the listing refusal (`DirectoryListingRefusedError` from the
46
+ * crawl): thrown BEFORE the first byte is copied, with every offender named,
47
+ * so a failing build leaves no half-written bundle and the operator fixes the
48
+ * whole list in one pass. Measured before this existed: on the git route a
49
+ * directory or dangling symlink threw a raw `ENOTSUP` / `ENOENT` out of
50
+ * `copyFile` after earlier files had already landed, and a file symlink out of
51
+ * the source was copied by content with no diagnostic at all; on the walk route
52
+ * every symlink was silently dropped.
53
+ *
54
+ * The message speaks the bundle's coordinates (root-relative paths), never the
55
+ * build host's absolute paths, and names the remedy — the `exclude:` knob — in
56
+ * the same terms the listing refusal does.
57
+ */
58
+ export class PluginSymlinkRefusedError extends Error {
59
+ refused;
60
+ constructor(refused) {
61
+ const lines = refused.map((entry) => ` - '${entry.path}' ${describeRefusal(entry)}`);
62
+ super(`Refusing to copy the plugin source: ${refused.length} symbolic link(s) cannot be shipped in a bundle,`
63
+ + ` so nothing was copied.\n${lines.join('\n')}\n`
64
+ + 'Replace each link with the file it points at, or name it in the plugin\'s `exclude:` list to leave'
65
+ + ' it out of the bundle deliberately.');
66
+ this.name = 'PluginSymlinkRefusedError';
67
+ this.refused = refused;
68
+ }
69
+ }
22
70
  /**
23
71
  * Built-in exclusions for the verbatim plugin copy.
24
72
  *
@@ -104,6 +152,126 @@ function classifyRelative(rel) {
104
152
  return 'mcpCopied';
105
153
  return undefined;
106
154
  }
155
+ /**
156
+ * Split the crawl's paths into regular files and symlinks by `lstat`, on BOTH
157
+ * routes — this is the one predicate the two crawl lanes share. The walker
158
+ * never yields a symlink (see {@link sweepSymlinks}), so there it finds none;
159
+ * `git ls-files` yields every tracked symlink as an ordinary path, so there it
160
+ * is what stops `copyFile` from being the first thing to notice.
161
+ */
162
+ async function partitionByLstat(sourceDir, files) {
163
+ const regular = [];
164
+ const links = [];
165
+ for (const abs of files) {
166
+ const entry = { abs, rel: toForwardSlash(safePath.relative(sourceDir, abs)) };
167
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- path returned by the crawl of sourceDir
168
+ const info = await lstat(abs);
169
+ (info.isSymbolicLink() ? links : regular).push(entry);
170
+ }
171
+ return { regular, links };
172
+ }
173
+ /**
174
+ * Every symlink under `sourceDir` that the exclude list admits — the half of the
175
+ * population the walk route cannot see.
176
+ *
177
+ * `crawlDirectory`'s walker skips every symlink entry unless `followSymlinks`
178
+ * is set, and following would not do either: a directory link would be
179
+ * traversed (its contents yielded under the link's name) and a dangling one
180
+ * silently skipped as absence. Neither is "here is a symlink, decide". So on
181
+ * the walk route this pass lists them itself, with the SAME membership filter
182
+ * the crawl applied, and hands each one to the same judgement the git route's
183
+ * tracked symlinks get. A directory that will not list is not swallowed here:
184
+ * the crawl has already refused it by name before this runs.
185
+ *
186
+ * Only the walk route needs it. Inside a repository `git ls-files` already
187
+ * yields the tracked symlinks, and a sweep there would also find IGNORED ones
188
+ * (`node_modules/.bin/*` is nothing but symlinks) and refuse a bundle for links
189
+ * the crawl had correctly left out. The route is read the way the crawl reads
190
+ * it — is there a repository above `sourceDir` — with one gap: a repository
191
+ * whose `git ls-files` fails makes the crawl fall back to the walker, and that
192
+ * run gets no sweep. A repository with no working `git` already hard-fails the
193
+ * default scan elsewhere, so the gap is not widened here.
194
+ */
195
+ async function sweepSymlinks(sourceDir, isMember) {
196
+ const found = [];
197
+ const walk = async (dir) => {
198
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- walking beneath the validated sourceDir
199
+ const entries = await readdir(dir, { withFileTypes: true });
200
+ for (const entry of entries) {
201
+ const abs = safePath.join(dir, entry.name);
202
+ const rel = toForwardSlash(safePath.relative(sourceDir, abs));
203
+ if (!isMember(rel))
204
+ continue;
205
+ if (entry.isSymbolicLink()) {
206
+ found.push({ abs, rel });
207
+ }
208
+ else if (entry.isDirectory()) {
209
+ await walk(abs);
210
+ }
211
+ }
212
+ };
213
+ await walk(sourceDir);
214
+ return found;
215
+ }
216
+ /** Is `real` the source root itself, or beneath it? Both sides canonical. */
217
+ function isUnderSource(real, realSource) {
218
+ return real === realSource || real.startsWith(`${realSource}/`);
219
+ }
220
+ /**
221
+ * Judge one symlink: the one shape that ships (`'file'`, in-tree, copied by
222
+ * content) or the refusal that stops the copy.
223
+ *
224
+ * `shipped` is the set of root-relative REGULAR files this copy will land —
225
+ * after the crawl's membership (built-in exclusions, gitignore, tracking) and
226
+ * the caller's `exclude:`. A link ships only when its target is in that set:
227
+ * "in-tree" alone is not enough, because the tree is not the bundle. Every
228
+ * way a file can be left out — a caller pattern, `.claude-plugin/**`, a skill
229
+ * dir another phase produces, a gitignored or untracked path on the git route
230
+ * — is a way a one-line alias would put its bytes back, under a different
231
+ * name, with nothing to say so. Asking "would the target ship on its own?"
232
+ * closes all of them with the copy's own answer rather than re-deriving each
233
+ * exclusion here.
234
+ */
235
+ async function classifySymlink(link, realSource, shipped) {
236
+ let real;
237
+ try {
238
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- a symlink the crawl of sourceDir returned
239
+ real = toForwardSlash(await realpath(link.abs));
240
+ }
241
+ catch {
242
+ return { path: link.rel, reason: 'unresolvable' };
243
+ }
244
+ if (!isUnderSource(real, realSource))
245
+ return { path: link.rel, reason: 'escapes-source' };
246
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- canonical path proven to sit under sourceDir
247
+ if ((await stat(real)).isDirectory())
248
+ return { path: link.rel, reason: 'directory' };
249
+ const target = toForwardSlash(safePath.relative(realSource, real));
250
+ return shipped.has(target) ? 'file' : { path: link.rel, reason: 'target-excluded', target };
251
+ }
252
+ /**
253
+ * Judge every symlink and split them: the ones that ship, and the ones that
254
+ * stop the copy. Sorted by path so the refusal reads the same on every
255
+ * filesystem — `readdir` order is not stable across platforms.
256
+ */
257
+ async function judgeSymlinks(sourceDir, links, shipped) {
258
+ const copyable = [];
259
+ const refused = [];
260
+ if (links.length === 0)
261
+ return { copyable, refused };
262
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- sourceDir resolved from config
263
+ const realSource = toForwardSlash(await realpath(sourceDir));
264
+ for (const link of [...links].toSorted((a, b) => a.rel.localeCompare(b.rel))) {
265
+ const verdict = await classifySymlink(link, realSource, shipped);
266
+ if (verdict === 'file') {
267
+ copyable.push(link);
268
+ }
269
+ else {
270
+ refused.push(verdict);
271
+ }
272
+ }
273
+ return { copyable, refused };
274
+ }
107
275
  export async function treeCopyPlugin(options) {
108
276
  const { sourceDir, destDir, excludeSkillDirs = [], exclude: callerExclude = [], warn } = options;
109
277
  const result = {
@@ -113,6 +281,7 @@ export async function treeCopyPlugin(options) {
113
281
  mcpCopied: 0,
114
282
  filesCopied: 0,
115
283
  unusedExcludePatterns: [],
284
+ symlinksCopied: [],
116
285
  };
117
286
  // eslint-disable-next-line security/detect-non-literal-fs-filename -- sourceDir resolved from config
118
287
  if (!existsSync(sourceDir)) {
@@ -128,6 +297,14 @@ export async function treeCopyPlugin(options) {
128
297
  ...EXCLUDE_PATTERNS,
129
298
  ...excludeSkillDirs.flatMap((name) => expandExcludePattern(`skills/${name}`)),
130
299
  ];
300
+ // A directory the crawl cannot LIST stops the copy, by name. The alternative —
301
+ // enumerate around it and copy what was seen — ships a plugin missing every
302
+ // file beneath that directory while the build reports success, which is the
303
+ // silent-drop shape this whole function is built to refuse (see the
304
+ // zero-match report below). Refusing here also runs BEFORE the first copy,
305
+ // so a build that fails leaves no half-written bundle to be mistaken for one.
306
+ // Only the walk route lists directories; inside a repository `git ls-files`
307
+ // answers and a refusal surfaces on the file copy instead.
131
308
  const files = await crawlDirectory({
132
309
  baseDir: sourceDir,
133
310
  include: ['**/*'],
@@ -135,27 +312,55 @@ export async function treeCopyPlugin(options) {
135
312
  absolute: true,
136
313
  filesOnly: true,
137
314
  respectGitignore: true,
315
+ unreadable: {
316
+ refuse: {
317
+ root: sourceDir,
318
+ remedy: 'Fix the permissions on that directory, or name it in the plugin\'s `exclude:` list to leave it out of the bundle deliberately.',
319
+ },
320
+ },
138
321
  });
139
322
  // Caller `exclude:` patterns are applied HERE rather than handed to the crawl,
140
323
  // for two reasons: the two crawl lanes disagree about directory-shaped patterns
141
324
  // (see expandExcludePattern), and a pattern that matches nothing must be
142
325
  // reportable — a file the crawl never returns is a drop nothing can observe.
143
326
  const excludeMatchers = buildExcludeMatchers(callerExclude);
144
- for (const absPath of files) {
145
- const rel = toForwardSlash(safePath.relative(sourceDir, absPath));
146
- if (isExcludedByCaller(rel, excludeMatchers)) {
147
- continue;
148
- }
149
- const target = safePath.join(destDir, rel);
327
+ const notExcludedByCaller = (entry) => !isExcludedByCaller(entry.rel, excludeMatchers);
328
+ // Symlinks are decided BEFORE the first copy, on both routes, and by one
329
+ // judgement (see classifySymlink). The two lanes used to disagree twice over:
330
+ // the walker dropped every symlink silently, while `git ls-files` handed them
331
+ // to `copyFile`, which followed a link out of the source (shipping a file from
332
+ // elsewhere on the build host) and threw a raw errno on a directory or
333
+ // dangling one after earlier files had already landed. Collect first, judge,
334
+ // then copy — the same shape as the listing refusal above, so a build that
335
+ // fails on a symlink leaves no half-written bundle either.
336
+ const { regular, links: crawledLinks } = await partitionByLstat(sourceDir, files);
337
+ const links = gitFindRoot(sourceDir) === null
338
+ ? [...crawledLinks, ...(await sweepSymlinks(sourceDir, crawlPathFilter(['**/*'], exclude)))]
339
+ : crawledLinks;
340
+ // A link the caller excluded is left out like any other excluded path — and
341
+ // that is the remedy the refusal names, so it must count as a hit here.
342
+ // The regular files are filtered FIRST so the judgement can ask whether a
343
+ // link's target is one of them (see classifySymlink) — and so a caller
344
+ // pattern that matches only a link's target still records its hit.
345
+ const shippedRegular = regular.filter(notExcludedByCaller);
346
+ const { copyable, refused } = await judgeSymlinks(sourceDir, links.filter(notExcludedByCaller), new Set(shippedRegular.map((entry) => entry.rel)));
347
+ if (refused.length > 0) {
348
+ throw new PluginSymlinkRefusedError(refused);
349
+ }
350
+ for (const entry of [...shippedRegular, ...copyable]) {
351
+ const target = safePath.join(destDir, entry.rel);
150
352
  // eslint-disable-next-line security/detect-non-literal-fs-filename -- dest resolved from sourceDir+relative
151
353
  await mkdir(dirname(target), { recursive: true });
152
- await copyFile(absPath, target);
354
+ // `copyFile` follows a symlink, which is the point for the in-tree file
355
+ // links that reach here: the bundle carries the target's bytes.
356
+ await copyFile(entry.abs, target);
153
357
  result.filesCopied += 1;
154
- const bucket = classifyRelative(rel);
358
+ const bucket = classifyRelative(entry.rel);
155
359
  if (bucket) {
156
360
  result[bucket] += 1;
157
361
  }
158
362
  }
363
+ result.symlinksCopied = copyable.map((entry) => entry.rel);
159
364
  // A typo'd or wrong-shaped exclude pattern used to be perfectly silent: the
160
365
  // knob no-oped and the junk shipped anyway. Zero matches is the only evidence
161
366
  // the author can get, so it always leaves this function — as DATA, on the one
@@ -1 +1 @@
1
- {"version":3,"file":"tree-copy.js","sourceRoot":"","sources":["../../../../src/commands/claude/plugin/tree-copy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tree-copy.js","sourceRoot":"","sources":["../../../../src/commands/claude/plugin/tree-copy.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/corpus/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,mBAAmB,IAAI,OAAO,CA0D7C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/corpus/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,mBAAmB,IAAI,OAAO,CA6D7C"}
@@ -37,6 +37,9 @@ Output:
37
37
  <--out>/<UTC-date>-<vat-short-sha>/
38
38
  summary.yaml # index: per-plugin status + totals
39
39
  <name>-audit.yaml # full audit output per plugin
40
+ # results: one entry per audited file; issues: run-level
41
+ # findings. An audit over 0 files is audit.status: error
42
+ # with one RESOURCE_CHECK_BROKEN, never a clean row.
40
43
  <name>-review.md # full skill-review output (only with --with-review)
41
44
 
42
45
  Exit codes:
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/corpus/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,iBAAiB,EAA0B,MAAM,WAAW,CAAC;AAEtE,MAAM,UAAU,mBAAmB;IACjC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IAErC,MAAM;SACH,WAAW,CAAC,uFAAuF,CAAC;SACpG,WAAW,CAAC,KAAK,CAAC,CAAC;IAEtB,MAAM;SACH,OAAO,CAAC,kBAAkB,CAAC;SAC3B,WAAW,CAAC,qEAAqE,CAAC;SAClF,QAAQ,CAAC,aAAa,EAAE,+CAA+C,CAAC;SACxE,cAAc,CAAC,aAAa,EAAE,wEAAwE,CAAC;SACvG,MAAM,CAAC,eAAe,EAAE,uEAAuE,CAAC;SAChG,MAAM,CAAC,SAAS,EAAE,mDAAmD,CAAC;SACtE,MAAM,CAAC,KAAK,WAA0B,QAA4B;QACjE,MAAM,iBAAiB,CAAC,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAuB,CAAC,CAAC;IACjF,CAAC,CAAC;SACD,WAAW,CACV,OAAO,EACP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCL,CACI,CAAC;IAEJ,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/corpus/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,iBAAiB,EAA0B,MAAM,WAAW,CAAC;AAEtE,MAAM,UAAU,mBAAmB;IACjC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IAErC,MAAM;SACH,WAAW,CAAC,uFAAuF,CAAC;SACpG,WAAW,CAAC,KAAK,CAAC,CAAC;IAEtB,MAAM;SACH,OAAO,CAAC,kBAAkB,CAAC;SAC3B,WAAW,CAAC,qEAAqE,CAAC;SAClF,QAAQ,CAAC,aAAa,EAAE,+CAA+C,CAAC;SACxE,cAAc,CAAC,aAAa,EAAE,wEAAwE,CAAC;SACvG,MAAM,CAAC,eAAe,EAAE,uEAAuE,CAAC;SAChG,MAAM,CAAC,SAAS,EAAE,mDAAmD,CAAC;SACtE,MAAM,CAAC,KAAK,WAA0B,QAA4B;QACjE,MAAM,iBAAiB,CAAC,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAuB,CAAC,CAAC;IACjF,CAAC,CAAC;SACD,WAAW,CACV,OAAO,EACP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCL,CACI,CAAC;IAEJ,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -54,7 +54,6 @@ export interface PluginRow {
54
54
  review: ReviewOutcome;
55
55
  }
56
56
  export interface RunReport {
57
- schema_version: 1;
58
57
  generated_at: string;
59
58
  vat_version: string;
60
59
  vat_commit: string;
@@ -1 +1 @@
1
- {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../src/commands/corpus/report.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAIjE,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,YAAY,CAAC;AACzE,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,OAAO,GAAG,SAAS,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,WAAW,YAAa,SAAQ,cAAc;IAClD,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB,EAAE,OAAO,CAAC;IAC5B,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,cAAc,EAAE,CAAC,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE;QAAE,WAAW,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAChD,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAmC1D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAG1D;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBvF"}
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../src/commands/corpus/report.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAIjE,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,YAAY,CAAC;AACzE,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,OAAO,GAAG,SAAS,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,WAAW,YAAa,SAAQ,cAAc;IAClD,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB,EAAE,OAAO,CAAC;IAC5B,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE;QAAE,WAAW,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAChD,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAmC1D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAG1D;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAqBvF"}
@@ -67,7 +67,6 @@ export async function writeRunReport(report, outDir) {
67
67
  mkdirSync(runDir, { recursive: true });
68
68
  const totals = computeTotals(report);
69
69
  const dump = {
70
- schema_version: report.schema_version,
71
70
  generated_at: report.generated_at,
72
71
  vat_version: report.vat_version,
73
72
  vat_commit: report.vat_commit,
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/commands/corpus/report.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/commands/corpus/report.ts"],"names":[],"mappings":"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"}
@@ -10,13 +10,55 @@
10
10
  * URL handling clones via Layer 1's `withClonedRepo` helper. Validation
11
11
  * overlay (Task 5) is added on top of this base.
12
12
  */
13
- import type { PluginRow, ReviewOutcome } from './report.js';
13
+ import type { ValidationResult } from '@vibe-agent-toolkit/agent-skills';
14
+ import { type ValidationIssue } from '@vibe-agent-toolkit/schema';
15
+ import type { DirectoryRefusal } from '@vibe-agent-toolkit/utils/crawl';
16
+ import type { AuditOutcome, PluginRow, ReviewOutcome } from './report.js';
14
17
  import type { PluginEntry } from './seed.js';
15
18
  export interface RunnerOptions {
16
19
  runDir: string;
17
20
  withReview: boolean;
18
21
  debug: boolean;
19
22
  }
23
+ /** The per-plugin audit document: one result per file, plus the run-level findings that belong to none. */
24
+ export interface AuditDocument {
25
+ results: readonly ValidationResult[];
26
+ /** Present only when non-empty, so a clean run's document keeps its shape. */
27
+ issues?: readonly ValidationIssue[];
28
+ }
29
+ /**
30
+ * Derive one plugin's audit row and its document from the per-file results.
31
+ *
32
+ * 🚨 **An audit over zero files is an ERROR, not "an empty tree audits
33
+ * cleanly".** `summarizeRun` over zero results gives `files_scanned: 0` and
34
+ * zero findings, and zero findings is `success` — so a source that resolved to
35
+ * a tree with nothing to audit (a wrong subdirectory, a clone whose default
36
+ * branch holds no skill, an excluded tree) wrote the same `summary.yaml` row as
37
+ * a clean plugin. The review lane on the identical fixture already answered
38
+ * `error` ("No SKILL.md files found"); this is the same question one lane
39
+ * over, and it now gets the same answer, through the shared mechanism in
40
+ * `run-integrity.ts`: one non-overridable `RESOURCE_CHECK_BROKEN` at `error`,
41
+ * counted in the row's `errors` and `findings_emitted`, carried in the document
42
+ * under `issues` beside the (empty) per-file results.
43
+ *
44
+ * `unloadable` is deliberately NOT the status here. Unloadable means the audit
45
+ * could not run — a missing path, a failed clone. This audit ran, and found no
46
+ * file to run over; the difference is the difference between "no verdict
47
+ * possible" and "this verdict is vacuous", and `computeTotals` counts them
48
+ * apart.
49
+ *
50
+ * Pure, and exported for that reason: the runner's loop clones, writes and
51
+ * catches, and the refusal has to be pinned without any of that.
52
+ *
53
+ * @param results - One validation result per audited file
54
+ * @param durationMs - The row's measured duration
55
+ * @param outputPath - Where the document is written, relative to the run dir
56
+ * @returns The row's audit outcome and the document to write for it
57
+ */
58
+ export declare function buildAuditOutcome(results: readonly ValidationResult[], durationMs: number, outputPath: string): {
59
+ audit: AuditOutcome;
60
+ document: AuditDocument;
61
+ };
20
62
  /**
21
63
  * Run audit + optional review against one plugin entry.
22
64
  */
@@ -26,6 +68,21 @@ export interface SkillReviewSection {
26
68
  ok: boolean;
27
69
  body: string;
28
70
  }
71
+ /**
72
+ * One failed section per directory the review scan could not list.
73
+ *
74
+ * The review lane's population is what `scan` enumerates; a directory it could
75
+ * not enter is a set of skills that were never reviewed, and a review.md that
76
+ * omits them reads as one that covered the plugin. Filing the gap on the
77
+ * existing per-skill channel — `ok: false`, keyed by the directory — is what
78
+ * makes `buildReviewOutcome` grade the run `error` and the aggregate name the
79
+ * subtree, without inventing a second channel the report would have to learn.
80
+ *
81
+ * @param unreadable - What `ScanSummary.unreadable` carried
82
+ * @param scanPath - The plugin root every section is keyed relative to
83
+ * @returns Sections in the order the refusals were met
84
+ */
85
+ export declare function unlistedDirectorySections(unreadable: readonly DirectoryRefusal[], scanPath: string): SkillReviewSection[];
29
86
  /**
30
87
  * Derive one plugin's `ReviewOutcome` from its per-skill sections.
31
88
  *
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/commands/corpus/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAiBH,OAAO,KAAK,EAA8B,SAAS,EAAE,aAAa,EAAiB,MAAM,aAAa,CAAC;AACvG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;CAChB;AAcD;;GAEG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,SAAS,CAAC,CAKpB;AAyED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAsDD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,SAAS,kBAAkB,EAAE,EACvC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,aAAa,CAmBf"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/commands/corpus/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEzE,OAAO,EAA8C,KAAK,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE9G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAUxE,OAAO,KAAK,EAAE,YAAY,EAAgB,SAAS,EAAE,aAAa,EAAiB,MAAM,aAAa,CAAC;AACvG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;CAChB;AAcD,2GAA2G;AAC3G,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACrC,8EAA8E;IAC9E,MAAM,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,SAAS,gBAAgB,EAAE,EACpC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,CAqBlD;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,SAAS,CAAC,CAKpB;AAiED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAsDD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,SAAS,gBAAgB,EAAE,EACvC,QAAQ,EAAE,MAAM,GACf,kBAAkB,EAAE,CAYtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,SAAS,kBAAkB,EAAE,EACvC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,aAAa,CAmBf"}
@@ -15,10 +15,11 @@ import { existsSync, writeFileSync } from 'node:fs';
15
15
  import { dirname } from 'node:path';
16
16
  import { scan } from '@vibe-agent-toolkit/discovery';
17
17
  import { calculateValidationStatus, countBySeverity } from '@vibe-agent-toolkit/schema';
18
- import { safePath } from '@vibe-agent-toolkit/utils';
18
+ import { safePath, toForwardSlash, transientRefusalClause } from '@vibe-agent-toolkit/utils';
19
19
  import { isGitUrl, parseGitUrl } from '@vibe-agent-toolkit/utils/git';
20
20
  import * as yaml from 'yaml';
21
21
  import { createLogger } from '../../utils/logger.js';
22
+ import { nothingCheckedFinding } from '../../utils/run-integrity.js';
22
23
  import { resolveVatBinPath } from '../../utils/vat-bin-path.js';
23
24
  import { withClonedRepo } from '../audit/git-url-clone.js';
24
25
  import { deriveScanRoot, getValidationResults } from '../audit.js';
@@ -32,6 +33,55 @@ const SKIPPED_REVIEW = { status: 'skipped', duration_ms: 0 };
32
33
  function summarizeRun(allIssues, filesScanned) {
33
34
  return { ...countBySeverity(allIssues), files_scanned: filesScanned };
34
35
  }
36
+ /**
37
+ * Derive one plugin's audit row and its document from the per-file results.
38
+ *
39
+ * 🚨 **An audit over zero files is an ERROR, not "an empty tree audits
40
+ * cleanly".** `summarizeRun` over zero results gives `files_scanned: 0` and
41
+ * zero findings, and zero findings is `success` — so a source that resolved to
42
+ * a tree with nothing to audit (a wrong subdirectory, a clone whose default
43
+ * branch holds no skill, an excluded tree) wrote the same `summary.yaml` row as
44
+ * a clean plugin. The review lane on the identical fixture already answered
45
+ * `error` ("No SKILL.md files found"); this is the same question one lane
46
+ * over, and it now gets the same answer, through the shared mechanism in
47
+ * `run-integrity.ts`: one non-overridable `RESOURCE_CHECK_BROKEN` at `error`,
48
+ * counted in the row's `errors` and `findings_emitted`, carried in the document
49
+ * under `issues` beside the (empty) per-file results.
50
+ *
51
+ * `unloadable` is deliberately NOT the status here. Unloadable means the audit
52
+ * could not run — a missing path, a failed clone. This audit ran, and found no
53
+ * file to run over; the difference is the difference between "no verdict
54
+ * possible" and "this verdict is vacuous", and `computeTotals` counts them
55
+ * apart.
56
+ *
57
+ * Pure, and exported for that reason: the runner's loop clones, writes and
58
+ * catches, and the refusal has to be pinned without any of that.
59
+ *
60
+ * @param results - One validation result per audited file
61
+ * @param durationMs - The row's measured duration
62
+ * @param outputPath - Where the document is written, relative to the run dir
63
+ * @returns The row's audit outcome and the document to write for it
64
+ */
65
+ export function buildAuditOutcome(results, durationMs, outputPath) {
66
+ const fileIssues = results.flatMap((r) => r.issues);
67
+ const runIssues = nothingCheckedFinding(results.length, fileIssues, () => 'The audit ran over 0 files, so this row is not a verdict: a plugin with nothing'
68
+ + ' to audit produces the same counts as a clean one. The source resolved to a tree'
69
+ + ' holding no auditable file — usually a wrong subdirectory, a clone whose default'
70
+ + ' branch carries no skill or plugin, or an excluded tree.'
71
+ + ' `vat audit <source>` over the same path shows what the scan enumerates.');
72
+ const allIssues = [...runIssues, ...fileIssues];
73
+ const summary = summarizeRun(allIssues, results.length);
74
+ return {
75
+ audit: {
76
+ status: calculateValidationStatus(allIssues),
77
+ duration_ms: durationMs,
78
+ summary,
79
+ findings_emitted: summary.errors + summary.warnings + summary.info,
80
+ output_path: outputPath,
81
+ },
82
+ document: { results, ...(runIssues.length === 0 ? {} : { issues: runIssues }) },
83
+ };
84
+ }
35
85
  /**
36
86
  * Run audit + optional review against one plugin entry.
37
87
  */
@@ -64,19 +114,12 @@ async function auditAndRecord(entry, scanPath, opts) {
64
114
  try {
65
115
  // The corpus run root is the scanned plugin itself — one root per row.
66
116
  const results = await getValidationResults(scanPath, true, {}, logger, deriveScanRoot(scanPath));
67
- const allIssues = results.flatMap(r => r.issues);
68
- const summary = summarizeRun(allIssues, results.length);
69
- const status = calculateValidationStatus(allIssues);
70
- const auditYamlPath = safePath.join(opts.runDir, `${entry.name}-audit.yaml`);
117
+ const outputPath = `${entry.name}-audit.yaml`;
118
+ const outcome = buildAuditOutcome(results, Date.now() - start, outputPath);
119
+ const auditYamlPath = safePath.join(opts.runDir, outputPath);
71
120
  // eslint-disable-next-line security/detect-non-literal-fs-filename -- composed under run dir
72
- writeFileSync(auditYamlPath, yaml.stringify({ results }, { lineWidth: 0, aliasDuplicateObjects: false }), 'utf-8');
73
- audit = {
74
- status,
75
- duration_ms: Date.now() - start,
76
- summary,
77
- findings_emitted: summary.errors + summary.warnings + summary.info,
78
- output_path: `${entry.name}-audit.yaml`,
79
- };
121
+ writeFileSync(auditYamlPath, yaml.stringify(outcome.document, { lineWidth: 0, aliasDuplicateObjects: false }), 'utf-8');
122
+ audit = outcome.audit;
80
123
  }
81
124
  catch (err) {
82
125
  audit = {
@@ -139,6 +182,33 @@ function summarizeReview(sections) {
139
182
  const reviewed = sections.filter((s) => s.ok).length;
140
183
  return { reviewed, failed: sections.length - reviewed, skills_scanned: sections.length };
141
184
  }
185
+ /**
186
+ * One failed section per directory the review scan could not list.
187
+ *
188
+ * The review lane's population is what `scan` enumerates; a directory it could
189
+ * not enter is a set of skills that were never reviewed, and a review.md that
190
+ * omits them reads as one that covered the plugin. Filing the gap on the
191
+ * existing per-skill channel — `ok: false`, keyed by the directory — is what
192
+ * makes `buildReviewOutcome` grade the run `error` and the aggregate name the
193
+ * subtree, without inventing a second channel the report would have to learn.
194
+ *
195
+ * @param unreadable - What `ScanSummary.unreadable` carried
196
+ * @param scanPath - The plugin root every section is keyed relative to
197
+ * @returns Sections in the order the refusals were met
198
+ */
199
+ export function unlistedDirectorySections(unreadable, scanPath) {
200
+ return unreadable.map((refusal) => {
201
+ const relativePath = toForwardSlash(safePath.relative(scanPath, refusal.directory)) || '.';
202
+ const cause = refusal.transient
203
+ ? `${transientRefusalClause(refusal.code)} — re-run before investigating anything`
204
+ : `listing was refused with ${refusal.code}`;
205
+ return {
206
+ relativePath,
207
+ ok: false,
208
+ body: `Directory could not be listed (${cause}); every skill beneath it was not reviewed.`,
209
+ };
210
+ });
211
+ }
142
212
  /**
143
213
  * Derive one plugin's `ReviewOutcome` from its per-skill sections.
144
214
  *
@@ -182,7 +252,12 @@ async function runSkillReview(entry, scanPath, runDir) {
182
252
  const reviewPath = safePath.join(runDir, `${entry.name}-review.md`);
183
253
  const summary = await scan({ path: scanPath, recursive: true });
184
254
  const skills = summary.results.filter((r) => r.format === 'agent-skill' && !r.isGitIgnored);
185
- if (skills.length === 0) {
255
+ // Directories the scan could not list hold skills this review never saw. They
256
+ // enter the aggregate as failed sections — see `unlistedDirectorySections` —
257
+ // so the outcome is `error` and the review names the gap, while every skill
258
+ // that WAS found is still reviewed below.
259
+ const unlisted = unlistedDirectorySections(summary.unreadable, scanPath);
260
+ if (skills.length === 0 && unlisted.length === 0) {
186
261
  return {
187
262
  status: 'error',
188
263
  duration_ms: Date.now() - start,
@@ -190,7 +265,7 @@ async function runSkillReview(entry, scanPath, runDir) {
190
265
  error: `No SKILL.md files found under ${scanPath}`,
191
266
  };
192
267
  }
193
- const sections = [];
268
+ const sections = [...unlisted];
194
269
  for (const skill of skills) {
195
270
  const skillDir = dirname(skill.path);
196
271
  sections.push(reviewOneSkill(bin, skillDir, skill.relativePath));