@alcyone-labs/arg-parser 2.2.0 → 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.
Files changed (42) hide show
  1. package/README.md +226 -20
  2. package/dist/assets/.dxtignore.template +0 -1
  3. package/dist/config/ConfigurationManager.d.ts.map +1 -1
  4. package/dist/config/plugins/ConfigPlugin.d.ts.map +1 -1
  5. package/dist/config/plugins/ConfigPluginRegistry.d.ts +1 -1
  6. package/dist/config/plugins/ConfigPluginRegistry.d.ts.map +1 -1
  7. package/dist/config/plugins/TomlConfigPlugin.d.ts +1 -1
  8. package/dist/config/plugins/TomlConfigPlugin.d.ts.map +1 -1
  9. package/dist/config/plugins/YamlConfigPlugin.d.ts +1 -1
  10. package/dist/config/plugins/YamlConfigPlugin.d.ts.map +1 -1
  11. package/dist/config/plugins/index.d.ts +4 -4
  12. package/dist/config/plugins/index.d.ts.map +1 -1
  13. package/dist/core/ArgParser.d.ts +14 -3
  14. package/dist/core/ArgParser.d.ts.map +1 -1
  15. package/dist/core/ArgParserBase.d.ts.map +1 -1
  16. package/dist/core/log-path-utils.d.ts +59 -0
  17. package/dist/core/log-path-utils.d.ts.map +1 -0
  18. package/dist/core/types.d.ts +1 -1
  19. package/dist/core/types.d.ts.map +1 -1
  20. package/dist/dxt/DxtGenerator-testUtils.d.ts +22 -0
  21. package/dist/dxt/DxtGenerator-testUtils.d.ts.map +1 -0
  22. package/dist/dxt/DxtGenerator.d.ts +11 -65
  23. package/dist/dxt/DxtGenerator.d.ts.map +1 -1
  24. package/dist/index.cjs +799 -1260
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.ts +5 -4
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.min.mjs +6303 -6736
  29. package/dist/index.min.mjs.map +1 -1
  30. package/dist/index.mjs +799 -1260
  31. package/dist/index.mjs.map +1 -1
  32. package/dist/mcp/ArgParserMcp.d.ts.map +1 -1
  33. package/dist/mcp/mcp-notifications.d.ts +4 -4
  34. package/dist/mcp/mcp-notifications.d.ts.map +1 -1
  35. package/dist/mcp/mcp-prompts.d.ts.map +1 -1
  36. package/dist/mcp/mcp-protocol-versions.d.ts +11 -11
  37. package/dist/mcp/mcp-protocol-versions.d.ts.map +1 -1
  38. package/dist/mcp/mcp-resources.d.ts.map +1 -1
  39. package/dist/testing/fuzzy-test-cli.d.ts.map +1 -1
  40. package/dist/testing/fuzzy-tester.d.ts.map +1 -1
  41. package/package.json +2 -3
  42. package/dist/assets/tsdown.dxt.config.ts +0 -37
package/dist/index.cjs CHANGED
@@ -325,7 +325,9 @@ class JsonConfigPlugin extends ConfigPlugin {
325
325
  const { _meta, ...config } = parsed;
326
326
  return config;
327
327
  } catch (error) {
328
- throw new Error(`Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}`);
328
+ throw new Error(
329
+ `Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}`
330
+ );
329
331
  }
330
332
  }
331
333
  generate(_config, flags, parsedArgs) {
@@ -541,7 +543,9 @@ function enableConfigPlugins(pluginNames) {
541
543
  globalConfigPluginRegistry.registerPlugin(tomlPlugin);
542
544
  }
543
545
  } catch (error) {
544
- console.warn(`Failed to enable TOML plugin: ${error instanceof Error ? error.message : String(error)}`);
546
+ console.warn(
547
+ `Failed to enable TOML plugin: ${error instanceof Error ? error.message : String(error)}`
548
+ );
545
549
  }
546
550
  break;
547
551
  case "yaml":
@@ -552,7 +556,9 @@ function enableConfigPlugins(pluginNames) {
552
556
  globalConfigPluginRegistry.registerPlugin(yamlPlugin);
553
557
  }
554
558
  } catch (error) {
555
- console.warn(`Failed to enable YAML plugin: ${error instanceof Error ? error.message : String(error)}`);
559
+ console.warn(
560
+ `Failed to enable YAML plugin: ${error instanceof Error ? error.message : String(error)}`
561
+ );
556
562
  }
557
563
  break;
558
564
  default:
@@ -576,14 +582,18 @@ class ConfigurationManager {
576
582
  } else if (appName && appName !== "Argument Parser") {
577
583
  baseName = appName;
578
584
  }
