@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.
- package/dist/bin.js +4 -0
- package/dist/bin.js.map +1 -1
- package/dist/commands/audit/git-url-clone.d.ts +32 -0
- package/dist/commands/audit/git-url-clone.d.ts.map +1 -0
- package/dist/commands/audit/git-url-clone.js +135 -0
- package/dist/commands/audit/git-url-clone.js.map +1 -0
- package/dist/commands/audit/provenance.d.ts +33 -0
- package/dist/commands/audit/provenance.d.ts.map +1 -0
- package/dist/commands/audit/provenance.js +57 -0
- package/dist/commands/audit/provenance.js.map +1 -0
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +218 -72
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/claude/marketplace/validate.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/validate.js +2 -1
- package/dist/commands/claude/marketplace/validate.js.map +1 -1
- package/dist/commands/corpus/index.d.ts +6 -0
- package/dist/commands/corpus/index.d.ts.map +1 -0
- package/dist/commands/corpus/index.js +53 -0
- package/dist/commands/corpus/index.js.map +1 -0
- package/dist/commands/corpus/report.d.ts +75 -0
- package/dist/commands/corpus/report.d.ts.map +1 -0
- package/dist/commands/corpus/report.js +83 -0
- package/dist/commands/corpus/report.js.map +1 -0
- package/dist/commands/corpus/runner.d.ts +24 -0
- package/dist/commands/corpus/runner.d.ts.map +1 -0
- package/dist/commands/corpus/runner.js +246 -0
- package/dist/commands/corpus/runner.js.map +1 -0
- package/dist/commands/corpus/scan.d.ts +15 -0
- package/dist/commands/corpus/scan.d.ts.map +1 -0
- package/dist/commands/corpus/scan.js +90 -0
- package/dist/commands/corpus/scan.js.map +1 -0
- package/dist/commands/corpus/seed.d.ts +178 -0
- package/dist/commands/corpus/seed.d.ts.map +1 -0
- package/dist/commands/corpus/seed.js +63 -0
- package/dist/commands/corpus/seed.js.map +1 -0
- package/dist/commands/inventory.d.ts +17 -0
- package/dist/commands/inventory.d.ts.map +1 -0
- package/dist/commands/inventory.js +90 -0
- package/dist/commands/inventory.js.map +1 -0
- package/dist/utils/git-url.d.ts +43 -0
- package/dist/utils/git-url.d.ts.map +1 -0
- package/dist/utils/git-url.js +135 -0
- package/dist/utils/git-url.js.map +1 -0
- package/docs/audit.md +54 -3
- 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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"}
|