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