@vibe-agent-toolkit/cli 0.1.42 → 0.2.0-rc.2
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 +24 -2
- package/dist/bin.js.map +1 -1
- package/dist/commands/audit/distributed-tree.d.ts +58 -0
- package/dist/commands/audit/distributed-tree.d.ts.map +1 -1
- package/dist/commands/audit/distributed-tree.js +68 -0
- package/dist/commands/audit/distributed-tree.js.map +1 -1
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +8 -2
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/build.js +1 -1
- package/dist/commands/cache/clear.d.ts +77 -0
- package/dist/commands/cache/clear.d.ts.map +1 -0
- package/dist/commands/cache/clear.js +162 -0
- package/dist/commands/cache/clear.js.map +1 -0
- package/dist/commands/cache/index.d.ts +68 -0
- package/dist/commands/cache/index.d.ts.map +1 -0
- package/dist/commands/cache/index.js +126 -0
- package/dist/commands/cache/index.js.map +1 -0
- package/dist/commands/claude/plugin/build.d.ts +15 -1
- package/dist/commands/claude/plugin/build.d.ts.map +1 -1
- package/dist/commands/claude/plugin/build.js +54 -9
- package/dist/commands/claude/plugin/build.js.map +1 -1
- package/dist/commands/claude/plugin/marketplace-json.d.ts +24 -9
- package/dist/commands/claude/plugin/marketplace-json.d.ts.map +1 -1
- package/dist/commands/claude/plugin/marketplace-json.js +10 -9
- package/dist/commands/claude/plugin/marketplace-json.js.map +1 -1
- package/dist/commands/inventory.d.ts.map +1 -1
- package/dist/commands/inventory.js +10 -3
- package/dist/commands/inventory.js.map +1 -1
- package/dist/commands/positional-args.js +1 -1
- package/dist/commands/positional-args.js.map +1 -1
- package/dist/commands/resources/index.d.ts.map +1 -1
- package/dist/commands/resources/index.js +7 -2
- package/dist/commands/resources/index.js.map +1 -1
- package/dist/commands/resources/validate.d.ts +15 -2
- package/dist/commands/resources/validate.d.ts.map +1 -1
- package/dist/commands/resources/validate.js +16 -1
- package/dist/commands/resources/validate.js.map +1 -1
- package/dist/commands/skills/package.d.ts +23 -2
- package/dist/commands/skills/package.d.ts.map +1 -1
- package/dist/commands/skills/package.js +36 -9
- package/dist/commands/skills/package.js.map +1 -1
- package/dist/commands/skills/scope-guard.js +1 -1
- package/dist/commands/skills/scope-guard.js.map +1 -1
- package/dist/commands/skills/skill-discovery.d.ts.map +1 -1
- package/dist/commands/skills/skill-discovery.js +5 -5
- package/dist/commands/skills/skill-discovery.js.map +1 -1
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +2 -1
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/verify.js +1 -1
- package/dist/utils/command-error.d.ts +19 -0
- package/dist/utils/command-error.d.ts.map +1 -1
- package/dist/utils/command-error.js +27 -0
- package/dist/utils/command-error.js.map +1 -1
- package/docs/index.md +21 -1
- package/package.json +16 -14
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clear.d.ts","sourceRoot":"","sources":["../../../src/commands/cache/clear.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAeH,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,iFAAiF;IACjF,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AASD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAcrC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAkBrF;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAYtF"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `vat cache clear` — delete VAT's shared temp-directory cache tree.
|
|
3
|
+
*
|
|
4
|
+
* "Recovery is rescan" was true but had no user-invocable form: a corrupt or
|
|
5
|
+
* merely stale cache could only be cleared by hand-deleting a path the docs
|
|
6
|
+
* described in prose. This is that path, named once.
|
|
7
|
+
*
|
|
8
|
+
* Scope is the WHOLE `<tmpdir>/.vat-cache/` tree, not just the parse tenant.
|
|
9
|
+
* That directory is shared — `external-links.json`, `auth-<user>/` and `parse/`
|
|
10
|
+
* all live under it — and "clear the cache" cannot honestly mean "clear one of
|
|
11
|
+
* the three". All of them are disposable by construction.
|
|
12
|
+
*/
|
|
13
|
+
import { promises as fs } from 'node:fs';
|
|
14
|
+
import { basename, dirname } from 'node:path';
|
|
15
|
+
import { parseCacheDirectory } from '@vibe-agent-toolkit/resources';
|
|
16
|
+
import { safePath } from '@vibe-agent-toolkit/utils';
|
|
17
|
+
import { handleCommandError } from '../../utils/command-error.js';
|
|
18
|
+
import { createLogger } from '../../utils/logger.js';
|
|
19
|
+
import { writeYamlOutput } from '../../utils/output.js';
|
|
20
|
+
/** The one name the shared cache root is allowed to have. See {@link vatCacheRoot}. */
|
|
21
|
+
const VAT_CACHE_DIR_NAME = '.vat-cache';
|
|
22
|
+
const EMPTY_USAGE = { entries: 0, bytes: 0 };
|
|
23
|
+
/**
|
|
24
|
+
* The shared cache root, `<tmpdir>/.vat-cache`.
|
|
25
|
+
*
|
|
26
|
+
* Derived from `parseCacheDirectory()` rather than re-joining `normalizedTmpdir()`
|
|
27
|
+
* with a third copy of the `.vat-cache` literal — one authority for where the
|
|
28
|
+
* tree lives, and the CLI stays out of the path-resolution business.
|
|
29
|
+
*
|
|
30
|
+
* The name check is not decoration: this function's return value is handed
|
|
31
|
+
* straight to a recursive delete, so if `parseCacheDirectory()` ever stopped
|
|
32
|
+
* carrying a `parse/` leaf, the naive parent would be the system temp directory
|
|
33
|
+
* itself. Refusing an unexpected shape turns that into an error instead of an
|
|
34
|
+
* `rm -rf /tmp`.
|
|
35
|
+
*
|
|
36
|
+
* ⚠ `@vibe-agent-toolkit/resources` now also exports a `vatCacheRoot()`, and
|
|
37
|
+
* `parseCacheDirectory()` is built from it — so on paper this derivation is a
|
|
38
|
+
* round trip. It is kept deliberately: the guard's job is to notice if that
|
|
39
|
+
* relationship ever changes, and importing the root directly would retire the
|
|
40
|
+
* only check standing between a shape change and a recursive delete of
|
|
41
|
+
* `<tmpdir>` itself. Deriving-then-verifying is the point.
|
|
42
|
+
*
|
|
43
|
+
* ✅ **It has now earned that keep.** When the cache gained a per-build
|
|
44
|
+
* namespace, the layout went from `.vat-cache/parse` to
|
|
45
|
+
* `.vat-cache/<namespace>/parse` and the old single-`dirname` derivation
|
|
46
|
+
* started returning `.vat-cache/<namespace>`. The name check turned a silent
|
|
47
|
+
* change of delete target into a loud refusal. Anyone tempted to simplify this
|
|
48
|
+
* into an import should read that sentence twice.
|
|
49
|
+
*
|
|
50
|
+
* @returns Absolute path to the cache root
|
|
51
|
+
* @throws {Error} If the derived ancestor is not named `.vat-cache`
|
|
52
|
+
*/
|
|
53
|
+
export function vatCacheRoot() {
|
|
54
|
+
const parseDir = parseCacheDirectory();
|
|
55
|
+
// Up two: `<root>/<namespace>/parse` → `<root>`. The namespace level is what
|
|
56
|
+
// makes this two rather than one; see the note above about why it is still
|
|
57
|
+
// derived and verified rather than imported.
|
|
58
|
+
const root = dirname(dirname(parseDir));
|
|
59
|
+
if (basename(root) !== VAT_CACHE_DIR_NAME) {
|
|
60
|
+
throw new Error(`Refusing to clear ${root}: expected a directory named ${VAT_CACHE_DIR_NAME} (derived from ${parseDir}).`);
|
|
61
|
+
}
|
|
62
|
+
return root;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Measure, then delete, an entire cache tree.
|
|
66
|
+
*
|
|
67
|
+
* Measured BEFORE the delete, because afterwards there is nothing left to count
|
|
68
|
+
* and a report of "removed: unknown" would make the command unverifiable.
|
|
69
|
+
*
|
|
70
|
+
* Deliberately reads no environment: `vat cache clear` runs whether or not
|
|
71
|
+
* caching is enabled for this process. A `VAT_CACHE=0` that also disarmed the
|
|
72
|
+
* cleanup would leave an operator with a cache they can neither use nor remove.
|
|
73
|
+
*
|
|
74
|
+
* @param cacheDir - Directory to remove, in full
|
|
75
|
+
* @returns What was removed
|
|
76
|
+
*/
|
|
77
|
+
export async function clearCacheDirectory(cacheDir) {
|
|
78
|
+
const entries = await readdirOrNull(cacheDir);
|
|
79
|
+
if (entries === null) {
|
|
80
|
+
return { status: 'success', cacheDir, existed: false, removed: [], entriesRemoved: 0, bytesRemoved: 0 };
|
|
81
|
+
}
|
|
82
|
+
const usage = await measureEntries(cacheDir, entries);
|
|
83
|
+
await fs.rm(cacheDir, { recursive: true, force: true });
|
|
84
|
+
return {
|
|
85
|
+
status: 'success',
|
|
86
|
+
cacheDir,
|
|
87
|
+
existed: true,
|
|
88
|
+
removed: entries.map((entry) => entry.name).sort((a, b) => a.localeCompare(b)),
|
|
89
|
+
entriesRemoved: usage.entries,
|
|
90
|
+
bytesRemoved: usage.bytes,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Command entry point: clear the real cache root and publish the report.
|
|
95
|
+
*
|
|
96
|
+
* @param options - Command options (only `--debug`, inherited from the root)
|
|
97
|
+
*/
|
|
98
|
+
export async function cacheClearCommand(options = {}) {
|
|
99
|
+
const startTime = Date.now();
|
|
100
|
+
const logger = createLogger(options.debug ? { debug: true } : {});
|
|
101
|
+
try {
|
|
102
|
+
const report = await clearCacheDirectory(vatCacheRoot());
|
|
103
|
+
logger.debug(`Cleared ${String(report.entriesRemoved)} cache entries from ${report.cacheDir}`);
|
|
104
|
+
writeYamlOutput(report);
|
|
105
|
+
process.exit(0);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
handleCommandError(error, logger, startTime, 'CacheClear');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* `readdir` that reports a missing directory as `null` rather than throwing.
|
|
113
|
+
*
|
|
114
|
+
* Only ENOENT is absorbed. EACCES on a directory that exists is a genuine
|
|
115
|
+
* failure — reporting it as "nothing to clear" would tell the operator their
|
|
116
|
+
* cache is gone when it is still on disk.
|
|
117
|
+
*/
|
|
118
|
+
async function readdirOrNull(dir) {
|
|
119
|
+
try {
|
|
120
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- path is the derived cache root or a caller-injected test directory
|
|
121
|
+
return await fs.readdir(dir, { withFileTypes: true });
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
if (error.code === 'ENOENT')
|
|
125
|
+
return null;
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/** Sum file count and bytes over already-listed directory entries. */
|
|
130
|
+
async function measureEntries(dir, entries) {
|
|
131
|
+
const usages = await Promise.all(entries.map(async (entry) => {
|
|
132
|
+
const child = safePath.join(dir, entry.name);
|
|
133
|
+
// Not `isFile()`: a symlink or socket is still an entry that is about to
|
|
134
|
+
// be removed, and counting only regular files would under-report it.
|
|
135
|
+
return entry.isDirectory() ? measureTree(child) : { entries: 1, bytes: await sizeOf(child) };
|
|
136
|
+
}));
|
|
137
|
+
return usages.reduce((total, usage) => ({ entries: total.entries + usage.entries, bytes: total.bytes + usage.bytes }), EMPTY_USAGE);
|
|
138
|
+
}
|
|
139
|
+
/** Recursive measure. A directory that vanished mid-walk contributes nothing. */
|
|
140
|
+
async function measureTree(dir) {
|
|
141
|
+
const entries = await readdirOrNull(dir);
|
|
142
|
+
return entries === null ? EMPTY_USAGE : measureEntries(dir, entries);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Size of one entry, without following symlinks.
|
|
146
|
+
*
|
|
147
|
+
* A file that disappears between the listing and the stat contributes 0 rather
|
|
148
|
+
* than failing the clear — the whole tree is about to be deleted anyway, and a
|
|
149
|
+
* concurrent vat run pruning its own temp file must not turn cleanup into an
|
|
150
|
+
* error.
|
|
151
|
+
*/
|
|
152
|
+
async function sizeOf(target) {
|
|
153
|
+
try {
|
|
154
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- path is inside the cache root being measured
|
|
155
|
+
const stats = await fs.lstat(target);
|
|
156
|
+
return stats.size;
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return 0;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=clear.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clear.js","sourceRoot":"","sources":["../../../src/commands/cache/clear.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache command group, plus the root-level `--no-cache` control surface.
|
|
3
|
+
*
|
|
4
|
+
* Both live here so the flag and the command that cleans up after it stay in one
|
|
5
|
+
* place: `--no-cache` decides whether this run *writes* to the caches, `vat cache
|
|
6
|
+
* clear` decides whether the caches *survive*.
|
|
7
|
+
*/
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
/**
|
|
10
|
+
* Root options this module reads. Commander represents `--no-cache` as the
|
|
11
|
+
* POSITIVE key `cache` — `true` by default, `false` only when the negated flag
|
|
12
|
+
* is passed. It NEVER produces `noCache`; reading that key is the exact bug that
|
|
13
|
+
* made three flags in this package silent no-ops (see
|
|
14
|
+
* `test/commands/commander-option-keys.test.ts`).
|
|
15
|
+
*/
|
|
16
|
+
export interface CacheControlOptions {
|
|
17
|
+
cache?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Register the root-level `--no-cache` flag and the hook that gives it effect.
|
|
21
|
+
*
|
|
22
|
+
* ## Why this sets an environment variable instead of plumbing a flag
|
|
23
|
+
*
|
|
24
|
+
* `vat validate`, `vat verify` and `vat build` enumerate nothing in their own
|
|
25
|
+
* process: each `spawnSync`s the vat binary once per phase, and the child is
|
|
26
|
+
* what parses the corpus. A flag parsed in the parent therefore never reaches
|
|
27
|
+
* the process whose caching it is supposed to control, whereas `process.env` is
|
|
28
|
+
* inherited by every child for free. `bin.ts` already leans on exactly that for
|
|
29
|
+
* `VAT_CONTEXT` / `VAT_CONTEXT_PATH`.
|
|
30
|
+
*
|
|
31
|
+
* `VAT_CACHE=0` is read by `ParseCache` (packages/resources/src/parse-cache.ts)
|
|
32
|
+
* per construction, never at module load, so setting it from a `preAction` hook
|
|
33
|
+
* — after Commander has parsed, before any command body runs — is observed.
|
|
34
|
+
*
|
|
35
|
+
* ## The collision with `vat resources validate --no-cache`
|
|
36
|
+
*
|
|
37
|
+
* This root program does NOT use `enablePositionalOptions()`, so Commander scans
|
|
38
|
+
* the WHOLE argv for root options, including everything after the subcommand
|
|
39
|
+
* name. That is the same mechanism that let a root `-v` shadow the subcommands'
|
|
40
|
+
* own `-v, --verbose` (see the incident recorded in `bin.ts`). Measured against
|
|
41
|
+
* commander 12: `vat resources validate docs --no-cache` leaves the ROOT with
|
|
42
|
+
* `cache: false` and the SUBCOMMAND with `cache: true` — the subcommand's
|
|
43
|
+
* identically-named flag is swallowed before it ever sees it, which would have
|
|
44
|
+
* silently re-enabled the external-URL cache the flag exists to bypass.
|
|
45
|
+
*
|
|
46
|
+
* Rather than break a shipped flag, the hook hands the value back down to
|
|
47
|
+
* whichever action command declares a `cache` option of its own. `--no-cache` is
|
|
48
|
+
* a superset — every cache off — so the handoff is a strengthening, never a
|
|
49
|
+
* reversal.
|
|
50
|
+
*
|
|
51
|
+
* @param program - The root program to register the flag and hook on
|
|
52
|
+
*/
|
|
53
|
+
export declare function registerCacheControl(program: Command): void;
|
|
54
|
+
/**
|
|
55
|
+
* Apply the root `--no-cache` decision: export it to child processes, and hand
|
|
56
|
+
* it down to an action command that declares its own `cache` option.
|
|
57
|
+
*
|
|
58
|
+
* Exported so a test can drive it from real parsed options rather than from a
|
|
59
|
+
* hand-built bag. Deliberately does nothing when the flag was not passed — a
|
|
60
|
+
* toggle that writes `VAT_CACHE=1` by default would be indistinguishable from
|
|
61
|
+
* one that is always on.
|
|
62
|
+
*
|
|
63
|
+
* @param rootOptions - Options bag from the ROOT program
|
|
64
|
+
* @param actionCommand - The command whose action is about to run
|
|
65
|
+
*/
|
|
66
|
+
export declare function applyCacheControl(rootOptions: CacheControlOptions, actionCommand: Command): void;
|
|
67
|
+
export declare function createCacheCommand(): Command;
|
|
68
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAM3D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,mBAAmB,EAAE,aAAa,EAAE,OAAO,GAAG,IAAI,CAWhG;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CA6D5C"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache command group, plus the root-level `--no-cache` control surface.
|
|
3
|
+
*
|
|
4
|
+
* Both live here so the flag and the command that cleans up after it stay in one
|
|
5
|
+
* place: `--no-cache` decides whether this run *writes* to the caches, `vat cache
|
|
6
|
+
* clear` decides whether the caches *survive*.
|
|
7
|
+
*/
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
import { cacheClearCommand } from './clear.js';
|
|
10
|
+
/**
|
|
11
|
+
* Register the root-level `--no-cache` flag and the hook that gives it effect.
|
|
12
|
+
*
|
|
13
|
+
* ## Why this sets an environment variable instead of plumbing a flag
|
|
14
|
+
*
|
|
15
|
+
* `vat validate`, `vat verify` and `vat build` enumerate nothing in their own
|
|
16
|
+
* process: each `spawnSync`s the vat binary once per phase, and the child is
|
|
17
|
+
* what parses the corpus. A flag parsed in the parent therefore never reaches
|
|
18
|
+
* the process whose caching it is supposed to control, whereas `process.env` is
|
|
19
|
+
* inherited by every child for free. `bin.ts` already leans on exactly that for
|
|
20
|
+
* `VAT_CONTEXT` / `VAT_CONTEXT_PATH`.
|
|
21
|
+
*
|
|
22
|
+
* `VAT_CACHE=0` is read by `ParseCache` (packages/resources/src/parse-cache.ts)
|
|
23
|
+
* per construction, never at module load, so setting it from a `preAction` hook
|
|
24
|
+
* — after Commander has parsed, before any command body runs — is observed.
|
|
25
|
+
*
|
|
26
|
+
* ## The collision with `vat resources validate --no-cache`
|
|
27
|
+
*
|
|
28
|
+
* This root program does NOT use `enablePositionalOptions()`, so Commander scans
|
|
29
|
+
* the WHOLE argv for root options, including everything after the subcommand
|
|
30
|
+
* name. That is the same mechanism that let a root `-v` shadow the subcommands'
|
|
31
|
+
* own `-v, --verbose` (see the incident recorded in `bin.ts`). Measured against
|
|
32
|
+
* commander 12: `vat resources validate docs --no-cache` leaves the ROOT with
|
|
33
|
+
* `cache: false` and the SUBCOMMAND with `cache: true` — the subcommand's
|
|
34
|
+
* identically-named flag is swallowed before it ever sees it, which would have
|
|
35
|
+
* silently re-enabled the external-URL cache the flag exists to bypass.
|
|
36
|
+
*
|
|
37
|
+
* Rather than break a shipped flag, the hook hands the value back down to
|
|
38
|
+
* whichever action command declares a `cache` option of its own. `--no-cache` is
|
|
39
|
+
* a superset — every cache off — so the handoff is a strengthening, never a
|
|
40
|
+
* reversal.
|
|
41
|
+
*
|
|
42
|
+
* @param program - The root program to register the flag and hook on
|
|
43
|
+
*/
|
|
44
|
+
export function registerCacheControl(program) {
|
|
45
|
+
program.option('--no-cache', "Disable VAT's disk caches for this run (also applies to spawned phases)");
|
|
46
|
+
program.hook('preAction', (_thisCommand, actionCommand) => {
|
|
47
|
+
applyCacheControl(program.opts(), actionCommand);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Apply the root `--no-cache` decision: export it to child processes, and hand
|
|
52
|
+
* it down to an action command that declares its own `cache` option.
|
|
53
|
+
*
|
|
54
|
+
* Exported so a test can drive it from real parsed options rather than from a
|
|
55
|
+
* hand-built bag. Deliberately does nothing when the flag was not passed — a
|
|
56
|
+
* toggle that writes `VAT_CACHE=1` by default would be indistinguishable from
|
|
57
|
+
* one that is always on.
|
|
58
|
+
*
|
|
59
|
+
* @param rootOptions - Options bag from the ROOT program
|
|
60
|
+
* @param actionCommand - The command whose action is about to run
|
|
61
|
+
*/
|
|
62
|
+
export function applyCacheControl(rootOptions, actionCommand) {
|
|
63
|
+
if (rootOptions.cache !== false)
|
|
64
|
+
return;
|
|
65
|
+
process.env['VAT_CACHE'] = '0';
|
|
66
|
+
// `attributeName()`, not `name()`: for `--no-cache` the latter returns
|
|
67
|
+
// 'no-cache', so a check written against it never matches and the handoff
|
|
68
|
+
// above becomes a no-op that looks like it works.
|
|
69
|
+
if (actionCommand.options.some((option) => option.attributeName() === 'cache')) {
|
|
70
|
+
actionCommand.setOptionValue('cache', false);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export function createCacheCommand() {
|
|
74
|
+
const cache = new Command('cache');
|
|
75
|
+
cache
|
|
76
|
+
.description("Manage VAT's shared on-disk caches in the system temp directory")
|
|
77
|
+
.helpCommand(false)
|
|
78
|
+
.addHelpText('after', `
|
|
79
|
+
Description:
|
|
80
|
+
VAT keeps three disposable caches under <tmpdir>/.vat-cache: parse facts
|
|
81
|
+
keyed by file content, external-URL validation results, and per-OS-user
|
|
82
|
+
authenticated-link content. None of them is durable — recovery is always
|
|
83
|
+
"rescan", and the OS temp purge is the eviction policy.
|
|
84
|
+
|
|
85
|
+
To run WITHOUT the caches rather than remove them, use --no-cache on any
|
|
86
|
+
command (or VAT_CACHE=0), which also applies to spawned phases.
|
|
87
|
+
|
|
88
|
+
Example:
|
|
89
|
+
$ vat cache clear # Reclaim the temp-directory cache tree
|
|
90
|
+
`);
|
|
91
|
+
cache
|
|
92
|
+
.command('clear')
|
|
93
|
+
.description('Delete the whole VAT cache tree from the system temp directory')
|
|
94
|
+
.action(async function () {
|
|
95
|
+
await cacheClearCommand(this.optsWithGlobals());
|
|
96
|
+
})
|
|
97
|
+
.addHelpText('after', `
|
|
98
|
+
Description:
|
|
99
|
+
Removes <tmpdir>/.vat-cache in its entirety — the parse cache, the
|
|
100
|
+
external-URL validation cache, and the per-OS-user authenticated-link cache.
|
|
101
|
+
Every one of them is disposable by design: the next run repopulates what it
|
|
102
|
+
needs, so the only cost of clearing is one cold pass.
|
|
103
|
+
|
|
104
|
+
Runs regardless of --no-cache / VAT_CACHE=0. Turning caching off must not
|
|
105
|
+
disarm the one command that reclaims the space.
|
|
106
|
+
|
|
107
|
+
A cache directory that does not exist is not an error — nothing to remove is
|
|
108
|
+
a successful clear.
|
|
109
|
+
|
|
110
|
+
Output:
|
|
111
|
+
- cacheDir: absolute path that was targeted
|
|
112
|
+
- existed: whether the directory was there at all
|
|
113
|
+
- removed: top-level entries that were deleted
|
|
114
|
+
- entriesRemoved / bytesRemoved: file count and total size, measured before
|
|
115
|
+
deletion
|
|
116
|
+
|
|
117
|
+
Exit Codes:
|
|
118
|
+
0 - Cache cleared (or already absent)
|
|
119
|
+
2 - Could not remove the cache (permissions, busy file)
|
|
120
|
+
|
|
121
|
+
Example:
|
|
122
|
+
$ vat cache clear # Reclaim the temp-directory cache tree
|
|
123
|
+
`);
|
|
124
|
+
return cache;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,iBAAiB,EAA0B,MAAM,YAAY,CAAC;AAavE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,yEAAyE,CAAC,CAAC;IAExG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,YAAY,EAAE,aAAa,EAAE,EAAE;QACxD,iBAAiB,CAAC,OAAO,CAAC,IAAI,EAAuB,EAAE,aAAa,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAAgC,EAAE,aAAsB;IACxF,IAAI,WAAW,CAAC,KAAK,KAAK,KAAK;QAAE,OAAO;IAExC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,GAAG,CAAC;IAE/B,uEAAuE;IACvE,0EAA0E;IAC1E,kDAAkD;IAClD,IAAI,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,aAAa,EAAE,KAAK,OAAO,CAAC,EAAE,CAAC;QAC/E,aAAa,CAAC,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,MAAM,KAAK,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAEnC,KAAK;SACF,WAAW,CAAC,iEAAiE,CAAC;SAC9E,WAAW,CAAC,KAAK,CAAC;SAClB,WAAW,CACV,OAAO,EACP;;;;;;;;;;;;CAYL,CACI,CAAC;IAEJ,KAAK;SACF,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,gEAAgE,CAAC;SAC7E,MAAM,CAAC,KAAK;QACX,MAAM,iBAAiB,CAAC,IAAI,CAAC,eAAe,EAAuB,CAAC,CAAC;IACvE,CAAC,CAAC;SACD,WAAW,CACV,OAAO,EACP;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BL,CACI,CAAC;IAEJ,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { type SeverityCounts } from '@vibe-agent-toolkit/agent-schema';
|
|
10
10
|
import { type DeclaredEvalSuite, type PackageSkillResult } from '@vibe-agent-toolkit/agent-skills';
|
|
11
|
-
import type { ResourceRegistry, SkillsConfig } from '@vibe-agent-toolkit/resources';
|
|
11
|
+
import type { ExternalPluginSource, ResourceRegistry, SkillsConfig } from '@vibe-agent-toolkit/resources';
|
|
12
12
|
import { Command } from 'commander';
|
|
13
13
|
import { createLogger } from '../../../utils/logger.js';
|
|
14
14
|
export interface PluginBuildCommandOptions {
|
|
@@ -52,11 +52,25 @@ interface PluginBuildResult {
|
|
|
52
52
|
*/
|
|
53
53
|
issueCounts: SeverityCounts;
|
|
54
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* A plugin entry that references another marketplace/repo's plugin instead of
|
|
57
|
+
* being built locally (`pluginDef.externalSource` is set). VAT never creates a
|
|
58
|
+
* directory or writes a plugin.json for it — the empty-plugin guard, tree-copy,
|
|
59
|
+
* skills packaging, and files[] mapping in {@link buildPlugin} all assume local
|
|
60
|
+
* content, none of which applies here.
|
|
61
|
+
*/
|
|
62
|
+
export interface ExternalPluginBuildResult {
|
|
63
|
+
pluginName: string;
|
|
64
|
+
pluginVersion: string | undefined;
|
|
65
|
+
source: ExternalPluginSource;
|
|
66
|
+
}
|
|
55
67
|
export interface MarketplaceBuildResult {
|
|
56
68
|
name: string;
|
|
57
69
|
status: 'built' | 'error';
|
|
58
70
|
reason?: string;
|
|
59
71
|
plugins: PluginBuildResult[];
|
|
72
|
+
/** Plugins referenced via `externalSource` — see {@link ExternalPluginBuildResult}. */
|
|
73
|
+
externalPlugins: ExternalPluginBuildResult[];
|
|
60
74
|
}
|
|
61
75
|
export declare function createPluginBuildCommand(): Command;
|
|
62
76
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../../src/commands/claude/plugin/build.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,EAAmB,KAAK,cAAc,EAAwB,MAAM,kCAAkC,CAAC;AAC9G,OAAO,EAA8M,KAAK,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAC/S,OAAO,KAAK,EAAyD,gBAAgB,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../../src/commands/claude/plugin/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -53,6 +53,12 @@ Description:
|
|
|
53
53
|
- Merges plugin.json with author, description, and VAT-supplied metadata
|
|
54
54
|
- Generates marketplace.json with plugin registry and relative source paths
|
|
55
55
|
|
|
56
|
+
A plugin entry with externalSource is REFERENCED, not built: no local dir,
|
|
57
|
+
tree-copy, or skills packaging — its externalSource object (github/url/npm/pip)
|
|
58
|
+
is emitted verbatim as that entry's marketplace.json source, so it resolves to
|
|
59
|
+
wherever the other marketplace/repo actually publishes it. Use this to
|
|
60
|
+
cherry-pick a plugin from one marketplace into another without vendoring it.
|
|
61
|
+
|
|
56
62
|
Output structure:
|
|
57
63
|
dist/.claude/plugins/marketplaces/<marketplace>/
|
|
58
64
|
.claude-plugin/marketplace.json
|
|
@@ -214,6 +220,7 @@ async function pluginBuildCommand(options) {
|
|
|
214
220
|
});
|
|
215
221
|
const duration = Date.now() - startTime;
|
|
216
222
|
const totalPlugins = results.flatMap((r) => r.plugins).length;
|
|
223
|
+
const totalExternalPlugins = results.flatMap((r) => r.externalPlugins).length;
|
|
217
224
|
const totalSkills = results.flatMap((r) => r.plugins).flatMap((p) => p.skillsCopied).length;
|
|
218
225
|
const allPlugins = results.flatMap((r) => r.plugins);
|
|
219
226
|
// KNOWN, DELIBERATELY NOT FIXED — this lane NAMES NOTHING. Every level of this
|
|
@@ -235,6 +242,7 @@ async function pluginBuildCommand(options) {
|
|
|
235
242
|
issueCounts: sumSeverityCounts(allPlugins.map((p) => p.issueCounts)),
|
|
236
243
|
marketplacesBuilt: results.filter((r) => r.status === 'built').length,
|
|
237
244
|
pluginsBuilt: totalPlugins,
|
|
245
|
+
pluginsReferenced: totalExternalPlugins,
|
|
238
246
|
skillsPackaged: totalSkills,
|
|
239
247
|
marketplaces: results.map((r) => ({
|
|
240
248
|
name: r.name,
|
|
@@ -263,6 +271,14 @@ async function pluginBuildCommand(options) {
|
|
|
263
271
|
localSkillsPackaged: p.localSkillsPackaged,
|
|
264
272
|
issueCounts: p.issueCounts,
|
|
265
273
|
})),
|
|
274
|
+
// Referenced, not built — no dir, no counts to report. `source` is the
|
|
275
|
+
// same object emitted verbatim into marketplace.json, so the report and
|
|
276
|
+
// the artifact can never disagree about what a reference points at.
|
|
277
|
+
externalPlugins: r.externalPlugins.map((p) => ({
|
|
278
|
+
name: p.pluginName,
|
|
279
|
+
...(p.pluginVersion ? { version: p.pluginVersion } : {}),
|
|
280
|
+
source: p.source,
|
|
281
|
+
})),
|
|
266
282
|
})),
|
|
267
283
|
duration: `${duration}ms`,
|
|
268
284
|
});
|
|
@@ -299,6 +315,7 @@ async function copyDistributionFiles(marketplaceDir, configDir, config, logger)
|
|
|
299
315
|
async function buildMarketplace(input) {
|
|
300
316
|
const { name, config, availableSkills, configDir, skillsConfig, rootVersion, registry, projectSkills, logger, verbose } = input;
|
|
301
317
|
const plugins = [];
|
|
318
|
+
const externalPlugins = [];
|
|
302
319
|
// Clean stale marketplace directory before rebuilding — removes orphaned plugins
|
|
303
320
|
const marketplaceBaseDir = safePath.join(configDir, 'dist', '.claude', 'plugins', 'marketplaces', name);
|
|
304
321
|
// eslint-disable-next-line security/detect-non-literal-fs-filename -- resolved from config
|
|
@@ -308,6 +325,23 @@ async function buildMarketplace(input) {
|
|
|
308
325
|
// Marketplace-level skills filter restricts pool available to plugins that use "*"
|
|
309
326
|
const marketplaceAvailable = resolveMarketplaceAvailableSkills(config, availableSkills);
|
|
310
327
|
for (const pluginDef of config.plugins) {
|
|
328
|
+
// externalSource plugins are never built or copied — they route straight
|
|
329
|
+
// to a marketplace.json entry referencing the other repo. Every phase
|
|
330
|
+
// buildPlugin runs (empty-plugin guard, tree-copy, skills packaging,
|
|
331
|
+
// plugin.json merge) assumes local content, none of which exists here.
|
|
332
|
+
if (pluginDef.externalSource) {
|
|
333
|
+
logger.info(` Referencing external plugin: ${pluginDef.name} (${pluginDef.externalSource.source})`);
|
|
334
|
+
// No rootVersion fallback here (unlike a built plugin): this marketplace
|
|
335
|
+
// does not own or build the referenced plugin, so tagging it with THIS
|
|
336
|
+
// repo's package.json version would misrepresent what version the other
|
|
337
|
+
// repo actually publishes. Only an explicit config version applies.
|
|
338
|
+
externalPlugins.push({
|
|
339
|
+
pluginName: pluginDef.name,
|
|
340
|
+
pluginVersion: pluginDef.version,
|
|
341
|
+
source: pluginDef.externalSource,
|
|
342
|
+
});
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
311
345
|
const pluginResult = await buildPlugin({
|
|
312
346
|
marketplaceName: name,
|
|
313
347
|
pluginDef,
|
|
@@ -328,23 +362,34 @@ async function buildMarketplace(input) {
|
|
|
328
362
|
const claudePluginDir = safePath.join(marketplaceDir, CLAUDE_PLUGIN_DIRNAME);
|
|
329
363
|
// eslint-disable-next-line security/detect-non-literal-fs-filename -- resolved paths
|
|
330
364
|
await mkdir(claudePluginDir, { recursive: true });
|
|
331
|
-
// Each entry's author is the plugin's own MERGED author (see
|
|
332
|
-
// so marketplace.json and that plugin's plugin.json
|
|
365
|
+
// Each BUILT entry's author is the plugin's own MERGED author (see
|
|
366
|
+
// marketplace-json.ts), so marketplace.json and that plugin's plugin.json
|
|
367
|
+
// cannot disagree. External entries carry no author — see marketplace-json.ts.
|
|
333
368
|
const marketplaceJson = buildMarketplaceJson({
|
|
334
369
|
name,
|
|
335
370
|
owner: config.owner,
|
|
336
|
-
plugins:
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
371
|
+
plugins: [
|
|
372
|
+
...plugins.map((p) => ({
|
|
373
|
+
kind: 'built',
|
|
374
|
+
name: p.pluginName,
|
|
375
|
+
description: config.plugins.find((pd) => pd.name === p.pluginName)?.description,
|
|
376
|
+
version: p.pluginVersion,
|
|
377
|
+
author: p.pluginAuthor,
|
|
378
|
+
})),
|
|
379
|
+
...externalPlugins.map((p) => ({
|
|
380
|
+
kind: 'external',
|
|
381
|
+
name: p.pluginName,
|
|
382
|
+
description: config.plugins.find((pd) => pd.name === p.pluginName)?.description,
|
|
383
|
+
version: p.pluginVersion,
|
|
384
|
+
source: p.source,
|
|
385
|
+
})),
|
|
386
|
+
],
|
|
342
387
|
});
|
|
343
388
|
// eslint-disable-next-line security/detect-non-literal-fs-filename -- resolved paths
|
|
344
389
|
await writeFile(safePath.join(claudePluginDir, 'marketplace.json'), JSON.stringify(marketplaceJson, null, 2));
|
|
345
390
|
logger.info(` .claude-plugin/marketplace.json`);
|
|
346
391
|
await copyDistributionFiles(marketplaceDir, configDir, config, logger);
|
|
347
|
-
return { name, status: 'built', plugins };
|
|
392
|
+
return { name, status: 'built', plugins, externalPlugins };
|
|
348
393
|
}
|
|
349
394
|
/**
|
|
350
395
|
* Resolve which pool skills are available to plugins in this marketplace.
|