579
- baseName = baseName.split(/[\s-_]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
585
+ baseName = baseName.split(/[\s-_]+/).map(
586
+ (word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
587
+ ).join("");
580
588
  return `${baseName}.env`;
581
589
  }
582
590
  /**
583
591
  * Handles the --s-save-to-env system flag at the final parser level
584
592
  */
585
593
  handleSaveToEnvFlag(processArgs, parserChain) {
586
- const saveToEnvIndex = processArgs.findIndex((arg) => arg === "--s-save-to-env");
594
+ const saveToEnvIndex = processArgs.findIndex(
595
+ (arg) => arg === "--s-save-to-env"
596
+ );
587
597
  if (saveToEnvIndex !== -1) {
588
598
  let filePath;
589
599
  if (saveToEnvIndex + 1 < processArgs.length) {
@@ -609,7 +619,11 @@ class ConfigurationManager {
609
619
  const finalParser = parserChain[parserChain.length - 1];
610
620
  const parsedArgs = finalParser.getLastParseResult();
611
621
  if (!parsedArgs) {
612
- console.log(simpleChalk.yellow("No parsed arguments available. Run the command first to generate configuration."));
622
+ console.log(
623
+ simpleChalk.yellow(
624
+ "No parsed arguments available. Run the command first to generate configuration."
625
+ )
626
+ );
613
627
  return;
614
628
  }
615
629
  const allFlags = [];
@@ -642,10 +656,18 @@ class ConfigurationManager {
642
656
  fs__namespace.writeFileSync(filePath, content, "utf8");
643
657
  console.log(simpleChalk.green(`✅ Configuration saved to: ${filePath}`));
644
658
  console.log(simpleChalk.gray(`Format: ${ext || ".env"}`));
645
- console.log(simpleChalk.gray(`Flags saved: ${Object.keys(parsedArgs.args).length}`));
659
+ console.log(
660
+ simpleChalk.gray(`Flags saved: ${Object.keys(parsedArgs.args).length}`)
661
+ );
646
662
  } catch (error) {
647
- console.error(simpleChalk.red(`❌ Failed to save configuration: ${error instanceof Error ? error.message : String(error)}`));
648
- throw new Error(`Failed to save configuration: ${error instanceof Error ? error.message : String(error)}`);
663
+ console.error(
664
+ simpleChalk.red(
665
+ `❌ Failed to save configuration: ${error instanceof Error ? error.message : String(error)}`
666
+ )
667
+ );
668
+ throw new Error(
669
+ `Failed to save configuration: ${error instanceof Error ? error.message : String(error)}`
670
+ );
649
671
  }
650
672
  }
651
673
  /**
@@ -682,7 +704,11 @@ class ConfigurationManager {
682
704
  }
683
705
  return this.convertConfigToFlagValues(rawConfig, parserChain);
684
706
  } catch (error) {
685
- console.warn(simpleChalk.yellow(`Warning: Could not load config file ${filePath}: ${error instanceof Error ? error.message : String(error)}`));
707
+ console.warn(
708
+ simpleChalk.yellow(
709
+ `Warning: Could not load config file ${filePath}: ${error instanceof Error ? error.message : String(error)}`
710
+ )
711
+ );
686
712
  return {};
687
713
  }
688
714
  }
@@ -716,7 +742,9 @@ class ConfigurationManager {
716
742
  if (plugin) {
717
743
  return plugin.parse(content);
718
744
  }
719
- console.warn("YAML plugin not available, using simple parser. Install js-yaml and enable YAML plugin for full support.");
745
+ console.warn(
746
+ "YAML plugin not available, using simple parser. Install js-yaml and enable YAML plugin for full support."
747
+ );
720
748
  const config = {};
721
749
  const lines = content.split("\n");
722
750
  let currentKey = null;
@@ -767,7 +795,9 @@ class ConfigurationManager {
767
795
  try {
768
796
  return JSON.parse(content) || {};
769
797
  } catch (error) {
770
- throw new Error(`Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}`);
798
+ throw new Error(
799
+ `Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}`
800
+ );
771
801
  }
772
802
  }
773
803
  /**
@@ -778,7 +808,9 @@ class ConfigurationManager {
778
808
  if (plugin) {
779
809
  return plugin.parse(content);
780
810
  }
781
- console.warn("TOML plugin not available, using simple parser. Install smol-toml and enable TOML plugin for full support.");
811
+ console.warn(
812
+ "TOML plugin not available, using simple parser. Install smol-toml and enable TOML plugin for full support."
813
+ );
782
814
  const config = {};
783
815
  const lines = content.split("\n");
784
816
  for (const line of lines) {
@@ -809,13 +841,19 @@ class ConfigurationManager {
809
841
  for (const [key, value] of Object.entries(rawConfig)) {
810
842
  let flag = allFlags.find((f) => f["name"] === key);
811
843
  if (!flag) {
812
- flag = allFlags.find((f) => f["name"].toLowerCase() === key.toLowerCase());
844
+ flag = allFlags.find(
845
+ (f) => f["name"].toLowerCase() === key.toLowerCase()
846
+ );
813
847
  }
814
848
  if (flag) {
815
849
  try {
816
850
  flagValues[flag["name"]] = this.convertValueToFlagType(value, flag);
817
851
  } catch (error) {
818
- console.warn(simpleChalk.yellow(`Warning: Could not convert config value for flag '${key}': ${error instanceof Error ? error.message : String(error)}`));
852
+ console.warn(
853
+ simpleChalk.yellow(
854
+ `Warning: Could not convert config value for flag '${key}': ${error instanceof Error ? error.message : String(error)}`
855
+ )
856
+ );
819
857
  }
820
858
  }
821
859
  }
@@ -852,17 +890,23 @@ class ConfigurationManager {
852
890
  }
853
891
  const num = Number(value);
854
892
  if (isNaN(num)) {
855
- throw new Error(`Cannot convert '${value}' to number for flag '${flag["name"]}'`);
893
+ throw new Error(
894
+ `Cannot convert '${value}' to number for flag '${flag["name"]}'`
895
+ );
856
896
  }
857
897
  return num;
858
898
  } else if (isBooleanType) {
859
899
  if (typeof value === "boolean") return value;
860
900
  if (typeof value === "string") {
861
901
  const lower = value.toLowerCase();
862
- if (lower === "true" || lower === "1" || lower === "yes" || lower === "on") return true;
863
- if (lower === "false" || lower === "0" || lower === "no" || lower === "off") return false;
902
+ if (lower === "true" || lower === "1" || lower === "yes" || lower === "on")
903
+ return true;
904
+ if (lower === "false" || lower === "0" || lower === "no" || lower === "off")
905
+ return false;
864
906
  }
865
- throw new Error(`Cannot convert '${value}' to boolean for flag '${flag["name"]}'`);
907
+ throw new Error(
908
+ `Cannot convert '${value}' to boolean for flag '${flag["name"]}'`
909
+ );
866
910
  } else if (flagType === "table") {
867
911
  if (Array.isArray(value)) return value;
868
912
  if (typeof value === "string") {
@@ -873,13 +917,17 @@ class ConfigurationManager {
873
917
  return value.split(",").map((v) => v.trim());
874
918
  }
875
919
  }
876
- throw new Error(`Cannot convert '${value}' to table for flag '${flag["name"]}'`);
920
+ throw new Error(
921
+ `Cannot convert '${value}' to table for flag '${flag["name"]}'`
922
+ );
877
923
  } else {
878
924
  if (typeof flagType === "function") {
879
925
  try {
880
926
  return flagType(value);
881
927
  } catch (error) {
882
- throw new Error(`Custom type conversion failed for flag '${flag["name"]}': ${error instanceof Error ? error.message : String(error)}`);
928
+ throw new Error(
929
+ `Custom type conversion failed for flag '${flag["name"]}': ${error instanceof Error ? error.message : String(error)}`
930
+ );
883
931
  }
884
932
  }
885
933
  return String(value);
@@ -954,7 +1002,9 @@ class ConfigurationManager {
954
1002
  if (Array.isArray(value)) {
955
1003
  lines.push(`${flag["name"]}:`);
956
1004
  for (const item of value) {
957
- lines.push(` - ${typeof item === "string" && item.includes(" ") ? `"${item}"` : item}`);
1005
+ lines.push(
1006
+ ` - ${typeof item === "string" && item.includes(" ") ? `"${item}"` : item}`
1007
+ );
958
1008
  }
959
1009
  } else if (typeof value === "string" && value.includes(" ")) {
960
1010
  lines.push(`${flag["name"]}: "${value}"`);
@@ -1188,64 +1238,22 @@ function createOutputSchema(pattern2) {
1188
1238
  }
1189
1239
  return OutputSchemaPatterns.successError();
1190
1240
  }
1191
- class DxtGenerator {
1192
- constructor(argParserInstance) {
1241
+ class DxtGeneratorTestUtils {
1242
+ constructor(argParserInstance, extractMcpServerInfo, handleExit) {
1193
1243
  this.argParserInstance = argParserInstance;
1194
- }
1195
- /**
1196
- * Helper method to handle exit logic based on autoExit setting
1197
- */
1198
- _handleExit(exitCode, message, type2, data2) {
1199
- const result = {
1200
- success: exitCode === 0,
1201
- exitCode,
1202
- message,
1203
- type: type2 || (exitCode === 0 ? "success" : "error"),
1204
- shouldExit: true,
1205
- data: data2
1206
- };
1207
- if (this.argParserInstance.getAutoExit() && typeof process === "object" && typeof process.exit === "function") {
1208
- process.exit(exitCode);
1209
- }
1210
- return result;
1211
- }
1212
- /**
1213
- * Handles the --s-build-dxt system flag to generate DXT packages for MCP servers
1214
- */
1215
- async handleBuildDxtFlag(processArgs, buildDxtIndex) {
1216
- var _a, _b, _c;
1217
- try {
1218
- 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"));
1219
- if (isTestMode) {
1220
- return await this.handleTestModeDxtGeneration(processArgs, buildDxtIndex);
1221
- }
1222
- const entryPointFile = process.argv[1];
1223
- if (!entryPointFile || !fs__namespace.existsSync(entryPointFile)) {
1224
- console.error(simpleChalk.red(`Error: Entry point file not found: ${entryPointFile}`));
1225
- return this._handleExit(1, "Entry point file not found", "error");
1226
- }
1227
- const outputDir = processArgs[buildDxtIndex + 1] || "./dxt";
1228
- console.log(simpleChalk.cyan(`
1229
- 🔧 Building DXT package for entry point: ${path__namespace.basename(entryPointFile)}`));
1230
- console.log(simpleChalk.gray(`Output directory: ${outputDir}`));
1231
- await this.buildDxtWithTsdown(entryPointFile, outputDir);
1232
- console.log(simpleChalk.green(`
1233
- ✅ DXT package generation completed!`));
1234
- return this._handleExit(0, "DXT package generation completed", "success", { entryPoint: entryPointFile, outputDir });
1235
- } catch (error) {
1236
- console.error(simpleChalk.red(`Error generating DXT package: ${error instanceof Error ? error.message : String(error)}`));
1237
- return this._handleExit(1, `Error generating DXT package: ${error instanceof Error ? error.message : String(error)}`, "error");
1238
- }
1244
+ this.extractMcpServerInfo = extractMcpServerInfo;
1245
+ this.handleExit = handleExit;
1239
1246
  }
1240
1247
  /**
1241
1248
  * Handles DXT generation in test mode by creating mock DXT package structure
1249
+ * This method creates simplified mock files for testing purposes
1242
1250
  */
1243
1251
  async handleTestModeDxtGeneration(processArgs, buildDxtIndex) {
1244
1252
  try {
1245
1253
  const outputDir = processArgs[buildDxtIndex + 1] || "./dxt-packages";
1246
1254
  const mcpTools = this.argParserInstance.toMcpTools();
1247
1255
  if (mcpTools.length === 0) {
1248
- return this._handleExit(0, "No MCP servers found", "success");
1256
+ return this.handleExit(0, "No MCP servers found", "success");
1249
1257
  }
1250
1258
  const serverInfo = this.extractMcpServerInfo();
1251
1259
  const folderName = `${serverInfo.name.replace(/[^a-zA-Z0-9_-]/g, "_")}-dxt`;
@@ -1274,7 +1282,10 @@ class DxtGenerator {
1274
1282
  })),
1275
1283
  icon: "logo.jpg"
1276
1284
  };
1277
- fs__namespace.writeFileSync(path__namespace.join(buildDir, "manifest.json"), JSON.stringify(manifest, null, 2));
1285
+ fs__namespace.writeFileSync(
1286
+ path__namespace.join(buildDir, "manifest.json"),
1287
+ JSON.stringify(manifest, null, 2)
1288
+ );
1278
1289
  const packageJson = {
1279
1290
  name: serverInfo.name,
1280
1291
  version: serverInfo.version,
@@ -1282,7 +1293,10 @@ class DxtGenerator {
1282
1293
  main: "index.mjs",
1283
1294
  type: "module"
1284
1295
  };
1285
- fs__namespace.writeFileSync(path__namespace.join(buildDir, "package.json"), JSON.stringify(packageJson, null, 2));
1296
+ fs__namespace.writeFileSync(
1297
+ path__namespace.join(buildDir, "package.json"),
1298
+ JSON.stringify(packageJson, null, 2)
1299
+ );
1286
1300
  const readme = `# ${serverInfo.name}
1287
1301
 
1288
1302
  ${serverInfo.description}
@@ -1291,88 +1305,172 @@ Generated by @alcyone-labs/arg-parser`;
1291
1305
  fs__namespace.writeFileSync(path__namespace.join(buildDir, "README.md"), readme);
1292
1306
  const buildScript = `#!/bin/bash
1293
1307
  echo "Mock DXT build script for ${serverInfo.name}"`;
1294
- fs__namespace.writeFileSync(path__namespace.join(buildDir, "build-dxt-package.sh"), buildScript);
1295
- return this._handleExit(0, "DXT package generation completed", "success", {
1308
+ fs__namespace.writeFileSync(
1309
+ path__namespace.join(buildDir, "build-dxt-package.sh"),
1310
+ buildScript
1311
+ );
1312
+ return this.handleExit(0, "DXT package generation completed", "success", {
1296
1313
  entryPoint: "test-mode",
1297
1314
  outputDir: buildDir
1298
1315
  });
1299
1316
  } catch (error) {
1300
- return this._handleExit(1, `Test mode DXT generation failed: ${error instanceof Error ? error.message : String(error)}`, "error");
1317
+ return this.handleExit(
1318
+ 1,
1319
+ `Test mode DXT generation failed: ${error instanceof Error ? error.message : String(error)}`,
1320
+ "error"
1321
+ );
1301
1322
  }
1302
1323
  }
1303
1324
  /**
1304
- * Generates a DXT package for the unified MCP server
1305
- * Now supports both withMcp() configuration and legacy addMcpSubCommand()
1325
+ * Checks if the current environment is in test mode
1326
+ * Used to determine whether to use test utilities or production code
1306
1327
  */
1307
- async generateDxtPackage(mcpSubCommand, outputDir) {
1308
- const serverInfo = this.extractMcpServerInfo(mcpSubCommand);
1309
- const tools = this.generateMcpToolsForDxt(mcpSubCommand);
1310
- const finalOutputDir = outputDir || "./dxt-packages";
1311
- const folderName = `${serverInfo.name.replace(/[^a-zA-Z0-9_-]/g, "_")}-dxt`;
1312
- const buildDir = path__namespace.join(finalOutputDir, folderName);
1313
- if (!fs__namespace.existsSync(buildDir)) {
1314
- fs__namespace.mkdirSync(buildDir, { recursive: true });
1315
- }
1316
- const serverDir = path__namespace.join(buildDir, "server");
1317
- if (!fs__namespace.existsSync(serverDir)) {
1318
- fs__namespace.mkdirSync(serverDir, { recursive: true });
1319
- }
1320
- const logoFilename = await this.addLogoToFolder(buildDir, serverInfo);
1321
- const manifest = this.createDxtManifest(serverInfo, tools, mcpSubCommand, logoFilename);
1322
- this.validateDxtManifest(manifest);
1323
- fs__namespace.writeFileSync(path__namespace.join(buildDir, "manifest.json"), JSON.stringify(manifest, null, 2));
1324
- this.addOriginalCliToFolder(buildDir);
1325
- const bundledCliPath = await this.bundleOriginalCliWithTsdown(serverDir);
1326
- const serverScript = this.createServerScript(serverInfo, bundledCliPath);
1327
- const serverScriptPath = path__namespace.join(serverDir, "index.mjs");
1328
- fs__namespace.writeFileSync(serverScriptPath, serverScript);
1329
- try {
1330
- fs__namespace.chmodSync(serverScriptPath, 493);
1331
- } catch (error) {
1332
- console.warn("⚠ Could not set executable permission on server script:", error instanceof Error ? error.message : String(error));
1333
- }
1334
- const packageJson = this.createDxtPackageJson(serverInfo);
1335
- fs__namespace.writeFileSync(path__namespace.join(buildDir, "package.json"), JSON.stringify(packageJson, null, 2));
1336
- const readme = this.createDxtReadme(serverInfo);
1337
- fs__namespace.writeFileSync(path__namespace.join(buildDir, "README.md"), readme);
1338
- const buildScript = this.createSimpleBuildScript(serverInfo);
1339
- fs__namespace.writeFileSync(path__namespace.join(buildDir, "build-dxt.sh"), buildScript);
1340
- const dxtIgnore = this.createDxtIgnore();
1341
- fs__namespace.writeFileSync(path__namespace.join(buildDir, ".dxtignore"), dxtIgnore);
1342
- try {
1343
- fs__namespace.chmodSync(path__namespace.join(buildDir, "build-dxt.sh"), 493);
1344
- } 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);
1345
1351
  }
1346
- console.log(simpleChalk.green(` ✓ Generated DXT package folder: ${folderName}`));
1347
- console.log(simpleChalk.gray(` Server: ${serverInfo.name} v${serverInfo.version}`));
1348
- console.log(simpleChalk.gray(` Tools: ${tools.length} tool(s)`));
1349
- console.log(simpleChalk.gray(` Location: ${buildDir}`));
1350
- console.log(simpleChalk.cyan(`
1351
- 📦 Creating DXT package using Anthropic's dxt pack...`));
1352
- console.log(simpleChalk.cyan(`
1353
- 📋 Manual steps to create your DXT package:`));
1354
- console.log(simpleChalk.white(` cd ${path__namespace.relative(process.cwd(), buildDir)}`));
1355
- console.log(simpleChalk.white(` ./build-dxt.sh`));
1352
+ return result;
1356
1353
  }
1357
1354
  /**
1358
- * Reads package.json to extract fallback information for DXT manifest
1355
+ * Handles the --s-build-dxt system flag to generate DXT packages for MCP servers
1359
1356
  */
1360
- readPackageJsonInfo() {
1357
+ async handleBuildDxtFlag(processArgs, buildDxtIndex) {
1361
1358
  try {
1362
- const packageJsonPath = path__namespace.join(process.cwd(), "package.json");
1363
- if (fs__namespace.existsSync(packageJsonPath)) {
1364
- const packageContent = fs__namespace.readFileSync(packageJsonPath, "utf-8");
1365
- const packageData = JSON.parse(packageContent);
1366
- return {
1367
- author: packageData.author,
1368
- repository: packageData.repository,
1369
- license: packageData.license,
1370
- homepage: packageData.homepage
1371
- };
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
+ );
1372
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
+ );
1373
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
+ );
1374
1473
  }
1375
- return null;
1376
1474
  }
1377
1475
  /**
1378
1476
  * Extracts server information from MCP configuration
@@ -1411,7 +1509,9 @@ echo "Mock DXT build script for ${serverInfo.name}"`;
1411
1509
  toolOptions = mcpConfig.toolOptions;
1412
1510
  }
1413
1511
  }
1414
- const mcpTools = this.argParserInstance.toMcpTools(toolOptions);
1512
+ const mcpTools = this.argParserInstance.toMcpTools(
1513
+ toolOptions
1514
+ );
1415
1515
  return mcpTools.map((tool) => ({
1416
1516
  name: tool.name,
1417
1517
  description: tool.description
@@ -1435,511 +1535,29 @@ echo "Mock DXT build script for ${serverInfo.name}"`;
1435
1535
  });
1436
1536
  }
1437
1537
  }
1438
- return tools.length > 0 ? tools : [{
1439
- name: "main",
1440
- description: "Main command tool"
1441
- }];
1442
- } catch (error) {
1443
- console.warn(simpleChalk.yellow(`Warning: Could not generate detailed tool list: ${error instanceof Error ? error.message : String(error)}`));
1444
- return [{
1445
- name: "main",
1446
- description: "Main command tool"
1447
- }];
1448
- }
1449
- }
1450
- createDxtManifest(serverInfo, tools, mcpSubCommand, logoFilename) {
1451
- var _a;
1452
- const packageInfo = this.readPackageJsonInfo();
1453
- let author = serverInfo.author;
1454
- if (!author && (packageInfo == null ? void 0 : packageInfo.author)) {
1455
- if (typeof packageInfo.author === "string") {
1456
- const match = packageInfo.author.match(/^([^<]+?)(?:\s*<([^>]+)>)?$/);
1457
- if (match) {
1458
- author = {
1459
- name: match[1].trim(),
1460
- email: (_a = match[2]) == null ? void 0 : _a.trim()
1461
- };
1462
- } else {
1463
- author = { name: packageInfo.author };
1464
- }
1465
- } else {
1466
- author = packageInfo.author;
1467
- }
1468
- }
1469
- if (!author) {
1470
- throw new Error("DXT manifest requires author information. Please provide it via withMcp() serverInfo.author, addMcpSubCommand serverInfo.author, or in package.json");
1471
- }
1472
- const cliArgs = this.generateCliArgsForDxt(mcpSubCommand);
1473
- const { envVars, userConfig } = this.generateEnvAndUserConfig();
1474
- const manifest = {
1475
- dxt_version: "0.1",
1476
- name: serverInfo.name,
1477
- version: serverInfo.version,
1478
- description: serverInfo.description || "MCP server generated from ArgParser",
1479
- author,
1480
- server: {
1481
- type: "node",
1482
- entry_point: "server/index.mjs",
1483
- mcp_config: {
1484
- command: "node",
1485
- args: ["${__dirname}/server/index.mjs", ...cliArgs],
1486
- env: envVars
1487
- }
1488
- },
1489
- tools: tools.map((tool) => ({
1490
- name: tool.name,
1491
- description: tool.description
1492
- }))
1493
- };
1494
- if (logoFilename) {
1495
- manifest.icon = logoFilename;
1496
- }
1497
- if (userConfig && Object.keys(userConfig).length > 0) {
1498
- manifest.user_config = userConfig;
1499
- }
1500
- if (serverInfo.repository || (packageInfo == null ? void 0 : packageInfo.repository)) {
1501
- manifest.repository = serverInfo.repository || (packageInfo == null ? void 0 : packageInfo.repository);
1502
- }
1503
- if (serverInfo.license || (packageInfo == null ? void 0 : packageInfo.license)) {
1504
- manifest.license = serverInfo.license || (packageInfo == null ? void 0 : packageInfo.license);
1505
- }
1506
- if (serverInfo.homepage || (packageInfo == null ? void 0 : packageInfo.homepage)) {
1507
- manifest.homepage = serverInfo.homepage || (packageInfo == null ? void 0 : packageInfo.homepage);
1508
- }
1509
- return manifest;
1510
- }
1511
- validateDxtManifest(manifest) {
1512
- const errors = [];
1513
- if (!manifest.dxt_version) errors.push("Missing required field: dxt_version");
1514
- if (!manifest.name) errors.push("Missing required field: name");
1515
- if (!manifest.version) errors.push("Missing required field: version");
1516
- if (!manifest.server) errors.push("Missing required field: server");
1517
- if (!manifest.author) errors.push("Missing required field: author");
1518
- if (manifest.server) {
1519
- if (!manifest.server.type) errors.push("Missing required field: server.type");
1520
- if (!manifest.server.entry_point) errors.push("Missing required field: server.entry_point");
1521
- if (!manifest.server.mcp_config) errors.push("Missing required field: server.mcp_config");
1522
- if (manifest.server.mcp_config) {
1523
- if (!manifest.server.mcp_config.command) errors.push("Missing required field: server.mcp_config.command");
1524
- if (!manifest.server.mcp_config.args || !Array.isArray(manifest.server.mcp_config.args)) {
1525
- errors.push("Missing or invalid field: server.mcp_config.args (must be array)");
1538
+ return tools.length > 0 ? tools : [
1539
+ {
1540
+ name: "main",
1541
+ description: "Main command tool"
1526
1542
  }
1527
- }
1528
- }
1529
- if (manifest.author && typeof manifest.author === "object") {
1530
- if (!manifest.author.name) errors.push("Missing required field: author.name");
1531
- }
1532
- if (manifest.dxt_version && manifest.dxt_version !== "0.1") {
1533
- errors.push("Unsupported dxt_version: only '0.1' is currently supported");
1534
- }
1535
- if (errors.length > 0) {
1536
- throw new Error(`DXT manifest validation failed:
1537
- ${errors.map((e) => ` - ${e}`).join("\n")}`);
1538
- }
1539
- }
1540
- createServerScript(serverInfo, bundledCliPath) {
1541
- const cliImportPath = bundledCliPath || "original-cli.mjs";
1542
- return `#!/usr/bin/env node
1543
-
1544
- // Generated MCP server for ${serverInfo.name}
1545
- // This server uses @alcyone-labs/arg-parser's built-in MCP functionality for full protocol compliance
1546
-
1547
- // FIRST: Set up MCP-safe logging to prevent STDOUT contamination
1548
- import { createMcpLogger } from '@alcyone-labs/simple-mcp-logger';
1549
-
1550
- // Auto-detect MCP mode and hijack console to prevent protocol corruption
1551
- const mcpLogger = createMcpLogger('${serverInfo.name}');
1552
- globalThis.console = mcpLogger;
1553
-
1554
- // Now import the CLI which already has MCP functionality configured
1555
- import originalCli from './${cliImportPath}';
1556
-
1557
- // Server configuration
1558
- const serverInfo = ${JSON.stringify(serverInfo, null, 2)};
1559
-
1560
- // Use mcpError for debugging output (safe STDERR, visible in client logs)
1561
- console.error(\`MCP Server: \${serverInfo.name} v\${serverInfo.version}\`);
1562
- console.error(\`Description: \${serverInfo.description}\`);
1563
- console.error(\`Generated from @alcyone-labs/arg-parser with built-in MCP functionality\`);
1564
- ${bundledCliPath ? "console.error(`Using bundled CLI for autonomous execution`);" : ""}
1565
-
1566
- // The original CLI has MCP functionality configured via withMcp() or addMcpSubCommand()
1567
- // We use the centralized --s-mcp-serve system flag to start the unified MCP server
1568
-
1569
- // Start the MCP server using the library's built-in centralized serving
1570
- // This works with both withMcp() configuration and legacy addMcpSubCommand() setups
1571
- originalCli.parse(['--s-mcp-serve']);
1572
- `;
1573
- }
1574
- createDxtPackageJson(serverInfo) {
1575
- const useLocalBuild = process.env["LOCAL_BUILD"] === "1";
1576
- const argParserDependency = useLocalBuild ? "file:../../arg-parser-local.tgz" : "^1.3.0";
1577
- let originalDependencies = {};
1578
- try {
1579
- const originalPackageJsonPath = path__namespace.join(process.cwd(), "package.json");
1580
- if (fs__namespace.existsSync(originalPackageJsonPath)) {
1581
- const originalPackageJson = JSON.parse(fs__namespace.readFileSync(originalPackageJsonPath, "utf8"));
1582
- originalDependencies = originalPackageJson.dependencies || {};
1583
- }
1543
+ ];
1584
1544
  } catch (error) {
1585
- console.warn("⚠ Could not read original package.json for dependencies:", error instanceof Error ? error.message : String(error));
1586
- }
1587
- const dependencies2 = {
1588
- ...originalDependencies,
1589
- "@alcyone-labs/arg-parser": argParserDependency,
1590
- "@alcyone-labs/simple-mcp-logger": "^1.0.0",
1591
- "@modelcontextprotocol/sdk": "^1.15.0",
1592
- "zod": "^3.22.4"
1593
- };
1594
- const devDependencies = {
1595
- "tsup": "^8.3.5"
1596
- };
1597
- Object.keys(dependencies2).forEach((key) => {
1598
- const depValue = dependencies2[key];
1599
- if (key !== "@alcyone-labs/arg-parser" && typeof depValue === "string" && depValue.startsWith("file:")) {
1600
- delete dependencies2[key];
1601
- console.warn(`⚠ Removed file: dependency ${key} from DXT package (not suitable for distribution)`);
1602
- }
1603
- });
1604
- return {
1605
- name: serverInfo.name,
1606
- version: serverInfo.version,
1607
- description: serverInfo.description,
1608
- main: "server/index.mjs",
1609
- type: "module",
1610
- scripts: {
1611
- start: "node server/index.mjs",
1612
- "build-dxt": "./build-dxt.sh"
1613
- },
1614
- dependencies: dependencies2,
1615
- devDependencies,
1616
- engines: {
1617
- node: ">=22.0.0"
1618
- },
1619
- author: serverInfo.author,
1620
- license: serverInfo.license || "MIT",
1621
- repository: serverInfo.repository
1622
- };
1623
- }
1624
- /**
1625
- * Creates a .dxtignore file to exclude build artifacts and unnecessary files
1626
- */
1627
- createDxtIgnore() {
1628
- return `# DXT ignore file - exclude these files from the DXT package
1629
- # Generated by @alcyone-labs/arg-parser
1630
-
1631
- # Build artifacts and logs
1632
- *.log
1633
- *.tmp
1634
- temp-dxt-build/
1635
-
1636
- # Build scripts (not needed in final package)
1637
- build-dxt.sh
1638
- arg-parser-local.tgz
1639
- tsup.config.autonomous.js
1640
- tsdown.config.mjs
1641
-
1642
- # Original files (replaced by bundled autonomous build)
1643
- server/index.original.mjs
1644
- server/*.autonomous.mjs
1645
-
1646
- # NOTE: server/original-cli.mjs is NOT excluded because it's needed for the MCP server to function
1647
- # The bundled version (if created) will be server/original-cli.bundled.mjs
1648
-
1649
- # NOTE: node_modules/ is NOT excluded because TSDown bundling may not be 100% autonomous
1650
- # If bundling is successful, node_modules won't be needed, but we include it as fallback
1651
- # The bundled server/index.mjs should be fully autonomous and not require node_modules
1652
-
1653
- # Development files
1654
- .git/
1655
- .gitignore
1656
- .env
1657
- .env.*
1658
-
1659
- # OS files
1660
- .DS_Store
1661
- Thumbs.db
1662
-
1663
- # IDE files
1664
- .vscode/
1665
- .idea/
1666
- *.swp
1667
- *.swo
1668
- `;
1669
- }
1670
- /**
1671
- * Creates a simple build script that uses TSDown bundling and Anthropic's dxt pack
1672
- */
1673
- createSimpleBuildScript(serverInfo) {
1674
- return `#!/bin/bash
1675
-
1676
- # Simple DXT Build Script for ${serverInfo.name}
1677
- # Generated by @alcyone-labs/arg-parser with TSDown bundling
1678
-
1679
- set -e
1680
-
1681
- echo "📦 Creating DXT package for ${serverInfo.name}..."
1682
-
1683
- # Step 1: Make server executable (required for MCP)
1684
- echo "🔧 Making server executable..."
1685
- chmod +x server/index.mjs
1686
-
1687
- # Step 2: Handle local development dependencies
1688
- if grep -q "file:.*arg-parser-local.tgz" package.json; then
1689
- echo "🔧 Checking for local package tarball..."
1690
-
1691
- # Check if the tarball exists in the parent directory
1692
- if [ -f "../../arg-parser-local.tgz" ]; then
1693
- echo "✅ Found local package tarball: ../../arg-parser-local.tgz"
1694
- else
1695
- echo "⚠️ Local tarball not found, falling back to npm registry"
1696
- echo "💡 To use local build, run: cd /path/to/arg-parser && npm pack && cp *.tgz examples/community/canny-cli/"
1697
-
1698
- # Replace with npm version
1699
- sed -i.bak 's|"file:.*arg-parser-local.tgz"|"^1.3.0"|g' package.json 2>/dev/null || \\
1700
- sed -i 's|"file:.*arg-parser-local.tgz"|"^1.3.0"|g' package.json
1701
- fi
1702
- fi
1703
-
1704
- # Step 3: Install dependencies (for runtime only, bundling was done during generation)
1705
- echo "📦 Installing dependencies..."
1706
- npm install
1707
-
1708
- # Step 4: Validate manifest
1709
- echo "🔍 Validating DXT manifest..."
1710
- if command -v npx >/dev/null 2>&1; then
1711
- if npx @anthropic-ai/dxt validate manifest.json; then
1712
- echo "✅ DXT manifest validation passed"
1713
- else
1714
- echo "❌ DXT manifest validation failed"
1715
- exit 1
1716
- fi
1717
- else
1718
- echo "⚠️ npx not found, skipping DXT validation"
1719
- fi
1720
-
1721
- # Step 5: Create DXT package using Anthropic's official packer
1722
- echo "📦 Creating DXT package..."
1723
- if command -v npx >/dev/null 2>&1; then
1724
- # Use dxt pack directly with .dxtignore for clean packaging
1725
- npx @anthropic-ai/dxt pack . "${serverInfo.name}.dxt"
1726
- else
1727
- # Fallback to standard zip if npx not available
1728
- echo "⚠️ npx not found, using zip fallback"
1729
- zip -r "${serverInfo.name}.dxt" . -x "node_modules/*" "*.log" ".git/*" "build-dxt.sh" "temp-dxt-build/*"
1730
- fi
1731
-
1732
- # Step 6: Sign the DXT package (optional)
1733
- echo "🔐 Signing DXT package..."
1734
- if command -v npx >/dev/null 2>&1 && command -v openssl >/dev/null 2>&1; then
1735
- if npx @anthropic-ai/dxt sign "${serverInfo.name}.dxt" --self-signed; then
1736
- echo "✅ DXT package signed successfully"
1737
- else
1738
- echo "⚠️ DXT signing failed, but package is still usable"
1739
- fi
1740
- else
1741
- echo "⚠️ npx or openssl not found, skipping DXT signing"
1742
- fi
1743
-
1744
- echo "✅ DXT package created: ${serverInfo.name}.dxt"
1745
- echo "🎯 This package includes bundled CLI with all dependencies!"
1746
- echo ""
1747
- echo "🎉 Installation Instructions:"
1748
- echo "You can now take the file '${serverInfo.name}.dxt' and install it on Claude Desktop"
1749
- echo "or supporting applications by using drag & drop on the Extensions Settings page,"
1750
- echo "or directly pointing the file selector to this file."
1751
- echo ""
1752
- echo "📁 DXT file location: $(pwd)/${serverInfo.name}.dxt"
1753
- `;
1754
- }
1755
- createDxtReadme(serverInfo) {
1756
- return `# ${serverInfo.name}
1757
-
1758
- ${serverInfo.description}
1759
-
1760
- ## Installation
1761
-
1762
- This is a Desktop Extension (DXT) package generated from @alcyone-labs/arg-parser.
1763
-
1764
- ### Automatic Installation
1765
- Open this .dxt file with Claude Desktop or other DXT-compatible applications for single-click installation.
1766
-
1767
- ### Manual Installation
1768
- 1. Extract the .dxt file (it's a ZIP archive)
1769
- 2. Run \`npm install\` to install dependencies
1770
- 3. Start the server with \`npm start\`
1771
-
1772
- ## Tools
1773
-
1774
- This MCP server provides the following tools:
1775
- ${this.generateMcpToolsForDxt().map((tool) => `- **${tool.name}**: ${tool.description}`).join("\n")}
1776
-
1777
- ## Building DXT Packages
1778
-
1779
- To rebuild the DXT package:
1780
-
1781
- ### Prerequisites
1782
- - Node.js 18+ installed
1783
- - npm package manager
1784
-
1785
- ### Build Steps
1786
-
1787
- \`\`\`bash
1788
- # 1. Install dependencies
1789
- npm install
1790
-
1791
- # 2. Build DXT package
1792
- npm run build-dxt
1793
- # or
1794
- ./build-dxt.sh
1795
-
1796
- # 3. The build script will:
1797
- # - Install dependencies
1798
- # - Validate the manifest
1799
- # - Create the DXT package using Anthropic's official packer
1800
- # - Sign the package (optional)
1801
- \`\`\`
1802
-
1803
- ### Manual Build Process
1804
-
1805
- If the automated build script doesn't work, you can build manually:
1806
-
1807
- \`\`\`bash
1808
- # 1. Install dependencies
1809
- npm install
1810
-
1811
- # 2. Create DXT package
1812
- npx @anthropic-ai/dxt pack . ${serverInfo.name}.dxt
1813
-
1814
- # 2. Update manifest.json
1815
- # Change "entry_point" from "server/index.js" to "dist-autonomous/server.cjs"
1816
-
1817
- # 3. Create new DXT with bundled server
1818
- # Replace server/index.js with dist-autonomous/server.cjs
1819
- # Remove package.json dependencies (optional)
1820
- \`\`\`
1821
-
1822
- ### Result
1823
- The resulting DXT package will be completely autonomous and won't require \`npm install\`.
1824
-
1825
- ## Generated Information
1826
-
1827
- - **Generator**: @alcyone-labs/arg-parser v1.3.0
1828
- - **Generated**: ${(/* @__PURE__ */ new Date()).toISOString()}
1829
- - **DXT Version**: 0.1
1830
-
1831
- ## Note
1832
-
1833
- This is a simplified DXT package. For full functionality and the latest features, use the original CLI directly.
1834
- For autonomous packages, follow the build instructions above.
1835
- `;
1836
- }
1837
- /**
1838
- * Maps ArgParser flag types to DXT user config types
1839
- */
1840
- mapFlagTypeToUserConfigType(flagType) {
1841
- if (typeof flagType === "function") {
1842
- if (flagType === String) return "string";
1843
- if (flagType === Number) return "number";
1844
- if (flagType === Boolean) return "boolean";
1845
- if (flagType === Array) return "array";
1846
- if (flagType === Object) return "object";
1847
- return "string";
1848
- }
1849
- switch (String(flagType).toLowerCase()) {
1850
- case "string":
1851
- return "string";
1852
- case "number":
1853
- return "number";
1854
- case "boolean":
1855
- return "boolean";
1856
- case "table":
1857
- return "array";
1858
- case "array":
1859
- return "array";
1860
- case "object":
1861
- return "object";
1862
- default:
1863
- return "string";
1864
- }
1865
- }
1866
- /**
1867
- * Generates CLI arguments for DXT manifest based on ArgParser flags
1868
- */
1869
- generateCliArgsForDxt(_mcpSubCommand) {
1870
- const args = [];
1871
- args.push("--s-mcp-serve");
1872
- return args;
1873
- }
1874
- /**
1875
- * Generates environment variables and user config for DXT manifest
1876
- */
1877
- generateEnvAndUserConfig() {
1878
- const envVars = {};
1879
- const userConfig = {};
1880
- const flags = this.argParserInstance.flags || [];
1881
- for (const flag of flags) {
1882
- const flagName = flag["name"];
1883
- if (flagName === "help" || flagName === "mcp") continue;
1884
- if (flag["env"]) {
1885
- const envVarName = flag["env"];
1886
- envVars[envVarName] = `\${user_config.${envVarName}}`;
1887
- userConfig[envVarName] = {
1888
- type: this.mapFlagTypeToUserConfigType(flag["type"]),
1889
- title: this.generateUserConfigTitle(envVarName),
1890
- description: flag["description"] || `${envVarName} environment variable`,
1891
- required: true,
1892
- // Always require env vars in user_config for better UX
1893
- sensitive: this.isSensitiveField(envVarName)
1894
- };
1895
- }
1896
- }
1897
- if (typeof this.argParserInstance.getTools === "function") {
1898
- const tools = this.argParserInstance.getTools();
1899
- for (const [, toolConfig] of tools) {
1900
- const toolFlags = toolConfig.flags || [];
1901
- for (const flag of toolFlags) {
1902
- const flagName = flag["name"];
1903
- if (flagName === "help" || flagName.startsWith("s-")) continue;
1904
- if (flag["env"]) {
1905
- const envVarName = flag["env"];
1906
- if (!envVars[envVarName]) {
1907
- envVars[envVarName] = `\${user_config.${envVarName}}`;
1908
- userConfig[envVarName] = {
1909
- type: this.mapFlagTypeToUserConfigType(flag["type"]),
1910
- title: this.generateUserConfigTitle(envVarName),
1911
- description: flag["description"] || `${envVarName} environment variable`,
1912
- required: true,
1913
- // Always require env vars in user_config for better UX
1914
- sensitive: this.isSensitiveField(envVarName)
1915
- };
1916
- }
1917
- }
1545
+ console.warn(
1546
+ simpleChalk.yellow(
1547
+ `Warning: Could not generate detailed tool list: ${error instanceof Error ? error.message : String(error)}`
1548
+ )
1549
+ );
1550
+ return [
1551
+ {
1552
+ name: "main",
1553
+ description: "Main command tool"
1918
1554
  }
1919
- }
1555
+ ];
1920
1556
  }
1921
- return { envVars, userConfig };
1922
- }
1923
- /**
1924
- * Generates a user-friendly title for user config fields
1925
- */
1926
- generateUserConfigTitle(flagName) {
1927
- return flagName.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
1928
1557
  }
1929
1558
  /**
1930
- * Checks if a field should be marked as sensitive in user config
1559
+ * Maps ArgParser flag types to DXT user config types
1931
1560
  */
1932
- isSensitiveField(fieldName) {
1933
- const sensitivePatterns = [
1934
- /key/i,
1935
- /token/i,
1936
- /secret/i,
1937
- /password/i,
1938
- /auth/i,
1939
- /credential/i
1940
- ];
1941
- return sensitivePatterns.some((pattern2) => pattern2.test(fieldName));
1942
- }
1943
1561
  /**
1944
1562
  * Adds the logo to the build folder if available
1945
1563
  * @returns The filename of the logo that was added, or undefined if no logo was added
@@ -1959,27 +1577,38 @@ For autonomous packages, follow the build instructions above.
1959
1577
  const urlPath = new URL(customLogo).pathname;
1960
1578
  const urlFilename = path__namespace.basename(urlPath);
1961
1579
  if (urlFilename && urlFilename.includes(".")) {
1962
- logoFilename = urlFilename;
1580
+ const ext = path__namespace.extname(urlFilename);
1581
+ logoFilename = `logo${ext}`;
1582
+ } else {
1583
+ logoFilename = "logo.jpg";
1963
1584
  }
1964
1585
  console.log("✓ Downloaded logo from URL");
1965
1586
  } else {
1966
- console.warn(`⚠ Failed to download logo: HTTP ${response.status}`);
1587
+ console.warn(
1588
+ `⚠ Failed to download logo: HTTP ${response.status}`
1589
+ );
1967
1590
  }
1968
1591
  } catch (error) {
1969
- console.warn("⚠ Failed to download logo from URL:", error instanceof Error ? error.message : String(error));
1592
+ console.warn(
1593
+ "⚠ Failed to download logo from URL:",
1594
+ error instanceof Error ? error.message : String(error)
1595
+ );
1970
1596
  }
1971
1597
  } else {
1972
1598
  let logoPath;
1973
1599
  if (entryPointFile && !path__namespace.isAbsolute(customLogo)) {
1974
1600
  const entryDir = path__namespace.dirname(entryPointFile);
1975
1601
  logoPath = path__namespace.resolve(entryDir, customLogo);
1976
- console.log(`📍 Resolving logo path relative to entry point: ${logoPath}`);
1602
+ console.log(
1603
+ `📍 Resolving logo path relative to entry point: ${logoPath}`
1604
+ );
1977
1605
  } else {
1978
1606
  logoPath = path__namespace.resolve(customLogo);
1979
1607
  }
1980
1608
  if (fs__namespace.existsSync(logoPath)) {
1981
1609
  logoBuffer = fs__namespace.readFileSync(logoPath);
1982
- logoFilename = path__namespace.basename(logoPath);
1610
+ const ext = path__namespace.extname(logoPath);
1611
+ logoFilename = `logo${ext}`;
1983
1612
  console.log("✓ Added custom logo from local file");
1984
1613
  } else {
1985
1614
  console.warn(`⚠ Custom logo file not found: ${logoPath}`);
@@ -1990,17 +1619,52 @@ For autonomous packages, follow the build instructions above.
1990
1619
  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);
1991
1620
  let logoPath = path__namespace.join(currentDir, "assets", "logo_1_small.jpg");
1992
1621
  if (!fs__namespace.existsSync(logoPath)) {
1993
- logoPath = path__namespace.join(currentDir, "..", "docs", "MCP", "icons", "logo_1_small.jpg");
1622
+ logoPath = path__namespace.join(
1623
+ currentDir,
1624
+ "..",
1625
+ "docs",
1626
+ "MCP",
1627
+ "icons",
1628
+ "logo_1_small.jpg"
1629
+ );
1630
+ }
1631
+ if (!fs__namespace.existsSync(logoPath)) {
1632
+ logoPath = path__namespace.join(
1633
+ process.cwd(),
1634
+ "docs",
1635
+ "MCP",
1636
+ "icons",
1637
+ "logo_1_small.jpg"
1638
+ );
1994
1639
  }
1995
1640
  if (!fs__namespace.existsSync(logoPath)) {
1996
- logoPath = path__namespace.join(process.cwd(), "docs", "MCP", "icons", "logo_1_small.jpg");
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
+ );
1997
1658
  }
1998
1659
  if (fs__namespace.existsSync(logoPath)) {
1999
1660
  logoBuffer = fs__namespace.readFileSync(logoPath);
2000
- logoFilename = "logo.jpg";
1661
+ const ext = path__namespace.extname(logoPath);
1662
+ logoFilename = `logo${ext}`;
2001
1663
  console.log("✓ Added default logo to build folder");
2002
1664
  } else {
2003
- console.warn("⚠ No logo found (custom or default), build folder will be created without icon");
1665
+ console.warn(
1666
+ "⚠ No logo found (custom or default), build folder will be created without icon"
1667
+ );
2004
1668
  return void 0;
2005
1669
  }
2006
1670
  }
@@ -2010,260 +1674,89 @@ For autonomous packages, follow the build instructions above.
2010
1674
  }
2011
1675
  return void 0;
2012
1676
  } catch (error) {
2013
- console.warn("⚠ Failed to add logo to build folder:", error instanceof Error ? error.message : String(error));
1677
+ console.warn(
1678
+ "⚠ Failed to add logo to build folder:",
1679
+ error instanceof Error ? error.message : String(error)
1680
+ );
2014
1681
  return void 0;
2015
1682
  }
2016
1683
  }
2017
- /**
2018
- * Processes CLI source code to replace global console with MCP-compliant Logger
2019
- */
2020
- processCliSourceForMcp(cliSource) {
2021
- const consoleReplacement = `import { createMcpLogger } from '@alcyone-labs/arg-parser';
2022
-
2023
- // Replace global console with MCP-compliant logger for DXT packages
2024
- const mcpLogger = createMcpLogger('[CLI]');
2025
- const originalConsole = globalThis.console;
2026
- globalThis.console = {
2027
- ...originalConsole,
2028
- log: (...args) => mcpLogger.info(...args),
2029
- info: (...args) => mcpLogger.info(...args),
2030
- warn: (...args) => mcpLogger.warn(...args),
2031
- debug: (...args) => mcpLogger.debug(...args),
2032
- // Keep error/trace/etc as-is since they use stderr (MCP-compliant)
2033
- error: originalConsole.error,
2034
- trace: originalConsole.trace,
2035
- assert: originalConsole.assert,
2036
- clear: originalConsole.clear,
2037
- count: originalConsole.count,
2038
- countReset: originalConsole.countReset,
2039
- dir: originalConsole.dir,
2040
- dirxml: originalConsole.dirxml,
2041
- group: originalConsole.group,
2042
- groupCollapsed: originalConsole.groupCollapsed,
2043
- groupEnd: originalConsole.groupEnd,
2044
- table: originalConsole.table,
2045
- time: originalConsole.time,
2046
- timeEnd: originalConsole.timeEnd,
2047
- timeLog: originalConsole.timeLog,
2048
- timeStamp: originalConsole.timeStamp,
2049
- };
2050
-
2051
- `;
2052
- const lines = cliSource.split("\n");
2053
- let lastImportIndex = -1;
2054
- for (let i = 0; i < lines.length; i++) {
2055
- const line = lines[i].trim();
2056
- if (line.startsWith("import ") && line.includes("from")) {
2057
- lastImportIndex = i;
2058
- } else if (line && !line.startsWith("//") && !line.startsWith("/*") && lastImportIndex >= 0) {
2059
- break;
2060
- }
2061
- }
2062
- if (lastImportIndex >= 0) {
2063
- lines.splice(lastImportIndex + 1, 0, "", ...consoleReplacement.trim().split("\n"));
2064
- return lines.join("\n");
2065
- } else {
2066
- return consoleReplacement + cliSource;
2067
- }
2068
- }
2069
- /**
2070
- * Adds the original CLI source to the build folder for handler execution
2071
- */
2072
- addOriginalCliToFolder(buildDir) {
2073
- try {
2074
- const appCommandName = this.argParserInstance.getAppCommandName();
2075
- const appName = this.argParserInstance.getAppName();
2076
- const possibleCliFiles = [
2077
- // Current working directory common patterns
2078
- path__namespace.join(process.cwd(), "index.js"),
2079
- path__namespace.join(process.cwd(), "index.mjs"),
2080
- path__namespace.join(process.cwd(), "cli.js"),
2081
- path__namespace.join(process.cwd(), "cli.mjs"),
2082
- path__namespace.join(process.cwd(), "main.js"),
2083
- path__namespace.join(process.cwd(), "main.mjs"),
2084
- // Look for files with the app command name
2085
- path__namespace.join(process.cwd(), `${appCommandName}.js`),
2086
- path__namespace.join(process.cwd(), `${appCommandName}.mjs`),
2087
- // Look for files with the app command name (sanitized)
2088
- path__namespace.join(process.cwd(), `${appCommandName.replace(/[^a-zA-Z0-9-]/g, "-")}.js`),
2089
- path__namespace.join(process.cwd(), `${appCommandName.replace(/[^a-zA-Z0-9-]/g, "-")}.mjs`),
2090
- // Look for files with app name patterns
2091
- path__namespace.join(process.cwd(), `${appName.toLowerCase().replace(/\s+/g, "-")}-cli.js`),
2092
- path__namespace.join(process.cwd(), `${appName.toLowerCase().replace(/\s+/g, "-")}-cli.mjs`),
2093
- // Look for files with first word of app name + cli
2094
- path__namespace.join(process.cwd(), `${appName.split(" ")[0].toLowerCase()}-cli.js`),
2095
- path__namespace.join(process.cwd(), `${appName.split(" ")[0].toLowerCase()}-cli.mjs`)
2096
- ];
2097
- let cliSourcePath = null;
2098
- for (const filePath of possibleCliFiles) {
2099
- if (fs__namespace.existsSync(filePath)) {
2100
- cliSourcePath = filePath;
2101
- break;
2102
- }
2103
- }
2104
- if (cliSourcePath) {
2105
- let cliSource = fs__namespace.readFileSync(cliSourcePath, "utf8");
2106
- cliSource = cliSource.replace(
2107
- /import\s*{\s*([^}]+)\s*}\s*from\s*['"][^'"]*\/dist\/index\.mjs['"];?/g,
2108
- "import { $1 } from '@alcyone-labs/arg-parser';"
2109
- );
2110
- cliSource = cliSource.replace(
2111
- /import\s+(\w+)\s+from\s*['"][^'"]*\/dist\/index\.mjs['"];?/g,
2112
- "import $1 from '@alcyone-labs/arg-parser';"
2113
- );
2114
- cliSource = this.processCliSourceForMcp(cliSource);
2115
- const parserVariableMatch = cliSource.match(/const\s+(\w+)\s*=\s*ArgParser\.withMcp\(/);
2116
- if (parserVariableMatch) {
2117
- const parserVariable = parserVariableMatch[1];
2118
- cliSource += `
2119
-
2120
- // Export the parser instance for MCP server use
2121
- export default ${parserVariable};
2122
-
2123
- // Add debugging for main execution
2124
- console.error('[MCP-DEBUG] CLI source loaded, checking execution context...');
2125
- console.error('[MCP-DEBUG] import.meta.url:', import.meta.url);
2126
- console.error('[MCP-DEBUG] process.argv[1]:', process.argv[1]);
2127
-
2128
- // Ensure MCP server processes don't exit prematurely
2129
- console.error('[MCP-DEBUG] Process argv:', process.argv);
2130
- console.error('[MCP-DEBUG] Checking for serve command...');
2131
-
2132
- if (process.argv.includes('serve')) {
2133
- console.error('[MCP-DEBUG] Detected serve command, setting up MCP server lifecycle...');
2134
-
2135
- // Override the original parse method to handle async MCP server
2136
- const originalParse = ${parserVariable}.parse;
2137
- ${parserVariable}.parse = async function(args) {
2138
- console.error('[MCP-DEBUG] Starting parse with args:', args);
2139
-
2140
- try {
2141
- const result = originalParse.call(this, args);
2142
- console.error('[MCP-DEBUG] Parse result:', typeof result, result?.constructor?.name);
2143
-
2144
- // If result is a Promise (MCP server), await it and keep process alive
2145
- if (result && typeof result.then === 'function') {
2146
- console.error('[MCP-DEBUG] Detected Promise result, awaiting...');
2147
- const mcpResult = await result;
2148
- console.error('[MCP-DEBUG] MCP server started, keeping process alive...');
2149
-
2150
- // Keep the process alive indefinitely for MCP server
2151
- const keepAlive = setInterval(() => {
2152
- // Do nothing, just keep the event loop alive
2153
- }, 30000);
2154
-
2155
- // Handle graceful shutdown
2156
- process.on('SIGINT', () => {
2157
- console.error('[MCP-INFO] Received SIGINT, shutting down gracefully...');
2158
- clearInterval(keepAlive);
2159
- process.exit(0);
2160
- });
2161
-
2162
- process.on('SIGTERM', () => {
2163
- console.error('[MCP-INFO] Received SIGTERM, shutting down gracefully...');
2164
- clearInterval(keepAlive);
2165
- process.exit(0);
2166
- });
2167
-
2168
- return mcpResult;
2169
- } else {
2170
- console.error('[MCP-DEBUG] Non-Promise result, returning normally');
2171
- return result;
2172
- }
2173
- } catch (error) {
2174
- console.error('[MCP-ERROR] Error in parse:', error);
2175
- throw error;
2176
- }
2177
- };
2178
- }
2179
- `;
2180
- } else {
2181
- console.warn("⚠ Could not find ArgParser instance in CLI source, MCP server may not work properly");
2182
- }
2183
- const serverDir = path__namespace.join(buildDir, "server");
2184
- if (!fs__namespace.existsSync(serverDir)) {
2185
- fs__namespace.mkdirSync(serverDir, { recursive: true });
2186
- }
2187
- fs__namespace.writeFileSync(path__namespace.join(serverDir, "original-cli.mjs"), cliSource);
2188
- console.log(`✓ Added original CLI source to build folder: ${path__namespace.basename(cliSourcePath)}`);
2189
- } else {
2190
- console.warn("⚠ Original CLI source not found, handlers may not work properly");
2191
- console.warn(" Searched for:", possibleCliFiles.map((f) => path__namespace.basename(f)).join(", "));
2192
- }
2193
- } catch (error) {
2194
- console.warn("⚠ Failed to add original CLI source:", error instanceof Error ? error.message : String(error));
2195
- }
2196
- }
2197
1684
  /**
2198
1685
  * Builds a complete DXT package using TSDown CLI for autonomous execution
2199
1686
  */
2200
- async buildDxtWithTsdown(entryPointFile, outputDir = "./dxt") {
1687
+ async buildDxtWithTsdown(entryPointFile, outputDir = "./dxt", withNodeModules = false) {
2201
1688
  try {
2202
1689
  console.log(simpleChalk.cyan("🔧 Building DXT package with TSDown..."));
2203
- const entryDir = path__namespace.dirname(entryPointFile);
1690
+ const projectRoot = this.findProjectRoot(entryPointFile);
1691
+ const absoluteEntryPath = path__namespace.resolve(entryPointFile);
1692
+ const relativeEntryPath = path__namespace.relative(projectRoot, absoluteEntryPath);
2204
1693
  const entryFileName = path__namespace.basename(entryPointFile);
2205
1694
  console.log(simpleChalk.gray(`Entry point: ${entryPointFile}`));
2206
- console.log(simpleChalk.gray(`Working directory: ${entryDir}`));
1695
+ console.log(simpleChalk.gray(`Project root: ${projectRoot}`));
1696
+ console.log(simpleChalk.gray(`Relative entry path: ${relativeEntryPath}`));
2207
1697
  const dxtIgnorePath = this.getDxtIgnoreTemplatePath();
2208
1698
  if (fs__namespace.existsSync(dxtIgnorePath)) {
2209
- fs__namespace.copyFileSync(dxtIgnorePath, path__namespace.join(entryDir, ".dxtignore"));
1699
+ fs__namespace.copyFileSync(dxtIgnorePath, path__namespace.join(projectRoot, ".dxtignore"));
2210
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
+ );
2211
1710
  const originalCwd = process.cwd();
2212
1711
  try {
2213
- process.chdir(entryDir);
1712
+ process.chdir(projectRoot);
2214
1713
  const { build } = await import("tsdown");
2215
- console.log(simpleChalk.gray(`Building with TSDown: ${entryFileName}`));
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
+ );
2216
1720
  const buildConfig = {
2217
- entry: [entryFileName],
2218
- outDir: path__namespace.resolve(process.cwd(), outputDir),
2219
- format: ["esm"],
1721
+ entry: [relativeEntryPath],
1722
+ outDir: path__namespace.resolve(originalCwd, outputDir),
1723
+ format: ["es"],
2220
1724
  target: "node22",
2221
- noExternal: () => true,
1725
+ define: {
1726
+ // Define any compile-time constants
1727
+ NODE_ENV: '"production"'
1728
+ },
2222
1729
  minify: false,
2223
1730
  sourcemap: false,
2224
- clean: false,
1731
+ // Remove all output folders and artefacts
1732
+ clean: [outputDir, "./.dxtignore", `${outputDir}.dxt`],
2225
1733
  silent: process.env["NO_SILENCE"] !== "1",
2226
- copy: [
2227
- // Copy logo from assets - try multiple possible locations
2228
- ...(() => {
2229
- const possibleLogoPaths = [
2230
- // From built library assets
2231
- path__namespace.join(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), "..", "assets", "logo_1_small.jpg"),
2232
- // From node_modules
2233
- path__namespace.join(process.cwd(), "node_modules", "@alcyone-labs", "arg-parser", "dist", "assets", "logo_1_small.jpg"),
2234
- // From package root dist/assets (for local build)
2235
- path__namespace.join(process.cwd(), "dist", "assets", "logo_1_small.jpg"),
2236
- // From library root (development)
2237
- path__namespace.join(process.cwd(), "..", "..", "..", "docs", "MCP", "icons", "logo_1_small.jpg")
2238
- ];
2239
- for (const logoPath of possibleLogoPaths) {
2240
- if (fs__namespace.existsSync(logoPath)) {
2241
- console.log(simpleChalk.gray(`Found logo at: ${logoPath}`));
2242
- return [{ from: logoPath, to: "logo.jpg" }];
2243
- }
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) {
1741
+ console.log(
1742
+ simpleChalk.gray(
1743
+ "📦 Including node_modules in bundle (may take longer)..."
1744
+ )
1745
+ );
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
+ });
2244
1756
  }
2245
- console.log(simpleChalk.yellow("⚠ Logo not found in any expected location"));
2246
- return [];
2247
- })()
2248
- ],
2249
- external: [
2250
- // Node.js built-ins only - everything else should be bundled for true autonomy
2251
- "stream",
2252
- "fs",
2253
- "path",
2254
- "url",
2255
- "util",
2256
- "events",
2257
- "child_process",
2258
- "os",
2259
- "tty",
2260
- "process",
2261
- "crypto",
2262
- "http",
2263
- "https",
2264
- "net",
2265
- "zlib"
2266
- ],
1757
+ }
1758
+ return outputPaths;
1759
+ },
2267
1760
  platform: "node",
2268
1761
  plugins: []
2269
1762
  };
