vectorvesper 0.2.1 → 0.3.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.
Files changed (2) hide show
  1. package/dist/index.js +107 -30
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -59,17 +59,6 @@ function detectProject(cwd = process.cwd()) {
59
59
  }
60
60
  const isTypeScript = fs.existsSync(path.join(rootPath, "tsconfig.json"));
61
61
  const hasSrcDir = fs.existsSync(path.join(rootPath, "src"));
62
- const tailwindConfigs = [
63
- "tailwind.config.js",
64
- "tailwind.config.ts",
65
- "tailwind.config.cjs",
66
- "tailwind.config.mjs"
67
- ];
68
- const hasTailwind = tailwindConfigs.some(
69
- (config) => fs.existsSync(path.join(rootPath, config))
70
- );
71
- let framework = "unknown";
72
- let nextRouter;
73
62
  const pkgPath = path.join(rootPath, "package.json");
74
63
  let dependencies = {};
75
64
  let devDependencies = {};
@@ -78,9 +67,23 @@ function detectProject(cwd = process.cwd()) {
78
67
  const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
79
68
  dependencies = pkg.dependencies || {};
80
69
  devDependencies = pkg.devDependencies || {};
81
- } catch (e) {
70
+ } catch {
82
71
  }
83
72
  }
73
+ const allDeps = { ...dependencies, ...devDependencies };
74
+ const tailwindConfigs = [
75
+ "tailwind.config.js",
76
+ "tailwind.config.ts",
77
+ "tailwind.config.cjs",
78
+ "tailwind.config.mjs"
79
+ ];
80
+ const hasTailwindConfig = tailwindConfigs.some(
81
+ (config) => fs.existsSync(path.join(rootPath, config))
82
+ );
83
+ const hasTailwindDep = "tailwindcss" in allDeps || "@tailwindcss/postcss" in allDeps || "@tailwindcss/vite" in allDeps;
84
+ const hasTailwind = hasTailwindConfig || hasTailwindDep;
85
+ let framework = "unknown";
86
+ let nextRouter;
84
87
  if (dependencies["next"] || devDependencies["next"]) {
85
88
  framework = "next";
86
89
  const searchPath = hasSrcDir ? path.join(rootPath, "src") : rootPath;
@@ -714,6 +717,37 @@ function recordInstall(components, installDir, projectRoot) {
714
717
  }
715
718
  writeManifest(projectRoot, manifest);
716
719
  }
720
+ function findOrphanedFiles(components, installDir, projectRoot, previousManifest) {
721
+ const compDir = path5.join(projectRoot, installDir);
722
+ const currentTargets = /* @__PURE__ */ new Set();
723
+ for (const component of components) {
724
+ for (const file of component.files) currentTargets.add(file.target);
725
+ }
726
+ const orphans = [];
727
+ const seen = /* @__PURE__ */ new Set();
728
+ for (const component of components) {
729
+ const entry = previousManifest.components[component.slug];
730
+ if (!entry) continue;
731
+ for (const target of entry.files) {
732
+ if (currentTargets.has(target)) continue;
733
+ if (seen.has(target)) continue;
734
+ seen.add(target);
735
+ const absolutePath = path5.resolve(compDir, target);
736
+ const relativeFromRoot = path5.relative(projectRoot, absolutePath);
737
+ if (relativeFromRoot.startsWith("..") || path5.isAbsolute(relativeFromRoot)) continue;
738
+ if (!fs5.existsSync(absolutePath)) continue;
739
+ orphans.push({ absolutePath, relativePath: relativeFromRoot, target });
740
+ }
741
+ }
742
+ return orphans;
743
+ }
744
+ function removeFiles(files) {
745
+ for (const file of files) {
746
+ if (fs5.existsSync(file.absolutePath)) {
747
+ fs5.rmSync(file.absolutePath, { force: true });
748
+ }
749
+ }
750
+ }
717
751
 
718
752
  // src/utils/install.ts
