vectorvesper 0.2.1 → 0.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.
Files changed (2) hide show
  1. package/dist/index.js +92 -18
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -714,6 +714,37 @@ function recordInstall(components, installDir, projectRoot) {
714
714
  }
715
715
  writeManifest(projectRoot, manifest);
716
716
  }
717
+ function findOrphanedFiles(components, installDir, projectRoot, previousManifest) {
718
+ const compDir = path5.join(projectRoot, installDir);
719
+ const currentTargets = /* @__PURE__ */ new Set();
720
+ for (const component of components) {
721
+ for (const file of component.files) currentTargets.add(file.target);
722
+ }
723
+ const orphans = [];
724
+ const seen = /* @__PURE__ */ new Set();
725
+ for (const component of components) {
726
+ const entry = previousManifest.components[component.slug];
727
+ if (!entry) continue;
728
+ for (const target of entry.files) {
729
+ if (currentTargets.has(target)) continue;
730
+ if (seen.has(target)) continue;
731
+ seen.add(target);
732
+ const absolutePath = path5.resolve(compDir, target);
733
+ const relativeFromRoot = path5.relative(projectRoot, absolutePath);
734
+ if (relativeFromRoot.startsWith("..") || path5.isAbsolute(relativeFromRoot)) continue;
735
+ if (!fs5.existsSync(absolutePath)) continue;
736
+ orphans.push({ absolutePath, relativePath: relativeFromRoot, target });
737
+ }
738
+ }
739
+ return orphans;
740
+ }
741
+ function removeFiles(files) {
742
+ for (const file of files) {
743
+ if (fs5.existsSync(file.absolutePath)) {
744
+ fs5.rmSync(file.absolutePath, { force: true });
745
+ }
746
+ }
747
+ }
717
748
 
718
749
  // src/utils/install.ts
719
750
  import fs6 from "fs";
@@ -889,6 +920,39 @@ Installing dependencies with ${projectInfo.packageManager}...`));
889
920
  console.log(` Run manually: ${pc6.bold(pc6.cyan(installCmd))}`);
890
921
  }
891
922
  }
923
+ async function handlePrune(orphans, slug, options) {
924
+ if (orphans.length === 0) return;
925
+ const list = orphans.map((o) => ` ${pc6.dim("\u2022")} ${pc6.cyan(o.relativePath)}`).join("\n");
926
+ let shouldPrune = options.prune === true;
927
+ if (!shouldPrune) {
928
+ console.log(
929
+ pc6.yellow(
930
+ `
931
+ \u{1F9F9} ${orphans.length} file(s) from a previous version of ${pc6.cyan(slug)} are no longer part of it:`
932
+ )
933
+ );
934
+ console.log(list);
935
+ if (options.yes) {
936
+ console.log(pc6.dim(` Re-run with ${pc6.cyan("--prune")} to remove them.`));
937
+ return;
938
+ }
939
+ const answer = await confirm2({
940
+ message: "Remove these orphaned files?",
941
+ initialValue: true
942
+ });
943
+ if (isCancel2(answer) || !answer) {
944
+ console.log(pc6.dim(` Left in place. Run with ${pc6.cyan("--prune")} later to remove them.`));
945
+ return;
946
+ }
947
+ shouldPrune = true;
948
+ }
949
+ removeFiles(orphans);
950
+ console.log(pc6.green(`
951
+ \u{1F9F9} Removed ${orphans.length} orphaned file(s):`));
952
+ for (const o of orphans) {
953
+ console.log(` ${pc6.red("\u2212")} ${pc6.cyan(o.relativePath)}`);
954
+ }
955
+ }
892
956
  async function addCommand(slug, options = {}) {
893
957
  try {
894
958
  validateSlug(slug);
@@ -959,6 +1023,13 @@ async function addCommand(slug, options = {}) {
959
1023
  }
960
1024
  const targetComponent = resolvedComponents[resolvedComponents.length - 1];
961
1025
  const installPath = toForwardSlash(path7.join(componentInstallDir, targetComponent.slug));
1026
+ let orphans = [];
1027
+ try {
1028
+ const previousManifest = readManifest(projectRoot);
1029
+ orphans = findOrphanedFiles(resolvedComponents, componentInstallDir, projectRoot, previousManifest);
1030
+ } catch {
1031
+ orphans = [];
1032
+ }
962
1033
  if (options.dryRun) {
963
1034
  spinner.succeed(pc6.yellow("Dry-run: simulation completed. No files were written."));
964
1035
  console.log(pc6.bold(pc6.yellow("\n[Dry Run] Files that would be created/modified:")));
@@ -966,6 +1037,13 @@ async function addCommand(slug, options = {}) {
966
1037
  const status = fs7.existsSync(file.absolutePath) ? pc6.yellow("(exists, would overwrite)") : pc6.green("(new)");
967
1038
  console.log(` ${pc6.cyan(file.relativePath)} ${status}`);
968
1039
  }
1040
+ if (orphans.length > 0) {
1041
+ console.log(pc6.bold(pc6.yellow("\n[Dry Run] Orphaned files from a previous version:")));
1042
+ for (const o of orphans) {
1043
+ const note = options.prune ? pc6.red("(would remove)") : pc6.dim("(use --prune to remove)");
1044
+ console.log(` ${pc6.cyan(o.relativePath)} ${note}`);
1045
+ }
1046
+ }
969
1047
  const missing = getMissingDependencies(resolvedComponents, projectRoot);
970
1048
  if (missing.length > 0) {
971
1049
  console.log(pc6.yellow(`