@@ -2282,262 +1775,40 @@ export default ${JSON.stringify(buildConfig, null, 2)};
2282
1775
  // To run manually:
2283
1776
  // npx tsdown -c tsdown.config.dxt.ts
2284
1777
  `;
2285
- fs__namespace.writeFileSync(path__namespace.join("dxt", "tsdown.config.dxt.ts"), configContent);
2286
- console.log(simpleChalk.gray("📝 Debug config written to dxt/tsdown.config.dxt.ts"));
1778
+ fs__namespace.writeFileSync(
1779
+ path__namespace.join("dxt", "tsdown.config.dxt.ts"),
1780
+ configContent
1781
+ );
1782
+ console.log(
1783
+ simpleChalk.gray("📝 Debug config written to dxt/tsdown.config.dxt.ts")
1784
+ );
2287
1785
  }
2288
1786
  await build(buildConfig);
2289
1787
  console.log(simpleChalk.green("✅ TSDown bundling completed"));
2290
- await this.copyLogoManually(outputDir);
2291
- await this.setupDxtPackageFiles(entryPointFile, outputDir);
2292
- console.log(simpleChalk.cyan("📦 DXT package ready for packing"));
2293
- console.log(simpleChalk.gray(`To complete the process, run: npx @anthropic-ai/dxt pack ${outputDir}/`));
2294
- } finally {
2295
- process.chdir(originalCwd);
2296
- }
2297
- } catch (error) {
2298
- throw new Error(`TSDown DXT build failed: ${error instanceof Error ? error.message : String(error)}`);
2299
- }
2300
- }
2301
- /**
2302
- * Bundles the original CLI using TSDown for autonomous execution (legacy method)
2303
- */
2304
- async bundleOriginalCliWithTsdown(serverDir) {
2305
- try {
2306
- const { build } = await import("tsdown");
2307
- console.log(simpleChalk.cyan("🔧 Bundling CLI with TSDown for autonomous execution..."));
2308
- const configContent = this.getTsdownConfigContent();
2309
- const localConfigPath = path__namespace.join(serverDir, "tsdown.config.mjs");
2310
- fs__namespace.writeFileSync(localConfigPath, configContent);
2311
- const originalCliPath = path__namespace.join(serverDir, "original-cli.mjs");
2312
- if (!fs__namespace.existsSync(originalCliPath)) {
2313
- console.warn(simpleChalk.yellow("⚠ Original CLI not found, skipping TSDown bundling"));
2314
- return null;
2315
- }
2316
- const buildOptions = {
2317
- entry: ["original-cli.mjs"],
2318
- // Use relative path since we'll chdir to serverDir
2319
- outDir: ".",
2320
- // Output to current directory (serverDir)
2321
- format: "esm",
2322
- target: "node22",
2323
- // Bundle EVERYTHING except Node.js built-ins for true autonomy
2324
- noExternal: (id) => {
2325
- if (!id.startsWith("node:") && !this.isNodeBuiltin(id)) return true;
2326
- return false;
2327
- },
2328
- minify: false,
2329
- sourcemap: false,
2330
- clean: false,
2331
- outExtension: () => ({ js: ".bundled.mjs" }),
2332
- alias: {
2333
- // Alias chalk to SimpleChalk for autonomous builds
2334
- chalk: path__namespace.resolve(process.cwd(), "node_modules/@alcyone-labs/arg-parser/dist/SimpleChalk.mjs")
2335
- },
2336
- external: [
2337
- // Only Node.js built-ins - everything else gets bundled for true autonomy
2338
- "node:stream",
2339
- "node:fs",
2340
- "node:path",
2341
- "node:url",
2342
- "node:util",
2343
- "node:events",
2344
- "node:child_process",
2345
- "node:os",
2346
- "node:tty",
2347
- "node:process",
2348
- "node:crypto",
2349
- "node:http",
2350
- "node:https",
2351
- "node:net",
2352
- "node:zlib",
2353
- "node:fs/promises",
2354
- "node:timers",
2355
- "stream",
2356
- "fs",
2357
- "path",
2358
- "url",
2359
- "util",
2360
- "events",
2361
- "child_process",
2362
- "os",
2363
- "tty",
2364
- "process",
2365
- "crypto",
2366
- "http",
2367
- "https",
2368
- "net",
2369
- "zlib",
2370
- "fs/promises",
2371
- "timers",
2372
- "timers/promises",
2373
- "perf_hooks",
2374
- "async_hooks",
2375
- "inspector",
2376
- "v8",
2377
- "vm",
2378
- "assert",
2379
- "constants",
2380
- "module",
2381
- "repl",
2382
- "string_decoder",
2383
- "punycode",
2384
- "domain",
2385
- "querystring",
2386
- "readline",
2387
- "worker_threads",
2388
- "cluster",
2389
- "dgram",
2390
- "dns",
2391
- "buffer"
2392
- ],
2393
- platform: "node",
2394
- plugins: [],
2395
- // Resolve local dependencies properly
2396
- resolve: {
2397
- alias: {
2398
- // Handle local monorepo dependencies
2399
- "@alcyone-labs/arg-parser": path__namespace.resolve(process.cwd())
2400
- }
2401
- }
2402
- };
2403
- const originalCwd = process.cwd();
2404
- try {
2405
- process.chdir(serverDir);
2406
- await build(buildOptions);
1788
+ const detectedOutputFile = this.detectTsdownOutputFile(
1789
+ outputDir,
1790
+ entryFileName
1791
+ );
1792
+ await this.setupDxtPackageFiles(
1793
+ entryPointFile,
1794
+ outputDir,
1795
+ detectedOutputFile ?? void 0,
1796
+ logoFilename ?? "logo.jpg"
1797
+ );
1798
+ console.log(simpleChalk.cyan("📦 DXT package ready for packing"));
1799
+ console.log(
1800
+ simpleChalk.gray(
1801
+ `To complete the process, run: npx @anthropic-ai/dxt pack ${outputDir}/`
1802
+ )
1803
+ );
2407
1804
  } finally {
2408
1805
  process.chdir(originalCwd);
2409
1806
  }
2410
- const possibleBundledFiles = [
2411
- "original-cli.bundled.mjs",
2412
- "original-cli.js",
2413
- "original-cli.mjs"
2414
- ];
2415
- let bundledPath = null;
2416
- let bundledFileName = null;
2417
- for (const fileName of possibleBundledFiles) {
2418
- const filePath = path__namespace.join(serverDir, fileName);
2419
- if (fs__namespace.existsSync(filePath) && fileName !== "original-cli.mjs") {
2420
- bundledPath = filePath;
2421
- bundledFileName = fileName;
2422
- break;
2423
- }
2424
- }
2425
- if (bundledPath && bundledFileName) {
2426
- console.log(simpleChalk.green(`✅ TSDown bundling completed successfully: ${bundledFileName}`));
2427
- const expectedBundledPath = path__namespace.join(serverDir, "original-cli.bundled.mjs");
2428
- if (bundledPath !== expectedBundledPath) {
2429
- fs__namespace.renameSync(bundledPath, expectedBundledPath);
2430
- bundledFileName = "original-cli.bundled.mjs";
2431
- }
2432
- try {
2433
- fs__namespace.unlinkSync(localConfigPath);
2434
- } catch (error) {
2435
- }
2436
- try {
2437
- fs__namespace.chmodSync(expectedBundledPath, 493);
2438
- } catch (error) {
2439
- console.warn("⚠ Could not set executable permission on bundled file:", error instanceof Error ? error.message : String(error));
2440
- }
2441
- return bundledFileName;
2442
- } else {
2443
- console.warn(simpleChalk.yellow("⚠ TSDown bundling failed, bundled file not found"));
2444
- return null;
2445
- }
2446
1807
  } catch (error) {
2447
- console.warn(simpleChalk.yellow(`⚠ TSDown bundling failed: ${error instanceof Error ? error.message : String(error)}`));
2448
- console.log(simpleChalk.gray(" Falling back to non-bundled approach"));
2449
- return null;
2450
- }
2451
- }
2452
- /**
2453
- * Checks if a module ID is a Node.js built-in
2454
- */
2455
- isNodeBuiltin(id) {
2456
- const nodeBuiltins = [
2457
- "stream",
2458
- "fs",
2459
- "path",
2460
- "url",
2461
- "util",
2462
- "events",
2463
- "child_process",
2464
- "os",
2465
- "tty",
2466
- "process",
2467
- "crypto",
2468
- "http",
2469
- "https",
2470
- "net",
2471
- "zlib",
2472
- "fs/promises",
2473
- "timers",
2474
- "timers/promises",
2475
- "perf_hooks",
2476
- "async_hooks",
2477
- "inspector",
2478
- "v8",
2479
- "vm",
2480
- "assert",
2481
- "constants",
2482
- "module",
2483
- "repl",
2484
- "string_decoder",
2485
- "punycode",
2486
- "domain",
2487
- "querystring",
2488
- "readline",
2489
- "worker_threads",
2490
- "cluster",
2491
- "dgram",
2492
- "dns",
2493
- "buffer"
2494
- ];
2495
- return nodeBuiltins.includes(id) || id.startsWith("node:");
2496
- }
2497
- /**
2498
- * Gets the TSDown configuration content as a string
2499
- */
2500
- getTsdownConfigContent() {
2501
- 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);
2502
- const assetsConfigPath = path__namespace.join(currentDir, "..", "assets", "tsdown.dxt.config.ts");
2503
- if (fs__namespace.existsSync(assetsConfigPath)) {
2504
- try {
2505
- const content = fs__namespace.readFileSync(assetsConfigPath, "utf-8");
2506
- return content.replace('/// <reference types="tsdown" />', "").replace('import { defineConfig } from "tsdown/config";', 'import { defineConfig } from "tsdown";').replace("export default defineConfig(", "export default defineConfig(");
2507
- } catch (error) {
2508
- console.warn(simpleChalk.yellow("⚠ Could not read TSDown config from assets, using fallback"));
2509
- }
2510
- }
2511
- const rootConfigPath = path__namespace.join(process.cwd(), "tsdown.dxt.config.ts");
2512
- if (fs__namespace.existsSync(rootConfigPath)) {
2513
- try {
2514
- const content = fs__namespace.readFileSync(rootConfigPath, "utf-8");
2515
- return content.replace('/// <reference types="tsdown" />', "").replace('import { defineConfig } from "tsdown/config";', 'import { defineConfig } from "tsdown";');
2516
- } catch (error) {
2517
- console.warn(simpleChalk.yellow("⚠ Could not read TSDown config from root, using default"));
2518
- }
1808
+ throw new Error(
1809
+ `TSDown DXT build failed: ${error instanceof Error ? error.message : String(error)}`
1810
+ );
2519
1811
  }
2520
- return `import { defineConfig } from "tsdown";
2521
- import path from "path";
2522
-
2523
- export default defineConfig({
2524
- outDir: "server",
2525
- format: ["esm", "module"],
2526
- target: "node22",
2527
- noExternal: () => true,
2528
- minify: false,
2529
- sourcemap: false,
2530
- clean: false,
2531
- alias: {
2532
- chalk: path.resolve(process.cwd(), "node_modules/@alcyone-labs/arg-parser/dist/SimpleChalk.mjs"),
2533
- },
2534
- external: [
2535
- "stream", "fs", "path", "url", "util", "events", "child_process",
2536
- "os", "tty", "process", "crypto", "http", "https", "net", "zlib",
2537
- ],
2538
- platform: "node",
2539
- plugins: [],
2540
- });`;
2541
1812
  }
2542
1813
  /**
2543
1814
  * Gets the path to the .dxtignore template file in assets
@@ -2545,9 +1816,22 @@ export default defineConfig({
2545
1816
  getDxtIgnoreTemplatePath() {
2546
1817
  const possiblePaths = [
2547
1818
  // 1. From the built library assets (when installed via npm)
2548
- path__namespace.join(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), "..", "assets", ".dxtignore.template"),
1819
+ path__namespace.join(
1820
+ 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),
1821
+ "..",
1822
+ "assets",
1823
+ ".dxtignore.template"
1824
+ ),
2549
1825
  // 2. From node_modules/@alcyone-labs/arg-parser/dist/assets (when installed via npm)
2550
- path__namespace.join(process.cwd(), "node_modules", "@alcyone-labs", "arg-parser", "dist", "assets", ".dxtignore.template"),
1826
+ path__namespace.join(
1827
+ process.cwd(),
1828
+ "node_modules",
1829
+ "@alcyone-labs",
1830
+ "arg-parser",
1831
+ "dist",
1832
+ "assets",
1833
+ ".dxtignore.template"
1834
+ ),
2551
1835
  // 3. From the root directory (development/local build)
2552
1836
  path__namespace.join(process.cwd(), ".dxtignore.template"),
2553
1837
  // 4. From the library root (when using local file dependency)
@@ -2565,8 +1849,8 @@ export default defineConfig({
2565
1849
  /**
2566
1850
  * Sets up DXT package files (manifest.json) in the output directory
2567
1851
  */
2568
- async setupDxtPackageFiles(entryPointFile, outputDir = "./dxt") {
2569
- var _a, _b, _c, _d, _e;
1852
+ async setupDxtPackageFiles(entryPointFile, outputDir = "./dxt", actualOutputFilename, logoFilename = "logo.jpg") {
1853
+ var _a, _b, _c, _d, _e, _f;
2570
1854
  const dxtDir = path__namespace.resolve(process.cwd(), outputDir);
2571
1855
  if (!fs__namespace.existsSync(dxtDir)) {
2572
1856
  throw new Error(`TSDown output directory (${outputDir}) not found`);
@@ -2588,11 +1872,15 @@ export default defineConfig({
2588
1872
  description: tool.description
2589
1873
  }));
2590
1874
  } catch (error) {
2591
- console.warn(simpleChalk.yellow(`Warning: Could not generate unified tool list: ${error instanceof Error ? error.message : String(error)}`));
2592
- const mainFlags2 = this.argParserInstance.flags;
1875
+ console.warn(
1876
+ simpleChalk.yellow(
1877
+ `Warning: Could not generate unified tool list: ${error instanceof Error ? error.message : String(error)}`
1878
+ )
1879
+ );
1880
+ const mainFlags = this.argParserInstance.flags;
2593
1881
  const properties2 = {};
2594
1882
  const required2 = [];
2595
- for (const flag of mainFlags2) {
1883
+ for (const flag of mainFlags) {
2596
1884
  if (flag.name === "help" || flag.name.startsWith("s-")) continue;
2597
1885
  properties2[flag.name] = {
2598
1886
  type: getJsonSchemaTypeFromFlag(flag.type),
@@ -2609,59 +1897,24 @@ export default defineConfig({
2609
1897
  }
2610
1898
  }
2611
1899
  const commandName = this.argParserInstance.getAppCommandName();
2612
- tools = [{
2613
- name: commandName || packageInfo.name || "cli-tool",
2614
- description: packageInfo.description || this.argParserInstance.getDescription() || "CLI tool"
2615
- }];
2616
- }
2617
- const envVars = {};
2618
- const userConfig = {};
2619
- const mainFlags = this.argParserInstance.flags;
2620
- for (const flag of mainFlags) {
2621
- const envVar = flag.env || flag.envVar;
2622
- if (envVar) {
2623
- envVars[envVar] = `\${user_config.${envVar}}`;
2624
- userConfig[envVar] = {
2625
- type: "string",
2626
- title: envVar.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
2627
- description: flag.description || `${envVar} environment variable`,
2628
- required: true,
2629
- // Always require env vars in user_config for better UX
2630
- sensitive: true
2631
- // Assume env vars are sensitive
2632
- };
2633
- }
2634
- }
2635
- if (typeof this.argParserInstance.getTools === "function") {
2636
- const tools2 = this.argParserInstance.getTools();
2637
- for (const [, toolConfig] of tools2) {
2638
- const toolFlags = toolConfig.flags || [];
2639
- for (const flag of toolFlags) {
2640
- const envVar = flag.env || flag.envVar;
2641
- if (envVar && !envVars[envVar]) {
2642
- envVars[envVar] = `\${user_config.${envVar}}`;
2643
- userConfig[envVar] = {
2644
- type: "string",
2645
- title: envVar.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
2646
- description: flag.description || `${envVar} environment variable`,
2647
- required: true,
2648
- // Always require env vars in user_config for better UX
2649
- sensitive: true
2650
- // Assume env vars are sensitive
2651
- };
2652
- }
1900
+ tools = [
1901
+ {
1902
+ name: commandName || packageInfo.name || "cli-tool",
1903
+ description: packageInfo.description || this.argParserInstance.getDescription() || "CLI tool"
2653
1904
  }
2654
- }
1905
+ ];
2655
1906
  }
1907
+ const { envVars, userConfig } = this.generateEnvAndUserConfig();
2656
1908
  const serverInfo = this.extractMcpServerInfo();
2657
- let logoFilename = "logo.jpg";
2658
- if (serverInfo == null ? void 0 : serverInfo.logo) {
2659
- const customLogoFilename = await this.addLogoToFolder(dxtDir, serverInfo, entryPointFile);
2660
- if (customLogoFilename) {
2661
- logoFilename = customLogoFilename;
2662
- }
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");
2663
1917
  }
2664
- const entryFileName = path__namespace.basename(entryPointFile);
2665
1918
  const manifest = {
2666
1919
  dxt_version: "0.1",
2667
1920
  name: serverInfo.name || packageInfo.name || "mcp-server",
@@ -2679,7 +1932,10 @@ export default defineConfig({
2679
1932
  command: "node",
2680
1933
  args: [
2681
1934
  `\${__dirname}/${entryFileName}`,
2682
- "--s-mcp-serve"
1935
+ "--s-mcp-serve",
1936
+ // Overwrite the CLI config to only use stdio to avoid conflicts
1937
+ "--s-mcp-transport",
1938
+ "stdio"
2683
1939
  ],
2684
1940
  env: envVars
2685
1941
  }
@@ -2687,46 +1943,147 @@ export default defineConfig({
2687
1943
  tools,
2688
1944
  icon: logoFilename,
2689
1945
  ...Object.keys(userConfig).length > 0 && { user_config: userConfig },
2690
- repository: {
1946
+ repository: ((_e = packageInfo.repository) == null ? void 0 : _e.url) ? {
2691
1947
  type: "git",
2692
- url: ((_e = packageInfo.repository) == null ? void 0 : _e.url) || "https://github.com/alcyone-labs/arg-parser"
2693
- },
1948
+ url: (_f = packageInfo.repository) == null ? void 0 : _f.url
1949
+ } : void 0,
2694
1950
  license: packageInfo.license || "MIT"
2695
1951
  };
2696
- fs__namespace.writeFileSync(path__namespace.join(dxtDir, "manifest.json"), JSON.stringify(manifest, null, 2));
1952
+ fs__namespace.writeFileSync(
1953
+ path__namespace.join(dxtDir, "manifest.json"),
1954
+ JSON.stringify(manifest, null, 2)
1955
+ );
2697
1956
  console.log(simpleChalk.gray("✅ DXT package files set up"));
2698
1957
  }
2699
1958
  /**
2700
- * Manually copy logo since TSDown's copy option doesn't work programmatically
1959
+ * Detects the actual output filename generated by TSDown
2701
1960
  */
2702
- async copyLogoManually(outputDir = "./dxt") {
2703
- const dxtDir = path__namespace.resolve(process.cwd(), outputDir);
2704
- if (!fs__namespace.existsSync(dxtDir)) {
2705
- console.warn(simpleChalk.yellow(`⚠ Output directory (${outputDir}) not found, skipping logo copy`));
2706
- return;
1961
+ detectTsdownOutputFile(outputDir, expectedBaseName) {
1962
+ try {
1963
+ const dxtDir = path__namespace.resolve(process.cwd(), outputDir);
1964
+ if (!fs__namespace.existsSync(dxtDir)) {
1965
+ console.warn(
1966
+ simpleChalk.yellow(`⚠ Output directory (${outputDir}) not found`)
1967
+ );
1968
+ return null;
1969
+ }
1970
+ const files = fs__namespace.readdirSync(dxtDir).filter(
1971
+ (file) => (file.endsWith(".js") || file.endsWith(".mjs")) && !file.includes("chunk-") && !file.includes("dist-") && !file.startsWith(".")
1972
+ );
1973
+ const baseNameWithoutExt = path__namespace.parse(expectedBaseName).name;
1974
+ for (const ext of [".js", ".mjs"]) {
1975
+ const exactMatch = `${baseNameWithoutExt}${ext}`;
1976
+ if (files.includes(exactMatch)) {
1977
+ console.log(simpleChalk.gray(`✓ Detected TSDown output: ${exactMatch}`));
1978
+ return exactMatch;
1979
+ }
1980
+ }
1981
+ const mainFiles = files.filter(
1982
+ (file) => !file.includes("chunk") && !file.includes("dist") && file !== "logo.jpg" && file !== "manifest.json"
1983
+ );
1984
+ if (mainFiles.length === 1) {
1985
+ console.log(simpleChalk.gray(`✓ Detected TSDown output: ${mainFiles[0]}`));
1986
+ return mainFiles[0];
1987
+ }
1988
+ if (mainFiles.length > 1) {
1989
+ let bestMatch = mainFiles[0];
1990
+ let bestScore = 0;
1991
+ for (const file of mainFiles) {
1992
+ const filePath = path__namespace.join(dxtDir, file);
1993
+ const stats = fs__namespace.statSync(filePath);
1994
+ const nameScore = file.includes(baseNameWithoutExt) ? 100 : 0;
1995
+ const sizeScore = Math.min(stats.size / 1e3, 50);
1996
+ const totalScore = nameScore + sizeScore;
1997
+ if (totalScore > bestScore) {
1998
+ bestScore = totalScore;
1999
+ bestMatch = file;
2000
+ }
2001
+ }
2002
+ console.log(
2003
+ simpleChalk.gray(
2004
+ `✓ Detected TSDown output: ${bestMatch} (best match from ${mainFiles.length} candidates)`
2005
+ )
2006
+ );
2007
+ return bestMatch;
2008
+ }
2009
+ console.warn(
2010
+ simpleChalk.yellow(`⚠ Could not detect TSDown output file in ${outputDir}`)
2011
+ );
2012
+ return null;
2013
+ } catch (error) {
2014
+ console.warn(
2015
+ simpleChalk.yellow(
2016
+ `⚠ Error detecting TSDown output: ${error instanceof Error ? error.message : String(error)}`
2017
+ )
2018
+ );
2019
+ return null;
2707
2020
  }
2708
- const possibleLogoPaths = [
2709
- // From built library assets
2710
- path__namespace.join(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), "..", "assets", "logo_1_small.jpg"),
2711
- // From node_modules
2712
- path__namespace.join(process.cwd(), "node_modules", "@alcyone-labs", "arg-parser", "dist", "assets", "logo_1_small.jpg"),
2713
- // From package root dist/assets (for local build)
2714
- path__namespace.join(process.cwd(), "dist", "assets", "logo_1_small.jpg"),
2715
- // From library root (development)
2716
- path__namespace.join(process.cwd(), "..", "..", "..", "docs", "MCP", "icons", "logo_1_small.jpg")
2717
- ];
2718
- for (const logoPath of possibleLogoPaths) {
2719
- if (fs__namespace.existsSync(logoPath)) {
2720
- try {
2721
- fs__namespace.copyFileSync(logoPath, path__namespace.join(dxtDir, "logo.jpg"));
2722
- console.log(simpleChalk.gray(`✅ Logo copied from: ${logoPath}`));
2723
- return;
2724
- } catch (error) {
2725
- console.warn(simpleChalk.yellow(`⚠ Failed to copy logo from ${logoPath}: ${error}`));
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
+ }
2726
2083
  }
2727
2084
  }
2728
2085
  }
2729
- console.warn(simpleChalk.yellow("⚠ Logo not found in any expected location"));
2086
+ return { envVars, userConfig };
2730
2087
  }
2731
2088
  }
2732
2089
  class McpNotificationsManager {
@@ -2881,10 +2238,16 @@ class McpNotificationsManager {
2881
2238
  sendNotificationToClient(client, type2) {
2882
2239
  try {
2883
2240
  if (client.connection && typeof client.connection.sendNotification === "function") {
2884
- client.connection.sendNotification(`notifications/${type2}/list_changed`, {});
2241
+ client.connection.sendNotification(
2242
+ `notifications/${type2}/list_changed`,
2243
+ {}
2244
+ );
2885
2245
  }
2886
2246
  } catch (error) {
2887
- console.error(`Error sending notification to client ${client.clientId}:`, error);
2247
+ console.error(
2248
+ `Error sending notification to client ${client.clientId}:`,
2249
+ error
2250
+ );
2888
2251
  this.removeClient(client.clientId);
2889
2252
  }
2890
2253
  }
@@ -2973,7 +2336,9 @@ class McpPromptsManager {
2973
2336
  return await entry.config.handler(validatedArgs);
2974
2337
  } catch (error) {
2975
2338
  if (error instanceof zod.z.ZodError) {
2976
- throw new Error(`Invalid arguments for prompt '${name}': ${error.message}`);
2339
+ throw new Error(
2340
+ `Invalid arguments for prompt '${name}': ${error.message}`
2341
+ );
2977
2342
  }
2978
2343
  throw error;
2979
2344
  }
@@ -3173,7 +2538,9 @@ class McpResourcesManager {
3173
2538
  try {
3174
2539
  new ResourceTemplateParser(config.uriTemplate);
3175
2540
  } catch (error) {
3176
- throw new Error(`Invalid URI template '${config.uriTemplate}': ${error instanceof Error ? error.message : String(error)}`);
2541
+ throw new Error(
2542
+ `Invalid URI template '${config.uriTemplate}': ${error instanceof Error ? error.message : String(error)}`
2543
+ );
3177
2544
  }
3178
2545
  }
3179
2546
  /**
@@ -3278,6 +2645,97 @@ const _FlagManager = class _FlagManager {
3278
2645
  __flags = new WeakMap();
3279
2646
  _throwForDuplicateFlags = new WeakMap();
3280
2647
  let FlagManager = _FlagManager;
2648
+ function detectEntryPoint() {
2649
+ try {
2650
+ if (process.argv[1] && fs__namespace.existsSync(process.argv[1])) {
2651
+ return process.argv[1];
2652
+ }
2653
+ if (typeof require !== "undefined" && require.main && require.main.filename) {
2654
+ return require.main.filename;
2655
+ }
2656
+ return null;
2657
+ } catch {
2658
+ return null;
2659
+ }
2660
+ }
2661
+ function getEntryPointFromImportMeta(importMetaUrl) {
2662
+ if (importMetaUrl.startsWith("file://")) {
2663
+ return decodeURIComponent(importMetaUrl.replace("file://", ""));
2664
+ }
2665
+ return importMetaUrl;
2666
+ }
2667
+ function normalizePath(path2) {
2668
+ return path2.trim();
2669
+ }
2670
+ function resolveLogPath(logPath, fallbackEntryPoint) {
2671
+ if (typeof logPath === "string") {
2672
+ const normalizedPath2 = normalizePath(logPath);
2673
+ if (path__namespace.isAbsolute(normalizedPath2)) {
2674
+ return normalizedPath2;
2675
+ }
2676
+ if (normalizedPath2.startsWith("cwd:")) {
2677
+ const relativePath = normalizedPath2.slice(4);
2678
+ return path__namespace.resolve(process.cwd(), relativePath);
2679
+ }
2680
+ const entryPoint = detectEntryPoint() || fallbackEntryPoint;
2681
+ if (entryPoint) {
2682
+ return path__namespace.resolve(path__namespace.dirname(entryPoint), normalizedPath2);
2683
+ }
2684
+ console.warn(
2685
+ `Warning: Could not detect entry point for log path resolution. Using process.cwd() as fallback. Path: ${normalizedPath2}`
2686
+ );
2687
+ return path__namespace.resolve(process.cwd(), normalizedPath2);
2688
+ }
2689
+ const { path: logFilePath, relativeTo = "entry", basePath } = logPath;
2690
+ const normalizedPath = normalizePath(logFilePath);
2691
+ switch (relativeTo) {
2692
+ case "absolute":
2693
+ if (basePath) {
2694
+ return path__namespace.resolve(basePath, normalizedPath);
2695
+ }
2696
+ if (path__namespace.isAbsolute(normalizedPath)) {
2697
+ return normalizedPath;
2698
+ }
2699
+ console.warn(
2700
+ `Warning: relativeTo 'absolute' specified but no basePath provided and path is not absolute. Using process.cwd() as fallback. Path: ${normalizedPath}`
2701
+ );
2702
+ return path__namespace.resolve(process.cwd(), normalizedPath);
2703
+ case "cwd":
2704
+ return path__namespace.resolve(process.cwd(), normalizedPath);
2705
+ case "entry":
2706
+ default:
2707
+ const entryPoint = detectEntryPoint() || fallbackEntryPoint;
2708
+ if (entryPoint) {
2709
+ return path__namespace.resolve(path__namespace.dirname(entryPoint), normalizedPath);
2710
+ }
2711
+ console.warn(
2712
+ `Warning: Could not detect entry point for log path resolution. Using process.cwd() as fallback. Path: ${normalizedPath}`
2713
+ );
2714
+ return path__namespace.resolve(process.cwd(), normalizedPath);
2715
+ }
2716
+ }
2717
+ function entryRelative(path2) {
2718
+ return {
2719
+ path: path2,
2720
+ relativeTo: "entry"
2721
+ };
2722
+ }
2723
+ function cwdRelative(path2) {
2724
+ return {
2725
+ path: path2,
2726
+ relativeTo: "cwd"
2727
+ };
2728
+ }
2729
+ function absolutePath(path2, basePath) {
2730
+ return {
2731
+ path: path2,
2732
+ relativeTo: "absolute",
2733
+ basePath
2734
+ };
2735
+ }
2736
+ function legacyCwdPath(path2) {
2737
+ return `cwd:${path2}`;
2738
+ }
3281
2739
  class ArgParserError extends Error {
3282
2740
  constructor(message, cmdChain = []) {
3283
2741
  super(message);
@@ -4675,15 +4133,14 @@ _handleBuildDxtFlag_fn = async function(processArgs, buildDxtIndex) {
4675
4133
  };
4676
4134
  _handleMcpServeFlag_fn = async function(processArgs, _mcpServeIndex) {
4677
4135
  var _a;
4136
+ const transportOptions = __privateMethod(this, _ArgParserBase_instances, _parseMcpTransportOptions_fn).call(this, processArgs);
4137
+ const mcpServerConfig = __privateMethod(this, _ArgParserBase_instances, _getMcpServerConfiguration_fn).call(this);
4138
+ const effectiveLogPath = transportOptions.logPath || (mcpServerConfig == null ? void 0 : mcpServerConfig.logPath) || "./logs/mcp.log";
4139
+ const resolvedLogPath = resolveLogPath(effectiveLogPath);
4678
4140
  let mcpLogger;
4679
4141
  try {
4680
- const mcpLoggerModule = await Function(
4681
- 'return import("@alcyone-labs/simple-mcp-logger")'
4682
- )();
4683
- mcpLogger = mcpLoggerModule.createMcpLogger(
4684
- "MCP Serve",
4685
- "./logs/mcp.log"
4686
- );
4142
+ const mcpLoggerModule = await import("@alcyone-labs/simple-mcp-logger");
4143
+ mcpLogger = mcpLoggerModule.createMcpLogger("MCP Serve", resolvedLogPath);
4687
4144
  globalThis.console = mcpLogger;
4688
4145
  } catch {
4689
4146
  mcpLogger = {
@@ -4694,7 +4151,6 @@ _handleMcpServeFlag_fn = async function(processArgs, _mcpServeIndex) {
4694
4151
  mcpLogger.mcpError(
4695
4152
  "Starting --s-mcp-serve system flag handler - console hijacked for MCP safety"
4696
4153
  );
4697
- const mcpServerConfig = __privateMethod(this, _ArgParserBase_instances, _getMcpServerConfiguration_fn).call(this);
4698
4154
  if (!mcpServerConfig) {
4699
4155
  mcpLogger.mcpError(
4700
4156
  "No MCP server configuration found. Use withMcp() or addMcpSubCommand() to configure MCP server."
@@ -4708,13 +4164,16 @@ _handleMcpServeFlag_fn = async function(processArgs, _mcpServeIndex) {
4708
4164
  mcpLogger.mcpError(
4709
4165
  `Found MCP server configuration: ${((_a = mcpServerConfig.serverInfo) == null ? void 0 : _a.name) || "unnamed"}`
4710
4166
  );
4711
- const transportOptions = __privateMethod(this, _ArgParserBase_instances, _parseMcpTransportOptions_fn).call(this, processArgs);
4167
+ mcpLogger.mcpError(`Using log path: ${resolvedLogPath}`);
4712
4168
  mcpLogger.mcpError(
4713
4169
  `Transport options: ${JSON.stringify(transportOptions)}`
4714
4170
  );
4715
4171
  try {
4716
4172
  mcpLogger.mcpError("Starting unified MCP server with all tools");
4717
- await __privateMethod(this, _ArgParserBase_instances, _startUnifiedMcpServer_fn).call(this, mcpServerConfig, transportOptions);
4173
+ await __privateMethod(this, _ArgParserBase_instances, _startUnifiedMcpServer_fn).call(this, mcpServerConfig, {
4174
+ ...transportOptions,
4175
+ logPath: resolvedLogPath
4176
+ });
4718
4177
  mcpLogger.mcpError("Successfully started unified MCP server");
4719
4178
  } catch (error) {
4720
4179
  mcpLogger.mcpError(
@@ -4783,18 +4242,34 @@ _startUnifiedMcpServer_fn = async function(mcpServerConfig, transportOptions) {
4783
4242
  await mcpParser.startMcpServerWithMultipleTransports(
4784
4243
  serverInfo,
4785
4244
  transportConfigs,
4786
- toolOptions
4245
+ toolOptions,
4246
+ transportOptions.logPath
4787
4247
  );
4788
4248
  } catch (error) {
4789
4249
  throw new Error(
4790
4250
  `Error parsing transports configuration: ${error.message}. Expected JSON format: '[{"type":"stdio"},{"type":"sse","port":3001}]'`
4791
4251
  );
4792
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
+ );
4793
4267
  } else if (defaultTransports && defaultTransports.length > 0) {
4794
4268
  await mcpParser.startMcpServerWithMultipleTransports(
4795
4269
  serverInfo,
4796
4270
  defaultTransports,
4797
- toolOptions
4271
+ toolOptions,
4272
+ transportOptions.logPath
4798
4273
  );
4799
4274
  } else if (defaultTransport) {
4800
4275
  await mcpParser.startMcpServerWithTransport(
@@ -4806,20 +4281,16 @@ _startUnifiedMcpServer_fn = async function(mcpServerConfig, transportOptions) {
4806
4281
  path: defaultTransport.path,
4807
4282
  sessionIdGenerator: defaultTransport.sessionIdGenerator
4808
4283
  },
4809
- toolOptions
4284
+ toolOptions,
4285
+ transportOptions.logPath
4810
4286
  );
4811
4287
  } else {
4812
- const transportType = transportOptions.transportType || "stdio";
4813
- const finalTransportOptions = {
4814
- port: transportOptions.port,
4815
- host: transportOptions.host || "localhost",
4816
- path: transportOptions.path || "/mcp"
4817
- };
4818
4288
  await mcpParser.startMcpServerWithTransport(
4819
4289
  serverInfo,
4820
- transportType,
4821
- finalTransportOptions,
4822
- toolOptions
4290
+ "stdio",
4291
+ {},
4292
+ toolOptions,
4293
+ transportOptions.logPath
4823
4294
  );
4824
4295
  }
4825
4296
  };
@@ -4886,6 +4357,12 @@ _parseMcpTransportOptions_fn = function(processArgs) {
4886
4357
  i++;
4887
4358
  }
4888
4359
  break;
4360
+ case "--s-mcp-log-path":
4361
+ if (nextArg && !nextArg.startsWith("-")) {
4362
+ options.logPath = nextArg;
4363
+ i++;
4364
+ }
4365
+ break;
4889
4366
  // Backward compatibility: support old flags but with deprecation warning
4890
4367
  case "--transport":
4891
4368
  case "--port":
@@ -6171,11 +5648,14 @@ Migration guide: https://github.com/alcyone-labs/arg-parser/blob/main/docs/MCP-M
6171
5648
  * @param toolOptions Optional MCP tool generation options
6172
5649
  * @returns Configured MCP server instance
6173
5650
  */
6174
- async createMcpServer(serverInfo, toolOptions) {
6175
- var _a;
6176
- const logger = simpleMcpLogger.createMcpLogger("MCP Server Creation", "./logs/mcp.log");
5651
+ async createMcpServer(serverInfo, toolOptions, logPath) {
5652
+ var _a, _b;
5653
+ const resolvedLogPath = resolveLogPath(
5654
+ logPath || ((_a = this._mcpServerConfig) == null ? void 0 : _a.logPath) || "./logs/mcp.log"
5655
+ );
5656
+ const logger = simpleMcpLogger.createMcpLogger("MCP Server Creation", resolvedLogPath);
6177
5657
  try {
6178
- const effectiveServerInfo = serverInfo || ((_a = this._mcpServerConfig) == null ? void 0 : _a.serverInfo);
5658
+ const effectiveServerInfo = serverInfo || ((_b = this._mcpServerConfig) == null ? void 0 : _b.serverInfo);
6179
5659
  if (!effectiveServerInfo) {
6180
5660
  throw new Error(
6181
5661
  "No MCP server configuration found. Use withMcp() to configure server info or provide serverInfo parameter."
@@ -6356,11 +5836,11 @@ Migration guide: https://github.com/alcyone-labs/arg-parser/blob/main/docs/MCP-M
6356
5836
  * @param toolOptions Optional MCP tool generation options
6357
5837
  * @returns Promise that resolves when all servers are started
6358
5838
  */
6359
- async startMcpServerWithMultipleTransports(serverInfo, transports, toolOptions) {
6360
- const server = await this.createMcpServer(serverInfo, toolOptions);
5839
+ async startMcpServerWithMultipleTransports(serverInfo, transports, toolOptions, logPath) {
5840
+ const server = await this.createMcpServer(serverInfo, toolOptions, logPath);
6361
5841
  const startPromises = [];
6362
5842
  for (const transportConfig of transports) {
6363
- const promise = __privateMethod(this, _ArgParser_instances, _startSingleTransport_fn).call(this, server, serverInfo, transportConfig);
5843
+ const promise = __privateMethod(this, _ArgParser_instances, _startSingleTransport_fn).call(this, server, serverInfo, transportConfig, logPath);
6364
5844
  startPromises.push(promise);
6365
5845
  }
6366
5846
  await Promise.all(startPromises);
@@ -6373,12 +5853,12 @@ Migration guide: https://github.com/alcyone-labs/arg-parser/blob/main/docs/MCP-M
6373
5853
  * @param toolOptions Optional MCP tool generation options
6374
5854
  * @returns Promise that resolves when server is connected
6375
5855
  */
6376
- async startMcpServerWithTransport(serverInfo, transportType, transportOptions = {}, toolOptions) {
6377
- const server = await this.createMcpServer(serverInfo, toolOptions);
5856
+ async startMcpServerWithTransport(serverInfo, transportType, transportOptions = {}, toolOptions, logPath) {
5857
+ const server = await this.createMcpServer(serverInfo, toolOptions, logPath);
6378
5858
  await __privateMethod(this, _ArgParser_instances, _startSingleTransport_fn).call(this, server, serverInfo, {
6379
5859
  type: transportType,
6380
5860
  ...transportOptions
6381
- });
5861
+ }, logPath);
6382
5862
  }
6383
5863
  async parse(processArgs, options) {
6384
5864
  let result = await ArgParserBase.prototype.parse.call(
@@ -6640,8 +6120,9 @@ registerToolAsSubCommand_fn = function(toolConfig) {
6640
6120
  handler: toolConfig.handler
6641
6121
  });
6642
6122
  };
6643
- _startSingleTransport_fn = async function(server, serverInfo, transportConfig) {
6644
- const logger = simpleMcpLogger.createMcpLogger("MCP Transport", "./logs/mcp.log");
6123
+ _startSingleTransport_fn = async function(server, serverInfo, transportConfig, logPath) {
6124
+ const resolvedLogPath = resolveLogPath(logPath || "./logs/mcp.log");
6125
+ const logger = simpleMcpLogger.createMcpLogger("MCP Transport", resolvedLogPath);
6645
6126
  try {
6646
6127
  logger.mcpError(
6647
6128
  `Starting ${transportConfig.type} transport for server: ${serverInfo.name}`
@@ -6817,7 +6298,9 @@ class TomlConfigPlugin extends ConfigPlugin {
6817
6298
  }
6818
6299
  return parsed;
6819
6300
  } catch (error) {
6820
- throw new Error(`Failed to parse TOML: ${error instanceof Error ? error.message : String(error)}`);
6301
+ throw new Error(
6302
+ `Failed to parse TOML: ${error instanceof Error ? error.message : String(error)}`
6303
+ );
6821
6304
  }
6822
6305
  }
6823
6306
  generate(_config, flags, parsedArgs) {
@@ -6857,7 +6340,9 @@ class TomlConfigPlugin extends ConfigPlugin {
6857
6340
  const tomlContent = this.tomlModule.stringify(configWithValues);
6858
6341
  return lines.join("\n") + "\n" + tomlContent;
6859
6342
  } catch (error) {
6860
- throw new Error(`Failed to generate TOML: ${error instanceof Error ? error.message : String(error)}`);
6343
+ throw new Error(
6344
+ `Failed to generate TOML: ${error instanceof Error ? error.message : String(error)}`
6345
+ );
6861
6346
  }
6862
6347
  }
6863
6348
  /**
@@ -6893,7 +6378,10 @@ function createTomlPlugin() {
6893
6378
  try {
6894
6379
  return new TomlConfigPlugin();
6895
6380
  } catch (error) {
6896
- console.warn("TOML plugin not available:", error instanceof Error ? error.message : String(error));
6381
+ console.warn(
6382
+ "TOML plugin not available:",
6383
+ error instanceof Error ? error.message : String(error)
6384
+ );
6897
6385
  return null;
6898
6386
  }
6899
6387
  }
@@ -6909,7 +6397,10 @@ async function createTomlPluginAsync() {
6909
6397
  const tomlModule = await Promise.resolve().then(() => index$1);
6910
6398
  return new TomlConfigPlugin(tomlModule);
6911
6399
  } catch (error) {
6912
- console.warn("TOML plugin not available:", error instanceof Error ? error.message : String(error));
6400
+ console.warn(
6401
+ "TOML plugin not available:",
6402
+ error instanceof Error ? error.message : String(error)
6403
+ );
6913
6404
  return null;
6914
6405
  }
6915
6406
  }
@@ -6955,7 +6446,9 @@ class YamlConfigPlugin extends ConfigPlugin {
6955
6446
  }
6956
6447
  return parsed;
6957
6448
  } catch (error) {
6958
- throw new Error(`Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
6449
+ throw new Error(
6450
+ `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`
6451
+ );
6959
6452
  }
