@vibe-agent-toolkit/cli 0.1.34-rc.2 → 0.1.34

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 (46) hide show
  1. package/dist/bin.js +4 -0
  2. package/dist/bin.js.map +1 -1
  3. package/dist/commands/audit/git-url-clone.d.ts +32 -0
  4. package/dist/commands/audit/git-url-clone.d.ts.map +1 -0
  5. package/dist/commands/audit/git-url-clone.js +135 -0
  6. package/dist/commands/audit/git-url-clone.js.map +1 -0
  7. package/dist/commands/audit/provenance.d.ts +33 -0
  8. package/dist/commands/audit/provenance.d.ts.map +1 -0
  9. package/dist/commands/audit/provenance.js +57 -0
  10. package/dist/commands/audit/provenance.js.map +1 -0
  11. package/dist/commands/audit.d.ts.map +1 -1
  12. package/dist/commands/audit.js +218 -72
  13. package/dist/commands/audit.js.map +1 -1
  14. package/dist/commands/claude/marketplace/validate.d.ts.map +1 -1
  15. package/dist/commands/claude/marketplace/validate.js +2 -1
  16. package/dist/commands/claude/marketplace/validate.js.map +1 -1
  17. package/dist/commands/corpus/index.d.ts +6 -0
  18. package/dist/commands/corpus/index.d.ts.map +1 -0
  19. package/dist/commands/corpus/index.js +53 -0
  20. package/dist/commands/corpus/index.js.map +1 -0
  21. package/dist/commands/corpus/report.d.ts +75 -0
  22. package/dist/commands/corpus/report.d.ts.map +1 -0
  23. package/dist/commands/corpus/report.js +83 -0
  24. package/dist/commands/corpus/report.js.map +1 -0
  25. package/dist/commands/corpus/runner.d.ts +24 -0
  26. package/dist/commands/corpus/runner.d.ts.map +1 -0
  27. package/dist/commands/corpus/runner.js +246 -0
  28. package/dist/commands/corpus/runner.js.map +1 -0
  29. package/dist/commands/corpus/scan.d.ts +15 -0
  30. package/dist/commands/corpus/scan.d.ts.map +1 -0
  31. package/dist/commands/corpus/scan.js +90 -0
  32. package/dist/commands/corpus/scan.js.map +1 -0
  33. package/dist/commands/corpus/seed.d.ts +178 -0
  34. package/dist/commands/corpus/seed.d.ts.map +1 -0
  35. package/dist/commands/corpus/seed.js +63 -0
  36. package/dist/commands/corpus/seed.js.map +1 -0
  37. package/dist/commands/inventory.d.ts +17 -0
  38. package/dist/commands/inventory.d.ts.map +1 -0
  39. package/dist/commands/inventory.js +90 -0
  40. package/dist/commands/inventory.js.map +1 -0
  41. package/dist/utils/git-url.d.ts +43 -0
  42. package/dist/utils/git-url.d.ts.map +1 -0
  43. package/dist/utils/git-url.js +135 -0
  44. package/dist/utils/git-url.js.map +1 -0
  45. package/docs/audit.md +54 -3
  46. package/package.json +11 -11
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Corpus command group — Phase 1 ships only `scan`.
3
+ */
4
+ import { Command } from 'commander';
5
+ import { corpusScanCommand } from './scan.js';
6
+ export function createCorpusCommand() {
7
+ const corpus = new Command('corpus');
8
+ corpus
9
+ .description('Run vat audit (and optionally vat skill review) at scale across a tracked plugin seed')
10
+ .helpCommand(false);
11
+ corpus
12
+ .command('scan [seed-file]')
13
+ .description('Audit each plugin in the seed; write a per-run snapshot under --out')
14
+ .argument('[seed-file]', 'Path to seed YAML (default: corpus/seed.yaml)')
15
+ .requiredOption('--out <dir>', 'Output directory for the run snapshot (no default — must be specified)')
16
+ .option('--with-review', 'Also invoke vat skill review per plugin (LLM-backed; uses API tokens)')
17
+ .option('--debug', 'Enable debug logging and preserve cloned tempdirs')
18
+ .action(async function (seedFile) {
19
+ await corpusScanCommand(seedFile, this.optsWithGlobals());
20
+ })
21
+ .addHelpText('after', `
22
+ Description:
23
+ Reads a seed YAML listing plugins to audit (each entry: { source, name,
24
+ validation? }), runs 'vat audit' against each (and optionally 'vat skill
25
+ review' with --with-review), writes summary.yaml plus per-plugin sibling
26
+ files into a date-sha subdirectory of --out.
27
+
28
+ source forms accepted (same as vat audit):
29
+ - local path (absolute or relative)
30
+ - https://host/owner/repo.git[#ref[:subpath]]
31
+ - GitHub web URL (https://github.com/owner/repo/tree/<ref>/<subpath>)
32
+ - GitHub shorthand (owner/repo, with optional #ref:subpath)
33
+ - SSH URL (git@host:owner/repo.git or ssh://...)
34
+ - file:// URL (local bare-repo testing)
35
+
36
+ Output:
37
+ <--out>/<UTC-date>-<vat-short-sha>/
38
+ summary.yaml # index: per-plugin status + totals
39
+ <name>-audit.yaml # full audit output per plugin
40
+ <name>-review.md # full skill-review output (only with --with-review)
41
+
42
+ Exit codes:
43
+ 0 - scan completed (regardless of unloadable plugins)
44
+ 2 - scan failed to start (seed missing, --out missing, etc.)
45
+ 130 - interrupted by SIGINT (partial results written)
46
+
47
+ Example:
48
+ $ vat corpus scan --out ~/scratch/vat-corpus-runs
49
+ $ vat corpus scan corpus/seed.yaml --out ~/scratch/vat-corpus-runs --with-review
50
+ `);
51
+ return corpus;
52
+ }
53
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BL,CACI,CAAC;IAEJ,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Run-summary types + writer for `vat corpus scan`.
3
+ *
4
+ * `summary.yaml` is the index for one scan run. Per-plugin full audit
5
+ * outputs and full skill-review outputs are written as sibling files
6
+ * referenced by relative `output_path`. Totals are derived from the
7
+ * per-plugin rows so callers can pass raw rows and let this module
8
+ * compute aggregates.
9
+ */
10
+ export type AuditStatus = 'success' | 'warning' | 'error' | 'unloadable';
11
+ export type ReviewStatus = 'ok' | 'error' | 'skipped';
12
+ export interface AuditSummary {
13
+ errors: number;
14
+ warnings: number;
15
+ info: number;
16
+ files_scanned: number;
17
+ }
18
+ export interface AuditOutcome {
19
+ status: AuditStatus;
20
+ duration_ms: number;
21
+ summary?: AuditSummary;
22
+ findings_emitted?: number;
23
+ output_path?: string;
24
+ error?: string;
25
+ }
26
+ export interface ReviewOutcome {
27
+ status: ReviewStatus;
28
+ duration_ms: number;
29
+ output_path?: string;
30
+ error?: string;
31
+ }
32
+ export interface PluginRow {
33
+ source: string;
34
+ name: string;
35
+ validation_applied: boolean;
36
+ audit: AuditOutcome;
37
+ review: ReviewOutcome;
38
+ }
39
+ export interface RunReport {
40
+ schema_version: 1;
41
+ generated_at: string;
42
+ vat_version: string;
43
+ vat_commit: string;
44
+ seed_file: string;
45
+ flags: {
46
+ with_review: boolean;
47
+ debug: boolean;
48
+ };
49
+ plugins: PluginRow[];
50
+ }
51
+ export interface RunTotals {
52
+ plugins: number;
53
+ audit_clean: number;
54
+ audit_warning: number;
55
+ audit_error: number;
56
+ unloadable: number;
57
+ reviewed?: number;
58
+ }
59
+ /**
60
+ * Compute totals over the per-plugin rows.
61
+ */
62
+ export declare function computeTotals(report: RunReport): RunTotals;
63
+ /**
64
+ * Build the run directory name: `<YYYY-MM-DD>-<vat-short-sha>`.
65
+ * Date is the UTC date of `generated_at`.
66
+ */
67
+ export declare function runDirectoryName(report: RunReport): string;
68
+ /**
69
+ * Write `summary.yaml` (and create the run directory) under `outDir`.
70
+ * Returns the absolute path of the created run directory. Per-plugin
71
+ * sibling files (audit outputs, review outputs) are written by the
72
+ * runner — this function only writes the summary index.
73
+ */
74
+ export declare function writeRunReport(report: RunReport, outDir: string): Promise<string>;
75
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../src/commands/corpus/report.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,YAAY,CAAC;AACzE,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,OAAO,GAAG,SAAS,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,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,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,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;CACnB;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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Run-summary types + writer for `vat corpus scan`.
3
+ *
4
+ * `summary.yaml` is the index for one scan run. Per-plugin full audit
5
+ * outputs and full skill-review outputs are written as sibling files
6
+ * referenced by relative `output_path`. Totals are derived from the
7
+ * per-plugin rows so callers can pass raw rows and let this module
8
+ * compute aggregates.
9
+ */
10
+ import { mkdirSync, writeFileSync } from 'node:fs';
11
+ import { safePath } from '@vibe-agent-toolkit/utils';
12
+ import * as yaml from 'js-yaml';
13
+ /**
14
+ * Compute totals over the per-plugin rows.
15
+ */
16
+ export function computeTotals(report) {
17
+ const totals = {
18
+ plugins: report.plugins.length,
19
+ audit_clean: 0,
20
+ audit_warning: 0,
21
+ audit_error: 0,
22
+ unloadable: 0,
23
+ };
24
+ for (const row of report.plugins) {
25
+ switch (row.audit.status) {
26
+ case 'success': {
27
+ totals.audit_clean += 1;
28
+ break;
29
+ }
30
+ case 'warning': {
31
+ totals.audit_warning += 1;
32
+ break;
33
+ }
34
+ case 'error': {
35
+ totals.audit_error += 1;
36
+ break;
37
+ }
38
+ case 'unloadable': {
39
+ totals.unloadable += 1;
40
+ break;
41
+ }
42
+ }
43
+ }
44
+ if (report.flags.with_review) {
45
+ totals.reviewed = report.plugins.filter((p) => p.review.status !== 'skipped').length;
46
+ }
47
+ return totals;
48
+ }
49
+ /**
50
+ * Build the run directory name: `<YYYY-MM-DD>-<vat-short-sha>`.
51
+ * Date is the UTC date of `generated_at`.
52
+ */
53
+ export function runDirectoryName(report) {
54
+ const datePart = report.generated_at.slice(0, 10); // 'YYYY-MM-DD'
55
+ return `${datePart}-${report.vat_commit}`;
56
+ }
57
+ /**
58
+ * Write `summary.yaml` (and create the run directory) under `outDir`.
59
+ * Returns the absolute path of the created run directory. Per-plugin
60
+ * sibling files (audit outputs, review outputs) are written by the
61
+ * runner — this function only writes the summary index.
62
+ */
63
+ export async function writeRunReport(report, outDir) {
64
+ const runDir = safePath.join(outDir, runDirectoryName(report));
65
+ // eslint-disable-next-line local/no-fs-mkdirSync, security/detect-non-literal-fs-filename -- the corpus output dir is caller-supplied; mkdir-recursive is the right call here
66
+ mkdirSync(runDir, { recursive: true });
67
+ const totals = computeTotals(report);
68
+ const dump = {
69
+ schema_version: report.schema_version,
70
+ generated_at: report.generated_at,
71
+ vat_version: report.vat_version,
72
+ vat_commit: report.vat_commit,
73
+ seed_file: report.seed_file,
74
+ flags: report.flags,
75
+ plugins: report.plugins,
76
+ totals,
77
+ };
78
+ const summaryPath = safePath.join(runDir, 'summary.yaml');
79
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- summaryPath composed under our run dir
80
+ writeFileSync(summaryPath, yaml.dump(dump, { lineWidth: -1 }), 'utf-8');
81
+ return runDir;
82
+ }
83
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/commands/corpus/report.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEnD,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAuDhC;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,MAAiB;IAC7C,MAAM,MAAM,GAAc;QACxB,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM;QAC9B,WAAW,EAAE,CAAC;QACd,aAAa,EAAE,CAAC;QAChB,WAAW,EAAE,CAAC;QACd,UAAU,EAAE,CAAC;KACd,CAAC;IAEF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACjC,QAAQ,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YACzB,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,MAAM,CAAC,WAAW,IAAI,CAAC,CAAC;gBACxB,MAAM;YACR,CAAC;YACD,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,MAAM,CAAC,aAAa,IAAI,CAAC,CAAC;gBAC1B,MAAM;YACR,CAAC;YACD,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,MAAM,CAAC,WAAW,IAAI,CAAC,CAAC;gBACxB,MAAM;YACR,CAAC;YACD,KAAK,YAAY,CAAC,CAAC,CAAC;gBAClB,MAAM,CAAC,UAAU,IAAI,CAAC,CAAC;gBACvB,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;QAC7B,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IACvF,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe;IAClE,OAAO,GAAG,QAAQ,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;AAC5C,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAiB,EAAE,MAAc;IACpE,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/D,8KAA8K;IAC9K,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEvC,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG;QACX,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM;KACP,CAAC;IAEF,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC1D,6GAA6G;IAC7G,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;IAExE,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Per-plugin orchestrator for `vat corpus scan`.
3
+ *
4
+ * Phase 1 scope: resolve source (local or URL), optionally overlay a
5
+ * synthetic `vibe-agent-toolkit.config.yaml` from the entry's `validation:`
6
+ * block, run `vat audit` in-process, optionally invoke `vat skill review`,
7
+ * write per-plugin sibling files into the run directory, and return a
8
+ * PluginRow. Per-plugin failures never abort the loop.
9
+ *
10
+ * URL handling clones via Layer 1's `withClonedRepo` helper. Validation
11
+ * overlay (Task 5) is added on top of this base.
12
+ */
13
+ import type { PluginRow } from './report.js';
14
+ import type { PluginEntry } from './seed.js';
15
+ export interface RunnerOptions {
16
+ runDir: string;
17
+ withReview: boolean;
18
+ debug: boolean;
19
+ }
20
+ /**
21
+ * Run audit + optional review against one plugin entry.
22
+ */
23
+ export declare function auditOnePlugin(entry: PluginEntry, opts: RunnerOptions): Promise<PluginRow>;
24
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/commands/corpus/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAgBH,OAAO,KAAK,EAA2C,SAAS,EAAiB,MAAM,aAAa,CAAC;AACrG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAqB7C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;CAChB;AA0BD;;GAEG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,SAAS,CAAC,CAKpB"}
@@ -0,0 +1,246 @@
1
+ /**
2
+ * Per-plugin orchestrator for `vat corpus scan`.
3
+ *
4
+ * Phase 1 scope: resolve source (local or URL), optionally overlay a
5
+ * synthetic `vibe-agent-toolkit.config.yaml` from the entry's `validation:`
6
+ * block, run `vat audit` in-process, optionally invoke `vat skill review`,
7
+ * write per-plugin sibling files into the run directory, and return a
8
+ * PluginRow. Per-plugin failures never abort the loop.
9
+ *
10
+ * URL handling clones via Layer 1's `withClonedRepo` helper. Validation
11
+ * overlay (Task 5) is added on top of this base.
12
+ */
13
+ import { spawnSync } from 'node:child_process';
14
+ import { existsSync, writeFileSync } from 'node:fs';
15
+ import { dirname } from 'node:path';
16
+ import { fileURLToPath } from 'node:url';
17
+ import { scan } from '@vibe-agent-toolkit/discovery';
18
+ import { safePath } from '@vibe-agent-toolkit/utils';
19
+ import * as yaml from 'js-yaml';
20
+ import { isGitUrl, parseGitUrl } from '../../utils/git-url.js';
21
+ import { createLogger } from '../../utils/logger.js';
22
+ import { withClonedRepo } from '../audit/git-url-clone.js';
23
+ import { getValidationResults } from '../audit.js';
24
+ const __dirname = dirname(fileURLToPath(import.meta.url));
25
+ /**
26
+ * Resolve the path to the built vat CLI entry. Works whether the runner is
27
+ * invoked from compiled dist (production) or from source under vitest. In
28
+ * either case we always invoke the *compiled* `dist/bin.js` — `node` cannot
29
+ * execute `.ts` directly, so the source-tree fallback walks across to
30
+ * `packages/cli/dist/bin.js`. A build is therefore required before tests that
31
+ * exercise the review path can pass.
32
+ */
33
+ function resolveVatBinPath() {
34
+ // Compiled tree: packages/cli/dist/commands/corpus/runner.js → packages/cli/dist/bin.js
35
+ const compiled = safePath.resolve(__dirname, '../../bin.js');
36
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- internal path
37
+ if (existsSync(compiled))
38
+ return compiled;
39
+ // Source tree (vitest): packages/cli/src/commands/corpus/runner.ts → packages/cli/dist/bin.js
40
+ return safePath.resolve(__dirname, '../../../dist/bin.js');
41
+ }
42
+ const SKIPPED_REVIEW = { status: 'skipped', duration_ms: 0 };
43
+ function statusFromCounts(errors, warnings) {
44
+ if (errors > 0)
45
+ return 'error';
46
+ if (warnings > 0)
47
+ return 'warning';
48
+ return 'success';
49
+ }
50
+ function summarizeResults(results) {
51
+ let errors = 0;
52
+ let warnings = 0;
53
+ let info = 0;
54
+ for (const r of results) {
55
+ for (const issue of r.issues ?? []) {
56
+ if (issue.severity === 'error')
57
+ errors += 1;
58
+ else if (issue.severity === 'warning')
59
+ warnings += 1;
60
+ else if (issue.severity === 'info')
61
+ info += 1;
62
+ }
63
+ }
64
+ return { errors, warnings, info, files_scanned: results.length };
65
+ }
66
+ /**
67
+ * Run audit + optional review against one plugin entry.
68
+ */
69
+ export async function auditOnePlugin(entry, opts) {
70
+ if (isGitUrl(entry.source)) {
71
+ return runUrlEntry(entry, opts);
72
+ }
73
+ return runLocalEntry(entry, opts);
74
+ }
75
+ async function runLocalEntry(entry, opts) {
76
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- caller-supplied seed entry
77
+ if (!existsSync(entry.source)) {
78
+ return unloadableRow(entry, `Source path not found: ${entry.source}`, 0);
79
+ }
80
+ return auditAndRecord(entry, entry.source, opts);
81
+ }
82
+ async function runUrlEntry(entry, opts) {
83
+ try {
84
+ return await withClonedRepo(parseGitUrl(entry.source), { keepTempForDebug: opts.debug }, async ({ targetDir }) => auditAndRecord(entry, targetDir, opts));
85
+ }
86
+ catch (err) {
87
+ return unloadableRow(entry, err instanceof Error ? err.message : String(err), 0);
88
+ }
89
+ }
90
+ async function auditAndRecord(entry, scanPath, opts) {
91
+ const logger = createLogger(opts.debug ? { debug: true } : {});
92
+ const start = Date.now();
93
+ const validationApplied = applyValidationOverlay(entry, scanPath);
94
+ let audit;
95
+ try {
96
+ const results = await getValidationResults(scanPath, true, {}, logger);
97
+ const summary = summarizeResults(results);
98
+ const status = statusFromCounts(summary.errors, summary.warnings);
99
+ const auditYamlPath = safePath.join(opts.runDir, `${entry.name}-audit.yaml`);
100
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- composed under run dir
101
+ writeFileSync(auditYamlPath, yaml.dump({ results }, { lineWidth: -1 }), 'utf-8');
102
+ audit = {
103
+ status,
104
+ duration_ms: Date.now() - start,
105
+ summary,
106
+ findings_emitted: summary.errors + summary.warnings + summary.info,
107
+ output_path: `${entry.name}-audit.yaml`,
108
+ };
109
+ }
110
+ catch (err) {
111
+ audit = {
112
+ status: 'unloadable',
113
+ duration_ms: Date.now() - start,
114
+ error: err instanceof Error ? err.message : String(err),
115
+ };
116
+ }
117
+ // Skip review when audit was unloadable — nothing meaningful to review.
118
+ const review = opts.withReview && audit.status !== 'unloadable'
119
+ ? await runSkillReview(entry, scanPath, opts.runDir)
120
+ : SKIPPED_REVIEW;
121
+ return {
122
+ source: entry.source,
123
+ name: entry.name,
124
+ validation_applied: validationApplied,
125
+ audit,
126
+ review,
127
+ };
128
+ }
129
+ /**
130
+ * Spawn `vat skill review <skillDir>` for one skill and return a markdown
131
+ * section describing the result. Subprocess failure is captured as an
132
+ * error section rather than thrown — one bad skill must not abort siblings.
133
+ */
134
+ function reviewOneSkill(bin, skillDir, relativePath) {
135
+ // eslint-disable-next-line sonarjs/no-os-command-from-path -- node is required for invoking vat
136
+ const result = spawnSync('node', [bin, 'skill', 'review', skillDir], {
137
+ encoding: 'utf-8',
138
+ stdio: ['ignore', 'pipe', 'pipe'],
139
+ });
140
+ // `vat skill review` exit semantics:
141
+ // 0 — review clean
142
+ // 1 — review completed but found warnings/errors (still a successful review for corpus purposes)
143
+ // 2 (or other non-zero / null) — system error, the review did not run to completion
144
+ const SKILL_REVIEW_FINDINGS_EXIT = 1;
145
+ const reviewRan = result.status === 0 || result.status === SKILL_REVIEW_FINDINGS_EXIT;
146
+ if (!reviewRan) {
147
+ const stderr = (result.stderr ?? '').trim();
148
+ const message = stderr || `vat skill review exited with code ${result.status ?? 'unknown'}`;
149
+ const stdout = (result.stdout ?? '').trim();
150
+ const stdoutBlock = stdout ? `\n\n${stdout}` : '';
151
+ const body = `**[review failed]**\n\n${message}${stdoutBlock}`;
152
+ return { relativePath, ok: false, body };
153
+ }
154
+ const body = ((result.stdout ?? '') + (result.stderr ?? '')).trim();
155
+ return { relativePath, ok: true, body };
156
+ }
157
+ function renderAggregatedReview(entry, sections, okCount) {
158
+ const header = `# Skill review: ${entry.name}\n\nReviewed ${okCount} of ${sections.length} skills (${sections.length - okCount} errors).\n`;
159
+ const rendered = sections
160
+ .map((s) => `\n---\n\n## ${s.relativePath}\n\n${s.body}\n`)
161
+ .join('');
162
+ return `${header}${rendered}`;
163
+ }
164
+ /**
165
+ * Discover every SKILL.md under `scanPath` (recursive, gitignore-aware) and
166
+ * invoke `vat skill review` once per skill directory. Concatenate the
167
+ * outputs into `<name>-review.md` with a section per skill keyed by the
168
+ * skill's path relative to the plugin root.
169
+ *
170
+ * Per-skill subprocess failures become error sections; the aggregate is
171
+ * still written so users can see which skills passed and which failed.
172
+ * Returns `status: 'error'` only when no skills were discovered or every
173
+ * subprocess failed.
174
+ */
175
+ async function runSkillReview(entry, scanPath, runDir) {
176
+ const start = Date.now();
177
+ const bin = resolveVatBinPath();
178
+ const reviewPath = safePath.join(runDir, `${entry.name}-review.md`);
179
+ const summary = await scan({ path: scanPath, recursive: true });
180
+ const skills = summary.results.filter((r) => r.format === 'agent-skill' && !r.isGitIgnored);
181
+ if (skills.length === 0) {
182
+ return {
183
+ status: 'error',
184
+ duration_ms: Date.now() - start,
185
+ error: `No SKILL.md files found under ${scanPath}`,
186
+ };
187
+ }
188
+ const sections = [];
189
+ for (const skill of skills) {
190
+ const skillDir = dirname(skill.path);
191
+ sections.push(reviewOneSkill(bin, skillDir, skill.relativePath));
192
+ }
193
+ const okCount = sections.filter((s) => s.ok).length;
194
+ const aggregated = renderAggregatedReview(entry, sections, okCount);
195
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- composed under run dir
196
+ writeFileSync(reviewPath, aggregated, 'utf-8');
197
+ if (okCount === 0) {
198
+ const errors = sections
199
+ .map((s) => `${s.relativePath}: ${s.body.replaceAll('\n', ' ').slice(0, 200)}`)
200
+ .join('; ');
201
+ return {
202
+ status: 'error',
203
+ duration_ms: Date.now() - start,
204
+ error: `All ${sections.length} skill reviews failed. ${errors}`,
205
+ output_path: `${entry.name}-review.md`,
206
+ };
207
+ }
208
+ return {
209
+ status: 'ok',
210
+ duration_ms: Date.now() - start,
211
+ output_path: `${entry.name}-review.md`,
212
+ };
213
+ }
214
+ /**
215
+ * Write a synthetic `vibe-agent-toolkit.config.yaml` at the audit target,
216
+ * placing the entry's `validation:` block under `skills.defaults.validation`.
217
+ * Returns true iff the overlay was written.
218
+ *
219
+ * Phase 1: clobbers any pre-existing config in the cloned tree. Merging
220
+ * with author-shipped configs is a follow-up.
221
+ */
222
+ function applyValidationOverlay(entry, scanPath) {
223
+ if (!entry.validation)
224
+ return false;
225
+ const overlayPath = safePath.join(scanPath, 'vibe-agent-toolkit.config.yaml');
226
+ const overlay = {
227
+ skills: {
228
+ defaults: {
229
+ validation: entry.validation,
230
+ },
231
+ },
232
+ };
233
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- composed under audit target
234
+ writeFileSync(overlayPath, yaml.dump(overlay, { lineWidth: -1 }), 'utf-8');
235
+ return true;
236
+ }
237
+ function unloadableRow(entry, error, durationMs) {
238
+ return {
239
+ source: entry.source,
240
+ name: entry.name,
241
+ validation_applied: false,
242
+ audit: { status: 'unloadable', duration_ms: durationMs, error },
243
+ review: SKIPPED_REVIEW,
244
+ };
245
+ }
246
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../../src/commands/corpus/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `vat corpus scan [seed-file] --out <dir>` — Phase 1 orchestrator.
3
+ *
4
+ * Reads the seed, delegates each entry to the runner sequentially,
5
+ * writes summary.yaml and per-plugin sibling files into a date-sha
6
+ * subdirectory of `--out`. Sequential by design — concurrency is a
7
+ * follow-up once the seed grows past ~50.
8
+ */
9
+ export interface CorpusScanOptions {
10
+ out?: string;
11
+ withReview?: boolean;
12
+ debug?: boolean;
13
+ }
14
+ export declare function corpusScanCommand(seedFileArg: string | undefined, options: CorpusScanOptions): Promise<void>;
15
+ //# sourceMappingURL=scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/commands/corpus/scan.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAeH,MAAM,WAAW,iBAAiB;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAwBD,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CA2Df"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * `vat corpus scan [seed-file] --out <dir>` — Phase 1 orchestrator.
3
+ *
4
+ * Reads the seed, delegates each entry to the runner sequentially,
5
+ * writes summary.yaml and per-plugin sibling files into a date-sha
6
+ * subdirectory of `--out`. Sequential by design — concurrency is a
7
+ * follow-up once the seed grows past ~50.
8
+ */
9
+ import { mkdirSync, readFileSync } from 'node:fs';
10
+ import { dirname } from 'node:path';
11
+ import { fileURLToPath } from 'node:url';
12
+ import { safeExecSync, safePath } from '@vibe-agent-toolkit/utils';
13
+ import { handleCommandError } from '../../utils/command-error.js';
14
+ import { createLogger } from '../../utils/logger.js';
15
+ import { writeRunReport } from './report.js';
16
+ import { auditOnePlugin } from './runner.js';
17
+ import { loadSeedFile } from './seed.js';
18
+ const DEFAULT_SEED_PATH = 'corpus/seed.yaml';
19
+ const __dirname = dirname(fileURLToPath(import.meta.url));
20
+ function readVatVersion() {
21
+ // packages/cli/dist/commands/corpus/scan.js → packages/cli/package.json
22
+ // packages/cli/src/commands/corpus/scan.ts → packages/cli/package.json
23
+ const pkgPath = safePath.resolve(__dirname, '../../../package.json');
24
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- internal package.json path
25
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
26
+ return pkg.version ?? 'unknown';
27
+ }
28
+ function readVatCommit() {
29
+ try {
30
+ const out = safeExecSync('git', ['rev-parse', '--short=8', 'HEAD'], { encoding: 'utf-8' });
31
+ return (typeof out === 'string' ? out : out.toString('utf-8')).trim();
32
+ }
33
+ catch {
34
+ return 'unknown';
35
+ }
36
+ }
37
+ export async function corpusScanCommand(seedFileArg, options) {
38
+ const logger = createLogger(options.debug ? { debug: true } : {});
39
+ const startTime = Date.now();
40
+ try {
41
+ if (!options.out) {
42
+ throw new Error('specify an output directory: --out <path>');
43
+ }
44
+ const seedPath = seedFileArg ?? DEFAULT_SEED_PATH;
45
+ const seed = loadSeedFile(seedPath);
46
+ // eslint-disable-next-line local/no-fs-mkdirSync, security/detect-non-literal-fs-filename -- caller-supplied output dir; recursive create is correct here
47
+ mkdirSync(options.out, { recursive: true });
48
+ // We need the run directory to write per-plugin files into during the
49
+ // loop. Build the report skeleton, derive the run dir name, create it,
50
+ // then run the loop.
51
+ const generatedAt = new Date().toISOString().replace(/\.\d+Z$/, 'Z');
52
+ const vatVersion = readVatVersion();
53
+ const vatCommit = readVatCommit();
54
+ const runDirName = `${generatedAt.slice(0, 10)}-${vatCommit}`;
55
+ const runDir = safePath.join(options.out, runDirName);
56
+ // eslint-disable-next-line local/no-fs-mkdirSync, security/detect-non-literal-fs-filename -- composed under user-supplied --out
57
+ mkdirSync(runDir, { recursive: true });
58
+ const rows = [];
59
+ for (const entry of seed.plugins) {
60
+ logger.info(`[${entry.name}] auditing ${entry.source}`);
61
+ const row = await auditOnePlugin(entry, {
62
+ runDir,
63
+ withReview: options.withReview === true,
64
+ debug: options.debug === true,
65
+ });
66
+ rows.push(row);
67
+ logger.info(`[${entry.name}] audit=${row.audit.status} review=${row.review.status}`);
68
+ }
69
+ const report = {
70
+ schema_version: 1,
71
+ generated_at: generatedAt,
72
+ vat_version: vatVersion,
73
+ vat_commit: vatCommit,
74
+ seed_file: seedPath,
75
+ flags: {
76
+ with_review: options.withReview === true,
77
+ debug: options.debug === true,
78
+ },
79
+ plugins: rows,
80
+ };
81
+ await writeRunReport(report, options.out);
82
+ logger.info(`Wrote run report to ${runDir}/summary.yaml`);
83
+ logger.info(` ${rows.length} plugins; durations recorded in summary.yaml`);
84
+ logger.debug(`Total scan duration: ${Date.now() - startTime}ms`);
85
+ }
86
+ catch (err) {
87
+ handleCommandError(err, logger, startTime, 'CorpusScan');
88
+ }
89
+ }
90
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/commands/corpus/scan.ts"],"names":[],"mappings":"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"}