@vibe-agent-toolkit/cli 0.1.33 → 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/hierarchical-output.js +2 -2
- package/dist/commands/audit/hierarchical-output.js.map +1 -1
- 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 +257 -34
- 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/claude/plugin/build.d.ts +4 -3
- package/dist/commands/claude/plugin/build.d.ts.map +1 -1
- package/dist/commands/claude/plugin/build.js +178 -71
- package/dist/commands/claude/plugin/build.js.map +1 -1
- package/dist/commands/claude/plugin/plugin-files.d.ts +19 -0
- package/dist/commands/claude/plugin/plugin-files.d.ts.map +1 -0
- package/dist/commands/claude/plugin/plugin-files.js +53 -0
- package/dist/commands/claude/plugin/plugin-files.js.map +1 -0
- package/dist/commands/claude/plugin/plugin-json-merge.d.ts +29 -0
- package/dist/commands/claude/plugin/plugin-json-merge.d.ts.map +1 -0
- package/dist/commands/claude/plugin/plugin-json-merge.js +76 -0
- package/dist/commands/claude/plugin/plugin-json-merge.js.map +1 -0
- package/dist/commands/claude/plugin/plugin-validators.d.ts +13 -0
- package/dist/commands/claude/plugin/plugin-validators.d.ts.map +1 -0
- package/dist/commands/claude/plugin/plugin-validators.js +59 -0
- package/dist/commands/claude/plugin/plugin-validators.js.map +1 -0
- package/dist/commands/claude/plugin/tree-copy.d.ts +23 -0
- package/dist/commands/claude/plugin/tree-copy.d.ts.map +1 -0
- package/dist/commands/claude/plugin/tree-copy.js +68 -0
- package/dist/commands/claude/plugin/tree-copy.js.map +1 -0
- 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 +60 -3
- package/package.json +11 -11
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build-time validators for plugin declarations.
|
|
3
|
+
*
|
|
4
|
+
* - verifyPluginDirCaseMatch: guards against macOS/Windows case-insensitive FS drift
|
|
5
|
+
* (plugin: "foo-bar" -> plugins/Foo-Bar/ locally would break on Linux CI).
|
|
6
|
+
* - verifyNoCaseCollidingPluginNames: rejects pairs whose toLowerCase() collides.
|
|
7
|
+
* - parsePluginJsonFiles: parse-only JSON validation of hooks.json + .mcp.json
|
|
8
|
+
* (deep schema validation is Claude runtime's job).
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync } from 'node:fs';
|
|
11
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
12
|
+
import { safePath } from '@vibe-agent-toolkit/utils';
|
|
13
|
+
export async function verifyPluginDirCaseMatch(projectRoot, pluginName) {
|
|
14
|
+
const pluginsBase = safePath.join(projectRoot, 'plugins');
|
|
15
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- controlled path
|
|
16
|
+
if (!existsSync(pluginsBase))
|
|
17
|
+
return;
|
|
18
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- controlled path
|
|
19
|
+
const entries = await readdir(pluginsBase, { withFileTypes: true });
|
|
20
|
+
const matchInsensitive = entries.find((e) => e.isDirectory() && e.name.toLowerCase() === pluginName.toLowerCase());
|
|
21
|
+
if (matchInsensitive && matchInsensitive.name !== pluginName) {
|
|
22
|
+
throw new Error(`Plugin "${pluginName}" declared in config, but on-disk directory is "plugins/${matchInsensitive.name}/". ` +
|
|
23
|
+
`Names must match exactly (case-sensitive). This check catches macOS/Windows case-insensitive FS drift ` +
|
|
24
|
+
`that would break on Linux CI. Rename the directory or the config entry to match.`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function verifyNoCaseCollidingPluginNames(names) {
|
|
28
|
+
const seen = new Map();
|
|
29
|
+
for (const name of names) {
|
|
30
|
+
const key = name.toLowerCase();
|
|
31
|
+
const prior = seen.get(key);
|
|
32
|
+
if (prior === name) {
|
|
33
|
+
throw new Error(`Plugin name "${name}" is declared more than once across marketplaces. ` +
|
|
34
|
+
`Plugin names must be globally unique within a repo; rename one.`);
|
|
35
|
+
}
|
|
36
|
+
if (prior && prior !== name) {
|
|
37
|
+
throw new Error(`Plugin names "${prior}" and "${name}" differ only in case. ` +
|
|
38
|
+
`They would collide on case-insensitive filesystems; rename one.`);
|
|
39
|
+
}
|
|
40
|
+
seen.set(key, name);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function parseJsonFileIfPresent(path, label) {
|
|
44
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- resolved path
|
|
45
|
+
if (!existsSync(path))
|
|
46
|
+
return;
|
|
47
|
+
try {
|
|
48
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- resolved path
|
|
49
|
+
JSON.parse(await readFile(path, 'utf-8'));
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
throw new Error(`${label} is not valid JSON: ${e.message}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export async function parsePluginJsonFiles(pluginSourceDir) {
|
|
56
|
+
await parseJsonFileIfPresent(safePath.join(pluginSourceDir, 'hooks', 'hooks.json'), 'hooks/hooks.json');
|
|
57
|
+
await parseJsonFileIfPresent(safePath.join(pluginSourceDir, '.mcp.json'), '.mcp.json');
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=plugin-validators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-validators.js","sourceRoot":"","sources":["../../../../src/commands/claude/plugin/plugin-validators.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,WAAmB,EACnB,UAAkB;IAElB,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAC1D,sFAAsF;IACtF,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO;IAErC,sFAAsF;IACtF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,MAAM,gBAAgB,GAAG,OAAO,CAAC,IAAI,CACnC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,UAAU,CAAC,WAAW,EAAE,CAC5E,CAAC;IACF,IAAI,gBAAgB,IAAI,gBAAgB,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC7D,MAAM,IAAI,KAAK,CACb,WAAW,UAAU,2DAA2D,gBAAgB,CAAC,IAAI,MAAM;YACzG,wGAAwG;YACxG,kFAAkF,CACrF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gCAAgC,CAAC,KAAwB;IACvE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CACb,gBAAgB,IAAI,oDAAoD;gBACtE,iEAAiE,CACpE,CAAC;QACJ,CAAC;QACD,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CACb,iBAAiB,KAAK,UAAU,IAAI,yBAAyB;gBAC3D,iEAAiE,CACpE,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,sBAAsB,CAAC,IAAY,EAAE,KAAa;IAC/D,oFAAoF;IACpF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO;IAC9B,IAAI,CAAC;QACH,oFAAoF;QACpF,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,uBAAwB,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;IACzE,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,eAAuB;IAChE,MAAM,sBAAsB,CAC1B,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,OAAO,EAAE,YAAY,CAAC,EACrD,kBAAkB,CACnB,CAAC;IACF,MAAM,sBAAsB,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,EAAE,WAAW,CAAC,CAAC;AACzF,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tree-copy stream for plugin build.
|
|
3
|
+
*
|
|
4
|
+
* Copies everything under <sourceDir> to <destDir>, except:
|
|
5
|
+
* - .claude-plugin/ (owned by plugin.json merge-write)
|
|
6
|
+
*
|
|
7
|
+
* Respects .gitignore via crawlDirectory (respectGitignore: true, the default).
|
|
8
|
+
* Returns counts keyed to the spec's YAML summary extension.
|
|
9
|
+
*/
|
|
10
|
+
export interface TreeCopyOptions {
|
|
11
|
+
sourceDir: string;
|
|
12
|
+
destDir: string;
|
|
13
|
+
warn?: (message: string) => void;
|
|
14
|
+
}
|
|
15
|
+
export interface TreeCopyResult {
|
|
16
|
+
commandsCopied: number;
|
|
17
|
+
hooksCopied: number;
|
|
18
|
+
agentsCopied: number;
|
|
19
|
+
mcpCopied: number;
|
|
20
|
+
filesCopied: number;
|
|
21
|
+
}
|
|
22
|
+
export declare function treeCopyPlugin(options: TreeCopyOptions): Promise<TreeCopyResult>;
|
|
23
|
+
//# sourceMappingURL=tree-copy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-copy.d.ts","sourceRoot":"","sources":["../../../../src/commands/claude/plugin/tree-copy.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAYD,wBAAsB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAiDtF"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tree-copy stream for plugin build.
|
|
3
|
+
*
|
|
4
|
+
* Copies everything under <sourceDir> to <destDir>, except:
|
|
5
|
+
* - .claude-plugin/ (owned by plugin.json merge-write)
|
|
6
|
+
*
|
|
7
|
+
* Respects .gitignore via crawlDirectory (respectGitignore: true, the default).
|
|
8
|
+
* Returns counts keyed to the spec's YAML summary extension.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync } from 'node:fs';
|
|
11
|
+
import { copyFile, mkdir } from 'node:fs/promises';
|
|
12
|
+
import { dirname } from 'node:path';
|
|
13
|
+
import { crawlDirectory, safePath, toForwardSlash } from '@vibe-agent-toolkit/utils';
|
|
14
|
+
const EXCLUDE_PATTERNS = ['.claude-plugin/**'];
|
|
15
|
+
function classifyRelative(rel) {
|
|
16
|
+
if (rel.startsWith('commands/'))
|
|
17
|
+
return 'commandsCopied';
|
|
18
|
+
if (rel.startsWith('hooks/'))
|
|
19
|
+
return 'hooksCopied';
|
|
20
|
+
if (rel.startsWith('agents/'))
|
|
21
|
+
return 'agentsCopied';
|
|
22
|
+
if (rel === '.mcp.json')
|
|
23
|
+
return 'mcpCopied';
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
export async function treeCopyPlugin(options) {
|
|
27
|
+
const { sourceDir, destDir, warn } = options;
|
|
28
|
+
const result = {
|
|
29
|
+
commandsCopied: 0,
|
|
30
|
+
hooksCopied: 0,
|
|
31
|
+
agentsCopied: 0,
|
|
32
|
+
mcpCopied: 0,
|
|
33
|
+
filesCopied: 0,
|
|
34
|
+
};
|
|
35
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- sourceDir resolved from config
|
|
36
|
+
if (!existsSync(sourceDir)) {
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
const authorMarketplaceJson = safePath.join(sourceDir, '.claude-plugin', 'marketplace.json');
|
|
40
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- controlled path
|
|
41
|
+
if (existsSync(authorMarketplaceJson) && warn) {
|
|
42
|
+
warn(`Ignoring ${toForwardSlash(authorMarketplaceJson)}: marketplace.json is VAT-generated ` +
|
|
43
|
+
`at the marketplace level and cannot be supplied per-plugin.`);
|
|
44
|
+
}
|
|
45
|
+
const files = await crawlDirectory({
|
|
46
|
+
baseDir: sourceDir,
|
|
47
|
+
include: ['**/*'],
|
|
48
|
+
exclude: EXCLUDE_PATTERNS,
|
|
49
|
+
absolute: true,
|
|
50
|
+
filesOnly: true,
|
|
51
|
+
respectGitignore: true,
|
|
52
|
+
dot: true,
|
|
53
|
+
});
|
|
54
|
+
for (const absPath of files) {
|
|
55
|
+
const rel = toForwardSlash(safePath.relative(sourceDir, absPath));
|
|
56
|
+
const target = safePath.join(destDir, rel);
|
|
57
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- dest resolved from sourceDir+relative
|
|
58
|
+
await mkdir(dirname(target), { recursive: true });
|
|
59
|
+
await copyFile(absPath, target);
|
|
60
|
+
result.filesCopied += 1;
|
|
61
|
+
const bucket = classifyRelative(rel);
|
|
62
|
+
if (bucket) {
|
|
63
|
+
result[bucket] += 1;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=tree-copy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-copy.js","sourceRoot":"","sources":["../../../../src/commands/claude/plugin/tree-copy.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAgBrF,MAAM,gBAAgB,GAAG,CAAC,mBAAmB,CAAC,CAAC;AAE/C,SAAS,gBAAgB,CAAC,GAAW;IACnC,IAAI,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,gBAAgB,CAAC;IACzD,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,aAAa,CAAC;IACnD,IAAI,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,cAAc,CAAC;IACrD,IAAI,GAAG,KAAK,WAAW;QAAE,OAAO,WAAW,CAAC;IAC5C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAwB;IAC3D,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IAC7C,MAAM,MAAM,GAAmB;QAC7B,cAAc,EAAE,CAAC;QACjB,WAAW,EAAE,CAAC;QACd,YAAY,EAAE,CAAC;QACf,SAAS,EAAE,CAAC;QACZ,WAAW,EAAE,CAAC;KACf,CAAC;IAEF,qGAAqG;IACrG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,qBAAqB,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;IAC7F,sFAAsF;IACtF,IAAI,UAAU,CAAC,qBAAqB,CAAC,IAAI,IAAI,EAAE,CAAC;QAC9C,IAAI,CACF,YAAY,cAAc,CAAC,qBAAqB,CAAC,sCAAsC;YACrF,6DAA6D,CAChE,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC;QACjC,OAAO,EAAE,SAAS;QAClB,OAAO,EAAE,CAAC,MAAM,CAAC;QACjB,OAAO,EAAE,gBAAgB;QACzB,QAAQ,EAAE,IAAI;QACd,SAAS,EAAE,IAAI;QACf,gBAAgB,EAAE,IAAI;QACtB,GAAG,EAAE,IAAI;KACV,CAAC,CAAC;IAEH,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;QAClE,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC3C,4GAA4G;QAC5G,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAChC,MAAM,CAAC,WAAW,IAAI,CAAC,CAAC;QAExB,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +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,CAoD7C"}
|
|
@@ -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"}
|