6960
6453
  }
6961
6454
  generate(_config, flags, parsedArgs) {
@@ -6989,7 +6482,9 @@ class YamlConfigPlugin extends ConfigPlugin {
6989
6482
  });
6990
6483
  return lines.join("\n") + "\n" + yamlContent;
6991
6484
  } catch (error) {
6992
- throw new Error(`Failed to generate YAML: ${error instanceof Error ? error.message : String(error)}`);
6485
+ throw new Error(
6486
+ `Failed to generate YAML: ${error instanceof Error ? error.message : String(error)}`
6487
+ );
6993
6488
  }
6994
6489
  }
6995
6490
  /**
@@ -7019,7 +6514,10 @@ function createYamlPlugin() {
7019
6514
  try {
7020
6515
  return new YamlConfigPlugin();
7021
6516
  } catch (error) {
7022
- console.warn("YAML plugin not available:", error instanceof Error ? error.message : String(error));
6517
+ console.warn(
6518
+ "YAML plugin not available:",
6519
+ error instanceof Error ? error.message : String(error)
6520
+ );
7023
6521
  return null;
7024
6522
  }
7025
6523
  }
@@ -7035,7 +6533,10 @@ async function createYamlPluginAsync() {
7035
6533
  const yamlModule = await import("js-yaml");
7036
6534
  return new YamlConfigPlugin(yamlModule);
7037
6535
  } catch (error) {
7038
- console.warn("YAML plugin not available:", error instanceof Error ? error.message : String(error));
6536
+ console.warn(
6537
+ "YAML plugin not available:",
6538
+ error instanceof Error ? error.message : String(error)
6539
+ );
7039
6540
  return null;
7040
6541
  }
7041
6542
  }
@@ -7064,7 +6565,9 @@ class ArgParserFuzzyTester {
7064
6565
  const results = [];
7065
6566
  if (this.options.verbose) {
7066
6567
  console.log(`Discovered ${commandPaths.length} command paths:`);
7067
- commandPaths.forEach((path2) => console.log(` ${path2.join(" ") || "(root)"}`));
6568
+ commandPaths.forEach(
6569
+ (path2) => console.log(` ${path2.join(" ") || "(root)"}`)
6570
+ );
7068
6571
  }
7069
6572
  for (const commandPath of commandPaths) {
7070
6573
  const pathResults = await this.testCommandPath(commandPath);
@@ -7090,7 +6593,12 @@ class ArgParserFuzzyTester {
7090
6593
  for (const [subCommandName, subCommand] of subCommands) {
7091
6594
  const newPath = [...currentPath, subCommandName];
7092
6595
  allPaths.push(newPath);
7093
- this.discoverSubCommandPaths(subCommand.parser, newPath, allPaths, depth + 1);
6596
+ this.discoverSubCommandPaths(
6597
+ subCommand.parser,
6598
+ newPath,
6599
+ allPaths,
6600
+ depth + 1
6601
+ );
7094
6602
  }
7095
6603
  }
7096
6604
  /**
@@ -8307,6 +7815,7 @@ class Protocol {
8307
7815
  this._responseHandlers = /* @__PURE__ */ new Map();