719
753
  import fs6 from "fs";
@@ -889,6 +923,39 @@ Installing dependencies with ${projectInfo.packageManager}...`));
889
923
  console.log(` Run manually: ${pc6.bold(pc6.cyan(installCmd))}`);
890
924
  }
891
925
  }
926
+ async function handlePrune(orphans, slug, options) {
927
+ if (orphans.length === 0) return;
928
+ const list = orphans.map((o) => ` ${pc6.dim("\u2022")} ${pc6.cyan(o.relativePath)}`).join("\n");
929
+ let shouldPrune = options.prune === true;
930
+ if (!shouldPrune) {
931
+ console.log(
932
+ pc6.yellow(
933
+ `
934
+ \u{1F9F9} ${orphans.length} file(s) from a previous version of ${pc6.cyan(slug)} are no longer part of it:`
935
+ )
936
+ );
937
+ console.log(list);
938
+ if (options.yes) {
939
+ console.log(pc6.dim(` Re-run with ${pc6.cyan("--prune")} to remove them.`));
940
+ return;
941
+ }
942
+ const answer = await confirm2({
943
+ message: "Remove these orphaned files?",
944
+ initialValue: true
945
+ });
946
+ if (isCancel2(answer) || !answer) {
947
+ console.log(pc6.dim(` Left in place. Run with ${pc6.cyan("--prune")} later to remove them.`));
948
+ return;
949
+ }
950
+ shouldPrune = true;
951
+ }
952
+ removeFiles(orphans);
953
+ console.log(pc6.green(`
954
+ \u{1F9F9} Removed ${orphans.length} orphaned file(s):`));
955
+ for (const o of orphans) {
956
+ console.log(` ${pc6.red("\u2212")} ${pc6.cyan(o.relativePath)}`);
957
+ }
958
+ }
892
959
  async function addCommand(slug, options = {}) {
893
960
  try {
894
961
  validateSlug(slug);
@@ -959,6 +1026,13 @@ async function addCommand(slug, options = {}) {
959
1026
  }
960
1027
  const targetComponent = resolvedComponents[resolvedComponents.length - 1];
961
1028
  const installPath = toForwardSlash(path7.join(componentInstallDir, targetComponent.slug));
1029
+ let orphans = [];
1030
+ try {
1031
+ const previousManifest = readManifest(projectRoot);
1032
+ orphans = findOrphanedFiles(resolvedComponents, componentInstallDir, projectRoot, previousManifest);
1033
+ } catch {
1034
+ orphans = [];
1035
+ }
962
1036
  if (options.dryRun) {
963
1037
  spinner.succeed(pc6.yellow("Dry-run: simulation completed. No files were written."));
964
1038
  console.log(pc6.bold(pc6.yellow("\n[Dry Run] Files that would be created/modified:")));
@@ -966,6 +1040,13 @@ async function addCommand(slug, options = {}) {
966
1040
  const status = fs7.existsSync(file.absolutePath) ? pc6.yellow("(exists, would overwrite)") : pc6.green("(new)");
967
1041
  console.log(` ${pc6.cyan(file.relativePath)} ${status}`);
968
1042
  }
1043
+ if (orphans.length > 0) {
1044
+ console.log(pc6.bold(pc6.yellow("\n[Dry Run] Orphaned files from a previous version:")));
1045
+ for (const o of orphans) {
1046
+ const note = options.prune ? pc6.red("(would remove)") : pc6.dim("(use --prune to remove)");
1047
+ console.log(` ${pc6.cyan(o.relativePath)} ${note}`);
1048
+ }
1049
+ }
969
1050
  const missing = getMissingDependencies(resolvedComponents, projectRoot);
970
1051
  if (missing.length > 0) {
971
1052
  console.log(pc6.yellow(`
@@ -979,6 +1060,7 @@ async function addCommand(slug, options = {}) {
979
1060
  }
