vectorvesper 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-32GDEAJM.js → chunk-HOJ3DQSV.js} +11 -242
- package/dist/chunk-SFP5K3ZO.js +243 -0
- package/dist/chunk-XN3PPCIM.js +41 -0
- package/dist/hooks.json +120 -31
- package/dist/index.js +9 -7
- package/dist/mcp-IHHFTU4U.js +107 -0
- package/dist/{server-7WN7N3ZG.js → server-P6ZU3IS6.js} +36 -44
- package/package.json +67 -66
- package/dist/mcp-DOUIUZGA.js +0 -24
|
@@ -1,37 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
/** Standard info message */
|
|
9
|
-
info(message) {
|
|
10
|
-
console.log(message);
|
|
11
|
-
},
|
|
12
|
-
/** Success message with green checkmark */
|
|
13
|
-
success(message) {
|
|
14
|
-
console.log(`${pc.green("\u2714")} ${message}`);
|
|
15
|
-
},
|
|
16
|
-
/** Warning message */
|
|
17
|
-
warn(message) {
|
|
18
|
-
console.log(pc.yellow(`\u26A0\uFE0F ${message}`));
|
|
19
|
-
},
|
|
20
|
-
/** Error message */
|
|
21
|
-
error(message) {
|
|
22
|
-
console.error(pc.red(`\u274C ${message}`));
|
|
23
|
-
},
|
|
24
|
-
/** Debug message — only shown when --verbose is active */
|
|
25
|
-
debug(message) {
|
|
26
|
-
if (verboseMode) {
|
|
27
|
-
console.log(pc.dim(` [debug] ${message}`));
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
/** Blank line */
|
|
31
|
-
break() {
|
|
32
|
-
console.log("");
|
|
33
|
-
}
|
|
34
|
-
};
|
|
1
|
+
import {
|
|
2
|
+
RegistryComponentSchema,
|
|
3
|
+
RegistryIndexSchema,
|
|
4
|
+
getAuthToken,
|
|
5
|
+
logger,
|
|
6
|
+
validateSlug
|
|
7
|
+
} from "./chunk-SFP5K3ZO.js";
|
|
35
8
|
|
|
36
9
|
// src/utils/project.ts
|
|
37
10
|
import fs from "fs";
|
|
@@ -97,203 +70,9 @@ function detectProject(cwd = process.cwd()) {
|
|
|
97
70
|
};
|
|
98
71
|
}
|
|
99
72
|
|
|
100
|
-
// src/utils/
|
|
73
|
+
// src/utils/registry.ts
|
|
101
74
|
import fs2 from "fs";
|
|
102
75
|
import path2 from "path";
|
|
103
|
-
import os from "os";
|
|
104
|
-
|
|
105
|
-
// src/utils/types.ts
|
|
106
|
-
import { z } from "zod";
|
|
107
|
-
var SLUG_REGEX = /^[a-z0-9][a-z0-9-]*$/;
|
|
108
|
-
function validateSlug(slug) {
|
|
109
|
-
if (!SLUG_REGEX.test(slug)) {
|
|
110
|
-
throw new Error(
|
|
111
|
-
`Invalid component slug "${slug}". Slugs must contain only lowercase letters, numbers, and hyphens, and cannot start with a hyphen.`
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
var ComponentFileSchema = z.object({
|
|
116
|
-
path: z.string(),
|
|
117
|
-
target: z.string(),
|
|
118
|
-
type: z.enum(["component", "types", "shader", "lib", "docs"]),
|
|
119
|
-
content: z.string()
|
|
120
|
-
});
|
|
121
|
-
var RegistryComponentSchema = z.object({
|
|
122
|
-
slug: z.string(),
|
|
123
|
-
name: z.string(),
|
|
124
|
-
title: z.string(),
|
|
125
|
-
description: z.string(),
|
|
126
|
-
version: z.string(),
|
|
127
|
-
tier: z.enum(["free", "pro"]),
|
|
128
|
-
category: z.string(),
|
|
129
|
-
type: z.string(),
|
|
130
|
-
frameworks: z.array(z.string()),
|
|
131
|
-
files: z.array(ComponentFileSchema),
|
|
132
|
-
dependencies: z.array(z.string()),
|
|
133
|
-
devDependencies: z.array(z.string()),
|
|
134
|
-
registryDependencies: z.array(z.string()),
|
|
135
|
-
requiresClient: z.boolean(),
|
|
136
|
-
supportsReducedMotion: z.boolean(),
|
|
137
|
-
usesWebGL: z.boolean(),
|
|
138
|
-
usesPointer: z.boolean(),
|
|
139
|
-
usesScroll: z.boolean(),
|
|
140
|
-
// Optional metadata — kept in sync with the registry builder schema.
|
|
141
|
-
// Declared here (rather than relying on .passthrough()) so the CLI can
|
|
142
|
-
// read them with full type-safety for post-install guidance.
|
|
143
|
-
entry: z.string().optional(),
|
|
144
|
-
exportName: z.string().optional(),
|
|
145
|
-
usesTailwind: z.boolean().optional(),
|
|
146
|
-
fallbacks: z.array(z.string()).optional(),
|
|
147
|
-
recipes: z.array(z.string()).optional(),
|
|
148
|
-
docsUrl: z.string().optional(),
|
|
149
|
-
previewUrl: z.string().optional()
|
|
150
|
-
}).passthrough();
|
|
151
|
-
var IndexComponentSchema = z.object({
|
|
152
|
-
slug: z.string(),
|
|
153
|
-
name: z.string(),
|
|
154
|
-
title: z.string(),
|
|
155
|
-
description: z.string(),
|
|
156
|
-
version: z.string(),
|
|
157
|
-
tier: z.enum(["free", "pro"]),
|
|
158
|
-
category: z.string(),
|
|
159
|
-
type: z.string(),
|
|
160
|
-
frameworks: z.array(z.string()),
|
|
161
|
-
files: z.array(z.object({
|
|
162
|
-
path: z.string(),
|
|
163
|
-
target: z.string(),
|
|
164
|
-
type: z.enum(["component", "types", "shader", "lib", "docs"])
|
|
165
|
-
})),
|
|
166
|
-
dependencies: z.array(z.string()),
|
|
167
|
-
devDependencies: z.array(z.string()),
|
|
168
|
-
registryDependencies: z.array(z.string()),
|
|
169
|
-
requiresClient: z.boolean(),
|
|
170
|
-
supportsReducedMotion: z.boolean(),
|
|
171
|
-
usesWebGL: z.boolean(),
|
|
172
|
-
usesPointer: z.boolean(),
|
|
173
|
-
usesScroll: z.boolean(),
|
|
174
|
-
entry: z.string().optional(),
|
|
175
|
-
exportName: z.string().optional(),
|
|
176
|
-
usesTailwind: z.boolean().optional(),
|
|
177
|
-
// These are emitted by the registry build and were reaching consumers only
|
|
178
|
-
// through .passthrough(), i.e. typed as unknown. Declared optional rather
|
|
179
|
-
// than required so an older published registry still validates.
|
|
180
|
-
fallbacks: z.array(z.string()).optional(),
|
|
181
|
-
recipes: z.array(z.string()).optional(),
|
|
182
|
-
docsUrl: z.string().optional(),
|
|
183
|
-
previewUrl: z.string().optional()
|
|
184
|
-
}).passthrough();
|
|
185
|
-
var RegistryIndexSchema = z.object({
|
|
186
|
-
version: z.string(),
|
|
187
|
-
components: z.array(IndexComponentSchema)
|
|
188
|
-
});
|
|
189
|
-
var VVConfigSchema = z.object({
|
|
190
|
-
tsx: z.boolean(),
|
|
191
|
-
framework: z.enum(["next", "vite", "unknown"]),
|
|
192
|
-
aliases: z.object({
|
|
193
|
-
vv: z.string()
|
|
194
|
-
})
|
|
195
|
-
});
|
|
196
|
-
var VVGlobalConfigSchema = z.object({
|
|
197
|
-
// Auth — license key for paid components
|
|
198
|
-
auth: z.object({
|
|
199
|
-
token: z.string().optional(),
|
|
200
|
-
email: z.string().optional(),
|
|
201
|
-
tier: z.enum(["free", "pro", "team"]).optional(),
|
|
202
|
-
expiresAt: z.string().optional()
|
|
203
|
-
}).optional(),
|
|
204
|
-
// Preferences
|
|
205
|
-
telemetry: z.boolean().optional()
|
|
206
|
-
}).passthrough();
|
|
207
|
-
var ManifestEntrySchema = z.object({
|
|
208
|
-
version: z.string(),
|
|
209
|
-
installedAt: z.string(),
|
|
210
|
-
installedOn: z.string(),
|
|
211
|
-
files: z.array(z.string())
|
|
212
|
-
});
|
|
213
|
-
var ManifestSchema = z.object({
|
|
214
|
-
components: z.record(z.string(), ManifestEntrySchema)
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
// src/utils/config.ts
|
|
218
|
-
var CONFIG_FILE_NAME = "vv.config.json";
|
|
219
|
-
function getConfigPath(cwd = process.cwd()) {
|
|
220
|
-
return path2.join(cwd, CONFIG_FILE_NAME);
|
|
221
|
-
}
|
|
222
|
-
function loadConfig(cwd = process.cwd()) {
|
|
223
|
-
const configPath = getConfigPath(cwd);
|
|
224
|
-
if (!fs2.existsSync(configPath)) {
|
|
225
|
-
return null;
|
|
226
|
-
}
|
|
227
|
-
let raw;
|
|
228
|
-
try {
|
|
229
|
-
const content = fs2.readFileSync(configPath, "utf-8");
|
|
230
|
-
raw = JSON.parse(content);
|
|
231
|
-
} catch {
|
|
232
|
-
throw new Error(
|
|
233
|
-
`Failed to parse vv.config.json \u2014 the file contains invalid JSON. Delete it and run "npx vectorvesper init" to regenerate.`
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
const result = VVConfigSchema.safeParse(raw);
|
|
237
|
-
if (!result.success) {
|
|
238
|
-
const issues = result.error.issues.map((i) => ` \u2022 ${i.path.join(".")}: ${i.message}`).join("\n");
|
|
239
|
-
throw new Error(
|
|
240
|
-
`Invalid vv.config.json \u2014 schema validation failed:
|
|
241
|
-
${issues}
|
|
242
|
-
Delete the file and run "npx vectorvesper init" to regenerate.`
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
|
-
return result.data;
|
|
246
|
-
}
|
|
247
|
-
function writeConfig(config, cwd = process.cwd()) {
|
|
248
|
-
const configPath = getConfigPath(cwd);
|
|
249
|
-
fs2.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
250
|
-
}
|
|
251
|
-
var GLOBAL_CONFIG_DIR = path2.join(os.homedir(), ".vv");
|
|
252
|
-
var GLOBAL_CONFIG_PATH = path2.join(GLOBAL_CONFIG_DIR, "config.json");
|
|
253
|
-
function getGlobalConfigPath() {
|
|
254
|
-
return GLOBAL_CONFIG_PATH;
|
|
255
|
-
}
|
|
256
|
-
function loadGlobalConfig() {
|
|
257
|
-
if (!fs2.existsSync(GLOBAL_CONFIG_PATH)) {
|
|
258
|
-
return {};
|
|
259
|
-
}
|
|
260
|
-
try {
|
|
261
|
-
const content = fs2.readFileSync(GLOBAL_CONFIG_PATH, "utf-8");
|
|
262
|
-
const raw = JSON.parse(content);
|
|
263
|
-
const result = VVGlobalConfigSchema.safeParse(raw);
|
|
264
|
-
if (!result.success) {
|
|
265
|
-
logger.debug(`Global config validation failed: ${result.error.message}`);
|
|
266
|
-
return {};
|
|
267
|
-
}
|
|
268
|
-
return result.data;
|
|
269
|
-
} catch {
|
|
270
|
-
logger.debug("Failed to parse global config, using defaults.");
|
|
271
|
-
return {};
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
function saveGlobalConfig(config) {
|
|
275
|
-
if (!fs2.existsSync(GLOBAL_CONFIG_DIR)) {
|
|
276
|
-
fs2.mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true });
|
|
277
|
-
}
|
|
278
|
-
fs2.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
|
|
279
|
-
}
|
|
280
|
-
function getAuthToken() {
|
|
281
|
-
const config = loadGlobalConfig();
|
|
282
|
-
return config.auth?.token;
|
|
283
|
-
}
|
|
284
|
-
function resolveAlias(alias, hasSrcDir) {
|
|
285
|
-
if (alias.startsWith("@/")) {
|
|
286
|
-
return alias.replace("@/", hasSrcDir ? "src/" : "");
|
|
287
|
-
}
|
|
288
|
-
if (alias.startsWith("~/")) {
|
|
289
|
-
return alias.replace("~/", hasSrcDir ? "src/" : "");
|
|
290
|
-
}
|
|
291
|
-
return alias;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
// src/utils/registry.ts
|
|
295
|
-
import fs3 from "fs";
|
|
296
|
-
import path3 from "path";
|
|
297
76
|
import { fileURLToPath } from "url";
|
|
298
77
|
var DEFAULT_REGISTRY_URL = "https://raw.githubusercontent.com/vectorvesper/vv-components/main/r";
|
|
299
78
|
var DEFAULT_PRO_API_URL = "https://vectorvesper.dev/api/cli/registry";
|
|
@@ -402,12 +181,12 @@ async function fetchRegistryData(urlOrPath) {
|
|
|
402
181
|
if (urlOrPath.startsWith("file://")) {
|
|
403
182
|
cleanPath = fileURLToPath(urlOrPath);
|
|
404
183
|
}
|
|
405
|
-
cleanPath =
|
|
406
|
-
if (!
|
|
184
|
+
cleanPath = path2.resolve(cleanPath);
|
|
185
|
+
if (!fs2.existsSync(cleanPath)) {
|
|
407
186
|
throw new Error(`Registry path not found: ${cleanPath}`);
|
|
408
187
|
}
|
|
409
188
|
logger.debug(`Reading local registry: ${cleanPath}`);
|
|
410
|
-
return
|
|
189
|
+
return fs2.readFileSync(cleanPath, "utf-8");
|
|
411
190
|
}
|
|
412
191
|
async function fetchRegistryIndex() {
|
|
413
192
|
const baseUrl = getRegistryBaseUrl();
|
|
@@ -482,17 +261,7 @@ ${issues}`);
|
|
|
482
261
|
}
|
|
483
262
|
|
|
484
263
|
export {
|
|
485
|
-
setVerbose,
|
|
486
|
-
logger,
|
|
487
264
|
detectProject,
|
|
488
|
-
validateSlug,
|
|
489
|
-
loadConfig,
|
|
490
|
-
writeConfig,
|
|
491
|
-
getGlobalConfigPath,
|
|
492
|
-
loadGlobalConfig,
|
|
493
|
-
saveGlobalConfig,
|
|
494
|
-
getAuthToken,
|
|
495
|
-
resolveAlias,
|
|
496
265
|
fetchRegistryIndex,
|
|
497
266
|
fetchComponent
|
|
498
267
|
};
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
// src/utils/logger.ts
|
|
2
|
+
import pc from "picocolors";
|
|
3
|
+
var verboseMode = false;
|
|
4
|
+
function setVerbose(enabled) {
|
|
5
|
+
verboseMode = enabled;
|
|
6
|
+
}
|
|
7
|
+
var logger = {
|
|
8
|
+
/** Standard info message */
|
|
9
|
+
info(message) {
|
|
10
|
+
console.log(message);
|
|
11
|
+
},
|
|
12
|
+
/** Success message with green checkmark */
|
|
13
|
+
success(message) {
|
|
14
|
+
console.log(`${pc.green("\u2714")} ${message}`);
|
|
15
|
+
},
|
|
16
|
+
/** Warning message */
|
|
17
|
+
warn(message) {
|
|
18
|
+
console.log(pc.yellow(`\u26A0\uFE0F ${message}`));
|
|
19
|
+
},
|
|
20
|
+
/** Error message */
|
|
21
|
+
error(message) {
|
|
22
|
+
console.error(pc.red(`\u274C ${message}`));
|
|
23
|
+
},
|
|
24
|
+
/** Debug message — only shown when --verbose is active */
|
|
25
|
+
debug(message) {
|
|
26
|
+
if (verboseMode) {
|
|
27
|
+
console.log(pc.dim(` [debug] ${message}`));
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
/** Blank line */
|
|
31
|
+
break() {
|
|
32
|
+
console.log("");
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// src/utils/config.ts
|
|
37
|
+
import fs from "fs";
|
|
38
|
+
import path from "path";
|
|
39
|
+
import os from "os";
|
|
40
|
+
|
|
41
|
+
// src/utils/types.ts
|
|
42
|
+
import { z } from "zod";
|
|
43
|
+
var SLUG_REGEX = /^[a-z0-9][a-z0-9-]*$/;
|
|
44
|
+
function validateSlug(slug) {
|
|
45
|
+
if (!SLUG_REGEX.test(slug)) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`Invalid component slug "${slug}". Slugs must contain only lowercase letters, numbers, and hyphens, and cannot start with a hyphen.`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
var ComponentFileSchema = z.object({
|
|
52
|
+
path: z.string(),
|
|
53
|
+
target: z.string(),
|
|
54
|
+
type: z.enum(["component", "types", "shader", "lib", "docs"]),
|
|
55
|
+
content: z.string()
|
|
56
|
+
});
|
|
57
|
+
var RegistryComponentSchema = z.object({
|
|
58
|
+
slug: z.string(),
|
|
59
|
+
name: z.string(),
|
|
60
|
+
title: z.string(),
|
|
61
|
+
description: z.string(),
|
|
62
|
+
version: z.string(),
|
|
63
|
+
tier: z.enum(["free", "pro"]),
|
|
64
|
+
category: z.string(),
|
|
65
|
+
type: z.string(),
|
|
66
|
+
frameworks: z.array(z.string()),
|
|
67
|
+
files: z.array(ComponentFileSchema),
|
|
68
|
+
dependencies: z.array(z.string()),
|
|
69
|
+
devDependencies: z.array(z.string()),
|
|
70
|
+
registryDependencies: z.array(z.string()),
|
|
71
|
+
requiresClient: z.boolean(),
|
|
72
|
+
supportsReducedMotion: z.boolean(),
|
|
73
|
+
usesWebGL: z.boolean(),
|
|
74
|
+
usesPointer: z.boolean(),
|
|
75
|
+
usesScroll: z.boolean(),
|
|
76
|
+
// Optional metadata — kept in sync with the registry builder schema.
|
|
77
|
+
// Declared here (rather than relying on .passthrough()) so the CLI can
|
|
78
|
+
// read them with full type-safety for post-install guidance.
|
|
79
|
+
entry: z.string().optional(),
|
|
80
|
+
exportName: z.string().optional(),
|
|
81
|
+
usesTailwind: z.boolean().optional(),
|
|
82
|
+
fallbacks: z.array(z.string()).optional(),
|
|
83
|
+
recipes: z.array(z.string()).optional(),
|
|
84
|
+
docsUrl: z.string().optional(),
|
|
85
|
+
previewUrl: z.string().optional()
|
|
86
|
+
}).passthrough();
|
|
87
|
+
var IndexComponentSchema = z.object({
|
|
88
|
+
slug: z.string(),
|
|
89
|
+
name: z.string(),
|
|
90
|
+
title: z.string(),
|
|
91
|
+
description: z.string(),
|
|
92
|
+
version: z.string(),
|
|
93
|
+
tier: z.enum(["free", "pro"]),
|
|
94
|
+
category: z.string(),
|
|
95
|
+
type: z.string(),
|
|
96
|
+
frameworks: z.array(z.string()),
|
|
97
|
+
files: z.array(z.object({
|
|
98
|
+
path: z.string(),
|
|
99
|
+
target: z.string(),
|
|
100
|
+
type: z.enum(["component", "types", "shader", "lib", "docs"])
|
|
101
|
+
})),
|
|
102
|
+
dependencies: z.array(z.string()),
|
|
103
|
+
devDependencies: z.array(z.string()),
|
|
104
|
+
registryDependencies: z.array(z.string()),
|
|
105
|
+
requiresClient: z.boolean(),
|
|
106
|
+
supportsReducedMotion: z.boolean(),
|
|
107
|
+
usesWebGL: z.boolean(),
|
|
108
|
+
usesPointer: z.boolean(),
|
|
109
|
+
usesScroll: z.boolean(),
|
|
110
|
+
entry: z.string().optional(),
|
|
111
|
+
exportName: z.string().optional(),
|
|
112
|
+
usesTailwind: z.boolean().optional(),
|
|
113
|
+
// These are emitted by the registry build and were reaching consumers only
|
|
114
|
+
// through .passthrough(), i.e. typed as unknown. Declared optional rather
|
|
115
|
+
// than required so an older published registry still validates.
|
|
116
|
+
fallbacks: z.array(z.string()).optional(),
|
|
117
|
+
recipes: z.array(z.string()).optional(),
|
|
118
|
+
docsUrl: z.string().optional(),
|
|
119
|
+
previewUrl: z.string().optional()
|
|
120
|
+
}).passthrough();
|
|
121
|
+
var RegistryIndexSchema = z.object({
|
|
122
|
+
version: z.string(),
|
|
123
|
+
components: z.array(IndexComponentSchema)
|
|
124
|
+
});
|
|
125
|
+
var VVConfigSchema = z.object({
|
|
126
|
+
tsx: z.boolean(),
|
|
127
|
+
framework: z.enum(["next", "vite", "unknown"]),
|
|
128
|
+
aliases: z.object({
|
|
129
|
+
vv: z.string()
|
|
130
|
+
})
|
|
131
|
+
});
|
|
132
|
+
var VVGlobalConfigSchema = z.object({
|
|
133
|
+
// Auth — license key for paid components
|
|
134
|
+
auth: z.object({
|
|
135
|
+
token: z.string().optional(),
|
|
136
|
+
email: z.string().optional(),
|
|
137
|
+
tier: z.enum(["free", "pro", "team"]).optional(),
|
|
138
|
+
expiresAt: z.string().optional()
|
|
139
|
+
}).optional(),
|
|
140
|
+
// Preferences
|
|
141
|
+
telemetry: z.boolean().optional()
|
|
142
|
+
}).passthrough();
|
|
143
|
+
var ManifestEntrySchema = z.object({
|
|
144
|
+
version: z.string(),
|
|
145
|
+
installedAt: z.string(),
|
|
146
|
+
installedOn: z.string(),
|
|
147
|
+
files: z.array(z.string())
|
|
148
|
+
});
|
|
149
|
+
var ManifestSchema = z.object({
|
|
150
|
+
components: z.record(z.string(), ManifestEntrySchema)
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// src/utils/config.ts
|
|
154
|
+
var CONFIG_FILE_NAME = "vv.config.json";
|
|
155
|
+
function getConfigPath(cwd = process.cwd()) {
|
|
156
|
+
return path.join(cwd, CONFIG_FILE_NAME);
|
|
157
|
+
}
|
|
158
|
+
function loadConfig(cwd = process.cwd()) {
|
|
159
|
+
const configPath = getConfigPath(cwd);
|
|
160
|
+
if (!fs.existsSync(configPath)) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
let raw;
|
|
164
|
+
try {
|
|
165
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
166
|
+
raw = JSON.parse(content);
|
|
167
|
+
} catch {
|
|
168
|
+
throw new Error(
|
|
169
|
+
`Failed to parse vv.config.json \u2014 the file contains invalid JSON. Delete it and run "npx vectorvesper init" to regenerate.`
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
const result = VVConfigSchema.safeParse(raw);
|
|
173
|
+
if (!result.success) {
|
|
174
|
+
const issues = result.error.issues.map((i) => ` \u2022 ${i.path.join(".")}: ${i.message}`).join("\n");
|
|
175
|
+
throw new Error(
|
|
176
|
+
`Invalid vv.config.json \u2014 schema validation failed:
|
|
177
|
+
${issues}
|
|
178
|
+
Delete the file and run "npx vectorvesper init" to regenerate.`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return result.data;
|
|
182
|
+
}
|
|
183
|
+
function writeConfig(config, cwd = process.cwd()) {
|
|
184
|
+
const configPath = getConfigPath(cwd);
|
|
185
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
186
|
+
}
|
|
187
|
+
var GLOBAL_CONFIG_DIR = path.join(os.homedir(), ".vv");
|
|
188
|
+
var GLOBAL_CONFIG_PATH = path.join(GLOBAL_CONFIG_DIR, "config.json");
|
|
189
|
+
function getGlobalConfigPath() {
|
|
190
|
+
return GLOBAL_CONFIG_PATH;
|
|
191
|
+
}
|
|
192
|
+
function loadGlobalConfig() {
|
|
193
|
+
if (!fs.existsSync(GLOBAL_CONFIG_PATH)) {
|
|
194
|
+
return {};
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
const content = fs.readFileSync(GLOBAL_CONFIG_PATH, "utf-8");
|
|
198
|
+
const raw = JSON.parse(content);
|
|
199
|
+
const result = VVGlobalConfigSchema.safeParse(raw);
|
|
200
|
+
if (!result.success) {
|
|
201
|
+
logger.debug(`Global config validation failed: ${result.error.message}`);
|
|
202
|
+
return {};
|
|
203
|
+
}
|
|
204
|
+
return result.data;
|
|
205
|
+
} catch {
|
|
206
|
+
logger.debug("Failed to parse global config, using defaults.");
|
|
207
|
+
return {};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function saveGlobalConfig(config) {
|
|
211
|
+
if (!fs.existsSync(GLOBAL_CONFIG_DIR)) {
|
|
212
|
+
fs.mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true });
|
|
213
|
+
}
|
|
214
|
+
fs.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
|
|
215
|
+
}
|
|
216
|
+
function getAuthToken() {
|
|
217
|
+
const config = loadGlobalConfig();
|
|
218
|
+
return config.auth?.token;
|
|
219
|
+
}
|
|
220
|
+
function resolveAlias(alias, hasSrcDir) {
|
|
221
|
+
if (alias.startsWith("@/")) {
|
|
222
|
+
return alias.replace("@/", hasSrcDir ? "src/" : "");
|
|
223
|
+
}
|
|
224
|
+
if (alias.startsWith("~/")) {
|
|
225
|
+
return alias.replace("~/", hasSrcDir ? "src/" : "");
|
|
226
|
+
}
|
|
227
|
+
return alias;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export {
|
|
231
|
+
setVerbose,
|
|
232
|
+
logger,
|
|
233
|
+
validateSlug,
|
|
234
|
+
RegistryComponentSchema,
|
|
235
|
+
RegistryIndexSchema,
|
|
236
|
+
loadConfig,
|
|
237
|
+
writeConfig,
|
|
238
|
+
getGlobalConfigPath,
|
|
239
|
+
loadGlobalConfig,
|
|
240
|
+
saveGlobalConfig,
|
|
241
|
+
getAuthToken,
|
|
242
|
+
resolveAlias
|
|
243
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// src/mcp/manifest.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
var CANDIDATES = [
|
|
7
|
+
path.join(__dirname, "hooks.json"),
|
|
8
|
+
path.join(__dirname, "../hooks.json"),
|
|
9
|
+
path.resolve(__dirname, "../../../registry/generated/hooks.lean.json"),
|
|
10
|
+
path.resolve(__dirname, "../../registry/generated/hooks.lean.json")
|
|
11
|
+
];
|
|
12
|
+
var cached = null;
|
|
13
|
+
function loadHookManifest() {
|
|
14
|
+
if (cached) return cached;
|
|
15
|
+
for (const candidate of CANDIDATES) {
|
|
16
|
+
if (!fs.existsSync(candidate)) continue;
|
|
17
|
+
try {
|
|
18
|
+
const parsed = JSON.parse(fs.readFileSync(candidate, "utf-8"));
|
|
19
|
+
if (Array.isArray(parsed?.hooks)) {
|
|
20
|
+
cached = parsed;
|
|
21
|
+
return cached;
|
|
22
|
+
}
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
function findHook(name) {
|
|
29
|
+
const manifest = loadHookManifest();
|
|
30
|
+
if (!manifest) return null;
|
|
31
|
+
const wanted = name.toLowerCase();
|
|
32
|
+
return manifest.hooks.find((h) => h.name.toLowerCase() === wanted) ?? // Tolerate "sensor-bus" / "sensorbus" / "SensorBus" for "useSensorBus".
|
|
33
|
+
manifest.hooks.find(
|
|
34
|
+
(h) => h.name.toLowerCase().replace(/^use/, "") === wanted.replace(/^use/, "").replace(/-/g, "")
|
|
35
|
+
) ?? null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export {
|
|
39
|
+
loadHookManifest,
|
|
40
|
+
findHook
|
|
41
|
+
};
|