vectorvesper 2.1.1 → 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/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 = path.join(process.cwd(), targetLocalDir);
118
- if (!fs.existsSync(absoluteTargetDir)) {
119
- fs.mkdirSync(absoluteTargetDir, { recursive: true });
231
+ const absoluteTargetDir = path2.join(process.cwd(), targetLocalDir);
232
+ if (!fs2.existsSync(absoluteTargetDir)) {
233
+ fs2.mkdirSync(absoluteTargetDir, { recursive: true });
120
234
  }
121
- const manifestPath = path.join(process.cwd(), "vv-manifest.json");
122
- if (!fs.existsSync(manifestPath)) {
123
- fs.writeFileSync(manifestPath, JSON.stringify({ components: {} }, null, 2), "utf-8");
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 fs4 from "fs";
192
- import path4 from "path";
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 fs2 from "fs";
204
- import path2 from "path";
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 = path2.join(projectRoot, installDir);
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 = path2.resolve(compDir, file.target);
243
- const relativeFromRoot = path2.relative(projectRoot, absolutePath);
244
- if (relativeFromRoot.startsWith("..") || path2.isAbsolute(relativeFromRoot)) {
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: fs2.existsSync(absolutePath)
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 = path2.dirname(file.absolutePath);
263
- if (!fs2.existsSync(folder)) {
264
- fs2.mkdirSync(folder, { recursive: true });
382
+ const folder = path3.dirname(file.absolutePath);
383
+ if (!fs3.existsSync(folder)) {
384
+ fs3.mkdirSync(folder, { recursive: true });
265
385
  }
266
- fs2.writeFileSync(file.absolutePath, file.content, "utf-8");
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 path2.join(projectRoot, MANIFEST_NAME);
391
+ return path3.join(projectRoot, MANIFEST_NAME);
272
392
  }
273
393
  function readManifest(projectRoot) {
274
394
  const manifestPath = getManifestPath(projectRoot);
275
- if (!fs2.existsSync(manifestPath)) {
395
+ if (!fs3.existsSync(manifestPath)) {
276
396
  return { components: {} };
277
397
  }
278
- const parsed = JSON.parse(fs2.readFileSync(manifestPath, "utf-8"));
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
- fs2.writeFileSync(getManifestPath(projectRoot), JSON.stringify(manifest, null, 2), "utf-8");
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(path2.join(installDir, component.slug)),
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 = path2.join(projectRoot, installDir);
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 = path2.resolve(compDir, target);
314
- const relativeFromRoot = path2.relative(projectRoot, absolutePath);
315
- if (relativeFromRoot.startsWith("..") || path2.isAbsolute(relativeFromRoot)) continue;
316
- if (!fs2.existsSync(absolutePath)) continue;
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 (fs2.existsSync(file.absolutePath)) {
325
- fs2.rmSync(file.absolutePath, { force: true });
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 fs3 from "fs";
332
- import path3 from "path";
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 = path3.join(projectRoot, "package.json");
340
- if (!fs3.existsSync(pkgPath)) return [];
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(fs3.readFileSync(pkgPath, "utf-8"));
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(path4.join(componentInstallDir, targetComponent.slug));
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 = fs4.existsSync(file.absolutePath) ? pc5.yellow("(exists, would overwrite)") : pc5.green("(new)");
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 fs5 from "fs";
897
- import path5 from "path";
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 = path5.join(projectRoot, installDir);
1067
+ const baseDir = path6.join(projectRoot, installDir);
939
1068
  const targets = entry.files ?? [];
940
- const absoluteFiles = targets.map((t) => path5.resolve(baseDir, 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(` ${fs5.existsSync(f) ? pc7.red("\u2212") : pc7.dim("\xB7")} ${pc7.cyan(path5.relative(projectRoot, f))}`);
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 (fs5.existsSync(f)) {
962
- fs5.rmSync(f);
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 ${path5.relative(projectRoot, f)}: ${message}`));
1096
+ console.log(pc7.yellow(` \u26A0\uFE0F Could not delete ${path6.relative(projectRoot, f)}: ${message}`));
968
1097
  }
969
1098
  }
970
- const componentDir = path5.resolve(baseDir, slug);
1099
+ const componentDir = path6.resolve(baseDir, slug);
971
1100
  try {
972
- if (fs5.existsSync(componentDir) && fs5.readdirSync(componentDir).length === 0) {
973
- fs5.rmdirSync(componentDir);
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 fs6 from "fs";
994
- import path6 from "path";
1122
+ import fs7 from "fs";
1123
+ import path7 from "path";
995
1124
  import pc8 from "picocolors";
996
- var CLI_VERSION = true ? "2.1.1" : "0.0.0-dev";
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 = path6.join(process.cwd(), "vv-manifest.json");
1027
- if (fs6.existsSync(manifestPath)) {
1155
+ const manifestPath = path7.join(process.cwd(), "vv-manifest.json");
1156
+ if (fs7.existsSync(manifestPath)) {
1028
1157
  try {
1029
- const manifest = JSON.parse(fs6.readFileSync(manifestPath, "utf-8"));
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 fs7 from "fs";
1057
- import path7 from "path";
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 = path7.join(projectRoot, "vv-manifest.json");
1063
- if (!fs7.existsSync(manifestPath)) {
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(fs7.readFileSync(manifestPath, "utf-8"));
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.1.1" : "0.0.0-dev";
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("Run as an MCP server (stdio) for AI coding agents. `vv mcp status` checks the setup.").option("--stdio", "Force server mode even from an interactive terminal").action(async (action, options) => {
1333
- const { mcpCommand } = await import("./mcp-FCM3FZSK.js");
1334
- await mcpCommand(action, options);
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);