@@ -979,6 +1057,7 @@ async function addCommand(slug, options = {}) {
979
1057
  }
980
1058
  if (filesToWrite.length === 0) {
981
1059
  spinner.succeed(pc6.green("All files skipped (already up to date)."));
1060
+ await handlePrune(orphans, targetComponent.slug, options);
982
1061
  return;
983
1062
  }
984
1063
  spinner.text = "Writing component files...";
@@ -1002,6 +1081,7 @@ async function addCommand(slug, options = {}) {
1002
1081
  for (const file of filesToWrite) {
1003
1082
  console.log(` ${pc6.green("\u2714")} ${pc6.cyan(file.relativePath)}`);
1004
1083
  }
1084
+ await handlePrune(orphans, targetComponent.slug, options);
1005
1085
  await handleDependencies(resolvedComponents, projectRoot, projectInfo, options);
1006
1086
  printGuidance(targetComponent, {
1007
1087
  alias: config.aliases.vv,
@@ -1076,6 +1156,7 @@ async function updateCommand(slug, options = {}) {
1076
1156
  const updated = [];
1077
1157
  const upToDate = [];
1078
1158
  const failed = [];
1159
+ const updatedComponents = [];
1079
1160
  for (const target of targets) {
1080
1161
  spinner.text = `Updating ${pc7.cyan(target)}...`;
1081
1162
  try {
@@ -1090,6 +1171,7 @@ async function updateCommand(slug, options = {}) {
1090
1171
  writeFiles(planned.map((f) => ({ absolutePath: f.absolutePath, content: f.content })));
1091
1172
  recordInstall(components, installDir, projectRoot);
1092
1173
  updated.push(`${target} \u2192 ${remote.version}`);
1174
+ updatedComponents.push(...components);
1093
1175
  } catch (error) {
1094
1176
  const message = error instanceof Error ? error.message : String(error);
1095
1177
  failed.push({ slug: target, reason: message });
@@ -1113,6 +1195,9 @@ async function updateCommand(slug, options = {}) {
1113
1195
  for (const f of failed) console.log(` ${pc7.red("\u2716")} ${f.slug}: ${pc7.dim(f.reason)}`);
1114
1196
  }
1115
1197
  console.log("");
1198
+ if (updatedComponents.length > 0) {
1199
+ await handleDependencies(updatedComponents, projectRoot, projectInfo, options);
1200
+ }
1116
1201
  if (failed.length > 0) process.exit(1);
1117
1202
  }
1118
1203
 
@@ -1217,7 +1302,7 @@ Remove ${slug}
1217
1302
  import fs9 from "fs";
1218
1303
  import path9 from "path";
1219
1304
  import pc9 from "picocolors";
1220
- var CLI_VERSION = true ? "0.2.1" : "0.0.0-dev";
1305
+ var CLI_VERSION = true ? "0.3.0" : "0.0.0-dev";
1221
1306
  async function infoCommand() {
1222
1307
  console.log(pc9.bold(pc9.cyan("\nVector Vesper Diagnostics\n")));
1223
1308
  const projectInfo = detectProject();
@@ -1237,17 +1322,6 @@ async function infoCommand() {
1237
1322
  console.log(` \u2022 Has src/ folder: ${pc9.cyan(projectInfo.hasSrcDir ? "Yes" : "No")}`);
1238
1323
  console.log(` \u2022 Tailwind CSS: ${pc9.cyan(projectInfo.hasTailwind ? "Yes" : "No")}`);
1239
1324
  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
1325
  console.log(pc9.bold(pc9.white("Configuration (vv.config.json):")));
1252
1326
  if (config) {
1253
1327
  console.log(` \u2022 Framework Set: ${pc9.cyan(config.framework)}`);
@@ -1526,7 +1600,7 @@ async function whoamiCommand() {
1526
1600
  }
1527
1601
 
1528
1602
  // src/index.ts
1529
- var version = true ? "0.2.1" : "0.0.0-dev";
1603
+ var version = true ? "0.3.0" : "0.0.0-dev";
1530
1604
  var program = new Command();
1531
1605
  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
1606
  const opts = thisCommand.opts();
@@ -1540,10 +1614,10 @@ program.command("init").description("Initialize Vector Vesper configuration in y
1540
1614
  program.command("list").description("List all available components in the registry").action(async () => {
1541
1615
  await listCommand();
1542
1616
  });
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) => {
1617
+ 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
1618
  await addCommand(slug, options);
1545
1619
  });
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) => {
1620
+ 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
1621
  await updateCommand(slug, options);
1548
1622
  });
1549
1623
  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 +1629,13 @@ program.command("info").description("Show project diagnostics and list installed
1555
1629
  program.command("diff [slug]").description("Check for updates against the component registry").action(async (slug) => {
1556
1630
  await diffCommand(slug);
1557
1631
  });
1558
- program.command("login <key>").description("Authenticate with a license key for pro components").action(async (key) => {
1632
+ program.command("login <key>", { hidden: true }).description("Authenticate with a license key for pro components").action(async (key) => {
1559
1633
  await loginCommand(key);
1560
1634
  });
1561
- program.command("logout").description("Clear stored license credentials").action(async () => {
1635
+ program.command("logout", { hidden: true }).description("Clear stored license credentials").action(async () => {
1562
1636
  await logoutCommand();
1563
1637
  });
1564
- program.command("whoami").description("Show current authentication status").action(async () => {
1638
+ program.command("whoami", { hidden: true }).description("Show current authentication status").action(async () => {
1565
1639
  await whoamiCommand();
1566
1640
  });
1567
1641
  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.0",
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",