980
1061
  if (filesToWrite.length === 0) {
981
1062
  spinner.succeed(pc6.green("All files skipped (already up to date)."));
1063
+ await handlePrune(orphans, targetComponent.slug, options);
982
1064
  return;
983
1065
  }
984
1066
  spinner.text = "Writing component files...";
@@ -1002,6 +1084,7 @@ async function addCommand(slug, options = {}) {
1002
1084
  for (const file of filesToWrite) {
1003
1085
  console.log(` ${pc6.green("\u2714")} ${pc6.cyan(file.relativePath)}`);
1004
1086
  }
1087
+ await handlePrune(orphans, targetComponent.slug, options);
1005
1088
  await handleDependencies(resolvedComponents, projectRoot, projectInfo, options);
1006
1089
  printGuidance(targetComponent, {
1007
1090
  alias: config.aliases.vv,
@@ -1076,6 +1159,7 @@ async function updateCommand(slug, options = {}) {
1076
1159
  const updated = [];
1077
1160
  const upToDate = [];
1078
1161
  const failed = [];
1162
+ const updatedComponents = [];
1079
1163
  for (const target of targets) {
1080
1164
  spinner.text = `Updating ${pc7.cyan(target)}...`;
1081
1165
  try {
@@ -1090,6 +1174,7 @@ async function updateCommand(slug, options = {}) {
1090
1174
  writeFiles(planned.map((f) => ({ absolutePath: f.absolutePath, content: f.content })));
1091
1175
  recordInstall(components, installDir, projectRoot);
1092
1176
  updated.push(`${target} \u2192 ${remote.version}`);
1177
+ updatedComponents.push(...components);
1093
1178
  } catch (error) {
1094
1179
  const message = error instanceof Error ? error.message : String(error);
1095
1180
  failed.push({ slug: target, reason: message });
@@ -1113,6 +1198,9 @@ async function updateCommand(slug, options = {}) {
1113
1198
  for (const f of failed) console.log(` ${pc7.red("\u2716")} ${f.slug}: ${pc7.dim(f.reason)}`);
1114
1199
  }
1115
1200
  console.log("");
1201
+ if (updatedComponents.length > 0) {
1202
+ await handleDependencies(updatedComponents, projectRoot, projectInfo, options);
1203
+ }
1116
1204
  if (failed.length > 0) process.exit(1);
1117
1205
  }
1118
1206
 
@@ -1217,7 +1305,7 @@ Remove ${slug}
1217
1305
  import fs9 from "fs";
1218
1306
  import path9 from "path";
1219
1307
  import pc9 from "picocolors";
1220
- var CLI_VERSION = true ? "0.2.1" : "0.0.0-dev";
1308
+ var CLI_VERSION = true ? "0.3.2" : "0.0.0-dev";
1221
1309
  async function infoCommand() {
1222
1310
  console.log(pc9.bold(pc9.cyan("\nVector Vesper Diagnostics\n")));
1223
1311
  const projectInfo = detectProject();
@@ -1237,17 +1325,6 @@ async function infoCommand() {
1237
1325
  console.log(` \u2022 Has src/ folder: ${pc9.cyan(projectInfo.hasSrcDir ? "Yes" : "No")}`);
1238
1326
  console.log(` \u2022 Tailwind CSS: ${pc9.cyan(projectInfo.hasTailwind ? "Yes" : "No")}`);
1239
1327
  console.log("");
1240
- console.log(pc9.bold(pc9.white("Authentication:")));
1241
- const token = getAuthToken();
1242
- if (token) {
1243
- const maskedKey = token.slice(0, 6) + "\u2026" + token.slice(-4);
1244
- console.log(` \u2022 Status: ${pc9.green("Authenticated")}`);
1245
- console.log(` \u2022 Key: ${pc9.cyan(maskedKey)}`);
1246
- } else {
1247
- console.log(` \u2022 Status: ${pc9.yellow("Anonymous (free tier)")}`);
1248
- console.log(` ${pc9.dim(" Run")} ${pc9.cyan("npx vectorvesper login <key>")} ${pc9.dim("to unlock pro components")}`);
1249
- }
1250
- console.log("");
1251
1328
  console.log(pc9.bold(pc9.white("Configuration (vv.config.json):")));
1252
1329
  if (config) {
1253
1330
  console.log(` \u2022 Framework Set: ${pc9.cyan(config.framework)}`);
@@ -1526,7 +1603,7 @@ async function whoamiCommand() {
1526
1603
  }
1527
1604
 
1528
1605
  // src/index.ts
1529
- var version = true ? "0.2.1" : "0.0.0-dev";
1606
+ var version = true ? "0.3.2" : "0.0.0-dev";
1530
1607
  var program = new Command();
1531
1608
  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) => {
1532
1609
  const opts = thisCommand.opts();
@@ -1540,10 +1617,10 @@ program.command("init").description("Initialize Vector Vesper configuration in y
1540
1617
  program.command("list").description("List all available components in the registry").action(async () => {
1541
1618
  await listCommand();
1542
1619
  });
1543
- program.command("add <slug>").description("Add a component to your project").option("-o, --overwrite", "Overwrite existing files without prompting").option("-y, --yes", "Accept all default prompts").option("-d, --dry-run", "Simulate the installation without writing files").option("--no-install", "Skip auto-installing missing dependencies").action(async (slug, options) => {
1620
+ program.command("add <slug>").description("Add a component to your project").option("-o, --overwrite", "Overwrite existing files without prompting").option("-y, --yes", "Accept all default prompts").option("-d, --dry-run", "Simulate the installation without writing files").option("--no-install", "Skip auto-installing missing dependencies").option("--prune", "Remove files left over from a previous version of the component").action(async (slug, options) => {
1544
1621
  await addCommand(slug, options);
1545
1622
  });
1546
- program.command("update [slug]").description("Update installed components to the latest registry version").option("-f, --force", "Re-write files even if the version already matches").action(async (slug, options) => {
1623
+ program.command("update [slug]").description("Update installed components to the latest registry version").option("-f, --force", "Re-write files even if the version already matches").option("-y, --yes", "Accept all prompts (auto-install missing dependencies)").option("--no-install", "Skip auto-installing missing dependencies").action(async (slug, options) => {
1547
1624
  await updateCommand(slug, options);
1548
1625
  });
1549
1626
  program.command("remove <slug>").alias("rm").description("Remove an installed component and its files").option("-y, --yes", "Skip the confirmation prompt").action(async (slug, options) => {
@@ -1555,13 +1632,13 @@ program.command("info").description("Show project diagnostics and list installed
1555
1632
  program.command("diff [slug]").description("Check for updates against the component registry").action(async (slug) => {
1556
1633
  await diffCommand(slug);
1557
1634
  });
1558
- program.command("login <key>").description("Authenticate with a license key for pro components").action(async (key) => {
1635
+ program.command("login <key>", { hidden: true }).description("Authenticate with a license key for pro components").action(async (key) => {
1559
1636
  await loginCommand(key);
1560
1637
  });
1561
- program.command("logout").description("Clear stored license credentials").action(async () => {
1638
+ program.command("logout", { hidden: true }).description("Clear stored license credentials").action(async () => {
1562
1639
  await logoutCommand();
1563
1640
  });
1564
- program.command("whoami").description("Show current authentication status").action(async () => {
1641
+ program.command("whoami", { hidden: true }).description("Show current authentication status").action(async () => {
1565
1642
  await whoamiCommand();
1566
1643
  });
1567
1644
  process.on("unhandledRejection", (error) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vectorvesper",
3
- "version": "0.2.1",
3
+ "version": "0.3.2",
4
4
  "description": "Add WebGL, React Three Fiber & advanced motion components to your project via CLI — motion, engineered.",
5
5
  "type": "module",
6
6
  "license": "MIT",