@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.
- package/README.md +226 -20
- package/dist/assets/.dxtignore.template +0 -1
- package/dist/config/ConfigurationManager.d.ts.map +1 -1
- package/dist/config/plugins/ConfigPlugin.d.ts.map +1 -1
- package/dist/config/plugins/ConfigPluginRegistry.d.ts +1 -1
- package/dist/config/plugins/ConfigPluginRegistry.d.ts.map +1 -1
- package/dist/config/plugins/TomlConfigPlugin.d.ts +1 -1
- package/dist/config/plugins/TomlConfigPlugin.d.ts.map +1 -1
- package/dist/config/plugins/YamlConfigPlugin.d.ts +1 -1
- package/dist/config/plugins/YamlConfigPlugin.d.ts.map +1 -1
- package/dist/config/plugins/index.d.ts +4 -4
- package/dist/config/plugins/index.d.ts.map +1 -1
- package/dist/core/ArgParser.d.ts +14 -3
- package/dist/core/ArgParser.d.ts.map +1 -1
- package/dist/core/ArgParserBase.d.ts.map +1 -1
- package/dist/core/log-path-utils.d.ts +59 -0
- package/dist/core/log-path-utils.d.ts.map +1 -0
- package/dist/core/types.d.ts +1 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/dxt/DxtGenerator-testUtils.d.ts +22 -0
- package/dist/dxt/DxtGenerator-testUtils.d.ts.map +1 -0
- package/dist/dxt/DxtGenerator.d.ts +11 -65
- package/dist/dxt/DxtGenerator.d.ts.map +1 -1
- package/dist/index.cjs +799 -1260
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.min.mjs +6303 -6736
- package/dist/index.min.mjs.map +1 -1
- package/dist/index.mjs +799 -1260
- package/dist/index.mjs.map +1 -1
- package/dist/mcp/ArgParserMcp.d.ts.map +1 -1
- package/dist/mcp/mcp-notifications.d.ts +4 -4
- package/dist/mcp/mcp-notifications.d.ts.map +1 -1
- package/dist/mcp/mcp-prompts.d.ts.map +1 -1
- package/dist/mcp/mcp-protocol-versions.d.ts +11 -11
- package/dist/mcp/mcp-protocol-versions.d.ts.map +1 -1
- package/dist/mcp/mcp-resources.d.ts.map +1 -1
- package/dist/testing/fuzzy-test-cli.d.ts.map +1 -1
- package/dist/testing/fuzzy-tester.d.ts.map +1 -1
- package/package.json +2 -3
- package/dist/assets/tsdown.dxt.config.ts +0 -37
package/dist/index.mjs
CHANGED
|
@@ -284,7 +284,9 @@ class JsonConfigPlugin extends ConfigPlugin {
|
|
|
284
284
|
const { _meta, ...config } = parsed;
|
|
285
285
|
return config;
|
|
286
286
|
} catch (error) {
|
|
287
|
-
throw new Error(
|
|
287
|
+
throw new Error(
|
|
288
|
+
`Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
289
|
+
);
|
|
288
290
|
}
|
|
289
291
|
}
|
|
290
292
|
generate(_config, flags, parsedArgs) {
|
|
@@ -500,7 +502,9 @@ function enableConfigPlugins(pluginNames) {
|
|
|
500
502
|
globalConfigPluginRegistry.registerPlugin(tomlPlugin);
|
|
501
503
|
}
|
|
502
504
|
} catch (error) {
|
|
503
|
-
console.warn(
|
|
505
|
+
console.warn(
|
|
506
|
+
`Failed to enable TOML plugin: ${error instanceof Error ? error.message : String(error)}`
|
|
507
|
+
);
|
|
504
508
|
}
|
|
505
509
|
break;
|
|
506
510
|
case "yaml":
|
|
@@ -511,7 +515,9 @@ function enableConfigPlugins(pluginNames) {
|
|
|
511
515
|
globalConfigPluginRegistry.registerPlugin(yamlPlugin);
|
|
512
516
|
}
|
|
513
517
|
} catch (error) {
|
|
514
|
-
console.warn(
|
|
518
|
+
console.warn(
|
|
519
|
+
`Failed to enable YAML plugin: ${error instanceof Error ? error.message : String(error)}`
|
|
520
|
+
);
|
|
515
521
|
}
|
|
516
522
|
break;
|
|
517
523
|
default:
|
|
@@ -535,14 +541,18 @@ class ConfigurationManager {
|
|
|
535
541
|
} else if (appName && appName !== "Argument Parser") {
|
|
536
542
|
baseName = appName;
|
|
537
543
|
}
|
|
538
|
-
baseName = baseName.split(/[\s-_]+/).map(
|
|
544
|
+
baseName = baseName.split(/[\s-_]+/).map(
|
|
545
|
+
(word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
|
|
546
|
+
).join("");
|
|
539
547
|
return `${baseName}.env`;
|
|
540
548
|
}
|
|
541
549
|
/**
|
|
542
550
|
* Handles the --s-save-to-env system flag at the final parser level
|
|
543
551
|
*/
|
|
544
552
|
handleSaveToEnvFlag(processArgs, parserChain) {
|
|
545
|
-
const saveToEnvIndex = processArgs.findIndex(
|
|
553
|
+
const saveToEnvIndex = processArgs.findIndex(
|
|
554
|
+
(arg) => arg === "--s-save-to-env"
|
|
555
|
+
);
|
|
546
556
|
if (saveToEnvIndex !== -1) {
|
|
547
557
|
let filePath;
|
|
548
558
|
if (saveToEnvIndex + 1 < processArgs.length) {
|
|
@@ -568,7 +578,11 @@ class ConfigurationManager {
|
|
|
568
578
|
const finalParser = parserChain[parserChain.length - 1];
|
|
569
579
|
const parsedArgs = finalParser.getLastParseResult();
|
|
570
580
|
if (!parsedArgs) {
|
|
571
|
-
console.log(
|
|
581
|
+
console.log(
|
|
582
|
+
simpleChalk.yellow(
|
|
583
|
+
"No parsed arguments available. Run the command first to generate configuration."
|
|
584
|
+
)
|
|
585
|
+
);
|
|
572
586
|
return;
|
|
573
587
|
}
|
|
574
588
|
const allFlags = [];
|
|
@@ -601,10 +615,18 @@ class ConfigurationManager {
|
|
|
601
615
|
fs.writeFileSync(filePath, content, "utf8");
|
|
602
616
|
console.log(simpleChalk.green(`✅ Configuration saved to: ${filePath}`));
|
|
603
617
|
console.log(simpleChalk.gray(`Format: ${ext || ".env"}`));
|
|
604
|
-
console.log(
|
|
618
|
+
console.log(
|
|
619
|
+
simpleChalk.gray(`Flags saved: ${Object.keys(parsedArgs.args).length}`)
|
|
620
|
+
);
|
|
605
621
|
} catch (error) {
|
|
606
|
-
console.error(
|
|
607
|
-
|
|
622
|
+
console.error(
|
|
623
|
+
simpleChalk.red(
|
|
624
|
+
`❌ Failed to save configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
625
|
+
)
|
|
626
|
+
);
|
|
627
|
+
throw new Error(
|
|
628
|
+
`Failed to save configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
629
|
+
);
|
|
608
630
|
}
|
|
609
631
|
}
|
|
610
632
|
/**
|
|
@@ -641,7 +663,11 @@ class ConfigurationManager {
|
|
|
641
663
|
}
|
|
642
664
|
return this.convertConfigToFlagValues(rawConfig, parserChain);
|
|
643
665
|
} catch (error) {
|
|
644
|
-
console.warn(
|
|
666
|
+
console.warn(
|
|
667
|
+
simpleChalk.yellow(
|
|
668
|
+
`Warning: Could not load config file ${filePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
669
|
+
)
|
|
670
|
+
);
|
|
645
671
|
return {};
|
|
646
672
|
}
|
|
647
673
|
}
|
|
@@ -675,7 +701,9 @@ class ConfigurationManager {
|
|
|
675
701
|
if (plugin) {
|
|
676
702
|
return plugin.parse(content);
|
|
677
703
|
}
|
|
678
|
-
console.warn(
|
|
704
|
+
console.warn(
|
|
705
|
+
"YAML plugin not available, using simple parser. Install js-yaml and enable YAML plugin for full support."
|
|
706
|
+
);
|
|
679
707
|
const config = {};
|
|
680
708
|
const lines = content.split("\n");
|
|
681
709
|
let currentKey = null;
|
|
@@ -726,7 +754,9 @@ class ConfigurationManager {
|
|
|
726
754
|
try {
|
|
727
755
|
return JSON.parse(content) || {};
|
|
728
756
|
} catch (error) {
|
|
729
|
-
throw new Error(
|
|
757
|
+
throw new Error(
|
|
758
|
+
`Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
759
|
+
);
|
|
730
760
|
}
|
|
731
761
|
}
|
|
732
762
|
/**
|
|
@@ -737,7 +767,9 @@ class ConfigurationManager {
|
|
|
737
767
|
if (plugin) {
|
|
738
768
|
return plugin.parse(content);
|
|
739
769
|
}
|
|
740
|
-
console.warn(
|
|
770
|
+
console.warn(
|
|
771
|
+
"TOML plugin not available, using simple parser. Install smol-toml and enable TOML plugin for full support."
|
|
772
|
+
);
|
|
741
773
|
const config = {};
|
|
742
774
|
const lines = content.split("\n");
|
|
743
775
|
for (const line of lines) {
|
|
@@ -768,13 +800,19 @@ class ConfigurationManager {
|
|
|
768
800
|
for (const [key, value] of Object.entries(rawConfig)) {
|
|
769
801
|
let flag = allFlags.find((f) => f["name"] === key);
|
|
770
802
|
if (!flag) {
|
|
771
|
-
flag = allFlags.find(
|
|
803
|
+
flag = allFlags.find(
|
|
804
|
+
(f) => f["name"].toLowerCase() === key.toLowerCase()
|
|
805
|
+
);
|
|
772
806
|
}
|
|
773
807
|
if (flag) {
|
|
774
808
|
try {
|
|
775
809
|
flagValues[flag["name"]] = this.convertValueToFlagType(value, flag);
|
|
776
810
|
} catch (error) {
|
|
777
|
-
console.warn(
|
|
811
|
+
console.warn(
|
|
812
|
+
simpleChalk.yellow(
|
|
813
|
+
`Warning: Could not convert config value for flag '${key}': ${error instanceof Error ? error.message : String(error)}`
|
|
814
|
+
)
|
|
815
|
+
);
|
|
778
816
|
}
|
|
779
817
|
}
|
|
780
818
|
}
|
|
@@ -811,17 +849,23 @@ class ConfigurationManager {
|
|
|
811
849
|
}
|
|
812
850
|
const num = Number(value);
|
|
813
851
|
if (isNaN(num)) {
|
|
814
|
-
throw new Error(
|
|
852
|
+
throw new Error(
|
|
853
|
+
`Cannot convert '${value}' to number for flag '${flag["name"]}'`
|
|
854
|
+
);
|
|
815
855
|
}
|
|
816
856
|
return num;
|
|
817
857
|
} else if (isBooleanType) {
|
|
818
858
|
if (typeof value === "boolean") return value;
|
|
819
859
|
if (typeof value === "string") {
|
|
820
860
|
const lower = value.toLowerCase();
|
|
821
|
-
if (lower === "true" || lower === "1" || lower === "yes" || lower === "on")
|
|
822
|
-
|
|
861
|
+
if (lower === "true" || lower === "1" || lower === "yes" || lower === "on")
|
|
862
|
+
return true;
|
|
863
|
+
if (lower === "false" || lower === "0" || lower === "no" || lower === "off")
|
|
864
|
+
return false;
|
|
823
865
|
}
|
|
824
|
-
throw new Error(
|
|
866
|
+
throw new Error(
|
|
867
|
+
`Cannot convert '${value}' to boolean for flag '${flag["name"]}'`
|
|
868
|
+
);
|
|
825
869
|
} else if (flagType === "table") {
|
|
826
870
|
if (Array.isArray(value)) return value;
|
|
827
871
|
if (typeof value === "string") {
|
|
@@ -832,13 +876,17 @@ class ConfigurationManager {
|
|
|
832
876
|
return value.split(",").map((v) => v.trim());
|
|
833
877
|
}
|
|
834
878
|
}
|
|
835
|
-
throw new Error(
|
|
879
|
+
throw new Error(
|
|
880
|
+
`Cannot convert '${value}' to table for flag '${flag["name"]}'`
|
|
881
|
+
);
|
|
836
882
|
} else {
|
|
837
883
|
if (typeof flagType === "function") {
|
|
838
884
|
try {
|
|
839
885
|
return flagType(value);
|
|
840
886
|
} catch (error) {
|
|
841
|
-
throw new Error(
|
|
887
|
+
throw new Error(
|
|
888
|
+
`Custom type conversion failed for flag '${flag["name"]}': ${error instanceof Error ? error.message : String(error)}`
|
|
889
|
+
);
|
|
842
890
|
}
|
|
843
891
|
}
|
|
844
892
|
return String(value);
|
|
@@ -913,7 +961,9 @@ class ConfigurationManager {
|
|
|
913
961
|
if (Array.isArray(value)) {
|
|
914
962
|
lines.push(`${flag["name"]}:`);
|
|
915
963
|
for (const item of value) {
|
|
916
|
-
lines.push(
|
|
964
|
+
lines.push(
|
|
965
|
+
` - ${typeof item === "string" && item.includes(" ") ? `"${item}"` : item}`
|
|
966
|
+
);
|
|
917
967
|
}
|
|
918
968
|
} else if (typeof value === "string" && value.includes(" ")) {
|
|
919
969
|
lines.push(`${flag["name"]}: "${value}"`);
|
|
@@ -1147,64 +1197,22 @@ function createOutputSchema(pattern2) {
|
|
|
1147
1197
|
}
|
|
1148
1198
|
return OutputSchemaPatterns.successError();
|
|
1149
1199
|
}
|
|
1150
|
-
class
|
|
1151
|
-
constructor(argParserInstance) {
|
|
1200
|
+
class DxtGeneratorTestUtils {
|
|
1201
|
+
constructor(argParserInstance, extractMcpServerInfo, handleExit) {
|
|
1152
1202
|
this.argParserInstance = argParserInstance;
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
* Helper method to handle exit logic based on autoExit setting
|
|
1156
|
-
*/
|
|
1157
|
-
_handleExit(exitCode, message, type2, data2) {
|
|
1158
|
-
const result = {
|
|
1159
|
-
success: exitCode === 0,
|
|
1160
|
-
exitCode,
|
|
1161
|
-
message,
|
|
1162
|
-
type: type2 || (exitCode === 0 ? "success" : "error"),
|
|
1163
|
-
shouldExit: true,
|
|
1164
|
-
data: data2
|
|
1165
|
-
};
|
|
1166
|
-
if (this.argParserInstance.getAutoExit() && typeof process === "object" && typeof process.exit === "function") {
|
|
1167
|
-
process.exit(exitCode);
|
|
1168
|
-
}
|
|
1169
|
-
return result;
|
|
1170
|
-
}
|
|
1171
|
-
/**
|
|
1172
|
-
* Handles the --s-build-dxt system flag to generate DXT packages for MCP servers
|
|
1173
|
-
*/
|
|
1174
|
-
async handleBuildDxtFlag(processArgs, buildDxtIndex) {
|
|
1175
|
-
var _a, _b, _c;
|
|
1176
|
-
try {
|
|
1177
|
-
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"));
|
|
1178
|
-
if (isTestMode) {
|
|
1179
|
-
return await this.handleTestModeDxtGeneration(processArgs, buildDxtIndex);
|
|
1180
|
-
}
|
|
1181
|
-
const entryPointFile = process.argv[1];
|
|
1182
|
-
if (!entryPointFile || !fs.existsSync(entryPointFile)) {
|
|
1183
|
-
console.error(simpleChalk.red(`Error: Entry point file not found: ${entryPointFile}`));
|
|
1184
|
-
return this._handleExit(1, "Entry point file not found", "error");
|
|
1185
|
-
}
|
|
1186
|
-
const outputDir = processArgs[buildDxtIndex + 1] || "./dxt";
|
|
1187
|
-
console.log(simpleChalk.cyan(`
|
|
1188
|
-
🔧 Building DXT package for entry point: ${path.basename(entryPointFile)}`));
|
|
1189
|
-
console.log(simpleChalk.gray(`Output directory: ${outputDir}`));
|
|
1190
|
-
await this.buildDxtWithTsdown(entryPointFile, outputDir);
|
|
1191
|
-
console.log(simpleChalk.green(`
|
|
1192
|
-
✅ DXT package generation completed!`));
|
|
1193
|
-
return this._handleExit(0, "DXT package generation completed", "success", { entryPoint: entryPointFile, outputDir });
|
|
1194
|
-
} catch (error) {
|
|
1195
|
-
console.error(simpleChalk.red(`Error generating DXT package: ${error instanceof Error ? error.message : String(error)}`));
|
|
1196
|
-
return this._handleExit(1, `Error generating DXT package: ${error instanceof Error ? error.message : String(error)}`, "error");
|
|
1197
|
-
}
|
|
1203
|
+
this.extractMcpServerInfo = extractMcpServerInfo;
|
|
1204
|
+
this.handleExit = handleExit;
|
|
1198
1205
|
}
|
|
1199
1206
|
/**
|
|
1200
1207
|
* Handles DXT generation in test mode by creating mock DXT package structure
|
|
1208
|
+
* This method creates simplified mock files for testing purposes
|
|
1201
1209
|
*/
|
|
1202
1210
|
async handleTestModeDxtGeneration(processArgs, buildDxtIndex) {
|
|
1203
1211
|
try {
|
|
1204
1212
|
const outputDir = processArgs[buildDxtIndex + 1] || "./dxt-packages";
|
|
1205
1213
|
const mcpTools = this.argParserInstance.toMcpTools();
|
|
1206
1214
|
if (mcpTools.length === 0) {
|
|
1207
|
-
return this.
|
|
1215
|
+
return this.handleExit(0, "No MCP servers found", "success");
|
|
1208
1216
|
}
|
|
1209
1217
|
const serverInfo = this.extractMcpServerInfo();
|
|
1210
1218
|
const folderName = `${serverInfo.name.replace(/[^a-zA-Z0-9_-]/g, "_")}-dxt`;
|
|
@@ -1233,7 +1241,10 @@ class DxtGenerator {
|
|
|
1233
1241
|
})),
|
|
1234
1242
|
icon: "logo.jpg"
|
|
1235
1243
|
};
|
|
1236
|
-
fs.writeFileSync(
|
|
1244
|
+
fs.writeFileSync(
|
|
1245
|
+
path.join(buildDir, "manifest.json"),
|
|
1246
|
+
JSON.stringify(manifest, null, 2)
|
|
1247
|
+
);
|
|
1237
1248
|
const packageJson = {
|
|
1238
1249
|
name: serverInfo.name,
|
|
1239
1250
|
version: serverInfo.version,
|
|
@@ -1241,7 +1252,10 @@ class DxtGenerator {
|
|
|
1241
1252
|
main: "index.mjs",
|
|
1242
1253
|
type: "module"
|
|
1243
1254
|
};
|
|
1244
|
-
fs.writeFileSync(
|
|
1255
|
+
fs.writeFileSync(
|
|
1256
|
+
path.join(buildDir, "package.json"),
|
|
1257
|
+
JSON.stringify(packageJson, null, 2)
|
|
1258
|
+
);
|
|
1245
1259
|
const readme = `# ${serverInfo.name}
|
|
1246
1260
|
|
|
1247
1261
|
${serverInfo.description}
|
|
@@ -1250,88 +1264,172 @@ Generated by @alcyone-labs/arg-parser`;
|
|
|
1250
1264
|
fs.writeFileSync(path.join(buildDir, "README.md"), readme);
|
|
1251
1265
|
const buildScript = `#!/bin/bash
|
|
1252
1266
|
echo "Mock DXT build script for ${serverInfo.name}"`;
|
|
1253
|
-
fs.writeFileSync(
|
|
1254
|
-
|
|
1267
|
+
fs.writeFileSync(
|
|
1268
|
+
path.join(buildDir, "build-dxt-package.sh"),
|
|
1269
|
+
buildScript
|
|
1270
|
+
);
|
|
1271
|
+
return this.handleExit(0, "DXT package generation completed", "success", {
|
|
1255
1272
|
entryPoint: "test-mode",
|
|
1256
1273
|
outputDir: buildDir
|
|
1257
1274
|
});
|
|
1258
1275
|
} catch (error) {
|
|
1259
|
-
return this.
|
|
1276
|
+
return this.handleExit(
|
|
1277
|
+
1,
|
|
1278
|
+
`Test mode DXT generation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
1279
|
+
"error"
|
|
1280
|
+
);
|
|
1260
1281
|
}
|
|
1261
1282
|
}
|
|
1262
1283
|
/**
|
|
1263
|
-
*
|
|
1264
|
-
*
|
|
1284
|
+
* Checks if the current environment is in test mode
|
|
1285
|
+
* Used to determine whether to use test utilities or production code
|
|
1265
1286
|
*/
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
const
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
fs.chmodSync(serverScriptPath, 493);
|
|
1290
|
-
} catch (error) {
|
|
1291
|
-
console.warn("⚠ Could not set executable permission on server script:", error instanceof Error ? error.message : String(error));
|
|
1292
|
-
}
|
|
1293
|
-
const packageJson = this.createDxtPackageJson(serverInfo);
|
|
1294
|
-
fs.writeFileSync(path.join(buildDir, "package.json"), JSON.stringify(packageJson, null, 2));
|
|
1295
|
-
const readme = this.createDxtReadme(serverInfo);
|
|
1296
|
-
fs.writeFileSync(path.join(buildDir, "README.md"), readme);
|
|
1297
|
-
const buildScript = this.createSimpleBuildScript(serverInfo);
|
|
1298
|
-
fs.writeFileSync(path.join(buildDir, "build-dxt.sh"), buildScript);
|
|
1299
|
-
const dxtIgnore = this.createDxtIgnore();
|
|
1300
|
-
fs.writeFileSync(path.join(buildDir, ".dxtignore"), dxtIgnore);
|
|
1301
|
-
try {
|
|
1302
|
-
fs.chmodSync(path.join(buildDir, "build-dxt.sh"), 493);
|
|
1303
|
-
} catch (error) {
|
|
1287
|
+
static isTestMode() {
|
|
1288
|
+
var _a, _b, _c;
|
|
1289
|
+
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"));
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
class DxtGenerator {
|
|
1293
|
+
constructor(argParserInstance) {
|
|
1294
|
+
this.argParserInstance = argParserInstance;
|
|
1295
|
+
}
|
|
1296
|
+
/**
|
|
1297
|
+
* Helper method to handle exit logic based on autoExit setting
|
|
1298
|
+
*/
|
|
1299
|
+
_handleExit(exitCode, message, type2, data2) {
|
|
1300
|
+
const result = {
|
|
1301
|
+
success: exitCode === 0,
|
|
1302
|
+
exitCode,
|
|
1303
|
+
message,
|
|
1304
|
+
type: type2 || (exitCode === 0 ? "success" : "error"),
|
|
1305
|
+
shouldExit: true,
|
|
1306
|
+
data: data2
|
|
1307
|
+
};
|
|
1308
|
+
if (this.argParserInstance.getAutoExit() && typeof process === "object" && typeof process.exit === "function") {
|
|
1309
|
+
process.exit(exitCode);
|
|
1304
1310
|
}
|
|
1305
|
-
|
|
1306
|
-
console.log(simpleChalk.gray(` Server: ${serverInfo.name} v${serverInfo.version}`));
|
|
1307
|
-
console.log(simpleChalk.gray(` Tools: ${tools.length} tool(s)`));
|
|
1308
|
-
console.log(simpleChalk.gray(` Location: ${buildDir}`));
|
|
1309
|
-
console.log(simpleChalk.cyan(`
|
|
1310
|
-
📦 Creating DXT package using Anthropic's dxt pack...`));
|
|
1311
|
-
console.log(simpleChalk.cyan(`
|
|
1312
|
-
📋 Manual steps to create your DXT package:`));
|
|
1313
|
-
console.log(simpleChalk.white(` cd ${path.relative(process.cwd(), buildDir)}`));
|
|
1314
|
-
console.log(simpleChalk.white(` ./build-dxt.sh`));
|
|
1311
|
+
return result;
|
|
1315
1312
|
}
|
|
1316
1313
|
/**
|
|
1317
|
-
*
|
|
1314
|
+
* Handles the --s-build-dxt system flag to generate DXT packages for MCP servers
|
|
1318
1315
|
*/
|
|
1319
|
-
|
|
1316
|
+
async handleBuildDxtFlag(processArgs, buildDxtIndex) {
|
|
1320
1317
|
try {
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1318
|
+
if (DxtGeneratorTestUtils.isTestMode()) {
|
|
1319
|
+
const testUtils = new DxtGeneratorTestUtils(
|
|
1320
|
+
this.argParserInstance,
|
|
1321
|
+
() => this.extractMcpServerInfo(),
|
|
1322
|
+
(exitCode, message, type2, data2) => this._handleExit(exitCode, message, type2, data2)
|
|
1323
|
+
);
|
|
1324
|
+
return await testUtils.handleTestModeDxtGeneration(
|
|
1325
|
+
processArgs,
|
|
1326
|
+
buildDxtIndex
|
|
1327
|
+
);
|
|
1328
|
+
}
|
|
1329
|
+
const withNodeModules = processArgs.includes("--s-with-node-modules");
|
|
1330
|
+
if (withNodeModules) {
|
|
1331
|
+
console.log(
|
|
1332
|
+
simpleChalk.yellow(
|
|
1333
|
+
"🗂️ --s-with-node-modules detected: will include node_modules in bundle"
|
|
1334
|
+
)
|
|
1335
|
+
);
|
|
1336
|
+
const nodeModulesPath = path.resolve("./node_modules");
|
|
1337
|
+
if (!fs.existsSync(nodeModulesPath)) {
|
|
1338
|
+
console.error(
|
|
1339
|
+
simpleChalk.red(
|
|
1340
|
+
"❌ Error: node_modules directory not found. Please run the installation command first."
|
|
1341
|
+
)
|
|
1342
|
+
);
|
|
1343
|
+
console.log(
|
|
1344
|
+
simpleChalk.cyan(
|
|
1345
|
+
"💡 Required command: pnpm install --prod --node-linker=hoisted"
|
|
1346
|
+
)
|
|
1347
|
+
);
|
|
1348
|
+
return this._handleExit(
|
|
1349
|
+
1,
|
|
1350
|
+
"node_modules directory not found",
|
|
1351
|
+
"error"
|
|
1352
|
+
);
|
|
1353
|
+
}
|
|
1354
|
+
try {
|
|
1355
|
+
const nodeModulesContents = fs.readdirSync(nodeModulesPath);
|
|
1356
|
+
const hasNestedNodeModules = nodeModulesContents.filter((item) => !item.startsWith(".") && !item.startsWith("@")).some((item) => {
|
|
1357
|
+
const itemPath = path.join(nodeModulesPath, item);
|
|
1358
|
+
try {
|
|
1359
|
+
return fs.statSync(itemPath).isDirectory() && fs.existsSync(path.join(itemPath, "node_modules"));
|
|
1360
|
+
} catch {
|
|
1361
|
+
return false;
|
|
1362
|
+
}
|
|
1363
|
+
});
|
|
1364
|
+
if (hasNestedNodeModules) {
|
|
1365
|
+
console.warn(
|
|
1366
|
+
simpleChalk.yellow(
|
|
1367
|
+
"⚠️ Warning: Detected nested node_modules. For best results, ensure hoisted installation:"
|
|
1368
|
+
)
|
|
1369
|
+
);
|
|
1370
|
+
console.log(
|
|
1371
|
+
simpleChalk.cyan(
|
|
1372
|
+
" rm -rf node_modules && pnpm install --prod --node-linker=hoisted"
|
|
1373
|
+
)
|
|
1374
|
+
);
|
|
1375
|
+
} else {
|
|
1376
|
+
console.log(
|
|
1377
|
+
simpleChalk.green(
|
|
1378
|
+
"✅ node_modules appears properly hoisted and ready for bundling"
|
|
1379
|
+
)
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1382
|
+
} catch (error) {
|
|
1383
|
+
console.warn(
|
|
1384
|
+
simpleChalk.yellow(
|
|
1385
|
+
`⚠️ Could not validate node_modules structure: ${error instanceof Error ? error.message : String(error)}`
|
|
1386
|
+
)
|
|
1387
|
+
);
|
|
1388
|
+
}
|
|
1389
|
+
console.log(
|
|
1390
|
+
simpleChalk.gray(
|
|
1391
|
+
"💡 This will create a fully autonomous DXT with all native dependencies included"
|
|
1392
|
+
)
|
|
1393
|
+
);
|
|
1331
1394
|
}
|
|
1395
|
+
const entryPointFile = process.argv[1];
|
|
1396
|
+
if (!entryPointFile || !fs.existsSync(entryPointFile)) {
|
|
1397
|
+
console.error(
|
|
1398
|
+
simpleChalk.red(`Error: Entry point file not found: ${entryPointFile}`)
|
|
1399
|
+
);
|
|
1400
|
+
return this._handleExit(1, "Entry point file not found", "error");
|
|
1401
|
+
}
|
|
1402
|
+
let outputDir = processArgs[buildDxtIndex + 1] || "./dxt";
|
|
1403
|
+
if (outputDir.startsWith("--s-")) outputDir = "./dxt";
|
|
1404
|
+
console.log(
|
|
1405
|
+
simpleChalk.cyan(
|
|
1406
|
+
`
|
|
1407
|
+
🔧 Building DXT package for entry point: ${entryPointFile}`
|
|
1408
|
+
)
|
|
1409
|
+
);
|
|
1410
|
+
console.log(simpleChalk.gray(`Output directory: ${outputDir}`));
|
|
1411
|
+
console.log(simpleChalk.gray(`Entrypoint file: ${entryPointFile}`));
|
|
1412
|
+
await this.buildDxtWithTsdown(entryPointFile, outputDir, withNodeModules);
|
|
1413
|
+
console.log(simpleChalk.green(`
|
|
1414
|
+
✅ DXT package generation completed!`));
|
|
1415
|
+
return this._handleExit(
|
|
1416
|
+
0,
|
|
1417
|
+
"DXT package generation completed",
|
|
1418
|
+
"success",
|
|
1419
|
+
{ entryPoint: entryPointFile, outputDir }
|
|
1420
|
+
);
|
|
1332
1421
|
} catch (error) {
|
|
1422
|
+
console.error(
|
|
1423
|
+
simpleChalk.red(
|
|
1424
|
+
`Error generating DXT package: ${error instanceof Error ? error.message : String(error)}`
|
|
1425
|
+
)
|
|
1426
|
+
);
|
|
1427
|
+
return this._handleExit(
|
|
1428
|
+
1,
|
|
1429
|
+
`Error generating DXT package: ${error instanceof Error ? error.message : String(error)}`,
|
|
1430
|
+
"error"
|
|
1431
|
+
);
|
|
1333
1432
|
}
|
|
1334
|
-
return null;
|
|
1335
1433
|
}
|
|
1336
1434
|
/**
|
|
1337
1435
|
* Extracts server information from MCP configuration
|
|
@@ -1370,7 +1468,9 @@ echo "Mock DXT build script for ${serverInfo.name}"`;
|
|
|
1370
1468
|
toolOptions = mcpConfig.toolOptions;
|
|
1371
1469
|
}
|
|
1372
1470
|
}
|
|
1373
|
-
const mcpTools = this.argParserInstance.toMcpTools(
|
|
1471
|
+
const mcpTools = this.argParserInstance.toMcpTools(
|
|
1472
|
+
toolOptions
|
|
1473
|
+
);
|
|
1374
1474
|
return mcpTools.map((tool) => ({
|
|
1375
1475
|
name: tool.name,
|
|
1376
1476
|
description: tool.description
|
|
@@ -1394,511 +1494,29 @@ echo "Mock DXT build script for ${serverInfo.name}"`;
|
|
|
1394
1494
|
});
|
|
1395
1495
|
}
|
|
1396
1496
|
}
|
|
1397
|
-
return tools.length > 0 ? tools : [
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
} catch (error) {
|
|
1402
|
-
console.warn(simpleChalk.yellow(`Warning: Could not generate detailed tool list: ${error instanceof Error ? error.message : String(error)}`));
|
|
1403
|
-
return [{
|
|
1404
|
-
name: "main",
|
|
1405
|
-
description: "Main command tool"
|
|
1406
|
-
}];
|
|
1407
|
-
}
|
|
1408
|
-
}
|
|
1409
|
-
createDxtManifest(serverInfo, tools, mcpSubCommand, logoFilename) {
|
|
1410
|
-
var _a;
|
|
1411
|
-
const packageInfo = this.readPackageJsonInfo();
|
|
1412
|
-
let author = serverInfo.author;
|
|
1413
|
-
if (!author && (packageInfo == null ? void 0 : packageInfo.author)) {
|
|
1414
|
-
if (typeof packageInfo.author === "string") {
|
|
1415
|
-
const match = packageInfo.author.match(/^([^<]+?)(?:\s*<([^>]+)>)?$/);
|
|
1416
|
-
if (match) {
|
|
1417
|
-
author = {
|
|
1418
|
-
name: match[1].trim(),
|
|
1419
|
-
email: (_a = match[2]) == null ? void 0 : _a.trim()
|
|
1420
|
-
};
|
|
1421
|
-
} else {
|
|
1422
|
-
author = { name: packageInfo.author };
|
|
1423
|
-
}
|
|
1424
|
-
} else {
|
|
1425
|
-
author = packageInfo.author;
|
|
1426
|
-
}
|
|
1427
|
-
}
|
|
1428
|
-
if (!author) {
|
|
1429
|
-
throw new Error("DXT manifest requires author information. Please provide it via withMcp() serverInfo.author, addMcpSubCommand serverInfo.author, or in package.json");
|
|
1430
|
-
}
|
|
1431
|
-
const cliArgs = this.generateCliArgsForDxt(mcpSubCommand);
|
|
1432
|
-
const { envVars, userConfig } = this.generateEnvAndUserConfig();
|
|
1433
|
-
const manifest = {
|
|
1434
|
-
dxt_version: "0.1",
|
|
1435
|
-
name: serverInfo.name,
|
|
1436
|
-
version: serverInfo.version,
|
|
1437
|
-
description: serverInfo.description || "MCP server generated from ArgParser",
|
|
1438
|
-
author,
|
|
1439
|
-
server: {
|
|
1440
|
-
type: "node",
|
|
1441
|
-
entry_point: "server/index.mjs",
|
|
1442
|
-
mcp_config: {
|
|
1443
|
-
command: "node",
|
|
1444
|
-
args: ["${__dirname}/server/index.mjs", ...cliArgs],
|
|
1445
|
-
env: envVars
|
|
1446
|
-
}
|
|
1447
|
-
},
|
|
1448
|
-
tools: tools.map((tool) => ({
|
|
1449
|
-
name: tool.name,
|
|
1450
|
-
description: tool.description
|
|
1451
|
-
}))
|
|
1452
|
-
};
|
|
1453
|
-
if (logoFilename) {
|
|
1454
|
-
manifest.icon = logoFilename;
|
|
1455
|
-
}
|
|
1456
|
-
if (userConfig && Object.keys(userConfig).length > 0) {
|
|
1457
|
-
manifest.user_config = userConfig;
|
|
1458
|
-
}
|
|
1459
|
-
if (serverInfo.repository || (packageInfo == null ? void 0 : packageInfo.repository)) {
|
|
1460
|
-
manifest.repository = serverInfo.repository || (packageInfo == null ? void 0 : packageInfo.repository);
|
|
1461
|
-
}
|
|
1462
|
-
if (serverInfo.license || (packageInfo == null ? void 0 : packageInfo.license)) {
|
|
1463
|
-
manifest.license = serverInfo.license || (packageInfo == null ? void 0 : packageInfo.license);
|
|
1464
|
-
}
|
|
1465
|
-
if (serverInfo.homepage || (packageInfo == null ? void 0 : packageInfo.homepage)) {
|
|
1466
|
-
manifest.homepage = serverInfo.homepage || (packageInfo == null ? void 0 : packageInfo.homepage);
|
|
1467
|
-
}
|
|
1468
|
-
return manifest;
|
|
1469
|
-
}
|
|
1470
|
-
validateDxtManifest(manifest) {
|
|
1471
|
-
const errors = [];
|
|
1472
|
-
if (!manifest.dxt_version) errors.push("Missing required field: dxt_version");
|
|
1473
|
-
if (!manifest.name) errors.push("Missing required field: name");
|
|
1474
|
-
if (!manifest.version) errors.push("Missing required field: version");
|
|
1475
|
-
if (!manifest.server) errors.push("Missing required field: server");
|
|
1476
|
-
if (!manifest.author) errors.push("Missing required field: author");
|
|
1477
|
-
if (manifest.server) {
|
|
1478
|
-
if (!manifest.server.type) errors.push("Missing required field: server.type");
|
|
1479
|
-
if (!manifest.server.entry_point) errors.push("Missing required field: server.entry_point");
|
|
1480
|
-
if (!manifest.server.mcp_config) errors.push("Missing required field: server.mcp_config");
|
|
1481
|
-
if (manifest.server.mcp_config) {
|
|
1482
|
-
if (!manifest.server.mcp_config.command) errors.push("Missing required field: server.mcp_config.command");
|
|
1483
|
-
if (!manifest.server.mcp_config.args || !Array.isArray(manifest.server.mcp_config.args)) {
|
|
1484
|
-
errors.push("Missing or invalid field: server.mcp_config.args (must be array)");
|
|
1497
|
+
return tools.length > 0 ? tools : [
|
|
1498
|
+
{
|
|
1499
|
+
name: "main",
|
|
1500
|
+
description: "Main command tool"
|
|
1485
1501
|
}
|
|
1486
|
-
|
|
1487
|
-
}
|
|
1488
|
-
if (manifest.author && typeof manifest.author === "object") {
|
|
1489
|
-
if (!manifest.author.name) errors.push("Missing required field: author.name");
|
|
1490
|
-
}
|
|
1491
|
-
if (manifest.dxt_version && manifest.dxt_version !== "0.1") {
|
|
1492
|
-
errors.push("Unsupported dxt_version: only '0.1' is currently supported");
|
|
1493
|
-
}
|
|
1494
|
-
if (errors.length > 0) {
|
|
1495
|
-
throw new Error(`DXT manifest validation failed:
|
|
1496
|
-
${errors.map((e) => ` - ${e}`).join("\n")}`);
|
|
1497
|
-
}
|
|
1498
|
-
}
|
|
1499
|
-
createServerScript(serverInfo, bundledCliPath) {
|
|
1500
|
-
const cliImportPath = bundledCliPath || "original-cli.mjs";
|
|
1501
|
-
return `#!/usr/bin/env node
|
|
1502
|
-
|
|
1503
|
-
// Generated MCP server for ${serverInfo.name}
|
|
1504
|
-
// This server uses @alcyone-labs/arg-parser's built-in MCP functionality for full protocol compliance
|
|
1505
|
-
|
|
1506
|
-
// FIRST: Set up MCP-safe logging to prevent STDOUT contamination
|
|
1507
|
-
import { createMcpLogger } from '@alcyone-labs/simple-mcp-logger';
|
|
1508
|
-
|
|
1509
|
-
// Auto-detect MCP mode and hijack console to prevent protocol corruption
|
|
1510
|
-
const mcpLogger = createMcpLogger('${serverInfo.name}');
|
|
1511
|
-
globalThis.console = mcpLogger;
|
|
1512
|
-
|
|
1513
|
-
// Now import the CLI which already has MCP functionality configured
|
|
1514
|
-
import originalCli from './${cliImportPath}';
|
|
1515
|
-
|
|
1516
|
-
// Server configuration
|
|
1517
|
-
const serverInfo = ${JSON.stringify(serverInfo, null, 2)};
|
|
1518
|
-
|
|
1519
|
-
// Use mcpError for debugging output (safe STDERR, visible in client logs)
|
|
1520
|
-
console.error(\`MCP Server: \${serverInfo.name} v\${serverInfo.version}\`);
|
|
1521
|
-
console.error(\`Description: \${serverInfo.description}\`);
|
|
1522
|
-
console.error(\`Generated from @alcyone-labs/arg-parser with built-in MCP functionality\`);
|
|
1523
|
-
${bundledCliPath ? "console.error(`Using bundled CLI for autonomous execution`);" : ""}
|
|
1524
|
-
|
|
1525
|
-
// The original CLI has MCP functionality configured via withMcp() or addMcpSubCommand()
|
|
1526
|
-
// We use the centralized --s-mcp-serve system flag to start the unified MCP server
|
|
1527
|
-
|
|
1528
|
-
// Start the MCP server using the library's built-in centralized serving
|
|
1529
|
-
// This works with both withMcp() configuration and legacy addMcpSubCommand() setups
|
|
1530
|
-
originalCli.parse(['--s-mcp-serve']);
|
|
1531
|
-
`;
|
|
1532
|
-
}
|
|
1533
|
-
createDxtPackageJson(serverInfo) {
|
|
1534
|
-
const useLocalBuild = process.env["LOCAL_BUILD"] === "1";
|
|
1535
|
-
const argParserDependency = useLocalBuild ? "file:../../arg-parser-local.tgz" : "^1.3.0";
|
|
1536
|
-
let originalDependencies = {};
|
|
1537
|
-
try {
|
|
1538
|
-
const originalPackageJsonPath = path.join(process.cwd(), "package.json");
|
|
1539
|
-
if (fs.existsSync(originalPackageJsonPath)) {
|
|
1540
|
-
const originalPackageJson = JSON.parse(fs.readFileSync(originalPackageJsonPath, "utf8"));
|
|
1541
|
-
originalDependencies = originalPackageJson.dependencies || {};
|
|
1542
|
-
}
|
|
1502
|
+
];
|
|
1543
1503
|
} catch (error) {
|
|
1544
|
-
console.warn(
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
const devDependencies = {
|
|
1554
|
-
"tsup": "^8.3.5"
|
|
1555
|
-
};
|
|
1556
|
-
Object.keys(dependencies2).forEach((key) => {
|
|
1557
|
-
const depValue = dependencies2[key];
|
|
1558
|
-
if (key !== "@alcyone-labs/arg-parser" && typeof depValue === "string" && depValue.startsWith("file:")) {
|
|
1559
|
-
delete dependencies2[key];
|
|
1560
|
-
console.warn(`⚠ Removed file: dependency ${key} from DXT package (not suitable for distribution)`);
|
|
1561
|
-
}
|
|
1562
|
-
});
|
|
1563
|
-
return {
|
|
1564
|
-
name: serverInfo.name,
|
|
1565
|
-
version: serverInfo.version,
|
|
1566
|
-
description: serverInfo.description,
|
|
1567
|
-
main: "server/index.mjs",
|
|
1568
|
-
type: "module",
|
|
1569
|
-
scripts: {
|
|
1570
|
-
start: "node server/index.mjs",
|
|
1571
|
-
"build-dxt": "./build-dxt.sh"
|
|
1572
|
-
},
|
|
1573
|
-
dependencies: dependencies2,
|
|
1574
|
-
devDependencies,
|
|
1575
|
-
engines: {
|
|
1576
|
-
node: ">=22.0.0"
|
|
1577
|
-
},
|
|
1578
|
-
author: serverInfo.author,
|
|
1579
|
-
license: serverInfo.license || "MIT",
|
|
1580
|
-
repository: serverInfo.repository
|
|
1581
|
-
};
|
|
1582
|
-
}
|
|
1583
|
-
/**
|
|
1584
|
-
* Creates a .dxtignore file to exclude build artifacts and unnecessary files
|
|
1585
|
-
*/
|
|
1586
|
-
createDxtIgnore() {
|
|
1587
|
-
return `# DXT ignore file - exclude these files from the DXT package
|
|
1588
|
-
# Generated by @alcyone-labs/arg-parser
|
|
1589
|
-
|
|
1590
|
-
# Build artifacts and logs
|
|
1591
|
-
*.log
|
|
1592
|
-
*.tmp
|
|
1593
|
-
temp-dxt-build/
|
|
1594
|
-
|
|
1595
|
-
# Build scripts (not needed in final package)
|
|
1596
|
-
build-dxt.sh
|
|
1597
|
-
arg-parser-local.tgz
|
|
1598
|
-
tsup.config.autonomous.js
|
|
1599
|
-
tsdown.config.mjs
|
|
1600
|
-
|
|
1601
|
-
# Original files (replaced by bundled autonomous build)
|
|
1602
|
-
server/index.original.mjs
|
|
1603
|
-
server/*.autonomous.mjs
|
|
1604
|
-
|
|
1605
|
-
# NOTE: server/original-cli.mjs is NOT excluded because it's needed for the MCP server to function
|
|
1606
|
-
# The bundled version (if created) will be server/original-cli.bundled.mjs
|
|
1607
|
-
|
|
1608
|
-
# NOTE: node_modules/ is NOT excluded because TSDown bundling may not be 100% autonomous
|
|
1609
|
-
# If bundling is successful, node_modules won't be needed, but we include it as fallback
|
|
1610
|
-
# The bundled server/index.mjs should be fully autonomous and not require node_modules
|
|
1611
|
-
|
|
1612
|
-
# Development files
|
|
1613
|
-
.git/
|
|
1614
|
-
.gitignore
|
|
1615
|
-
.env
|
|
1616
|
-
.env.*
|
|
1617
|
-
|
|
1618
|
-
# OS files
|
|
1619
|
-
.DS_Store
|
|
1620
|
-
Thumbs.db
|
|
1621
|
-
|
|
1622
|
-
# IDE files
|
|
1623
|
-
.vscode/
|
|
1624
|
-
.idea/
|
|
1625
|
-
*.swp
|
|
1626
|
-
*.swo
|
|
1627
|
-
`;
|
|
1628
|
-
}
|
|
1629
|
-
/**
|
|
1630
|
-
* Creates a simple build script that uses TSDown bundling and Anthropic's dxt pack
|
|
1631
|
-
*/
|
|
1632
|
-
createSimpleBuildScript(serverInfo) {
|
|
1633
|
-
return `#!/bin/bash
|
|
1634
|
-
|
|
1635
|
-
# Simple DXT Build Script for ${serverInfo.name}
|
|
1636
|
-
# Generated by @alcyone-labs/arg-parser with TSDown bundling
|
|
1637
|
-
|
|
1638
|
-
set -e
|
|
1639
|
-
|
|
1640
|
-
echo "📦 Creating DXT package for ${serverInfo.name}..."
|
|
1641
|
-
|
|
1642
|
-
# Step 1: Make server executable (required for MCP)
|
|
1643
|
-
echo "🔧 Making server executable..."
|
|
1644
|
-
chmod +x server/index.mjs
|
|
1645
|
-
|
|
1646
|
-
# Step 2: Handle local development dependencies
|
|
1647
|
-
if grep -q "file:.*arg-parser-local.tgz" package.json; then
|
|
1648
|
-
echo "🔧 Checking for local package tarball..."
|
|
1649
|
-
|
|
1650
|
-
# Check if the tarball exists in the parent directory
|
|
1651
|
-
if [ -f "../../arg-parser-local.tgz" ]; then
|
|
1652
|
-
echo "✅ Found local package tarball: ../../arg-parser-local.tgz"
|
|
1653
|
-
else
|
|
1654
|
-
echo "⚠️ Local tarball not found, falling back to npm registry"
|
|
1655
|
-
echo "💡 To use local build, run: cd /path/to/arg-parser && npm pack && cp *.tgz examples/community/canny-cli/"
|
|
1656
|
-
|
|
1657
|
-
# Replace with npm version
|
|
1658
|
-
sed -i.bak 's|"file:.*arg-parser-local.tgz"|"^1.3.0"|g' package.json 2>/dev/null || \\
|
|
1659
|
-
sed -i 's|"file:.*arg-parser-local.tgz"|"^1.3.0"|g' package.json
|
|
1660
|
-
fi
|
|
1661
|
-
fi
|
|
1662
|
-
|
|
1663
|
-
# Step 3: Install dependencies (for runtime only, bundling was done during generation)
|
|
1664
|
-
echo "📦 Installing dependencies..."
|
|
1665
|
-
npm install
|
|
1666
|
-
|
|
1667
|
-
# Step 4: Validate manifest
|
|
1668
|
-
echo "🔍 Validating DXT manifest..."
|
|
1669
|
-
if command -v npx >/dev/null 2>&1; then
|
|
1670
|
-
if npx @anthropic-ai/dxt validate manifest.json; then
|
|
1671
|
-
echo "✅ DXT manifest validation passed"
|
|
1672
|
-
else
|
|
1673
|
-
echo "❌ DXT manifest validation failed"
|
|
1674
|
-
exit 1
|
|
1675
|
-
fi
|
|
1676
|
-
else
|
|
1677
|
-
echo "⚠️ npx not found, skipping DXT validation"
|
|
1678
|
-
fi
|
|
1679
|
-
|
|
1680
|
-
# Step 5: Create DXT package using Anthropic's official packer
|
|
1681
|
-
echo "📦 Creating DXT package..."
|
|
1682
|
-
if command -v npx >/dev/null 2>&1; then
|
|
1683
|
-
# Use dxt pack directly with .dxtignore for clean packaging
|
|
1684
|
-
npx @anthropic-ai/dxt pack . "${serverInfo.name}.dxt"
|
|
1685
|
-
else
|
|
1686
|
-
# Fallback to standard zip if npx not available
|
|
1687
|
-
echo "⚠️ npx not found, using zip fallback"
|
|
1688
|
-
zip -r "${serverInfo.name}.dxt" . -x "node_modules/*" "*.log" ".git/*" "build-dxt.sh" "temp-dxt-build/*"
|
|
1689
|
-
fi
|
|
1690
|
-
|
|
1691
|
-
# Step 6: Sign the DXT package (optional)
|
|
1692
|
-
echo "🔐 Signing DXT package..."
|
|
1693
|
-
if command -v npx >/dev/null 2>&1 && command -v openssl >/dev/null 2>&1; then
|
|
1694
|
-
if npx @anthropic-ai/dxt sign "${serverInfo.name}.dxt" --self-signed; then
|
|
1695
|
-
echo "✅ DXT package signed successfully"
|
|
1696
|
-
else
|
|
1697
|
-
echo "⚠️ DXT signing failed, but package is still usable"
|
|
1698
|
-
fi
|
|
1699
|
-
else
|
|
1700
|
-
echo "⚠️ npx or openssl not found, skipping DXT signing"
|
|
1701
|
-
fi
|
|
1702
|
-
|
|
1703
|
-
echo "✅ DXT package created: ${serverInfo.name}.dxt"
|
|
1704
|
-
echo "🎯 This package includes bundled CLI with all dependencies!"
|
|
1705
|
-
echo ""
|
|
1706
|
-
echo "🎉 Installation Instructions:"
|
|
1707
|
-
echo "You can now take the file '${serverInfo.name}.dxt' and install it on Claude Desktop"
|
|
1708
|
-
echo "or supporting applications by using drag & drop on the Extensions Settings page,"
|
|
1709
|
-
echo "or directly pointing the file selector to this file."
|
|
1710
|
-
echo ""
|
|
1711
|
-
echo "📁 DXT file location: $(pwd)/${serverInfo.name}.dxt"
|
|
1712
|
-
`;
|
|
1713
|
-
}
|
|
1714
|
-
createDxtReadme(serverInfo) {
|
|
1715
|
-
return `# ${serverInfo.name}
|
|
1716
|
-
|
|
1717
|
-
${serverInfo.description}
|
|
1718
|
-
|
|
1719
|
-
## Installation
|
|
1720
|
-
|
|
1721
|
-
This is a Desktop Extension (DXT) package generated from @alcyone-labs/arg-parser.
|
|
1722
|
-
|
|
1723
|
-
### Automatic Installation
|
|
1724
|
-
Open this .dxt file with Claude Desktop or other DXT-compatible applications for single-click installation.
|
|
1725
|
-
|
|
1726
|
-
### Manual Installation
|
|
1727
|
-
1. Extract the .dxt file (it's a ZIP archive)
|
|
1728
|
-
2. Run \`npm install\` to install dependencies
|
|
1729
|
-
3. Start the server with \`npm start\`
|
|
1730
|
-
|
|
1731
|
-
## Tools
|
|
1732
|
-
|
|
1733
|
-
This MCP server provides the following tools:
|
|
1734
|
-
${this.generateMcpToolsForDxt().map((tool) => `- **${tool.name}**: ${tool.description}`).join("\n")}
|
|
1735
|
-
|
|
1736
|
-
## Building DXT Packages
|
|
1737
|
-
|
|
1738
|
-
To rebuild the DXT package:
|
|
1739
|
-
|
|
1740
|
-
### Prerequisites
|
|
1741
|
-
- Node.js 18+ installed
|
|
1742
|
-
- npm package manager
|
|
1743
|
-
|
|
1744
|
-
### Build Steps
|
|
1745
|
-
|
|
1746
|
-
\`\`\`bash
|
|
1747
|
-
# 1. Install dependencies
|
|
1748
|
-
npm install
|
|
1749
|
-
|
|
1750
|
-
# 2. Build DXT package
|
|
1751
|
-
npm run build-dxt
|
|
1752
|
-
# or
|
|
1753
|
-
./build-dxt.sh
|
|
1754
|
-
|
|
1755
|
-
# 3. The build script will:
|
|
1756
|
-
# - Install dependencies
|
|
1757
|
-
# - Validate the manifest
|
|
1758
|
-
# - Create the DXT package using Anthropic's official packer
|
|
1759
|
-
# - Sign the package (optional)
|
|
1760
|
-
\`\`\`
|
|
1761
|
-
|
|
1762
|
-
### Manual Build Process
|
|
1763
|
-
|
|
1764
|
-
If the automated build script doesn't work, you can build manually:
|
|
1765
|
-
|
|
1766
|
-
\`\`\`bash
|
|
1767
|
-
# 1. Install dependencies
|
|
1768
|
-
npm install
|
|
1769
|
-
|
|
1770
|
-
# 2. Create DXT package
|
|
1771
|
-
npx @anthropic-ai/dxt pack . ${serverInfo.name}.dxt
|
|
1772
|
-
|
|
1773
|
-
# 2. Update manifest.json
|
|
1774
|
-
# Change "entry_point" from "server/index.js" to "dist-autonomous/server.cjs"
|
|
1775
|
-
|
|
1776
|
-
# 3. Create new DXT with bundled server
|
|
1777
|
-
# Replace server/index.js with dist-autonomous/server.cjs
|
|
1778
|
-
# Remove package.json dependencies (optional)
|
|
1779
|
-
\`\`\`
|
|
1780
|
-
|
|
1781
|
-
### Result
|
|
1782
|
-
The resulting DXT package will be completely autonomous and won't require \`npm install\`.
|
|
1783
|
-
|
|
1784
|
-
## Generated Information
|
|
1785
|
-
|
|
1786
|
-
- **Generator**: @alcyone-labs/arg-parser v1.3.0
|
|
1787
|
-
- **Generated**: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
1788
|
-
- **DXT Version**: 0.1
|
|
1789
|
-
|
|
1790
|
-
## Note
|
|
1791
|
-
|
|
1792
|
-
This is a simplified DXT package. For full functionality and the latest features, use the original CLI directly.
|
|
1793
|
-
For autonomous packages, follow the build instructions above.
|
|
1794
|
-
`;
|
|
1795
|
-
}
|
|
1796
|
-
/**
|
|
1797
|
-
* Maps ArgParser flag types to DXT user config types
|
|
1798
|
-
*/
|
|
1799
|
-
mapFlagTypeToUserConfigType(flagType) {
|
|
1800
|
-
if (typeof flagType === "function") {
|
|
1801
|
-
if (flagType === String) return "string";
|
|
1802
|
-
if (flagType === Number) return "number";
|
|
1803
|
-
if (flagType === Boolean) return "boolean";
|
|
1804
|
-
if (flagType === Array) return "array";
|
|
1805
|
-
if (flagType === Object) return "object";
|
|
1806
|
-
return "string";
|
|
1807
|
-
}
|
|
1808
|
-
switch (String(flagType).toLowerCase()) {
|
|
1809
|
-
case "string":
|
|
1810
|
-
return "string";
|
|
1811
|
-
case "number":
|
|
1812
|
-
return "number";
|
|
1813
|
-
case "boolean":
|
|
1814
|
-
return "boolean";
|
|
1815
|
-
case "table":
|
|
1816
|
-
return "array";
|
|
1817
|
-
case "array":
|
|
1818
|
-
return "array";
|
|
1819
|
-
case "object":
|
|
1820
|
-
return "object";
|
|
1821
|
-
default:
|
|
1822
|
-
return "string";
|
|
1823
|
-
}
|
|
1824
|
-
}
|
|
1825
|
-
/**
|
|
1826
|
-
* Generates CLI arguments for DXT manifest based on ArgParser flags
|
|
1827
|
-
*/
|
|
1828
|
-
generateCliArgsForDxt(_mcpSubCommand) {
|
|
1829
|
-
const args = [];
|
|
1830
|
-
args.push("--s-mcp-serve");
|
|
1831
|
-
return args;
|
|
1832
|
-
}
|
|
1833
|
-
/**
|
|
1834
|
-
* Generates environment variables and user config for DXT manifest
|
|
1835
|
-
*/
|
|
1836
|
-
generateEnvAndUserConfig() {
|
|
1837
|
-
const envVars = {};
|
|
1838
|
-
const userConfig = {};
|
|
1839
|
-
const flags = this.argParserInstance.flags || [];
|
|
1840
|
-
for (const flag of flags) {
|
|
1841
|
-
const flagName = flag["name"];
|
|
1842
|
-
if (flagName === "help" || flagName === "mcp") continue;
|
|
1843
|
-
if (flag["env"]) {
|
|
1844
|
-
const envVarName = flag["env"];
|
|
1845
|
-
envVars[envVarName] = `\${user_config.${envVarName}}`;
|
|
1846
|
-
userConfig[envVarName] = {
|
|
1847
|
-
type: this.mapFlagTypeToUserConfigType(flag["type"]),
|
|
1848
|
-
title: this.generateUserConfigTitle(envVarName),
|
|
1849
|
-
description: flag["description"] || `${envVarName} environment variable`,
|
|
1850
|
-
required: true,
|
|
1851
|
-
// Always require env vars in user_config for better UX
|
|
1852
|
-
sensitive: this.isSensitiveField(envVarName)
|
|
1853
|
-
};
|
|
1854
|
-
}
|
|
1855
|
-
}
|
|
1856
|
-
if (typeof this.argParserInstance.getTools === "function") {
|
|
1857
|
-
const tools = this.argParserInstance.getTools();
|
|
1858
|
-
for (const [, toolConfig] of tools) {
|
|
1859
|
-
const toolFlags = toolConfig.flags || [];
|
|
1860
|
-
for (const flag of toolFlags) {
|
|
1861
|
-
const flagName = flag["name"];
|
|
1862
|
-
if (flagName === "help" || flagName.startsWith("s-")) continue;
|
|
1863
|
-
if (flag["env"]) {
|
|
1864
|
-
const envVarName = flag["env"];
|
|
1865
|
-
if (!envVars[envVarName]) {
|
|
1866
|
-
envVars[envVarName] = `\${user_config.${envVarName}}`;
|
|
1867
|
-
userConfig[envVarName] = {
|
|
1868
|
-
type: this.mapFlagTypeToUserConfigType(flag["type"]),
|
|
1869
|
-
title: this.generateUserConfigTitle(envVarName),
|
|
1870
|
-
description: flag["description"] || `${envVarName} environment variable`,
|
|
1871
|
-
required: true,
|
|
1872
|
-
// Always require env vars in user_config for better UX
|
|
1873
|
-
sensitive: this.isSensitiveField(envVarName)
|
|
1874
|
-
};
|
|
1875
|
-
}
|
|
1876
|
-
}
|
|
1504
|
+
console.warn(
|
|
1505
|
+
simpleChalk.yellow(
|
|
1506
|
+
`Warning: Could not generate detailed tool list: ${error instanceof Error ? error.message : String(error)}`
|
|
1507
|
+
)
|
|
1508
|
+
);
|
|
1509
|
+
return [
|
|
1510
|
+
{
|
|
1511
|
+
name: "main",
|
|
1512
|
+
description: "Main command tool"
|
|
1877
1513
|
}
|
|
1878
|
-
|
|
1514
|
+
];
|
|
1879
1515
|
}
|
|
1880
|
-
return { envVars, userConfig };
|
|
1881
|
-
}
|
|
1882
|
-
/**
|
|
1883
|
-
* Generates a user-friendly title for user config fields
|
|
1884
|
-
*/
|
|
1885
|
-
generateUserConfigTitle(flagName) {
|
|
1886
|
-
return flagName.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
|
|
1887
1516
|
}
|
|
1888
1517
|
/**
|
|
1889
|
-
*
|
|
1518
|
+
* Maps ArgParser flag types to DXT user config types
|
|
1890
1519
|
*/
|
|
1891
|
-
isSensitiveField(fieldName) {
|
|
1892
|
-
const sensitivePatterns = [
|
|
1893
|
-
/key/i,
|
|
1894
|
-
/token/i,
|
|
1895
|
-
/secret/i,
|
|
1896
|
-
/password/i,
|
|
1897
|
-
/auth/i,
|
|
1898
|
-
/credential/i
|
|
1899
|
-
];
|
|
1900
|
-
return sensitivePatterns.some((pattern2) => pattern2.test(fieldName));
|
|
1901
|
-
}
|
|
1902
1520
|
/**
|
|
1903
1521
|
* Adds the logo to the build folder if available
|
|
1904
1522
|
* @returns The filename of the logo that was added, or undefined if no logo was added
|
|
@@ -1918,27 +1536,38 @@ For autonomous packages, follow the build instructions above.
|
|
|
1918
1536
|
const urlPath = new URL(customLogo).pathname;
|
|
1919
1537
|
const urlFilename = path.basename(urlPath);
|
|
1920
1538
|
if (urlFilename && urlFilename.includes(".")) {
|
|
1921
|
-
|
|
1539
|
+
const ext = path.extname(urlFilename);
|
|
1540
|
+
logoFilename = `logo${ext}`;
|
|
1541
|
+
} else {
|
|
1542
|
+
logoFilename = "logo.jpg";
|
|
1922
1543
|
}
|
|
1923
1544
|
console.log("✓ Downloaded logo from URL");
|
|
1924
1545
|
} else {
|
|
1925
|
-
console.warn(
|
|
1546
|
+
console.warn(
|
|
1547
|
+
`⚠ Failed to download logo: HTTP ${response.status}`
|
|
1548
|
+
);
|
|
1926
1549
|
}
|
|
1927
1550
|
} catch (error) {
|
|
1928
|
-
console.warn(
|
|
1551
|
+
console.warn(
|
|
1552
|
+
"⚠ Failed to download logo from URL:",
|
|
1553
|
+
error instanceof Error ? error.message : String(error)
|
|
1554
|
+
);
|
|
1929
1555
|
}
|
|
1930
1556
|
} else {
|
|
1931
1557
|
let logoPath;
|
|
1932
1558
|
if (entryPointFile && !path.isAbsolute(customLogo)) {
|
|
1933
1559
|
const entryDir = path.dirname(entryPointFile);
|
|
1934
1560
|
logoPath = path.resolve(entryDir, customLogo);
|
|
1935
|
-
console.log(
|
|
1561
|
+
console.log(
|
|
1562
|
+
`📍 Resolving logo path relative to entry point: ${logoPath}`
|
|
1563
|
+
);
|
|
1936
1564
|
} else {
|
|
1937
1565
|
logoPath = path.resolve(customLogo);
|
|
1938
1566
|
}
|
|
1939
1567
|
if (fs.existsSync(logoPath)) {
|
|
1940
1568
|
logoBuffer = fs.readFileSync(logoPath);
|
|
1941
|
-
|
|
1569
|
+
const ext = path.extname(logoPath);
|
|
1570
|
+
logoFilename = `logo${ext}`;
|
|
1942
1571
|
console.log("✓ Added custom logo from local file");
|
|
1943
1572
|
} else {
|
|
1944
1573
|
console.warn(`⚠ Custom logo file not found: ${logoPath}`);
|
|
@@ -1949,17 +1578,52 @@ For autonomous packages, follow the build instructions above.
|
|
|
1949
1578
|
const currentDir = path.dirname(new URL(import.meta.url).pathname);
|
|
1950
1579
|
let logoPath = path.join(currentDir, "assets", "logo_1_small.jpg");
|
|
1951
1580
|
if (!fs.existsSync(logoPath)) {
|
|
1952
|
-
logoPath = path.join(
|
|
1581
|
+
logoPath = path.join(
|
|
1582
|
+
currentDir,
|
|
1583
|
+
"..",
|
|
1584
|
+
"docs",
|
|
1585
|
+
"MCP",
|
|
1586
|
+
"icons",
|
|
1587
|
+
"logo_1_small.jpg"
|
|
1588
|
+
);
|
|
1589
|
+
}
|
|
1590
|
+
if (!fs.existsSync(logoPath)) {
|
|
1591
|
+
logoPath = path.join(
|
|
1592
|
+
process.cwd(),
|
|
1593
|
+
"docs",
|
|
1594
|
+
"MCP",
|
|
1595
|
+
"icons",
|
|
1596
|
+
"logo_1_small.jpg"
|
|
1597
|
+
);
|
|
1953
1598
|
}
|
|
1954
1599
|
if (!fs.existsSync(logoPath)) {
|
|
1955
|
-
logoPath = path.join(
|
|
1600
|
+
logoPath = path.join(
|
|
1601
|
+
process.cwd(),
|
|
1602
|
+
"node_modules",
|
|
1603
|
+
"@alcyone-labs",
|
|
1604
|
+
"arg-parser",
|
|
1605
|
+
"dist",
|
|
1606
|
+
"assets",
|
|
1607
|
+
"logo_1_small.jpg"
|
|
1608
|
+
);
|
|
1609
|
+
}
|
|
1610
|
+
if (!fs.existsSync(logoPath)) {
|
|
1611
|
+
logoPath = path.join(
|
|
1612
|
+
process.cwd(),
|
|
1613
|
+
"dist",
|
|
1614
|
+
"assets",
|
|
1615
|
+
"logo_1_small.jpg"
|
|
1616
|
+
);
|
|
1956
1617
|
}
|
|
1957
1618
|
if (fs.existsSync(logoPath)) {
|
|
1958
1619
|
logoBuffer = fs.readFileSync(logoPath);
|
|
1959
|
-
|
|
1620
|
+
const ext = path.extname(logoPath);
|
|
1621
|
+
logoFilename = `logo${ext}`;
|
|
1960
1622
|
console.log("✓ Added default logo to build folder");
|
|
1961
1623
|
} else {
|
|
1962
|
-
console.warn(
|
|
1624
|
+
console.warn(
|
|
1625
|
+
"⚠ No logo found (custom or default), build folder will be created without icon"
|
|
1626
|
+
);
|
|
1963
1627
|
return void 0;
|
|
1964
1628
|
}
|
|
1965
1629
|
}
|
|
@@ -1969,260 +1633,89 @@ For autonomous packages, follow the build instructions above.
|
|
|
1969
1633
|
}
|
|
1970
1634
|
return void 0;
|
|
1971
1635
|
} catch (error) {
|
|
1972
|
-
console.warn(
|
|
1636
|
+
console.warn(
|
|
1637
|
+
"⚠ Failed to add logo to build folder:",
|
|
1638
|
+
error instanceof Error ? error.message : String(error)
|
|
1639
|
+
);
|
|
1973
1640
|
return void 0;
|
|
1974
1641
|
}
|
|
1975
1642
|
}
|
|
1976
|
-
/**
|
|
1977
|
-
* Processes CLI source code to replace global console with MCP-compliant Logger
|
|
1978
|
-
*/
|
|
1979
|
-
processCliSourceForMcp(cliSource) {
|
|
1980
|
-
const consoleReplacement = `import { createMcpLogger } from '@alcyone-labs/arg-parser';
|
|
1981
|
-
|
|
1982
|
-
// Replace global console with MCP-compliant logger for DXT packages
|
|
1983
|
-
const mcpLogger = createMcpLogger('[CLI]');
|
|
1984
|
-
const originalConsole = globalThis.console;
|
|
1985
|
-
globalThis.console = {
|
|
1986
|
-
...originalConsole,
|
|
1987
|
-
log: (...args) => mcpLogger.info(...args),
|
|
1988
|
-
info: (...args) => mcpLogger.info(...args),
|
|
1989
|
-
warn: (...args) => mcpLogger.warn(...args),
|
|
1990
|
-
debug: (...args) => mcpLogger.debug(...args),
|
|
1991
|
-
// Keep error/trace/etc as-is since they use stderr (MCP-compliant)
|
|
1992
|
-
error: originalConsole.error,
|
|
1993
|
-
trace: originalConsole.trace,
|
|
1994
|
-
assert: originalConsole.assert,
|
|
1995
|
-
clear: originalConsole.clear,
|
|
1996
|
-
count: originalConsole.count,
|
|
1997
|
-
countReset: originalConsole.countReset,
|
|
1998
|
-
dir: originalConsole.dir,
|
|
1999
|
-
dirxml: originalConsole.dirxml,
|
|
2000
|
-
group: originalConsole.group,
|
|
2001
|
-
groupCollapsed: originalConsole.groupCollapsed,
|
|
2002
|
-
groupEnd: originalConsole.groupEnd,
|
|
2003
|
-
table: originalConsole.table,
|
|
2004
|
-
time: originalConsole.time,
|
|
2005
|
-
timeEnd: originalConsole.timeEnd,
|
|
2006
|
-
timeLog: originalConsole.timeLog,
|
|
2007
|
-
timeStamp: originalConsole.timeStamp,
|
|
2008
|
-
};
|
|
2009
|
-
|
|
2010
|
-
`;
|
|
2011
|
-
const lines = cliSource.split("\n");
|
|
2012
|
-
let lastImportIndex = -1;
|
|
2013
|
-
for (let i = 0; i < lines.length; i++) {
|
|
2014
|
-
const line = lines[i].trim();
|
|
2015
|
-
if (line.startsWith("import ") && line.includes("from")) {
|
|
2016
|
-
lastImportIndex = i;
|
|
2017
|
-
} else if (line && !line.startsWith("//") && !line.startsWith("/*") && lastImportIndex >= 0) {
|
|
2018
|
-
break;
|
|
2019
|
-
}
|
|
2020
|
-
}
|
|
2021
|
-
if (lastImportIndex >= 0) {
|
|
2022
|
-
lines.splice(lastImportIndex + 1, 0, "", ...consoleReplacement.trim().split("\n"));
|
|
2023
|
-
return lines.join("\n");
|
|
2024
|
-
} else {
|
|
2025
|
-
return consoleReplacement + cliSource;
|
|
2026
|
-
}
|
|
2027
|
-
}
|
|
2028
|
-
/**
|
|
2029
|
-
* Adds the original CLI source to the build folder for handler execution
|
|
2030
|
-
*/
|
|
2031
|
-
addOriginalCliToFolder(buildDir) {
|
|
2032
|
-
try {
|
|
2033
|
-
const appCommandName = this.argParserInstance.getAppCommandName();
|
|
2034
|
-
const appName = this.argParserInstance.getAppName();
|
|
2035
|
-
const possibleCliFiles = [
|
|
2036
|
-
// Current working directory common patterns
|
|
2037
|
-
path.join(process.cwd(), "index.js"),
|
|
2038
|
-
path.join(process.cwd(), "index.mjs"),
|
|
2039
|
-
path.join(process.cwd(), "cli.js"),
|
|
2040
|
-
path.join(process.cwd(), "cli.mjs"),
|
|
2041
|
-
path.join(process.cwd(), "main.js"),
|
|
2042
|
-
path.join(process.cwd(), "main.mjs"),
|
|
2043
|
-
// Look for files with the app command name
|
|
2044
|
-
path.join(process.cwd(), `${appCommandName}.js`),
|
|
2045
|
-
path.join(process.cwd(), `${appCommandName}.mjs`),
|
|
2046
|
-
// Look for files with the app command name (sanitized)
|
|
2047
|
-
path.join(process.cwd(), `${appCommandName.replace(/[^a-zA-Z0-9-]/g, "-")}.js`),
|
|
2048
|
-
path.join(process.cwd(), `${appCommandName.replace(/[^a-zA-Z0-9-]/g, "-")}.mjs`),
|
|
2049
|
-
// Look for files with app name patterns
|
|
2050
|
-
path.join(process.cwd(), `${appName.toLowerCase().replace(/\s+/g, "-")}-cli.js`),
|
|
2051
|
-
path.join(process.cwd(), `${appName.toLowerCase().replace(/\s+/g, "-")}-cli.mjs`),
|
|
2052
|
-
// Look for files with first word of app name + cli
|
|
2053
|
-
path.join(process.cwd(), `${appName.split(" ")[0].toLowerCase()}-cli.js`),
|
|
2054
|
-
path.join(process.cwd(), `${appName.split(" ")[0].toLowerCase()}-cli.mjs`)
|
|
2055
|
-
];
|
|
2056
|
-
let cliSourcePath = null;
|
|
2057
|
-
for (const filePath of possibleCliFiles) {
|
|
2058
|
-
if (fs.existsSync(filePath)) {
|
|
2059
|
-
cliSourcePath = filePath;
|
|
2060
|
-
break;
|
|
2061
|
-
}
|
|
2062
|
-
}
|
|
2063
|
-
if (cliSourcePath) {
|
|
2064
|
-
let cliSource = fs.readFileSync(cliSourcePath, "utf8");
|
|
2065
|
-
cliSource = cliSource.replace(
|
|
2066
|
-
/import\s*{\s*([^}]+)\s*}\s*from\s*['"][^'"]*\/dist\/index\.mjs['"];?/g,
|
|
2067
|
-
"import { $1 } from '@alcyone-labs/arg-parser';"
|
|
2068
|
-
);
|
|
2069
|
-
cliSource = cliSource.replace(
|
|
2070
|
-
/import\s+(\w+)\s+from\s*['"][^'"]*\/dist\/index\.mjs['"];?/g,
|
|
2071
|
-
"import $1 from '@alcyone-labs/arg-parser';"
|
|
2072
|
-
);
|
|
2073
|
-
cliSource = this.processCliSourceForMcp(cliSource);
|
|
2074
|
-
const parserVariableMatch = cliSource.match(/const\s+(\w+)\s*=\s*ArgParser\.withMcp\(/);
|
|
2075
|
-
if (parserVariableMatch) {
|
|
2076
|
-
const parserVariable = parserVariableMatch[1];
|
|
2077
|
-
cliSource += `
|
|
2078
|
-
|
|
2079
|
-
// Export the parser instance for MCP server use
|
|
2080
|
-
export default ${parserVariable};
|
|
2081
|
-
|
|
2082
|
-
// Add debugging for main execution
|
|
2083
|
-
console.error('[MCP-DEBUG] CLI source loaded, checking execution context...');
|
|
2084
|
-
console.error('[MCP-DEBUG] import.meta.url:', import.meta.url);
|
|
2085
|
-
console.error('[MCP-DEBUG] process.argv[1]:', process.argv[1]);
|
|
2086
|
-
|
|
2087
|
-
// Ensure MCP server processes don't exit prematurely
|
|
2088
|
-
console.error('[MCP-DEBUG] Process argv:', process.argv);
|
|
2089
|
-
console.error('[MCP-DEBUG] Checking for serve command...');
|
|
2090
|
-
|
|
2091
|
-
if (process.argv.includes('serve')) {
|
|
2092
|
-
console.error('[MCP-DEBUG] Detected serve command, setting up MCP server lifecycle...');
|
|
2093
|
-
|
|
2094
|
-
// Override the original parse method to handle async MCP server
|
|
2095
|
-
const originalParse = ${parserVariable}.parse;
|
|
2096
|
-
${parserVariable}.parse = async function(args) {
|
|
2097
|
-
console.error('[MCP-DEBUG] Starting parse with args:', args);
|
|
2098
|
-
|
|
2099
|
-
try {
|
|
2100
|
-
const result = originalParse.call(this, args);
|
|
2101
|
-
console.error('[MCP-DEBUG] Parse result:', typeof result, result?.constructor?.name);
|
|
2102
|
-
|
|
2103
|
-
// If result is a Promise (MCP server), await it and keep process alive
|
|
2104
|
-
if (result && typeof result.then === 'function') {
|
|
2105
|
-
console.error('[MCP-DEBUG] Detected Promise result, awaiting...');
|
|
2106
|
-
const mcpResult = await result;
|
|
2107
|
-
console.error('[MCP-DEBUG] MCP server started, keeping process alive...');
|
|
2108
|
-
|
|
2109
|
-
// Keep the process alive indefinitely for MCP server
|
|
2110
|
-
const keepAlive = setInterval(() => {
|
|
2111
|
-
// Do nothing, just keep the event loop alive
|
|
2112
|
-
}, 30000);
|
|
2113
|
-
|
|
2114
|
-
// Handle graceful shutdown
|
|
2115
|
-
process.on('SIGINT', () => {
|
|
2116
|
-
console.error('[MCP-INFO] Received SIGINT, shutting down gracefully...');
|
|
2117
|
-
clearInterval(keepAlive);
|
|
2118
|
-
process.exit(0);
|
|
2119
|
-
});
|
|
2120
|
-
|
|
2121
|
-
process.on('SIGTERM', () => {
|
|
2122
|
-
console.error('[MCP-INFO] Received SIGTERM, shutting down gracefully...');
|
|
2123
|
-
clearInterval(keepAlive);
|
|
2124
|
-
process.exit(0);
|
|
2125
|
-
});
|
|
2126
|
-
|
|
2127
|
-
return mcpResult;
|
|
2128
|
-
} else {
|
|
2129
|
-
console.error('[MCP-DEBUG] Non-Promise result, returning normally');
|
|
2130
|
-
return result;
|
|
2131
|
-
}
|
|
2132
|
-
} catch (error) {
|
|
2133
|
-
console.error('[MCP-ERROR] Error in parse:', error);
|
|
2134
|
-
throw error;
|
|
2135
|
-
}
|
|
2136
|
-
};
|
|
2137
|
-
}
|
|
2138
|
-
`;
|
|
2139
|
-
} else {
|
|
2140
|
-
console.warn("⚠ Could not find ArgParser instance in CLI source, MCP server may not work properly");
|
|
2141
|
-
}
|
|
2142
|
-
const serverDir = path.join(buildDir, "server");
|
|
2143
|
-
if (!fs.existsSync(serverDir)) {
|
|
2144
|
-
fs.mkdirSync(serverDir, { recursive: true });
|
|
2145
|
-
}
|
|
2146
|
-
fs.writeFileSync(path.join(serverDir, "original-cli.mjs"), cliSource);
|
|
2147
|
-
console.log(`✓ Added original CLI source to build folder: ${path.basename(cliSourcePath)}`);
|
|
2148
|
-
} else {
|
|
2149
|
-
console.warn("⚠ Original CLI source not found, handlers may not work properly");
|
|
2150
|
-
console.warn(" Searched for:", possibleCliFiles.map((f) => path.basename(f)).join(", "));
|
|
2151
|
-
}
|
|
2152
|
-
} catch (error) {
|
|
2153
|
-
console.warn("⚠ Failed to add original CLI source:", error instanceof Error ? error.message : String(error));
|
|
2154
|
-
}
|
|
2155
|
-
}
|
|
2156
1643
|
/**
|
|
2157
1644
|
* Builds a complete DXT package using TSDown CLI for autonomous execution
|
|
2158
1645
|
*/
|
|
2159
|
-
async buildDxtWithTsdown(entryPointFile, outputDir = "./dxt") {
|
|
1646
|
+
async buildDxtWithTsdown(entryPointFile, outputDir = "./dxt", withNodeModules = false) {
|
|
2160
1647
|
try {
|
|
2161
1648
|
console.log(simpleChalk.cyan("🔧 Building DXT package with TSDown..."));
|
|
2162
|
-
const
|
|
1649
|
+
const projectRoot = this.findProjectRoot(entryPointFile);
|
|
1650
|
+
const absoluteEntryPath = path.resolve(entryPointFile);
|
|
1651
|
+
const relativeEntryPath = path.relative(projectRoot, absoluteEntryPath);
|
|
2163
1652
|
const entryFileName = path.basename(entryPointFile);
|
|
2164
1653
|
console.log(simpleChalk.gray(`Entry point: ${entryPointFile}`));
|
|
2165
|
-
console.log(simpleChalk.gray(`
|
|
1654
|
+
console.log(simpleChalk.gray(`Project root: ${projectRoot}`));
|
|
1655
|
+
console.log(simpleChalk.gray(`Relative entry path: ${relativeEntryPath}`));
|
|
2166
1656
|
const dxtIgnorePath = this.getDxtIgnoreTemplatePath();
|
|
2167
1657
|
if (fs.existsSync(dxtIgnorePath)) {
|
|
2168
|
-
fs.copyFileSync(dxtIgnorePath, path.join(
|
|
1658
|
+
fs.copyFileSync(dxtIgnorePath, path.join(projectRoot, ".dxtignore"));
|
|
2169
1659
|
}
|
|
1660
|
+
const serverInfo = this.extractMcpServerInfo();
|
|
1661
|
+
const logoFilename = await this.addLogoToFolder(
|
|
1662
|
+
projectRoot,
|
|
1663
|
+
serverInfo,
|
|
1664
|
+
entryPointFile
|
|
1665
|
+
);
|
|
1666
|
+
console.log(
|
|
1667
|
+
logoFilename ? simpleChalk.gray(`✓ Logo prepared: ${logoFilename}`) : simpleChalk.gray("⚠ No logo available")
|
|
1668
|
+
);
|
|
2170
1669
|
const originalCwd = process.cwd();
|
|
2171
1670
|
try {
|
|
2172
|
-
process.chdir(
|
|
1671
|
+
process.chdir(projectRoot);
|
|
2173
1672
|
const { build } = await import("tsdown");
|
|
2174
|
-
console.log(simpleChalk.gray(`Building with TSDown: ${
|
|
1673
|
+
console.log(simpleChalk.gray(`Building with TSDown: ${relativeEntryPath}`));
|
|
1674
|
+
console.log(
|
|
1675
|
+
simpleChalk.green(
|
|
1676
|
+
`${withNodeModules ? "with node_modules" : "without node_modules"}`
|
|
1677
|
+
)
|
|
1678
|
+
);
|
|
2175
1679
|
const buildConfig = {
|
|
2176
|
-
entry: [
|
|
2177
|
-
outDir: path.resolve(
|
|
2178
|
-
format: ["
|
|
1680
|
+
entry: [relativeEntryPath],
|
|
1681
|
+
outDir: path.resolve(originalCwd, outputDir),
|
|
1682
|
+
format: ["es"],
|
|
2179
1683
|
target: "node22",
|
|
2180
|
-
|
|
1684
|
+
define: {
|
|
1685
|
+
// Define any compile-time constants
|
|
1686
|
+
NODE_ENV: '"production"'
|
|
1687
|
+
},
|
|
2181
1688
|
minify: false,
|
|
2182
1689
|
sourcemap: false,
|
|
2183
|
-
|
|
1690
|
+
// Remove all output folders and artefacts
|
|
1691
|
+
clean: [outputDir, "./.dxtignore", `${outputDir}.dxt`],
|
|
2184
1692
|
silent: process.env["NO_SILENCE"] !== "1",
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
}
|
|
1693
|
+
external: (_, importer) => withNodeModules ? importer == null ? void 0 : importer.includes("node_modules") : false,
|
|
1694
|
+
noExternal: (_, importer) => withNodeModules ? (importer == null ? void 0 : importer.includes("node_modules")) === false : true,
|
|
1695
|
+
copy: async (options) => {
|
|
1696
|
+
const outputPaths = [
|
|
1697
|
+
"package.json"
|
|
1698
|
+
];
|
|
1699
|
+
if (withNodeModules) {
|
|
1700
|
+
console.log(
|
|
1701
|
+
simpleChalk.gray(
|
|
1702
|
+
"📦 Including node_modules in bundle (may take longer)..."
|
|
1703
|
+
)
|
|
1704
|
+
);
|
|
1705
|
+
outputPaths.push("node_modules");
|
|
1706
|
+
}
|
|
1707
|
+
if (logoFilename) {
|
|
1708
|
+
const logoPath = path.join(process.cwd(), logoFilename);
|
|
1709
|
+
if (fs.existsSync(logoPath)) {
|
|
1710
|
+
console.log(simpleChalk.gray(`Adding logo from: ${logoPath}`));
|
|
1711
|
+
outputPaths.push({
|
|
1712
|
+
from: logoPath,
|
|
1713
|
+
to: path.join(options.outDir, logoFilename)
|
|
1714
|
+
});
|
|
2203
1715
|
}
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
],
|
|
2208
|
-
external: [
|
|
2209
|
-
// Node.js built-ins only - everything else should be bundled for true autonomy
|
|
2210
|
-
"stream",
|
|
2211
|
-
"fs",
|
|
2212
|
-
"path",
|
|
2213
|
-
"url",
|
|
2214
|
-
"util",
|
|
2215
|
-
"events",
|
|
2216
|
-
"child_process",
|
|
2217
|
-
"os",
|
|
2218
|
-
"tty",
|
|
2219
|
-
"process",
|
|
2220
|
-
"crypto",
|
|
2221
|
-
"http",
|
|
2222
|
-
"https",
|
|
2223
|
-
"net",
|
|
2224
|
-
"zlib"
|
|
2225
|
-
],
|
|
1716
|
+
}
|
|
1717
|
+
return outputPaths;
|
|
1718
|
+
},
|
|
2226
1719
|
platform: "node",
|
|
2227
1720
|
plugins: []
|
|
2228
1721
|
};
|
|
@@ -2241,262 +1734,40 @@ export default ${JSON.stringify(buildConfig, null, 2)};
|
|
|
2241
1734
|
// To run manually:
|
|
2242
1735
|
// npx tsdown -c tsdown.config.dxt.ts
|
|
2243
1736
|
`;
|
|
2244
|
-
fs.writeFileSync(
|
|
2245
|
-
|
|
1737
|
+
fs.writeFileSync(
|
|
1738
|
+
path.join("dxt", "tsdown.config.dxt.ts"),
|
|
1739
|
+
configContent
|
|
1740
|
+
);
|
|
1741
|
+
console.log(
|
|
1742
|
+
simpleChalk.gray("📝 Debug config written to dxt/tsdown.config.dxt.ts")
|
|
1743
|
+
);
|
|
2246
1744
|
}
|
|
2247
1745
|
await build(buildConfig);
|
|
2248
1746
|
console.log(simpleChalk.green("✅ TSDown bundling completed"));
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
const { build } = await import("tsdown");
|
|
2266
|
-
console.log(simpleChalk.cyan("🔧 Bundling CLI with TSDown for autonomous execution..."));
|
|
2267
|
-
const configContent = this.getTsdownConfigContent();
|
|
2268
|
-
const localConfigPath = path.join(serverDir, "tsdown.config.mjs");
|
|
2269
|
-
fs.writeFileSync(localConfigPath, configContent);
|
|
2270
|
-
const originalCliPath = path.join(serverDir, "original-cli.mjs");
|
|
2271
|
-
if (!fs.existsSync(originalCliPath)) {
|
|
2272
|
-
console.warn(simpleChalk.yellow("⚠ Original CLI not found, skipping TSDown bundling"));
|
|
2273
|
-
return null;
|
|
2274
|
-
}
|
|
2275
|
-
const buildOptions = {
|
|
2276
|
-
entry: ["original-cli.mjs"],
|
|
2277
|
-
// Use relative path since we'll chdir to serverDir
|
|
2278
|
-
outDir: ".",
|
|
2279
|
-
// Output to current directory (serverDir)
|
|
2280
|
-
format: "esm",
|
|
2281
|
-
target: "node22",
|
|
2282
|
-
// Bundle EVERYTHING except Node.js built-ins for true autonomy
|
|
2283
|
-
noExternal: (id) => {
|
|
2284
|
-
if (!id.startsWith("node:") && !this.isNodeBuiltin(id)) return true;
|
|
2285
|
-
return false;
|
|
2286
|
-
},
|
|
2287
|
-
minify: false,
|
|
2288
|
-
sourcemap: false,
|
|
2289
|
-
clean: false,
|
|
2290
|
-
outExtension: () => ({ js: ".bundled.mjs" }),
|
|
2291
|
-
alias: {
|
|
2292
|
-
// Alias chalk to SimpleChalk for autonomous builds
|
|
2293
|
-
chalk: path.resolve(process.cwd(), "node_modules/@alcyone-labs/arg-parser/dist/SimpleChalk.mjs")
|
|
2294
|
-
},
|
|
2295
|
-
external: [
|
|
2296
|
-
// Only Node.js built-ins - everything else gets bundled for true autonomy
|
|
2297
|
-
"node:stream",
|
|
2298
|
-
"node:fs",
|
|
2299
|
-
"node:path",
|
|
2300
|
-
"node:url",
|
|
2301
|
-
"node:util",
|
|
2302
|
-
"node:events",
|
|
2303
|
-
"node:child_process",
|
|
2304
|
-
"node:os",
|
|
2305
|
-
"node:tty",
|
|
2306
|
-
"node:process",
|
|
2307
|
-
"node:crypto",
|
|
2308
|
-
"node:http",
|
|
2309
|
-
"node:https",
|
|
2310
|
-
"node:net",
|
|
2311
|
-
"node:zlib",
|
|
2312
|
-
"node:fs/promises",
|
|
2313
|
-
"node:timers",
|
|
2314
|
-
"stream",
|
|
2315
|
-
"fs",
|
|
2316
|
-
"path",
|
|
2317
|
-
"url",
|
|
2318
|
-
"util",
|
|
2319
|
-
"events",
|
|
2320
|
-
"child_process",
|
|
2321
|
-
"os",
|
|
2322
|
-
"tty",
|
|
2323
|
-
"process",
|
|
2324
|
-
"crypto",
|
|
2325
|
-
"http",
|
|
2326
|
-
"https",
|
|
2327
|
-
"net",
|
|
2328
|
-
"zlib",
|
|
2329
|
-
"fs/promises",
|
|
2330
|
-
"timers",
|
|
2331
|
-
"timers/promises",
|
|
2332
|
-
"perf_hooks",
|
|
2333
|
-
"async_hooks",
|
|
2334
|
-
"inspector",
|
|
2335
|
-
"v8",
|
|
2336
|
-
"vm",
|
|
2337
|
-
"assert",
|
|
2338
|
-
"constants",
|
|
2339
|
-
"module",
|
|
2340
|
-
"repl",
|
|
2341
|
-
"string_decoder",
|
|
2342
|
-
"punycode",
|
|
2343
|
-
"domain",
|
|
2344
|
-
"querystring",
|
|
2345
|
-
"readline",
|
|
2346
|
-
"worker_threads",
|
|
2347
|
-
"cluster",
|
|
2348
|
-
"dgram",
|
|
2349
|
-
"dns",
|
|
2350
|
-
"buffer"
|
|
2351
|
-
],
|
|
2352
|
-
platform: "node",
|
|
2353
|
-
plugins: [],
|
|
2354
|
-
// Resolve local dependencies properly
|
|
2355
|
-
resolve: {
|
|
2356
|
-
alias: {
|
|
2357
|
-
// Handle local monorepo dependencies
|
|
2358
|
-
"@alcyone-labs/arg-parser": path.resolve(process.cwd())
|
|
2359
|
-
}
|
|
2360
|
-
}
|
|
2361
|
-
};
|
|
2362
|
-
const originalCwd = process.cwd();
|
|
2363
|
-
try {
|
|
2364
|
-
process.chdir(serverDir);
|
|
2365
|
-
await build(buildOptions);
|
|
1747
|
+
const detectedOutputFile = this.detectTsdownOutputFile(
|
|
1748
|
+
outputDir,
|
|
1749
|
+
entryFileName
|
|
1750
|
+
);
|
|
1751
|
+
await this.setupDxtPackageFiles(
|
|
1752
|
+
entryPointFile,
|
|
1753
|
+
outputDir,
|
|
1754
|
+
detectedOutputFile ?? void 0,
|
|
1755
|
+
logoFilename ?? "logo.jpg"
|
|
1756
|
+
);
|
|
1757
|
+
console.log(simpleChalk.cyan("📦 DXT package ready for packing"));
|
|
1758
|
+
console.log(
|
|
1759
|
+
simpleChalk.gray(
|
|
1760
|
+
`To complete the process, run: npx @anthropic-ai/dxt pack ${outputDir}/`
|
|
1761
|
+
)
|
|
1762
|
+
);
|
|
2366
1763
|
} finally {
|
|
2367
1764
|
process.chdir(originalCwd);
|
|
2368
1765
|
}
|
|
2369
|
-
const possibleBundledFiles = [
|
|
2370
|
-
"original-cli.bundled.mjs",
|
|
2371
|
-
"original-cli.js",
|
|
2372
|
-
"original-cli.mjs"
|
|
2373
|
-
];
|
|
2374
|
-
let bundledPath = null;
|
|
2375
|
-
let bundledFileName = null;
|
|
2376
|
-
for (const fileName of possibleBundledFiles) {
|
|
2377
|
-
const filePath = path.join(serverDir, fileName);
|
|
2378
|
-
if (fs.existsSync(filePath) && fileName !== "original-cli.mjs") {
|
|
2379
|
-
bundledPath = filePath;
|
|
2380
|
-
bundledFileName = fileName;
|
|
2381
|
-
break;
|
|
2382
|
-
}
|
|
2383
|
-
}
|
|
2384
|
-
if (bundledPath && bundledFileName) {
|
|
2385
|
-
console.log(simpleChalk.green(`✅ TSDown bundling completed successfully: ${bundledFileName}`));
|
|
2386
|
-
const expectedBundledPath = path.join(serverDir, "original-cli.bundled.mjs");
|
|
2387
|
-
if (bundledPath !== expectedBundledPath) {
|
|
2388
|
-
fs.renameSync(bundledPath, expectedBundledPath);
|
|
2389
|
-
bundledFileName = "original-cli.bundled.mjs";
|
|
2390
|
-
}
|
|
2391
|
-
try {
|
|
2392
|
-
fs.unlinkSync(localConfigPath);
|
|
2393
|
-
} catch (error) {
|
|
2394
|
-
}
|
|
2395
|
-
try {
|
|
2396
|
-
fs.chmodSync(expectedBundledPath, 493);
|
|
2397
|
-
} catch (error) {
|
|
2398
|
-
console.warn("⚠ Could not set executable permission on bundled file:", error instanceof Error ? error.message : String(error));
|
|
2399
|
-
}
|
|
2400
|
-
return bundledFileName;
|
|
2401
|
-
} else {
|
|
2402
|
-
console.warn(simpleChalk.yellow("⚠ TSDown bundling failed, bundled file not found"));
|
|
2403
|
-
return null;
|
|
2404
|
-
}
|
|
2405
1766
|
} catch (error) {
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
}
|
|
2410
|
-
}
|
|
2411
|
-
/**
|
|
2412
|
-
* Checks if a module ID is a Node.js built-in
|
|
2413
|
-
*/
|
|
2414
|
-
isNodeBuiltin(id) {
|
|
2415
|
-
const nodeBuiltins = [
|
|
2416
|
-
"stream",
|
|
2417
|
-
"fs",
|
|
2418
|
-
"path",
|
|
2419
|
-
"url",
|
|
2420
|
-
"util",
|
|
2421
|
-
"events",
|
|
2422
|
-
"child_process",
|
|
2423
|
-
"os",
|
|
2424
|
-
"tty",
|
|
2425
|
-
"process",
|
|
2426
|
-
"crypto",
|
|
2427
|
-
"http",
|
|
2428
|
-
"https",
|
|
2429
|
-
"net",
|
|
2430
|
-
"zlib",
|
|
2431
|
-
"fs/promises",
|
|
2432
|
-
"timers",
|
|
2433
|
-
"timers/promises",
|
|
2434
|
-
"perf_hooks",
|
|
2435
|
-
"async_hooks",
|
|
2436
|
-
"inspector",
|
|
2437
|
-
"v8",
|
|
2438
|
-
"vm",
|
|
2439
|
-
"assert",
|
|
2440
|
-
"constants",
|
|
2441
|
-
"module",
|
|
2442
|
-
"repl",
|
|
2443
|
-
"string_decoder",
|
|
2444
|
-
"punycode",
|
|
2445
|
-
"domain",
|
|
2446
|
-
"querystring",
|
|
2447
|
-
"readline",
|
|
2448
|
-
"worker_threads",
|
|
2449
|
-
"cluster",
|
|
2450
|
-
"dgram",
|
|
2451
|
-
"dns",
|
|
2452
|
-
"buffer"
|
|
2453
|
-
];
|
|
2454
|
-
return nodeBuiltins.includes(id) || id.startsWith("node:");
|
|
2455
|
-
}
|
|
2456
|
-
/**
|
|
2457
|
-
* Gets the TSDown configuration content as a string
|
|
2458
|
-
*/
|
|
2459
|
-
getTsdownConfigContent() {
|
|
2460
|
-
const currentDir = path.dirname(new URL(import.meta.url).pathname);
|
|
2461
|
-
const assetsConfigPath = path.join(currentDir, "..", "assets", "tsdown.dxt.config.ts");
|
|
2462
|
-
if (fs.existsSync(assetsConfigPath)) {
|
|
2463
|
-
try {
|
|
2464
|
-
const content = fs.readFileSync(assetsConfigPath, "utf-8");
|
|
2465
|
-
return content.replace('/// <reference types="tsdown" />', "").replace('import { defineConfig } from "tsdown/config";', 'import { defineConfig } from "tsdown";').replace("export default defineConfig(", "export default defineConfig(");
|
|
2466
|
-
} catch (error) {
|
|
2467
|
-
console.warn(simpleChalk.yellow("⚠ Could not read TSDown config from assets, using fallback"));
|
|
2468
|
-
}
|
|
2469
|
-
}
|
|
2470
|
-
const rootConfigPath = path.join(process.cwd(), "tsdown.dxt.config.ts");
|
|
2471
|
-
if (fs.existsSync(rootConfigPath)) {
|
|
2472
|
-
try {
|
|
2473
|
-
const content = fs.readFileSync(rootConfigPath, "utf-8");
|
|
2474
|
-
return content.replace('/// <reference types="tsdown" />', "").replace('import { defineConfig } from "tsdown/config";', 'import { defineConfig } from "tsdown";');
|
|
2475
|
-
} catch (error) {
|
|
2476
|
-
console.warn(simpleChalk.yellow("⚠ Could not read TSDown config from root, using default"));
|
|
2477
|
-
}
|
|
1767
|
+
throw new Error(
|
|
1768
|
+
`TSDown DXT build failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1769
|
+
);
|
|
2478
1770
|
}
|
|
2479
|
-
return `import { defineConfig } from "tsdown";
|
|
2480
|
-
import path from "path";
|
|
2481
|
-
|
|
2482
|
-
export default defineConfig({
|
|
2483
|
-
outDir: "server",
|
|
2484
|
-
format: ["esm", "module"],
|
|
2485
|
-
target: "node22",
|
|
2486
|
-
noExternal: () => true,
|
|
2487
|
-
minify: false,
|
|
2488
|
-
sourcemap: false,
|
|
2489
|
-
clean: false,
|
|
2490
|
-
alias: {
|
|
2491
|
-
chalk: path.resolve(process.cwd(), "node_modules/@alcyone-labs/arg-parser/dist/SimpleChalk.mjs"),
|
|
2492
|
-
},
|
|
2493
|
-
external: [
|
|
2494
|
-
"stream", "fs", "path", "url", "util", "events", "child_process",
|
|
2495
|
-
"os", "tty", "process", "crypto", "http", "https", "net", "zlib",
|
|
2496
|
-
],
|
|
2497
|
-
platform: "node",
|
|
2498
|
-
plugins: [],
|
|
2499
|
-
});`;
|
|
2500
1771
|
}
|
|
2501
1772
|
/**
|
|
2502
1773
|
* Gets the path to the .dxtignore template file in assets
|
|
@@ -2504,9 +1775,22 @@ export default defineConfig({
|
|
|
2504
1775
|
getDxtIgnoreTemplatePath() {
|
|
2505
1776
|
const possiblePaths = [
|
|
2506
1777
|
// 1. From the built library assets (when installed via npm)
|
|
2507
|
-
path.join(
|
|
1778
|
+
path.join(
|
|
1779
|
+
path.dirname(new URL(import.meta.url).pathname),
|
|
1780
|
+
"..",
|
|
1781
|
+
"assets",
|
|
1782
|
+
".dxtignore.template"
|
|
1783
|
+
),
|
|
2508
1784
|
// 2. From node_modules/@alcyone-labs/arg-parser/dist/assets (when installed via npm)
|
|
2509
|
-
path.join(
|
|
1785
|
+
path.join(
|
|
1786
|
+
process.cwd(),
|
|
1787
|
+
"node_modules",
|
|
1788
|
+
"@alcyone-labs",
|
|
1789
|
+
"arg-parser",
|
|
1790
|
+
"dist",
|
|
1791
|
+
"assets",
|
|
1792
|
+
".dxtignore.template"
|
|
1793
|
+
),
|
|
2510
1794
|
// 3. From the root directory (development/local build)
|
|
2511
1795
|
path.join(process.cwd(), ".dxtignore.template"),
|
|
2512
1796
|
// 4. From the library root (when using local file dependency)
|
|
@@ -2524,8 +1808,8 @@ export default defineConfig({
|
|
|
2524
1808
|
/**
|
|
2525
1809
|
* Sets up DXT package files (manifest.json) in the output directory
|
|
2526
1810
|
*/
|
|
2527
|
-
async setupDxtPackageFiles(entryPointFile, outputDir = "./dxt") {
|
|
2528
|
-
var _a, _b, _c, _d, _e;
|
|
1811
|
+
async setupDxtPackageFiles(entryPointFile, outputDir = "./dxt", actualOutputFilename, logoFilename = "logo.jpg") {
|
|
1812
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2529
1813
|
const dxtDir = path.resolve(process.cwd(), outputDir);
|
|
2530
1814
|
if (!fs.existsSync(dxtDir)) {
|
|
2531
1815
|
throw new Error(`TSDown output directory (${outputDir}) not found`);
|
|
@@ -2547,11 +1831,15 @@ export default defineConfig({
|
|
|
2547
1831
|
description: tool.description
|
|
2548
1832
|
}));
|
|
2549
1833
|
} catch (error) {
|
|
2550
|
-
console.warn(
|
|
2551
|
-
|
|
1834
|
+
console.warn(
|
|
1835
|
+
simpleChalk.yellow(
|
|
1836
|
+
`Warning: Could not generate unified tool list: ${error instanceof Error ? error.message : String(error)}`
|
|
1837
|
+
)
|
|
1838
|
+
);
|
|
1839
|
+
const mainFlags = this.argParserInstance.flags;
|
|
2552
1840
|
const properties2 = {};
|
|
2553
1841
|
const required2 = [];
|
|
2554
|
-
for (const flag of
|
|
1842
|
+
for (const flag of mainFlags) {
|
|
2555
1843
|
if (flag.name === "help" || flag.name.startsWith("s-")) continue;
|
|
2556
1844
|
properties2[flag.name] = {
|
|
2557
1845
|
type: getJsonSchemaTypeFromFlag(flag.type),
|
|
@@ -2568,59 +1856,24 @@ export default defineConfig({
|
|
|
2568
1856
|
}
|
|
2569
1857
|
}
|
|
2570
1858
|
const commandName = this.argParserInstance.getAppCommandName();
|
|
2571
|
-
tools = [
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
}
|
|
2576
|
-
const envVars = {};
|
|
2577
|
-
const userConfig = {};
|
|
2578
|
-
const mainFlags = this.argParserInstance.flags;
|
|
2579
|
-
for (const flag of mainFlags) {
|
|
2580
|
-
const envVar = flag.env || flag.envVar;
|
|
2581
|
-
if (envVar) {
|
|
2582
|
-
envVars[envVar] = `\${user_config.${envVar}}`;
|
|
2583
|
-
userConfig[envVar] = {
|
|
2584
|
-
type: "string",
|
|
2585
|
-
title: envVar.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
2586
|
-
description: flag.description || `${envVar} environment variable`,
|
|
2587
|
-
required: true,
|
|
2588
|
-
// Always require env vars in user_config for better UX
|
|
2589
|
-
sensitive: true
|
|
2590
|
-
// Assume env vars are sensitive
|
|
2591
|
-
};
|
|
2592
|
-
}
|
|
2593
|
-
}
|
|
2594
|
-
if (typeof this.argParserInstance.getTools === "function") {
|
|
2595
|
-
const tools2 = this.argParserInstance.getTools();
|
|
2596
|
-
for (const [, toolConfig] of tools2) {
|
|
2597
|
-
const toolFlags = toolConfig.flags || [];
|
|
2598
|
-
for (const flag of toolFlags) {
|
|
2599
|
-
const envVar = flag.env || flag.envVar;
|
|
2600
|
-
if (envVar && !envVars[envVar]) {
|
|
2601
|
-
envVars[envVar] = `\${user_config.${envVar}}`;
|
|
2602
|
-
userConfig[envVar] = {
|
|
2603
|
-
type: "string",
|
|
2604
|
-
title: envVar.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
2605
|
-
description: flag.description || `${envVar} environment variable`,
|
|
2606
|
-
required: true,
|
|
2607
|
-
// Always require env vars in user_config for better UX
|
|
2608
|
-
sensitive: true
|
|
2609
|
-
// Assume env vars are sensitive
|
|
2610
|
-
};
|
|
2611
|
-
}
|
|
1859
|
+
tools = [
|
|
1860
|
+
{
|
|
1861
|
+
name: commandName || packageInfo.name || "cli-tool",
|
|
1862
|
+
description: packageInfo.description || this.argParserInstance.getDescription() || "CLI tool"
|
|
2612
1863
|
}
|
|
2613
|
-
|
|
1864
|
+
];
|
|
2614
1865
|
}
|
|
1866
|
+
const { envVars, userConfig } = this.generateEnvAndUserConfig();
|
|
2615
1867
|
const serverInfo = this.extractMcpServerInfo();
|
|
2616
|
-
let
|
|
2617
|
-
if (
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
1868
|
+
let entryFileName;
|
|
1869
|
+
if (actualOutputFilename) {
|
|
1870
|
+
entryFileName = actualOutputFilename;
|
|
1871
|
+
} else {
|
|
1872
|
+
const projectRoot = this.findProjectRoot(entryPointFile);
|
|
1873
|
+
const absoluteEntryPath = path.resolve(entryPointFile);
|
|
1874
|
+
const relativeEntryPath = path.relative(projectRoot, absoluteEntryPath);
|
|
1875
|
+
entryFileName = relativeEntryPath.replace(/\.ts$/, ".js");
|
|
2622
1876
|
}
|
|
2623
|
-
const entryFileName = path.basename(entryPointFile);
|
|
2624
1877
|
const manifest = {
|
|
2625
1878
|
dxt_version: "0.1",
|
|
2626
1879
|
name: serverInfo.name || packageInfo.name || "mcp-server",
|
|
@@ -2638,7 +1891,10 @@ export default defineConfig({
|
|
|
2638
1891
|
command: "node",
|
|
2639
1892
|
args: [
|
|
2640
1893
|
`\${__dirname}/${entryFileName}`,
|
|
2641
|
-
"--s-mcp-serve"
|
|
1894
|
+
"--s-mcp-serve",
|
|
1895
|
+
// Overwrite the CLI config to only use stdio to avoid conflicts
|
|
1896
|
+
"--s-mcp-transport",
|
|
1897
|
+
"stdio"
|
|
2642
1898
|
],
|
|
2643
1899
|
env: envVars
|
|
2644
1900
|
}
|
|
@@ -2646,46 +1902,147 @@ export default defineConfig({
|
|
|
2646
1902
|
tools,
|
|
2647
1903
|
icon: logoFilename,
|
|
2648
1904
|
...Object.keys(userConfig).length > 0 && { user_config: userConfig },
|
|
2649
|
-
repository: {
|
|
1905
|
+
repository: ((_e = packageInfo.repository) == null ? void 0 : _e.url) ? {
|
|
2650
1906
|
type: "git",
|
|
2651
|
-
url: (
|
|
2652
|
-
},
|
|
1907
|
+
url: (_f = packageInfo.repository) == null ? void 0 : _f.url
|
|
1908
|
+
} : void 0,
|
|
2653
1909
|
license: packageInfo.license || "MIT"
|
|
2654
1910
|
};
|
|
2655
|
-
fs.writeFileSync(
|
|
1911
|
+
fs.writeFileSync(
|
|
1912
|
+
path.join(dxtDir, "manifest.json"),
|
|
1913
|
+
JSON.stringify(manifest, null, 2)
|
|
1914
|
+
);
|
|
2656
1915
|
console.log(simpleChalk.gray("✅ DXT package files set up"));
|
|
2657
1916
|
}
|
|
2658
1917
|
/**
|
|
2659
|
-
*
|
|
1918
|
+
* Detects the actual output filename generated by TSDown
|
|
2660
1919
|
*/
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
1920
|
+
detectTsdownOutputFile(outputDir, expectedBaseName) {
|
|
1921
|
+
try {
|
|
1922
|
+
const dxtDir = path.resolve(process.cwd(), outputDir);
|
|
1923
|
+
if (!fs.existsSync(dxtDir)) {
|
|
1924
|
+
console.warn(
|
|
1925
|
+
simpleChalk.yellow(`⚠ Output directory (${outputDir}) not found`)
|
|
1926
|
+
);
|
|
1927
|
+
return null;
|
|
1928
|
+
}
|
|
1929
|
+
const files = fs.readdirSync(dxtDir).filter(
|
|
1930
|
+
(file) => (file.endsWith(".js") || file.endsWith(".mjs")) && !file.includes("chunk-") && !file.includes("dist-") && !file.startsWith(".")
|
|
1931
|
+
);
|
|
1932
|
+
const baseNameWithoutExt = path.parse(expectedBaseName).name;
|
|
1933
|
+
for (const ext of [".js", ".mjs"]) {
|
|
1934
|
+
const exactMatch = `${baseNameWithoutExt}${ext}`;
|
|
1935
|
+
if (files.includes(exactMatch)) {
|
|
1936
|
+
console.log(simpleChalk.gray(`✓ Detected TSDown output: ${exactMatch}`));
|
|
1937
|
+
return exactMatch;
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
const mainFiles = files.filter(
|
|
1941
|
+
(file) => !file.includes("chunk") && !file.includes("dist") && file !== "logo.jpg" && file !== "manifest.json"
|
|
1942
|
+
);
|
|
1943
|
+
if (mainFiles.length === 1) {
|
|
1944
|
+
console.log(simpleChalk.gray(`✓ Detected TSDown output: ${mainFiles[0]}`));
|
|
1945
|
+
return mainFiles[0];
|
|
1946
|
+
}
|
|
1947
|
+
if (mainFiles.length > 1) {
|
|
1948
|
+
let bestMatch = mainFiles[0];
|
|
1949
|
+
let bestScore = 0;
|
|
1950
|
+
for (const file of mainFiles) {
|
|
1951
|
+
const filePath = path.join(dxtDir, file);
|
|
1952
|
+
const stats = fs.statSync(filePath);
|
|
1953
|
+
const nameScore = file.includes(baseNameWithoutExt) ? 100 : 0;
|
|
1954
|
+
const sizeScore = Math.min(stats.size / 1e3, 50);
|
|
1955
|
+
const totalScore = nameScore + sizeScore;
|
|
1956
|
+
if (totalScore > bestScore) {
|
|
1957
|
+
bestScore = totalScore;
|
|
1958
|
+
bestMatch = file;
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
console.log(
|
|
1962
|
+
simpleChalk.gray(
|
|
1963
|
+
`✓ Detected TSDown output: ${bestMatch} (best match from ${mainFiles.length} candidates)`
|
|
1964
|
+
)
|
|
1965
|
+
);
|
|
1966
|
+
return bestMatch;
|
|
1967
|
+
}
|
|
1968
|
+
console.warn(
|
|
1969
|
+
simpleChalk.yellow(`⚠ Could not detect TSDown output file in ${outputDir}`)
|
|
1970
|
+
);
|
|
1971
|
+
return null;
|
|
1972
|
+
} catch (error) {
|
|
1973
|
+
console.warn(
|
|
1974
|
+
simpleChalk.yellow(
|
|
1975
|
+
`⚠ Error detecting TSDown output: ${error instanceof Error ? error.message : String(error)}`
|
|
1976
|
+
)
|
|
1977
|
+
);
|
|
1978
|
+
return null;
|
|
2666
1979
|
}
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
path.join(
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
if (
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
1980
|
+
}
|
|
1981
|
+
findProjectRoot(entryPointFile) {
|
|
1982
|
+
let currentDir = path.dirname(path.resolve(entryPointFile));
|
|
1983
|
+
let attempts = 0;
|
|
1984
|
+
const maxAttempts = 5;
|
|
1985
|
+
while (attempts < maxAttempts) {
|
|
1986
|
+
const packageJsonPath = path.join(currentDir, "package.json");
|
|
1987
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
1988
|
+
return currentDir;
|
|
1989
|
+
}
|
|
1990
|
+
const parentDir = path.dirname(currentDir);
|
|
1991
|
+
if (parentDir === currentDir) {
|
|
1992
|
+
break;
|
|
1993
|
+
}
|
|
1994
|
+
currentDir = parentDir;
|
|
1995
|
+
attempts++;
|
|
1996
|
+
}
|
|
1997
|
+
throw new Error(
|
|
1998
|
+
`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.`
|
|
1999
|
+
);
|
|
2000
|
+
}
|
|
2001
|
+
/**
|
|
2002
|
+
* Generate environment variables and user configuration from ArgParser flags
|
|
2003
|
+
* @returns Object containing envVars and userConfig
|
|
2004
|
+
*/
|
|
2005
|
+
generateEnvAndUserConfig() {
|
|
2006
|
+
const envVars = {};
|
|
2007
|
+
const userConfig = {};
|
|
2008
|
+
const mainFlags = this.argParserInstance.flags;
|
|
2009
|
+
for (const flag of mainFlags) {
|
|
2010
|
+
const envVar = flag.env || flag.envVar;
|
|
2011
|
+
if (envVar) {
|
|
2012
|
+
envVars[envVar] = `\${user_config.${envVar}}`;
|
|
2013
|
+
userConfig[envVar] = {
|
|
2014
|
+
type: "string",
|
|
2015
|
+
title: envVar.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
2016
|
+
description: flag.description || `${envVar} environment variable`,
|
|
2017
|
+
required: true,
|
|
2018
|
+
// Always require env vars in user_config for better UX
|
|
2019
|
+
sensitive: true
|
|
2020
|
+
// Assume env vars are sensitive
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
if (typeof this.argParserInstance.getTools === "function") {
|
|
2025
|
+
const tools = this.argParserInstance.getTools();
|
|
2026
|
+
for (const [, toolConfig] of tools) {
|
|
2027
|
+
const toolFlags = toolConfig.flags || [];
|
|
2028
|
+
for (const flag of toolFlags) {
|
|
2029
|
+
const envVar = flag.env || flag.envVar;
|
|
2030
|
+
if (envVar && !envVars[envVar]) {
|
|
2031
|
+
envVars[envVar] = `\${user_config.${envVar}}`;
|
|
2032
|
+
userConfig[envVar] = {
|
|
2033
|
+
type: "string",
|
|
2034
|
+
title: envVar.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
2035
|
+
description: flag.description || `${envVar} environment variable`,
|
|
2036
|
+
required: true,
|
|
2037
|
+
// Always require env vars in user_config for better UX
|
|
2038
|
+
sensitive: true
|
|
2039
|
+
// Assume env vars are sensitive
|
|
2040
|
+
};
|
|
2041
|
+
}
|
|
2685
2042
|
}
|
|
2686
2043
|
}
|
|
2687
2044
|
}
|
|
2688
|
-
|
|
2045
|
+
return { envVars, userConfig };
|
|
2689
2046
|
}
|
|
2690
2047
|
}
|
|
2691
2048
|
class McpNotificationsManager {
|
|
@@ -2840,10 +2197,16 @@ class McpNotificationsManager {
|
|
|
2840
2197
|
sendNotificationToClient(client, type2) {
|
|
2841
2198
|
try {
|
|
2842
2199
|
if (client.connection && typeof client.connection.sendNotification === "function") {
|
|
2843
|
-
client.connection.sendNotification(
|
|
2200
|
+
client.connection.sendNotification(
|
|
2201
|
+
`notifications/${type2}/list_changed`,
|
|
2202
|
+
{}
|
|
2203
|
+
);
|
|
2844
2204
|
}
|
|
2845
2205
|
} catch (error) {
|
|
2846
|
-
console.error(
|
|
2206
|
+
console.error(
|
|
2207
|
+
`Error sending notification to client ${client.clientId}:`,
|
|
2208
|
+
error
|
|
2209
|
+
);
|
|
2847
2210
|
this.removeClient(client.clientId);
|
|
2848
2211
|
}
|
|
2849
2212
|
}
|
|
@@ -2932,7 +2295,9 @@ class McpPromptsManager {
|
|
|
2932
2295
|
return await entry.config.handler(validatedArgs);
|
|
2933
2296
|
} catch (error) {
|
|
2934
2297
|
if (error instanceof z.ZodError) {
|
|
2935
|
-
throw new Error(
|
|
2298
|
+
throw new Error(
|
|
2299
|
+
`Invalid arguments for prompt '${name}': ${error.message}`
|
|
2300
|
+
);
|
|
2936
2301
|
}
|
|
2937
2302
|
throw error;
|
|
2938
2303
|
}
|
|
@@ -3132,7 +2497,9 @@ class McpResourcesManager {
|
|
|
3132
2497
|
try {
|
|
3133
2498
|
new ResourceTemplateParser(config.uriTemplate);
|
|
3134
2499
|
} catch (error) {
|
|
3135
|
-
throw new Error(
|
|
2500
|
+
throw new Error(
|
|
2501
|
+
`Invalid URI template '${config.uriTemplate}': ${error instanceof Error ? error.message : String(error)}`
|
|
2502
|
+
);
|
|
3136
2503
|
}
|
|
3137
2504
|
}
|
|
3138
2505
|
/**
|
|
@@ -3237,6 +2604,97 @@ const _FlagManager = class _FlagManager {
|
|
|
3237
2604
|
__flags = new WeakMap();
|
|
3238
2605
|
_throwForDuplicateFlags = new WeakMap();
|
|
3239
2606
|
let FlagManager = _FlagManager;
|
|
2607
|
+
function detectEntryPoint() {
|
|
2608
|
+
try {
|
|
2609
|
+
if (process.argv[1] && fs.existsSync(process.argv[1])) {
|
|
2610
|
+
return process.argv[1];
|
|
2611
|
+
}
|
|
2612
|
+
if (typeof require !== "undefined" && require.main && require.main.filename) {
|
|
2613
|
+
return require.main.filename;
|
|
2614
|
+
}
|
|
2615
|
+
return null;
|
|
2616
|
+
} catch {
|
|
2617
|
+
return null;
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
function getEntryPointFromImportMeta(importMetaUrl) {
|
|
2621
|
+
if (importMetaUrl.startsWith("file://")) {
|
|
2622
|
+
return decodeURIComponent(importMetaUrl.replace("file://", ""));
|
|
2623
|
+
}
|
|
2624
|
+
return importMetaUrl;
|
|
2625
|
+
}
|
|
2626
|
+
function normalizePath(path2) {
|
|
2627
|
+
return path2.trim();
|
|
2628
|
+
}
|
|
2629
|
+
function resolveLogPath(logPath, fallbackEntryPoint) {
|
|
2630
|
+
if (typeof logPath === "string") {
|
|
2631
|
+
const normalizedPath2 = normalizePath(logPath);
|
|
2632
|
+
if (path.isAbsolute(normalizedPath2)) {
|
|
2633
|
+
return normalizedPath2;
|
|
2634
|
+
}
|
|
2635
|
+
if (normalizedPath2.startsWith("cwd:")) {
|
|
2636
|
+
const relativePath = normalizedPath2.slice(4);
|
|
2637
|
+
return path.resolve(process.cwd(), relativePath);
|
|
2638
|
+
}
|
|
2639
|
+
const entryPoint = detectEntryPoint() || fallbackEntryPoint;
|
|
2640
|
+
if (entryPoint) {
|
|
2641
|
+
return path.resolve(path.dirname(entryPoint), normalizedPath2);
|
|
2642
|
+
}
|
|
2643
|
+
console.warn(
|
|
2644
|
+
`Warning: Could not detect entry point for log path resolution. Using process.cwd() as fallback. Path: ${normalizedPath2}`
|
|
2645
|
+
);
|
|
2646
|
+
return path.resolve(process.cwd(), normalizedPath2);
|
|
2647
|
+
}
|
|
2648
|
+
const { path: logFilePath, relativeTo = "entry", basePath } = logPath;
|
|
2649
|
+
const normalizedPath = normalizePath(logFilePath);
|
|
2650
|
+
switch (relativeTo) {
|
|
2651
|
+
case "absolute":
|
|
2652
|
+
if (basePath) {
|
|
2653
|
+
return path.resolve(basePath, normalizedPath);
|
|
2654
|
+
}
|
|
2655
|
+
if (path.isAbsolute(normalizedPath)) {
|
|
2656
|
+
return normalizedPath;
|
|
2657
|
+
}
|
|
2658
|
+
console.warn(
|
|
2659
|
+
`Warning: relativeTo 'absolute' specified but no basePath provided and path is not absolute. Using process.cwd() as fallback. Path: ${normalizedPath}`
|
|
2660
|
+
);
|
|
2661
|
+
return path.resolve(process.cwd(), normalizedPath);
|
|
2662
|
+
case "cwd":
|
|
2663
|
+
return path.resolve(process.cwd(), normalizedPath);
|
|
2664
|
+
case "entry":
|
|
2665
|
+
default:
|
|
2666
|
+
const entryPoint = detectEntryPoint() || fallbackEntryPoint;
|
|
2667
|
+
if (entryPoint) {
|
|
2668
|
+
return path.resolve(path.dirname(entryPoint), normalizedPath);
|
|
2669
|
+
}
|
|
2670
|
+
console.warn(
|
|
2671
|
+
`Warning: Could not detect entry point for log path resolution. Using process.cwd() as fallback. Path: ${normalizedPath}`
|
|
2672
|
+
);
|
|
2673
|
+
return path.resolve(process.cwd(), normalizedPath);
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
function entryRelative(path2) {
|
|
2677
|
+
return {
|
|
2678
|
+
path: path2,
|
|
2679
|
+
relativeTo: "entry"
|
|
2680
|
+
};
|
|
2681
|
+
}
|
|
2682
|
+
function cwdRelative(path2) {
|
|
2683
|
+
return {
|
|
2684
|
+
path: path2,
|
|
2685
|
+
relativeTo: "cwd"
|
|
2686
|
+
};
|
|
2687
|
+
}
|
|
2688
|
+
function absolutePath(path2, basePath) {
|
|
2689
|
+
return {
|
|
2690
|
+
path: path2,
|
|
2691
|
+
relativeTo: "absolute",
|
|
2692
|
+
basePath
|
|
2693
|
+
};
|
|
2694
|
+
}
|
|
2695
|
+
function legacyCwdPath(path2) {
|
|
2696
|
+
return `cwd:${path2}`;
|
|
2697
|
+
}
|
|
3240
2698
|
class ArgParserError extends Error {
|
|
3241
2699
|
constructor(message, cmdChain = []) {
|
|
3242
2700
|
super(message);
|
|
@@ -4634,15 +4092,14 @@ _handleBuildDxtFlag_fn = async function(processArgs, buildDxtIndex) {
|
|
|
4634
4092
|
};
|
|
4635
4093
|
_handleMcpServeFlag_fn = async function(processArgs, _mcpServeIndex) {
|
|
4636
4094
|
var _a;
|
|
4095
|
+
const transportOptions = __privateMethod(this, _ArgParserBase_instances, _parseMcpTransportOptions_fn).call(this, processArgs);
|
|
4096
|
+
const mcpServerConfig = __privateMethod(this, _ArgParserBase_instances, _getMcpServerConfiguration_fn).call(this);
|
|
4097
|
+
const effectiveLogPath = transportOptions.logPath || (mcpServerConfig == null ? void 0 : mcpServerConfig.logPath) || "./logs/mcp.log";
|
|
4098
|
+
const resolvedLogPath = resolveLogPath(effectiveLogPath);
|
|
4637
4099
|
let mcpLogger;
|
|
4638
4100
|
try {
|
|
4639
|
-
const mcpLoggerModule = await
|
|
4640
|
-
|
|
4641
|
-
)();
|
|
4642
|
-
mcpLogger = mcpLoggerModule.createMcpLogger(
|
|
4643
|
-
"MCP Serve",
|
|
4644
|
-
"./logs/mcp.log"
|
|
4645
|
-
);
|
|
4101
|
+
const mcpLoggerModule = await import("@alcyone-labs/simple-mcp-logger");
|
|
4102
|
+
mcpLogger = mcpLoggerModule.createMcpLogger("MCP Serve", resolvedLogPath);
|
|
4646
4103
|
globalThis.console = mcpLogger;
|
|
4647
4104
|
} catch {
|
|
4648
4105
|
mcpLogger = {
|
|
@@ -4653,7 +4110,6 @@ _handleMcpServeFlag_fn = async function(processArgs, _mcpServeIndex) {
|
|
|
4653
4110
|
mcpLogger.mcpError(
|
|
4654
4111
|
"Starting --s-mcp-serve system flag handler - console hijacked for MCP safety"
|
|
4655
4112
|
);
|
|
4656
|
-
const mcpServerConfig = __privateMethod(this, _ArgParserBase_instances, _getMcpServerConfiguration_fn).call(this);
|
|
4657
4113
|
if (!mcpServerConfig) {
|
|
4658
4114
|
mcpLogger.mcpError(
|
|
4659
4115
|
"No MCP server configuration found. Use withMcp() or addMcpSubCommand() to configure MCP server."
|
|
@@ -4667,13 +4123,16 @@ _handleMcpServeFlag_fn = async function(processArgs, _mcpServeIndex) {
|
|
|
4667
4123
|
mcpLogger.mcpError(
|
|
4668
4124
|
`Found MCP server configuration: ${((_a = mcpServerConfig.serverInfo) == null ? void 0 : _a.name) || "unnamed"}`
|
|
4669
4125
|
);
|
|
4670
|
-
|
|
4126
|
+
mcpLogger.mcpError(`Using log path: ${resolvedLogPath}`);
|
|
4671
4127
|
mcpLogger.mcpError(
|
|
4672
4128
|
`Transport options: ${JSON.stringify(transportOptions)}`
|
|
4673
4129
|
);
|
|
4674
4130
|
try {
|
|
4675
4131
|
mcpLogger.mcpError("Starting unified MCP server with all tools");
|
|
4676
|
-
await __privateMethod(this, _ArgParserBase_instances, _startUnifiedMcpServer_fn).call(this, mcpServerConfig,
|
|
4132
|
+
await __privateMethod(this, _ArgParserBase_instances, _startUnifiedMcpServer_fn).call(this, mcpServerConfig, {
|
|
4133
|
+
...transportOptions,
|
|
4134
|
+
logPath: resolvedLogPath
|
|
4135
|
+
});
|
|
4677
4136
|
mcpLogger.mcpError("Successfully started unified MCP server");
|
|
4678
4137
|
} catch (error) {
|
|
4679
4138
|
mcpLogger.mcpError(
|
|
@@ -4742,18 +4201,34 @@ _startUnifiedMcpServer_fn = async function(mcpServerConfig, transportOptions) {
|
|
|
4742
4201
|
await mcpParser.startMcpServerWithMultipleTransports(
|
|
4743
4202
|
serverInfo,
|
|
4744
4203
|
transportConfigs,
|
|
4745
|
-
toolOptions
|
|
4204
|
+
toolOptions,
|
|
4205
|
+
transportOptions.logPath
|
|
4746
4206
|
);
|
|
4747
4207
|
} catch (error) {
|
|
4748
4208
|
throw new Error(
|
|
4749
4209
|
`Error parsing transports configuration: ${error.message}. Expected JSON format: '[{"type":"stdio"},{"type":"sse","port":3001}]'`
|
|
4750
4210
|
);
|
|
4751
4211
|
}
|
|
4212
|
+
} else if (transportOptions.transportType) {
|
|
4213
|
+
const transportType = transportOptions.transportType;
|
|
4214
|
+
const finalTransportOptions = {
|
|
4215
|
+
port: transportOptions.port,
|
|
4216
|
+
host: transportOptions.host || "localhost",
|
|
4217
|
+
path: transportOptions.path || "/mcp"
|
|
4218
|
+
};
|
|
4219
|
+
await mcpParser.startMcpServerWithTransport(
|
|
4220
|
+
serverInfo,
|
|
4221
|
+
transportType,
|
|
4222
|
+
finalTransportOptions,
|
|
4223
|
+
toolOptions,
|
|
4224
|
+
transportOptions.logPath
|
|
4225
|
+
);
|
|
4752
4226
|
} else if (defaultTransports && defaultTransports.length > 0) {
|
|
4753
4227
|
await mcpParser.startMcpServerWithMultipleTransports(
|
|
4754
4228
|
serverInfo,
|
|
4755
4229
|
defaultTransports,
|
|
4756
|
-
toolOptions
|
|
4230
|
+
toolOptions,
|
|
4231
|
+
transportOptions.logPath
|
|
4757
4232
|
);
|
|
4758
4233
|
} else if (defaultTransport) {
|
|
4759
4234
|
await mcpParser.startMcpServerWithTransport(
|
|
@@ -4765,20 +4240,16 @@ _startUnifiedMcpServer_fn = async function(mcpServerConfig, transportOptions) {
|
|
|
4765
4240
|
path: defaultTransport.path,
|
|
4766
4241
|
sessionIdGenerator: defaultTransport.sessionIdGenerator
|
|
4767
4242
|
},
|
|
4768
|
-
toolOptions
|
|
4243
|
+
toolOptions,
|
|
4244
|
+
transportOptions.logPath
|
|
4769
4245
|
);
|
|
4770
4246
|
} else {
|
|
4771
|
-
const transportType = transportOptions.transportType || "stdio";
|
|
4772
|
-
const finalTransportOptions = {
|
|
4773
|
-
port: transportOptions.port,
|
|
4774
|
-
host: transportOptions.host || "localhost",
|
|
4775
|
-
path: transportOptions.path || "/mcp"
|
|
4776
|
-
};
|
|
4777
4247
|
await mcpParser.startMcpServerWithTransport(
|
|
4778
4248
|
serverInfo,
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
toolOptions
|
|
4249
|
+
"stdio",
|
|
4250
|
+
{},
|
|
4251
|
+
toolOptions,
|
|
4252
|
+
transportOptions.logPath
|
|
4782
4253
|
);
|
|
4783
4254
|
}
|
|
4784
4255
|
};
|
|
@@ -4845,6 +4316,12 @@ _parseMcpTransportOptions_fn = function(processArgs) {
|
|
|
4845
4316
|
i++;
|
|
4846
4317
|
}
|
|
4847
4318
|
break;
|
|
4319
|
+
case "--s-mcp-log-path":
|
|
4320
|
+
if (nextArg && !nextArg.startsWith("-")) {
|
|
4321
|
+
options.logPath = nextArg;
|
|
4322
|
+
i++;
|
|
4323
|
+
}
|
|
4324
|
+
break;
|
|
4848
4325
|
// Backward compatibility: support old flags but with deprecation warning
|
|
4849
4326
|
case "--transport":
|
|
4850
4327
|
case "--port":
|
|
@@ -6130,11 +5607,14 @@ Migration guide: https://github.com/alcyone-labs/arg-parser/blob/main/docs/MCP-M
|
|
|
6130
5607
|
* @param toolOptions Optional MCP tool generation options
|
|
6131
5608
|
* @returns Configured MCP server instance
|
|
6132
5609
|
*/
|
|
6133
|
-
async createMcpServer(serverInfo, toolOptions) {
|
|
6134
|
-
var _a;
|
|
6135
|
-
const
|
|
5610
|
+
async createMcpServer(serverInfo, toolOptions, logPath) {
|
|
5611
|
+
var _a, _b;
|
|
5612
|
+
const resolvedLogPath = resolveLogPath(
|
|
5613
|
+
logPath || ((_a = this._mcpServerConfig) == null ? void 0 : _a.logPath) || "./logs/mcp.log"
|
|
5614
|
+
);
|
|
5615
|
+
const logger2 = createMcpLogger("MCP Server Creation", resolvedLogPath);
|
|
6136
5616
|
try {
|
|
6137
|
-
const effectiveServerInfo = serverInfo || ((
|
|
5617
|
+
const effectiveServerInfo = serverInfo || ((_b = this._mcpServerConfig) == null ? void 0 : _b.serverInfo);
|
|
6138
5618
|
if (!effectiveServerInfo) {
|
|
6139
5619
|
throw new Error(
|
|
6140
5620
|
"No MCP server configuration found. Use withMcp() to configure server info or provide serverInfo parameter."
|
|
@@ -6315,11 +5795,11 @@ Migration guide: https://github.com/alcyone-labs/arg-parser/blob/main/docs/MCP-M
|
|
|
6315
5795
|
* @param toolOptions Optional MCP tool generation options
|
|
6316
5796
|
* @returns Promise that resolves when all servers are started
|
|
6317
5797
|
*/
|
|
6318
|
-
async startMcpServerWithMultipleTransports(serverInfo, transports, toolOptions) {
|
|
6319
|
-
const server = await this.createMcpServer(serverInfo, toolOptions);
|
|
5798
|
+
async startMcpServerWithMultipleTransports(serverInfo, transports, toolOptions, logPath) {
|
|
5799
|
+
const server = await this.createMcpServer(serverInfo, toolOptions, logPath);
|
|
6320
5800
|
const startPromises = [];
|
|
6321
5801
|
for (const transportConfig of transports) {
|
|
6322
|
-
const promise = __privateMethod(this, _ArgParser_instances, _startSingleTransport_fn).call(this, server, serverInfo, transportConfig);
|
|
5802
|
+
const promise = __privateMethod(this, _ArgParser_instances, _startSingleTransport_fn).call(this, server, serverInfo, transportConfig, logPath);
|
|
6323
5803
|
startPromises.push(promise);
|
|
6324
5804
|
}
|
|
6325
5805
|
await Promise.all(startPromises);
|
|
@@ -6332,12 +5812,12 @@ Migration guide: https://github.com/alcyone-labs/arg-parser/blob/main/docs/MCP-M
|
|
|
6332
5812
|
* @param toolOptions Optional MCP tool generation options
|
|
6333
5813
|
* @returns Promise that resolves when server is connected
|
|
6334
5814
|
*/
|
|
6335
|
-
async startMcpServerWithTransport(serverInfo, transportType, transportOptions = {}, toolOptions) {
|
|
6336
|
-
const server = await this.createMcpServer(serverInfo, toolOptions);
|
|
5815
|
+
async startMcpServerWithTransport(serverInfo, transportType, transportOptions = {}, toolOptions, logPath) {
|
|
5816
|
+
const server = await this.createMcpServer(serverInfo, toolOptions, logPath);
|
|
6337
5817
|
await __privateMethod(this, _ArgParser_instances, _startSingleTransport_fn).call(this, server, serverInfo, {
|
|
6338
5818
|
type: transportType,
|
|
6339
5819
|
...transportOptions
|
|
6340
|
-
});
|
|
5820
|
+
}, logPath);
|
|
6341
5821
|
}
|
|
6342
5822
|
async parse(processArgs, options) {
|
|
6343
5823
|
let result = await ArgParserBase.prototype.parse.call(
|
|
@@ -6599,8 +6079,9 @@ registerToolAsSubCommand_fn = function(toolConfig) {
|
|
|
6599
6079
|
handler: toolConfig.handler
|
|
6600
6080
|
});
|
|
6601
6081
|
};
|
|
6602
|
-
_startSingleTransport_fn = async function(server, serverInfo, transportConfig) {
|
|
6603
|
-
const
|
|
6082
|
+
_startSingleTransport_fn = async function(server, serverInfo, transportConfig, logPath) {
|
|
6083
|
+
const resolvedLogPath = resolveLogPath(logPath || "./logs/mcp.log");
|
|
6084
|
+
const logger2 = createMcpLogger("MCP Transport", resolvedLogPath);
|
|
6604
6085
|
try {
|
|
6605
6086
|
logger2.mcpError(
|
|
6606
6087
|
`Starting ${transportConfig.type} transport for server: ${serverInfo.name}`
|
|
@@ -6776,7 +6257,9 @@ class TomlConfigPlugin extends ConfigPlugin {
|
|
|
6776
6257
|
}
|
|
6777
6258
|
return parsed;
|
|
6778
6259
|
} catch (error) {
|
|
6779
|
-
throw new Error(
|
|
6260
|
+
throw new Error(
|
|
6261
|
+
`Failed to parse TOML: ${error instanceof Error ? error.message : String(error)}`
|
|
6262
|
+
);
|
|
6780
6263
|
}
|
|
6781
6264
|
}
|
|
6782
6265
|
generate(_config, flags, parsedArgs) {
|
|
@@ -6816,7 +6299,9 @@ class TomlConfigPlugin extends ConfigPlugin {
|
|
|
6816
6299
|
const tomlContent = this.tomlModule.stringify(configWithValues);
|
|
6817
6300
|
return lines.join("\n") + "\n" + tomlContent;
|
|
6818
6301
|
} catch (error) {
|
|
6819
|
-
throw new Error(
|
|
6302
|
+
throw new Error(
|
|
6303
|
+
`Failed to generate TOML: ${error instanceof Error ? error.message : String(error)}`
|
|
6304
|
+
);
|
|
6820
6305
|
}
|
|
6821
6306
|
}
|
|
6822
6307
|
/**
|
|
@@ -6852,7 +6337,10 @@ function createTomlPlugin() {
|
|
|
6852
6337
|
try {
|
|
6853
6338
|
return new TomlConfigPlugin();
|
|
6854
6339
|
} catch (error) {
|
|
6855
|
-
console.warn(
|
|
6340
|
+
console.warn(
|
|
6341
|
+
"TOML plugin not available:",
|
|
6342
|
+
error instanceof Error ? error.message : String(error)
|
|
6343
|
+
);
|
|
6856
6344
|
return null;
|
|
6857
6345
|
}
|
|
6858
6346
|
}
|
|
@@ -6868,7 +6356,10 @@ async function createTomlPluginAsync() {
|
|
|
6868
6356
|
const tomlModule = await Promise.resolve().then(() => index$1);
|
|
6869
6357
|
return new TomlConfigPlugin(tomlModule);
|
|
6870
6358
|
} catch (error) {
|
|
6871
|
-
console.warn(
|
|
6359
|
+
console.warn(
|
|
6360
|
+
"TOML plugin not available:",
|
|
6361
|
+
error instanceof Error ? error.message : String(error)
|
|
6362
|
+
);
|
|
6872
6363
|
return null;
|
|
6873
6364
|
}
|
|
6874
6365
|
}
|
|
@@ -6914,7 +6405,9 @@ class YamlConfigPlugin extends ConfigPlugin {
|
|
|
6914
6405
|
}
|
|
6915
6406
|
return parsed;
|
|
6916
6407
|
} catch (error) {
|
|
6917
|
-
throw new Error(
|
|
6408
|
+
throw new Error(
|
|
6409
|
+
`Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`
|
|
6410
|
+
);
|
|
6918
6411
|
}
|
|
6919
6412
|
}
|
|
6920
6413
|
generate(_config, flags, parsedArgs) {
|
|
@@ -6948,7 +6441,9 @@ class YamlConfigPlugin extends ConfigPlugin {
|
|
|
6948
6441
|
});
|
|
6949
6442
|
return lines.join("\n") + "\n" + yamlContent;
|
|
6950
6443
|
} catch (error) {
|
|
6951
|
-
throw new Error(
|
|
6444
|
+
throw new Error(
|
|
6445
|
+
`Failed to generate YAML: ${error instanceof Error ? error.message : String(error)}`
|
|
6446
|
+
);
|
|
6952
6447
|
}
|
|
6953
6448
|
}
|
|
6954
6449
|
/**
|
|
@@ -6978,7 +6473,10 @@ function createYamlPlugin() {
|
|
|
6978
6473
|
try {
|
|
6979
6474
|
return new YamlConfigPlugin();
|
|
6980
6475
|
} catch (error) {
|
|
6981
|
-
console.warn(
|
|
6476
|
+
console.warn(
|
|
6477
|
+
"YAML plugin not available:",
|
|
6478
|
+
error instanceof Error ? error.message : String(error)
|
|
6479
|
+
);
|
|
6982
6480
|
return null;
|
|
6983
6481
|
}
|
|
6984
6482
|
}
|
|
@@ -6994,7 +6492,10 @@ async function createYamlPluginAsync() {
|
|
|
6994
6492
|
const yamlModule = await import("js-yaml");
|
|
6995
6493
|
return new YamlConfigPlugin(yamlModule);
|
|
6996
6494
|
} catch (error) {
|
|
6997
|
-
console.warn(
|
|
6495
|
+
console.warn(
|
|
6496
|
+
"YAML plugin not available:",
|
|
6497
|
+
error instanceof Error ? error.message : String(error)
|
|
6498
|
+
);
|
|
6998
6499
|
return null;
|
|
6999
6500
|
}
|
|
7000
6501
|
}
|
|
@@ -7023,7 +6524,9 @@ class ArgParserFuzzyTester {
|
|
|
7023
6524
|
const results = [];
|
|
7024
6525
|
if (this.options.verbose) {
|
|
7025
6526
|
console.log(`Discovered ${commandPaths.length} command paths:`);
|
|
7026
|
-
commandPaths.forEach(
|
|
6527
|
+
commandPaths.forEach(
|
|
6528
|
+
(path2) => console.log(` ${path2.join(" ") || "(root)"}`)
|
|
6529
|
+
);
|
|
7027
6530
|
}
|
|
7028
6531
|
for (const commandPath of commandPaths) {
|
|
7029
6532
|
const pathResults = await this.testCommandPath(commandPath);
|
|
@@ -7049,7 +6552,12 @@ class ArgParserFuzzyTester {
|
|
|
7049
6552
|
for (const [subCommandName, subCommand] of subCommands) {
|
|
7050
6553
|
const newPath = [...currentPath, subCommandName];
|
|
7051
6554
|
allPaths.push(newPath);
|
|
7052
|
-
this.discoverSubCommandPaths(
|
|
6555
|
+
this.discoverSubCommandPaths(
|
|
6556
|
+
subCommand.parser,
|
|
6557
|
+
newPath,
|
|
6558
|
+
allPaths,
|
|
6559
|
+
depth + 1
|
|
6560
|
+
);
|
|
7053
6561
|
}
|
|
7054
6562
|
}
|
|
7055
6563
|
/**
|
|
@@ -8266,6 +7774,7 @@ class Protocol {
|
|
|
8266
7774
|
this._responseHandlers = /* @__PURE__ */ new Map();
|
|
8267
7775
|
this._progressHandlers = /* @__PURE__ */ new Map();
|
|
8268
7776
|
this._timeoutInfo = /* @__PURE__ */ new Map();
|
|
7777
|
+
this._pendingDebouncedNotifications = /* @__PURE__ */ new Set();
|
|
8269
7778
|
this.setNotificationHandler(CancelledNotificationSchema, (notification) => {
|
|
8270
7779
|
const controller = this._requestHandlerAbortControllers.get(notification.params.requestId);
|
|
8271
7780
|
controller === null || controller === void 0 ? void 0 : controller.abort(notification.params.reason);
|
|
@@ -8347,6 +7856,7 @@ class Protocol {
|
|
|
8347
7856
|
const responseHandlers = this._responseHandlers;
|
|
8348
7857
|
this._responseHandlers = /* @__PURE__ */ new Map();
|
|
8349
7858
|
this._progressHandlers.clear();
|
|
7859
|
+
this._pendingDebouncedNotifications.clear();
|
|
8350
7860
|
this._transport = void 0;
|
|
8351
7861
|
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
8352
7862
|
const error = new McpError(ErrorCode.ConnectionClosed, "Connection closed");
|
|
@@ -8546,10 +8056,32 @@ class Protocol {
|
|
|
8546
8056
|
* Emits a notification, which is a one-way message that does not expect a response.
|
|
8547
8057
|
*/
|
|
8548
8058
|
async notification(notification, options) {
|
|
8059
|
+
var _a, _b;
|
|
8549
8060
|
if (!this._transport) {
|
|
8550
8061
|
throw new Error("Not connected");
|
|
8551
8062
|
}
|
|
8552
8063
|
this.assertNotificationCapability(notification.method);
|
|
8064
|
+
const debouncedMethods = (_b = (_a = this._options) === null || _a === void 0 ? void 0 : _a.debouncedNotificationMethods) !== null && _b !== void 0 ? _b : [];
|
|
8065
|
+
const canDebounce = debouncedMethods.includes(notification.method) && !notification.params && !(options === null || options === void 0 ? void 0 : options.relatedRequestId);
|
|
8066
|
+
if (canDebounce) {
|
|
8067
|
+
if (this._pendingDebouncedNotifications.has(notification.method)) {
|
|
8068
|
+
return;
|
|
8069
|
+
}
|
|
8070
|
+
this._pendingDebouncedNotifications.add(notification.method);
|
|
8071
|
+
Promise.resolve().then(() => {
|
|
8072
|
+
var _a2;
|
|
8073
|
+
this._pendingDebouncedNotifications.delete(notification.method);
|
|
8074
|
+
if (!this._transport) {
|
|
8075
|
+
return;
|
|
8076
|
+
}
|
|
8077
|
+
const jsonrpcNotification2 = {
|
|
8078
|
+
...notification,
|
|
8079
|
+
jsonrpc: "2.0"
|
|
8080
|
+
};
|
|
8081
|
+
(_a2 = this._transport) === null || _a2 === void 0 ? void 0 : _a2.send(jsonrpcNotification2, options).catch((error) => this._onerror(error));
|
|
8082
|
+
});
|
|
8083
|
+
return;
|
|
8084
|
+
}
|
|
8553
8085
|
const jsonrpcNotification = {
|
|
8554
8086
|
...notification,
|
|
8555
8087
|
jsonrpc: "2.0"
|
|
@@ -24941,6 +24473,7 @@ export {
|
|
|
24941
24473
|
simpleChalk as SimpleChalk,
|
|
24942
24474
|
TomlConfigPlugin,
|
|
24943
24475
|
YamlConfigPlugin,
|
|
24476
|
+
absolutePath,
|
|
24944
24477
|
convertFlagToJsonSchemaProperty,
|
|
24945
24478
|
convertFlagsToJsonSchema,
|
|
24946
24479
|
convertFlagsToZodSchema,
|
|
@@ -24954,14 +24487,20 @@ export {
|
|
|
24954
24487
|
createTomlPluginAsync,
|
|
24955
24488
|
createYamlPlugin,
|
|
24956
24489
|
createYamlPluginAsync,
|
|
24490
|
+
cwdRelative,
|
|
24491
|
+
detectEntryPoint,
|
|
24957
24492
|
enableConfigPlugins,
|
|
24958
24493
|
enableOptionalConfigPlugins,
|
|
24959
24494
|
enableOptionalConfigPluginsAsync,
|
|
24495
|
+
entryRelative,
|
|
24960
24496
|
extractSimplifiedResponse,
|
|
24961
24497
|
generateMcpToolsFromArgParser,
|
|
24498
|
+
getEntryPointFromImportMeta,
|
|
24962
24499
|
getJsonSchemaTypeFromFlag,
|
|
24963
24500
|
globalConfigPluginRegistry,
|
|
24501
|
+
legacyCwdPath,
|
|
24964
24502
|
logger,
|
|
24503
|
+
resolveLogPath,
|
|
24965
24504
|
zodFlagSchema
|
|
24966
24505
|
};
|
|
24967
24506
|
//# sourceMappingURL=index.mjs.map
|