vectorvesper 1.2.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 +295 -720
- 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
|
|
|
@@ -943,11 +514,11 @@ async function handleDependencies(components, projectRoot, projectInfo, options)
|
|
|
943
514
|
const missing = getMissingDependencies(components, projectRoot);
|
|
944
515
|
if (missing.length === 0) return;
|
|
945
516
|
const installCmd = getInstallCommand(projectInfo.packageManager, missing);
|
|
946
|
-
const depsLabel = missing.map((d) =>
|
|
517
|
+
const depsLabel = missing.map((d) => pc5.cyan(d)).join(", ");
|
|
947
518
|
if (options.install === false) {
|
|
948
|
-
console.log(
|
|
519
|
+
console.log(pc5.yellow(`
|
|
949
520
|
\u26A0\uFE0F Missing dependencies: ${depsLabel}`));
|
|
950
|
-
console.log(` Run: ${
|
|
521
|
+
console.log(` Run: ${pc5.bold(pc5.cyan(installCmd))}`);
|
|
951
522
|
return;
|
|
952
523
|
}
|
|
953
524
|
let shouldInstall = options.yes === true;
|
|
@@ -958,44 +529,44 @@ async function handleDependencies(components, projectRoot, projectInfo, options)
|
|
|
958
529
|
initialValue: true
|
|
959
530
|
});
|
|
960
531
|
if (isCancel2(answer)) {
|
|
961
|
-
console.log(
|
|
532
|
+
console.log(pc5.dim(` Skipped. Run: ${pc5.cyan(installCmd)}`));
|
|
962
533
|
return;
|
|
963
534
|
}
|
|
964
535
|
shouldInstall = answer;
|
|
965
536
|
}
|
|
966
537
|
if (!shouldInstall) {
|
|
967
|
-
console.log(
|
|
538
|
+
console.log(pc5.dim(` Skipped. Run: ${pc5.cyan(installCmd)} when ready.`));
|
|
968
539
|
return;
|
|
969
540
|
}
|
|
970
|
-
console.log(
|
|
541
|
+
console.log(pc5.dim(`
|
|
971
542
|
Installing dependencies with ${projectInfo.packageManager}...`));
|
|
972
543
|
try {
|
|
973
544
|
const ok = installDependencies(missing, projectInfo.packageManager, projectRoot);
|
|
974
545
|
if (ok) {
|
|
975
|
-
console.log(
|
|
546
|
+
console.log(pc5.green(`\u2714 Dependencies installed.`));
|
|
976
547
|
} else {
|
|
977
|
-
console.log(
|
|
548
|
+
console.log(pc5.yellow(`\u26A0\uFE0F Dependency install did not complete. Run manually: ${pc5.cyan(installCmd)}`));
|
|
978
549
|
}
|
|
979
550
|
} catch (error) {
|
|
980
551
|
const message = error instanceof Error ? error.message : String(error);
|
|
981
|
-
console.log(
|
|
982
|
-
console.log(` Run manually: ${
|
|
552
|
+
console.log(pc5.yellow(`\u26A0\uFE0F ${message}`));
|
|
553
|
+
console.log(` Run manually: ${pc5.bold(pc5.cyan(installCmd))}`);
|
|
983
554
|
}
|
|
984
555
|
}
|
|
985
556
|
async function handlePrune(orphans, slug, options) {
|
|
986
557
|
if (orphans.length === 0) return;
|
|
987
|
-
const list = orphans.map((o) => ` ${
|
|
558
|
+
const list = orphans.map((o) => ` ${pc5.dim("\u2022")} ${pc5.cyan(o.relativePath)}`).join("\n");
|
|
988
559
|
let shouldPrune = options.prune === true;
|
|
989
560
|
if (!shouldPrune) {
|
|
990
561
|
console.log(
|
|
991
|
-
|
|
562
|
+
pc5.yellow(
|
|
992
563
|
`
|
|
993
|
-
\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:`
|
|
994
565
|
)
|
|
995
566
|
);
|
|
996
567
|
console.log(list);
|
|
997
568
|
if (options.yes) {
|
|
998
|
-
console.log(
|
|
569
|
+
console.log(pc5.dim(` Re-run with ${pc5.cyan("--prune")} to remove them.`));
|
|
999
570
|
return;
|
|
1000
571
|
}
|
|
1001
572
|
const answer = await confirm2({
|
|
@@ -1003,16 +574,16 @@ async function handlePrune(orphans, slug, options) {
|
|
|
1003
574
|
initialValue: true
|
|
1004
575
|
});
|
|
1005
576
|
if (isCancel2(answer) || !answer) {
|
|
1006
|
-
console.log(
|
|
577
|
+
console.log(pc5.dim(` Left in place. Run with ${pc5.cyan("--prune")} later to remove them.`));
|
|
1007
578
|
return;
|
|
1008
579
|
}
|
|
1009
580
|
shouldPrune = true;
|
|
1010
581
|
}
|
|
1011
582
|
removeFiles(orphans);
|
|
1012
|
-
console.log(
|
|
583
|
+
console.log(pc5.green(`
|
|
1013
584
|
\u{1F9F9} Removed ${orphans.length} orphaned file(s):`));
|
|
1014
585
|
for (const o of orphans) {
|
|
1015
|
-
console.log(` ${
|
|
586
|
+
console.log(` ${pc5.red("\u2212")} ${pc5.cyan(o.relativePath)}`);
|
|
1016
587
|
}
|
|
1017
588
|
}
|
|
1018
589
|
async function addCommand(slug, options = {}) {
|
|
@@ -1020,7 +591,7 @@ async function addCommand(slug, options = {}) {
|
|
|
1020
591
|
validateSlug(slug);
|
|
1021
592
|
} catch (error) {
|
|
1022
593
|
const message = error instanceof Error ? error.message : String(error);
|
|
1023
|
-
console.error(`${
|
|
594
|
+
console.error(`${pc5.red(pc5.bold("Error:"))} ${message}`);
|
|
1024
595
|
process.exit(1);
|
|
1025
596
|
}
|
|
1026
597
|
let config;
|
|
@@ -1028,13 +599,13 @@ async function addCommand(slug, options = {}) {
|
|
|
1028
599
|
config = loadConfig();
|
|
1029
600
|
} catch (error) {
|
|
1030
601
|
const message = error instanceof Error ? error.message : String(error);
|
|
1031
|
-
console.error(`${
|
|
602
|
+
console.error(`${pc5.red(pc5.bold("Error:"))} ${message}`);
|
|
1032
603
|
process.exit(1);
|
|
1033
604
|
}
|
|
1034
605
|
if (!config) {
|
|
1035
606
|
console.error(
|
|
1036
|
-
`${
|
|
1037
|
-
\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.`
|
|
1038
609
|
);
|
|
1039
610
|
process.exit(1);
|
|
1040
611
|
return;
|
|
@@ -1042,13 +613,13 @@ async function addCommand(slug, options = {}) {
|
|
|
1042
613
|
const projectInfo = detectProject();
|
|
1043
614
|
const componentInstallDir = resolveAlias(config.aliases.vv, projectInfo.hasSrcDir);
|
|
1044
615
|
const projectRoot = process.cwd();
|
|
1045
|
-
const spinner = ora2({ text: `Resolving component ${
|
|
616
|
+
const spinner = ora2({ text: `Resolving component ${pc5.cyan(slug)}...`, color: "cyan" }).start();
|
|
1046
617
|
let resolvedComponents;
|
|
1047
618
|
try {
|
|
1048
619
|
resolvedComponents = await resolveComponentTree(slug);
|
|
1049
620
|
} catch (error) {
|
|
1050
621
|
const message = error instanceof Error ? error.message : String(error);
|
|
1051
|
-
spinner.fail(
|
|
622
|
+
spinner.fail(pc5.red(`Failed to resolve component "${slug}": ${message}`));
|
|
1052
623
|
process.exit(1);
|
|
1053
624
|
return;
|
|
1054
625
|
}
|
|
@@ -1070,7 +641,7 @@ async function addCommand(slug, options = {}) {
|
|
|
1070
641
|
planned = planFiles(resolvedComponents, componentInstallDir, projectRoot);
|
|
1071
642
|
} catch (error) {
|
|
1072
643
|
const message = error instanceof Error ? error.message : String(error);
|
|
1073
|
-
spinner.fail(
|
|
644
|
+
spinner.fail(pc5.red(message));
|
|
1074
645
|
process.exit(1);
|
|
1075
646
|
return;
|
|
1076
647
|
}
|
|
@@ -1079,11 +650,11 @@ async function addCommand(slug, options = {}) {
|
|
|
1079
650
|
if (file.exists && !options.dryRun && !options.overwrite && !options.yes) {
|
|
1080
651
|
spinner.stop();
|
|
1081
652
|
const answer = await confirm2({
|
|
1082
|
-
message:
|
|
653
|
+
message: pc5.yellow(`File already exists: "${file.relativePath}". Overwrite?`),
|
|
1083
654
|
initialValue: false
|
|
1084
655
|
});
|
|
1085
656
|
if (isCancel2(answer) || !answer) {
|
|
1086
|
-
console.log(
|
|
657
|
+
console.log(pc5.dim(` Skipping existing file: ${file.relativePath}`));
|
|
1087
658
|
spinner.start("Continuing installation...");
|
|
1088
659
|
continue;
|
|
1089
660
|
}
|
|
@@ -1096,7 +667,7 @@ async function addCommand(slug, options = {}) {
|
|
|
1096
667
|
});
|
|
1097
668
|
}
|
|
1098
669
|
const targetComponent = resolvedComponents[resolvedComponents.length - 1];
|
|
1099
|
-
const installPath = toForwardSlash(
|
|
670
|
+
const installPath = toForwardSlash(path4.join(componentInstallDir, targetComponent.slug));
|
|
1100
671
|
let orphans = [];
|
|
1101
672
|
try {
|
|
1102
673
|
const previousManifest = readManifest(projectRoot);
|
|
@@ -1105,32 +676,32 @@ async function addCommand(slug, options = {}) {
|
|
|
1105
676
|
orphans = [];
|
|
1106
677
|
}
|
|
1107
678
|
if (options.dryRun) {
|
|
1108
|
-
spinner.succeed(
|
|
1109
|
-
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:")));
|
|
1110
681
|
for (const file of filesToWrite) {
|
|
1111
|
-
const status =
|
|
1112
|
-
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}`);
|
|
1113
684
|
}
|
|
1114
685
|
if (orphans.length > 0) {
|
|
1115
|
-
console.log(
|
|
686
|
+
console.log(pc5.bold(pc5.yellow("\n[Dry Run] Orphaned files from a previous version:")));
|
|
1116
687
|
for (const o of orphans) {
|
|
1117
|
-
const note = options.prune ?
|
|
1118
|
-
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}`);
|
|
1119
690
|
}
|
|
1120
691
|
}
|
|
1121
692
|
const missing = getMissingDependencies(resolvedComponents, projectRoot);
|
|
1122
693
|
if (missing.length > 0) {
|
|
1123
|
-
console.log(
|
|
1124
|
-
\u26A0\uFE0F Would need dependencies: ${missing.map((d) =>
|
|
1125
|
-
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))}`);
|
|
1126
697
|
}
|
|
1127
698
|
console.log("");
|
|
1128
|
-
console.log(
|
|
699
|
+
console.log(pc5.bold(pc5.yellow(`\u2714 [Dry Run] Would add ${pc5.cyan(targetComponent.slug)} to ${installPath}`)));
|
|
1129
700
|
console.log("");
|
|
1130
701
|
return;
|
|
1131
702
|
}
|
|
1132
703
|
if (filesToWrite.length === 0) {
|
|
1133
|
-
spinner.succeed(
|
|
704
|
+
spinner.succeed(pc5.green("All files skipped (already up to date)."));
|
|
1134
705
|
await handlePrune(orphans, targetComponent.slug, options);
|
|
1135
706
|
return;
|
|
1136
707
|
}
|
|
@@ -1139,7 +710,7 @@ async function addCommand(slug, options = {}) {
|
|
|
1139
710
|
writeFiles(filesToWrite);
|
|
1140
711
|
} catch (error) {
|
|
1141
712
|
const message = error instanceof Error ? error.message : String(error);
|
|
1142
|
-
spinner.fail(
|
|
713
|
+
spinner.fail(pc5.red(`Failed to write files: ${message}`));
|
|
1143
714
|
process.exit(1);
|
|
1144
715
|
return;
|
|
1145
716
|
}
|
|
@@ -1150,10 +721,10 @@ async function addCommand(slug, options = {}) {
|
|
|
1150
721
|
logger.warn(`Failed to update vv-manifest.json: ${message}`);
|
|
1151
722
|
logger.warn("Component was installed but may not appear in 'npx vectorvesper info' or 'npx vectorvesper diff'.");
|
|
1152
723
|
}
|
|
1153
|
-
spinner.succeed(
|
|
1154
|
-
console.log(
|
|
724
|
+
spinner.succeed(pc5.green("Files written successfully!"));
|
|
725
|
+
console.log(pc5.dim("\nCreated files:"));
|
|
1155
726
|
for (const file of filesToWrite) {
|
|
1156
|
-
console.log(` ${
|
|
727
|
+
console.log(` ${pc5.green("\u2714")} ${pc5.cyan(file.relativePath)}`);
|
|
1157
728
|
}
|
|
1158
729
|
await handlePrune(orphans, targetComponent.slug, options);
|
|
1159
730
|
await handleDependencies(resolvedComponents, projectRoot, projectInfo, options);
|
|
@@ -1163,20 +734,20 @@ async function addCommand(slug, options = {}) {
|
|
|
1163
734
|
hasTailwind: projectInfo.hasTailwind
|
|
1164
735
|
});
|
|
1165
736
|
if (transpileWarnings.length > 0) {
|
|
1166
|
-
console.log(
|
|
737
|
+
console.log(pc5.yellow(`
|
|
1167
738
|
\u26A0\uFE0F Some files were kept as TypeScript:`));
|
|
1168
|
-
for (const w of transpileWarnings) console.log(` ${
|
|
739
|
+
for (const w of transpileWarnings) console.log(` ${pc5.dim(w)}`);
|
|
1169
740
|
}
|
|
1170
741
|
console.log("");
|
|
1171
|
-
console.log(
|
|
742
|
+
console.log(pc5.bold(pc5.green(`\u2714 Added ${pc5.cyan(targetComponent.slug)} to ${installPath}`)));
|
|
1172
743
|
console.log("");
|
|
1173
|
-
console.log(
|
|
1174
|
-
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"));
|
|
1175
746
|
console.log("");
|
|
1176
747
|
}
|
|
1177
748
|
|
|
1178
749
|
// src/commands/update.ts
|
|
1179
|
-
import
|
|
750
|
+
import pc6 from "picocolors";
|
|
1180
751
|
import ora3 from "ora";
|
|
1181
752
|
async function updateCommand(slug, options = {}) {
|
|
1182
753
|
const projectRoot = process.cwd();
|
|
@@ -1185,14 +756,14 @@ async function updateCommand(slug, options = {}) {
|
|
|
1185
756
|
config = loadConfig();
|
|
1186
757
|
} catch (error) {
|
|
1187
758
|
const message = error instanceof Error ? error.message : String(error);
|
|
1188
|
-
console.error(`${
|
|
759
|
+
console.error(`${pc6.red(pc6.bold("Error:"))} ${message}`);
|
|
1189
760
|
process.exit(1);
|
|
1190
761
|
return;
|
|
1191
762
|
}
|
|
1192
763
|
if (!config) {
|
|
1193
764
|
console.error(
|
|
1194
|
-
`${
|
|
1195
|
-
\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.`
|
|
1196
767
|
);
|
|
1197
768
|
process.exit(1);
|
|
1198
769
|
return;
|
|
@@ -1202,9 +773,9 @@ async function updateCommand(slug, options = {}) {
|
|
|
1202
773
|
const manifest = readManifest(projectRoot);
|
|
1203
774
|
const installedSlugs = Object.keys(manifest.components);
|
|
1204
775
|
if (installedSlugs.length === 0) {
|
|
1205
|
-
console.log(
|
|
776
|
+
console.log(pc6.yellow(`
|
|
1206
777
|
\u26A0\uFE0F No components are installed in this project.`));
|
|
1207
|
-
console.log(`\u{1F449} Add one with ${
|
|
778
|
+
console.log(`\u{1F449} Add one with ${pc6.bold(pc6.cyan("npx vectorvesper add <slug>"))}
|
|
1208
779
|
`);
|
|
1209
780
|
return;
|
|
1210
781
|
}
|
|
@@ -1214,16 +785,16 @@ async function updateCommand(slug, options = {}) {
|
|
|
1214
785
|
validateSlug(slug);
|
|
1215
786
|
} catch (error) {
|
|
1216
787
|
const message = error instanceof Error ? error.message : String(error);
|
|
1217
|
-
console.error(
|
|
788
|
+
console.error(pc6.red(`
|
|
1218
789
|
\u274C ${message}
|
|
1219
790
|
`));
|
|
1220
791
|
process.exit(1);
|
|
1221
792
|
return;
|
|
1222
793
|
}
|
|
1223
794
|
if (!manifest.components[slug]) {
|
|
1224
|
-
console.log(
|
|
795
|
+
console.log(pc6.red(`
|
|
1225
796
|
\u274C Component "${slug}" is not installed in this project.`));
|
|
1226
|
-
console.log(`\u{1F449} Run ${
|
|
797
|
+
console.log(`\u{1F449} Run ${pc6.cyan(`npx vectorvesper add ${slug}`)} to install it.
|
|
1227
798
|
`);
|
|
1228
799
|
return;
|
|
1229
800
|
}
|
|
@@ -1238,7 +809,7 @@ async function updateCommand(slug, options = {}) {
|
|
|
1238
809
|
const updatedComponents = [];
|
|
1239
810
|
const transpileWarnings = [];
|
|
1240
811
|
for (const target of targets) {
|
|
1241
|
-
spinner.text = `Updating ${
|
|
812
|
+
spinner.text = `Updating ${pc6.cyan(target)}...`;
|
|
1242
813
|
try {
|
|
1243
814
|
let components = await resolveComponentTree(target);
|
|
1244
815
|
const remote = components[components.length - 1];
|
|
@@ -1268,26 +839,26 @@ async function updateCommand(slug, options = {}) {
|
|
|
1268
839
|
}
|
|
1269
840
|
}
|
|
1270
841
|
spinner.stop();
|
|
1271
|
-
console.log(
|
|
842
|
+
console.log(pc6.bold(pc6.cyan("\nVector Vesper Update\n")));
|
|
1272
843
|
if (updated.length > 0) {
|
|
1273
|
-
console.log(
|
|
1274
|
-
for (const u of updated) console.log(` ${
|
|
1275
|
-
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."));
|
|
1276
847
|
}
|
|
1277
848
|
if (upToDate.length > 0) {
|
|
1278
|
-
console.log(
|
|
849
|
+
console.log(pc6.bold(pc6.gray(`
|
|
1279
850
|
Already up to date (${upToDate.length}):`)));
|
|
1280
|
-
console.log(` ${
|
|
851
|
+
console.log(` ${pc6.dim(upToDate.join(", "))}`);
|
|
1281
852
|
}
|
|
1282
853
|
if (failed.length > 0) {
|
|
1283
|
-
console.log(
|
|
854
|
+
console.log(pc6.bold(pc6.red(`
|
|
1284
855
|
Failed (${failed.length}):`)));
|
|
1285
|
-
for (const f of failed) console.log(` ${
|
|
856
|
+
for (const f of failed) console.log(` ${pc6.red("\u2716")} ${f.slug}: ${pc6.dim(f.reason)}`);
|
|
1286
857
|
}
|
|
1287
858
|
if (transpileWarnings.length > 0) {
|
|
1288
|
-
console.log(
|
|
859
|
+
console.log(pc6.yellow(`
|
|
1289
860
|
\u26A0\uFE0F Some files were kept as TypeScript:`));
|
|
1290
|
-
for (const w of transpileWarnings) console.log(` ${
|
|
861
|
+
for (const w of transpileWarnings) console.log(` ${pc6.dim(w)}`);
|
|
1291
862
|
}
|
|
1292
863
|
console.log("");
|
|
1293
864
|
if (updatedComponents.length > 0) {
|
|
@@ -1297,16 +868,16 @@ async function updateCommand(slug, options = {}) {
|
|
|
1297
868
|
}
|
|
1298
869
|
|
|
1299
870
|
// src/commands/remove.ts
|
|
1300
|
-
import
|
|
1301
|
-
import
|
|
1302
|
-
import
|
|
871
|
+
import fs5 from "fs";
|
|
872
|
+
import path5 from "path";
|
|
873
|
+
import pc7 from "picocolors";
|
|
1303
874
|
import { confirm as confirm3, isCancel as isCancel3 } from "@clack/prompts";
|
|
1304
875
|
async function removeCommand(slug, options = {}) {
|
|
1305
876
|
try {
|
|
1306
877
|
validateSlug(slug);
|
|
1307
878
|
} catch (error) {
|
|
1308
879
|
const message = error instanceof Error ? error.message : String(error);
|
|
1309
|
-
console.error(`${
|
|
880
|
+
console.error(`${pc7.red(pc7.bold("Error:"))} ${message}`);
|
|
1310
881
|
process.exit(1);
|
|
1311
882
|
return;
|
|
1312
883
|
}
|
|
@@ -1316,14 +887,14 @@ async function removeCommand(slug, options = {}) {
|
|
|
1316
887
|
config = loadConfig();
|
|
1317
888
|
} catch (error) {
|
|
1318
889
|
const message = error instanceof Error ? error.message : String(error);
|
|
1319
|
-
console.error(`${
|
|
890
|
+
console.error(`${pc7.red(pc7.bold("Error:"))} ${message}`);
|
|
1320
891
|
process.exit(1);
|
|
1321
892
|
return;
|
|
1322
893
|
}
|
|
1323
894
|
if (!config) {
|
|
1324
895
|
console.error(
|
|
1325
|
-
`${
|
|
1326
|
-
\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.`
|
|
1327
898
|
);
|
|
1328
899
|
process.exit(1);
|
|
1329
900
|
return;
|
|
@@ -1331,50 +902,50 @@ async function removeCommand(slug, options = {}) {
|
|
|
1331
902
|
const manifest = readManifest(projectRoot);
|
|
1332
903
|
const entry = manifest.components[slug];
|
|
1333
904
|
if (!entry) {
|
|
1334
|
-
console.log(
|
|
905
|
+
console.log(pc7.yellow(`
|
|
1335
906
|
\u26A0\uFE0F Component "${slug}" is not installed (not in vv-manifest.json).`));
|
|
1336
|
-
console.log(`\u{1F449} See installed components with ${
|
|
907
|
+
console.log(`\u{1F449} See installed components with ${pc7.bold(pc7.cyan("npx vectorvesper info"))}
|
|
1337
908
|
`);
|
|
1338
909
|
return;
|
|
1339
910
|
}
|
|
1340
911
|
const projectInfo = detectProject();
|
|
1341
912
|
const installDir = resolveAlias(config.aliases.vv, projectInfo.hasSrcDir);
|
|
1342
|
-
const baseDir =
|
|
913
|
+
const baseDir = path5.join(projectRoot, installDir);
|
|
1343
914
|
const targets = entry.files ?? [];
|
|
1344
|
-
const absoluteFiles = targets.map((t) =>
|
|
1345
|
-
console.log(
|
|
915
|
+
const absoluteFiles = targets.map((t) => path5.resolve(baseDir, t));
|
|
916
|
+
console.log(pc7.bold(pc7.cyan(`
|
|
1346
917
|
Remove ${slug}
|
|
1347
918
|
`)));
|
|
1348
|
-
console.log(
|
|
919
|
+
console.log(pc7.dim(" The following files will be deleted:"));
|
|
1349
920
|
for (const f of absoluteFiles) {
|
|
1350
|
-
console.log(` ${
|
|
921
|
+
console.log(` ${fs5.existsSync(f) ? pc7.red("\u2212") : pc7.dim("\xB7")} ${pc7.cyan(path5.relative(projectRoot, f))}`);
|
|
1351
922
|
}
|
|
1352
923
|
if (!options.yes) {
|
|
1353
924
|
const answer = await confirm3({
|
|
1354
|
-
message:
|
|
925
|
+
message: pc7.yellow(`Delete ${absoluteFiles.length} file(s) for "${slug}"?`),
|
|
1355
926
|
initialValue: false
|
|
1356
927
|
});
|
|
1357
928
|
if (isCancel3(answer) || !answer) {
|
|
1358
|
-
console.log(
|
|
929
|
+
console.log(pc7.dim("\n Cancelled. Nothing was removed.\n"));
|
|
1359
930
|
return;
|
|
1360
931
|
}
|
|
1361
932
|
}
|
|
1362
933
|
let deleted = 0;
|
|
1363
934
|
for (const f of absoluteFiles) {
|
|
1364
935
|
try {
|
|
1365
|
-
if (
|
|
1366
|
-
|
|
936
|
+
if (fs5.existsSync(f)) {
|
|
937
|
+
fs5.rmSync(f);
|
|
1367
938
|
deleted++;
|
|
1368
939
|
}
|
|
1369
940
|
} catch (error) {
|
|
1370
941
|
const message = error instanceof Error ? error.message : String(error);
|
|
1371
|
-
console.log(
|
|
942
|
+
console.log(pc7.yellow(` \u26A0\uFE0F Could not delete ${path5.relative(projectRoot, f)}: ${message}`));
|
|
1372
943
|
}
|
|
1373
944
|
}
|
|
1374
|
-
const componentDir =
|
|
945
|
+
const componentDir = path5.resolve(baseDir, slug);
|
|
1375
946
|
try {
|
|
1376
|
-
if (
|
|
1377
|
-
|
|
947
|
+
if (fs5.existsSync(componentDir) && fs5.readdirSync(componentDir).length === 0) {
|
|
948
|
+
fs5.rmdirSync(componentDir);
|
|
1378
949
|
}
|
|
1379
950
|
} catch {
|
|
1380
951
|
}
|
|
@@ -1383,23 +954,23 @@ Remove ${slug}
|
|
|
1383
954
|
writeManifest(projectRoot, manifest);
|
|
1384
955
|
} catch (error) {
|
|
1385
956
|
const message = error instanceof Error ? error.message : String(error);
|
|
1386
|
-
console.log(
|
|
957
|
+
console.log(pc7.yellow(` \u26A0\uFE0F Removed files but failed to update vv-manifest.json: ${message}`));
|
|
1387
958
|
}
|
|
1388
959
|
console.log("");
|
|
1389
|
-
console.log(
|
|
960
|
+
console.log(pc7.bold(pc7.green(`\u2714 Removed ${pc7.cyan(slug)} (${deleted} file(s) deleted).`)));
|
|
1390
961
|
if ((entry.files ?? []).length === 0) {
|
|
1391
|
-
console.log(
|
|
962
|
+
console.log(pc7.dim(" No files were tracked for this component; manifest entry cleared."));
|
|
1392
963
|
}
|
|
1393
964
|
console.log("");
|
|
1394
965
|
}
|
|
1395
966
|
|
|
1396
967
|
// src/commands/info.ts
|
|
1397
|
-
import
|
|
1398
|
-
import
|
|
1399
|
-
import
|
|
968
|
+
import fs6 from "fs";
|
|
969
|
+
import path6 from "path";
|
|
970
|
+
import pc8 from "picocolors";
|
|
1400
971
|
var CLI_VERSION = true ? "1.2.0" : "0.0.0-dev";
|
|
1401
972
|
async function infoCommand() {
|
|
1402
|
-
console.log(
|
|
973
|
+
console.log(pc8.bold(pc8.cyan("\nVector Vesper Diagnostics\n")));
|
|
1403
974
|
const projectInfo = detectProject();
|
|
1404
975
|
let config;
|
|
1405
976
|
try {
|
|
@@ -1407,84 +978,84 @@ async function infoCommand() {
|
|
|
1407
978
|
} catch {
|
|
1408
979
|
config = null;
|
|
1409
980
|
}
|
|
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: ${
|
|
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")}`);
|
|
1419
990
|
console.log("");
|
|
1420
|
-
console.log(
|
|
991
|
+
console.log(pc8.bold(pc8.white("Configuration (vv.config.json):")));
|
|
1421
992
|
if (config) {
|
|
1422
|
-
console.log(` \u2022 Framework Set: ${
|
|
1423
|
-
console.log(` \u2022 TypeScript Set: ${
|
|
1424
|
-
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)}`);
|
|
1425
996
|
} else {
|
|
1426
|
-
console.log(` ${
|
|
997
|
+
console.log(` ${pc8.yellow("\u26A0\uFE0F No vv.config.json found in this directory.")}`);
|
|
1427
998
|
}
|
|
1428
999
|
console.log("");
|
|
1429
|
-
console.log(
|
|
1430
|
-
const manifestPath =
|
|
1431
|
-
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)) {
|
|
1432
1003
|
try {
|
|
1433
|
-
const manifest = JSON.parse(
|
|
1004
|
+
const manifest = JSON.parse(fs6.readFileSync(manifestPath, "utf-8"));
|
|
1434
1005
|
const components = manifest.components || {};
|
|
1435
1006
|
const slugs = Object.keys(components);
|
|
1436
1007
|
if (slugs.length === 0) {
|
|
1437
|
-
console.log(` ${
|
|
1008
|
+
console.log(` ${pc8.dim("No components installed yet.")}`);
|
|
1438
1009
|
} else {
|
|
1439
|
-
console.log(
|
|
1440
|
-
console.log(` ${
|
|
1441
|
-
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(" ------------------------------------------------------------"));
|
|
1442
1013
|
for (const slug of slugs) {
|
|
1443
1014
|
const info = components[slug];
|
|
1444
1015
|
const version2 = info?.version ?? "unknown";
|
|
1445
1016
|
const installedAt = info?.installedAt ?? "unknown";
|
|
1446
|
-
console.log(` ${
|
|
1017
|
+
console.log(` ${pc8.cyan(slug.padEnd(25))} ${pc8.green(version2.padEnd(10))} ${pc8.gray(installedAt)}`);
|
|
1447
1018
|
}
|
|
1448
|
-
console.log(
|
|
1019
|
+
console.log(pc8.dim(" ------------------------------------------------------------"));
|
|
1449
1020
|
}
|
|
1450
1021
|
} catch {
|
|
1451
|
-
console.log(` ${
|
|
1022
|
+
console.log(` ${pc8.red("\u274C Error reading vv-manifest.json: Invalid JSON format.")}`);
|
|
1452
1023
|
}
|
|
1453
1024
|
} else {
|
|
1454
|
-
console.log(` ${
|
|
1025
|
+
console.log(` ${pc8.dim("No components installed yet (vv-manifest.json not found).")}`);
|
|
1455
1026
|
}
|
|
1456
1027
|
console.log("");
|
|
1457
1028
|
}
|
|
1458
1029
|
|
|
1459
1030
|
// src/commands/diff.ts
|
|
1460
|
-
import
|
|
1461
|
-
import
|
|
1462
|
-
import
|
|
1031
|
+
import fs7 from "fs";
|
|
1032
|
+
import path7 from "path";
|
|
1033
|
+
import pc9 from "picocolors";
|
|
1463
1034
|
import ora4 from "ora";
|
|
1464
1035
|
async function diffCommand(slug) {
|
|
1465
1036
|
const projectRoot = process.cwd();
|
|
1466
|
-
const manifestPath =
|
|
1467
|
-
if (!
|
|
1468
|
-
console.log(
|
|
1037
|
+
const manifestPath = path7.join(projectRoot, "vv-manifest.json");
|
|
1038
|
+
if (!fs7.existsSync(manifestPath)) {
|
|
1039
|
+
console.log(pc9.yellow(`
|
|
1469
1040
|
\u26A0\uFE0F No vv-manifest.json found in this directory.`));
|
|
1470
|
-
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>"))}
|
|
1471
1042
|
`);
|
|
1472
1043
|
return;
|
|
1473
1044
|
}
|
|
1474
1045
|
let manifest;
|
|
1475
1046
|
try {
|
|
1476
|
-
manifest = JSON.parse(
|
|
1047
|
+
manifest = JSON.parse(fs7.readFileSync(manifestPath, "utf-8"));
|
|
1477
1048
|
} catch {
|
|
1478
|
-
console.error(
|
|
1049
|
+
console.error(pc9.red(`\u274C Error reading vv-manifest.json: Invalid JSON format.`));
|
|
1479
1050
|
process.exit(1);
|
|
1480
1051
|
return;
|
|
1481
1052
|
}
|
|
1482
1053
|
const installedComponents = manifest.components || {};
|
|
1483
1054
|
const installedSlugs = Object.keys(installedComponents);
|
|
1484
1055
|
if (installedSlugs.length === 0) {
|
|
1485
|
-
console.log(
|
|
1056
|
+
console.log(pc9.yellow(`
|
|
1486
1057
|
\u26A0\uFE0F No components are registered as installed in vv-manifest.json.`));
|
|
1487
|
-
console.log(`\u{1F449} Add components using ${
|
|
1058
|
+
console.log(`\u{1F449} Add components using ${pc9.bold(pc9.cyan("npx vectorvesper add <slug>"))}
|
|
1488
1059
|
`);
|
|
1489
1060
|
return;
|
|
1490
1061
|
}
|
|
@@ -1493,21 +1064,21 @@ async function diffCommand(slug) {
|
|
|
1493
1064
|
validateSlug(slug);
|
|
1494
1065
|
} catch (error) {
|
|
1495
1066
|
const message = error instanceof Error ? error.message : String(error);
|
|
1496
|
-
console.error(
|
|
1067
|
+
console.error(pc9.red(`
|
|
1497
1068
|
\u274C ${message}
|
|
1498
1069
|
`));
|
|
1499
1070
|
process.exit(1);
|
|
1500
1071
|
}
|
|
1501
1072
|
if (!installedComponents[slug]) {
|
|
1502
|
-
console.log(
|
|
1073
|
+
console.log(pc9.red(`
|
|
1503
1074
|
\u274C Component "${slug}" is not installed in this project.`));
|
|
1504
|
-
console.log(`\u{1F449} Run ${
|
|
1075
|
+
console.log(`\u{1F449} Run ${pc9.cyan(`npx vectorvesper add ${slug}`)} to install it.
|
|
1505
1076
|
`);
|
|
1506
1077
|
return;
|
|
1507
1078
|
}
|
|
1508
1079
|
const localInfo = installedComponents[slug];
|
|
1509
1080
|
const spinner = ora4({
|
|
1510
|
-
text: `Checking updates for ${
|
|
1081
|
+
text: `Checking updates for ${pc9.cyan(slug)}...`,
|
|
1511
1082
|
color: "cyan"
|
|
1512
1083
|
}).start();
|
|
1513
1084
|
try {
|
|
@@ -1515,21 +1086,21 @@ async function diffCommand(slug) {
|
|
|
1515
1086
|
spinner.stop();
|
|
1516
1087
|
const localVersion = localInfo.version ?? "unknown";
|
|
1517
1088
|
const remoteVersion = remoteComponent.version;
|
|
1518
|
-
console.log(
|
|
1089
|
+
console.log(pc9.bold(pc9.cyan(`
|
|
1519
1090
|
Component Diff: ${slug}`)));
|
|
1520
|
-
console.log(` \u2022 Local version: ${
|
|
1521
|
-
console.log(` \u2022 Latest version: ${
|
|
1091
|
+
console.log(` \u2022 Local version: ${pc9.yellow(localVersion)}`);
|
|
1092
|
+
console.log(` \u2022 Latest version: ${pc9.green(remoteVersion)}`);
|
|
1522
1093
|
if (localVersion === remoteVersion) {
|
|
1523
|
-
console.log(` \u2022 Status: ${
|
|
1094
|
+
console.log(` \u2022 Status: ${pc9.green("\u2714 Up to date")}
|
|
1524
1095
|
`);
|
|
1525
1096
|
} else {
|
|
1526
|
-
console.log(` \u2022 Status: ${
|
|
1527
|
-
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.
|
|
1528
1099
|
`);
|
|
1529
1100
|
}
|
|
1530
1101
|
} catch (error) {
|
|
1531
1102
|
const message = error instanceof Error ? error.message : String(error);
|
|
1532
|
-
spinner.fail(
|
|
1103
|
+
spinner.fail(pc9.red(`Failed to fetch remote component details: ${message}`));
|
|
1533
1104
|
process.exit(1);
|
|
1534
1105
|
}
|
|
1535
1106
|
} else {
|
|
@@ -1540,14 +1111,14 @@ Component Diff: ${slug}`)));
|
|
|
1540
1111
|
try {
|
|
1541
1112
|
const registryIndex = await fetchRegistryIndex();
|
|
1542
1113
|
spinner.stop();
|
|
1543
|
-
console.log(
|
|
1544
|
-
console.log(
|
|
1114
|
+
console.log(pc9.bold(pc9.cyan("\nVector Vesper Component Version Comparison\n")));
|
|
1115
|
+
console.log(pc9.dim(" ----------------------------------------------------------------------"));
|
|
1545
1116
|
console.log(
|
|
1546
|
-
` ${
|
|
1547
|
-
|
|
1548
|
-
)} ${
|
|
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"))}`
|
|
1549
1120
|
);
|
|
1550
|
-
console.log(
|
|
1121
|
+
console.log(pc9.dim(" ----------------------------------------------------------------------"));
|
|
1551
1122
|
let updatesAvailableCount = 0;
|
|
1552
1123
|
for (const instSlug of installedSlugs) {
|
|
1553
1124
|
const localInfo = installedComponents[instSlug];
|
|
@@ -1555,67 +1126,67 @@ Component Diff: ${slug}`)));
|
|
|
1555
1126
|
const remoteInfo = registryIndex.components.find((c) => c.slug === instSlug);
|
|
1556
1127
|
if (!remoteInfo) {
|
|
1557
1128
|
console.log(
|
|
1558
|
-
` ${
|
|
1129
|
+
` ${pc9.cyan(instSlug.padEnd(25))} ${pc9.yellow(
|
|
1559
1130
|
localVersion.padEnd(10)
|
|
1560
|
-
)} ${
|
|
1131
|
+
)} ${pc9.red("unknown".padEnd(10))} ${pc9.red("Not found in registry")}`
|
|
1561
1132
|
);
|
|
1562
1133
|
} else {
|
|
1563
1134
|
const remoteVersion = remoteInfo.version;
|
|
1564
1135
|
if (localVersion === remoteVersion) {
|
|
1565
1136
|
console.log(
|
|
1566
|
-
` ${
|
|
1137
|
+
` ${pc9.cyan(instSlug.padEnd(25))} ${pc9.gray(
|
|
1567
1138
|
localVersion.padEnd(10)
|
|
1568
|
-
)} ${
|
|
1139
|
+
)} ${pc9.gray(remoteVersion.padEnd(10))} ${pc9.green("\u2714 Up to date")}`
|
|
1569
1140
|
);
|
|
1570
1141
|
} else {
|
|
1571
1142
|
updatesAvailableCount++;
|
|
1572
1143
|
console.log(
|
|
1573
|
-
` ${
|
|
1144
|
+
` ${pc9.cyan(instSlug.padEnd(25))} ${pc9.yellow(
|
|
1574
1145
|
localVersion.padEnd(10)
|
|
1575
|
-
)} ${
|
|
1576
|
-
|
|
1146
|
+
)} ${pc9.green(remoteVersion.padEnd(10))} ${pc9.bold(
|
|
1147
|
+
pc9.yellow("\u26A0\uFE0F Update available")
|
|
1577
1148
|
)}`
|
|
1578
1149
|
);
|
|
1579
1150
|
}
|
|
1580
1151
|
}
|
|
1581
1152
|
}
|
|
1582
|
-
console.log(
|
|
1153
|
+
console.log(pc9.dim(" ----------------------------------------------------------------------"));
|
|
1583
1154
|
if (updatesAvailableCount > 0) {
|
|
1584
1155
|
console.log(
|
|
1585
1156
|
`
|
|
1586
|
-
\u{1F4E2} ${
|
|
1157
|
+
\u{1F4E2} ${pc9.bold(pc9.yellow(String(updatesAvailableCount)))} component(s) have updates available.`
|
|
1587
1158
|
);
|
|
1588
|
-
console.log(`\u{1F449} Run ${
|
|
1159
|
+
console.log(`\u{1F449} Run ${pc9.bold(pc9.cyan("npx vectorvesper add <slug> --overwrite"))} to update a component.
|
|
1589
1160
|
`);
|
|
1590
1161
|
} else {
|
|
1591
1162
|
console.log(`
|
|
1592
|
-
${
|
|
1163
|
+
${pc9.green("\u2714")} All components are up to date!
|
|
1593
1164
|
`);
|
|
1594
1165
|
}
|
|
1595
1166
|
} catch (error) {
|
|
1596
1167
|
const message = error instanceof Error ? error.message : String(error);
|
|
1597
|
-
spinner.fail(
|
|
1168
|
+
spinner.fail(pc9.red(`Failed to check updates: ${message}`));
|
|
1598
1169
|
process.exit(1);
|
|
1599
1170
|
}
|
|
1600
1171
|
}
|
|
1601
1172
|
}
|
|
1602
1173
|
|
|
1603
1174
|
// src/commands/auth.ts
|
|
1604
|
-
import
|
|
1175
|
+
import pc10 from "picocolors";
|
|
1605
1176
|
async function loginCommand(key) {
|
|
1606
1177
|
if (!key || key.trim().length === 0) {
|
|
1607
|
-
logger.error("Please provide
|
|
1178
|
+
logger.error("Please provide your access token.");
|
|
1608
1179
|
console.log(`
|
|
1609
|
-
Usage: ${
|
|
1610
|
-
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")}
|
|
1611
1182
|
`);
|
|
1612
1183
|
process.exit(1);
|
|
1613
1184
|
}
|
|
1614
1185
|
const trimmedKey = key.trim();
|
|
1615
1186
|
if (trimmedKey.length < 8) {
|
|
1616
|
-
logger.error("That doesn't look like a valid
|
|
1187
|
+
logger.error("That doesn't look like a valid token.");
|
|
1617
1188
|
console.log(`
|
|
1618
|
-
\u{1F511}
|
|
1189
|
+
\u{1F511} Generate a token at ${pc10.cyan("https://vectorvesper.dev/account")}
|
|
1619
1190
|
`);
|
|
1620
1191
|
process.exit(1);
|
|
1621
1192
|
}
|
|
@@ -1632,18 +1203,18 @@ async function loginCommand(key) {
|
|
|
1632
1203
|
process.exit(1);
|
|
1633
1204
|
}
|
|
1634
1205
|
console.log("");
|
|
1635
|
-
console.log(` ${
|
|
1636
|
-
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())}`);
|
|
1637
1208
|
console.log("");
|
|
1638
|
-
console.log(` ${
|
|
1639
|
-
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")}`);
|
|
1640
1211
|
console.log("");
|
|
1641
1212
|
}
|
|
1642
1213
|
async function logoutCommand() {
|
|
1643
1214
|
const config = loadGlobalConfig();
|
|
1644
1215
|
if (!config.auth?.token) {
|
|
1645
1216
|
console.log(`
|
|
1646
|
-
${
|
|
1217
|
+
${pc10.dim("You're not logged in. Nothing to do.")}
|
|
1647
1218
|
`);
|
|
1648
1219
|
return;
|
|
1649
1220
|
}
|
|
@@ -1656,40 +1227,40 @@ async function logoutCommand() {
|
|
|
1656
1227
|
process.exit(1);
|
|
1657
1228
|
}
|
|
1658
1229
|
console.log("");
|
|
1659
|
-
console.log(` ${
|
|
1660
|
-
console.log(` ${
|
|
1661
|
-
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.")}`);
|
|
1662
1233
|
console.log("");
|
|
1663
1234
|
}
|
|
1664
1235
|
async function whoamiCommand() {
|
|
1665
1236
|
const config = loadGlobalConfig();
|
|
1666
1237
|
console.log("");
|
|
1667
|
-
console.log(
|
|
1238
|
+
console.log(pc10.bold(pc10.cyan(" Vector Vesper Account Status\n")));
|
|
1668
1239
|
if (config.auth?.token) {
|
|
1669
1240
|
const maskedKey = config.auth.token.slice(0, 6) + "\u2026" + config.auth.token.slice(-4);
|
|
1670
1241
|
const tier = config.auth.tier || "pro";
|
|
1671
|
-
console.log(` ${
|
|
1672
|
-
console.log(` ${
|
|
1673
|
-
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)}`);
|
|
1674
1245
|
if (config.auth.email) {
|
|
1675
|
-
console.log(` ${
|
|
1246
|
+
console.log(` ${pc10.bold("Email:")} ${pc10.cyan(config.auth.email)}`);
|
|
1676
1247
|
}
|
|
1677
1248
|
if (config.auth.expiresAt) {
|
|
1678
1249
|
const expiry = new Date(config.auth.expiresAt);
|
|
1679
1250
|
const now = /* @__PURE__ */ new Date();
|
|
1680
1251
|
const isExpired = expiry < now;
|
|
1681
|
-
console.log(` ${
|
|
1252
|
+
console.log(` ${pc10.bold("Expires:")} ${isExpired ? pc10.red("EXPIRED") : pc10.green(expiry.toLocaleDateString())}`);
|
|
1682
1253
|
}
|
|
1683
1254
|
console.log("");
|
|
1684
|
-
console.log(` ${
|
|
1685
|
-
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")}`);
|
|
1686
1257
|
} else {
|
|
1687
|
-
console.log(` ${
|
|
1688
|
-
console.log(` ${
|
|
1258
|
+
console.log(` ${pc10.bold("Status:")} ${pc10.yellow("Anonymous (free tier)")}`);
|
|
1259
|
+
console.log(` ${pc10.bold("Access:")} ${pc10.dim("Free components only")}`);
|
|
1689
1260
|
console.log("");
|
|
1690
|
-
console.log(` ${
|
|
1691
|
-
console.log(` ${
|
|
1692
|
-
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")}`);
|
|
1693
1264
|
}
|
|
1694
1265
|
console.log("");
|
|
1695
1266
|
}
|
|
@@ -1733,6 +1304,10 @@ program.command("logout", { hidden: true }).description("Clear stored license cr
|
|
|
1733
1304
|
program.command("whoami", { hidden: true }).description("Show current authentication status").action(async () => {
|
|
1734
1305
|
await whoamiCommand();
|
|
1735
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
|
+
});
|
|
1736
1311
|
process.on("unhandledRejection", (error) => {
|
|
1737
1312
|
console.error("An unexpected error occurred:", error instanceof Error ? error.message : error);
|
|
1738
1313
|
process.exit(1);
|