@alcyone-labs/arg-parser 2.2.1 → 2.3.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/README.md +146 -20
- package/dist/assets/.dxtignore.template +0 -1
- package/dist/core/ArgParserBase.d.ts.map +1 -1
- package/dist/dxt/DxtGenerator-testUtils.d.ts +22 -0
- package/dist/dxt/DxtGenerator-testUtils.d.ts.map +1 -0
- package/dist/dxt/DxtGenerator.d.ts +9 -67
- package/dist/dxt/DxtGenerator.d.ts.map +1 -1
- package/dist/index.cjs +367 -1382
- package/dist/index.cjs.map +1 -1
- package/dist/index.min.mjs +6059 -6986
- package/dist/index.min.mjs.map +1 -1
- package/dist/index.mjs +367 -1382
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -3
- package/dist/assets/tsdown.dxt.config.ts +0 -37
package/dist/index.cjs
CHANGED
|
@@ -1238,86 +1238,22 @@ function createOutputSchema(pattern2) {
|
|
|
1238
1238
|
}
|
|
1239
1239
|
return OutputSchemaPatterns.successError();
|
|
1240
1240
|
}
|
|
1241
|
-
class
|
|
1242
|
-
constructor(argParserInstance) {
|
|
1241
|
+
class DxtGeneratorTestUtils {
|
|
1242
|
+
constructor(argParserInstance, extractMcpServerInfo, handleExit) {
|
|
1243
1243
|
this.argParserInstance = argParserInstance;
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
* Helper method to handle exit logic based on autoExit setting
|
|
1247
|
-
*/
|
|
1248
|
-
_handleExit(exitCode, message, type2, data2) {
|
|
1249
|
-
const result = {
|
|
1250
|
-
success: exitCode === 0,
|
|
1251
|
-
exitCode,
|
|
1252
|
-
message,
|
|
1253
|
-
type: type2 || (exitCode === 0 ? "success" : "error"),
|
|
1254
|
-
shouldExit: true,
|
|
1255
|
-
data: data2
|
|
1256
|
-
};
|
|
1257
|
-
if (this.argParserInstance.getAutoExit() && typeof process === "object" && typeof process.exit === "function") {
|
|
1258
|
-
process.exit(exitCode);
|
|
1259
|
-
}
|
|
1260
|
-
return result;
|
|
1261
|
-
}
|
|
1262
|
-
/**
|
|
1263
|
-
* Handles the --s-build-dxt system flag to generate DXT packages for MCP servers
|
|
1264
|
-
*/
|
|
1265
|
-
async handleBuildDxtFlag(processArgs, buildDxtIndex) {
|
|
1266
|
-
var _a, _b, _c;
|
|
1267
|
-
try {
|
|
1268
|
-
const isTestMode = process.env["NODE_ENV"] === "test" || ((_a = process.argv[0]) == null ? void 0 : _a.includes("vitest")) || ((_b = process.argv[1]) == null ? void 0 : _b.includes("vitest")) || ((_c = process.argv[1]) == null ? void 0 : _c.includes("tinypool"));
|
|
1269
|
-
if (isTestMode) {
|
|
1270
|
-
return await this.handleTestModeDxtGeneration(
|
|
1271
|
-
processArgs,
|
|
1272
|
-
buildDxtIndex
|
|
1273
|
-
);
|
|
1274
|
-
}
|
|
1275
|
-
const entryPointFile = process.argv[1];
|
|
1276
|
-
if (!entryPointFile || !fs__namespace.existsSync(entryPointFile)) {
|
|
1277
|
-
console.error(
|
|
1278
|
-
simpleChalk.red(`Error: Entry point file not found: ${entryPointFile}`)
|
|
1279
|
-
);
|
|
1280
|
-
return this._handleExit(1, "Entry point file not found", "error");
|
|
1281
|
-
}
|
|
1282
|
-
const outputDir = processArgs[buildDxtIndex + 1] || "./dxt";
|
|
1283
|
-
console.log(
|
|
1284
|
-
simpleChalk.cyan(
|
|
1285
|
-
`
|
|
1286
|
-
🔧 Building DXT package for entry point: ${path__namespace.basename(entryPointFile)}`
|
|
1287
|
-
)
|
|
1288
|
-
);
|
|
1289
|
-
console.log(simpleChalk.gray(`Output directory: ${outputDir}`));
|
|
1290
|
-
await this.buildDxtWithTsdown(entryPointFile, outputDir);
|
|
1291
|
-
console.log(simpleChalk.green(`
|
|
1292
|
-
✅ DXT package generation completed!`));
|
|
1293
|
-
return this._handleExit(
|
|
1294
|
-
0,
|
|
1295
|
-
"DXT package generation completed",
|
|
1296
|
-
"success",
|
|
1297
|
-
{ entryPoint: entryPointFile, outputDir }
|
|
1298
|
-
);
|
|
1299
|
-
} catch (error) {
|
|
1300
|
-
console.error(
|
|
1301
|
-
simpleChalk.red(
|
|
1302
|
-
`Error generating DXT package: ${error instanceof Error ? error.message : String(error)}`
|
|
1303
|
-
)
|
|
1304
|
-
);
|
|
1305
|
-
return this._handleExit(
|
|
1306
|
-
1,
|
|
1307
|
-
`Error generating DXT package: ${error instanceof Error ? error.message : String(error)}`,
|
|
1308
|
-
"error"
|
|
1309
|
-
);
|
|
1310
|
-
}
|
|
1244
|
+
this.extractMcpServerInfo = extractMcpServerInfo;
|
|
1245
|
+
this.handleExit = handleExit;
|
|
1311
1246
|
}
|
|
1312
1247
|
/**
|
|
1313
1248
|
* Handles DXT generation in test mode by creating mock DXT package structure
|
|
1249
|
+
* This method creates simplified mock files for testing purposes
|
|
1314
1250
|
*/
|
|
1315
1251
|
async handleTestModeDxtGeneration(processArgs, buildDxtIndex) {
|
|
1316
1252
|
try {
|
|
1317
1253
|
const outputDir = processArgs[buildDxtIndex + 1] || "./dxt-packages";
|
|
1318
1254
|
const mcpTools = this.argParserInstance.toMcpTools();
|
|
1319
1255
|
if (mcpTools.length === 0) {
|
|
1320
|
-
return this.
|
|
1256
|
+
return this.handleExit(0, "No MCP servers found", "success");
|
|
1321
1257
|
}
|
|
1322
1258
|
const serverInfo = this.extractMcpServerInfo();
|
|
1323
1259
|
const folderName = `${serverInfo.name.replace(/[^a-zA-Z0-9_-]/g, "_")}-dxt`;
|
|
@@ -1373,17 +1309,12 @@ echo "Mock DXT build script for ${serverInfo.name}"`;
|
|
|
1373
1309
|
path__namespace.join(buildDir, "build-dxt-package.sh"),
|
|
1374
1310
|
buildScript
|
|
1375
1311
|
);
|
|
1376
|
-
return this.
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
{
|
|
1381
|
-
entryPoint: "test-mode",
|
|
1382
|
-
outputDir: buildDir
|
|
1383
|
-
}
|
|
1384
|
-
);
|
|
1312
|
+
return this.handleExit(0, "DXT package generation completed", "success", {
|
|
1313
|
+
entryPoint: "test-mode",
|
|
1314
|
+
outputDir: buildDir
|
|
1315
|
+
});
|
|
1385
1316
|
} catch (error) {
|
|
1386
|
-
return this.
|
|
1317
|
+
return this.handleExit(
|
|
1387
1318
|
1,
|
|
1388
1319
|
`Test mode DXT generation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
1389
1320
|
"error"
|
|
@@ -1391,96 +1322,155 @@ echo "Mock DXT build script for ${serverInfo.name}"`;
|
|
|
1391
1322
|
}
|
|
1392
1323
|
}
|
|
1393
1324
|
/**
|
|
1394
|
-
*
|
|
1395
|
-
*
|
|
1325
|
+
* Checks if the current environment is in test mode
|
|
1326
|
+
* Used to determine whether to use test utilities or production code
|
|
1396
1327
|
*/
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
const
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
JSON.stringify(manifest, null, 2)
|
|
1421
|
-
);
|
|
1422
|
-
this.addOriginalCliToFolder(buildDir);
|
|
1423
|
-
const bundledCliPath = await this.bundleOriginalCliWithTsdown(serverDir);
|
|
1424
|
-
const serverScript = this.createServerScript(serverInfo, bundledCliPath);
|
|
1425
|
-
const serverScriptPath = path__namespace.join(serverDir, "index.mjs");
|
|
1426
|
-
fs__namespace.writeFileSync(serverScriptPath, serverScript);
|
|
1427
|
-
try {
|
|
1428
|
-
fs__namespace.chmodSync(serverScriptPath, 493);
|
|
1429
|
-
} catch (error) {
|
|
1430
|
-
console.warn(
|
|
1431
|
-
"⚠ Could not set executable permission on server script:",
|
|
1432
|
-
error instanceof Error ? error.message : String(error)
|
|
1433
|
-
);
|
|
1434
|
-
}
|
|
1435
|
-
const packageJson = this.createDxtPackageJson(serverInfo);
|
|
1436
|
-
fs__namespace.writeFileSync(
|
|
1437
|
-
path__namespace.join(buildDir, "package.json"),
|
|
1438
|
-
JSON.stringify(packageJson, null, 2)
|
|
1439
|
-
);
|
|
1440
|
-
const readme = this.createDxtReadme(serverInfo);
|
|
1441
|
-
fs__namespace.writeFileSync(path__namespace.join(buildDir, "README.md"), readme);
|
|
1442
|
-
const buildScript = this.createSimpleBuildScript(serverInfo);
|
|
1443
|
-
fs__namespace.writeFileSync(path__namespace.join(buildDir, "build-dxt.sh"), buildScript);
|
|
1444
|
-
const dxtIgnore = this.createDxtIgnore();
|
|
1445
|
-
fs__namespace.writeFileSync(path__namespace.join(buildDir, ".dxtignore"), dxtIgnore);
|
|
1446
|
-
try {
|
|
1447
|
-
fs__namespace.chmodSync(path__namespace.join(buildDir, "build-dxt.sh"), 493);
|
|
1448
|
-
} catch (error) {
|
|
1328
|
+
static isTestMode() {
|
|
1329
|
+
var _a, _b, _c;
|
|
1330
|
+
return process.env["NODE_ENV"] === "test" || ((_a = process.argv[0]) == null ? void 0 : _a.includes("vitest")) || ((_b = process.argv[1]) == null ? void 0 : _b.includes("vitest")) || ((_c = process.argv[1]) == null ? void 0 : _c.includes("tinypool"));
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
class DxtGenerator {
|
|
1334
|
+
constructor(argParserInstance) {
|
|
1335
|
+
this.argParserInstance = argParserInstance;
|
|
1336
|
+
}
|
|
1337
|
+
/**
|
|
1338
|
+
* Helper method to handle exit logic based on autoExit setting
|
|
1339
|
+
*/
|
|
1340
|
+
_handleExit(exitCode, message, type2, data2) {
|
|
1341
|
+
const result = {
|
|
1342
|
+
success: exitCode === 0,
|
|
1343
|
+
exitCode,
|
|
1344
|
+
message,
|
|
1345
|
+
type: type2 || (exitCode === 0 ? "success" : "error"),
|
|
1346
|
+
shouldExit: true,
|
|
1347
|
+
data: data2
|
|
1348
|
+
};
|
|
1349
|
+
if (this.argParserInstance.getAutoExit() && typeof process === "object" && typeof process.exit === "function") {
|
|
1350
|
+
process.exit(exitCode);
|
|
1449
1351
|
}
|
|
1450
|
-
|
|
1451
|
-
console.log(
|
|
1452
|
-
simpleChalk.gray(` Server: ${serverInfo.name} v${serverInfo.version}`)
|
|
1453
|
-
);
|
|
1454
|
-
console.log(simpleChalk.gray(` Tools: ${tools.length} tool(s)`));
|
|
1455
|
-
console.log(simpleChalk.gray(` Location: ${buildDir}`));
|
|
1456
|
-
console.log(
|
|
1457
|
-
simpleChalk.cyan(`
|
|
1458
|
-
📦 Creating DXT package using Anthropic's dxt pack...`)
|
|
1459
|
-
);
|
|
1460
|
-
console.log(simpleChalk.cyan(`
|
|
1461
|
-
📋 Manual steps to create your DXT package:`));
|
|
1462
|
-
console.log(simpleChalk.white(` cd ${path__namespace.relative(process.cwd(), buildDir)}`));
|
|
1463
|
-
console.log(simpleChalk.white(` ./build-dxt.sh`));
|
|
1352
|
+
return result;
|
|
1464
1353
|
}
|
|
1465
1354
|
/**
|
|
1466
|
-
*
|
|
1355
|
+
* Handles the --s-build-dxt system flag to generate DXT packages for MCP servers
|
|
1467
1356
|
*/
|
|
1468
|
-
|
|
1357
|
+
async handleBuildDxtFlag(processArgs, buildDxtIndex) {
|
|
1469
1358
|
try {
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1359
|
+
if (DxtGeneratorTestUtils.isTestMode()) {
|
|
1360
|
+
const testUtils = new DxtGeneratorTestUtils(
|
|
1361
|
+
this.argParserInstance,
|
|
1362
|
+
() => this.extractMcpServerInfo(),
|
|
1363
|
+
(exitCode, message, type2, data2) => this._handleExit(exitCode, message, type2, data2)
|
|
1364
|
+
);
|
|
1365
|
+
return await testUtils.handleTestModeDxtGeneration(
|
|
1366
|
+
processArgs,
|
|
1367
|
+
buildDxtIndex
|
|
1368
|
+
);
|
|
1369
|
+
}
|
|
1370
|
+
const withNodeModules = processArgs.includes("--s-with-node-modules");
|
|
1371
|
+
if (withNodeModules) {
|
|
1372
|
+
console.log(
|
|
1373
|
+
simpleChalk.yellow(
|
|
1374
|
+
"🗂️ --s-with-node-modules detected: will include node_modules in bundle"
|
|
1375
|
+
)
|
|
1376
|
+
);
|
|
1377
|
+
const nodeModulesPath = path__namespace.resolve("./node_modules");
|
|
1378
|
+
if (!fs__namespace.existsSync(nodeModulesPath)) {
|
|
1379
|
+
console.error(
|
|
1380
|
+
simpleChalk.red(
|
|
1381
|
+
"❌ Error: node_modules directory not found. Please run the installation command first."
|
|
1382
|
+
)
|
|
1383
|
+
);
|
|
1384
|
+
console.log(
|
|
1385
|
+
simpleChalk.cyan(
|
|
1386
|
+
"💡 Required command: pnpm install --prod --node-linker=hoisted"
|
|
1387
|
+
)
|
|
1388
|
+
);
|
|
1389
|
+
return this._handleExit(
|
|
1390
|
+
1,
|
|
1391
|
+
"node_modules directory not found",
|
|
1392
|
+
"error"
|
|
1393
|
+
);
|
|
1394
|
+
}
|
|
1395
|
+
try {
|
|
1396
|
+
const nodeModulesContents = fs__namespace.readdirSync(nodeModulesPath);
|
|
1397
|
+
const hasNestedNodeModules = nodeModulesContents.filter((item) => !item.startsWith(".") && !item.startsWith("@")).some((item) => {
|
|
1398
|
+
const itemPath = path__namespace.join(nodeModulesPath, item);
|
|
1399
|
+
try {
|
|
1400
|
+
return fs__namespace.statSync(itemPath).isDirectory() && fs__namespace.existsSync(path__namespace.join(itemPath, "node_modules"));
|
|
1401
|
+
} catch {
|
|
1402
|
+
return false;
|
|
1403
|
+
}
|
|
1404
|
+
});
|
|
1405
|
+
if (hasNestedNodeModules) {
|
|
1406
|
+
console.warn(
|
|
1407
|
+
simpleChalk.yellow(
|
|
1408
|
+
"⚠️ Warning: Detected nested node_modules. For best results, ensure hoisted installation:"
|
|
1409
|
+
)
|
|
1410
|
+
);
|
|
1411
|
+
console.log(
|
|
1412
|
+
simpleChalk.cyan(
|
|
1413
|
+
" rm -rf node_modules && pnpm install --prod --node-linker=hoisted"
|
|
1414
|
+
)
|
|
1415
|
+
);
|
|
1416
|
+
} else {
|
|
1417
|
+
console.log(
|
|
1418
|
+
simpleChalk.green(
|
|
1419
|
+
"✅ node_modules appears properly hoisted and ready for bundling"
|
|
1420
|
+
)
|
|
1421
|
+
);
|
|
1422
|
+
}
|
|
1423
|
+
} catch (error) {
|
|
1424
|
+
console.warn(
|
|
1425
|
+
simpleChalk.yellow(
|
|
1426
|
+
`⚠️ Could not validate node_modules structure: ${error instanceof Error ? error.message : String(error)}`
|
|
1427
|
+
)
|
|
1428
|
+
);
|
|
1429
|
+
}
|
|
1430
|
+
console.log(
|
|
1431
|
+
simpleChalk.gray(
|
|
1432
|
+
"💡 This will create a fully autonomous DXT with all native dependencies included"
|
|
1433
|
+
)
|
|
1434
|
+
);
|
|
1480
1435
|
}
|
|
1436
|
+
const entryPointFile = process.argv[1];
|
|
1437
|
+
if (!entryPointFile || !fs__namespace.existsSync(entryPointFile)) {
|
|
1438
|
+
console.error(
|
|
1439
|
+
simpleChalk.red(`Error: Entry point file not found: ${entryPointFile}`)
|
|
1440
|
+
);
|
|
1441
|
+
return this._handleExit(1, "Entry point file not found", "error");
|
|
1442
|
+
}
|
|
1443
|
+
let outputDir = processArgs[buildDxtIndex + 1] || "./dxt";
|
|
1444
|
+
if (outputDir.startsWith("--s-")) outputDir = "./dxt";
|
|
1445
|
+
console.log(
|
|
1446
|
+
simpleChalk.cyan(
|
|
1447
|
+
`
|
|
1448
|
+
🔧 Building DXT package for entry point: ${entryPointFile}`
|
|
1449
|
+
)
|
|
1450
|
+
);
|
|
1451
|
+
console.log(simpleChalk.gray(`Output directory: ${outputDir}`));
|
|
1452
|
+
console.log(simpleChalk.gray(`Entrypoint file: ${entryPointFile}`));
|
|
1453
|
+
await this.buildDxtWithTsdown(entryPointFile, outputDir, withNodeModules);
|
|
1454
|
+
console.log(simpleChalk.green(`
|
|
1455
|
+
✅ DXT package generation completed!`));
|
|
1456
|
+
return this._handleExit(
|
|
1457
|
+
0,
|
|
1458
|
+
"DXT package generation completed",
|
|
1459
|
+
"success",
|
|
1460
|
+
{ entryPoint: entryPointFile, outputDir }
|
|
1461
|
+
);
|
|
1481
1462
|
} catch (error) {
|
|
1463
|
+
console.error(
|
|
1464
|
+
simpleChalk.red(
|
|
1465
|
+
`Error generating DXT package: ${error instanceof Error ? error.message : String(error)}`
|
|
1466
|
+
)
|
|
1467
|
+
);
|
|
1468
|
+
return this._handleExit(
|
|
1469
|
+
1,
|
|
1470
|
+
`Error generating DXT package: ${error instanceof Error ? error.message : String(error)}`,
|
|
1471
|
+
"error"
|
|
1472
|
+
);
|
|
1482
1473
|
}
|
|
1483
|
-
return null;
|
|
1484
1474
|
}
|
|
1485
1475
|
/**
|
|
1486
1476
|
* Extracts server information from MCP configuration
|
|
@@ -1565,518 +1555,9 @@ echo "Mock DXT build script for ${serverInfo.name}"`;
|
|
|
1565
1555
|
];
|
|
1566
1556
|
}
|
|
1567
1557
|
}
|
|
1568
|
-
createDxtManifest(serverInfo, tools, mcpSubCommand, logoFilename) {
|
|
1569
|
-
var _a;
|
|
1570
|
-
const packageInfo = this.readPackageJsonInfo();
|
|
1571
|
-
let author = serverInfo.author;
|
|
1572
|
-
if (!author && (packageInfo == null ? void 0 : packageInfo.author)) {
|
|
1573
|
-
if (typeof packageInfo.author === "string") {
|
|
1574
|
-
const match = packageInfo.author.match(/^([^<]+?)(?:\s*<([^>]+)>)?$/);
|
|
1575
|
-
if (match) {
|
|
1576
|
-
author = {
|
|
1577
|
-
name: match[1].trim(),
|
|
1578
|
-
email: (_a = match[2]) == null ? void 0 : _a.trim()
|
|
1579
|
-
};
|
|
1580
|
-
} else {
|
|
1581
|
-
author = { name: packageInfo.author };
|
|
1582
|
-
}
|
|
1583
|
-
} else {
|
|
1584
|
-
author = packageInfo.author;
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1587
|
-
if (!author) {
|
|
1588
|
-
throw new Error(
|
|
1589
|
-
"DXT manifest requires author information. Please provide it via withMcp() serverInfo.author, addMcpSubCommand serverInfo.author, or in package.json"
|
|
1590
|
-
);
|
|
1591
|
-
}
|
|
1592
|
-
const cliArgs = this.generateCliArgsForDxt(mcpSubCommand);
|
|
1593
|
-
const { envVars, userConfig } = this.generateEnvAndUserConfig();
|
|
1594
|
-
const manifest = {
|
|
1595
|
-
dxt_version: "0.1",
|
|
1596
|
-
name: serverInfo.name,
|
|
1597
|
-
version: serverInfo.version,
|
|
1598
|
-
description: serverInfo.description || "MCP server generated from ArgParser",
|
|
1599
|
-
author,
|
|
1600
|
-
server: {
|
|
1601
|
-
type: "node",
|
|
1602
|
-
entry_point: "server/index.mjs",
|
|
1603
|
-
mcp_config: {
|
|
1604
|
-
command: "node",
|
|
1605
|
-
args: ["${__dirname}/server/index.mjs", ...cliArgs],
|
|
1606
|
-
env: envVars
|
|
1607
|
-
}
|
|
1608
|
-
},
|
|
1609
|
-
tools: tools.map((tool) => ({
|
|
1610
|
-
name: tool.name,
|
|
1611
|
-
description: tool.description
|
|
1612
|
-
}))
|
|
1613
|
-
};
|
|
1614
|
-
if (logoFilename) {
|
|
1615
|
-
manifest.icon = logoFilename;
|
|
1616
|
-
}
|
|
1617
|
-
if (userConfig && Object.keys(userConfig).length > 0) {
|
|
1618
|
-
manifest.user_config = userConfig;
|
|
1619
|
-
}
|
|
1620
|
-
if (serverInfo.repository || (packageInfo == null ? void 0 : packageInfo.repository)) {
|
|
1621
|
-
manifest.repository = serverInfo.repository || (packageInfo == null ? void 0 : packageInfo.repository);
|
|
1622
|
-
}
|
|
1623
|
-
if (serverInfo.license || (packageInfo == null ? void 0 : packageInfo.license)) {
|
|
1624
|
-
manifest.license = serverInfo.license || (packageInfo == null ? void 0 : packageInfo.license);
|
|
1625
|
-
}
|
|
1626
|
-
if (serverInfo.homepage || (packageInfo == null ? void 0 : packageInfo.homepage)) {
|
|
1627
|
-
manifest.homepage = serverInfo.homepage || (packageInfo == null ? void 0 : packageInfo.homepage);
|
|
1628
|
-
}
|
|
1629
|
-
return manifest;
|
|
1630
|
-
}
|
|
1631
|
-
validateDxtManifest(manifest) {
|
|
1632
|
-
const errors = [];
|
|
1633
|
-
if (!manifest.dxt_version)
|
|
1634
|
-
errors.push("Missing required field: dxt_version");
|
|
1635
|
-
if (!manifest.name) errors.push("Missing required field: name");
|
|
1636
|
-
if (!manifest.version) errors.push("Missing required field: version");
|
|
1637
|
-
if (!manifest.server) errors.push("Missing required field: server");
|
|
1638
|
-
if (!manifest.author) errors.push("Missing required field: author");
|
|
1639
|
-
if (manifest.server) {
|
|
1640
|
-
if (!manifest.server.type)
|
|
1641
|
-
errors.push("Missing required field: server.type");
|
|
1642
|
-
if (!manifest.server.entry_point)
|
|
1643
|
-
errors.push("Missing required field: server.entry_point");
|
|
1644
|
-
if (!manifest.server.mcp_config)
|
|
1645
|
-
errors.push("Missing required field: server.mcp_config");
|
|
1646
|
-
if (manifest.server.mcp_config) {
|
|
1647
|
-
if (!manifest.server.mcp_config.command)
|
|
1648
|
-
errors.push("Missing required field: server.mcp_config.command");
|
|
1649
|
-
if (!manifest.server.mcp_config.args || !Array.isArray(manifest.server.mcp_config.args)) {
|
|
1650
|
-
errors.push(
|
|
1651
|
-
"Missing or invalid field: server.mcp_config.args (must be array)"
|
|
1652
|
-
);
|
|
1653
|
-
}
|
|
1654
|
-
}
|
|
1655
|
-
}
|
|
1656
|
-
if (manifest.author && typeof manifest.author === "object") {
|
|
1657
|
-
if (!manifest.author.name)
|
|
1658
|
-
errors.push("Missing required field: author.name");
|
|
1659
|
-
}
|
|
1660
|
-
if (manifest.dxt_version && manifest.dxt_version !== "0.1") {
|
|
1661
|
-
errors.push("Unsupported dxt_version: only '0.1' is currently supported");
|
|
1662
|
-
}
|
|
1663
|
-
if (errors.length > 0) {
|
|
1664
|
-
throw new Error(
|
|
1665
|
-
`DXT manifest validation failed:
|
|
1666
|
-
${errors.map((e) => ` - ${e}`).join("\n")}`
|
|
1667
|
-
);
|
|
1668
|
-
}
|
|
1669
|
-
}
|
|
1670
|
-
createServerScript(serverInfo, bundledCliPath) {
|
|
1671
|
-
const cliImportPath = bundledCliPath || "original-cli.mjs";
|
|
1672
|
-
return `#!/usr/bin/env node
|
|
1673
|
-
|
|
1674
|
-
// Generated MCP server for ${serverInfo.name}
|
|
1675
|
-
// This server uses @alcyone-labs/arg-parser's built-in MCP functionality for full protocol compliance
|
|
1676
|
-
|
|
1677
|
-
// FIRST: Set up MCP-safe logging to prevent STDOUT contamination
|
|
1678
|
-
import { createMcpLogger } from '@alcyone-labs/simple-mcp-logger';
|
|
1679
|
-
|
|
1680
|
-
// Auto-detect MCP mode and hijack console to prevent protocol corruption
|
|
1681
|
-
const mcpLogger = createMcpLogger('${serverInfo.name}');
|
|
1682
|
-
globalThis.console = mcpLogger;
|
|
1683
|
-
|
|
1684
|
-
// Now import the CLI which already has MCP functionality configured
|
|
1685
|
-
import originalCli from './${cliImportPath}';
|
|
1686
|
-
|
|
1687
|
-
// Server configuration
|
|
1688
|
-
const serverInfo = ${JSON.stringify(serverInfo, null, 2)};
|
|
1689
|
-
|
|
1690
|
-
// Use mcpError for debugging output (safe STDERR, visible in client logs)
|
|
1691
|
-
console.error(\`MCP Server: \${serverInfo.name} v\${serverInfo.version}\`);
|
|
1692
|
-
console.error(\`Description: \${serverInfo.description}\`);
|
|
1693
|
-
console.error(\`Generated from @alcyone-labs/arg-parser with built-in MCP functionality\`);
|
|
1694
|
-
${bundledCliPath ? "console.error(`Using bundled CLI for autonomous execution`);" : ""}
|
|
1695
|
-
|
|
1696
|
-
// The original CLI has MCP functionality configured via withMcp() or addMcpSubCommand()
|
|
1697
|
-
// We use the centralized --s-mcp-serve system flag to start the unified MCP server
|
|
1698
|
-
|
|
1699
|
-
// Start the MCP server using the library's built-in centralized serving
|
|
1700
|
-
// This works with both withMcp() configuration and legacy addMcpSubCommand() setups
|
|
1701
|
-
originalCli.parse(['--s-mcp-serve']);
|
|
1702
|
-
`;
|
|
1703
|
-
}
|
|
1704
|
-
createDxtPackageJson(serverInfo) {
|
|
1705
|
-
const useLocalBuild = process.env["LOCAL_BUILD"] === "1";
|
|
1706
|
-
const argParserDependency = useLocalBuild ? "file:../../arg-parser-local.tgz" : "^1.3.0";
|
|
1707
|
-
let originalDependencies = {};
|
|
1708
|
-
try {
|
|
1709
|
-
const originalPackageJsonPath = path__namespace.join(process.cwd(), "package.json");
|
|
1710
|
-
if (fs__namespace.existsSync(originalPackageJsonPath)) {
|
|
1711
|
-
const originalPackageJson = JSON.parse(
|
|
1712
|
-
fs__namespace.readFileSync(originalPackageJsonPath, "utf8")
|
|
1713
|
-
);
|
|
1714
|
-
originalDependencies = originalPackageJson.dependencies || {};
|
|
1715
|
-
}
|
|
1716
|
-
} catch (error) {
|
|
1717
|
-
console.warn(
|
|
1718
|
-
"⚠ Could not read original package.json for dependencies:",
|
|
1719
|
-
error instanceof Error ? error.message : String(error)
|
|
1720
|
-
);
|
|
1721
|
-
}
|
|
1722
|
-
const dependencies2 = {
|
|
1723
|
-
...originalDependencies,
|
|
1724
|
-
"@alcyone-labs/arg-parser": argParserDependency,
|
|
1725
|
-
"@alcyone-labs/simple-mcp-logger": "^1.0.0",
|
|
1726
|
-
"@modelcontextprotocol/sdk": "^1.15.0",
|
|
1727
|
-
zod: "^3.22.4"
|
|
1728
|
-
};
|
|
1729
|
-
const devDependencies = {
|
|
1730
|
-
tsup: "^8.3.5"
|
|
1731
|
-
};
|
|
1732
|
-
Object.keys(dependencies2).forEach((key) => {
|
|
1733
|
-
const depValue = dependencies2[key];
|
|
1734
|
-
if (key !== "@alcyone-labs/arg-parser" && typeof depValue === "string" && depValue.startsWith("file:")) {
|
|
1735
|
-
delete dependencies2[key];
|
|
1736
|
-
console.warn(
|
|
1737
|
-
`⚠ Removed file: dependency ${key} from DXT package (not suitable for distribution)`
|
|
1738
|
-
);
|
|
1739
|
-
}
|
|
1740
|
-
});
|
|
1741
|
-
return {
|
|
1742
|
-
name: serverInfo.name,
|
|
1743
|
-
version: serverInfo.version,
|
|
1744
|
-
description: serverInfo.description,
|
|
1745
|
-
main: "server/index.mjs",
|
|
1746
|
-
type: "module",
|
|
1747
|
-
scripts: {
|
|
1748
|
-
start: "node server/index.mjs",
|
|
1749
|
-
"build-dxt": "./build-dxt.sh"
|
|
1750
|
-
},
|
|
1751
|
-
dependencies: dependencies2,
|
|
1752
|
-
devDependencies,
|
|
1753
|
-
engines: {
|
|
1754
|
-
node: ">=22.0.0"
|
|
1755
|
-
},
|
|
1756
|
-
author: serverInfo.author,
|
|
1757
|
-
license: serverInfo.license || "MIT",
|
|
1758
|
-
repository: serverInfo.repository
|
|
1759
|
-
};
|
|
1760
|
-
}
|
|
1761
|
-
/**
|
|
1762
|
-
* Creates a .dxtignore file to exclude build artifacts and unnecessary files
|
|
1763
|
-
*/
|
|
1764
|
-
createDxtIgnore() {
|
|
1765
|
-
return `# DXT ignore file - exclude these files from the DXT package
|
|
1766
|
-
# Generated by @alcyone-labs/arg-parser
|
|
1767
|
-
|
|
1768
|
-
# Build artifacts and logs
|
|
1769
|
-
*.log
|
|
1770
|
-
*.tmp
|
|
1771
|
-
temp-dxt-build/
|
|
1772
|
-
|
|
1773
|
-
# Build scripts (not needed in final package)
|
|
1774
|
-
build-dxt.sh
|
|
1775
|
-
arg-parser-local.tgz
|
|
1776
|
-
tsup.config.autonomous.js
|
|
1777
|
-
tsdown.config.mjs
|
|
1778
|
-
|
|
1779
|
-
# Original files (replaced by bundled autonomous build)
|
|
1780
|
-
server/index.original.mjs
|
|
1781
|
-
server/*.autonomous.mjs
|
|
1782
|
-
|
|
1783
|
-
# NOTE: server/original-cli.mjs is NOT excluded because it's needed for the MCP server to function
|
|
1784
|
-
# The bundled version (if created) will be server/original-cli.bundled.mjs
|
|
1785
|
-
|
|
1786
|
-
# NOTE: node_modules/ is NOT excluded because TSDown bundling may not be 100% autonomous
|
|
1787
|
-
# If bundling is successful, node_modules won't be needed, but we include it as fallback
|
|
1788
|
-
# The bundled server/index.mjs should be fully autonomous and not require node_modules
|
|
1789
|
-
|
|
1790
|
-
# Development files
|
|
1791
|
-
.git/
|
|
1792
|
-
.gitignore
|
|
1793
|
-
.env
|
|
1794
|
-
.env.*
|
|
1795
|
-
|
|
1796
|
-
# OS files
|
|
1797
|
-
.DS_Store
|
|
1798
|
-
Thumbs.db
|
|
1799
|
-
|
|
1800
|
-
# IDE files
|
|
1801
|
-
.vscode/
|
|
1802
|
-
.idea/
|
|
1803
|
-
*.swp
|
|
1804
|
-
*.swo
|
|
1805
|
-
`;
|
|
1806
|
-
}
|
|
1807
|
-
/**
|
|
1808
|
-
* Creates a simple build script that uses TSDown bundling and Anthropic's dxt pack
|
|
1809
|
-
*/
|
|
1810
|
-
createSimpleBuildScript(serverInfo) {
|
|
1811
|
-
return `#!/bin/bash
|
|
1812
|
-
|
|
1813
|
-
# Simple DXT Build Script for ${serverInfo.name}
|
|
1814
|
-
# Generated by @alcyone-labs/arg-parser with TSDown bundling
|
|
1815
|
-
|
|
1816
|
-
set -e
|
|
1817
|
-
|
|
1818
|
-
echo "📦 Creating DXT package for ${serverInfo.name}..."
|
|
1819
|
-
|
|
1820
|
-
# Step 1: Make server executable (required for MCP)
|
|
1821
|
-
echo "🔧 Making server executable..."
|
|
1822
|
-
chmod +x server/index.mjs
|
|
1823
|
-
|
|
1824
|
-
# Step 2: Handle local development dependencies
|
|
1825
|
-
if grep -q "file:.*arg-parser-local.tgz" package.json; then
|
|
1826
|
-
echo "🔧 Checking for local package tarball..."
|
|
1827
|
-
|
|
1828
|
-
# Check if the tarball exists in the parent directory
|
|
1829
|
-
if [ -f "../../arg-parser-local.tgz" ]; then
|
|
1830
|
-
echo "✅ Found local package tarball: ../../arg-parser-local.tgz"
|
|
1831
|
-
else
|
|
1832
|
-
echo "⚠️ Local tarball not found, falling back to npm registry"
|
|
1833
|
-
echo "💡 To use local build, run: cd /path/to/arg-parser && npm pack && cp *.tgz examples/community/canny-cli/"
|
|
1834
|
-
|
|
1835
|
-
# Replace with npm version
|
|
1836
|
-
sed -i.bak 's|"file:.*arg-parser-local.tgz"|"^1.3.0"|g' package.json 2>/dev/null || \\
|
|
1837
|
-
sed -i 's|"file:.*arg-parser-local.tgz"|"^1.3.0"|g' package.json
|
|
1838
|
-
fi
|
|
1839
|
-
fi
|
|
1840
|
-
|
|
1841
|
-
# Step 3: Install dependencies (for runtime only, bundling was done during generation)
|
|
1842
|
-
echo "📦 Installing dependencies..."
|
|
1843
|
-
npm install
|
|
1844
|
-
|
|
1845
|
-
# Step 4: Validate manifest
|
|
1846
|
-
echo "🔍 Validating DXT manifest..."
|
|
1847
|
-
if command -v npx >/dev/null 2>&1; then
|
|
1848
|
-
if npx @anthropic-ai/dxt validate manifest.json; then
|
|
1849
|
-
echo "✅ DXT manifest validation passed"
|
|
1850
|
-
else
|
|
1851
|
-
echo "❌ DXT manifest validation failed"
|
|
1852
|
-
exit 1
|
|
1853
|
-
fi
|
|
1854
|
-
else
|
|
1855
|
-
echo "⚠️ npx not found, skipping DXT validation"
|
|
1856
|
-
fi
|
|
1857
|
-
|
|
1858
|
-
# Step 5: Create DXT package using Anthropic's official packer
|
|
1859
|
-
echo "📦 Creating DXT package..."
|
|
1860
|
-
if command -v npx >/dev/null 2>&1; then
|
|
1861
|
-
# Use dxt pack directly with .dxtignore for clean packaging
|
|
1862
|
-
npx @anthropic-ai/dxt pack . "${serverInfo.name}.dxt"
|
|
1863
|
-
else
|
|
1864
|
-
# Fallback to standard zip if npx not available
|
|
1865
|
-
echo "⚠️ npx not found, using zip fallback"
|
|
1866
|
-
zip -r "${serverInfo.name}.dxt" . -x "node_modules/*" "*.log" ".git/*" "build-dxt.sh" "temp-dxt-build/*"
|
|
1867
|
-
fi
|
|
1868
|
-
|
|
1869
|
-
# Step 6: Sign the DXT package (optional)
|
|
1870
|
-
echo "🔐 Signing DXT package..."
|
|
1871
|
-
if command -v npx >/dev/null 2>&1 && command -v openssl >/dev/null 2>&1; then
|
|
1872
|
-
if npx @anthropic-ai/dxt sign "${serverInfo.name}.dxt" --self-signed; then
|
|
1873
|
-
echo "✅ DXT package signed successfully"
|
|
1874
|
-
else
|
|
1875
|
-
echo "⚠️ DXT signing failed, but package is still usable"
|
|
1876
|
-
fi
|
|
1877
|
-
else
|
|
1878
|
-
echo "⚠️ npx or openssl not found, skipping DXT signing"
|
|
1879
|
-
fi
|
|
1880
|
-
|
|
1881
|
-
echo "✅ DXT package created: ${serverInfo.name}.dxt"
|
|
1882
|
-
echo "🎯 This package includes bundled CLI with all dependencies!"
|
|
1883
|
-
echo ""
|
|
1884
|
-
echo "🎉 Installation Instructions:"
|
|
1885
|
-
echo "You can now take the file '${serverInfo.name}.dxt' and install it on Claude Desktop"
|
|
1886
|
-
echo "or supporting applications by using drag & drop on the Extensions Settings page,"
|
|
1887
|
-
echo "or directly pointing the file selector to this file."
|
|
1888
|
-
echo ""
|
|
1889
|
-
echo "📁 DXT file location: $(pwd)/${serverInfo.name}.dxt"
|
|
1890
|
-
`;
|
|
1891
|
-
}
|
|
1892
|
-
createDxtReadme(serverInfo) {
|
|
1893
|
-
return `# ${serverInfo.name}
|
|
1894
|
-
|
|
1895
|
-
${serverInfo.description}
|
|
1896
|
-
|
|
1897
|
-
## Installation
|
|
1898
|
-
|
|
1899
|
-
This is a Desktop Extension (DXT) package generated from @alcyone-labs/arg-parser.
|
|
1900
|
-
|
|
1901
|
-
### Automatic Installation
|
|
1902
|
-
Open this .dxt file with Claude Desktop or other DXT-compatible applications for single-click installation.
|
|
1903
|
-
|
|
1904
|
-
### Manual Installation
|
|
1905
|
-
1. Extract the .dxt file (it's a ZIP archive)
|
|
1906
|
-
2. Run \`npm install\` to install dependencies
|
|
1907
|
-
3. Start the server with \`npm start\`
|
|
1908
|
-
|
|
1909
|
-
## Tools
|
|
1910
|
-
|
|
1911
|
-
This MCP server provides the following tools:
|
|
1912
|
-
${this.generateMcpToolsForDxt().map((tool) => `- **${tool.name}**: ${tool.description}`).join("\n")}
|
|
1913
|
-
|
|
1914
|
-
## Building DXT Packages
|
|
1915
|
-
|
|
1916
|
-
To rebuild the DXT package:
|
|
1917
|
-
|
|
1918
|
-
### Prerequisites
|
|
1919
|
-
- Node.js 18+ installed
|
|
1920
|
-
- npm package manager
|
|
1921
|
-
|
|
1922
|
-
### Build Steps
|
|
1923
|
-
|
|
1924
|
-
\`\`\`bash
|
|
1925
|
-
# 1. Install dependencies
|
|
1926
|
-
npm install
|
|
1927
|
-
|
|
1928
|
-
# 2. Build DXT package
|
|
1929
|
-
npm run build-dxt
|
|
1930
|
-
# or
|
|
1931
|
-
./build-dxt.sh
|
|
1932
|
-
|
|
1933
|
-
# 3. The build script will:
|
|
1934
|
-
# - Install dependencies
|
|
1935
|
-
# - Validate the manifest
|
|
1936
|
-
# - Create the DXT package using Anthropic's official packer
|
|
1937
|
-
# - Sign the package (optional)
|
|
1938
|
-
\`\`\`
|
|
1939
|
-
|
|
1940
|
-
### Manual Build Process
|
|
1941
|
-
|
|
1942
|
-
If the automated build script doesn't work, you can build manually:
|
|
1943
|
-
|
|
1944
|
-
\`\`\`bash
|
|
1945
|
-
# 1. Install dependencies
|
|
1946
|
-
npm install
|
|
1947
|
-
|
|
1948
|
-
# 2. Create DXT package
|
|
1949
|
-
npx @anthropic-ai/dxt pack . ${serverInfo.name}.dxt
|
|
1950
|
-
|
|
1951
|
-
# 2. Update manifest.json
|
|
1952
|
-
# Change "entry_point" from "server/index.js" to "dist-autonomous/server.cjs"
|
|
1953
|
-
|
|
1954
|
-
# 3. Create new DXT with bundled server
|
|
1955
|
-
# Replace server/index.js with dist-autonomous/server.cjs
|
|
1956
|
-
# Remove package.json dependencies (optional)
|
|
1957
|
-
\`\`\`
|
|
1958
|
-
|
|
1959
|
-
### Result
|
|
1960
|
-
The resulting DXT package will be completely autonomous and won't require \`npm install\`.
|
|
1961
|
-
|
|
1962
|
-
## Generated Information
|
|
1963
|
-
|
|
1964
|
-
- **Generator**: @alcyone-labs/arg-parser v1.3.0
|
|
1965
|
-
- **Generated**: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
1966
|
-
- **DXT Version**: 0.1
|
|
1967
|
-
|
|
1968
|
-
## Note
|
|
1969
|
-
|
|
1970
|
-
This is a simplified DXT package. For full functionality and the latest features, use the original CLI directly.
|
|
1971
|
-
For autonomous packages, follow the build instructions above.
|
|
1972
|
-
`;
|
|
1973
|
-
}
|
|
1974
1558
|
/**
|
|
1975
1559
|
* Maps ArgParser flag types to DXT user config types
|
|
1976
1560
|
*/
|
|
1977
|
-
mapFlagTypeToUserConfigType(flagType) {
|
|
1978
|
-
if (typeof flagType === "function") {
|
|
1979
|
-
if (flagType === String) return "string";
|
|
1980
|
-
if (flagType === Number) return "number";
|
|
1981
|
-
if (flagType === Boolean) return "boolean";
|
|
1982
|
-
if (flagType === Array) return "array";
|
|
1983
|
-
if (flagType === Object) return "object";
|
|
1984
|
-
return "string";
|
|
1985
|
-
}
|
|
1986
|
-
switch (String(flagType).toLowerCase()) {
|
|
1987
|
-
case "string":
|
|
1988
|
-
return "string";
|
|
1989
|
-
case "number":
|
|
1990
|
-
return "number";
|
|
1991
|
-
case "boolean":
|
|
1992
|
-
return "boolean";
|
|
1993
|
-
case "table":
|
|
1994
|
-
return "array";
|
|
1995
|
-
case "array":
|
|
1996
|
-
return "array";
|
|
1997
|
-
case "object":
|
|
1998
|
-
return "object";
|
|
1999
|
-
default:
|
|
2000
|
-
return "string";
|
|
2001
|
-
}
|
|
2002
|
-
}
|
|
2003
|
-
/**
|
|
2004
|
-
* Generates CLI arguments for DXT manifest based on ArgParser flags
|
|
2005
|
-
*/
|
|
2006
|
-
generateCliArgsForDxt(_mcpSubCommand) {
|
|
2007
|
-
const args = [];
|
|
2008
|
-
args.push("--s-mcp-serve");
|
|
2009
|
-
return args;
|
|
2010
|
-
}
|
|
2011
|
-
/**
|
|
2012
|
-
* Generates environment variables and user config for DXT manifest
|
|
2013
|
-
*/
|
|
2014
|
-
generateEnvAndUserConfig() {
|
|
2015
|
-
const envVars = {};
|
|
2016
|
-
const userConfig = {};
|
|
2017
|
-
const flags = this.argParserInstance.flags || [];
|
|
2018
|
-
for (const flag of flags) {
|
|
2019
|
-
const flagName = flag["name"];
|
|
2020
|
-
if (flagName === "help" || flagName === "mcp") continue;
|
|
2021
|
-
if (flag["env"]) {
|
|
2022
|
-
const envVarName = flag["env"];
|
|
2023
|
-
envVars[envVarName] = `\${user_config.${envVarName}}`;
|
|
2024
|
-
userConfig[envVarName] = {
|
|
2025
|
-
type: this.mapFlagTypeToUserConfigType(flag["type"]),
|
|
2026
|
-
title: this.generateUserConfigTitle(envVarName),
|
|
2027
|
-
description: flag["description"] || `${envVarName} environment variable`,
|
|
2028
|
-
required: true,
|
|
2029
|
-
// Always require env vars in user_config for better UX
|
|
2030
|
-
sensitive: this.isSensitiveField(envVarName)
|
|
2031
|
-
};
|
|
2032
|
-
}
|
|
2033
|
-
}
|
|
2034
|
-
if (typeof this.argParserInstance.getTools === "function") {
|
|
2035
|
-
const tools = this.argParserInstance.getTools();
|
|
2036
|
-
for (const [, toolConfig] of tools) {
|
|
2037
|
-
const toolFlags = toolConfig.flags || [];
|
|
2038
|
-
for (const flag of toolFlags) {
|
|
2039
|
-
const flagName = flag["name"];
|
|
2040
|
-
if (flagName === "help" || flagName.startsWith("s-")) continue;
|
|
2041
|
-
if (flag["env"]) {
|
|
2042
|
-
const envVarName = flag["env"];
|
|
2043
|
-
if (!envVars[envVarName]) {
|
|
2044
|
-
envVars[envVarName] = `\${user_config.${envVarName}}`;
|
|
2045
|
-
userConfig[envVarName] = {
|
|
2046
|
-
type: this.mapFlagTypeToUserConfigType(flag["type"]),
|
|
2047
|
-
title: this.generateUserConfigTitle(envVarName),
|
|
2048
|
-
description: flag["description"] || `${envVarName} environment variable`,
|
|
2049
|
-
required: true,
|
|
2050
|
-
// Always require env vars in user_config for better UX
|
|
2051
|
-
sensitive: this.isSensitiveField(envVarName)
|
|
2052
|
-
};
|
|
2053
|
-
}
|
|
2054
|
-
}
|
|
2055
|
-
}
|
|
2056
|
-
}
|
|
2057
|
-
}
|
|
2058
|
-
return { envVars, userConfig };
|
|
2059
|
-
}
|
|
2060
|
-
/**
|
|
2061
|
-
* Generates a user-friendly title for user config fields
|
|
2062
|
-
*/
|
|
2063
|
-
generateUserConfigTitle(flagName) {
|
|
2064
|
-
return flagName.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
|
|
2065
|
-
}
|
|
2066
|
-
/**
|
|
2067
|
-
* Checks if a field should be marked as sensitive in user config
|
|
2068
|
-
*/
|
|
2069
|
-
isSensitiveField(fieldName) {
|
|
2070
|
-
const sensitivePatterns = [
|
|
2071
|
-
/key/i,
|
|
2072
|
-
/token/i,
|
|
2073
|
-
/secret/i,
|
|
2074
|
-
/password/i,
|
|
2075
|
-
/auth/i,
|
|
2076
|
-
/credential/i
|
|
2077
|
-
];
|
|
2078
|
-
return sensitivePatterns.some((pattern2) => pattern2.test(fieldName));
|
|
2079
|
-
}
|
|
2080
1561
|
/**
|
|
2081
1562
|
* Adds the logo to the build folder if available
|
|
2082
1563
|
* @returns The filename of the logo that was added, or undefined if no logo was added
|
|
@@ -2096,7 +1577,10 @@ For autonomous packages, follow the build instructions above.
|
|
|
2096
1577
|
const urlPath = new URL(customLogo).pathname;
|
|
2097
1578
|
const urlFilename = path__namespace.basename(urlPath);
|
|
2098
1579
|
if (urlFilename && urlFilename.includes(".")) {
|
|
2099
|
-
|
|
1580
|
+
const ext = path__namespace.extname(urlFilename);
|
|
1581
|
+
logoFilename = `logo${ext}`;
|
|
1582
|
+
} else {
|
|
1583
|
+
logoFilename = "logo.jpg";
|
|
2100
1584
|
}
|
|
2101
1585
|
console.log("✓ Downloaded logo from URL");
|
|
2102
1586
|
} else {
|
|
@@ -2123,7 +1607,8 @@ For autonomous packages, follow the build instructions above.
|
|
|
2123
1607
|
}
|
|
2124
1608
|
if (fs__namespace.existsSync(logoPath)) {
|
|
2125
1609
|
logoBuffer = fs__namespace.readFileSync(logoPath);
|
|
2126
|
-
|
|
1610
|
+
const ext = path__namespace.extname(logoPath);
|
|
1611
|
+
logoFilename = `logo${ext}`;
|
|
2127
1612
|
console.log("✓ Added custom logo from local file");
|
|
2128
1613
|
} else {
|
|
2129
1614
|
console.warn(`⚠ Custom logo file not found: ${logoPath}`);
|
|
@@ -2152,9 +1637,29 @@ For autonomous packages, follow the build instructions above.
|
|
|
2152
1637
|
"logo_1_small.jpg"
|
|
2153
1638
|
);
|
|
2154
1639
|
}
|
|
1640
|
+
if (!fs__namespace.existsSync(logoPath)) {
|
|
1641
|
+
logoPath = path__namespace.join(
|
|
1642
|
+
process.cwd(),
|
|
1643
|
+
"node_modules",
|
|
1644
|
+
"@alcyone-labs",
|
|
1645
|
+
"arg-parser",
|
|
1646
|
+
"dist",
|
|
1647
|
+
"assets",
|
|
1648
|
+
"logo_1_small.jpg"
|
|
1649
|
+
);
|
|
1650
|
+
}
|
|
1651
|
+
if (!fs__namespace.existsSync(logoPath)) {
|
|
1652
|
+
logoPath = path__namespace.join(
|
|
1653
|
+
process.cwd(),
|
|
1654
|
+
"dist",
|
|
1655
|
+
"assets",
|
|
1656
|
+
"logo_1_small.jpg"
|
|
1657
|
+
);
|
|
1658
|
+
}
|
|
2155
1659
|
if (fs__namespace.existsSync(logoPath)) {
|
|
2156
1660
|
logoBuffer = fs__namespace.readFileSync(logoPath);
|
|
2157
|
-
|
|
1661
|
+
const ext = path__namespace.extname(logoPath);
|
|
1662
|
+
logoFilename = `logo${ext}`;
|
|
2158
1663
|
console.log("✓ Added default logo to build folder");
|
|
2159
1664
|
} else {
|
|
2160
1665
|
console.warn(
|
|
@@ -2176,317 +1681,82 @@ For autonomous packages, follow the build instructions above.
|
|
|
2176
1681
|
return void 0;
|
|
2177
1682
|
}
|
|
2178
1683
|
}
|
|
2179
|
-
/**
|
|
2180
|
-
* Processes CLI source code to replace global console with MCP-compliant Logger
|
|
2181
|
-
*/
|
|
2182
|
-
processCliSourceForMcp(cliSource) {
|
|
2183
|
-
const consoleReplacement = `import { createMcpLogger } from '@alcyone-labs/arg-parser';
|
|
2184
|
-
|
|
2185
|
-
// Replace global console with MCP-compliant logger for DXT packages
|
|
2186
|
-
const mcpLogger = createMcpLogger('[CLI]');
|
|
2187
|
-
const originalConsole = globalThis.console;
|
|
2188
|
-
globalThis.console = {
|
|
2189
|
-
...originalConsole,
|
|
2190
|
-
log: (...args) => mcpLogger.info(...args),
|
|
2191
|
-
info: (...args) => mcpLogger.info(...args),
|
|
2192
|
-
warn: (...args) => mcpLogger.warn(...args),
|
|
2193
|
-
debug: (...args) => mcpLogger.debug(...args),
|
|
2194
|
-
// Keep error/trace/etc as-is since they use stderr (MCP-compliant)
|
|
2195
|
-
error: originalConsole.error,
|
|
2196
|
-
trace: originalConsole.trace,
|
|
2197
|
-
assert: originalConsole.assert,
|
|
2198
|
-
clear: originalConsole.clear,
|
|
2199
|
-
count: originalConsole.count,
|
|
2200
|
-
countReset: originalConsole.countReset,
|
|
2201
|
-
dir: originalConsole.dir,
|
|
2202
|
-
dirxml: originalConsole.dirxml,
|
|
2203
|
-
group: originalConsole.group,
|
|
2204
|
-
groupCollapsed: originalConsole.groupCollapsed,
|
|
2205
|
-
groupEnd: originalConsole.groupEnd,
|
|
2206
|
-
table: originalConsole.table,
|
|
2207
|
-
time: originalConsole.time,
|
|
2208
|
-
timeEnd: originalConsole.timeEnd,
|
|
2209
|
-
timeLog: originalConsole.timeLog,
|
|
2210
|
-
timeStamp: originalConsole.timeStamp,
|
|
2211
|
-
};
|
|
2212
|
-
|
|
2213
|
-
`;
|
|
2214
|
-
const lines = cliSource.split("\n");
|
|
2215
|
-
let lastImportIndex = -1;
|
|
2216
|
-
for (let i = 0; i < lines.length; i++) {
|
|
2217
|
-
const line = lines[i].trim();
|
|
2218
|
-
if (line.startsWith("import ") && line.includes("from")) {
|
|
2219
|
-
lastImportIndex = i;
|
|
2220
|
-
} else if (line && !line.startsWith("//") && !line.startsWith("/*") && lastImportIndex >= 0) {
|
|
2221
|
-
break;
|
|
2222
|
-
}
|
|
2223
|
-
}
|
|
2224
|
-
if (lastImportIndex >= 0) {
|
|
2225
|
-
lines.splice(
|
|
2226
|
-
lastImportIndex + 1,
|
|
2227
|
-
0,
|
|
2228
|
-
"",
|
|
2229
|
-
...consoleReplacement.trim().split("\n")
|
|
2230
|
-
);
|
|
2231
|
-
return lines.join("\n");
|
|
2232
|
-
} else {
|
|
2233
|
-
return consoleReplacement + cliSource;
|
|
2234
|
-
}
|
|
2235
|
-
}
|
|
2236
|
-
/**
|
|
2237
|
-
* Adds the original CLI source to the build folder for handler execution
|
|
2238
|
-
*/
|
|
2239
|
-
addOriginalCliToFolder(buildDir) {
|
|
2240
|
-
try {
|
|
2241
|
-
const appCommandName = this.argParserInstance.getAppCommandName();
|
|
2242
|
-
const appName = this.argParserInstance.getAppName();
|
|
2243
|
-
const possibleCliFiles = [
|
|
2244
|
-
// Current working directory common patterns
|
|
2245
|
-
path__namespace.join(process.cwd(), "index.js"),
|
|
2246
|
-
path__namespace.join(process.cwd(), "index.mjs"),
|
|
2247
|
-
path__namespace.join(process.cwd(), "cli.js"),
|
|
2248
|
-
path__namespace.join(process.cwd(), "cli.mjs"),
|
|
2249
|
-
path__namespace.join(process.cwd(), "main.js"),
|
|
2250
|
-
path__namespace.join(process.cwd(), "main.mjs"),
|
|
2251
|
-
// Look for files with the app command name
|
|
2252
|
-
path__namespace.join(process.cwd(), `${appCommandName}.js`),
|
|
2253
|
-
path__namespace.join(process.cwd(), `${appCommandName}.mjs`),
|
|
2254
|
-
// Look for files with the app command name (sanitized)
|
|
2255
|
-
path__namespace.join(
|
|
2256
|
-
process.cwd(),
|
|
2257
|
-
`${appCommandName.replace(/[^a-zA-Z0-9-]/g, "-")}.js`
|
|
2258
|
-
),
|
|
2259
|
-
path__namespace.join(
|
|
2260
|
-
process.cwd(),
|
|
2261
|
-
`${appCommandName.replace(/[^a-zA-Z0-9-]/g, "-")}.mjs`
|
|
2262
|
-
),
|
|
2263
|
-
// Look for files with app name patterns
|
|
2264
|
-
path__namespace.join(
|
|
2265
|
-
process.cwd(),
|
|
2266
|
-
`${appName.toLowerCase().replace(/\s+/g, "-")}-cli.js`
|
|
2267
|
-
),
|
|
2268
|
-
path__namespace.join(
|
|
2269
|
-
process.cwd(),
|
|
2270
|
-
`${appName.toLowerCase().replace(/\s+/g, "-")}-cli.mjs`
|
|
2271
|
-
),
|
|
2272
|
-
// Look for files with first word of app name + cli
|
|
2273
|
-
path__namespace.join(
|
|
2274
|
-
process.cwd(),
|
|
2275
|
-
`${appName.split(" ")[0].toLowerCase()}-cli.js`
|
|
2276
|
-
),
|
|
2277
|
-
path__namespace.join(
|
|
2278
|
-
process.cwd(),
|
|
2279
|
-
`${appName.split(" ")[0].toLowerCase()}-cli.mjs`
|
|
2280
|
-
)
|
|
2281
|
-
];
|
|
2282
|
-
let cliSourcePath = null;
|
|
2283
|
-
for (const filePath of possibleCliFiles) {
|
|
2284
|
-
if (fs__namespace.existsSync(filePath)) {
|
|
2285
|
-
cliSourcePath = filePath;
|
|
2286
|
-
break;
|
|
2287
|
-
}
|
|
2288
|
-
}
|
|
2289
|
-
if (cliSourcePath) {
|
|
2290
|
-
let cliSource = fs__namespace.readFileSync(cliSourcePath, "utf8");
|
|
2291
|
-
cliSource = cliSource.replace(
|
|
2292
|
-
/import\s*{\s*([^}]+)\s*}\s*from\s*['"][^'"]*\/dist\/index\.mjs['"];?/g,
|
|
2293
|
-
"import { $1 } from '@alcyone-labs/arg-parser';"
|
|
2294
|
-
);
|
|
2295
|
-
cliSource = cliSource.replace(
|
|
2296
|
-
/import\s+(\w+)\s+from\s*['"][^'"]*\/dist\/index\.mjs['"];?/g,
|
|
2297
|
-
"import $1 from '@alcyone-labs/arg-parser';"
|
|
2298
|
-
);
|
|
2299
|
-
cliSource = this.processCliSourceForMcp(cliSource);
|
|
2300
|
-
const parserVariableMatch = cliSource.match(
|
|
2301
|
-
/const\s+(\w+)\s*=\s*ArgParser\.withMcp\(/
|
|
2302
|
-
);
|
|
2303
|
-
if (parserVariableMatch) {
|
|
2304
|
-
const parserVariable = parserVariableMatch[1];
|
|
2305
|
-
cliSource += `
|
|
2306
|
-
|
|
2307
|
-
// Export the parser instance for MCP server use
|
|
2308
|
-
export default ${parserVariable};
|
|
2309
|
-
|
|
2310
|
-
// Add debugging for main execution
|
|
2311
|
-
console.error('[MCP-DEBUG] CLI source loaded, checking execution context...');
|
|
2312
|
-
console.error('[MCP-DEBUG] import.meta.url:', import.meta.url);
|
|
2313
|
-
console.error('[MCP-DEBUG] process.argv[1]:', process.argv[1]);
|
|
2314
|
-
|
|
2315
|
-
// Ensure MCP server processes don't exit prematurely
|
|
2316
|
-
console.error('[MCP-DEBUG] Process argv:', process.argv);
|
|
2317
|
-
console.error('[MCP-DEBUG] Checking for serve command...');
|
|
2318
|
-
|
|
2319
|
-
if (process.argv.includes('serve')) {
|
|
2320
|
-
console.error('[MCP-DEBUG] Detected serve command, setting up MCP server lifecycle...');
|
|
2321
|
-
|
|
2322
|
-
// Override the original parse method to handle async MCP server
|
|
2323
|
-
const originalParse = ${parserVariable}.parse;
|
|
2324
|
-
${parserVariable}.parse = async function(args) {
|
|
2325
|
-
console.error('[MCP-DEBUG] Starting parse with args:', args);
|
|
2326
|
-
|
|
2327
|
-
try {
|
|
2328
|
-
const result = originalParse.call(this, args);
|
|
2329
|
-
console.error('[MCP-DEBUG] Parse result:', typeof result, result?.constructor?.name);
|
|
2330
|
-
|
|
2331
|
-
// If result is a Promise (MCP server), await it and keep process alive
|
|
2332
|
-
if (result && typeof result.then === 'function') {
|
|
2333
|
-
console.error('[MCP-DEBUG] Detected Promise result, awaiting...');
|
|
2334
|
-
const mcpResult = await result;
|
|
2335
|
-
console.error('[MCP-DEBUG] MCP server started, keeping process alive...');
|
|
2336
|
-
|
|
2337
|
-
// Keep the process alive indefinitely for MCP server
|
|
2338
|
-
const keepAlive = setInterval(() => {
|
|
2339
|
-
// Do nothing, just keep the event loop alive
|
|
2340
|
-
}, 30000);
|
|
2341
|
-
|
|
2342
|
-
// Handle graceful shutdown
|
|
2343
|
-
process.on('SIGINT', () => {
|
|
2344
|
-
console.error('[MCP-INFO] Received SIGINT, shutting down gracefully...');
|
|
2345
|
-
clearInterval(keepAlive);
|
|
2346
|
-
process.exit(0);
|
|
2347
|
-
});
|
|
2348
|
-
|
|
2349
|
-
process.on('SIGTERM', () => {
|
|
2350
|
-
console.error('[MCP-INFO] Received SIGTERM, shutting down gracefully...');
|
|
2351
|
-
clearInterval(keepAlive);
|
|
2352
|
-
process.exit(0);
|
|
2353
|
-
});
|
|
2354
|
-
|
|
2355
|
-
return mcpResult;
|
|
2356
|
-
} else {
|
|
2357
|
-
console.error('[MCP-DEBUG] Non-Promise result, returning normally');
|
|
2358
|
-
return result;
|
|
2359
|
-
}
|
|
2360
|
-
} catch (error) {
|
|
2361
|
-
console.error('[MCP-ERROR] Error in parse:', error);
|
|
2362
|
-
throw error;
|
|
2363
|
-
}
|
|
2364
|
-
};
|
|
2365
|
-
}
|
|
2366
|
-
`;
|
|
2367
|
-
} else {
|
|
2368
|
-
console.warn(
|
|
2369
|
-
"⚠ Could not find ArgParser instance in CLI source, MCP server may not work properly"
|
|
2370
|
-
);
|
|
2371
|
-
}
|
|
2372
|
-
const serverDir = path__namespace.join(buildDir, "server");
|
|
2373
|
-
if (!fs__namespace.existsSync(serverDir)) {
|
|
2374
|
-
fs__namespace.mkdirSync(serverDir, { recursive: true });
|
|
2375
|
-
}
|
|
2376
|
-
fs__namespace.writeFileSync(path__namespace.join(serverDir, "original-cli.mjs"), cliSource);
|
|
2377
|
-
console.log(
|
|
2378
|
-
`✓ Added original CLI source to build folder: ${path__namespace.basename(cliSourcePath)}`
|
|
2379
|
-
);
|
|
2380
|
-
} else {
|
|
2381
|
-
console.warn(
|
|
2382
|
-
"⚠ Original CLI source not found, handlers may not work properly"
|
|
2383
|
-
);
|
|
2384
|
-
console.warn(
|
|
2385
|
-
" Searched for:",
|
|
2386
|
-
possibleCliFiles.map((f) => path__namespace.basename(f)).join(", ")
|
|
2387
|
-
);
|
|
2388
|
-
}
|
|
2389
|
-
} catch (error) {
|
|
2390
|
-
console.warn(
|
|
2391
|
-
"⚠ Failed to add original CLI source:",
|
|
2392
|
-
error instanceof Error ? error.message : String(error)
|
|
2393
|
-
);
|
|
2394
|
-
}
|
|
2395
|
-
}
|
|
2396
1684
|
/**
|
|
2397
1685
|
* Builds a complete DXT package using TSDown CLI for autonomous execution
|
|
2398
1686
|
*/
|
|
2399
|
-
async buildDxtWithTsdown(entryPointFile, outputDir = "./dxt") {
|
|
1687
|
+
async buildDxtWithTsdown(entryPointFile, outputDir = "./dxt", withNodeModules = false) {
|
|
2400
1688
|
try {
|
|
2401
1689
|
console.log(simpleChalk.cyan("🔧 Building DXT package with TSDown..."));
|
|
2402
|
-
const
|
|
1690
|
+
const projectRoot = this.findProjectRoot(entryPointFile);
|
|
1691
|
+
const absoluteEntryPath = path__namespace.resolve(entryPointFile);
|
|
1692
|
+
const relativeEntryPath = path__namespace.relative(projectRoot, absoluteEntryPath);
|
|
2403
1693
|
const entryFileName = path__namespace.basename(entryPointFile);
|
|
2404
1694
|
console.log(simpleChalk.gray(`Entry point: ${entryPointFile}`));
|
|
2405
|
-
console.log(simpleChalk.gray(`
|
|
1695
|
+
console.log(simpleChalk.gray(`Project root: ${projectRoot}`));
|
|
1696
|
+
console.log(simpleChalk.gray(`Relative entry path: ${relativeEntryPath}`));
|
|
2406
1697
|
const dxtIgnorePath = this.getDxtIgnoreTemplatePath();
|
|
2407
1698
|
if (fs__namespace.existsSync(dxtIgnorePath)) {
|
|
2408
|
-
fs__namespace.copyFileSync(dxtIgnorePath, path__namespace.join(
|
|
1699
|
+
fs__namespace.copyFileSync(dxtIgnorePath, path__namespace.join(projectRoot, ".dxtignore"));
|
|
2409
1700
|
}
|
|
1701
|
+
const serverInfo = this.extractMcpServerInfo();
|
|
1702
|
+
const logoFilename = await this.addLogoToFolder(
|
|
1703
|
+
projectRoot,
|
|
1704
|
+
serverInfo,
|
|
1705
|
+
entryPointFile
|
|
1706
|
+
);
|
|
1707
|
+
console.log(
|
|
1708
|
+
logoFilename ? simpleChalk.gray(`✓ Logo prepared: ${logoFilename}`) : simpleChalk.gray("⚠ No logo available")
|
|
1709
|
+
);
|
|
2410
1710
|
const originalCwd = process.cwd();
|
|
2411
1711
|
try {
|
|
2412
|
-
process.chdir(
|
|
1712
|
+
process.chdir(projectRoot);
|
|
2413
1713
|
const { build } = await import("tsdown");
|
|
2414
|
-
console.log(simpleChalk.gray(`Building with TSDown: ${
|
|
1714
|
+
console.log(simpleChalk.gray(`Building with TSDown: ${relativeEntryPath}`));
|
|
1715
|
+
console.log(
|
|
1716
|
+
simpleChalk.green(
|
|
1717
|
+
`${withNodeModules ? "with node_modules" : "without node_modules"}`
|
|
1718
|
+
)
|
|
1719
|
+
);
|
|
2415
1720
|
const buildConfig = {
|
|
2416
|
-
entry: [
|
|
2417
|
-
outDir: path__namespace.resolve(
|
|
2418
|
-
format: ["
|
|
1721
|
+
entry: [relativeEntryPath],
|
|
1722
|
+
outDir: path__namespace.resolve(originalCwd, outputDir),
|
|
1723
|
+
format: ["es"],
|
|
2419
1724
|
target: "node22",
|
|
2420
|
-
|
|
1725
|
+
define: {
|
|
1726
|
+
// Define any compile-time constants
|
|
1727
|
+
NODE_ENV: '"production"'
|
|
1728
|
+
},
|
|
2421
1729
|
minify: false,
|
|
2422
1730
|
sourcemap: false,
|
|
2423
|
-
|
|
1731
|
+
// Remove all output folders and artefacts
|
|
1732
|
+
clean: [outputDir, "./.dxtignore", `${outputDir}.dxt`],
|
|
2424
1733
|
silent: process.env["NO_SILENCE"] !== "1",
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
"..",
|
|
2433
|
-
"assets",
|
|
2434
|
-
"logo_1_small.jpg"
|
|
2435
|
-
),
|
|
2436
|
-
// From node_modules
|
|
2437
|
-
path__namespace.join(
|
|
2438
|
-
process.cwd(),
|
|
2439
|
-
"node_modules",
|
|
2440
|
-
"@alcyone-labs",
|
|
2441
|
-
"arg-parser",
|
|
2442
|
-
"dist",
|
|
2443
|
-
"assets",
|
|
2444
|
-
"logo_1_small.jpg"
|
|
2445
|
-
),
|
|
2446
|
-
// From package root dist/assets (for local build)
|
|
2447
|
-
path__namespace.join(process.cwd(), "dist", "assets", "logo_1_small.jpg"),
|
|
2448
|
-
// From library root (development)
|
|
2449
|
-
path__namespace.join(
|
|
2450
|
-
process.cwd(),
|
|
2451
|
-
"..",
|
|
2452
|
-
"..",
|
|
2453
|
-
"..",
|
|
2454
|
-
"docs",
|
|
2455
|
-
"MCP",
|
|
2456
|
-
"icons",
|
|
2457
|
-
"logo_1_small.jpg"
|
|
2458
|
-
)
|
|
2459
|
-
];
|
|
2460
|
-
for (const logoPath of possibleLogoPaths) {
|
|
2461
|
-
if (fs__namespace.existsSync(logoPath)) {
|
|
2462
|
-
console.log(simpleChalk.gray(`Found logo at: ${logoPath}`));
|
|
2463
|
-
return [{ from: logoPath, to: "logo.jpg" }];
|
|
2464
|
-
}
|
|
2465
|
-
}
|
|
1734
|
+
external: (_, importer) => withNodeModules ? importer == null ? void 0 : importer.includes("node_modules") : false,
|
|
1735
|
+
noExternal: (_, importer) => withNodeModules ? (importer == null ? void 0 : importer.includes("node_modules")) === false : true,
|
|
1736
|
+
copy: async (options) => {
|
|
1737
|
+
const outputPaths = [
|
|
1738
|
+
"package.json"
|
|
1739
|
+
];
|
|
1740
|
+
if (withNodeModules) {
|
|
2466
1741
|
console.log(
|
|
2467
|
-
simpleChalk.
|
|
1742
|
+
simpleChalk.gray(
|
|
1743
|
+
"📦 Including node_modules in bundle (may take longer)..."
|
|
1744
|
+
)
|
|
2468
1745
|
);
|
|
2469
|
-
|
|
2470
|
-
}
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
"process",
|
|
2484
|
-
"crypto",
|
|
2485
|
-
"http",
|
|
2486
|
-
"https",
|
|
2487
|
-
"net",
|
|
2488
|
-
"zlib"
|
|
2489
|
-
],
|
|
1746
|
+
outputPaths.push("node_modules");
|
|
1747
|
+
}
|
|
1748
|
+
if (logoFilename) {
|
|
1749
|
+
const logoPath = path__namespace.join(process.cwd(), logoFilename);
|
|
1750
|
+
if (fs__namespace.existsSync(logoPath)) {
|
|
1751
|
+
console.log(simpleChalk.gray(`Adding logo from: ${logoPath}`));
|
|
1752
|
+
outputPaths.push({
|
|
1753
|
+
from: logoPath,
|
|
1754
|
+
to: path__namespace.join(options.outDir, logoFilename)
|
|
1755
|
+
});
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
return outputPaths;
|
|
1759
|
+
},
|
|
2490
1760
|
platform: "node",
|
|
2491
1761
|
plugins: []
|
|
2492
1762
|
};
|
|
@@ -2515,15 +1785,15 @@ export default ${JSON.stringify(buildConfig, null, 2)};
|
|
|
2515
1785
|
}
|
|
2516
1786
|
await build(buildConfig);
|
|
2517
1787
|
console.log(simpleChalk.green("✅ TSDown bundling completed"));
|
|
2518
|
-
const
|
|
1788
|
+
const detectedOutputFile = this.detectTsdownOutputFile(
|
|
2519
1789
|
outputDir,
|
|
2520
1790
|
entryFileName
|
|
2521
1791
|
);
|
|
2522
|
-
await this.copyLogoManually(outputDir);
|
|
2523
1792
|
await this.setupDxtPackageFiles(
|
|
2524
1793
|
entryPointFile,
|
|
2525
1794
|
outputDir,
|
|
2526
|
-
|
|
1795
|
+
detectedOutputFile ?? void 0,
|
|
1796
|
+
logoFilename ?? "logo.jpg"
|
|
2527
1797
|
);
|
|
2528
1798
|
console.log(simpleChalk.cyan("📦 DXT package ready for packing"));
|
|
2529
1799
|
console.log(
|
|
@@ -2540,292 +1810,6 @@ export default ${JSON.stringify(buildConfig, null, 2)};
|
|
|
2540
1810
|
);
|
|
2541
1811
|
}
|
|
2542
1812
|
}
|
|
2543
|
-
/**
|
|
2544
|
-
* Bundles the original CLI using TSDown for autonomous execution (legacy method)
|
|
2545
|
-
*/
|
|
2546
|
-
async bundleOriginalCliWithTsdown(serverDir) {
|
|
2547
|
-
try {
|
|
2548
|
-
const { build } = await import("tsdown");
|
|
2549
|
-
console.log(
|
|
2550
|
-
simpleChalk.cyan("🔧 Bundling CLI with TSDown for autonomous execution...")
|
|
2551
|
-
);
|
|
2552
|
-
const configContent = this.getTsdownConfigContent();
|
|
2553
|
-
const localConfigPath = path__namespace.join(serverDir, "tsdown.config.mjs");
|
|
2554
|
-
fs__namespace.writeFileSync(localConfigPath, configContent);
|
|
2555
|
-
const originalCliPath = path__namespace.join(serverDir, "original-cli.mjs");
|
|
2556
|
-
if (!fs__namespace.existsSync(originalCliPath)) {
|
|
2557
|
-
console.warn(
|
|
2558
|
-
simpleChalk.yellow("⚠ Original CLI not found, skipping TSDown bundling")
|
|
2559
|
-
);
|
|
2560
|
-
return null;
|
|
2561
|
-
}
|
|
2562
|
-
const buildOptions = {
|
|
2563
|
-
entry: ["original-cli.mjs"],
|
|
2564
|
-
// Use relative path since we'll chdir to serverDir
|
|
2565
|
-
outDir: ".",
|
|
2566
|
-
// Output to current directory (serverDir)
|
|
2567
|
-
format: "esm",
|
|
2568
|
-
target: "node22",
|
|
2569
|
-
// Bundle EVERYTHING except Node.js built-ins for true autonomy
|
|
2570
|
-
noExternal: (id) => {
|
|
2571
|
-
if (!id.startsWith("node:") && !this.isNodeBuiltin(id)) return true;
|
|
2572
|
-
return false;
|
|
2573
|
-
},
|
|
2574
|
-
minify: false,
|
|
2575
|
-
sourcemap: false,
|
|
2576
|
-
clean: false,
|
|
2577
|
-
outExtension: () => ({ js: ".bundled.mjs" }),
|
|
2578
|
-
alias: {
|
|
2579
|
-
// Alias chalk to SimpleChalk for autonomous builds
|
|
2580
|
-
chalk: path__namespace.resolve(
|
|
2581
|
-
process.cwd(),
|
|
2582
|
-
"node_modules/@alcyone-labs/arg-parser/dist/SimpleChalk.mjs"
|
|
2583
|
-
)
|
|
2584
|
-
},
|
|
2585
|
-
external: [
|
|
2586
|
-
// Only Node.js built-ins - everything else gets bundled for true autonomy
|
|
2587
|
-
"node:stream",
|
|
2588
|
-
"node:fs",
|
|
2589
|
-
"node:path",
|
|
2590
|
-
"node:url",
|
|
2591
|
-
"node:util",
|
|
2592
|
-
"node:events",
|
|
2593
|
-
"node:child_process",
|
|
2594
|
-
"node:os",
|
|
2595
|
-
"node:tty",
|
|
2596
|
-
"node:process",
|
|
2597
|
-
"node:crypto",
|
|
2598
|
-
"node:http",
|
|
2599
|
-
"node:https",
|
|
2600
|
-
"node:net",
|
|
2601
|
-
"node:zlib",
|
|
2602
|
-
"node:fs/promises",
|
|
2603
|
-
"node:timers",
|
|
2604
|
-
"stream",
|
|
2605
|
-
"fs",
|
|
2606
|
-
"path",
|
|
2607
|
-
"url",
|
|
2608
|
-
"util",
|
|
2609
|
-
"events",
|
|
2610
|
-
"child_process",
|
|
2611
|
-
"os",
|
|
2612
|
-
"tty",
|
|
2613
|
-
"process",
|
|
2614
|
-
"crypto",
|
|
2615
|
-
"http",
|
|
2616
|
-
"https",
|
|
2617
|
-
"net",
|
|
2618
|
-
"zlib",
|
|
2619
|
-
"fs/promises",
|
|
2620
|
-
"timers",
|
|
2621
|
-
"timers/promises",
|
|
2622
|
-
"perf_hooks",
|
|
2623
|
-
"async_hooks",
|
|
2624
|
-
"inspector",
|
|
2625
|
-
"v8",
|
|
2626
|
-
"vm",
|
|
2627
|
-
"assert",
|
|
2628
|
-
"constants",
|
|
2629
|
-
"module",
|
|
2630
|
-
"repl",
|
|
2631
|
-
"string_decoder",
|
|
2632
|
-
"punycode",
|
|
2633
|
-
"domain",
|
|
2634
|
-
"querystring",
|
|
2635
|
-
"readline",
|
|
2636
|
-
"worker_threads",
|
|
2637
|
-
"cluster",
|
|
2638
|
-
"dgram",
|
|
2639
|
-
"dns",
|
|
2640
|
-
"buffer"
|
|
2641
|
-
],
|
|
2642
|
-
platform: "node",
|
|
2643
|
-
plugins: [],
|
|
2644
|
-
// Resolve local dependencies properly
|
|
2645
|
-
resolve: {
|
|
2646
|
-
alias: {
|
|
2647
|
-
// Handle local monorepo dependencies
|
|
2648
|
-
"@alcyone-labs/arg-parser": path__namespace.resolve(process.cwd())
|
|
2649
|
-
}
|
|
2650
|
-
}
|
|
2651
|
-
};
|
|
2652
|
-
const originalCwd = process.cwd();
|
|
2653
|
-
try {
|
|
2654
|
-
process.chdir(serverDir);
|
|
2655
|
-
await build(buildOptions);
|
|
2656
|
-
} finally {
|
|
2657
|
-
process.chdir(originalCwd);
|
|
2658
|
-
}
|
|
2659
|
-
const possibleBundledFiles = [
|
|
2660
|
-
"original-cli.bundled.mjs",
|
|
2661
|
-
"original-cli.js",
|
|
2662
|
-
"original-cli.mjs"
|
|
2663
|
-
];
|
|
2664
|
-
let bundledPath = null;
|
|
2665
|
-
let bundledFileName = null;
|
|
2666
|
-
for (const fileName of possibleBundledFiles) {
|
|
2667
|
-
const filePath = path__namespace.join(serverDir, fileName);
|
|
2668
|
-
if (fs__namespace.existsSync(filePath) && fileName !== "original-cli.mjs") {
|
|
2669
|
-
bundledPath = filePath;
|
|
2670
|
-
bundledFileName = fileName;
|
|
2671
|
-
break;
|
|
2672
|
-
}
|
|
2673
|
-
}
|
|
2674
|
-
if (bundledPath && bundledFileName) {
|
|
2675
|
-
console.log(
|
|
2676
|
-
simpleChalk.green(
|
|
2677
|
-
`✅ TSDown bundling completed successfully: ${bundledFileName}`
|
|
2678
|
-
)
|
|
2679
|
-
);
|
|
2680
|
-
const expectedBundledPath = path__namespace.join(
|
|
2681
|
-
serverDir,
|
|
2682
|
-
"original-cli.bundled.mjs"
|
|
2683
|
-
);
|
|
2684
|
-
if (bundledPath !== expectedBundledPath) {
|
|
2685
|
-
fs__namespace.renameSync(bundledPath, expectedBundledPath);
|
|
2686
|
-
bundledFileName = "original-cli.bundled.mjs";
|
|
2687
|
-
}
|
|
2688
|
-
try {
|
|
2689
|
-
fs__namespace.unlinkSync(localConfigPath);
|
|
2690
|
-
} catch (error) {
|
|
2691
|
-
}
|
|
2692
|
-
try {
|
|
2693
|
-
fs__namespace.chmodSync(expectedBundledPath, 493);
|
|
2694
|
-
} catch (error) {
|
|
2695
|
-
console.warn(
|
|
2696
|
-
"⚠ Could not set executable permission on bundled file:",
|
|
2697
|
-
error instanceof Error ? error.message : String(error)
|
|
2698
|
-
);
|
|
2699
|
-
}
|
|
2700
|
-
return bundledFileName;
|
|
2701
|
-
} else {
|
|
2702
|
-
console.warn(
|
|
2703
|
-
simpleChalk.yellow("⚠ TSDown bundling failed, bundled file not found")
|
|
2704
|
-
);
|
|
2705
|
-
return null;
|
|
2706
|
-
}
|
|
2707
|
-
} catch (error) {
|
|
2708
|
-
console.warn(
|
|
2709
|
-
simpleChalk.yellow(
|
|
2710
|
-
`⚠ TSDown bundling failed: ${error instanceof Error ? error.message : String(error)}`
|
|
2711
|
-
)
|
|
2712
|
-
);
|
|
2713
|
-
console.log(simpleChalk.gray(" Falling back to non-bundled approach"));
|
|
2714
|
-
return null;
|
|
2715
|
-
}
|
|
2716
|
-
}
|
|
2717
|
-
/**
|
|
2718
|
-
* Checks if a module ID is a Node.js built-in
|
|
2719
|
-
*/
|
|
2720
|
-
isNodeBuiltin(id) {
|
|
2721
|
-
const nodeBuiltins = [
|
|
2722
|
-
"stream",
|
|
2723
|
-
"fs",
|
|
2724
|
-
"path",
|
|
2725
|
-
"url",
|
|
2726
|
-
"util",
|
|
2727
|
-
"events",
|
|
2728
|
-
"child_process",
|
|
2729
|
-
"os",
|
|
2730
|
-
"tty",
|
|
2731
|
-
"process",
|
|
2732
|
-
"crypto",
|
|
2733
|
-
"http",
|
|
2734
|
-
"https",
|
|
2735
|
-
"net",
|
|
2736
|
-
"zlib",
|
|
2737
|
-
"fs/promises",
|
|
2738
|
-
"timers",
|
|
2739
|
-
"timers/promises",
|
|
2740
|
-
"perf_hooks",
|
|
2741
|
-
"async_hooks",
|
|
2742
|
-
"inspector",
|
|
2743
|
-
"v8",
|
|
2744
|
-
"vm",
|
|
2745
|
-
"assert",
|
|
2746
|
-
"constants",
|
|
2747
|
-
"module",
|
|
2748
|
-
"repl",
|
|
2749
|
-
"string_decoder",
|
|
2750
|
-
"punycode",
|
|
2751
|
-
"domain",
|
|
2752
|
-
"querystring",
|
|
2753
|
-
"readline",
|
|
2754
|
-
"worker_threads",
|
|
2755
|
-
"cluster",
|
|
2756
|
-
"dgram",
|
|
2757
|
-
"dns",
|
|
2758
|
-
"buffer"
|
|
2759
|
-
];
|
|
2760
|
-
return nodeBuiltins.includes(id) || id.startsWith("node:");
|
|
2761
|
-
}
|
|
2762
|
-
/**
|
|
2763
|
-
* Gets the TSDown configuration content as a string
|
|
2764
|
-
*/
|
|
2765
|
-
getTsdownConfigContent() {
|
|
2766
|
-
const currentDir = path__namespace.dirname(new URL(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index.cjs", document.baseURI).href).pathname);
|
|
2767
|
-
const assetsConfigPath = path__namespace.join(
|
|
2768
|
-
currentDir,
|
|
2769
|
-
"..",
|
|
2770
|
-
"assets",
|
|
2771
|
-
"tsdown.dxt.config.ts"
|
|
2772
|
-
);
|
|
2773
|
-
if (fs__namespace.existsSync(assetsConfigPath)) {
|
|
2774
|
-
try {
|
|
2775
|
-
const content = fs__namespace.readFileSync(assetsConfigPath, "utf-8");
|
|
2776
|
-
return content.replace('/// <reference types="tsdown" />', "").replace(
|
|
2777
|
-
'import { defineConfig } from "tsdown/config";',
|
|
2778
|
-
'import { defineConfig } from "tsdown";'
|
|
2779
|
-
).replace(
|
|
2780
|
-
"export default defineConfig(",
|
|
2781
|
-
"export default defineConfig("
|
|
2782
|
-
);
|
|
2783
|
-
} catch (error) {
|
|
2784
|
-
console.warn(
|
|
2785
|
-
simpleChalk.yellow(
|
|
2786
|
-
"⚠ Could not read TSDown config from assets, using fallback"
|
|
2787
|
-
)
|
|
2788
|
-
);
|
|
2789
|
-
}
|
|
2790
|
-
}
|
|
2791
|
-
const rootConfigPath = path__namespace.join(process.cwd(), "tsdown.dxt.config.ts");
|
|
2792
|
-
if (fs__namespace.existsSync(rootConfigPath)) {
|
|
2793
|
-
try {
|
|
2794
|
-
const content = fs__namespace.readFileSync(rootConfigPath, "utf-8");
|
|
2795
|
-
return content.replace('/// <reference types="tsdown" />', "").replace(
|
|
2796
|
-
'import { defineConfig } from "tsdown/config";',
|
|
2797
|
-
'import { defineConfig } from "tsdown";'
|
|
2798
|
-
);
|
|
2799
|
-
} catch (error) {
|
|
2800
|
-
console.warn(
|
|
2801
|
-
simpleChalk.yellow(
|
|
2802
|
-
"⚠ Could not read TSDown config from root, using default"
|
|
2803
|
-
)
|
|
2804
|
-
);
|
|
2805
|
-
}
|
|
2806
|
-
}
|
|
2807
|
-
return `import { defineConfig } from "tsdown";
|
|
2808
|
-
import path from "path";
|
|
2809
|
-
|
|
2810
|
-
export default defineConfig({
|
|
2811
|
-
outDir: "server",
|
|
2812
|
-
format: ["esm", "module"],
|
|
2813
|
-
target: "node22",
|
|
2814
|
-
noExternal: () => true,
|
|
2815
|
-
minify: false,
|
|
2816
|
-
sourcemap: false,
|
|
2817
|
-
clean: false,
|
|
2818
|
-
alias: {
|
|
2819
|
-
chalk: path.resolve(process.cwd(), "node_modules/@alcyone-labs/arg-parser/dist/SimpleChalk.mjs"),
|
|
2820
|
-
},
|
|
2821
|
-
external: [
|
|
2822
|
-
"stream", "fs", "path", "url", "util", "events", "child_process",
|
|
2823
|
-
"os", "tty", "process", "crypto", "http", "https", "net", "zlib",
|
|
2824
|
-
],
|
|
2825
|
-
platform: "node",
|
|
2826
|
-
plugins: [],
|
|
2827
|
-
});`;
|
|
2828
|
-
}
|
|
2829
1813
|
/**
|
|
2830
1814
|
* Gets the path to the .dxtignore template file in assets
|
|
2831
1815
|
*/
|
|
@@ -2865,8 +1849,8 @@ export default defineConfig({
|
|
|
2865
1849
|
/**
|
|
2866
1850
|
* Sets up DXT package files (manifest.json) in the output directory
|
|
2867
1851
|
*/
|
|
2868
|
-
async setupDxtPackageFiles(entryPointFile, outputDir = "./dxt", actualOutputFilename) {
|
|
2869
|
-
var _a, _b, _c, _d, _e;
|
|
1852
|
+
async setupDxtPackageFiles(entryPointFile, outputDir = "./dxt", actualOutputFilename, logoFilename = "logo.jpg") {
|
|
1853
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2870
1854
|
const dxtDir = path__namespace.resolve(process.cwd(), outputDir);
|
|
2871
1855
|
if (!fs__namespace.existsSync(dxtDir)) {
|
|
2872
1856
|
throw new Error(`TSDown output directory (${outputDir}) not found`);
|
|
@@ -2893,10 +1877,10 @@ export default defineConfig({
|
|
|
2893
1877
|
`Warning: Could not generate unified tool list: ${error instanceof Error ? error.message : String(error)}`
|
|
2894
1878
|
)
|
|
2895
1879
|
);
|
|
2896
|
-
const
|
|
1880
|
+
const mainFlags = this.argParserInstance.flags;
|
|
2897
1881
|
const properties2 = {};
|
|
2898
1882
|
const required2 = [];
|
|
2899
|
-
for (const flag of
|
|
1883
|
+
for (const flag of mainFlags) {
|
|
2900
1884
|
if (flag.name === "help" || flag.name.startsWith("s-")) continue;
|
|
2901
1885
|
properties2[flag.name] = {
|
|
2902
1886
|
type: getJsonSchemaTypeFromFlag(flag.type),
|
|
@@ -2920,58 +1904,17 @@ export default defineConfig({
|
|
|
2920
1904
|
}
|
|
2921
1905
|
];
|
|
2922
1906
|
}
|
|
2923
|
-
const envVars =
|
|
2924
|
-
const userConfig = {};
|
|
2925
|
-
const mainFlags = this.argParserInstance.flags;
|
|
2926
|
-
for (const flag of mainFlags) {
|
|
2927
|
-
const envVar = flag.env || flag.envVar;
|
|
2928
|
-
if (envVar) {
|
|
2929
|
-
envVars[envVar] = `\${user_config.${envVar}}`;
|
|
2930
|
-
userConfig[envVar] = {
|
|
2931
|
-
type: "string",
|
|
2932
|
-
title: envVar.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
2933
|
-
description: flag.description || `${envVar} environment variable`,
|
|
2934
|
-
required: true,
|
|
2935
|
-
// Always require env vars in user_config for better UX
|
|
2936
|
-
sensitive: true
|
|
2937
|
-
// Assume env vars are sensitive
|
|
2938
|
-
};
|
|
2939
|
-
}
|
|
2940
|
-
}
|
|
2941
|
-
if (typeof this.argParserInstance.getTools === "function") {
|
|
2942
|
-
const tools2 = this.argParserInstance.getTools();
|
|
2943
|
-
for (const [, toolConfig] of tools2) {
|
|
2944
|
-
const toolFlags = toolConfig.flags || [];
|
|
2945
|
-
for (const flag of toolFlags) {
|
|
2946
|
-
const envVar = flag.env || flag.envVar;
|
|
2947
|
-
if (envVar && !envVars[envVar]) {
|
|
2948
|
-
envVars[envVar] = `\${user_config.${envVar}}`;
|
|
2949
|
-
userConfig[envVar] = {
|
|
2950
|
-
type: "string",
|
|
2951
|
-
title: envVar.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
2952
|
-
description: flag.description || `${envVar} environment variable`,
|
|
2953
|
-
required: true,
|
|
2954
|
-
// Always require env vars in user_config for better UX
|
|
2955
|
-
sensitive: true
|
|
2956
|
-
// Assume env vars are sensitive
|
|
2957
|
-
};
|
|
2958
|
-
}
|
|
2959
|
-
}
|
|
2960
|
-
}
|
|
2961
|
-
}
|
|
1907
|
+
const { envVars, userConfig } = this.generateEnvAndUserConfig();
|
|
2962
1908
|
const serverInfo = this.extractMcpServerInfo();
|
|
2963
|
-
let
|
|
2964
|
-
if (
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
);
|
|
2970
|
-
|
|
2971
|
-
logoFilename = customLogoFilename;
|
|
2972
|
-
}
|
|
1909
|
+
let entryFileName;
|
|
1910
|
+
if (actualOutputFilename) {
|
|
1911
|
+
entryFileName = actualOutputFilename;
|
|
1912
|
+
} else {
|
|
1913
|
+
const projectRoot = this.findProjectRoot(entryPointFile);
|
|
1914
|
+
const absoluteEntryPath = path__namespace.resolve(entryPointFile);
|
|
1915
|
+
const relativeEntryPath = path__namespace.relative(projectRoot, absoluteEntryPath);
|
|
1916
|
+
entryFileName = relativeEntryPath.replace(/\.ts$/, ".js");
|
|
2973
1917
|
}
|
|
2974
|
-
const entryFileName = actualOutputFilename || path__namespace.basename(entryPointFile).replace(/\.ts$/, ".js");
|
|
2975
1918
|
const manifest = {
|
|
2976
1919
|
dxt_version: "0.1",
|
|
2977
1920
|
name: serverInfo.name || packageInfo.name || "mcp-server",
|
|
@@ -2987,17 +1930,23 @@ export default defineConfig({
|
|
|
2987
1930
|
entry_point: entryFileName,
|
|
2988
1931
|
mcp_config: {
|
|
2989
1932
|
command: "node",
|
|
2990
|
-
args: [
|
|
1933
|
+
args: [
|
|
1934
|
+
`\${__dirname}/${entryFileName}`,
|
|
1935
|
+
"--s-mcp-serve",
|
|
1936
|
+
// Overwrite the CLI config to only use stdio to avoid conflicts
|
|
1937
|
+
"--s-mcp-transport",
|
|
1938
|
+
"stdio"
|
|
1939
|
+
],
|
|
2991
1940
|
env: envVars
|
|
2992
1941
|
}
|
|
2993
1942
|
},
|
|
2994
1943
|
tools,
|
|
2995
1944
|
icon: logoFilename,
|
|
2996
1945
|
...Object.keys(userConfig).length > 0 && { user_config: userConfig },
|
|
2997
|
-
repository: {
|
|
1946
|
+
repository: ((_e = packageInfo.repository) == null ? void 0 : _e.url) ? {
|
|
2998
1947
|
type: "git",
|
|
2999
|
-
url: (
|
|
3000
|
-
},
|
|
1948
|
+
url: (_f = packageInfo.repository) == null ? void 0 : _f.url
|
|
1949
|
+
} : void 0,
|
|
3001
1950
|
license: packageInfo.license || "MIT"
|
|
3002
1951
|
};
|
|
3003
1952
|
fs__namespace.writeFileSync(
|
|
@@ -3006,66 +1955,6 @@ export default defineConfig({
|
|
|
3006
1955
|
);
|
|
3007
1956
|
console.log(simpleChalk.gray("✅ DXT package files set up"));
|
|
3008
1957
|
}
|
|
3009
|
-
/**
|
|
3010
|
-
* Manually copy logo since TSDown's copy option doesn't work programmatically
|
|
3011
|
-
*/
|
|
3012
|
-
async copyLogoManually(outputDir = "./dxt") {
|
|
3013
|
-
const dxtDir = path__namespace.resolve(process.cwd(), outputDir);
|
|
3014
|
-
if (!fs__namespace.existsSync(dxtDir)) {
|
|
3015
|
-
console.warn(
|
|
3016
|
-
simpleChalk.yellow(
|
|
3017
|
-
`⚠ Output directory (${outputDir}) not found, skipping logo copy`
|
|
3018
|
-
)
|
|
3019
|
-
);
|
|
3020
|
-
return;
|
|
3021
|
-
}
|
|
3022
|
-
const possibleLogoPaths = [
|
|
3023
|
-
// From built library assets
|
|
3024
|
-
path__namespace.join(
|
|
3025
|
-
path__namespace.dirname(new URL(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index.cjs", document.baseURI).href).pathname),
|
|
3026
|
-
"..",
|
|
3027
|
-
"assets",
|
|
3028
|
-
"logo_1_small.jpg"
|
|
3029
|
-
),
|
|
3030
|
-
// From node_modules
|
|
3031
|
-
path__namespace.join(
|
|
3032
|
-
process.cwd(),
|
|
3033
|
-
"node_modules",
|
|
3034
|
-
"@alcyone-labs",
|
|
3035
|
-
"arg-parser",
|
|
3036
|
-
"dist",
|
|
3037
|
-
"assets",
|
|
3038
|
-
"logo_1_small.jpg"
|
|
3039
|
-
),
|
|
3040
|
-
// From package root dist/assets (for local build)
|
|
3041
|
-
path__namespace.join(process.cwd(), "dist", "assets", "logo_1_small.jpg"),
|
|
3042
|
-
// From library root (development)
|
|
3043
|
-
path__namespace.join(
|
|
3044
|
-
process.cwd(),
|
|
3045
|
-
"..",
|
|
3046
|
-
"..",
|
|
3047
|
-
"..",
|
|
3048
|
-
"docs",
|
|
3049
|
-
"MCP",
|
|
3050
|
-
"icons",
|
|
3051
|
-
"logo_1_small.jpg"
|
|
3052
|
-
)
|
|
3053
|
-
];
|
|
3054
|
-
for (const logoPath of possibleLogoPaths) {
|
|
3055
|
-
if (fs__namespace.existsSync(logoPath)) {
|
|
3056
|
-
try {
|
|
3057
|
-
fs__namespace.copyFileSync(logoPath, path__namespace.join(dxtDir, "logo.jpg"));
|
|
3058
|
-
console.log(simpleChalk.gray(`✅ Logo copied from: ${logoPath}`));
|
|
3059
|
-
return;
|
|
3060
|
-
} catch (error) {
|
|
3061
|
-
console.warn(
|
|
3062
|
-
simpleChalk.yellow(`⚠ Failed to copy logo from ${logoPath}: ${error}`)
|
|
3063
|
-
);
|
|
3064
|
-
}
|
|
3065
|
-
}
|
|
3066
|
-
}
|
|
3067
|
-
console.warn(simpleChalk.yellow("⚠ Logo not found in any expected location"));
|
|
3068
|
-
}
|
|
3069
1958
|
/**
|
|
3070
1959
|
* Detects the actual output filename generated by TSDown
|
|
3071
1960
|
*/
|
|
@@ -3130,6 +2019,72 @@ export default defineConfig({
|
|
|
3130
2019
|
return null;
|
|
3131
2020
|
}
|
|
3132
2021
|
}
|
|
2022
|
+
findProjectRoot(entryPointFile) {
|
|
2023
|
+
let currentDir = path__namespace.dirname(path__namespace.resolve(entryPointFile));
|
|
2024
|
+
let attempts = 0;
|
|
2025
|
+
const maxAttempts = 5;
|
|
2026
|
+
while (attempts < maxAttempts) {
|
|
2027
|
+
const packageJsonPath = path__namespace.join(currentDir, "package.json");
|
|
2028
|
+
if (fs__namespace.existsSync(packageJsonPath)) {
|
|
2029
|
+
return currentDir;
|
|
2030
|
+
}
|
|
2031
|
+
const parentDir = path__namespace.dirname(currentDir);
|
|
2032
|
+
if (parentDir === currentDir) {
|
|
2033
|
+
break;
|
|
2034
|
+
}
|
|
2035
|
+
currentDir = parentDir;
|
|
2036
|
+
attempts++;
|
|
2037
|
+
}
|
|
2038
|
+
throw new Error(
|
|
2039
|
+
`Could not find package.json within ${maxAttempts} directories up from ${entryPointFile}. Please ensure your entry point is within a project that has a package.json file.`
|
|
2040
|
+
);
|
|
2041
|
+
}
|
|
2042
|
+
/**
|
|
2043
|
+
* Generate environment variables and user configuration from ArgParser flags
|
|
2044
|
+
* @returns Object containing envVars and userConfig
|
|
2045
|
+
*/
|
|
2046
|
+
generateEnvAndUserConfig() {
|
|
2047
|
+
const envVars = {};
|
|
2048
|
+
const userConfig = {};
|
|
2049
|
+
const mainFlags = this.argParserInstance.flags;
|
|
2050
|
+
for (const flag of mainFlags) {
|
|
2051
|
+
const envVar = flag.env || flag.envVar;
|
|
2052
|
+
if (envVar) {
|
|
2053
|
+
envVars[envVar] = `\${user_config.${envVar}}`;
|
|
2054
|
+
userConfig[envVar] = {
|
|
2055
|
+
type: "string",
|
|
2056
|
+
title: envVar.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
2057
|
+
description: flag.description || `${envVar} environment variable`,
|
|
2058
|
+
required: true,
|
|
2059
|
+
// Always require env vars in user_config for better UX
|
|
2060
|
+
sensitive: true
|
|
2061
|
+
// Assume env vars are sensitive
|
|
2062
|
+
};
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
if (typeof this.argParserInstance.getTools === "function") {
|
|
2066
|
+
const tools = this.argParserInstance.getTools();
|
|
2067
|
+
for (const [, toolConfig] of tools) {
|
|
2068
|
+
const toolFlags = toolConfig.flags || [];
|
|
2069
|
+
for (const flag of toolFlags) {
|
|
2070
|
+
const envVar = flag.env || flag.envVar;
|
|
2071
|
+
if (envVar && !envVars[envVar]) {
|
|
2072
|
+
envVars[envVar] = `\${user_config.${envVar}}`;
|
|
2073
|
+
userConfig[envVar] = {
|
|
2074
|
+
type: "string",
|
|
2075
|
+
title: envVar.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
2076
|
+
description: flag.description || `${envVar} environment variable`,
|
|
2077
|
+
required: true,
|
|
2078
|
+
// Always require env vars in user_config for better UX
|
|
2079
|
+
sensitive: true
|
|
2080
|
+
// Assume env vars are sensitive
|
|
2081
|
+
};
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
return { envVars, userConfig };
|
|
2087
|
+
}
|
|
3133
2088
|
}
|
|
3134
2089
|
class McpNotificationsManager {
|
|
3135
2090
|
constructor() {
|
|
@@ -5184,9 +4139,7 @@ _handleMcpServeFlag_fn = async function(processArgs, _mcpServeIndex) {
|
|
|
5184
4139
|
const resolvedLogPath = resolveLogPath(effectiveLogPath);
|
|
5185
4140
|
let mcpLogger;
|
|
5186
4141
|
try {
|
|
5187
|
-
const mcpLoggerModule = await
|
|
5188
|
-
'return import("@alcyone-labs/simple-mcp-logger")'
|
|
5189
|
-
)();
|
|
4142
|
+
const mcpLoggerModule = await import("@alcyone-labs/simple-mcp-logger");
|
|
5190
4143
|
mcpLogger = mcpLoggerModule.createMcpLogger("MCP Serve", resolvedLogPath);
|
|
5191
4144
|
globalThis.console = mcpLogger;
|
|
5192
4145
|
} catch {
|
|
@@ -5297,6 +4250,20 @@ _startUnifiedMcpServer_fn = async function(mcpServerConfig, transportOptions) {
|
|
|
5297
4250
|
`Error parsing transports configuration: ${error.message}. Expected JSON format: '[{"type":"stdio"},{"type":"sse","port":3001}]'`
|
|
5298
4251
|
);
|
|
5299
4252
|
}
|
|
4253
|
+
} else if (transportOptions.transportType) {
|
|
4254
|
+
const transportType = transportOptions.transportType;
|
|
4255
|
+
const finalTransportOptions = {
|
|
4256
|
+
port: transportOptions.port,
|
|
4257
|
+
host: transportOptions.host || "localhost",
|
|
4258
|
+
path: transportOptions.path || "/mcp"
|
|
4259
|
+
};
|
|
4260
|
+
await mcpParser.startMcpServerWithTransport(
|
|
4261
|
+
serverInfo,
|
|
4262
|
+
transportType,
|
|
4263
|
+
finalTransportOptions,
|
|
4264
|
+
toolOptions,
|
|
4265
|
+
transportOptions.logPath
|
|
4266
|
+
);
|
|
5300
4267
|
} else if (defaultTransports && defaultTransports.length > 0) {
|
|
5301
4268
|
await mcpParser.startMcpServerWithMultipleTransports(
|
|
5302
4269
|
serverInfo,
|
|
@@ -5318,16 +4285,10 @@ _startUnifiedMcpServer_fn = async function(mcpServerConfig, transportOptions) {
|
|
|
5318
4285
|
transportOptions.logPath
|
|
5319
4286
|
);
|
|
5320
4287
|
} else {
|
|
5321
|
-
const transportType = transportOptions.transportType || "stdio";
|
|
5322
|
-
const finalTransportOptions = {
|
|
5323
|
-
port: transportOptions.port,
|
|
5324
|
-
host: transportOptions.host || "localhost",
|
|
5325
|
-
path: transportOptions.path || "/mcp"
|
|
5326
|
-
};
|
|
5327
4288
|
await mcpParser.startMcpServerWithTransport(
|
|
5328
4289
|
serverInfo,
|
|
5329
|
-
|
|
5330
|
-
|
|
4290
|
+
"stdio",
|
|
4291
|
+
{},
|
|
5331
4292
|
toolOptions,
|
|
5332
4293
|
transportOptions.logPath
|
|
5333
4294
|
);
|
|
@@ -8854,6 +7815,7 @@ class Protocol {
|
|
|
8854
7815
|
this._responseHandlers = /* @__PURE__ */ new Map();
|
|
8855
7816
|
this._progressHandlers = /* @__PURE__ */ new Map();
|
|
8856
7817
|
this._timeoutInfo = /* @__PURE__ */ new Map();
|
|
7818
|
+
this._pendingDebouncedNotifications = /* @__PURE__ */ new Set();
|
|
8857
7819
|
this.setNotificationHandler(CancelledNotificationSchema, (notification) => {
|
|
8858
7820
|
const controller = this._requestHandlerAbortControllers.get(notification.params.requestId);
|
|
8859
7821
|
controller === null || controller === void 0 ? void 0 : controller.abort(notification.params.reason);
|
|
@@ -8935,6 +7897,7 @@ class Protocol {
|
|
|
8935
7897
|
const responseHandlers = this._responseHandlers;
|
|
8936
7898
|
this._responseHandlers = /* @__PURE__ */ new Map();
|
|
8937
7899
|
this._progressHandlers.clear();
|
|
7900
|
+
this._pendingDebouncedNotifications.clear();
|
|
8938
7901
|
this._transport = void 0;
|
|
8939
7902
|
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
8940
7903
|
const error = new McpError(ErrorCode.ConnectionClosed, "Connection closed");
|
|
@@ -9134,10 +8097,32 @@ class Protocol {
|
|
|
9134
8097
|
* Emits a notification, which is a one-way message that does not expect a response.
|
|
9135
8098
|
*/
|
|
9136
8099
|
async notification(notification, options) {
|
|
8100
|
+
var _a, _b;
|
|
9137
8101
|
if (!this._transport) {
|
|
9138
8102
|
throw new Error("Not connected");
|
|
9139
8103
|
}
|
|
9140
8104
|
this.assertNotificationCapability(notification.method);
|
|
8105
|
+
const debouncedMethods = (_b = (_a = this._options) === null || _a === void 0 ? void 0 : _a.debouncedNotificationMethods) !== null && _b !== void 0 ? _b : [];
|
|
8106
|
+
const canDebounce = debouncedMethods.includes(notification.method) && !notification.params && !(options === null || options === void 0 ? void 0 : options.relatedRequestId);
|
|
8107
|
+
if (canDebounce) {
|
|
8108
|
+
if (this._pendingDebouncedNotifications.has(notification.method)) {
|
|
8109
|
+
return;
|
|
8110
|
+
}
|
|
8111
|
+
this._pendingDebouncedNotifications.add(notification.method);
|
|
8112
|
+
Promise.resolve().then(() => {
|
|
8113
|
+
var _a2;
|
|
8114
|
+
this._pendingDebouncedNotifications.delete(notification.method);
|
|
8115
|
+
if (!this._transport) {
|
|
8116
|
+
return;
|
|
8117
|
+
}
|
|
8118
|
+
const jsonrpcNotification2 = {
|
|
8119
|
+
...notification,
|
|
8120
|
+
jsonrpc: "2.0"
|
|
8121
|
+
};
|
|
8122
|
+
(_a2 = this._transport) === null || _a2 === void 0 ? void 0 : _a2.send(jsonrpcNotification2, options).catch((error) => this._onerror(error));
|
|
8123
|
+
});
|
|
8124
|
+
return;
|
|
8125
|
+
}
|
|
9141
8126
|
const jsonrpcNotification = {
|
|
9142
8127
|
...notification,
|
|
9143
8128
|
jsonrpc: "2.0"
|