vectorvesper 1.2.0 → 2.0.1
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/chunk-HOJ3DQSV.js +267 -0
- package/dist/chunk-SFP5K3ZO.js +243 -0
- package/dist/chunk-XN3PPCIM.js +41 -0
- package/dist/hooks.json +886 -0
- package/dist/index.js +299 -722
- package/dist/mcp-ZGA5K5VW.js +107 -0
- package/dist/server-5CFZ6BS7.js +391 -0
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -1,304 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
detectProject,
|
|
4
|
+
fetchComponent,
|
|
5
|
+
fetchRegistryIndex
|
|
6
|
+
} from "./chunk-HOJ3DQSV.js";
|
|
7
|
+
import {
|
|
8
|
+
getAuthToken,
|
|
9
|
+
getGlobalConfigPath,
|
|
10
|
+
loadConfig,
|
|
11
|
+
loadGlobalConfig,
|
|
12
|
+
logger,
|
|
13
|
+
resolveAlias,
|
|
14
|
+
saveGlobalConfig,
|
|
15
|
+
setVerbose,
|
|
16
|
+
validateSlug,
|
|
17
|
+
writeConfig
|
|
18
|
+
} from "./chunk-SFP5K3ZO.js";
|
|
2
19
|
|
|
3
20
|
// src/index.ts
|
|
4
21
|
import { Command } from "commander";
|
|
5
22
|
|
|
6
|
-
// src/utils/logger.ts
|
|
7
|
-
import pc from "picocolors";
|
|
8
|
-
var verboseMode = false;
|
|
9
|
-
function setVerbose(enabled) {
|
|
10
|
-
verboseMode = enabled;
|
|
11
|
-
}
|
|
12
|
-
var logger = {
|
|
13
|
-
/** Standard info message */
|
|
14
|
-
info(message) {
|
|
15
|
-
console.log(message);
|
|
16
|
-
},
|
|
17
|
-
/** Success message with green checkmark */
|
|
18
|
-
success(message) {
|
|
19
|
-
console.log(`${pc.green("\u2714")} ${message}`);
|
|
20
|
-
},
|
|
21
|
-
/** Warning message */
|
|
22
|
-
warn(message) {
|
|
23
|
-
console.log(pc.yellow(`\u26A0\uFE0F ${message}`));
|
|
24
|
-
},
|
|
25
|
-
/** Error message */
|
|
26
|
-
error(message) {
|
|
27
|
-
console.error(pc.red(`\u274C ${message}`));
|
|
28
|
-
},
|
|
29
|
-
/** Debug message — only shown when --verbose is active */
|
|
30
|
-
debug(message) {
|
|
31
|
-
if (verboseMode) {
|
|
32
|
-
console.log(pc.dim(` [debug] ${message}`));
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
/** Blank line */
|
|
36
|
-
break() {
|
|
37
|
-
console.log("");
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
|
|
41
23
|
// src/commands/init.ts
|
|
42
24
|
import { intro, outro, select, text, confirm, isCancel } from "@clack/prompts";
|
|
43
|
-
import
|
|
44
|
-
import fs3 from "fs";
|
|
45
|
-
import path3 from "path";
|
|
46
|
-
|
|
47
|
-
// src/utils/project.ts
|
|
25
|
+
import pc from "picocolors";
|
|
48
26
|
import fs from "fs";
|
|
49
27
|
import path from "path";
|
|
50
|
-
function detectProject(cwd = process.cwd()) {
|
|
51
|
-
const rootPath = cwd;
|
|
52
|
-
let packageManager = "npm";
|
|
53
|
-
if (fs.existsSync(path.join(rootPath, "pnpm-lock.yaml"))) {
|
|
54
|
-
packageManager = "pnpm";
|
|
55
|
-
} else if (fs.existsSync(path.join(rootPath, "yarn.lock"))) {
|
|
56
|
-
packageManager = "yarn";
|
|
57
|
-
} else if (fs.existsSync(path.join(rootPath, "bun.lockb")) || fs.existsSync(path.join(rootPath, "bun.lock"))) {
|
|
58
|
-
packageManager = "bun";
|
|
59
|
-
}
|
|
60
|
-
const isTypeScript = fs.existsSync(path.join(rootPath, "tsconfig.json"));
|
|
61
|
-
const hasSrcDir = fs.existsSync(path.join(rootPath, "src"));
|
|
62
|
-
const pkgPath = path.join(rootPath, "package.json");
|
|
63
|
-
let dependencies = {};
|
|
64
|
-
let devDependencies = {};
|
|
65
|
-
if (fs.existsSync(pkgPath)) {
|
|
66
|
-
try {
|
|
67
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
68
|
-
dependencies = pkg.dependencies || {};
|
|
69
|
-
devDependencies = pkg.devDependencies || {};
|
|
70
|
-
} catch {
|
|
71
|
-
}
|
|
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;
|
|
87
|
-
if (dependencies["next"] || devDependencies["next"]) {
|
|
88
|
-
framework = "next";
|
|
89
|
-
const searchPath = hasSrcDir ? path.join(rootPath, "src") : rootPath;
|
|
90
|
-
if (fs.existsSync(path.join(searchPath, "app"))) {
|
|
91
|
-
nextRouter = "app";
|
|
92
|
-
} else if (fs.existsSync(path.join(searchPath, "pages"))) {
|
|
93
|
-
nextRouter = "pages";
|
|
94
|
-
} else {
|
|
95
|
-
nextRouter = "app";
|
|
96
|
-
}
|
|
97
|
-
} else if (dependencies["vite"] || devDependencies["vite"] || fs.existsSync(path.join(rootPath, "vite.config.ts")) || fs.existsSync(path.join(rootPath, "vite.config.js"))) {
|
|
98
|
-
framework = "vite";
|
|
99
|
-
}
|
|
100
|
-
return {
|
|
101
|
-
packageManager,
|
|
102
|
-
isTypeScript,
|
|
103
|
-
framework,
|
|
104
|
-
nextRouter,
|
|
105
|
-
hasSrcDir,
|
|
106
|
-
hasTailwind,
|
|
107
|
-
rootPath
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// src/utils/config.ts
|
|
112
|
-
import fs2 from "fs";
|
|
113
|
-
import path2 from "path";
|
|
114
|
-
import os from "os";
|
|
115
|
-
|
|
116
|
-
// src/utils/types.ts
|
|
117
|
-
import { z } from "zod";
|
|
118
|
-
var SLUG_REGEX = /^[a-z0-9][a-z0-9-]*$/;
|
|
119
|
-
function validateSlug(slug) {
|
|
120
|
-
if (!SLUG_REGEX.test(slug)) {
|
|
121
|
-
throw new Error(
|
|
122
|
-
`Invalid component slug "${slug}". Slugs must contain only lowercase letters, numbers, and hyphens, and cannot start with a hyphen.`
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
var ComponentFileSchema = z.object({
|
|
127
|
-
path: z.string(),
|
|
128
|
-
target: z.string(),
|
|
129
|
-
type: z.enum(["component", "types", "shader", "lib", "docs"]),
|
|
130
|
-
content: z.string()
|
|
131
|
-
});
|
|
132
|
-
var RegistryComponentSchema = z.object({
|
|
133
|
-
slug: z.string(),
|
|
134
|
-
name: z.string(),
|
|
135
|
-
title: z.string(),
|
|
136
|
-
description: z.string(),
|
|
137
|
-
version: z.string(),
|
|
138
|
-
tier: z.enum(["free", "pro"]),
|
|
139
|
-
category: z.string(),
|
|
140
|
-
type: z.string(),
|
|
141
|
-
frameworks: z.array(z.string()),
|
|
142
|
-
files: z.array(ComponentFileSchema),
|
|
143
|
-
dependencies: z.array(z.string()),
|
|
144
|
-
devDependencies: z.array(z.string()),
|
|
145
|
-
registryDependencies: z.array(z.string()),
|
|
146
|
-
requiresClient: z.boolean(),
|
|
147
|
-
supportsReducedMotion: z.boolean(),
|
|
148
|
-
usesWebGL: z.boolean(),
|
|
149
|
-
usesPointer: z.boolean(),
|
|
150
|
-
usesScroll: z.boolean(),
|
|
151
|
-
// Optional metadata — kept in sync with the registry builder schema.
|
|
152
|
-
// Declared here (rather than relying on .passthrough()) so the CLI can
|
|
153
|
-
// read them with full type-safety for post-install guidance.
|
|
154
|
-
entry: z.string().optional(),
|
|
155
|
-
exportName: z.string().optional(),
|
|
156
|
-
usesTailwind: z.boolean().optional(),
|
|
157
|
-
fallbacks: z.array(z.string()).optional(),
|
|
158
|
-
recipes: z.array(z.string()).optional(),
|
|
159
|
-
docsUrl: z.string().optional(),
|
|
160
|
-
previewUrl: z.string().optional()
|
|
161
|
-
}).passthrough();
|
|
162
|
-
var IndexComponentSchema = z.object({
|
|
163
|
-
slug: z.string(),
|
|
164
|
-
name: z.string(),
|
|
165
|
-
title: z.string(),
|
|
166
|
-
description: z.string(),
|
|
167
|
-
version: z.string(),
|
|
168
|
-
tier: z.enum(["free", "pro"]),
|
|
169
|
-
category: z.string(),
|
|
170
|
-
type: z.string(),
|
|
171
|
-
frameworks: z.array(z.string()),
|
|
172
|
-
files: z.array(z.object({
|
|
173
|
-
path: z.string(),
|
|
174
|
-
target: z.string(),
|
|
175
|
-
type: z.enum(["component", "types", "shader", "lib", "docs"])
|
|
176
|
-
})),
|
|
177
|
-
dependencies: z.array(z.string()),
|
|
178
|
-
devDependencies: z.array(z.string()),
|
|
179
|
-
registryDependencies: z.array(z.string()),
|
|
180
|
-
requiresClient: z.boolean(),
|
|
181
|
-
supportsReducedMotion: z.boolean(),
|
|
182
|
-
usesWebGL: z.boolean(),
|
|
183
|
-
usesPointer: z.boolean(),
|
|
184
|
-
usesScroll: z.boolean(),
|
|
185
|
-
entry: z.string().optional(),
|
|
186
|
-
exportName: z.string().optional(),
|
|
187
|
-
usesTailwind: z.boolean().optional()
|
|
188
|
-
}).passthrough();
|
|
189
|
-
var RegistryIndexSchema = z.object({
|
|
190
|
-
version: z.string(),
|
|
191
|
-
components: z.array(IndexComponentSchema)
|
|
192
|
-
});
|
|
193
|
-
var VVConfigSchema = z.object({
|
|
194
|
-
tsx: z.boolean(),
|
|
195
|
-
framework: z.enum(["next", "vite", "unknown"]),
|
|
196
|
-
aliases: z.object({
|
|
197
|
-
vv: z.string()
|
|
198
|
-
})
|
|
199
|
-
});
|
|
200
|
-
var VVGlobalConfigSchema = z.object({
|
|
201
|
-
// Auth — license key for paid components
|
|
202
|
-
auth: z.object({
|
|
203
|
-
token: z.string().optional(),
|
|
204
|
-
email: z.string().optional(),
|
|
205
|
-
tier: z.enum(["free", "pro", "team"]).optional(),
|
|
206
|
-
expiresAt: z.string().optional()
|
|
207
|
-
}).optional(),
|
|
208
|
-
// Preferences
|
|
209
|
-
telemetry: z.boolean().optional()
|
|
210
|
-
}).passthrough();
|
|
211
|
-
var ManifestEntrySchema = z.object({
|
|
212
|
-
version: z.string(),
|
|
213
|
-
installedAt: z.string(),
|
|
214
|
-
installedOn: z.string(),
|
|
215
|
-
files: z.array(z.string())
|
|
216
|
-
});
|
|
217
|
-
var ManifestSchema = z.object({
|
|
218
|
-
components: z.record(z.string(), ManifestEntrySchema)
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
// src/utils/config.ts
|
|
222
|
-
var CONFIG_FILE_NAME = "vv.config.json";
|
|
223
|
-
function getConfigPath(cwd = process.cwd()) {
|
|
224
|
-
return path2.join(cwd, CONFIG_FILE_NAME);
|
|
225
|
-
}
|
|
226
|
-
function loadConfig(cwd = process.cwd()) {
|
|
227
|
-
const configPath = getConfigPath(cwd);
|
|
228
|
-
if (!fs2.existsSync(configPath)) {
|
|
229
|
-
return null;
|
|
230
|
-
}
|
|
231
|
-
let raw;
|
|
232
|
-
try {
|
|
233
|
-
const content = fs2.readFileSync(configPath, "utf-8");
|
|
234
|
-
raw = JSON.parse(content);
|
|
235
|
-
} catch {
|
|
236
|
-
throw new Error(
|
|
237
|
-
`Failed to parse vv.config.json \u2014 the file contains invalid JSON. Delete it and run "npx vectorvesper init" to regenerate.`
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
|
-
const result = VVConfigSchema.safeParse(raw);
|
|
241
|
-
if (!result.success) {
|
|
242
|
-
const issues = result.error.issues.map((i) => ` \u2022 ${i.path.join(".")}: ${i.message}`).join("\n");
|
|
243
|
-
throw new Error(
|
|
244
|
-
`Invalid vv.config.json \u2014 schema validation failed:
|
|
245
|
-
${issues}
|
|
246
|
-
Delete the file and run "npx vectorvesper init" to regenerate.`
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
return result.data;
|
|
250
|
-
}
|
|
251
|
-
function writeConfig(config, cwd = process.cwd()) {
|
|
252
|
-
const configPath = getConfigPath(cwd);
|
|
253
|
-
fs2.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
254
|
-
}
|
|
255
|
-
var GLOBAL_CONFIG_DIR = path2.join(os.homedir(), ".vv");
|
|
256
|
-
var GLOBAL_CONFIG_PATH = path2.join(GLOBAL_CONFIG_DIR, "config.json");
|
|
257
|
-
function getGlobalConfigPath() {
|
|
258
|
-
return GLOBAL_CONFIG_PATH;
|
|
259
|
-
}
|
|
260
|
-
function loadGlobalConfig() {
|
|
261
|
-
if (!fs2.existsSync(GLOBAL_CONFIG_PATH)) {
|
|
262
|
-
return {};
|
|
263
|
-
}
|
|
264
|
-
try {
|
|
265
|
-
const content = fs2.readFileSync(GLOBAL_CONFIG_PATH, "utf-8");
|
|
266
|
-
const raw = JSON.parse(content);
|
|
267
|
-
const result = VVGlobalConfigSchema.safeParse(raw);
|
|
268
|
-
if (!result.success) {
|
|
269
|
-
logger.debug(`Global config validation failed: ${result.error.message}`);
|
|
270
|
-
return {};
|
|
271
|
-
}
|
|
272
|
-
return result.data;
|
|
273
|
-
} catch {
|
|
274
|
-
logger.debug("Failed to parse global config, using defaults.");
|
|
275
|
-
return {};
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
function saveGlobalConfig(config) {
|
|
279
|
-
if (!fs2.existsSync(GLOBAL_CONFIG_DIR)) {
|
|
280
|
-
fs2.mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true });
|
|
281
|
-
}
|
|
282
|
-
fs2.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
|
|
283
|
-
}
|
|
284
|
-
function getAuthToken() {
|
|
285
|
-
const config = loadGlobalConfig();
|
|
286
|
-
return config.auth?.token;
|
|
287
|
-
}
|
|
288
|
-
function resolveAlias(alias, hasSrcDir) {
|
|
289
|
-
if (alias.startsWith("@/")) {
|
|
290
|
-
return alias.replace("@/", hasSrcDir ? "src/" : "");
|
|
291
|
-
}
|
|
292
|
-
if (alias.startsWith("~/")) {
|
|
293
|
-
return alias.replace("~/", hasSrcDir ? "src/" : "");
|
|
294
|
-
}
|
|
295
|
-
return alias;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// src/commands/init.ts
|
|
299
28
|
async function initCommand(options = {}) {
|
|
300
29
|
console.log("");
|
|
301
|
-
intro(
|
|
30
|
+
intro(pc.cyan(pc.bold(" Vector Vesper Setup ")));
|
|
302
31
|
const projectInfo = detectProject();
|
|
303
32
|
let tsx = projectInfo.isTypeScript;
|
|
304
33
|
let framework = projectInfo.framework;
|
|
@@ -308,39 +37,39 @@ async function initCommand(options = {}) {
|
|
|
308
37
|
const existingConfig = loadConfig();
|
|
309
38
|
if (existingConfig) {
|
|
310
39
|
const shouldOverwrite = await confirm({
|
|
311
|
-
message:
|
|
40
|
+
message: pc.yellow("vv.config.json already exists. Overwrite it?"),
|
|
312
41
|
initialValue: false
|
|
313
42
|
});
|
|
314
43
|
if (isCancel(shouldOverwrite) || !shouldOverwrite) {
|
|
315
|
-
outro(
|
|
44
|
+
outro(pc.red("Setup cancelled."));
|
|
316
45
|
return;
|
|
317
46
|
}
|
|
318
47
|
}
|
|
319
48
|
} catch (error) {
|
|
320
49
|
const message = error instanceof Error ? error.message : String(error);
|
|
321
|
-
console.log(
|
|
50
|
+
console.log(pc.yellow(`
|
|
322
51
|
\u26A0\uFE0F ${message}
|
|
323
52
|
`));
|
|
324
53
|
const shouldReplace = await confirm({
|
|
325
|
-
message:
|
|
54
|
+
message: pc.yellow("Replace the corrupted config?"),
|
|
326
55
|
initialValue: true
|
|
327
56
|
});
|
|
328
57
|
if (isCancel(shouldReplace) || !shouldReplace) {
|
|
329
|
-
outro(
|
|
58
|
+
outro(pc.red("Setup cancelled."));
|
|
330
59
|
return;
|
|
331
60
|
}
|
|
332
61
|
}
|
|
333
62
|
const tsxResponse = await confirm({
|
|
334
|
-
message: `Use TypeScript? ${
|
|
63
|
+
message: `Use TypeScript? ${pc.dim(`(Detected: ${projectInfo.isTypeScript ? "Yes" : "No"})`)}`,
|
|
335
64
|
initialValue: projectInfo.isTypeScript
|
|
336
65
|
});
|
|
337
66
|
if (isCancel(tsxResponse)) {
|
|
338
|
-
outro(
|
|
67
|
+
outro(pc.red("Setup cancelled."));
|
|
339
68
|
return;
|
|
340
69
|
}
|
|
341
70
|
tsx = tsxResponse;
|
|
342
71
|
const frameworkResponse = await select({
|
|
343
|
-
message: `Configure your framework: ${
|
|
72
|
+
message: `Configure your framework: ${pc.dim(`(Detected: ${projectInfo.framework})`)}`,
|
|
344
73
|
options: [
|
|
345
74
|
{ value: "next", label: "Next.js" },
|
|
346
75
|
{ value: "vite", label: "Vite" },
|
|
@@ -349,7 +78,7 @@ async function initCommand(options = {}) {
|
|
|
349
78
|
initialValue: projectInfo.framework
|
|
350
79
|
});
|
|
351
80
|
if (isCancel(frameworkResponse)) {
|
|
352
|
-
outro(
|
|
81
|
+
outro(pc.red("Setup cancelled."));
|
|
353
82
|
return;
|
|
354
83
|
}
|
|
355
84
|
framework = frameworkResponse;
|
|
@@ -365,15 +94,15 @@ async function initCommand(options = {}) {
|
|
|
365
94
|
}
|
|
366
95
|
});
|
|
367
96
|
if (isCancel(aliasResponse)) {
|
|
368
|
-
outro(
|
|
97
|
+
outro(pc.red("Setup cancelled."));
|
|
369
98
|
return;
|
|
370
99
|
}
|
|
371
100
|
aliasInput = aliasResponse;
|
|
372
101
|
} else {
|
|
373
|
-
console.log(
|
|
374
|
-
console.log(
|
|
375
|
-
console.log(
|
|
376
|
-
console.log(
|
|
102
|
+
console.log(pc.dim(` \u26A1 Running in non-interactive mode (-y)`));
|
|
103
|
+
console.log(pc.dim(` \u2022 TypeScript: ${tsx ? "Yes" : "No"}`));
|
|
104
|
+
console.log(pc.dim(` \u2022 Framework: ${framework}`));
|
|
105
|
+
console.log(pc.dim(` \u2022 Components Alias: ${aliasInput}`));
|
|
377
106
|
}
|
|
378
107
|
const config = {
|
|
379
108
|
tsx,
|
|
@@ -385,190 +114,34 @@ async function initCommand(options = {}) {
|
|
|
385
114
|
try {
|
|
386
115
|
writeConfig(config);
|
|
387
116
|
const targetLocalDir = resolveAlias(aliasInput, projectInfo.hasSrcDir);
|
|
388
|
-
const absoluteTargetDir =
|
|
389
|
-
if (!
|
|
390
|
-
|
|
117
|
+
const absoluteTargetDir = path.join(process.cwd(), targetLocalDir);
|
|
118
|
+
if (!fs.existsSync(absoluteTargetDir)) {
|
|
119
|
+
fs.mkdirSync(absoluteTargetDir, { recursive: true });
|
|
391
120
|
}
|
|
392
|
-
const manifestPath =
|
|
393
|
-
if (!
|
|
394
|
-
|
|
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");
|
|
395
124
|
}
|
|
396
125
|
console.log("");
|
|
397
126
|
outro(
|
|
398
|
-
`${
|
|
127
|
+
`${pc.green(pc.bold("\u2714 Success!"))} Vector Vesper initialized.
|
|
399
128
|
|
|
400
|
-
\u2022 Configuration written to ${
|
|
401
|
-
\u2022 Target directory created at ${
|
|
402
|
-
\u2022 Manifest created at ${
|
|
129
|
+
\u2022 Configuration written to ${pc.cyan("vv.config.json")}
|
|
130
|
+
\u2022 Target directory created at ${pc.cyan(targetLocalDir)}
|
|
131
|
+
\u2022 Manifest created at ${pc.cyan("vv-manifest.json")}
|
|
403
132
|
|
|
404
|
-
\u{1F449} Next, run: ${
|
|
133
|
+
\u{1F449} Next, run: ${pc.bold(pc.cyan("npx vectorvesper add <slug>"))} to add a component.`
|
|
405
134
|
);
|
|
406
135
|
} catch (error) {
|
|
407
136
|
const message = error instanceof Error ? error.message : String(error);
|
|
408
|
-
outro(
|
|
137
|
+
outro(pc.red(`Failed to initialize: ${message}`));
|
|
409
138
|
process.exit(1);
|
|
410
139
|
}
|
|
411
140
|
}
|
|
412
141
|
|
|
413
142
|
// src/commands/list.ts
|
|
414
|
-
import
|
|
143
|
+
import pc2 from "picocolors";
|
|
415
144
|
import ora from "ora";
|
|
416
|
-
|
|
417
|
-
// src/utils/registry.ts
|
|
418
|
-
import fs4 from "fs";
|
|
419
|
-
import path4 from "path";
|
|
420
|
-
import { fileURLToPath } from "url";
|
|
421
|
-
var DEFAULT_REGISTRY_URL = "https://raw.githubusercontent.com/vectorvesper/vv-components/main/r";
|
|
422
|
-
var FETCH_TIMEOUT_MS = 15e3;
|
|
423
|
-
var MAX_RETRIES = 1;
|
|
424
|
-
var RETRY_DELAY_MS = 1e3;
|
|
425
|
-
function getRegistryBaseUrl() {
|
|
426
|
-
return process.env.VV_REGISTRY_URL || DEFAULT_REGISTRY_URL;
|
|
427
|
-
}
|
|
428
|
-
function handleHttpError(status, url) {
|
|
429
|
-
switch (status) {
|
|
430
|
-
case 401:
|
|
431
|
-
throw new Error(
|
|
432
|
-
`Authentication required. This component requires a valid license key.
|
|
433
|
-
\u{1F449} Run "npx vectorvesper login <your-license-key>" to authenticate.
|
|
434
|
-
\u{1F511} Get a license at https://vectorvesper.dev/pricing`
|
|
435
|
-
);
|
|
436
|
-
case 402:
|
|
437
|
-
throw new Error(
|
|
438
|
-
`This is a Pro component and requires a license.
|
|
439
|
-
\u{1F449} Get lifetime access at https://vectorvesper.dev/pricing
|
|
440
|
-
\u{1F4A1} Run "npx vectorvesper list" to see all free components.`
|
|
441
|
-
);
|
|
442
|
-
case 403:
|
|
443
|
-
throw new Error(
|
|
444
|
-
`Access denied. Your license doesn't include this component.
|
|
445
|
-
\u{1F449} Check your account at https://vectorvesper.dev/account
|
|
446
|
-
\u{1F4A1} Run "npx vectorvesper whoami" to see your current access.`
|
|
447
|
-
);
|
|
448
|
-
case 404:
|
|
449
|
-
throw new Error(
|
|
450
|
-
`Component not found in the registry.
|
|
451
|
-
\u{1F449} Run "npx vectorvesper list" to see all available components.`
|
|
452
|
-
);
|
|
453
|
-
case 429:
|
|
454
|
-
throw new Error(
|
|
455
|
-
`Rate limited by the registry. Please wait a moment and try again.`
|
|
456
|
-
);
|
|
457
|
-
default:
|
|
458
|
-
throw new Error(
|
|
459
|
-
`Registry request failed: HTTP ${status}
|
|
460
|
-
URL: ${url}`
|
|
461
|
-
);
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
async function fetchWithRetry(url) {
|
|
465
|
-
const token = getAuthToken();
|
|
466
|
-
const headers = {
|
|
467
|
-
"User-Agent": "vv-cli",
|
|
468
|
-
"Accept": "application/json"
|
|
469
|
-
};
|
|
470
|
-
const isPublicRegistry = url.includes("raw.githubusercontent.com");
|
|
471
|
-
if (token && !isPublicRegistry) {
|
|
472
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
473
|
-
logger.debug(`Using auth token for request`);
|
|
474
|
-
}
|
|
475
|
-
let lastError = null;
|
|
476
|
-
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
477
|
-
try {
|
|
478
|
-
if (attempt > 0) {
|
|
479
|
-
logger.debug(`Retry attempt ${attempt} for ${url}`);
|
|
480
|
-
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS * attempt));
|
|
481
|
-
}
|
|
482
|
-
logger.debug(`Fetching: ${url}`);
|
|
483
|
-
const response = await fetch(url, {
|
|
484
|
-
headers,
|
|
485
|
-
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
486
|
-
});
|
|
487
|
-
if (!response.ok) {
|
|
488
|
-
if (response.status >= 400 && response.status < 500) {
|
|
489
|
-
handleHttpError(response.status, url);
|
|
490
|
-
}
|
|
491
|
-
throw new Error(`HTTP ${response.status}`);
|
|
492
|
-
}
|
|
493
|
-
return await response.text();
|
|
494
|
-
} catch (error) {
|
|
495
|
-
if (error instanceof Error) {
|
|
496
|
-
if (error.message.includes("Authentication required") || error.message.includes("Pro component") || error.message.includes("Access denied") || error.message.includes("not found in the registry")) {
|
|
497
|
-
throw error;
|
|
498
|
-
}
|
|
499
|
-
if (error.name === "TimeoutError" || error.name === "AbortError") {
|
|
500
|
-
lastError = new Error(
|
|
501
|
-
`Request timed out after ${FETCH_TIMEOUT_MS / 1e3}s. Check your internet connection or try again.`
|
|
502
|
-
);
|
|
503
|
-
continue;
|
|
504
|
-
}
|
|
505
|
-
lastError = error;
|
|
506
|
-
} else {
|
|
507
|
-
lastError = new Error(String(error));
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
throw lastError || new Error(`Failed to fetch: ${url}`);
|
|
512
|
-
}
|
|
513
|
-
async function fetchRegistryData(urlOrPath) {
|
|
514
|
-
if (urlOrPath.startsWith("http://") || urlOrPath.startsWith("https://")) {
|
|
515
|
-
if (urlOrPath.startsWith("http://") && !urlOrPath.includes("localhost") && !urlOrPath.includes("127.0.0.1")) {
|
|
516
|
-
logger.warn("Using insecure HTTP for registry. Consider switching to HTTPS.");
|
|
517
|
-
}
|
|
518
|
-
return fetchWithRetry(urlOrPath);
|
|
519
|
-
}
|
|
520
|
-
let cleanPath = urlOrPath;
|
|
521
|
-
if (urlOrPath.startsWith("file://")) {
|
|
522
|
-
cleanPath = fileURLToPath(urlOrPath);
|
|
523
|
-
}
|
|
524
|
-
cleanPath = path4.resolve(cleanPath);
|
|
525
|
-
if (!fs4.existsSync(cleanPath)) {
|
|
526
|
-
throw new Error(`Registry path not found: ${cleanPath}`);
|
|
527
|
-
}
|
|
528
|
-
logger.debug(`Reading local registry: ${cleanPath}`);
|
|
529
|
-
return fs4.readFileSync(cleanPath, "utf-8");
|
|
530
|
-
}
|
|
531
|
-
async function fetchRegistryIndex() {
|
|
532
|
-
const baseUrl = getRegistryBaseUrl();
|
|
533
|
-
const url = baseUrl.endsWith("/") ? `${baseUrl}registry.json` : `${baseUrl}/registry.json`;
|
|
534
|
-
const content = await fetchRegistryData(url);
|
|
535
|
-
let raw;
|
|
536
|
-
try {
|
|
537
|
-
raw = JSON.parse(content);
|
|
538
|
-
} catch {
|
|
539
|
-
throw new Error("Failed to parse registry index \u2014 received invalid JSON.");
|
|
540
|
-
}
|
|
541
|
-
const result = RegistryIndexSchema.safeParse(raw);
|
|
542
|
-
if (!result.success) {
|
|
543
|
-
logger.debug(`Registry index validation errors: ${result.error.message}`);
|
|
544
|
-
throw new Error("Registry index failed validation. The registry may be corrupted or incompatible with this CLI version.");
|
|
545
|
-
}
|
|
546
|
-
return result.data;
|
|
547
|
-
}
|
|
548
|
-
async function fetchComponent(slug) {
|
|
549
|
-
validateSlug(slug);
|
|
550
|
-
const baseUrl = getRegistryBaseUrl();
|
|
551
|
-
const url = baseUrl.endsWith("/") ? `${baseUrl}${slug}.json` : `${baseUrl}/${slug}.json`;
|
|
552
|
-
const content = await fetchRegistryData(url);
|
|
553
|
-
let raw;
|
|
554
|
-
try {
|
|
555
|
-
raw = JSON.parse(content);
|
|
556
|
-
} catch {
|
|
557
|
-
throw new Error(`Failed to parse component "${slug}" \u2014 received invalid JSON.`);
|
|
558
|
-
}
|
|
559
|
-
const result = RegistryComponentSchema.safeParse(raw);
|
|
560
|
-
if (!result.success) {
|
|
561
|
-
const issues = result.error.issues.map((i) => ` \u2022 ${i.path.join(".")}: ${i.message}`).join("\n");
|
|
562
|
-
logger.debug(`Component "${slug}" validation errors:
|
|
563
|
-
${issues}`);
|
|
564
|
-
throw new Error(
|
|
565
|
-
`Component "${slug}" failed validation. This may indicate an incompatible registry version. Try updating the CLI.`
|
|
566
|
-
);
|
|
567
|
-
}
|
|
568
|
-
return result.data;
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
// src/commands/list.ts
|
|
572
145
|
async function listCommand() {
|
|
573
146
|
const spinner = ora({
|
|
574
147
|
text: "Fetching components list...",
|
|
@@ -576,55 +149,55 @@ async function listCommand() {
|
|
|
576
149
|
}).start();
|
|
577
150
|
try {
|
|
578
151
|
const registry = await fetchRegistryIndex();
|
|
579
|
-
spinner.succeed(
|
|
152
|
+
spinner.succeed(pc2.green("Fetched components list successfully!\n"));
|
|
580
153
|
if (registry.components.length === 0) {
|
|
581
|
-
console.log(
|
|
582
|
-
console.log(
|
|
154
|
+
console.log(pc2.dim(" No components available in the registry yet."));
|
|
155
|
+
console.log(pc2.dim(" Check back soon or visit https://vectorvesper.dev\n"));
|
|
583
156
|
return;
|
|
584
157
|
}
|
|
585
158
|
const hasAuth = !!getAuthToken();
|
|
586
|
-
console.log(
|
|
587
|
-
console.log(
|
|
159
|
+
console.log(pc2.bold(pc2.white("Vector Vesper Available Components:")));
|
|
160
|
+
console.log(pc2.dim("--------------------------------------------------------------------------------"));
|
|
588
161
|
for (const c of registry.components) {
|
|
589
|
-
const slugCol =
|
|
590
|
-
const categoryCol =
|
|
162
|
+
const slugCol = pc2.cyan(c.slug.padEnd(25));
|
|
163
|
+
const categoryCol = pc2.yellow(c.category.padEnd(15));
|
|
591
164
|
let tierBadge;
|
|
592
165
|
if (c.tier === "pro") {
|
|
593
|
-
tierBadge = hasAuth ?
|
|
166
|
+
tierBadge = hasAuth ? pc2.magenta("pro ") : pc2.dim("\u{1F512} ");
|
|
594
167
|
} else {
|
|
595
|
-
tierBadge =
|
|
168
|
+
tierBadge = pc2.green("free");
|
|
596
169
|
}
|
|
597
|
-
console.log(`${slugCol} [${tierBadge}] ${categoryCol} ${
|
|
170
|
+
console.log(`${slugCol} [${tierBadge}] ${categoryCol} ${pc2.gray(c.description)}`);
|
|
598
171
|
}
|
|
599
|
-
console.log(
|
|
172
|
+
console.log(pc2.dim("--------------------------------------------------------------------------------"));
|
|
600
173
|
const freeCount = registry.components.filter((c) => c.tier === "free").length;
|
|
601
174
|
const proCount = registry.components.filter((c) => c.tier === "pro").length;
|
|
602
175
|
console.log(`
|
|
603
|
-
${
|
|
176
|
+
${pc2.green(String(freeCount))} free components${proCount > 0 ? ` \xB7 ${pc2.magenta(String(proCount))} pro components` : ""}`);
|
|
604
177
|
if (proCount > 0 && !hasAuth) {
|
|
605
|
-
console.log(` \u{1F511} ${
|
|
178
|
+
console.log(` \u{1F511} ${pc2.dim("Unlock pro components:")} ${pc2.cyan("npx vectorvesper login <key>")} ${pc2.dim("\xB7")} ${pc2.cyan("https://vectorvesper.dev/pricing")}`);
|
|
606
179
|
}
|
|
607
180
|
console.log(`
|
|
608
|
-
\u{1F449} Run ${
|
|
181
|
+
\u{1F449} Run ${pc2.bold(pc2.cyan("npx vectorvesper add <slug>"))} to add a component to your project.
|
|
609
182
|
`);
|
|
610
183
|
} catch (error) {
|
|
611
184
|
const message = error instanceof Error ? error.message : String(error);
|
|
612
|
-
spinner.fail(
|
|
185
|
+
spinner.fail(pc2.red(`Failed to fetch components list: ${message}`));
|
|
613
186
|
process.exit(1);
|
|
614
187
|
}
|
|
615
188
|
}
|
|
616
189
|
|
|
617
190
|
// src/commands/add.ts
|
|
618
|
-
import
|
|
619
|
-
import
|
|
191
|
+
import fs4 from "fs";
|
|
192
|
+
import path4 from "path";
|
|
620
193
|
import ora2 from "ora";
|
|
621
|
-
import
|
|
194
|
+
import pc5 from "picocolors";
|
|
622
195
|
import { confirm as confirm2, isCancel as isCancel2 } from "@clack/prompts";
|
|
623
196
|
|
|
624
197
|
// src/utils/installer.ts
|
|
625
|
-
import
|
|
626
|
-
import
|
|
627
|
-
import
|
|
198
|
+
import fs2 from "fs";
|
|
199
|
+
import path2 from "path";
|
|
200
|
+
import pc3 from "picocolors";
|
|
628
201
|
var MAX_DEPTH = 20;
|
|
629
202
|
function toForwardSlash(p) {
|
|
630
203
|
return p.replace(/\\/g, "/");
|
|
@@ -644,8 +217,8 @@ async function resolveComponentTree(slug) {
|
|
|
644
217
|
if (component.tier === "pro" && !getAuthToken()) {
|
|
645
218
|
throw new Error(
|
|
646
219
|
`"${componentSlug}" is a Pro component and requires a license.
|
|
647
|
-
\u{1F449} Run ${
|
|
648
|
-
\u{1F511} Get a license at ${
|
|
220
|
+
\u{1F449} Run ${pc3.cyan("npx vectorvesper login <your-license-key>")} to unlock pro components.
|
|
221
|
+
\u{1F511} Get a license at ${pc3.cyan("https://vectorvesper.dev/pricing")}`
|
|
649
222
|
);
|
|
650
223
|
}
|
|
651
224
|
for (const depSlug of component.registryDependencies ?? []) {
|
|
@@ -658,12 +231,12 @@ async function resolveComponentTree(slug) {
|
|
|
658
231
|
}
|
|
659
232
|
function planFiles(components, installDir, projectRoot) {
|
|
660
233
|
const planned = [];
|
|
661
|
-
const compDir =
|
|
234
|
+
const compDir = path2.join(projectRoot, installDir);
|
|
662
235
|
for (const component of components) {
|
|
663
236
|
for (const file of component.files) {
|
|
664
|
-
const absolutePath =
|
|
665
|
-
const relativeFromRoot =
|
|
666
|
-
if (relativeFromRoot.startsWith("..") ||
|
|
237
|
+
const absolutePath = path2.resolve(compDir, file.target);
|
|
238
|
+
const relativeFromRoot = path2.relative(projectRoot, absolutePath);
|
|
239
|
+
if (relativeFromRoot.startsWith("..") || path2.isAbsolute(relativeFromRoot)) {
|
|
667
240
|
throw new Error(
|
|
668
241
|
`Security Error: component target tries to escape project root: ${file.target}`
|
|
669
242
|
);
|
|
@@ -673,7 +246,7 @@ function planFiles(components, installDir, projectRoot) {
|
|
|
673
246
|
relativePath: relativeFromRoot,
|
|
674
247
|
target: file.target,
|
|
675
248
|
content: file.content,
|
|
676
|
-
exists:
|
|
249
|
+
exists: fs2.existsSync(absolutePath)
|
|
677
250
|
});
|
|
678
251
|
}
|
|
679
252
|
}
|
|
@@ -681,28 +254,28 @@ function planFiles(components, installDir, projectRoot) {
|
|
|
681
254
|
}
|
|
682
255
|
function writeFiles(files) {
|
|
683
256
|
for (const file of files) {
|
|
684
|
-
const folder =
|
|
685
|
-
if (!
|
|
686
|
-
|
|
257
|
+
const folder = path2.dirname(file.absolutePath);
|
|
258
|
+
if (!fs2.existsSync(folder)) {
|
|
259
|
+
fs2.mkdirSync(folder, { recursive: true });
|
|
687
260
|
}
|
|
688
|
-
|
|
261
|
+
fs2.writeFileSync(file.absolutePath, file.content, "utf-8");
|
|
689
262
|
}
|
|
690
263
|
}
|
|
691
264
|
var MANIFEST_NAME = "vv-manifest.json";
|
|
692
265
|
function getManifestPath(projectRoot) {
|
|
693
|
-
return
|
|
266
|
+
return path2.join(projectRoot, MANIFEST_NAME);
|
|
694
267
|
}
|
|
695
268
|
function readManifest(projectRoot) {
|
|
696
269
|
const manifestPath = getManifestPath(projectRoot);
|
|
697
|
-
if (!
|
|
270
|
+
if (!fs2.existsSync(manifestPath)) {
|
|
698
271
|
return { components: {} };
|
|
699
272
|
}
|
|
700
|
-
const parsed = JSON.parse(
|
|
273
|
+
const parsed = JSON.parse(fs2.readFileSync(manifestPath, "utf-8"));
|
|
701
274
|
if (!parsed.components) parsed.components = {};
|
|
702
275
|
return parsed;
|
|
703
276
|
}
|
|
704
277
|
function writeManifest(projectRoot, manifest) {
|
|
705
|
-
|
|
278
|
+
fs2.writeFileSync(getManifestPath(projectRoot), JSON.stringify(manifest, null, 2), "utf-8");
|
|
706
279
|
}
|
|
707
280
|
function recordInstall(components, installDir, projectRoot) {
|
|
708
281
|
const manifest = readManifest(projectRoot);
|
|
@@ -710,7 +283,7 @@ function recordInstall(components, installDir, projectRoot) {
|
|
|
710
283
|
for (const component of components) {
|
|
711
284
|
manifest.components[component.slug] = {
|
|
712
285
|
version: component.version,
|
|
713
|
-
installedAt: toForwardSlash(
|
|
286
|
+
installedAt: toForwardSlash(path2.join(installDir, component.slug)),
|
|
714
287
|
installedOn: today,
|
|
715
288
|
files: component.files.map((f) => f.target)
|
|
716
289
|
};
|
|
@@ -718,7 +291,7 @@ function recordInstall(components, installDir, projectRoot) {
|
|
|
718
291
|
writeManifest(projectRoot, manifest);
|
|
719
292
|
}
|
|
720
293
|
function findOrphanedFiles(components, installDir, projectRoot, previousManifest) {
|
|
721
|
-
const compDir =
|
|
294
|
+
const compDir = path2.join(projectRoot, installDir);
|
|
722
295
|
const currentTargets = /* @__PURE__ */ new Set();
|
|
723
296
|
for (const component of components) {
|
|
724
297
|
for (const file of component.files) currentTargets.add(file.target);
|
|
@@ -732,10 +305,10 @@ function findOrphanedFiles(components, installDir, projectRoot, previousManifest
|
|
|
732
305
|
if (currentTargets.has(target)) continue;
|
|
733
306
|
if (seen.has(target)) continue;
|
|
734
307
|
seen.add(target);
|
|
735
|
-
const absolutePath =
|
|
736
|
-
const relativeFromRoot =
|
|
737
|
-
if (relativeFromRoot.startsWith("..") ||
|
|
738
|
-
if (!
|
|
308
|
+
const absolutePath = path2.resolve(compDir, target);
|
|
309
|
+
const relativeFromRoot = path2.relative(projectRoot, absolutePath);
|
|
310
|
+
if (relativeFromRoot.startsWith("..") || path2.isAbsolute(relativeFromRoot)) continue;
|
|
311
|
+
if (!fs2.existsSync(absolutePath)) continue;
|
|
739
312
|
orphans.push({ absolutePath, relativePath: relativeFromRoot, target });
|
|
740
313
|
}
|
|
741
314
|
}
|
|
@@ -743,26 +316,26 @@ function findOrphanedFiles(components, installDir, projectRoot, previousManifest
|
|
|
743
316
|
}
|
|
744
317
|
function removeFiles(files) {
|
|
745
318
|
for (const file of files) {
|
|
746
|
-
if (
|
|
747
|
-
|
|
319
|
+
if (fs2.existsSync(file.absolutePath)) {
|
|
320
|
+
fs2.rmSync(file.absolutePath, { force: true });
|
|
748
321
|
}
|
|
749
322
|
}
|
|
750
323
|
}
|
|
751
324
|
|
|
752
325
|
// src/utils/install.ts
|
|
753
|
-
import
|
|
754
|
-
import
|
|
326
|
+
import fs3 from "fs";
|
|
327
|
+
import path3 from "path";
|
|
755
328
|
import { spawnSync } from "child_process";
|
|
756
329
|
var NPM_NAME_REGEX = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/i;
|
|
757
330
|
function isValidPackageName(name) {
|
|
758
331
|
return NPM_NAME_REGEX.test(name);
|
|
759
332
|
}
|
|
760
333
|
function getMissingDependencies(components, projectRoot) {
|
|
761
|
-
const pkgPath =
|
|
762
|
-
if (!
|
|
334
|
+
const pkgPath = path3.join(projectRoot, "package.json");
|
|
335
|
+
if (!fs3.existsSync(pkgPath)) return [];
|
|
763
336
|
let installed = {};
|
|
764
337
|
try {
|
|
765
|
-
const pkg = JSON.parse(
|
|
338
|
+
const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
|
|
766
339
|
installed = {
|
|
767
340
|
...pkg.dependencies,
|
|
768
341
|
...pkg.devDependencies,
|
|
@@ -807,7 +380,7 @@ function installDependencies(deps, pm, projectRoot) {
|
|
|
807
380
|
}
|
|
808
381
|
|
|
809
382
|
// src/utils/guidance.ts
|
|
810
|
-
import
|
|
383
|
+
import pc4 from "picocolors";
|
|
811
384
|
function toPascalCase(input) {
|
|
812
385
|
return input.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
813
386
|
}
|
|
@@ -858,24 +431,24 @@ const ${varName} = dynamic(
|
|
|
858
431
|
}
|
|
859
432
|
function printGuidance(component, ctx) {
|
|
860
433
|
const g = buildGuidance(component, ctx);
|
|
861
|
-
console.log(
|
|
434
|
+
console.log(pc4.bold(pc4.white(`
|
|
862
435
|
Using ${component.title || component.name}:`)));
|
|
863
436
|
if (g.ssrSnippet) {
|
|
864
|
-
console.log(
|
|
437
|
+
console.log(pc4.dim(" // SSR-safe (Next.js) \u2014 disables server rendering for WebGL:"));
|
|
865
438
|
for (const line of g.ssrSnippet.split("\n")) {
|
|
866
|
-
console.log(line ? ` ${
|
|
439
|
+
console.log(line ? ` ${pc4.cyan(line)}` : "");
|
|
867
440
|
}
|
|
868
441
|
} else {
|
|
869
|
-
console.log(` ${
|
|
442
|
+
console.log(` ${pc4.cyan(g.importSnippet)}`);
|
|
870
443
|
}
|
|
871
444
|
for (const note of g.notes) {
|
|
872
|
-
console.log(` ${
|
|
445
|
+
console.log(` ${pc4.green("\u2022")} ${pc4.dim(note)}`);
|
|
873
446
|
}
|
|
874
447
|
for (const warning of g.warnings) {
|
|
875
|
-
console.log(` ${
|
|
448
|
+
console.log(` ${pc4.yellow("\u26A0")} ${pc4.yellow(warning)}`);
|
|
876
449
|
}
|
|
877
450
|
if (g.docsUrl) {
|
|
878
|
-
console.log(` ${
|
|
451
|
+
console.log(` ${pc4.dim("Docs:")} ${pc4.cyan(g.docsUrl)}`);
|
|
879
452
|
}
|
|
880
453
|
}
|
|
881
454
|
|
|
@@ -943,11 +516,11 @@ async function handleDependencies(components, projectRoot, projectInfo, options)
|
|
|
943
516
|
const missing = getMissingDependencies(components, projectRoot);
|
|
944
517
|
if (missing.length === 0) return;
|
|
945
518
|
const installCmd = getInstallCommand(projectInfo.packageManager, missing);
|
|
946
|
-
const depsLabel = missing.map((d) =>
|
|
519
|
+
const depsLabel = missing.map((d) => pc5.cyan(d)).join(", ");
|
|
947
520
|
if (options.install === false) {
|
|
948
|
-
console.log(
|
|
521
|
+
console.log(pc5.yellow(`
|
|
949
522
|
\u26A0\uFE0F Missing dependencies: ${depsLabel}`));
|
|
950
|
-
console.log(` Run: ${
|
|
523
|
+
console.log(` Run: ${pc5.bold(pc5.cyan(installCmd))}`);
|
|
951
524
|
return;
|
|
952
525
|
}
|
|
953
526
|
let shouldInstall = options.yes === true;
|
|
@@ -958,44 +531,44 @@ async function handleDependencies(components, projectRoot, projectInfo, options)
|
|
|
958
531
|
initialValue: true
|
|
959
532
|
});
|
|
960
533
|
if (isCancel2(answer)) {
|
|
961
|
-
console.log(
|
|
534
|
+
console.log(pc5.dim(` Skipped. Run: ${pc5.cyan(installCmd)}`));
|
|
962
535
|
return;
|
|
963
536
|
}
|
|
964
537
|
shouldInstall = answer;
|
|
965
538
|
}
|
|
966
539
|
if (!shouldInstall) {
|
|
967
|
-
console.log(
|
|
540
|
+
console.log(pc5.dim(` Skipped. Run: ${pc5.cyan(installCmd)} when ready.`));
|
|
968
541
|
return;
|
|
969
542
|
}
|
|
970
|
-
console.log(
|
|
543
|
+
console.log(pc5.dim(`
|
|
971
544
|
Installing dependencies with ${projectInfo.packageManager}...`));
|
|
972
545
|
try {
|
|
973
546
|
const ok = installDependencies(missing, projectInfo.packageManager, projectRoot);
|
|
974
547
|
if (ok) {
|
|
975
|
-
console.log(
|
|
548
|
+
console.log(pc5.green(`\u2714 Dependencies installed.`));
|
|
976
549
|
} else {
|
|
977
|
-
console.log(
|
|
550
|
+
console.log(pc5.yellow(`\u26A0\uFE0F Dependency install did not complete. Run manually: ${pc5.cyan(installCmd)}`));
|
|
978
551
|
}
|
|
979
552
|
} catch (error) {
|
|
980
553
|
const message = error instanceof Error ? error.message : String(error);
|
|
981
|
-
console.log(
|
|
982
|
-
console.log(` Run manually: ${
|
|
554
|
+
console.log(pc5.yellow(`\u26A0\uFE0F ${message}`));
|
|
555
|
+
console.log(` Run manually: ${pc5.bold(pc5.cyan(installCmd))}`);
|
|
983
556
|
}
|
|
984
557
|
}
|
|
985
558
|
async function handlePrune(orphans, slug, options) {
|
|
986
559
|
if (orphans.length === 0) return;
|
|
987
|
-
const list = orphans.map((o) => ` ${
|
|
560
|
+
const list = orphans.map((o) => ` ${pc5.dim("\u2022")} ${pc5.cyan(o.relativePath)}`).join("\n");
|
|
988
561
|
let shouldPrune = options.prune === true;
|
|
989
562
|
if (!shouldPrune) {
|
|
990
563
|
console.log(
|
|
991
|
-
|
|
564
|
+
pc5.yellow(
|
|
992
565
|
`
|
|
993
|
-
\u{1F9F9} ${orphans.length} file(s) from a previous version of ${
|
|
566
|
+
\u{1F9F9} ${orphans.length} file(s) from a previous version of ${pc5.cyan(slug)} are no longer part of it:`
|
|
994
567
|
)
|
|
995
568
|
);
|
|
996
569
|
console.log(list);
|
|
997
570
|
if (options.yes) {
|
|
998
|
-
console.log(
|
|
571
|
+
console.log(pc5.dim(` Re-run with ${pc5.cyan("--prune")} to remove them.`));
|
|
999
572
|
return;
|
|
1000
573
|
}
|
|
1001
574
|
const answer = await confirm2({
|
|
@@ -1003,16 +576,16 @@ async function handlePrune(orphans, slug, options) {
|
|
|
1003
576
|
initialValue: true
|
|
1004
577
|
});
|
|
1005
578
|
if (isCancel2(answer) || !answer) {
|
|
1006
|
-
console.log(
|
|
579
|
+
console.log(pc5.dim(` Left in place. Run with ${pc5.cyan("--prune")} later to remove them.`));
|
|
1007
580
|
return;
|
|
1008
581
|
}
|
|
1009
582
|
shouldPrune = true;
|
|
1010
583
|
}
|
|
1011
584
|
removeFiles(orphans);
|
|
1012
|
-
console.log(
|
|
585
|
+
console.log(pc5.green(`
|
|
1013
586
|
\u{1F9F9} Removed ${orphans.length} orphaned file(s):`));
|
|
1014
587
|
for (const o of orphans) {
|
|
1015
|
-
console.log(` ${
|
|
588
|
+
console.log(` ${pc5.red("\u2212")} ${pc5.cyan(o.relativePath)}`);
|
|
1016
589
|
}
|
|
1017
590
|
}
|
|
1018
591
|
async function addCommand(slug, options = {}) {
|
|
@@ -1020,7 +593,7 @@ async function addCommand(slug, options = {}) {
|
|
|
1020
593
|
validateSlug(slug);
|
|
1021
594
|
} catch (error) {
|
|
1022
595
|
const message = error instanceof Error ? error.message : String(error);
|
|
1023
|
-
console.error(`${
|
|
596
|
+
console.error(`${pc5.red(pc5.bold("Error:"))} ${message}`);
|
|
1024
597
|
process.exit(1);
|
|
1025
598
|
}
|
|
1026
599
|
let config;
|
|
@@ -1028,13 +601,13 @@ async function addCommand(slug, options = {}) {
|
|
|
1028
601
|
config = loadConfig();
|
|
1029
602
|
} catch (error) {
|
|
1030
603
|
const message = error instanceof Error ? error.message : String(error);
|
|
1031
|
-
console.error(`${
|
|
604
|
+
console.error(`${pc5.red(pc5.bold("Error:"))} ${message}`);
|
|
1032
605
|
process.exit(1);
|
|
1033
606
|
}
|
|
1034
607
|
if (!config) {
|
|
1035
608
|
console.error(
|
|
1036
|
-
`${
|
|
1037
|
-
\u{1F449} Run ${
|
|
609
|
+
`${pc5.red(pc5.bold("Error:"))} No ${pc5.cyan("vv.config.json")} found in this directory.
|
|
610
|
+
\u{1F449} Run ${pc5.bold(pc5.cyan("npx vectorvesper init"))} first to set up your project.`
|
|
1038
611
|
);
|
|
1039
612
|
process.exit(1);
|
|
1040
613
|
return;
|
|
@@ -1042,13 +615,13 @@ async function addCommand(slug, options = {}) {
|
|
|
1042
615
|
const projectInfo = detectProject();
|
|
1043
616
|
const componentInstallDir = resolveAlias(config.aliases.vv, projectInfo.hasSrcDir);
|
|
1044
617
|
const projectRoot = process.cwd();
|
|
1045
|
-
const spinner = ora2({ text: `Resolving component ${
|
|
618
|
+
const spinner = ora2({ text: `Resolving component ${pc5.cyan(slug)}...`, color: "cyan" }).start();
|
|
1046
619
|
let resolvedComponents;
|
|
1047
620
|
try {
|
|
1048
621
|
resolvedComponents = await resolveComponentTree(slug);
|
|
1049
622
|
} catch (error) {
|
|
1050
623
|
const message = error instanceof Error ? error.message : String(error);
|
|
1051
|
-
spinner.fail(
|
|
624
|
+
spinner.fail(pc5.red(`Failed to resolve component "${slug}": ${message}`));
|
|
1052
625
|
process.exit(1);
|
|
1053
626
|
return;
|
|
1054
627
|
}
|
|
@@ -1070,7 +643,7 @@ async function addCommand(slug, options = {}) {
|
|
|
1070
643
|
planned = planFiles(resolvedComponents, componentInstallDir, projectRoot);
|
|
1071
644
|
} catch (error) {
|
|
1072
645
|
const message = error instanceof Error ? error.message : String(error);
|
|
1073
|
-
spinner.fail(
|
|
646
|
+
spinner.fail(pc5.red(message));
|
|
1074
647
|
process.exit(1);
|
|
1075
648
|
return;
|
|
1076
649
|
}
|
|
@@ -1079,11 +652,11 @@ async function addCommand(slug, options = {}) {
|
|
|
1079
652
|
if (file.exists && !options.dryRun && !options.overwrite && !options.yes) {
|
|
1080
653
|
spinner.stop();
|
|
1081
654
|
const answer = await confirm2({
|
|
1082
|
-
message:
|
|
655
|
+
message: pc5.yellow(`File already exists: "${file.relativePath}". Overwrite?`),
|
|
1083
656
|
initialValue: false
|
|
1084
657
|
});
|
|
1085
658
|
if (isCancel2(answer) || !answer) {
|
|
1086
|
-
console.log(
|
|
659
|
+
console.log(pc5.dim(` Skipping existing file: ${file.relativePath}`));
|
|
1087
660
|
spinner.start("Continuing installation...");
|
|
1088
661
|
continue;
|
|
1089
662
|
}
|
|
@@ -1096,7 +669,7 @@ async function addCommand(slug, options = {}) {
|
|
|
1096
669
|
});
|
|
1097
670
|
}
|
|
1098
671
|
const targetComponent = resolvedComponents[resolvedComponents.length - 1];
|
|
1099
|
-
const installPath = toForwardSlash(
|
|
672
|
+
const installPath = toForwardSlash(path4.join(componentInstallDir, targetComponent.slug));
|
|
1100
673
|
let orphans = [];
|
|
1101
674
|
try {
|
|
1102
675
|
const previousManifest = readManifest(projectRoot);
|
|
@@ -1105,32 +678,32 @@ async function addCommand(slug, options = {}) {
|
|
|
1105
678
|
orphans = [];
|
|
1106
679
|
}
|
|
1107
680
|
if (options.dryRun) {
|
|
1108
|
-
spinner.succeed(
|
|
1109
|
-
console.log(
|
|
681
|
+
spinner.succeed(pc5.yellow("Dry-run: simulation completed. No files were written."));
|
|
682
|
+
console.log(pc5.bold(pc5.yellow("\n[Dry Run] Files that would be created/modified:")));
|
|
1110
683
|
for (const file of filesToWrite) {
|
|
1111
|
-
const status =
|
|
1112
|
-
console.log(` ${
|
|
684
|
+
const status = fs4.existsSync(file.absolutePath) ? pc5.yellow("(exists, would overwrite)") : pc5.green("(new)");
|
|
685
|
+
console.log(` ${pc5.cyan(file.relativePath)} ${status}`);
|
|
1113
686
|
}
|
|
1114
687
|
if (orphans.length > 0) {
|
|
1115
|
-
console.log(
|
|
688
|
+
console.log(pc5.bold(pc5.yellow("\n[Dry Run] Orphaned files from a previous version:")));
|
|
1116
689
|
for (const o of orphans) {
|
|
1117
|
-
const note = options.prune ?
|
|
1118
|
-
console.log(` ${
|
|
690
|
+
const note = options.prune ? pc5.red("(would remove)") : pc5.dim("(use --prune to remove)");
|
|
691
|
+
console.log(` ${pc5.cyan(o.relativePath)} ${note}`);
|
|
1119
692
|
}
|
|
1120
693
|
}
|
|
1121
694
|
const missing = getMissingDependencies(resolvedComponents, projectRoot);
|
|
1122
695
|
if (missing.length > 0) {
|
|
1123
|
-
console.log(
|
|
1124
|
-
\u26A0\uFE0F Would need dependencies: ${missing.map((d) =>
|
|
1125
|
-
console.log(` ${
|
|
696
|
+
console.log(pc5.yellow(`
|
|
697
|
+
\u26A0\uFE0F Would need dependencies: ${missing.map((d) => pc5.cyan(d)).join(", ")}`));
|
|
698
|
+
console.log(` ${pc5.dim(getInstallCommand(projectInfo.packageManager, missing))}`);
|
|
1126
699
|
}
|
|
1127
700
|
console.log("");
|
|
1128
|
-
console.log(
|
|
701
|
+
console.log(pc5.bold(pc5.yellow(`\u2714 [Dry Run] Would add ${pc5.cyan(targetComponent.slug)} to ${installPath}`)));
|
|
1129
702
|
console.log("");
|
|
1130
703
|
return;
|
|
1131
704
|
}
|
|
1132
705
|
if (filesToWrite.length === 0) {
|
|
1133
|
-
spinner.succeed(
|
|
706
|
+
spinner.succeed(pc5.green("All files skipped (already up to date)."));
|
|
1134
707
|
await handlePrune(orphans, targetComponent.slug, options);
|
|
1135
708
|
return;
|
|
1136
709
|
}
|
|
@@ -1139,7 +712,7 @@ async function addCommand(slug, options = {}) {
|
|
|
1139
712
|
writeFiles(filesToWrite);
|
|
1140
713
|
} catch (error) {
|
|
1141
714
|
const message = error instanceof Error ? error.message : String(error);
|
|
1142
|
-
spinner.fail(
|
|
715
|
+
spinner.fail(pc5.red(`Failed to write files: ${message}`));
|
|
1143
716
|
process.exit(1);
|
|
1144
717
|
return;
|
|
1145
718
|
}
|
|
@@ -1150,10 +723,10 @@ async function addCommand(slug, options = {}) {
|
|
|
1150
723
|
logger.warn(`Failed to update vv-manifest.json: ${message}`);
|
|
1151
724
|
logger.warn("Component was installed but may not appear in 'npx vectorvesper info' or 'npx vectorvesper diff'.");
|
|
1152
725
|
}
|
|
1153
|
-
spinner.succeed(
|
|
1154
|
-
console.log(
|
|
726
|
+
spinner.succeed(pc5.green("Files written successfully!"));
|
|
727
|
+
console.log(pc5.dim("\nCreated files:"));
|
|
1155
728
|
for (const file of filesToWrite) {
|
|
1156
|
-
console.log(` ${
|
|
729
|
+
console.log(` ${pc5.green("\u2714")} ${pc5.cyan(file.relativePath)}`);
|
|
1157
730
|
}
|
|
1158
731
|
await handlePrune(orphans, targetComponent.slug, options);
|
|
1159
732
|
await handleDependencies(resolvedComponents, projectRoot, projectInfo, options);
|
|
@@ -1163,20 +736,20 @@ async function addCommand(slug, options = {}) {
|
|
|
1163
736
|
hasTailwind: projectInfo.hasTailwind
|
|
1164
737
|
});
|
|
1165
738
|
if (transpileWarnings.length > 0) {
|
|
1166
|
-
console.log(
|
|
739
|
+
console.log(pc5.yellow(`
|
|
1167
740
|
\u26A0\uFE0F Some files were kept as TypeScript:`));
|
|
1168
|
-
for (const w of transpileWarnings) console.log(` ${
|
|
741
|
+
for (const w of transpileWarnings) console.log(` ${pc5.dim(w)}`);
|
|
1169
742
|
}
|
|
1170
743
|
console.log("");
|
|
1171
|
-
console.log(
|
|
744
|
+
console.log(pc5.bold(pc5.green(`\u2714 Added ${pc5.cyan(targetComponent.slug)} to ${installPath}`)));
|
|
1172
745
|
console.log("");
|
|
1173
|
-
console.log(
|
|
1174
|
-
console.log(
|
|
746
|
+
console.log(pc5.gray("\u{1F449} Loving Vector Vesper? Star the repo: https://github.com/vectorvesper/vv-components"));
|
|
747
|
+
console.log(pc5.gray("\u{1F680} Premium shader & pixel systems: https://vectorvesper.dev/pricing"));
|
|
1175
748
|
console.log("");
|
|
1176
749
|
}
|
|
1177
750
|
|
|
1178
751
|
// src/commands/update.ts
|
|
1179
|
-
import
|
|
752
|
+
import pc6 from "picocolors";
|
|
1180
753
|
import ora3 from "ora";
|
|
1181
754
|
async function updateCommand(slug, options = {}) {
|
|
1182
755
|
const projectRoot = process.cwd();
|
|
@@ -1185,14 +758,14 @@ async function updateCommand(slug, options = {}) {
|
|
|
1185
758
|
config = loadConfig();
|
|
1186
759
|
} catch (error) {
|
|
1187
760
|
const message = error instanceof Error ? error.message : String(error);
|
|
1188
|
-
console.error(`${
|
|
761
|
+
console.error(`${pc6.red(pc6.bold("Error:"))} ${message}`);
|
|
1189
762
|
process.exit(1);
|
|
1190
763
|
return;
|
|
1191
764
|
}
|
|
1192
765
|
if (!config) {
|
|
1193
766
|
console.error(
|
|
1194
|
-
`${
|
|
1195
|
-
\u{1F449} Run ${
|
|
767
|
+
`${pc6.red(pc6.bold("Error:"))} No ${pc6.cyan("vv.config.json")} found.
|
|
768
|
+
\u{1F449} Run ${pc6.bold(pc6.cyan("npx vectorvesper init"))} first.`
|
|
1196
769
|
);
|
|
1197
770
|
process.exit(1);
|
|
1198
771
|
return;
|
|
@@ -1202,9 +775,9 @@ async function updateCommand(slug, options = {}) {
|
|
|
1202
775
|
const manifest = readManifest(projectRoot);
|
|
1203
776
|
const installedSlugs = Object.keys(manifest.components);
|
|
1204
777
|
if (installedSlugs.length === 0) {
|
|
1205
|
-
console.log(
|
|
778
|
+
console.log(pc6.yellow(`
|
|
1206
779
|
\u26A0\uFE0F No components are installed in this project.`));
|
|
1207
|
-
console.log(`\u{1F449} Add one with ${
|
|
780
|
+
console.log(`\u{1F449} Add one with ${pc6.bold(pc6.cyan("npx vectorvesper add <slug>"))}
|
|
1208
781
|
`);
|
|
1209
782
|
return;
|
|
1210
783
|
}
|
|
@@ -1214,16 +787,16 @@ async function updateCommand(slug, options = {}) {
|
|
|
1214
787
|
validateSlug(slug);
|
|
1215
788
|
} catch (error) {
|
|
1216
789
|
const message = error instanceof Error ? error.message : String(error);
|
|
1217
|
-
console.error(
|
|
790
|
+
console.error(pc6.red(`
|
|
1218
791
|
\u274C ${message}
|
|
1219
792
|
`));
|
|
1220
793
|
process.exit(1);
|
|
1221
794
|
return;
|
|
1222
795
|
}
|
|
1223
796
|
if (!manifest.components[slug]) {
|
|
1224
|
-
console.log(
|
|
797
|
+
console.log(pc6.red(`
|
|
1225
798
|
\u274C Component "${slug}" is not installed in this project.`));
|
|
1226
|
-
console.log(`\u{1F449} Run ${
|
|
799
|
+
console.log(`\u{1F449} Run ${pc6.cyan(`npx vectorvesper add ${slug}`)} to install it.
|
|
1227
800
|
`);
|
|
1228
801
|
return;
|
|
1229
802
|
}
|
|
@@ -1238,7 +811,7 @@ async function updateCommand(slug, options = {}) {
|
|
|
1238
811
|
const updatedComponents = [];
|
|
1239
812
|
const transpileWarnings = [];
|
|
1240
813
|
for (const target of targets) {
|
|
1241
|
-
spinner.text = `Updating ${
|
|
814
|
+
spinner.text = `Updating ${pc6.cyan(target)}...`;
|
|
1242
815
|
try {
|
|
1243
816
|
let components = await resolveComponentTree(target);
|
|
1244
817
|
const remote = components[components.length - 1];
|
|
@@ -1268,26 +841,26 @@ async function updateCommand(slug, options = {}) {
|
|
|
1268
841
|
}
|
|
1269
842
|
}
|
|
1270
843
|
spinner.stop();
|
|
1271
|
-
console.log(
|
|
844
|
+
console.log(pc6.bold(pc6.cyan("\nVector Vesper Update\n")));
|
|
1272
845
|
if (updated.length > 0) {
|
|
1273
|
-
console.log(
|
|
1274
|
-
for (const u of updated) console.log(` ${
|
|
1275
|
-
console.log(
|
|
846
|
+
console.log(pc6.bold(pc6.green(` Updated (${updated.length}):`)));
|
|
847
|
+
for (const u of updated) console.log(` ${pc6.green("\u2714")} ${u}`);
|
|
848
|
+
console.log(pc6.dim(" Note: updating overwrites local edits to these files."));
|
|
1276
849
|
}
|
|
1277
850
|
if (upToDate.length > 0) {
|
|
1278
|
-
console.log(
|
|
851
|
+
console.log(pc6.bold(pc6.gray(`
|
|
1279
852
|
Already up to date (${upToDate.length}):`)));
|
|
1280
|
-
console.log(` ${
|
|
853
|
+
console.log(` ${pc6.dim(upToDate.join(", "))}`);
|
|
1281
854
|
}
|
|
1282
855
|
if (failed.length > 0) {
|
|
1283
|
-
console.log(
|
|
856
|
+
console.log(pc6.bold(pc6.red(`
|
|
1284
857
|
Failed (${failed.length}):`)));
|
|
1285
|
-
for (const f of failed) console.log(` ${
|
|
858
|
+
for (const f of failed) console.log(` ${pc6.red("\u2716")} ${f.slug}: ${pc6.dim(f.reason)}`);
|
|
1286
859
|
}
|
|
1287
860
|
if (transpileWarnings.length > 0) {
|
|
1288
|
-
console.log(
|
|
861
|
+
console.log(pc6.yellow(`
|
|
1289
862
|
\u26A0\uFE0F Some files were kept as TypeScript:`));
|
|
1290
|
-
for (const w of transpileWarnings) console.log(` ${
|
|
863
|
+
for (const w of transpileWarnings) console.log(` ${pc6.dim(w)}`);
|
|
1291
864
|
}
|
|
1292
865
|
console.log("");
|
|
1293
866
|
if (updatedComponents.length > 0) {
|
|
@@ -1297,16 +870,16 @@ async function updateCommand(slug, options = {}) {
|
|
|
1297
870
|
}
|
|
1298
871
|
|
|
1299
872
|
// src/commands/remove.ts
|
|
1300
|
-
import
|
|
1301
|
-
import
|
|
1302
|
-
import
|
|
873
|
+
import fs5 from "fs";
|
|
874
|
+
import path5 from "path";
|
|
875
|
+
import pc7 from "picocolors";
|
|
1303
876
|
import { confirm as confirm3, isCancel as isCancel3 } from "@clack/prompts";
|
|
1304
877
|
async function removeCommand(slug, options = {}) {
|
|
1305
878
|
try {
|
|
1306
879
|
validateSlug(slug);
|
|
1307
880
|
} catch (error) {
|
|
1308
881
|
const message = error instanceof Error ? error.message : String(error);
|
|
1309
|
-
console.error(`${
|
|
882
|
+
console.error(`${pc7.red(pc7.bold("Error:"))} ${message}`);
|
|
1310
883
|
process.exit(1);
|
|
1311
884
|
return;
|
|
1312
885
|
}
|
|
@@ -1316,14 +889,14 @@ async function removeCommand(slug, options = {}) {
|
|
|
1316
889
|
config = loadConfig();
|
|
1317
890
|
} catch (error) {
|
|
1318
891
|
const message = error instanceof Error ? error.message : String(error);
|
|
1319
|
-
console.error(`${
|
|
892
|
+
console.error(`${pc7.red(pc7.bold("Error:"))} ${message}`);
|
|
1320
893
|
process.exit(1);
|
|
1321
894
|
return;
|
|
1322
895
|
}
|
|
1323
896
|
if (!config) {
|
|
1324
897
|
console.error(
|
|
1325
|
-
`${
|
|
1326
|
-
\u{1F449} Run ${
|
|
898
|
+
`${pc7.red(pc7.bold("Error:"))} No ${pc7.cyan("vv.config.json")} found.
|
|
899
|
+
\u{1F449} Run ${pc7.bold(pc7.cyan("npx vectorvesper init"))} first.`
|
|
1327
900
|
);
|
|
1328
901
|
process.exit(1);
|
|
1329
902
|
return;
|
|
@@ -1331,50 +904,50 @@ async function removeCommand(slug, options = {}) {
|
|
|
1331
904
|
const manifest = readManifest(projectRoot);
|
|
1332
905
|
const entry = manifest.components[slug];
|
|
1333
906
|
if (!entry) {
|
|
1334
|
-
console.log(
|
|
907
|
+
console.log(pc7.yellow(`
|
|
1335
908
|
\u26A0\uFE0F Component "${slug}" is not installed (not in vv-manifest.json).`));
|
|
1336
|
-
console.log(`\u{1F449} See installed components with ${
|
|
909
|
+
console.log(`\u{1F449} See installed components with ${pc7.bold(pc7.cyan("npx vectorvesper info"))}
|
|
1337
910
|
`);
|
|
1338
911
|
return;
|
|
1339
912
|
}
|
|
1340
913
|
const projectInfo = detectProject();
|
|
1341
914
|
const installDir = resolveAlias(config.aliases.vv, projectInfo.hasSrcDir);
|
|
1342
|
-
const baseDir =
|
|
915
|
+
const baseDir = path5.join(projectRoot, installDir);
|
|
1343
916
|
const targets = entry.files ?? [];
|
|
1344
|
-
const absoluteFiles = targets.map((t) =>
|
|
1345
|
-
console.log(
|
|
917
|
+
const absoluteFiles = targets.map((t) => path5.resolve(baseDir, t));
|
|
918
|
+
console.log(pc7.bold(pc7.cyan(`
|
|
1346
919
|
Remove ${slug}
|
|
1347
920
|
`)));
|
|
1348
|
-
console.log(
|
|
921
|
+
console.log(pc7.dim(" The following files will be deleted:"));
|
|
1349
922
|
for (const f of absoluteFiles) {
|
|
1350
|
-
console.log(` ${
|
|
923
|
+
console.log(` ${fs5.existsSync(f) ? pc7.red("\u2212") : pc7.dim("\xB7")} ${pc7.cyan(path5.relative(projectRoot, f))}`);
|
|
1351
924
|
}
|
|
1352
925
|
if (!options.yes) {
|
|
1353
926
|
const answer = await confirm3({
|
|
1354
|
-
message:
|
|
927
|
+
message: pc7.yellow(`Delete ${absoluteFiles.length} file(s) for "${slug}"?`),
|
|
1355
928
|
initialValue: false
|
|
1356
929
|
});
|
|
1357
930
|
if (isCancel3(answer) || !answer) {
|
|
1358
|
-
console.log(
|
|
931
|
+
console.log(pc7.dim("\n Cancelled. Nothing was removed.\n"));
|
|
1359
932
|
return;
|
|
1360
933
|
}
|
|
1361
934
|
}
|
|
1362
935
|
let deleted = 0;
|
|
1363
936
|
for (const f of absoluteFiles) {
|
|
1364
937
|
try {
|
|
1365
|
-
if (
|
|
1366
|
-
|
|
938
|
+
if (fs5.existsSync(f)) {
|
|
939
|
+
fs5.rmSync(f);
|
|
1367
940
|
deleted++;
|
|
1368
941
|
}
|
|
1369
942
|
} catch (error) {
|
|
1370
943
|
const message = error instanceof Error ? error.message : String(error);
|
|
1371
|
-
console.log(
|
|
944
|
+
console.log(pc7.yellow(` \u26A0\uFE0F Could not delete ${path5.relative(projectRoot, f)}: ${message}`));
|
|
1372
945
|
}
|
|
1373
946
|
}
|
|
1374
|
-
const componentDir =
|
|
947
|
+
const componentDir = path5.resolve(baseDir, slug);
|
|
1375
948
|
try {
|
|
1376
|
-
if (
|
|
1377
|
-
|
|
949
|
+
if (fs5.existsSync(componentDir) && fs5.readdirSync(componentDir).length === 0) {
|
|
950
|
+
fs5.rmdirSync(componentDir);
|
|
1378
951
|
}
|
|
1379
952
|
} catch {
|
|
1380
953
|
}
|
|
@@ -1383,23 +956,23 @@ Remove ${slug}
|
|
|
1383
956
|
writeManifest(projectRoot, manifest);
|
|
1384
957
|
} catch (error) {
|
|
1385
958
|
const message = error instanceof Error ? error.message : String(error);
|
|
1386
|
-
console.log(
|
|
959
|
+
console.log(pc7.yellow(` \u26A0\uFE0F Removed files but failed to update vv-manifest.json: ${message}`));
|
|
1387
960
|
}
|
|
1388
961
|
console.log("");
|
|
1389
|
-
console.log(
|
|
962
|
+
console.log(pc7.bold(pc7.green(`\u2714 Removed ${pc7.cyan(slug)} (${deleted} file(s) deleted).`)));
|
|
1390
963
|
if ((entry.files ?? []).length === 0) {
|
|
1391
|
-
console.log(
|
|
964
|
+
console.log(pc7.dim(" No files were tracked for this component; manifest entry cleared."));
|
|
1392
965
|
}
|
|
1393
966
|
console.log("");
|
|
1394
967
|
}
|
|
1395
968
|
|
|
1396
969
|
// src/commands/info.ts
|
|
1397
|
-
import
|
|
1398
|
-
import
|
|
1399
|
-
import
|
|
1400
|
-
var CLI_VERSION = true ? "
|
|
970
|
+
import fs6 from "fs";
|
|
971
|
+
import path6 from "path";
|
|
972
|
+
import pc8 from "picocolors";
|
|
973
|
+
var CLI_VERSION = true ? "2.0.1" : "0.0.0-dev";
|
|
1401
974
|
async function infoCommand() {
|
|
1402
|
-
console.log(
|
|
975
|
+
console.log(pc8.bold(pc8.cyan("\nVector Vesper Diagnostics\n")));
|
|
1403
976
|
const projectInfo = detectProject();
|
|
1404
977
|
let config;
|
|
1405
978
|
try {
|
|
@@ -1407,84 +980,84 @@ async function infoCommand() {
|
|
|
1407
980
|
} catch {
|
|
1408
981
|
config = null;
|
|
1409
982
|
}
|
|
1410
|
-
console.log(
|
|
1411
|
-
console.log(` \u2022 CLI Version: ${
|
|
1412
|
-
console.log(` \u2022 Node Version: ${
|
|
1413
|
-
console.log(` \u2022 OS: ${
|
|
1414
|
-
console.log(` \u2022 Package Manager: ${
|
|
1415
|
-
console.log(` \u2022 Framework: ${
|
|
1416
|
-
console.log(` \u2022 TypeScript: ${
|
|
1417
|
-
console.log(` \u2022 Has src/ folder: ${
|
|
1418
|
-
console.log(` \u2022 Tailwind CSS: ${
|
|
983
|
+
console.log(pc8.bold(pc8.white("Environment:")));
|
|
984
|
+
console.log(` \u2022 CLI Version: ${pc8.cyan(CLI_VERSION)}`);
|
|
985
|
+
console.log(` \u2022 Node Version: ${pc8.cyan(process.version)}`);
|
|
986
|
+
console.log(` \u2022 OS: ${pc8.cyan(`${process.platform} ${process.arch}`)}`);
|
|
987
|
+
console.log(` \u2022 Package Manager: ${pc8.cyan(projectInfo.packageManager)}`);
|
|
988
|
+
console.log(` \u2022 Framework: ${pc8.cyan(projectInfo.framework)}`);
|
|
989
|
+
console.log(` \u2022 TypeScript: ${pc8.cyan(projectInfo.isTypeScript ? "Yes" : "No")}`);
|
|
990
|
+
console.log(` \u2022 Has src/ folder: ${pc8.cyan(projectInfo.hasSrcDir ? "Yes" : "No")}`);
|
|
991
|
+
console.log(` \u2022 Tailwind CSS: ${pc8.cyan(projectInfo.hasTailwind ? "Yes" : "No")}`);
|
|
1419
992
|
console.log("");
|
|
1420
|
-
console.log(
|
|
993
|
+
console.log(pc8.bold(pc8.white("Configuration (vv.config.json):")));
|
|
1421
994
|
if (config) {
|
|
1422
|
-
console.log(` \u2022 Framework Set: ${
|
|
1423
|
-
console.log(` \u2022 TypeScript Set: ${
|
|
1424
|
-
console.log(` \u2022 Component Alias: ${
|
|
995
|
+
console.log(` \u2022 Framework Set: ${pc8.cyan(config.framework)}`);
|
|
996
|
+
console.log(` \u2022 TypeScript Set: ${pc8.cyan(config.tsx ? "Yes" : "No")}`);
|
|
997
|
+
console.log(` \u2022 Component Alias: ${pc8.cyan(config.aliases.vv)}`);
|
|
1425
998
|
} else {
|
|
1426
|
-
console.log(` ${
|
|
999
|
+
console.log(` ${pc8.yellow("\u26A0\uFE0F No vv.config.json found in this directory.")}`);
|
|
1427
1000
|
}
|
|
1428
1001
|
console.log("");
|
|
1429
|
-
console.log(
|
|
1430
|
-
const manifestPath =
|
|
1431
|
-
if (
|
|
1002
|
+
console.log(pc8.bold(pc8.white("Installed Components (vv-manifest.json):")));
|
|
1003
|
+
const manifestPath = path6.join(process.cwd(), "vv-manifest.json");
|
|
1004
|
+
if (fs6.existsSync(manifestPath)) {
|
|
1432
1005
|
try {
|
|
1433
|
-
const manifest = JSON.parse(
|
|
1006
|
+
const manifest = JSON.parse(fs6.readFileSync(manifestPath, "utf-8"));
|
|
1434
1007
|
const components = manifest.components || {};
|
|
1435
1008
|
const slugs = Object.keys(components);
|
|
1436
1009
|
if (slugs.length === 0) {
|
|
1437
|
-
console.log(` ${
|
|
1010
|
+
console.log(` ${pc8.dim("No components installed yet.")}`);
|
|
1438
1011
|
} else {
|
|
1439
|
-
console.log(
|
|
1440
|
-
console.log(` ${
|
|
1441
|
-
console.log(
|
|
1012
|
+
console.log(pc8.dim(" ------------------------------------------------------------"));
|
|
1013
|
+
console.log(` ${pc8.bold(pc8.white("Component".padEnd(25)))} ${pc8.bold(pc8.white("Version".padEnd(10)))} ${pc8.bold(pc8.white("Installed At"))}`);
|
|
1014
|
+
console.log(pc8.dim(" ------------------------------------------------------------"));
|
|
1442
1015
|
for (const slug of slugs) {
|
|
1443
1016
|
const info = components[slug];
|
|
1444
1017
|
const version2 = info?.version ?? "unknown";
|
|
1445
1018
|
const installedAt = info?.installedAt ?? "unknown";
|
|
1446
|
-
console.log(` ${
|
|
1019
|
+
console.log(` ${pc8.cyan(slug.padEnd(25))} ${pc8.green(version2.padEnd(10))} ${pc8.gray(installedAt)}`);
|
|
1447
1020
|
}
|
|
1448
|
-
console.log(
|
|
1021
|
+
console.log(pc8.dim(" ------------------------------------------------------------"));
|
|
1449
1022
|
}
|
|
1450
1023
|
} catch {
|
|
1451
|
-
console.log(` ${
|
|
1024
|
+
console.log(` ${pc8.red("\u274C Error reading vv-manifest.json: Invalid JSON format.")}`);
|
|
1452
1025
|
}
|
|
1453
1026
|
} else {
|
|
1454
|
-
console.log(` ${
|
|
1027
|
+
console.log(` ${pc8.dim("No components installed yet (vv-manifest.json not found).")}`);
|
|
1455
1028
|
}
|
|
1456
1029
|
console.log("");
|
|
1457
1030
|
}
|
|
1458
1031
|
|
|
1459
1032
|
// src/commands/diff.ts
|
|
1460
|
-
import
|
|
1461
|
-
import
|
|
1462
|
-
import
|
|
1033
|
+
import fs7 from "fs";
|
|
1034
|
+
import path7 from "path";
|
|
1035
|
+
import pc9 from "picocolors";
|
|
1463
1036
|
import ora4 from "ora";
|
|
1464
1037
|
async function diffCommand(slug) {
|
|
1465
1038
|
const projectRoot = process.cwd();
|
|
1466
|
-
const manifestPath =
|
|
1467
|
-
if (!
|
|
1468
|
-
console.log(
|
|
1039
|
+
const manifestPath = path7.join(projectRoot, "vv-manifest.json");
|
|
1040
|
+
if (!fs7.existsSync(manifestPath)) {
|
|
1041
|
+
console.log(pc9.yellow(`
|
|
1469
1042
|
\u26A0\uFE0F No vv-manifest.json found in this directory.`));
|
|
1470
|
-
console.log(`\u{1F449} Add components first using ${
|
|
1043
|
+
console.log(`\u{1F449} Add components first using ${pc9.bold(pc9.cyan("npx vectorvesper add <slug>"))}
|
|
1471
1044
|
`);
|
|
1472
1045
|
return;
|
|
1473
1046
|
}
|
|
1474
1047
|
let manifest;
|
|
1475
1048
|
try {
|
|
1476
|
-
manifest = JSON.parse(
|
|
1049
|
+
manifest = JSON.parse(fs7.readFileSync(manifestPath, "utf-8"));
|
|
1477
1050
|
} catch {
|
|
1478
|
-
console.error(
|
|
1051
|
+
console.error(pc9.red(`\u274C Error reading vv-manifest.json: Invalid JSON format.`));
|
|
1479
1052
|
process.exit(1);
|
|
1480
1053
|
return;
|
|
1481
1054
|
}
|
|
1482
1055
|
const installedComponents = manifest.components || {};
|
|
1483
1056
|
const installedSlugs = Object.keys(installedComponents);
|
|
1484
1057
|
if (installedSlugs.length === 0) {
|
|
1485
|
-
console.log(
|
|
1058
|
+
console.log(pc9.yellow(`
|
|
1486
1059
|
\u26A0\uFE0F No components are registered as installed in vv-manifest.json.`));
|
|
1487
|
-
console.log(`\u{1F449} Add components using ${
|
|
1060
|
+
console.log(`\u{1F449} Add components using ${pc9.bold(pc9.cyan("npx vectorvesper add <slug>"))}
|
|
1488
1061
|
`);
|
|
1489
1062
|
return;
|
|
1490
1063
|
}
|
|
@@ -1493,21 +1066,21 @@ async function diffCommand(slug) {
|
|
|
1493
1066
|
validateSlug(slug);
|
|
1494
1067
|
} catch (error) {
|
|
1495
1068
|
const message = error instanceof Error ? error.message : String(error);
|
|
1496
|
-
console.error(
|
|
1069
|
+
console.error(pc9.red(`
|
|
1497
1070
|
\u274C ${message}
|
|
1498
1071
|
`));
|
|
1499
1072
|
process.exit(1);
|
|
1500
1073
|
}
|
|
1501
1074
|
if (!installedComponents[slug]) {
|
|
1502
|
-
console.log(
|
|
1075
|
+
console.log(pc9.red(`
|
|
1503
1076
|
\u274C Component "${slug}" is not installed in this project.`));
|
|
1504
|
-
console.log(`\u{1F449} Run ${
|
|
1077
|
+
console.log(`\u{1F449} Run ${pc9.cyan(`npx vectorvesper add ${slug}`)} to install it.
|
|
1505
1078
|
`);
|
|
1506
1079
|
return;
|
|
1507
1080
|
}
|
|
1508
1081
|
const localInfo = installedComponents[slug];
|
|
1509
1082
|
const spinner = ora4({
|
|
1510
|
-
text: `Checking updates for ${
|
|
1083
|
+
text: `Checking updates for ${pc9.cyan(slug)}...`,
|
|
1511
1084
|
color: "cyan"
|
|
1512
1085
|
}).start();
|
|
1513
1086
|
try {
|
|
@@ -1515,21 +1088,21 @@ async function diffCommand(slug) {
|
|
|
1515
1088
|
spinner.stop();
|
|
1516
1089
|
const localVersion = localInfo.version ?? "unknown";
|
|
1517
1090
|
const remoteVersion = remoteComponent.version;
|
|
1518
|
-
console.log(
|
|
1091
|
+
console.log(pc9.bold(pc9.cyan(`
|
|
1519
1092
|
Component Diff: ${slug}`)));
|
|
1520
|
-
console.log(` \u2022 Local version: ${
|
|
1521
|
-
console.log(` \u2022 Latest version: ${
|
|
1093
|
+
console.log(` \u2022 Local version: ${pc9.yellow(localVersion)}`);
|
|
1094
|
+
console.log(` \u2022 Latest version: ${pc9.green(remoteVersion)}`);
|
|
1522
1095
|
if (localVersion === remoteVersion) {
|
|
1523
|
-
console.log(` \u2022 Status: ${
|
|
1096
|
+
console.log(` \u2022 Status: ${pc9.green("\u2714 Up to date")}
|
|
1524
1097
|
`);
|
|
1525
1098
|
} else {
|
|
1526
|
-
console.log(` \u2022 Status: ${
|
|
1527
|
-
console.log(` \u2022 Run ${
|
|
1099
|
+
console.log(` \u2022 Status: ${pc9.bold(pc9.yellow("\u26A0\uFE0F Update available!"))}`);
|
|
1100
|
+
console.log(` \u2022 Run ${pc9.bold(pc9.cyan(`npx vectorvesper add ${slug} --overwrite`))} to update.
|
|
1528
1101
|
`);
|
|
1529
1102
|
}
|
|
1530
1103
|
} catch (error) {
|
|
1531
1104
|
const message = error instanceof Error ? error.message : String(error);
|
|
1532
|
-
spinner.fail(
|
|
1105
|
+
spinner.fail(pc9.red(`Failed to fetch remote component details: ${message}`));
|
|
1533
1106
|
process.exit(1);
|
|
1534
1107
|
}
|
|
1535
1108
|
} else {
|
|
@@ -1540,14 +1113,14 @@ Component Diff: ${slug}`)));
|
|
|
1540
1113
|
try {
|
|
1541
1114
|
const registryIndex = await fetchRegistryIndex();
|
|
1542
1115
|
spinner.stop();
|
|
1543
|
-
console.log(
|
|
1544
|
-
console.log(
|
|
1116
|
+
console.log(pc9.bold(pc9.cyan("\nVector Vesper Component Version Comparison\n")));
|
|
1117
|
+
console.log(pc9.dim(" ----------------------------------------------------------------------"));
|
|
1545
1118
|
console.log(
|
|
1546
|
-
` ${
|
|
1547
|
-
|
|
1548
|
-
)} ${
|
|
1119
|
+
` ${pc9.bold(pc9.white("Component".padEnd(25)))} ${pc9.bold(
|
|
1120
|
+
pc9.white("Local".padEnd(10))
|
|
1121
|
+
)} ${pc9.bold(pc9.white("Latest".padEnd(10)))} ${pc9.bold(pc9.white("Status"))}`
|
|
1549
1122
|
);
|
|
1550
|
-
console.log(
|
|
1123
|
+
console.log(pc9.dim(" ----------------------------------------------------------------------"));
|
|
1551
1124
|
let updatesAvailableCount = 0;
|
|
1552
1125
|
for (const instSlug of installedSlugs) {
|
|
1553
1126
|
const localInfo = installedComponents[instSlug];
|
|
@@ -1555,67 +1128,67 @@ Component Diff: ${slug}`)));
|
|
|
1555
1128
|
const remoteInfo = registryIndex.components.find((c) => c.slug === instSlug);
|
|
1556
1129
|
if (!remoteInfo) {
|
|
1557
1130
|
console.log(
|
|
1558
|
-
` ${
|
|
1131
|
+
` ${pc9.cyan(instSlug.padEnd(25))} ${pc9.yellow(
|
|
1559
1132
|
localVersion.padEnd(10)
|
|
1560
|
-
)} ${
|
|
1133
|
+
)} ${pc9.red("unknown".padEnd(10))} ${pc9.red("Not found in registry")}`
|
|
1561
1134
|
);
|
|
1562
1135
|
} else {
|
|
1563
1136
|
const remoteVersion = remoteInfo.version;
|
|
1564
1137
|
if (localVersion === remoteVersion) {
|
|
1565
1138
|
console.log(
|
|
1566
|
-
` ${
|
|
1139
|
+
` ${pc9.cyan(instSlug.padEnd(25))} ${pc9.gray(
|
|
1567
1140
|
localVersion.padEnd(10)
|
|
1568
|
-
)} ${
|
|
1141
|
+
)} ${pc9.gray(remoteVersion.padEnd(10))} ${pc9.green("\u2714 Up to date")}`
|
|
1569
1142
|
);
|
|
1570
1143
|
} else {
|
|
1571
1144
|
updatesAvailableCount++;
|
|
1572
1145
|
console.log(
|
|
1573
|
-
` ${
|
|
1146
|
+
` ${pc9.cyan(instSlug.padEnd(25))} ${pc9.yellow(
|
|
1574
1147
|
localVersion.padEnd(10)
|
|
1575
|
-
)} ${
|
|
1576
|
-
|
|
1148
|
+
)} ${pc9.green(remoteVersion.padEnd(10))} ${pc9.bold(
|
|
1149
|
+
pc9.yellow("\u26A0\uFE0F Update available")
|
|
1577
1150
|
)}`
|
|
1578
1151
|
);
|
|
1579
1152
|
}
|
|
1580
1153
|
}
|
|
1581
1154
|
}
|
|
1582
|
-
console.log(
|
|
1155
|
+
console.log(pc9.dim(" ----------------------------------------------------------------------"));
|
|
1583
1156
|
if (updatesAvailableCount > 0) {
|
|
1584
1157
|
console.log(
|
|
1585
1158
|
`
|
|
1586
|
-
\u{1F4E2} ${
|
|
1159
|
+
\u{1F4E2} ${pc9.bold(pc9.yellow(String(updatesAvailableCount)))} component(s) have updates available.`
|
|
1587
1160
|
);
|
|
1588
|
-
console.log(`\u{1F449} Run ${
|
|
1161
|
+
console.log(`\u{1F449} Run ${pc9.bold(pc9.cyan("npx vectorvesper add <slug> --overwrite"))} to update a component.
|
|
1589
1162
|
`);
|
|
1590
1163
|
} else {
|
|
1591
1164
|
console.log(`
|
|
1592
|
-
${
|
|
1165
|
+
${pc9.green("\u2714")} All components are up to date!
|
|
1593
1166
|
`);
|
|
1594
1167
|
}
|
|
1595
1168
|
} catch (error) {
|
|
1596
1169
|
const message = error instanceof Error ? error.message : String(error);
|
|
1597
|
-
spinner.fail(
|
|
1170
|
+
spinner.fail(pc9.red(`Failed to check updates: ${message}`));
|
|
1598
1171
|
process.exit(1);
|
|
1599
1172
|
}
|
|
1600
1173
|
}
|
|
1601
1174
|
}
|
|
1602
1175
|
|
|
1603
1176
|
// src/commands/auth.ts
|
|
1604
|
-
import
|
|
1177
|
+
import pc10 from "picocolors";
|
|
1605
1178
|
async function loginCommand(key) {
|
|
1606
1179
|
if (!key || key.trim().length === 0) {
|
|
1607
|
-
logger.error("Please provide
|
|
1180
|
+
logger.error("Please provide your access token.");
|
|
1608
1181
|
console.log(`
|
|
1609
|
-
Usage: ${
|
|
1610
|
-
console.log(` \u{1F511}
|
|
1182
|
+
Usage: ${pc10.cyan("npx vectorvesper login <token>")}`);
|
|
1183
|
+
console.log(` \u{1F511} Generate a token at ${pc10.cyan("https://vectorvesper.dev/account")}
|
|
1611
1184
|
`);
|
|
1612
1185
|
process.exit(1);
|
|
1613
1186
|
}
|
|
1614
1187
|
const trimmedKey = key.trim();
|
|
1615
1188
|
if (trimmedKey.length < 8) {
|
|
1616
|
-
logger.error("That doesn't look like a valid
|
|
1189
|
+
logger.error("That doesn't look like a valid token.");
|
|
1617
1190
|
console.log(`
|
|
1618
|
-
\u{1F511}
|
|
1191
|
+
\u{1F511} Generate a token at ${pc10.cyan("https://vectorvesper.dev/account")}
|
|
1619
1192
|
`);
|
|
1620
1193
|
process.exit(1);
|
|
1621
1194
|
}
|
|
@@ -1632,18 +1205,18 @@ async function loginCommand(key) {
|
|
|
1632
1205
|
process.exit(1);
|
|
1633
1206
|
}
|
|
1634
1207
|
console.log("");
|
|
1635
|
-
console.log(` ${
|
|
1636
|
-
console.log(` ${
|
|
1208
|
+
console.log(` ${pc10.green(pc10.bold("\u2714"))} Token saved \u2014 you're logged in.`);
|
|
1209
|
+
console.log(` ${pc10.dim("Stored at:")} ${pc10.cyan(getGlobalConfigPath())}`);
|
|
1637
1210
|
console.log("");
|
|
1638
|
-
console.log(` ${
|
|
1639
|
-
console.log(` ${
|
|
1211
|
+
console.log(` ${pc10.dim("Pro components are now available when you run")} ${pc10.cyan("npx vectorvesper add <slug>")}`);
|
|
1212
|
+
console.log(` ${pc10.dim("To verify your account:")} ${pc10.cyan("npx vectorvesper whoami")}`);
|
|
1640
1213
|
console.log("");
|
|
1641
1214
|
}
|
|
1642
1215
|
async function logoutCommand() {
|
|
1643
1216
|
const config = loadGlobalConfig();
|
|
1644
1217
|
if (!config.auth?.token) {
|
|
1645
1218
|
console.log(`
|
|
1646
|
-
${
|
|
1219
|
+
${pc10.dim("You're not logged in. Nothing to do.")}
|
|
1647
1220
|
`);
|
|
1648
1221
|
return;
|
|
1649
1222
|
}
|
|
@@ -1656,46 +1229,46 @@ async function logoutCommand() {
|
|
|
1656
1229
|
process.exit(1);
|
|
1657
1230
|
}
|
|
1658
1231
|
console.log("");
|
|
1659
|
-
console.log(` ${
|
|
1660
|
-
console.log(` ${
|
|
1661
|
-
console.log(` ${
|
|
1232
|
+
console.log(` ${pc10.green(pc10.bold("\u2714"))} Logged out successfully.`);
|
|
1233
|
+
console.log(` ${pc10.dim("Your token has been removed from")} ${pc10.cyan(getGlobalConfigPath())}`);
|
|
1234
|
+
console.log(` ${pc10.dim("Free components remain available.")}`);
|
|
1662
1235
|
console.log("");
|
|
1663
1236
|
}
|
|
1664
1237
|
async function whoamiCommand() {
|
|
1665
1238
|
const config = loadGlobalConfig();
|
|
1666
1239
|
console.log("");
|
|
1667
|
-
console.log(
|
|
1240
|
+
console.log(pc10.bold(pc10.cyan(" Vector Vesper Account Status\n")));
|
|
1668
1241
|
if (config.auth?.token) {
|
|
1669
1242
|
const maskedKey = config.auth.token.slice(0, 6) + "\u2026" + config.auth.token.slice(-4);
|
|
1670
1243
|
const tier = config.auth.tier || "pro";
|
|
1671
|
-
console.log(` ${
|
|
1672
|
-
console.log(` ${
|
|
1673
|
-
console.log(` ${
|
|
1244
|
+
console.log(` ${pc10.bold("Status:")} ${pc10.green("Authenticated")}`);
|
|
1245
|
+
console.log(` ${pc10.bold("Token:")} ${pc10.cyan(maskedKey)}`);
|
|
1246
|
+
console.log(` ${pc10.bold("Tier:")} ${pc10.magenta(tier)}`);
|
|
1674
1247
|
if (config.auth.email) {
|
|
1675
|
-
console.log(` ${
|
|
1248
|
+
console.log(` ${pc10.bold("Email:")} ${pc10.cyan(config.auth.email)}`);
|
|
1676
1249
|
}
|
|
1677
1250
|
if (config.auth.expiresAt) {
|
|
1678
1251
|
const expiry = new Date(config.auth.expiresAt);
|
|
1679
1252
|
const now = /* @__PURE__ */ new Date();
|
|
1680
1253
|
const isExpired = expiry < now;
|
|
1681
|
-
console.log(` ${
|
|
1254
|
+
console.log(` ${pc10.bold("Expires:")} ${isExpired ? pc10.red("EXPIRED") : pc10.green(expiry.toLocaleDateString())}`);
|
|
1682
1255
|
}
|
|
1683
1256
|
console.log("");
|
|
1684
|
-
console.log(` ${
|
|
1685
|
-
console.log(` ${
|
|
1257
|
+
console.log(` ${pc10.dim("Config:")} ${pc10.cyan(getGlobalConfigPath())}`);
|
|
1258
|
+
console.log(` ${pc10.dim("Manage your account at")} ${pc10.cyan("https://vectorvesper.dev/account")}`);
|
|
1686
1259
|
} else {
|
|
1687
|
-
console.log(` ${
|
|
1688
|
-
console.log(` ${
|
|
1260
|
+
console.log(` ${pc10.bold("Status:")} ${pc10.yellow("Anonymous (free tier)")}`);
|
|
1261
|
+
console.log(` ${pc10.bold("Access:")} ${pc10.dim("Free components only")}`);
|
|
1689
1262
|
console.log("");
|
|
1690
|
-
console.log(` ${
|
|
1691
|
-
console.log(` ${
|
|
1692
|
-
console.log(` \u{1F511} ${
|
|
1263
|
+
console.log(` ${pc10.dim("To unlock pro components:")}`);
|
|
1264
|
+
console.log(` ${pc10.cyan("npx vectorvesper login <token>")}`);
|
|
1265
|
+
console.log(` \u{1F511} ${pc10.dim("Generate a token at")} ${pc10.cyan("https://vectorvesper.dev/account")}`);
|
|
1693
1266
|
}
|
|
1694
1267
|
console.log("");
|
|
1695
1268
|
}
|
|
1696
1269
|
|
|
1697
1270
|
// src/index.ts
|
|
1698
|
-
var version = true ? "
|
|
1271
|
+
var version = true ? "2.0.1" : "0.0.0-dev";
|
|
1699
1272
|
var program = new Command();
|
|
1700
1273
|
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) => {
|
|
1701
1274
|
const opts = thisCommand.opts();
|
|
@@ -1733,6 +1306,10 @@ program.command("logout", { hidden: true }).description("Clear stored license cr
|
|
|
1733
1306
|
program.command("whoami", { hidden: true }).description("Show current authentication status").action(async () => {
|
|
1734
1307
|
await whoamiCommand();
|
|
1735
1308
|
});
|
|
1309
|
+
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) => {
|
|
1310
|
+
const { mcpCommand } = await import("./mcp-ZGA5K5VW.js");
|
|
1311
|
+
await mcpCommand(action, options);
|
|
1312
|
+
});
|
|
1736
1313
|
process.on("unhandledRejection", (error) => {
|
|
1737
1314
|
console.error("An unexpected error occurred:", error instanceof Error ? error.message : error);
|
|
1738
1315
|
process.exit(1);
|