8308
7816
  this._progressHandlers = /* @__PURE__ */ new Map();
8309
7817
  this._timeoutInfo = /* @__PURE__ */ new Map();
7818
+ this._pendingDebouncedNotifications = /* @__PURE__ */ new Set();
8310
7819
  this.setNotificationHandler(CancelledNotificationSchema, (notification) => {
8311
7820
  const controller = this._requestHandlerAbortControllers.get(notification.params.requestId);
8312
7821
  controller === null || controller === void 0 ? void 0 : controller.abort(notification.params.reason);
@@ -8388,6 +7897,7 @@ class Protocol {
8388
7897
  const responseHandlers = this._responseHandlers;
8389
7898
  this._responseHandlers = /* @__PURE__ */ new Map();
8390
7899
  this._progressHandlers.clear();
7900
+ this._pendingDebouncedNotifications.clear();
8391
7901
  this._transport = void 0;
8392
7902
  (_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
8393
7903
  const error = new McpError(ErrorCode.ConnectionClosed, "Connection closed");
@@ -8587,10 +8097,32 @@ class Protocol {
8587
8097
  * Emits a notification, which is a one-way message that does not expect a response.
8588
8098
  */
8589
8099
  async notification(notification, options) {
8100
+ var _a, _b;
8590
8101
  if (!this._transport) {
8591
8102
  throw new Error("Not connected");
8592
8103
  }
8593
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
+ }
8594
8126
  const jsonrpcNotification = {
8595
8127
  ...notification,
8596
8128
  jsonrpc: "2.0"
@@ -24996,6 +24528,7 @@ exports.OutputSchemaPatterns = OutputSchemaPatterns;
24996
24528
  exports.SimpleChalk = simpleChalk;
24997
24529
  exports.TomlConfigPlugin = TomlConfigPlugin;
24998
24530
  exports.YamlConfigPlugin = YamlConfigPlugin;
24531
+ exports.absolutePath = absolutePath;
24999
24532
  exports.convertFlagToJsonSchemaProperty = convertFlagToJsonSchemaProperty;
25000
24533
  exports.convertFlagsToJsonSchema = convertFlagsToJsonSchema;
25001
24534
  exports.convertFlagsToZodSchema = convertFlagsToZodSchema;
@@ -25007,12 +24540,18 @@ exports.createTomlPlugin = createTomlPlugin;
25007
24540
  exports.createTomlPluginAsync = createTomlPluginAsync;
25008
24541
  exports.createYamlPlugin = createYamlPlugin;
25009
24542
  exports.createYamlPluginAsync = createYamlPluginAsync;
24543
+ exports.cwdRelative = cwdRelative;
24544
+ exports.detectEntryPoint = detectEntryPoint;
25010
24545
  exports.enableConfigPlugins = enableConfigPlugins;
25011
24546
  exports.enableOptionalConfigPlugins = enableOptionalConfigPlugins;
25012
24547
  exports.enableOptionalConfigPluginsAsync = enableOptionalConfigPluginsAsync;
24548
+ exports.entryRelative = entryRelative;
25013
24549
  exports.extractSimplifiedResponse = extractSimplifiedResponse;
25014
24550
  exports.generateMcpToolsFromArgParser = generateMcpToolsFromArgParser;
24551
+ exports.getEntryPointFromImportMeta = getEntryPointFromImportMeta;
25015
24552
  exports.getJsonSchemaTypeFromFlag = getJsonSchemaTypeFromFlag;
25016
24553
  exports.globalConfigPluginRegistry = globalConfigPluginRegistry;
24554
+ exports.legacyCwdPath = legacyCwdPath;
24555
+ exports.resolveLogPath = resolveLogPath;
25017
24556
  exports.zodFlagSchema = zodFlagSchema;
25018
24557
  //# sourceMappingURL=index.cjs.map