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.
- package/dist/index.js +107 -30
- 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
|
|
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
|
|
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
|
|
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) => {
|