vectorvesper 2.1.0 → 2.3.0
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/hooks.json +2339 -269
- package/dist/index.js +200 -67
- package/dist/mcp-H5YYBZ5V.js +300 -0
- package/dist/{server-ROPGTSDI.js → server-KJ3YQ7G4.js} +531 -37
- package/package.json +1 -1
- package/dist/mcp-OURIIFET.js +0 -116
package/dist/index.js
CHANGED
|
@@ -23,8 +23,122 @@ import { Command } from "commander";
|
|
|
23
23
|
// src/commands/init.ts
|
|
24
24
|
import { intro, outro, select, text, confirm, isCancel } from "@clack/prompts";
|
|
25
25
|
import pc from "picocolors";
|
|
26
|
+
import fs2 from "fs";
|
|
27
|
+
import path2 from "path";
|
|
28
|
+
|
|
29
|
+
// src/utils/agent-rules.ts
|
|
26
30
|
import fs from "fs";
|
|
27
31
|
import path from "path";
|
|
32
|
+
var BEGIN = "<!-- BEGIN:vectorvesper -->";
|
|
33
|
+
var END = "<!-- END:vectorvesper -->";
|
|
34
|
+
function renderBlock({ targetDir, alias, components = [] }) {
|
|
35
|
+
const installed = components.length > 0 ? components.slice().sort().map((c) => `\`${c}\``).join(", ") : "_none yet_";
|
|
36
|
+
return `# Vector Vesper motion
|
|
37
|
+
|
|
38
|
+
<!-- Managed by \`vv init\`. Put your own rules OUTSIDE this block \u2014 \`vv init\`
|
|
39
|
+
rewrites everything between the markers. \`vv add\` only touches the
|
|
40
|
+
"Installed" line below. -->
|
|
41
|
+
|
|
42
|
+
This project uses [\`@vectorvesper/motion\`](https://vectorvesper.dev/docs) \u2014 a
|
|
43
|
+
motion runtime where every animation shares **one frame loop**, one pointer and
|
|
44
|
+
scroll sensor layer, and one performance budget.
|
|
45
|
+
|
|
46
|
+
## The rule that matters
|
|
47
|
+
|
|
48
|
+
**Never start a \`requestAnimationFrame\` loop.** Subscribe to the shared
|
|
49
|
+
conductor instead:
|
|
50
|
+
|
|
51
|
+
\`\`\`ts
|
|
52
|
+
import { getConductor } from "@vectorvesper/motion";
|
|
53
|
+
|
|
54
|
+
const stop = getConductor().subscribe("render", (dt) => {
|
|
55
|
+
// dt is seconds since this subscriber last ran
|
|
56
|
+
});
|
|
57
|
+
// call stop() on cleanup \u2014 always
|
|
58
|
+
\`\`\`
|
|
59
|
+
|
|
60
|
+
A private loop runs outside the shared budget, so it cannot be throttled,
|
|
61
|
+
prioritised or shed when frames run long. Nothing errors when this is wrong;
|
|
62
|
+
it shows up later as jank on mid-range devices.
|
|
63
|
+
|
|
64
|
+
Same rule for pointer and scroll: read \`getSensorBus().state\` rather than
|
|
65
|
+
attaching your own listeners.
|
|
66
|
+
|
|
67
|
+
## Where things are
|
|
68
|
+
|
|
69
|
+
- Installed components: \`${targetDir}\`, imported from \`${alias}\`
|
|
70
|
+
- Installed: ${installed}
|
|
71
|
+
- Never edit files in that directory expecting updates to survive \u2014 \`vv add\`
|
|
72
|
+
rewrites them.
|
|
73
|
+
|
|
74
|
+
## Before writing animation code
|
|
75
|
+
|
|
76
|
+
If the \`vectorvesper\` MCP server is connected, use it \u2014 it has the full
|
|
77
|
+
contract for every primitive:
|
|
78
|
+
|
|
79
|
+
- \`search\` or \`list_hooks\` \u2014 find the primitive that already does this
|
|
80
|
+
- \`get_hook\` \u2014 its lane, what it conflicts with, when *not* to use it
|
|
81
|
+
- \`list_patterns\` / \`get_pattern\` \u2014 for anything combining primitives
|
|
82
|
+
(scrollytelling, marquees, adaptive heroes)
|
|
83
|
+
- \`check_motion\` \u2014 run it on files you changed; it catches unmanaged loops,
|
|
84
|
+
missing cleanup, per-frame state writes and missing reduced-motion guards
|
|
85
|
+
|
|
86
|
+
If it is not connected, the same material is at
|
|
87
|
+
<https://vectorvesper.dev/docs>. Run \`npx vectorvesper mcp status\` to check.
|
|
88
|
+
|
|
89
|
+
## Non-negotiable
|
|
90
|
+
|
|
91
|
+
- Autonomous motion must respect \`prefers-reduced-motion\`. User-driven
|
|
92
|
+
navigation may keep working; things that move on their own must stop.
|
|
93
|
+
- Never copy a hook's implementation into the project. A copy runs its own
|
|
94
|
+
loop, which is the problem this runtime exists to solve.`;
|
|
95
|
+
}
|
|
96
|
+
function writeAgentRules(cwd, input) {
|
|
97
|
+
const file = path.join(cwd, "AGENTS.md");
|
|
98
|
+
const block = `${BEGIN}
|
|
99
|
+
${renderBlock(input)}
|
|
100
|
+
${END}`;
|
|
101
|
+
if (!fs.existsSync(file)) {
|
|
102
|
+
fs.writeFileSync(file, `${block}
|
|
103
|
+
`, "utf-8");
|
|
104
|
+
return { action: "created", file: "AGENTS.md" };
|
|
105
|
+
}
|
|
106
|
+
const existing = fs.readFileSync(file, "utf-8");
|
|
107
|
+
const start = existing.indexOf(BEGIN);
|
|
108
|
+
const end = existing.indexOf(END);
|
|
109
|
+
if (start === -1 || end === -1 || end < start) {
|
|
110
|
+
const sep = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
111
|
+
fs.writeFileSync(file, `${existing}${sep}${block}
|
|
112
|
+
`, "utf-8");
|
|
113
|
+
return { action: "updated", file: "AGENTS.md" };
|
|
114
|
+
}
|
|
115
|
+
const next = existing.slice(0, start) + block + existing.slice(end + END.length);
|
|
116
|
+
if (next === existing) return { action: "unchanged", file: "AGENTS.md" };
|
|
117
|
+
fs.writeFileSync(file, next, "utf-8");
|
|
118
|
+
return { action: "updated", file: "AGENTS.md" };
|
|
119
|
+
}
|
|
120
|
+
var INSTALLED_LINE = /^- Installed: .*$/m;
|
|
121
|
+
function refreshAgentRules(cwd, input) {
|
|
122
|
+
try {
|
|
123
|
+
const file = path.join(cwd, "AGENTS.md");
|
|
124
|
+
if (!fs.existsSync(file)) return false;
|
|
125
|
+
const existing = fs.readFileSync(file, "utf-8");
|
|
126
|
+
const start = existing.indexOf(BEGIN);
|
|
127
|
+
const end = existing.indexOf(END);
|
|
128
|
+
if (start === -1 || end === -1 || end < start) return false;
|
|
129
|
+
const block = existing.slice(start, end);
|
|
130
|
+
if (!INSTALLED_LINE.test(block)) return false;
|
|
131
|
+
const installed = (input.components ?? []).length > 0 ? input.components.slice().sort().map((c) => `\`${c}\``).join(", ") : "_none yet_";
|
|
132
|
+
const nextBlock = block.replace(INSTALLED_LINE, `- Installed: ${installed}`);
|
|
133
|
+
if (nextBlock === block) return false;
|
|
134
|
+
fs.writeFileSync(file, existing.slice(0, start) + nextBlock + existing.slice(end), "utf-8");
|
|
135
|
+
return true;
|
|
136
|
+
} catch {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/commands/init.ts
|
|
28
142
|
async function initCommand(options = {}) {
|
|
29
143
|
console.log("");
|
|
30
144
|
intro(pc.cyan(pc.bold(" Vector Vesper Setup ")));
|
|
@@ -114,14 +228,18 @@ async function initCommand(options = {}) {
|
|
|
114
228
|
try {
|
|
115
229
|
writeConfig(config);
|
|
116
230
|
const targetLocalDir = resolveAlias(aliasInput, projectInfo.hasSrcDir);
|
|
117
|
-
const absoluteTargetDir =
|
|
118
|
-
if (!
|
|
119
|
-
|
|
231
|
+
const absoluteTargetDir = path2.join(process.cwd(), targetLocalDir);
|
|
232
|
+
if (!fs2.existsSync(absoluteTargetDir)) {
|
|
233
|
+
fs2.mkdirSync(absoluteTargetDir, { recursive: true });
|
|
120
234
|
}
|
|
121
|
-
const manifestPath =
|
|
122
|
-
if (!
|
|
123
|
-
|
|
235
|
+
const manifestPath = path2.join(process.cwd(), "vv-manifest.json");
|
|
236
|
+
if (!fs2.existsSync(manifestPath)) {
|
|
237
|
+
fs2.writeFileSync(manifestPath, JSON.stringify({ components: {} }, null, 2), "utf-8");
|
|
124
238
|
}
|
|
239
|
+
const rules = options.agentRules === false ? null : writeAgentRules(process.cwd(), {
|
|
240
|
+
targetDir: targetLocalDir,
|
|
241
|
+
alias: aliasInput
|
|
242
|
+
});
|
|
125
243
|
console.log("");
|
|
126
244
|
outro(
|
|
127
245
|
`${pc.green(pc.bold("\u2714 Success!"))} Vector Vesper initialized.
|
|
@@ -129,7 +247,9 @@ async function initCommand(options = {}) {
|
|
|
129
247
|
\u2022 Configuration written to ${pc.cyan("vv.config.json")}
|
|
130
248
|
\u2022 Target directory created at ${pc.cyan(targetLocalDir)}
|
|
131
249
|
\u2022 Manifest created at ${pc.cyan("vv-manifest.json")}
|
|
132
|
-
|
|
250
|
+
` + (rules ? ` \u2022 Agent rules ${rules.action} in ${pc.cyan(rules.file)}
|
|
251
|
+
` : ` \u2022 Agent rules skipped ${pc.dim("(--no-agent-rules)")}
|
|
252
|
+
`) + `
|
|
133
253
|
\u{1F449} Next, run: ${pc.bold(pc.cyan("npx vectorvesper add <slug>"))} to add a component.`
|
|
134
254
|
);
|
|
135
255
|
} catch (error) {
|
|
@@ -188,8 +308,8 @@ async function listCommand() {
|
|
|
188
308
|
}
|
|
189
309
|
|
|
190
310
|
// src/commands/add.ts
|
|
191
|
-
import
|
|
192
|
-
import
|
|
311
|
+
import fs5 from "fs";
|
|
312
|
+
import path5 from "path";
|
|
193
313
|
import ora2 from "ora";
|
|
194
314
|
import pc5 from "picocolors";
|
|
195
315
|
import { confirm as confirm2, isCancel as isCancel2 } from "@clack/prompts";
|
|
@@ -200,8 +320,8 @@ function isInteractive() {
|
|
|
200
320
|
}
|
|
201
321
|
|
|
202
322
|
// src/utils/installer.ts
|
|
203
|
-
import
|
|
204
|
-
import
|
|
323
|
+
import fs3 from "fs";
|
|
324
|
+
import path3 from "path";
|
|
205
325
|
import pc3 from "picocolors";
|
|
206
326
|
var MAX_DEPTH = 20;
|
|
207
327
|
function toForwardSlash(p) {
|
|
@@ -236,12 +356,12 @@ async function resolveComponentTree(slug) {
|
|
|
236
356
|
}
|
|
237
357
|
function planFiles(components, installDir, projectRoot) {
|
|
238
358
|
const planned = [];
|
|
239
|
-
const compDir =
|
|
359
|
+
const compDir = path3.join(projectRoot, installDir);
|
|
240
360
|
for (const component of components) {
|
|
241
361
|
for (const file of component.files) {
|
|
242
|
-
const absolutePath =
|
|
243
|
-
const relativeFromRoot =
|
|
244
|
-
if (relativeFromRoot.startsWith("..") ||
|
|
362
|
+
const absolutePath = path3.resolve(compDir, file.target);
|
|
363
|
+
const relativeFromRoot = path3.relative(projectRoot, absolutePath);
|
|
364
|
+
if (relativeFromRoot.startsWith("..") || path3.isAbsolute(relativeFromRoot)) {
|
|
245
365
|
throw new Error(
|
|
246
366
|
`Security Error: component target tries to escape project root: ${file.target}`
|
|
247
367
|
);
|
|
@@ -251,7 +371,7 @@ function planFiles(components, installDir, projectRoot) {
|
|
|
251
371
|
relativePath: relativeFromRoot,
|
|
252
372
|
target: file.target,
|
|
253
373
|
content: file.content,
|
|
254
|
-
exists:
|
|
374
|
+
exists: fs3.existsSync(absolutePath)
|
|
255
375
|
});
|
|
256
376
|
}
|
|
257
377
|
}
|
|
@@ -259,28 +379,28 @@ function planFiles(components, installDir, projectRoot) {
|
|
|
259
379
|
}
|
|
260
380
|
function writeFiles(files) {
|
|
261
381
|
for (const file of files) {
|
|
262
|
-
const folder =
|
|
263
|
-
if (!
|
|
264
|
-
|
|
382
|
+
const folder = path3.dirname(file.absolutePath);
|
|
383
|
+
if (!fs3.existsSync(folder)) {
|
|
384
|
+
fs3.mkdirSync(folder, { recursive: true });
|
|
265
385
|
}
|
|
266
|
-
|
|
386
|
+
fs3.writeFileSync(file.absolutePath, file.content, "utf-8");
|
|
267
387
|
}
|
|
268
388
|
}
|
|
269
389
|
var MANIFEST_NAME = "vv-manifest.json";
|
|
270
390
|
function getManifestPath(projectRoot) {
|
|
271
|
-
return
|
|
391
|
+
return path3.join(projectRoot, MANIFEST_NAME);
|
|
272
392
|
}
|
|
273
393
|
function readManifest(projectRoot) {
|
|
274
394
|
const manifestPath = getManifestPath(projectRoot);
|
|
275
|
-
if (!
|
|
395
|
+
if (!fs3.existsSync(manifestPath)) {
|
|
276
396
|
return { components: {} };
|
|
277
397
|
}
|
|
278
|
-
const parsed = JSON.parse(
|
|
398
|
+
const parsed = JSON.parse(fs3.readFileSync(manifestPath, "utf-8"));
|
|
279
399
|
if (!parsed.components) parsed.components = {};
|
|
280
400
|
return parsed;
|
|
281
401
|
}
|
|
282
402
|
function writeManifest(projectRoot, manifest) {
|
|
283
|
-
|
|
403
|
+
fs3.writeFileSync(getManifestPath(projectRoot), JSON.stringify(manifest, null, 2), "utf-8");
|
|
284
404
|
}
|
|
285
405
|
function recordInstall(components, installDir, projectRoot) {
|
|
286
406
|
const manifest = readManifest(projectRoot);
|
|
@@ -288,7 +408,7 @@ function recordInstall(components, installDir, projectRoot) {
|
|
|
288
408
|
for (const component of components) {
|
|
289
409
|
manifest.components[component.slug] = {
|
|
290
410
|
version: component.version,
|
|
291
|
-
installedAt: toForwardSlash(
|
|
411
|
+
installedAt: toForwardSlash(path3.join(installDir, component.slug)),
|
|
292
412
|
installedOn: today,
|
|
293
413
|
files: component.files.map((f) => f.target)
|
|
294
414
|
};
|
|
@@ -296,7 +416,7 @@ function recordInstall(components, installDir, projectRoot) {
|
|
|
296
416
|
writeManifest(projectRoot, manifest);
|
|
297
417
|
}
|
|
298
418
|
function findOrphanedFiles(components, installDir, projectRoot, previousManifest) {
|
|
299
|
-
const compDir =
|
|
419
|
+
const compDir = path3.join(projectRoot, installDir);
|
|
300
420
|
const currentTargets = /* @__PURE__ */ new Set();
|
|
301
421
|
for (const component of components) {
|
|
302
422
|
for (const file of component.files) currentTargets.add(file.target);
|
|
@@ -310,10 +430,10 @@ function findOrphanedFiles(components, installDir, projectRoot, previousManifest
|
|
|
310
430
|
if (currentTargets.has(target)) continue;
|
|
311
431
|
if (seen.has(target)) continue;
|
|
312
432
|
seen.add(target);
|
|
313
|
-
const absolutePath =
|
|
314
|
-
const relativeFromRoot =
|
|
315
|
-
if (relativeFromRoot.startsWith("..") ||
|
|
316
|
-
if (!
|
|
433
|
+
const absolutePath = path3.resolve(compDir, target);
|
|
434
|
+
const relativeFromRoot = path3.relative(projectRoot, absolutePath);
|
|
435
|
+
if (relativeFromRoot.startsWith("..") || path3.isAbsolute(relativeFromRoot)) continue;
|
|
436
|
+
if (!fs3.existsSync(absolutePath)) continue;
|
|
317
437
|
orphans.push({ absolutePath, relativePath: relativeFromRoot, target });
|
|
318
438
|
}
|
|
319
439
|
}
|
|
@@ -321,26 +441,26 @@ function findOrphanedFiles(components, installDir, projectRoot, previousManifest
|
|
|
321
441
|
}
|
|
322
442
|
function removeFiles(files) {
|
|
323
443
|
for (const file of files) {
|
|
324
|
-
if (
|
|
325
|
-
|
|
444
|
+
if (fs3.existsSync(file.absolutePath)) {
|
|
445
|
+
fs3.rmSync(file.absolutePath, { force: true });
|
|
326
446
|
}
|
|
327
447
|
}
|
|
328
448
|
}
|
|
329
449
|
|
|
330
450
|
// src/utils/install.ts
|
|
331
|
-
import
|
|
332
|
-
import
|
|
451
|
+
import fs4 from "fs";
|
|
452
|
+
import path4 from "path";
|
|
333
453
|
import { spawnSync } from "child_process";
|
|
334
454
|
var NPM_NAME_REGEX = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/i;
|
|
335
455
|
function isValidPackageName(name) {
|
|
336
456
|
return NPM_NAME_REGEX.test(name);
|
|
337
457
|
}
|
|
338
458
|
function getMissingDependencies(components, projectRoot) {
|
|
339
|
-
const pkgPath =
|
|
340
|
-
if (!
|
|
459
|
+
const pkgPath = path4.join(projectRoot, "package.json");
|
|
460
|
+
if (!fs4.existsSync(pkgPath)) return [];
|
|
341
461
|
let installed = {};
|
|
342
462
|
try {
|
|
343
|
-
const pkg = JSON.parse(
|
|
463
|
+
const pkg = JSON.parse(fs4.readFileSync(pkgPath, "utf-8"));
|
|
344
464
|
installed = {
|
|
345
465
|
...pkg.dependencies,
|
|
346
466
|
...pkg.devDependencies,
|
|
@@ -692,7 +812,7 @@ async function addCommand(slug, options = {}) {
|
|
|
692
812
|
});
|
|
693
813
|
}
|
|
694
814
|
const targetComponent = resolvedComponents[resolvedComponents.length - 1];
|
|
695
|
-
const installPath = toForwardSlash(
|
|
815
|
+
const installPath = toForwardSlash(path5.join(componentInstallDir, targetComponent.slug));
|
|
696
816
|
let orphans = [];
|
|
697
817
|
try {
|
|
698
818
|
const previousManifest = readManifest(projectRoot);
|
|
@@ -704,7 +824,7 @@ async function addCommand(slug, options = {}) {
|
|
|
704
824
|
spinner.succeed(pc5.yellow("Dry-run: simulation completed. No files were written."));
|
|
705
825
|
console.log(pc5.bold(pc5.yellow("\n[Dry Run] Files that would be created/modified:")));
|
|
706
826
|
for (const file of filesToWrite) {
|
|
707
|
-
const status =
|
|
827
|
+
const status = fs5.existsSync(file.absolutePath) ? pc5.yellow("(exists, would overwrite)") : pc5.green("(new)");
|
|
708
828
|
console.log(` ${pc5.cyan(file.relativePath)} ${status}`);
|
|
709
829
|
}
|
|
710
830
|
if (orphans.length > 0) {
|
|
@@ -746,6 +866,15 @@ async function addCommand(slug, options = {}) {
|
|
|
746
866
|
logger.warn(`Failed to update vv-manifest.json: ${message}`);
|
|
747
867
|
logger.warn("Component was installed but may not appear in 'npx vectorvesper info' or 'npx vectorvesper diff'.");
|
|
748
868
|
}
|
|
869
|
+
try {
|
|
870
|
+
const installed = Object.keys(readManifest(projectRoot).components ?? {});
|
|
871
|
+
refreshAgentRules(projectRoot, {
|
|
872
|
+
targetDir: componentInstallDir,
|
|
873
|
+
alias: config.aliases.vv,
|
|
874
|
+
components: installed
|
|
875
|
+
});
|
|
876
|
+
} catch {
|
|
877
|
+
}
|
|
749
878
|
spinner.succeed(pc5.green("Files written successfully!"));
|
|
750
879
|
console.log(pc5.dim("\nCreated files:"));
|
|
751
880
|
for (const file of filesToWrite) {
|
|
@@ -893,8 +1022,8 @@ async function updateCommand(slug, options = {}) {
|
|
|
893
1022
|
}
|
|
894
1023
|
|
|
895
1024
|
// src/commands/remove.ts
|
|
896
|
-
import
|
|
897
|
-
import
|
|
1025
|
+
import fs6 from "fs";
|
|
1026
|
+
import path6 from "path";
|
|
898
1027
|
import pc7 from "picocolors";
|
|
899
1028
|
import { confirm as confirm3, isCancel as isCancel3 } from "@clack/prompts";
|
|
900
1029
|
async function removeCommand(slug, options = {}) {
|
|
@@ -935,15 +1064,15 @@ async function removeCommand(slug, options = {}) {
|
|
|
935
1064
|
}
|
|
936
1065
|
const projectInfo = detectProject();
|
|
937
1066
|
const installDir = resolveAlias(config.aliases.vv, projectInfo.hasSrcDir);
|
|
938
|
-
const baseDir =
|
|
1067
|
+
const baseDir = path6.join(projectRoot, installDir);
|
|
939
1068
|
const targets = entry.files ?? [];
|
|
940
|
-
const absoluteFiles = targets.map((t) =>
|
|
1069
|
+
const absoluteFiles = targets.map((t) => path6.resolve(baseDir, t));
|
|
941
1070
|
console.log(pc7.bold(pc7.cyan(`
|
|
942
1071
|
Remove ${slug}
|
|
943
1072
|
`)));
|
|
944
1073
|
console.log(pc7.dim(" The following files will be deleted:"));
|
|
945
1074
|
for (const f of absoluteFiles) {
|
|
946
|
-
console.log(` ${
|
|
1075
|
+
console.log(` ${fs6.existsSync(f) ? pc7.red("\u2212") : pc7.dim("\xB7")} ${pc7.cyan(path6.relative(projectRoot, f))}`);
|
|
947
1076
|
}
|
|
948
1077
|
if (!options.yes) {
|
|
949
1078
|
const answer = await confirm3({
|
|
@@ -958,19 +1087,19 @@ Remove ${slug}
|
|
|
958
1087
|
let deleted = 0;
|
|
959
1088
|
for (const f of absoluteFiles) {
|
|
960
1089
|
try {
|
|
961
|
-
if (
|
|
962
|
-
|
|
1090
|
+
if (fs6.existsSync(f)) {
|
|
1091
|
+
fs6.rmSync(f);
|
|
963
1092
|
deleted++;
|
|
964
1093
|
}
|
|
965
1094
|
} catch (error) {
|
|
966
1095
|
const message = error instanceof Error ? error.message : String(error);
|
|
967
|
-
console.log(pc7.yellow(` \u26A0\uFE0F Could not delete ${
|
|
1096
|
+
console.log(pc7.yellow(` \u26A0\uFE0F Could not delete ${path6.relative(projectRoot, f)}: ${message}`));
|
|
968
1097
|
}
|
|
969
1098
|
}
|
|
970
|
-
const componentDir =
|
|
1099
|
+
const componentDir = path6.resolve(baseDir, slug);
|
|
971
1100
|
try {
|
|
972
|
-
if (
|
|
973
|
-
|
|
1101
|
+
if (fs6.existsSync(componentDir) && fs6.readdirSync(componentDir).length === 0) {
|
|
1102
|
+
fs6.rmdirSync(componentDir);
|
|
974
1103
|
}
|
|
975
1104
|
} catch {
|
|
976
1105
|
}
|
|
@@ -990,10 +1119,10 @@ Remove ${slug}
|
|
|
990
1119
|
}
|
|
991
1120
|
|
|
992
1121
|
// src/commands/info.ts
|
|
993
|
-
import
|
|
994
|
-
import
|
|
1122
|
+
import fs7 from "fs";
|
|
1123
|
+
import path7 from "path";
|
|
995
1124
|
import pc8 from "picocolors";
|
|
996
|
-
var CLI_VERSION = true ? "2.
|
|
1125
|
+
var CLI_VERSION = true ? "2.3.0" : "0.0.0-dev";
|
|
997
1126
|
async function infoCommand() {
|
|
998
1127
|
console.log(pc8.bold(pc8.cyan("\nVector Vesper Diagnostics\n")));
|
|
999
1128
|
const projectInfo = detectProject();
|
|
@@ -1023,10 +1152,10 @@ async function infoCommand() {
|
|
|
1023
1152
|
}
|
|
1024
1153
|
console.log("");
|
|
1025
1154
|
console.log(pc8.bold(pc8.white("Installed Components (vv-manifest.json):")));
|
|
1026
|
-
const manifestPath =
|
|
1027
|
-
if (
|
|
1155
|
+
const manifestPath = path7.join(process.cwd(), "vv-manifest.json");
|
|
1156
|
+
if (fs7.existsSync(manifestPath)) {
|
|
1028
1157
|
try {
|
|
1029
|
-
const manifest = JSON.parse(
|
|
1158
|
+
const manifest = JSON.parse(fs7.readFileSync(manifestPath, "utf-8"));
|
|
1030
1159
|
const components = manifest.components || {};
|
|
1031
1160
|
const slugs = Object.keys(components);
|
|
1032
1161
|
if (slugs.length === 0) {
|
|
@@ -1053,14 +1182,14 @@ async function infoCommand() {
|
|
|
1053
1182
|
}
|
|
1054
1183
|
|
|
1055
1184
|
// src/commands/diff.ts
|
|
1056
|
-
import
|
|
1057
|
-
import
|
|
1185
|
+
import fs8 from "fs";
|
|
1186
|
+
import path8 from "path";
|
|
1058
1187
|
import pc9 from "picocolors";
|
|
1059
1188
|
import ora4 from "ora";
|
|
1060
1189
|
async function diffCommand(slug) {
|
|
1061
1190
|
const projectRoot = process.cwd();
|
|
1062
|
-
const manifestPath =
|
|
1063
|
-
if (!
|
|
1191
|
+
const manifestPath = path8.join(projectRoot, "vv-manifest.json");
|
|
1192
|
+
if (!fs8.existsSync(manifestPath)) {
|
|
1064
1193
|
console.log(pc9.yellow(`
|
|
1065
1194
|
\u26A0\uFE0F No vv-manifest.json found in this directory.`));
|
|
1066
1195
|
console.log(`\u{1F449} Add components first using ${pc9.bold(pc9.cyan("npx vectorvesper add <slug>"))}
|
|
@@ -1069,7 +1198,7 @@ async function diffCommand(slug) {
|
|
|
1069
1198
|
}
|
|
1070
1199
|
let manifest;
|
|
1071
1200
|
try {
|
|
1072
|
-
manifest = JSON.parse(
|
|
1201
|
+
manifest = JSON.parse(fs8.readFileSync(manifestPath, "utf-8"));
|
|
1073
1202
|
} catch {
|
|
1074
1203
|
console.error(pc9.red(`\u274C Error reading vv-manifest.json: Invalid JSON format.`));
|
|
1075
1204
|
process.exit(1);
|
|
@@ -1291,7 +1420,7 @@ async function whoamiCommand() {
|
|
|
1291
1420
|
}
|
|
1292
1421
|
|
|
1293
1422
|
// src/index.ts
|
|
1294
|
-
var version = true ? "2.
|
|
1423
|
+
var version = true ? "2.3.0" : "0.0.0-dev";
|
|
1295
1424
|
var program = new Command();
|
|
1296
1425
|
program.name("vv").description("Vector Vesper CLI \u2014 add visual components to your React project").version(version).option("--verbose", "Show detailed debug output").hook("preAction", (thisCommand) => {
|
|
1297
1426
|
const opts = thisCommand.opts();
|
|
@@ -1299,7 +1428,7 @@ program.name("vv").description("Vector Vesper CLI \u2014 add visual components t
|
|
|
1299
1428
|
setVerbose(true);
|
|
1300
1429
|
}
|
|
1301
1430
|
});
|
|
1302
|
-
program.command("init").description("Initialize Vector Vesper configuration in your project").option("-y, --yes", "Accept all default prompts based on project detection").action(async (options) => {
|
|
1431
|
+
program.command("init").description("Initialize Vector Vesper configuration in your project").option("-y, --yes", "Accept all default prompts based on project detection").option("--no-agent-rules", "Skip writing the AGENTS.md block for AI coding assistants").action(async (options) => {
|
|
1303
1432
|
await initCommand(options);
|
|
1304
1433
|
});
|
|
1305
1434
|
program.command("list").description("List all available components in the registry").action(async () => {
|
|
@@ -1329,10 +1458,14 @@ program.command("logout", { hidden: true }).description("Clear stored license cr
|
|
|
1329
1458
|
program.command("whoami", { hidden: true }).description("Show current authentication status").action(async () => {
|
|
1330
1459
|
await whoamiCommand();
|
|
1331
1460
|
});
|
|
1332
|
-
program.command("mcp [action]").description(
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1461
|
+
program.command("mcp [action] [client]").description(
|
|
1462
|
+
"Run as an MCP server (stdio) for AI coding agents. `vv mcp install` wires it into your editor; `vv mcp status` checks the setup."
|
|
1463
|
+
).option("--stdio", "Force server mode even from an interactive terminal").option("-g, --global", "Write user-level config instead of project-level (install)").action(
|
|
1464
|
+
async (action, client, options) => {
|
|
1465
|
+
const { mcpCommand } = await import("./mcp-H5YYBZ5V.js");
|
|
1466
|
+
await mcpCommand(action, { ...options, client });
|
|
1467
|
+
}
|
|
1468
|
+
);
|
|
1336
1469
|
process.on("unhandledRejection", (error) => {
|
|
1337
1470
|
console.error("An unexpected error occurred:", error instanceof Error ? error.message : error);
|
|
1338
1471
|
process.exit(1);
|