@enconvo/dxt 0.2.6
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/LICENSE.md +7 -0
- package/README.md +118 -0
- package/dist/browser.d.ts +3 -0
- package/dist/browser.js +4 -0
- package/dist/cli/cli.d.ts +2 -0
- package/dist/cli/cli.js +275 -0
- package/dist/cli/init.d.ts +185 -0
- package/dist/cli/init.js +704 -0
- package/dist/cli/pack.d.ts +7 -0
- package/dist/cli/pack.js +194 -0
- package/dist/cli/unpack.d.ts +7 -0
- package/dist/cli/unpack.js +101 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +11 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +10 -0
- package/dist/node/files.d.ts +20 -0
- package/dist/node/files.js +115 -0
- package/dist/node/sign.d.ts +32 -0
- package/dist/node/sign.js +333 -0
- package/dist/node/validate.d.ts +2 -0
- package/dist/node/validate.js +124 -0
- package/dist/node.d.ts +6 -0
- package/dist/node.js +8 -0
- package/dist/schemas-loose.d.ts +629 -0
- package/dist/schemas-loose.js +97 -0
- package/dist/schemas.d.ts +637 -0
- package/dist/schemas.js +98 -0
- package/dist/shared/config.d.ts +34 -0
- package/dist/shared/config.js +157 -0
- package/dist/shared/log.d.ts +11 -0
- package/dist/shared/log.js +29 -0
- package/dist/types.d.ts +23 -0
- package/dist/types.js +1 -0
- package/package.json +83 -0
package/dist/cli/init.js
ADDED
@@ -0,0 +1,704 @@
|
|
1
|
+
import { confirm, input, select } from "@inquirer/prompts";
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
3
|
+
import { basename, join, resolve } from "path";
|
4
|
+
export function readPackageJson(dirPath) {
|
5
|
+
const packageJsonPath = join(dirPath, "package.json");
|
6
|
+
if (existsSync(packageJsonPath)) {
|
7
|
+
try {
|
8
|
+
return JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
9
|
+
}
|
10
|
+
catch (e) {
|
11
|
+
// Ignore package.json parsing errors
|
12
|
+
}
|
13
|
+
}
|
14
|
+
return {};
|
15
|
+
}
|
16
|
+
export function getDefaultAuthorName(packageData) {
|
17
|
+
if (typeof packageData.author === "string") {
|
18
|
+
return packageData.author;
|
19
|
+
}
|
20
|
+
return packageData.author?.name || "";
|
21
|
+
}
|
22
|
+
export function getDefaultAuthorEmail(packageData) {
|
23
|
+
if (typeof packageData.author === "object") {
|
24
|
+
return packageData.author?.email || "";
|
25
|
+
}
|
26
|
+
return "";
|
27
|
+
}
|
28
|
+
export function getDefaultAuthorUrl(packageData) {
|
29
|
+
if (typeof packageData.author === "object") {
|
30
|
+
return packageData.author?.url || "";
|
31
|
+
}
|
32
|
+
return "";
|
33
|
+
}
|
34
|
+
export function getDefaultRepositoryUrl(packageData) {
|
35
|
+
if (typeof packageData.repository === "string") {
|
36
|
+
return packageData.repository;
|
37
|
+
}
|
38
|
+
return packageData.repository?.url || "";
|
39
|
+
}
|
40
|
+
export function getDefaultBasicInfo(packageData, resolvedPath) {
|
41
|
+
const name = packageData.name || basename(resolvedPath);
|
42
|
+
const authorName = getDefaultAuthorName(packageData) || "Unknown Author";
|
43
|
+
const displayName = name;
|
44
|
+
const version = packageData.version || "1.0.0";
|
45
|
+
const description = packageData.description || "A DXT extension";
|
46
|
+
return { name, authorName, displayName, version, description };
|
47
|
+
}
|
48
|
+
export function getDefaultAuthorInfo(packageData) {
|
49
|
+
return {
|
50
|
+
authorEmail: getDefaultAuthorEmail(packageData),
|
51
|
+
authorUrl: getDefaultAuthorUrl(packageData),
|
52
|
+
};
|
53
|
+
}
|
54
|
+
export function getDefaultServerConfig(packageData) {
|
55
|
+
const serverType = "node";
|
56
|
+
const entryPoint = getDefaultEntryPoint(serverType, packageData);
|
57
|
+
const mcp_config = createMcpConfig(serverType, entryPoint);
|
58
|
+
return { serverType, entryPoint, mcp_config };
|
59
|
+
}
|
60
|
+
export function getDefaultOptionalFields(packageData) {
|
61
|
+
return {
|
62
|
+
keywords: "",
|
63
|
+
license: packageData.license || "MIT",
|
64
|
+
repository: undefined,
|
65
|
+
};
|
66
|
+
}
|
67
|
+
export function createMcpConfig(serverType, entryPoint) {
|
68
|
+
switch (serverType) {
|
69
|
+
case "node":
|
70
|
+
return {
|
71
|
+
command: "node",
|
72
|
+
args: ["${__dirname}/" + entryPoint],
|
73
|
+
env: {},
|
74
|
+
};
|
75
|
+
case "python":
|
76
|
+
return {
|
77
|
+
command: "python",
|
78
|
+
args: ["${__dirname}/" + entryPoint],
|
79
|
+
env: {
|
80
|
+
PYTHONPATH: "${__dirname}/server/lib",
|
81
|
+
},
|
82
|
+
};
|
83
|
+
case "binary":
|
84
|
+
return {
|
85
|
+
command: "${__dirname}/" + entryPoint,
|
86
|
+
args: [],
|
87
|
+
env: {},
|
88
|
+
};
|
89
|
+
}
|
90
|
+
}
|
91
|
+
export function getDefaultEntryPoint(serverType, packageData) {
|
92
|
+
switch (serverType) {
|
93
|
+
case "node":
|
94
|
+
return packageData?.main || "server/index.js";
|
95
|
+
case "python":
|
96
|
+
return "server/main.py";
|
97
|
+
case "binary":
|
98
|
+
return "server/my-server";
|
99
|
+
}
|
100
|
+
}
|
101
|
+
export async function promptBasicInfo(packageData, resolvedPath) {
|
102
|
+
const defaultName = packageData.name || basename(resolvedPath);
|
103
|
+
const name = await input({
|
104
|
+
message: "Extension name:",
|
105
|
+
default: defaultName,
|
106
|
+
validate: (value) => value.trim().length > 0 || "Name is required",
|
107
|
+
});
|
108
|
+
const authorName = await input({
|
109
|
+
message: "Author name:",
|
110
|
+
default: getDefaultAuthorName(packageData),
|
111
|
+
validate: (value) => value.trim().length > 0 || "Author name is required",
|
112
|
+
});
|
113
|
+
const displayName = await input({
|
114
|
+
message: "Display name (optional):",
|
115
|
+
default: name,
|
116
|
+
});
|
117
|
+
const version = await input({
|
118
|
+
message: "Version:",
|
119
|
+
default: packageData.version || "1.0.0",
|
120
|
+
validate: (value) => {
|
121
|
+
if (!value.trim())
|
122
|
+
return "Version is required";
|
123
|
+
if (!/^\d+\.\d+\.\d+/.test(value)) {
|
124
|
+
return "Version must follow semantic versioning (e.g., 1.0.0)";
|
125
|
+
}
|
126
|
+
return true;
|
127
|
+
},
|
128
|
+
});
|
129
|
+
const description = await input({
|
130
|
+
message: "Description:",
|
131
|
+
default: packageData.description || "",
|
132
|
+
validate: (value) => value.trim().length > 0 || "Description is required",
|
133
|
+
});
|
134
|
+
return { name, authorName, displayName, version, description };
|
135
|
+
}
|
136
|
+
export async function promptAuthorInfo(packageData) {
|
137
|
+
const authorEmail = await input({
|
138
|
+
message: "Author email (optional):",
|
139
|
+
default: getDefaultAuthorEmail(packageData),
|
140
|
+
});
|
141
|
+
const authorUrl = await input({
|
142
|
+
message: "Author URL (optional):",
|
143
|
+
default: getDefaultAuthorUrl(packageData),
|
144
|
+
});
|
145
|
+
return { authorEmail, authorUrl };
|
146
|
+
}
|
147
|
+
export async function promptServerConfig(packageData) {
|
148
|
+
const serverType = (await select({
|
149
|
+
message: "Server type:",
|
150
|
+
choices: [
|
151
|
+
{ name: "Node.js", value: "node" },
|
152
|
+
{ name: "Python", value: "python" },
|
153
|
+
{ name: "Binary", value: "binary" },
|
154
|
+
],
|
155
|
+
default: "node",
|
156
|
+
}));
|
157
|
+
const entryPoint = await input({
|
158
|
+
message: "Entry point:",
|
159
|
+
default: getDefaultEntryPoint(serverType, packageData),
|
160
|
+
});
|
161
|
+
const mcp_config = createMcpConfig(serverType, entryPoint);
|
162
|
+
return { serverType, entryPoint, mcp_config };
|
163
|
+
}
|
164
|
+
export async function promptTools() {
|
165
|
+
const addTools = await confirm({
|
166
|
+
message: "Does your MCP Server provide tools you want to advertise (optional)?",
|
167
|
+
default: true,
|
168
|
+
});
|
169
|
+
const tools = [];
|
170
|
+
let toolsGenerated = false;
|
171
|
+
if (addTools) {
|
172
|
+
let addMore = true;
|
173
|
+
while (addMore) {
|
174
|
+
const toolName = await input({
|
175
|
+
message: "Tool name:",
|
176
|
+
validate: (value) => value.trim().length > 0 || "Tool name is required",
|
177
|
+
});
|
178
|
+
const toolDescription = await input({
|
179
|
+
message: "Tool description (optional):",
|
180
|
+
});
|
181
|
+
tools.push({
|
182
|
+
name: toolName,
|
183
|
+
...(toolDescription ? { description: toolDescription } : {}),
|
184
|
+
});
|
185
|
+
addMore = await confirm({
|
186
|
+
message: "Add another tool?",
|
187
|
+
default: false,
|
188
|
+
});
|
189
|
+
}
|
190
|
+
// Ask about generated tools
|
191
|
+
toolsGenerated = await confirm({
|
192
|
+
message: "Does your server generate additional tools at runtime?",
|
193
|
+
default: false,
|
194
|
+
});
|
195
|
+
}
|
196
|
+
return { tools, toolsGenerated };
|
197
|
+
}
|
198
|
+
export async function promptPrompts() {
|
199
|
+
const addPrompts = await confirm({
|
200
|
+
message: "Does your MCP Server provide prompts you want to advertise (optional)?",
|
201
|
+
default: false,
|
202
|
+
});
|
203
|
+
const prompts = [];
|
204
|
+
let promptsGenerated = false;
|
205
|
+
if (addPrompts) {
|
206
|
+
let addMore = true;
|
207
|
+
while (addMore) {
|
208
|
+
const promptName = await input({
|
209
|
+
message: "Prompt name:",
|
210
|
+
validate: (value) => value.trim().length > 0 || "Prompt name is required",
|
211
|
+
});
|
212
|
+
const promptDescription = await input({
|
213
|
+
message: "Prompt description (optional):",
|
214
|
+
});
|
215
|
+
// Ask about arguments
|
216
|
+
const hasArguments = await confirm({
|
217
|
+
message: "Does this prompt have arguments?",
|
218
|
+
default: false,
|
219
|
+
});
|
220
|
+
const argumentNames = [];
|
221
|
+
if (hasArguments) {
|
222
|
+
let addMoreArgs = true;
|
223
|
+
while (addMoreArgs) {
|
224
|
+
const argName = await input({
|
225
|
+
message: "Argument name:",
|
226
|
+
validate: (value) => {
|
227
|
+
if (!value.trim())
|
228
|
+
return "Argument name is required";
|
229
|
+
if (argumentNames.includes(value)) {
|
230
|
+
return "Argument names must be unique";
|
231
|
+
}
|
232
|
+
return true;
|
233
|
+
},
|
234
|
+
});
|
235
|
+
argumentNames.push(argName);
|
236
|
+
addMoreArgs = await confirm({
|
237
|
+
message: "Add another argument?",
|
238
|
+
default: false,
|
239
|
+
});
|
240
|
+
}
|
241
|
+
}
|
242
|
+
// Prompt for the text template
|
243
|
+
const promptText = await input({
|
244
|
+
message: hasArguments
|
245
|
+
? `Prompt text (use \${arguments.name} for arguments: ${argumentNames.join(", ")}):`
|
246
|
+
: "Prompt text:",
|
247
|
+
validate: (value) => value.trim().length > 0 || "Prompt text is required",
|
248
|
+
});
|
249
|
+
prompts.push({
|
250
|
+
name: promptName,
|
251
|
+
...(promptDescription ? { description: promptDescription } : {}),
|
252
|
+
...(argumentNames.length > 0 ? { arguments: argumentNames } : {}),
|
253
|
+
text: promptText,
|
254
|
+
});
|
255
|
+
addMore = await confirm({
|
256
|
+
message: "Add another prompt?",
|
257
|
+
default: false,
|
258
|
+
});
|
259
|
+
}
|
260
|
+
// Ask about generated prompts
|
261
|
+
promptsGenerated = await confirm({
|
262
|
+
message: "Does your server generate additional prompts at runtime?",
|
263
|
+
default: false,
|
264
|
+
});
|
265
|
+
}
|
266
|
+
return { prompts, promptsGenerated };
|
267
|
+
}
|
268
|
+
export async function promptOptionalFields(packageData) {
|
269
|
+
const keywords = await input({
|
270
|
+
message: "Keywords (comma-separated, optional):",
|
271
|
+
default: "",
|
272
|
+
});
|
273
|
+
const license = await input({
|
274
|
+
message: "License:",
|
275
|
+
default: packageData.license || "MIT",
|
276
|
+
});
|
277
|
+
const addRepository = await confirm({
|
278
|
+
message: "Add repository information?",
|
279
|
+
default: !!packageData.repository,
|
280
|
+
});
|
281
|
+
let repository;
|
282
|
+
if (addRepository) {
|
283
|
+
const repoUrl = await input({
|
284
|
+
message: "Repository URL:",
|
285
|
+
default: getDefaultRepositoryUrl(packageData),
|
286
|
+
});
|
287
|
+
if (repoUrl) {
|
288
|
+
repository = {
|
289
|
+
type: "git",
|
290
|
+
url: repoUrl,
|
291
|
+
};
|
292
|
+
}
|
293
|
+
}
|
294
|
+
return { keywords, license, repository };
|
295
|
+
}
|
296
|
+
export async function promptLongDescription(description) {
|
297
|
+
const hasLongDescription = await confirm({
|
298
|
+
message: "Add a detailed long description?",
|
299
|
+
default: false,
|
300
|
+
});
|
301
|
+
if (hasLongDescription) {
|
302
|
+
const longDescription = await input({
|
303
|
+
message: "Long description (supports basic markdown):",
|
304
|
+
default: description,
|
305
|
+
});
|
306
|
+
return longDescription;
|
307
|
+
}
|
308
|
+
return undefined;
|
309
|
+
}
|
310
|
+
export async function promptUrls() {
|
311
|
+
const homepage = await input({
|
312
|
+
message: "Homepage URL (optional):",
|
313
|
+
validate: (value) => {
|
314
|
+
if (!value.trim())
|
315
|
+
return true;
|
316
|
+
try {
|
317
|
+
new URL(value);
|
318
|
+
return true;
|
319
|
+
}
|
320
|
+
catch {
|
321
|
+
return "Must be a valid URL (e.g., https://example.com)";
|
322
|
+
}
|
323
|
+
},
|
324
|
+
});
|
325
|
+
const documentation = await input({
|
326
|
+
message: "Documentation URL (optional):",
|
327
|
+
validate: (value) => {
|
328
|
+
if (!value.trim())
|
329
|
+
return true;
|
330
|
+
try {
|
331
|
+
new URL(value);
|
332
|
+
return true;
|
333
|
+
}
|
334
|
+
catch {
|
335
|
+
return "Must be a valid URL";
|
336
|
+
}
|
337
|
+
},
|
338
|
+
});
|
339
|
+
const support = await input({
|
340
|
+
message: "Support URL (optional):",
|
341
|
+
validate: (value) => {
|
342
|
+
if (!value.trim())
|
343
|
+
return true;
|
344
|
+
try {
|
345
|
+
new URL(value);
|
346
|
+
return true;
|
347
|
+
}
|
348
|
+
catch {
|
349
|
+
return "Must be a valid URL";
|
350
|
+
}
|
351
|
+
},
|
352
|
+
});
|
353
|
+
return { homepage, documentation, support };
|
354
|
+
}
|
355
|
+
export async function promptVisualAssets() {
|
356
|
+
const icon = await input({
|
357
|
+
message: "Icon file path (optional, relative to manifest):",
|
358
|
+
validate: (value) => {
|
359
|
+
if (!value.trim())
|
360
|
+
return true;
|
361
|
+
if (value.includes(".."))
|
362
|
+
return "Relative paths cannot include '..'";
|
363
|
+
return true;
|
364
|
+
},
|
365
|
+
});
|
366
|
+
const addScreenshots = await confirm({
|
367
|
+
message: "Add screenshots?",
|
368
|
+
default: false,
|
369
|
+
});
|
370
|
+
const screenshots = [];
|
371
|
+
if (addScreenshots) {
|
372
|
+
let addMore = true;
|
373
|
+
while (addMore) {
|
374
|
+
const screenshot = await input({
|
375
|
+
message: "Screenshot file path (relative to manifest):",
|
376
|
+
validate: (value) => {
|
377
|
+
if (!value.trim())
|
378
|
+
return "Screenshot path is required";
|
379
|
+
if (value.includes(".."))
|
380
|
+
return "Relative paths cannot include '..'";
|
381
|
+
return true;
|
382
|
+
},
|
383
|
+
});
|
384
|
+
screenshots.push(screenshot);
|
385
|
+
addMore = await confirm({
|
386
|
+
message: "Add another screenshot?",
|
387
|
+
default: false,
|
388
|
+
});
|
389
|
+
}
|
390
|
+
}
|
391
|
+
return { icon, screenshots };
|
392
|
+
}
|
393
|
+
export async function promptCompatibility(serverType) {
|
394
|
+
const addCompatibility = await confirm({
|
395
|
+
message: "Add compatibility constraints?",
|
396
|
+
default: false,
|
397
|
+
});
|
398
|
+
if (!addCompatibility) {
|
399
|
+
return undefined;
|
400
|
+
}
|
401
|
+
const addPlatforms = await confirm({
|
402
|
+
message: "Specify supported platforms?",
|
403
|
+
default: false,
|
404
|
+
});
|
405
|
+
let platforms;
|
406
|
+
if (addPlatforms) {
|
407
|
+
const selectedPlatforms = [];
|
408
|
+
const supportsDarwin = await confirm({
|
409
|
+
message: "Support macOS (darwin)?",
|
410
|
+
default: true,
|
411
|
+
});
|
412
|
+
if (supportsDarwin)
|
413
|
+
selectedPlatforms.push("darwin");
|
414
|
+
const supportsWin32 = await confirm({
|
415
|
+
message: "Support Windows (win32)?",
|
416
|
+
default: true,
|
417
|
+
});
|
418
|
+
if (supportsWin32)
|
419
|
+
selectedPlatforms.push("win32");
|
420
|
+
const supportsLinux = await confirm({
|
421
|
+
message: "Support Linux?",
|
422
|
+
default: true,
|
423
|
+
});
|
424
|
+
if (supportsLinux)
|
425
|
+
selectedPlatforms.push("linux");
|
426
|
+
platforms = selectedPlatforms.length > 0 ? selectedPlatforms : undefined;
|
427
|
+
}
|
428
|
+
let runtimes;
|
429
|
+
if (serverType !== "binary") {
|
430
|
+
const addRuntimes = await confirm({
|
431
|
+
message: "Specify runtime version constraints?",
|
432
|
+
default: false,
|
433
|
+
});
|
434
|
+
if (addRuntimes) {
|
435
|
+
if (serverType === "python") {
|
436
|
+
const pythonVersion = await input({
|
437
|
+
message: "Python version constraint (e.g., >=3.8,<4.0):",
|
438
|
+
validate: (value) => value.trim().length > 0 || "Python version constraint is required",
|
439
|
+
});
|
440
|
+
runtimes = { python: pythonVersion };
|
441
|
+
}
|
442
|
+
else if (serverType === "node") {
|
443
|
+
const nodeVersion = await input({
|
444
|
+
message: "Node.js version constraint (e.g., >=16.0.0):",
|
445
|
+
validate: (value) => value.trim().length > 0 || "Node.js version constraint is required",
|
446
|
+
});
|
447
|
+
runtimes = { node: nodeVersion };
|
448
|
+
}
|
449
|
+
}
|
450
|
+
}
|
451
|
+
return {
|
452
|
+
...(platforms ? { platforms } : {}),
|
453
|
+
...(runtimes ? { runtimes } : {}),
|
454
|
+
};
|
455
|
+
}
|
456
|
+
export async function promptUserConfig() {
|
457
|
+
const addUserConfig = await confirm({
|
458
|
+
message: "Add user-configurable options?",
|
459
|
+
default: false,
|
460
|
+
});
|
461
|
+
if (!addUserConfig) {
|
462
|
+
return {};
|
463
|
+
}
|
464
|
+
const userConfig = {};
|
465
|
+
let addMore = true;
|
466
|
+
while (addMore) {
|
467
|
+
const optionKey = await input({
|
468
|
+
message: "Configuration option key (unique identifier):",
|
469
|
+
validate: (value) => {
|
470
|
+
if (!value.trim())
|
471
|
+
return "Key is required";
|
472
|
+
if (userConfig[value])
|
473
|
+
return "Key must be unique";
|
474
|
+
return true;
|
475
|
+
},
|
476
|
+
});
|
477
|
+
const optionType = (await select({
|
478
|
+
message: "Option type:",
|
479
|
+
choices: [
|
480
|
+
{ name: "String", value: "string" },
|
481
|
+
{ name: "Number", value: "number" },
|
482
|
+
{ name: "Boolean", value: "boolean" },
|
483
|
+
{ name: "Directory", value: "directory" },
|
484
|
+
{ name: "File", value: "file" },
|
485
|
+
],
|
486
|
+
}));
|
487
|
+
const optionTitle = await input({
|
488
|
+
message: "Option title (human-readable name):",
|
489
|
+
validate: (value) => value.trim().length > 0 || "Title is required",
|
490
|
+
});
|
491
|
+
const optionDescription = await input({
|
492
|
+
message: "Option description:",
|
493
|
+
validate: (value) => value.trim().length > 0 || "Description is required",
|
494
|
+
});
|
495
|
+
const optionRequired = await confirm({
|
496
|
+
message: "Is this option required?",
|
497
|
+
default: false,
|
498
|
+
});
|
499
|
+
const optionSensitive = await confirm({
|
500
|
+
message: "Is this option sensitive (like a password)?",
|
501
|
+
default: false,
|
502
|
+
});
|
503
|
+
// Build the option object
|
504
|
+
const option = {
|
505
|
+
type: optionType,
|
506
|
+
title: optionTitle,
|
507
|
+
description: optionDescription,
|
508
|
+
required: optionRequired,
|
509
|
+
sensitive: optionSensitive,
|
510
|
+
};
|
511
|
+
// Add default value if not required
|
512
|
+
if (!optionRequired) {
|
513
|
+
let defaultValue;
|
514
|
+
if (optionType === "boolean") {
|
515
|
+
defaultValue = await confirm({
|
516
|
+
message: "Default value:",
|
517
|
+
default: false,
|
518
|
+
});
|
519
|
+
}
|
520
|
+
else if (optionType === "number") {
|
521
|
+
const defaultStr = await input({
|
522
|
+
message: "Default value (number):",
|
523
|
+
validate: (value) => {
|
524
|
+
if (!value.trim())
|
525
|
+
return true;
|
526
|
+
return !isNaN(Number(value)) || "Must be a valid number";
|
527
|
+
},
|
528
|
+
});
|
529
|
+
defaultValue = defaultStr ? Number(defaultStr) : undefined;
|
530
|
+
}
|
531
|
+
else {
|
532
|
+
defaultValue = await input({
|
533
|
+
message: "Default value (optional):",
|
534
|
+
});
|
535
|
+
}
|
536
|
+
if (defaultValue !== undefined && defaultValue !== "") {
|
537
|
+
option.default = defaultValue;
|
538
|
+
}
|
539
|
+
}
|
540
|
+
// Add constraints for number types
|
541
|
+
if (optionType === "number") {
|
542
|
+
const addConstraints = await confirm({
|
543
|
+
message: "Add min/max constraints?",
|
544
|
+
default: false,
|
545
|
+
});
|
546
|
+
if (addConstraints) {
|
547
|
+
const min = await input({
|
548
|
+
message: "Minimum value (optional):",
|
549
|
+
validate: (value) => {
|
550
|
+
if (!value.trim())
|
551
|
+
return true;
|
552
|
+
return !isNaN(Number(value)) || "Must be a valid number";
|
553
|
+
},
|
554
|
+
});
|
555
|
+
const max = await input({
|
556
|
+
message: "Maximum value (optional):",
|
557
|
+
validate: (value) => {
|
558
|
+
if (!value.trim())
|
559
|
+
return true;
|
560
|
+
return !isNaN(Number(value)) || "Must be a valid number";
|
561
|
+
},
|
562
|
+
});
|
563
|
+
if (min)
|
564
|
+
option.min = Number(min);
|
565
|
+
if (max)
|
566
|
+
option.max = Number(max);
|
567
|
+
}
|
568
|
+
}
|
569
|
+
userConfig[optionKey] = option;
|
570
|
+
addMore = await confirm({
|
571
|
+
message: "Add another configuration option?",
|
572
|
+
default: false,
|
573
|
+
});
|
574
|
+
}
|
575
|
+
return userConfig;
|
576
|
+
}
|
577
|
+
export function buildManifest(basicInfo, longDescription, authorInfo, urls, visualAssets, serverConfig, tools, toolsGenerated, prompts, promptsGenerated, compatibility, userConfig, optionalFields) {
|
578
|
+
const { name, displayName, version, description, authorName } = basicInfo;
|
579
|
+
const { authorEmail, authorUrl } = authorInfo;
|
580
|
+
const { serverType, entryPoint, mcp_config } = serverConfig;
|
581
|
+
const { keywords, license, repository } = optionalFields;
|
582
|
+
return {
|
583
|
+
dxt_version: "0.1",
|
584
|
+
name,
|
585
|
+
...(displayName && displayName !== name
|
586
|
+
? { display_name: displayName }
|
587
|
+
: {}),
|
588
|
+
version,
|
589
|
+
description,
|
590
|
+
...(longDescription ? { long_description: longDescription } : {}),
|
591
|
+
author: {
|
592
|
+
name: authorName,
|
593
|
+
...(authorEmail ? { email: authorEmail } : {}),
|
594
|
+
...(authorUrl ? { url: authorUrl } : {}),
|
595
|
+
},
|
596
|
+
...(urls.homepage ? { homepage: urls.homepage } : {}),
|
597
|
+
...(urls.documentation ? { documentation: urls.documentation } : {}),
|
598
|
+
...(urls.support ? { support: urls.support } : {}),
|
599
|
+
...(visualAssets.icon ? { icon: visualAssets.icon } : {}),
|
600
|
+
...(visualAssets.screenshots.length > 0
|
601
|
+
? { screenshots: visualAssets.screenshots }
|
602
|
+
: {}),
|
603
|
+
server: {
|
604
|
+
type: serverType,
|
605
|
+
entry_point: entryPoint,
|
606
|
+
mcp_config,
|
607
|
+
},
|
608
|
+
...(tools.length > 0 ? { tools } : {}),
|
609
|
+
...(toolsGenerated ? { tools_generated: true } : {}),
|
610
|
+
...(prompts.length > 0 ? { prompts } : {}),
|
611
|
+
...(promptsGenerated ? { prompts_generated: true } : {}),
|
612
|
+
...(compatibility ? { compatibility } : {}),
|
613
|
+
...(Object.keys(userConfig).length > 0 ? { user_config: userConfig } : {}),
|
614
|
+
...(keywords
|
615
|
+
? {
|
616
|
+
keywords: keywords
|
617
|
+
.split(",")
|
618
|
+
.map((k) => k.trim())
|
619
|
+
.filter((k) => k),
|
620
|
+
}
|
621
|
+
: {}),
|
622
|
+
...(license ? { license } : {}),
|
623
|
+
...(repository ? { repository } : {}),
|
624
|
+
};
|
625
|
+
}
|
626
|
+
export function printNextSteps() {
|
627
|
+
console.log("\nNext steps:");
|
628
|
+
console.log(`1. Ensure all your production dependencies are in this directory`);
|
629
|
+
console.log(`2. Run 'dxt pack' to create your .dxt file`);
|
630
|
+
}
|
631
|
+
export async function initExtension(targetPath = process.cwd(), nonInteractive = false) {
|
632
|
+
const resolvedPath = resolve(targetPath);
|
633
|
+
const manifestPath = join(resolvedPath, "manifest.json");
|
634
|
+
if (existsSync(manifestPath)) {
|
635
|
+
if (nonInteractive) {
|
636
|
+
console.log("manifest.json already exists. Use --force to overwrite in non-interactive mode.");
|
637
|
+
return false;
|
638
|
+
}
|
639
|
+
const overwrite = await confirm({
|
640
|
+
message: "manifest.json already exists. Overwrite?",
|
641
|
+
default: false,
|
642
|
+
});
|
643
|
+
if (!overwrite) {
|
644
|
+
console.log("Cancelled");
|
645
|
+
return false;
|
646
|
+
}
|
647
|
+
}
|
648
|
+
if (!nonInteractive) {
|
649
|
+
console.log("This utility will help you create a manifest.json file for your DXT extension.");
|
650
|
+
console.log("Press ^C at any time to quit.\n");
|
651
|
+
}
|
652
|
+
else {
|
653
|
+
console.log("Creating manifest.json with default values...");
|
654
|
+
}
|
655
|
+
try {
|
656
|
+
const packageData = readPackageJson(resolvedPath);
|
657
|
+
// Prompt for all information or use defaults
|
658
|
+
const basicInfo = nonInteractive
|
659
|
+
? getDefaultBasicInfo(packageData, resolvedPath)
|
660
|
+
: await promptBasicInfo(packageData, resolvedPath);
|
661
|
+
const longDescription = nonInteractive
|
662
|
+
? undefined
|
663
|
+
: await promptLongDescription(basicInfo.description);
|
664
|
+
const authorInfo = nonInteractive
|
665
|
+
? getDefaultAuthorInfo(packageData)
|
666
|
+
: await promptAuthorInfo(packageData);
|
667
|
+
const urls = nonInteractive
|
668
|
+
? { homepage: "", documentation: "", support: "" }
|
669
|
+
: await promptUrls();
|
670
|
+
const visualAssets = nonInteractive
|
671
|
+
? { icon: "", screenshots: [] }
|
672
|
+
: await promptVisualAssets();
|
673
|
+
const serverConfig = nonInteractive
|
674
|
+
? getDefaultServerConfig(packageData)
|
675
|
+
: await promptServerConfig(packageData);
|
676
|
+
const toolsData = nonInteractive
|
677
|
+
? { tools: [], toolsGenerated: false }
|
678
|
+
: await promptTools();
|
679
|
+
const promptsData = nonInteractive
|
680
|
+
? { prompts: [], promptsGenerated: false }
|
681
|
+
: await promptPrompts();
|
682
|
+
const compatibility = nonInteractive
|
683
|
+
? undefined
|
684
|
+
: await promptCompatibility(serverConfig.serverType);
|
685
|
+
const userConfig = nonInteractive ? {} : await promptUserConfig();
|
686
|
+
const optionalFields = nonInteractive
|
687
|
+
? getDefaultOptionalFields(packageData)
|
688
|
+
: await promptOptionalFields(packageData);
|
689
|
+
// Build manifest
|
690
|
+
const manifest = buildManifest(basicInfo, longDescription, authorInfo, urls, visualAssets, serverConfig, toolsData.tools, toolsData.toolsGenerated, promptsData.prompts, promptsData.promptsGenerated, compatibility, userConfig, optionalFields);
|
691
|
+
// Write manifest
|
692
|
+
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
693
|
+
console.log(`\nCreated manifest.json at ${manifestPath}`);
|
694
|
+
printNextSteps();
|
695
|
+
return true;
|
696
|
+
}
|
697
|
+
catch (error) {
|
698
|
+
if (error instanceof Error && error.message.includes("User force closed")) {
|
699
|
+
console.log("\nCancelled");
|
700
|
+
return false;
|
701
|
+
}
|
702
|
+
throw error;
|
703
|
+
}
|
704
|
+
}
|