@alcyone-labs/arg-parser 2.5.0 → 2.7.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/dist/index.mjs CHANGED
@@ -12,6 +12,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
12
12
  var __flags, _throwForDuplicateFlags, _appName, _appCommandName, _subCommandName, _parameters, _handler, _throwForDuplicateFlags2, _description, _handleErrors, _autoExit, _parentParser, _lastParseResult, _inheritParentFlags, _subCommands, _flagManager, _dxtGenerator, _configurationManager, _fuzzyMode, _mcpResourcesManager, _mcpPromptsManager, _mcpNotificationsManager, _ArgParserBase_instances, _identifyCommandChainAndParsers_fn, _handleGlobalChecks_fn, _validateMandatoryFlags_fn, _applyDefaultValues_fn, _prepareAndExecuteHandler_fn, parseFlags_fn, _enableFuzzyMode_fn, displayErrorAndExit_fn, _printRecursiveToConsole_fn, _buildRecursiveString_fn, _buildRecursiveJson_fn, _handleSaveToEnvFlag_fn, _handleBuildDxtFlag_fn, _handleMcpServeFlag_fn, _resolveLoggerConfigForServe_fn, _getMcpServerConfiguration_fn, _startUnifiedMcpServer_fn, _findAllMcpSubCommands_fn, _parseMcpTransportOptions_fn, _ArgParser_instances, _resolveLoggerConfig_fn, registerToolAsSubCommand_fn, _startSingleTransport_fn, processAsyncHandlerPromise_fn, _hasDate, _hasTime, _offset;
13
13
  import * as fs from "node:fs";
14
14
  import * as path from "node:path";
15
+ import { fileURLToPath } from "node:url";
15
16
  import { createRegExp, anyOf as anyOf$1, oneOrMore, char } from "magic-regexp";
16
17
  import { getTsconfig, createPathsMatcher } from "get-tsconfig";
17
18
  import { z } from "zod";
@@ -1034,6 +1035,29 @@ class ConfigurationManager {
1034
1035
  }
1035
1036
  }
1036
1037
  }
1038
+ const zodDxtOptionsSchema = z.object({
1039
+ sensitive: z.boolean().optional().describe("Whether this field should be marked as sensitive in DXT user_config"),
1040
+ localDefault: z.string().optional().describe("Default value specific to DXT sandbox environment"),
1041
+ type: z.enum(["string", "directory", "file", "boolean", "number"]).optional().describe("DXT input type - determines UI component in DXT clients"),
1042
+ multiple: z.boolean().optional().describe("Allow multiple values (for arrays)"),
1043
+ min: z.number().optional().describe("Minimum value (for number type)"),
1044
+ max: z.number().optional().describe("Maximum value (for number type)"),
1045
+ default: z.any().optional().describe("DXT-specific default value (overrides localDefault if provided)"),
1046
+ title: z.string().optional().describe("Custom title for the user_config field")
1047
+ }).strict().refine(
1048
+ (data2) => {
1049
+ if ((data2.min !== void 0 || data2.max !== void 0) && data2.type !== "number") {
1050
+ return false;
1051
+ }
1052
+ if (data2.min !== void 0 && data2.max !== void 0 && data2.min > data2.max) {
1053
+ return false;
1054
+ }
1055
+ return true;
1056
+ },
1057
+ {
1058
+ message: "Invalid dxtOptions: min/max can only be used with type 'number', and min must be <= max"
1059
+ }
1060
+ );
1037
1061
  const zodFlagSchema = z.object({
1038
1062
  name: z.string().min(1, "Flag name cannot be empty").describe(
1039
1063
  "The output property name, used as a return key `{name: value}`. Must be unique."
@@ -1105,7 +1129,8 @@ const zodFlagSchema = z.object({
1105
1129
  enum: z.array(z.any()).optional().describe("Array of allowed values for the flag."),
1106
1130
  env: z.union([z.string(), z.array(z.string())]).optional().describe(
1107
1131
  "Environment variables that should be set from this flag's value in DXT packages."
1108
- )
1132
+ ),
1133
+ dxtOptions: zodDxtOptionsSchema.optional().describe("DXT-specific configuration options for enhanced DXT manifest generation")
1109
1134
  }).transform((obj) => {
1110
1135
  const newObj = { ...obj };
1111
1136
  if ("default" in newObj && newObj["default"] !== void 0 && !("defaultValue" in newObj)) {
@@ -1303,6 +1328,353 @@ echo "Mock DXT build script for ${serverInfo.name}"`;
1303
1328
  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"));
1304
1329
  }
1305
1330
  }
1331
+ function detectEntryPoint() {
1332
+ try {
1333
+ if (process.argv[1] && fs.existsSync(process.argv[1])) {
1334
+ return process.argv[1];
1335
+ }
1336
+ if (typeof require !== "undefined" && require.main && require.main.filename) {
1337
+ return require.main.filename;
1338
+ }
1339
+ return null;
1340
+ } catch {
1341
+ return null;
1342
+ }
1343
+ }
1344
+ function getEntryPointFromImportMeta(importMetaUrl) {
1345
+ if (importMetaUrl.startsWith("file://")) {
1346
+ return decodeURIComponent(importMetaUrl.replace("file://", ""));
1347
+ }
1348
+ return importMetaUrl;
1349
+ }
1350
+ function normalizePath(path2) {
1351
+ return path2.trim();
1352
+ }
1353
+ function resolveLogPath(logPath, fallbackEntryPoint) {
1354
+ if (typeof logPath === "string") {
1355
+ const pathWithVariables2 = DxtPathResolver.substituteVariables(
1356
+ logPath,
1357
+ DxtPathResolver.detectContext()
1358
+ );
1359
+ const normalizedPath2 = normalizePath(pathWithVariables2);
1360
+ if (path.isAbsolute(normalizedPath2)) {
1361
+ return normalizedPath2;
1362
+ }
1363
+ if (normalizedPath2.startsWith("cwd:")) {
1364
+ const relativePath = normalizedPath2.slice(4);
1365
+ return path.resolve(process.cwd(), relativePath);
1366
+ }
1367
+ const entryPoint = detectEntryPoint() || fallbackEntryPoint;
1368
+ if (entryPoint) {
1369
+ return path.resolve(path.dirname(entryPoint), normalizedPath2);
1370
+ }
1371
+ console.warn(
1372
+ `Warning: Could not detect entry point for log path resolution. Using process.cwd() as fallback. Path: ${normalizedPath2}`
1373
+ );
1374
+ return path.resolve(process.cwd(), normalizedPath2);
1375
+ }
1376
+ const { path: logFilePath, relativeTo = "entry", basePath } = logPath;
1377
+ const pathWithVariables = DxtPathResolver.substituteVariables(
1378
+ logFilePath,
1379
+ DxtPathResolver.detectContext()
1380
+ );
1381
+ const normalizedPath = normalizePath(pathWithVariables);
1382
+ switch (relativeTo) {
1383
+ case "absolute":
1384
+ if (basePath) {
1385
+ const resolvedBasePath = DxtPathResolver.substituteVariables(
1386
+ basePath,
1387
+ DxtPathResolver.detectContext()
1388
+ );
1389
+ return path.resolve(resolvedBasePath, normalizedPath);
1390
+ }
1391
+ if (path.isAbsolute(normalizedPath)) {
1392
+ return normalizedPath;
1393
+ }
1394
+ console.warn(
1395
+ `Warning: relativeTo 'absolute' specified but no basePath provided and path is not absolute. Using process.cwd() as fallback. Path: ${normalizedPath}`
1396
+ );
1397
+ return path.resolve(process.cwd(), normalizedPath);
1398
+ case "cwd":
1399
+ return path.resolve(process.cwd(), normalizedPath);
1400
+ case "entry":
1401
+ default:
1402
+ const entryPoint = detectEntryPoint() || fallbackEntryPoint;
1403
+ if (entryPoint) {
1404
+ return path.resolve(path.dirname(entryPoint), normalizedPath);
1405
+ }
1406
+ console.warn(
1407
+ `Warning: Could not detect entry point for log path resolution. Using process.cwd() as fallback. Path: ${normalizedPath}`
1408
+ );
1409
+ return path.resolve(process.cwd(), normalizedPath);
1410
+ }
1411
+ }
1412
+ function entryRelative(path2) {
1413
+ return {
1414
+ path: path2,
1415
+ relativeTo: "entry"
1416
+ };
1417
+ }
1418
+ function cwdRelative(path2) {
1419
+ return {
1420
+ path: path2,
1421
+ relativeTo: "cwd"
1422
+ };
1423
+ }
1424
+ function absolutePath(path2, basePath) {
1425
+ return {
1426
+ path: path2,
1427
+ relativeTo: "absolute",
1428
+ basePath
1429
+ };
1430
+ }
1431
+ function legacyCwdPath(path2) {
1432
+ return `cwd:${path2}`;
1433
+ }
1434
+ const _DxtPathResolver = class _DxtPathResolver {
1435
+ /**
1436
+ * Detects the current execution context
1437
+ * @param forceRefresh - Force refresh of cached context
1438
+ * @returns Path context information
1439
+ */
1440
+ static detectContext(forceRefresh = false) {
1441
+ if (!forceRefresh && this._cachedContext) {
1442
+ return this._cachedContext;
1443
+ }
1444
+ const context = {
1445
+ isDxt: this.isDxtEnvironment(),
1446
+ userHome: void 0,
1447
+ cwd: typeof process !== "undefined" && typeof process.cwd === "function" ? process.cwd() : void 0
1448
+ };
1449
+ const entryPoint = detectEntryPoint();
1450
+ if (entryPoint) {
1451
+ context.entryDir = path.dirname(entryPoint);
1452
+ }
1453
+ if (context.isDxt) {
1454
+ context.extensionDir = this.detectDxtExtensionDir();
1455
+ }
1456
+ this._cachedContext = context;
1457
+ return context;
1458
+ }
1459
+ /**
1460
+ * Checks if the current environment is a DXT environment
1461
+ * @returns True if running in DXT, false otherwise
1462
+ */
1463
+ static isDxtEnvironment() {
1464
+ if (process.env["DXT_EXTENSION_DIR"] || process.env["CLAUDE_DESKTOP_DXT"]) {
1465
+ return true;
1466
+ }
1467
+ const dxtIndicators = [
1468
+ "manifest.json",
1469
+ // DXT packages have manifest.json
1470
+ ".dxt"
1471
+ // DXT marker file
1472
+ ];
1473
+ for (const indicator of dxtIndicators) {
1474
+ const indicatorPath = path.join(process.cwd(), indicator);
1475
+ if (fs.existsSync(indicatorPath)) {
1476
+ if (indicator === "manifest.json") {
1477
+ try {
1478
+ const manifest = JSON.parse(fs.readFileSync(indicatorPath, "utf-8"));
1479
+ if (manifest.server && manifest.user_config) {
1480
+ return true;
1481
+ }
1482
+ } catch {
1483
+ }
1484
+ } else {
1485
+ return true;
1486
+ }
1487
+ }
1488
+ }
1489
+ const cwd = process.cwd();
1490
+ if (cwd.includes("claude-desktop") || cwd.includes("extensions")) {
1491
+ return true;
1492
+ }
1493
+ return false;
1494
+ }
1495
+ /**
1496
+ * Detects the DXT extension directory
1497
+ * @returns DXT extension directory path or undefined
1498
+ */
1499
+ static detectDxtExtensionDir() {
1500
+ if (process.env["DXT_EXTENSION_DIR"]) {
1501
+ return process.env["DXT_EXTENSION_DIR"];
1502
+ }
1503
+ const cwd = process.cwd();
1504
+ if (fs.existsSync(path.join(cwd, "manifest.json"))) {
1505
+ return cwd;
1506
+ }
1507
+ let currentDir = cwd;
1508
+ for (let i = 0; i < 3; i++) {
1509
+ const parentDir = path.dirname(currentDir);
1510
+ if (parentDir === currentDir) break;
1511
+ if (fs.existsSync(path.join(parentDir, "manifest.json"))) {
1512
+ return parentDir;
1513
+ }
1514
+ currentDir = parentDir;
1515
+ }
1516
+ return void 0;
1517
+ }
1518
+ /**
1519
+ * Resolves a path with DXT variable substitution
1520
+ * @param inputPath - Path that may contain DXT variables
1521
+ * @param context - Optional context (will be detected if not provided)
1522
+ * @param config - Optional configuration for variable substitution
1523
+ * @returns Resolved absolute path
1524
+ */
1525
+ static resolvePath(inputPath, context, config) {
1526
+ const ctx = context || this.detectContext();
1527
+ const resolvedPath = this.substituteVariables(inputPath, ctx, config);
1528
+ if (path.isAbsolute(resolvedPath)) {
1529
+ return resolvedPath;
1530
+ }
1531
+ if (ctx.isDxt && ctx.extensionDir) {
1532
+ return path.resolve(ctx.extensionDir, resolvedPath);
1533
+ } else if (ctx.entryDir) {
1534
+ return path.resolve(ctx.entryDir, resolvedPath);
1535
+ } else {
1536
+ return path.resolve(ctx.cwd || process.cwd(), resolvedPath);
1537
+ }
1538
+ }
1539
+ /**
1540
+ * Substitutes DXT variables in a path string
1541
+ * @param inputPath - Path containing variables like ${HOME}, ${__dirname}, etc.
1542
+ * @param context - Path context
1543
+ * @param config - Variable substitution configuration
1544
+ * @returns Path with variables substituted
1545
+ */
1546
+ static substituteVariables(inputPath, context, config) {
1547
+ const safeHomedir = () => "/tmp";
1548
+ const homeDir = context.userHome || safeHomedir();
1549
+ const variables = {
1550
+ // Standard DXT variables
1551
+ HOME: homeDir,
1552
+ DOCUMENTS: path.join(homeDir, "Documents"),
1553
+ DOWNLOADS: path.join(homeDir, "Downloads"),
1554
+ DESKTOP: path.join(homeDir, "Desktop"),
1555
+ pathSeparator: path.sep,
1556
+ // Context-specific variables
1557
+ __dirname: context.isDxt && context.extensionDir ? context.extensionDir : context.entryDir || context.cwd || process.cwd(),
1558
+ // DXT-specific variables
1559
+ ...context.isDxt && context.extensionDir && {
1560
+ DXT_DIR: context.extensionDir,
1561
+ EXTENSION_DIR: context.extensionDir
1562
+ },
1563
+ // Custom variables override defaults
1564
+ ...config == null ? void 0 : config.customVariables
1565
+ };
1566
+ return inputPath.replace(/\$\{([^}]*)\}/g, (match, variableName) => {
1567
+ if (!variableName.trim()) {
1568
+ if (config == null ? void 0 : config.allowUndefined) {
1569
+ return match;
1570
+ }
1571
+ throw new Error(
1572
+ `Undefined DXT variable: ${variableName}. Available variables: ${Object.keys(variables).join(", ")}`
1573
+ );
1574
+ }
1575
+ const value = variables[variableName];
1576
+ if (value !== void 0) {
1577
+ return value;
1578
+ }
1579
+ if (config == null ? void 0 : config.allowUndefined) {
1580
+ return match;
1581
+ }
1582
+ throw new Error(
1583
+ `Undefined DXT variable: ${variableName}. Available variables: ${Object.keys(variables).join(", ")}`
1584
+ );
1585
+ });
1586
+ }
1587
+ /**
1588
+ * Creates a path for user data storage
1589
+ * @param filename - Name of the file or subdirectory
1590
+ * @param context - Optional context (will be detected if not provided)
1591
+ * @returns Absolute path for user data
1592
+ */
1593
+ static createUserDataPath(filename, context) {
1594
+ const ctx = context || this.detectContext();
1595
+ if (ctx.isDxt && ctx.extensionDir) {
1596
+ return path.join(ctx.extensionDir, "data", filename);
1597
+ } else {
1598
+ const safeHomedir = () => "/tmp";
1599
+ const userDataDir = process.env["XDG_DATA_HOME"] || path.join(ctx.userHome || safeHomedir(), ".local", "share");
1600
+ const appName = this.getAppName(ctx);
1601
+ return path.join(userDataDir, appName, filename);
1602
+ }
1603
+ }
1604
+ /**
1605
+ * Creates a path for temporary files
1606
+ * @param filename - Name of the temporary file
1607
+ * @param context - Optional context (will be detected if not provided)
1608
+ * @returns Absolute path for temporary file
1609
+ */
1610
+ static createTempPath(filename, context) {
1611
+ const ctx = context || this.detectContext();
1612
+ if (ctx.isDxt && ctx.extensionDir) {
1613
+ return path.join(ctx.extensionDir, "temp", filename);
1614
+ } else {
1615
+ const safeTmpdir = () => "/tmp";
1616
+ const appName = this.getAppName(ctx);
1617
+ return path.join(safeTmpdir(), appName, filename);
1618
+ }
1619
+ }
1620
+ /**
1621
+ * Creates a path for configuration files
1622
+ * @param filename - Name of the configuration file
1623
+ * @param context - Optional context (will be detected if not provided)
1624
+ * @returns Absolute path for configuration file
1625
+ */
1626
+ static createConfigPath(filename, context) {
1627
+ const ctx = context || this.detectContext();
1628
+ if (ctx.isDxt && ctx.extensionDir) {
1629
+ return path.join(ctx.extensionDir, "config", filename);
1630
+ } else {
1631
+ const safeHomedir = () => "/tmp";
1632
+ const configDir = process.env["XDG_CONFIG_HOME"] || path.join(ctx.userHome || safeHomedir(), ".config");
1633
+ const appName = this.getAppName(ctx);
1634
+ return path.join(configDir, appName, filename);
1635
+ }
1636
+ }
1637
+ /**
1638
+ * Gets the application name for directory creation
1639
+ * @param context - Path context
1640
+ * @returns Application name or default
1641
+ */
1642
+ static getAppName(context) {
1643
+ try {
1644
+ const packageJsonPath = path.join(context.entryDir || context.cwd || process.cwd(), "package.json");
1645
+ if (fs.existsSync(packageJsonPath)) {
1646
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
1647
+ return packageJson.name || "argparser-app";
1648
+ }
1649
+ } catch {
1650
+ }
1651
+ return "argparser-app";
1652
+ }
1653
+ /**
1654
+ * Ensures a directory exists, creating it if necessary
1655
+ * @param dirPath - Directory path to ensure
1656
+ * @returns True if directory exists or was created successfully
1657
+ */
1658
+ static ensureDirectory(dirPath) {
1659
+ try {
1660
+ if (!fs.existsSync(dirPath)) {
1661
+ fs.mkdirSync(dirPath, { recursive: true });
1662
+ }
1663
+ return true;
1664
+ } catch (error) {
1665
+ console.warn(`Failed to create directory: ${dirPath}`, error);
1666
+ return false;
1667
+ }
1668
+ }
1669
+ /**
1670
+ * Clears the cached context (useful for testing)
1671
+ */
1672
+ static clearCache() {
1673
+ this._cachedContext = null;
1674
+ }
1675
+ };
1676
+ _DxtPathResolver._cachedContext = null;
1677
+ let DxtPathResolver = _DxtPathResolver;
1306
1678
  class DxtGenerator {
1307
1679
  constructor(argParserInstance) {
1308
1680
  this.argParserInstance = argParserInstance;
@@ -1712,100 +2084,128 @@ class DxtGenerator {
1712
2084
  silent: process.env["NO_SILENCE"] !== "1",
1713
2085
  unbundle: true,
1714
2086
  external: (id, importer) => {
1715
- const external = this.shouldModuleBeExternal(
1716
- id,
1717
- importer,
1718
- withNodeModules
1719
- );
1720
- if (Boolean(process.env["DEBUG"]))
1721
- console.log(
1722
- `[${simpleChalk.blue("External")}] ${simpleChalk.yellow(external ? "true" : "false")} for module: (${simpleChalk.green(id)}), path: '${simpleChalk.grey(importer ?? "")}'`
2087
+ try {
2088
+ const external = this.shouldModuleBeExternal(
2089
+ id,
2090
+ importer,
2091
+ withNodeModules
1723
2092
  );
1724
- return external;
2093
+ if (Boolean(process.env["DEBUG"]))
2094
+ console.log(
2095
+ `[${simpleChalk.blue("External")}] ${simpleChalk.yellow(external ? "true" : "false")} for module: (${simpleChalk.green(id)}), path: '${simpleChalk.grey(importer ?? "")}'`
2096
+ );
2097
+ return Boolean(external);
2098
+ } catch (error) {
2099
+ console.warn(`Warning: Error in external function for ${id}:`, error);
2100
+ return true;
2101
+ }
1725
2102
  },
1726
2103
  noExternal: (id, importer) => {
1727
- const external = this.shouldModuleBeExternal(
1728
- id,
1729
- importer,
1730
- withNodeModules
1731
- );
1732
- if (Boolean(process.env["DEBUG"]))
1733
- console.log(
1734
- `[${simpleChalk.yellow("noExternal")}] ${simpleChalk.yellow(external === false ? "true" : "false")} for module: (${simpleChalk.green(id)}), path: '${simpleChalk.grey(importer ?? "")}'`
2104
+ try {
2105
+ const external = this.shouldModuleBeExternal(
2106
+ id,
2107
+ importer,
2108
+ withNodeModules
1735
2109
  );
1736
- return external === false;
2110
+ if (Boolean(process.env["DEBUG"]))
2111
+ console.log(
2112
+ `[${simpleChalk.yellow("noExternal")}] ${simpleChalk.yellow(external === false ? "true" : "false")} for module: (${simpleChalk.green(id)}), path: '${simpleChalk.grey(importer ?? "")}'`
2113
+ );
2114
+ return Boolean(external === false);
2115
+ } catch (error) {
2116
+ console.warn(`Warning: Error in noExternal function for ${id}:`, error);
2117
+ return false;
2118
+ }
1737
2119
  },
1738
2120
  copy: async (options) => {
1739
2121
  var _a2;
1740
- const outputPaths = [
1741
- "package.json"
1742
- ];
1743
- if (withNodeModules) {
1744
- console.log(
1745
- simpleChalk.gray(
1746
- "📦 Including node_modules in bundle (may take longer)..."
1747
- )
1748
- );
1749
- outputPaths.push("node_modules");
1750
- }
1751
- const dxtPackageRoot = entryDir !== "." && entryDir !== "" ? path.dirname(options.outDir) : options.outDir;
1752
- if (logoFilename) {
1753
- const currentDir = typeof process !== "undefined" ? process.cwd() : "/test";
1754
- const logoPath = path.join(currentDir, logoFilename);
1755
- if (fs.existsSync(logoPath)) {
1756
- console.log(simpleChalk.gray(`Adding logo from: ${logoPath}`));
1757
- outputPaths.push({
1758
- from: logoPath,
1759
- to: path.join(dxtPackageRoot, logoFilename)
1760
- });
2122
+ try {
2123
+ const outputPaths = [
2124
+ "package.json"
2125
+ ];
2126
+ if (withNodeModules) {
2127
+ console.log(
2128
+ simpleChalk.gray(
2129
+ "📦 Including node_modules in bundle (may take longer)..."
2130
+ )
2131
+ );
2132
+ outputPaths.push("node_modules");
1761
2133
  }
1762
- }
1763
- if ((_a2 = mcpConfig == null ? void 0 : mcpConfig.dxt) == null ? void 0 : _a2.include) {
1764
- console.log(
1765
- simpleChalk.gray(
1766
- "📁 Including additional files from DXT configuration..."
1767
- )
1768
- );
1769
- for (const includeItem of mcpConfig.dxt.include) {
1770
- if (typeof includeItem === "string") {
1771
- const sourcePath = path.resolve(projectRoot, includeItem);
1772
- if (fs.existsSync(sourcePath)) {
1773
- console.log(simpleChalk.gray(` • ${includeItem}`));
1774
- outputPaths.push({
1775
- from: sourcePath,
1776
- to: path.join(dxtPackageRoot, includeItem)
1777
- });
1778
- } else {
1779
- console.warn(
1780
- simpleChalk.yellow(
1781
- ` ⚠ File not found: ${includeItem} (resolved to ${sourcePath})`
1782
- )
1783
- );
1784
- }
1785
- } else {
1786
- const sourcePath = path.resolve(
1787
- projectRoot,
1788
- includeItem.from
1789
- );
1790
- if (fs.existsSync(sourcePath)) {
1791
- console.log(
1792
- simpleChalk.gray(` • ${includeItem.from} → ${includeItem.to}`)
2134
+ const dxtPackageRoot = entryDir !== "." && entryDir !== "" ? path.dirname(options.outDir) : options.outDir;
2135
+ if (logoFilename) {
2136
+ const currentDir = typeof process !== "undefined" ? process.cwd() : "/test";
2137
+ const logoPath = path.join(currentDir, logoFilename);
2138
+ if (fs.existsSync(logoPath)) {
2139
+ console.log(simpleChalk.gray(`Adding logo from: ${logoPath}`));
2140
+ outputPaths.push({
2141
+ from: logoPath,
2142
+ to: path.join(dxtPackageRoot, logoFilename)
2143
+ });
2144
+ }
2145
+ }
2146
+ if ((_a2 = mcpConfig == null ? void 0 : mcpConfig.dxt) == null ? void 0 : _a2.include) {
2147
+ console.log(
2148
+ simpleChalk.gray(
2149
+ "📁 Including additional files from DXT configuration..."
2150
+ )
2151
+ );
2152
+ for (const includeItem of mcpConfig.dxt.include) {
2153
+ if (typeof includeItem === "string") {
2154
+ const resolvedIncludePath = DxtPathResolver.substituteVariables(
2155
+ includeItem,
2156
+ DxtPathResolver.detectContext(),
2157
+ { allowUndefined: true }
2158
+ // Allow undefined variables for flexibility
1793
2159
  );
1794
- outputPaths.push({
1795
- from: sourcePath,
1796
- to: path.join(dxtPackageRoot, includeItem.to)
1797
- });
2160
+ const sourcePath = path.resolve(projectRoot, resolvedIncludePath);
2161
+ if (fs.existsSync(sourcePath)) {
2162
+ console.log(simpleChalk.gray(` • ${resolvedIncludePath}`));
2163
+ outputPaths.push({
2164
+ from: sourcePath,
2165
+ to: path.join(dxtPackageRoot, resolvedIncludePath)
2166
+ });
2167
+ } else {
2168
+ console.warn(
2169
+ simpleChalk.yellow(
2170
+ ` ⚠ File not found: ${resolvedIncludePath} (resolved to ${sourcePath})`
2171
+ )
2172
+ );
2173
+ }
1798
2174
  } else {
1799
- console.warn(
1800
- simpleChalk.yellow(
1801
- ` ⚠ File not found: ${includeItem.from} (resolved to ${sourcePath})`
1802
- )
2175
+ const resolvedFromPath = DxtPathResolver.substituteVariables(
2176
+ includeItem.from,
2177
+ DxtPathResolver.detectContext(),
2178
+ { allowUndefined: true }
2179
+ );
2180
+ const resolvedToPath = DxtPathResolver.substituteVariables(
2181
+ includeItem.to,
2182
+ DxtPathResolver.detectContext(),
2183
+ { allowUndefined: true }
1803
2184
  );
2185
+ const sourcePath = path.resolve(projectRoot, resolvedFromPath);
2186
+ if (fs.existsSync(sourcePath)) {
2187
+ console.log(
2188
+ simpleChalk.gray(` • ${resolvedFromPath} → ${resolvedToPath}`)
2189
+ );
2190
+ outputPaths.push({
2191
+ from: sourcePath,
2192
+ to: path.join(dxtPackageRoot, resolvedToPath)
2193
+ });
2194
+ } else {
2195
+ console.warn(
2196
+ simpleChalk.yellow(
2197
+ ` ⚠ File not found: ${resolvedFromPath} (resolved to ${sourcePath})`
2198
+ )
2199
+ );
2200
+ }
1804
2201
  }
1805
2202
  }
1806
2203
  }
2204
+ return outputPaths;
2205
+ } catch (error) {
2206
+ console.warn(`Warning: Error in copy function:`, error);
2207
+ return ["package.json"];
1807
2208
  }
1808
- return outputPaths;
1809
2209
  },
1810
2210
  platform: "node",
1811
2211
  plugins: []
@@ -1833,8 +2233,18 @@ export default ${JSON.stringify(buildConfig, null, 2)};
1833
2233
  simpleChalk.gray("📝 Debug config written to dxt/tsdown.config.dxt.ts")
1834
2234
  );
1835
2235
  }
1836
- await build(buildConfig);
1837
- console.log(simpleChalk.green("✅ TSDown bundling completed"));
2236
+ try {
2237
+ await build(buildConfig);
2238
+ console.log(simpleChalk.green("✅ TSDown bundling completed"));
2239
+ } catch (buildError) {
2240
+ console.error(simpleChalk.red("❌ TSDown build failed with error:"));
2241
+ console.error(buildError);
2242
+ if (buildError instanceof Error) {
2243
+ console.error(simpleChalk.red("Error message:"), buildError.message);
2244
+ console.error(simpleChalk.red("Error stack:"), buildError.stack);
2245
+ }
2246
+ throw new Error(`TSDown DXT build failed: ${buildError instanceof Error ? buildError.message : String(buildError)}`);
2247
+ }
1838
2248
  const detectedOutputFile = this.detectTsdownOutputFile(
1839
2249
  outputDir,
1840
2250
  relativeEntryPath.replace(/\.ts$/, ".js")
@@ -2093,7 +2503,7 @@ export default ${JSON.stringify(buildConfig, null, 2)};
2093
2503
  if (flag.enum) {
2094
2504
  properties2[flag.name].enum = flag.enum;
2095
2505
  }
2096
- if (flag.defaultValue !== void 0) {
2506
+ if (flag.defaultValue !== void 0 && typeof flag.defaultValue !== "function") {
2097
2507
  properties2[flag.name].default = flag.defaultValue;
2098
2508
  }
2099
2509
  if (flag.mandatory) {
@@ -2268,11 +2678,62 @@ export default ${JSON.stringify(buildConfig, null, 2)};
2268
2678
  `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.`
2269
2679
  );
2270
2680
  }
2681
+ /**
2682
+ * Validate dxtOptions for common mistakes and security issues
2683
+ * @param flag The flag with dxtOptions to validate
2684
+ * @param envVar The environment variable name for context
2685
+ */
2686
+ validateDxtOptions(flag, envVar) {
2687
+ const dxtOptions = flag.dxtOptions;
2688
+ if (!dxtOptions) return;
2689
+ if (dxtOptions.min !== void 0 && dxtOptions.max !== void 0) {
2690
+ if (dxtOptions.min > dxtOptions.max) {
2691
+ throw new Error(
2692
+ `Invalid dxtOptions for ${envVar}: min (${dxtOptions.min}) cannot be greater than max (${dxtOptions.max})`
2693
+ );
2694
+ }
2695
+ }
2696
+ if (dxtOptions.type !== void 0) {
2697
+ const validTypes = ["string", "directory", "file", "boolean", "number"];
2698
+ if (!validTypes.includes(dxtOptions.type)) {
2699
+ throw new Error(
2700
+ `Invalid dxtOptions.type for ${envVar}: "${dxtOptions.type}". Must be one of: ${validTypes.join(", ")}`
2701
+ );
2702
+ }
2703
+ }
2704
+ if (dxtOptions.default !== void 0 && dxtOptions.type !== void 0) {
2705
+ const defaultType = typeof dxtOptions.default;
2706
+ if (dxtOptions.type === "number" && defaultType !== "number") {
2707
+ throw new Error(
2708
+ `Invalid dxtOptions.default for ${envVar}: expected number, got ${defaultType}`
2709
+ );
2710
+ }
2711
+ if (dxtOptions.type === "boolean" && defaultType !== "boolean") {
2712
+ throw new Error(
2713
+ `Invalid dxtOptions.default for ${envVar}: expected boolean, got ${defaultType}`
2714
+ );
2715
+ }
2716
+ }
2717
+ const sensitiveKeywords = ["key", "token", "password", "secret", "auth"];
2718
+ const envLower = envVar.toLowerCase();
2719
+ const hasSensitiveKeyword = sensitiveKeywords.some((keyword2) => envLower.includes(keyword2));
2720
+ if (hasSensitiveKeyword && dxtOptions.sensitive === false) {
2721
+ console.warn(
2722
+ `⚠️ Security Warning: ${envVar} contains sensitive keyword but dxtOptions.sensitive is false`
2723
+ );
2724
+ }
2725
+ if (flag.mandatory === true && dxtOptions.sensitive !== false) {
2726
+ console.warn(
2727
+ `⚠️ Security Warning: ${envVar} is required and sensitive - consider providing a secure default or making it optional`
2728
+ );
2729
+ }
2730
+ }
2271
2731
  /**
2272
2732
  * Generate environment variables and user configuration from ArgParser flags
2273
2733
  * @returns Object containing envVars and userConfig
2274
2734
  */
2275
2735
  generateEnvAndUserConfig() {
2736
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2276
2737
  const envVars = {};
2277
2738
  const userConfig = {};
2278
2739
  const shouldBeRequired = (flag) => {
@@ -2285,23 +2746,78 @@ export default ${JSON.stringify(buildConfig, null, 2)};
2285
2746
  return false;
2286
2747
  };
2287
2748
  const shouldBeSensitive = (flag) => {
2749
+ var _a2;
2750
+ if (((_a2 = flag.dxtOptions) == null ? void 0 : _a2.sensitive) !== void 0) {
2751
+ return flag.dxtOptions.sensitive;
2752
+ }
2288
2753
  const envVar = flag.env || flag.envVar;
2289
2754
  return !!envVar;
2290
2755
  };
2756
+ const getDxtType = (flag) => {
2757
+ var _a2;
2758
+ if ((_a2 = flag.dxtOptions) == null ? void 0 : _a2.type) {
2759
+ return flag.dxtOptions.type;
2760
+ }
2761
+ if (typeof flag.type === "string") {
2762
+ const lowerType = flag.type.toLowerCase();
2763
+ if (["string", "boolean", "number"].includes(lowerType)) {
2764
+ return lowerType;
2765
+ }
2766
+ } else if (flag.type === String) {
2767
+ return "string";
2768
+ } else if (flag.type === Boolean) {
2769
+ return "boolean";
2770
+ } else if (flag.type === Number) {
2771
+ return "number";
2772
+ }
2773
+ return "string";
2774
+ };
2775
+ const getDxtTitle = (flag, envVar) => {
2776
+ var _a2;
2777
+ if ((_a2 = flag.dxtOptions) == null ? void 0 : _a2.title) {
2778
+ return flag.dxtOptions.title;
2779
+ }
2780
+ return envVar.replace(/_/g, " ").toLowerCase().replace(/\b\w/g, (l) => l.toUpperCase());
2781
+ };
2782
+ const getDxtDescription = (flag, envVar) => {
2783
+ var _a2, _b2;
2784
+ let baseDescription = flag.description || `${envVar} environment variable`;
2785
+ const defaultValue = ((_a2 = flag.dxtOptions) == null ? void 0 : _a2.default) ?? ((_b2 = flag.dxtOptions) == null ? void 0 : _b2.localDefault) ?? flag.defaultValue;
2786
+ if (defaultValue !== void 0 && typeof defaultValue !== "function") {
2787
+ baseDescription += ` (default: ${defaultValue})`;
2788
+ }
2789
+ return baseDescription;
2790
+ };
2291
2791
  const mainFlags = this.argParserInstance.flags;
2292
2792
  for (const flag of mainFlags) {
2293
2793
  const envVar = flag.env || flag.envVar;
2294
2794
  if (envVar) {
2795
+ this.validateDxtOptions(flag, envVar);
2295
2796
  envVars[envVar] = `\${user_config.${envVar}}`;
2296
- userConfig[envVar] = {
2297
- type: "string",
2298
- title: envVar.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
2299
- description: flag.description || `${envVar} environment variable`,
2797
+ const userConfigEntry = {
2798
+ type: getDxtType(flag),
2799
+ title: getDxtTitle(flag, envVar),
2800
+ description: getDxtDescription(flag, envVar),
2300
2801
  required: shouldBeRequired(flag),
2301
2802
  // Respect the flag's mandatory setting
2302
2803
  sensitive: shouldBeSensitive(flag)
2303
- // Set to sensitive if tied to ENV
2804
+ // Use dxtOptions or default logic
2304
2805
  };
2806
+ if (((_a = flag.dxtOptions) == null ? void 0 : _a.multiple) !== void 0) {
2807
+ userConfigEntry.multiple = flag.dxtOptions.multiple;
2808
+ }
2809
+ if (((_b = flag.dxtOptions) == null ? void 0 : _b.min) !== void 0) {
2810
+ userConfigEntry.min = flag.dxtOptions.min;
2811
+ }
2812
+ if (((_c = flag.dxtOptions) == null ? void 0 : _c.max) !== void 0) {
2813
+ userConfigEntry.max = flag.dxtOptions.max;
2814
+ }
2815
+ if (((_d = flag.dxtOptions) == null ? void 0 : _d.default) !== void 0 && typeof flag.dxtOptions.default !== "function") {
2816
+ userConfigEntry.default = flag.dxtOptions.default;
2817
+ } else if (((_e = flag.dxtOptions) == null ? void 0 : _e.localDefault) !== void 0 && typeof flag.dxtOptions.localDefault !== "function") {
2818
+ userConfigEntry.default = flag.dxtOptions.localDefault;
2819
+ }
2820
+ userConfig[envVar] = userConfigEntry;
2305
2821
  }
2306
2822
  }
2307
2823
  if (typeof this.argParserInstance.getTools === "function") {
@@ -2311,16 +2827,32 @@ export default ${JSON.stringify(buildConfig, null, 2)};
2311
2827
  for (const flag of toolFlags) {
2312
2828
  const envVar = flag.env || flag.envVar;
2313
2829
  if (envVar && !envVars[envVar]) {
2830
+ this.validateDxtOptions(flag, envVar);
2314
2831
  envVars[envVar] = `\${user_config.${envVar}}`;
2315
- userConfig[envVar] = {
2316
- type: "string",
2317
- title: envVar.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
2318
- description: flag.description || `${envVar} environment variable`,
2832
+ const userConfigEntry = {
2833
+ type: getDxtType(flag),
2834
+ title: getDxtTitle(flag, envVar),
2835
+ description: getDxtDescription(flag, envVar),
2319
2836
  required: shouldBeRequired(flag),
2320
2837
  // Respect the flag's mandatory setting
2321
2838
  sensitive: shouldBeSensitive(flag)
2322
- // Set to sensitive if tied to ENV
2839
+ // Use dxtOptions or default logic
2323
2840
  };
2841
+ if (((_f = flag.dxtOptions) == null ? void 0 : _f.multiple) !== void 0) {
2842
+ userConfigEntry.multiple = flag.dxtOptions.multiple;
2843
+ }
2844
+ if (((_g = flag.dxtOptions) == null ? void 0 : _g.min) !== void 0) {
2845
+ userConfigEntry.min = flag.dxtOptions.min;
2846
+ }
2847
+ if (((_h = flag.dxtOptions) == null ? void 0 : _h.max) !== void 0) {
2848
+ userConfigEntry.max = flag.dxtOptions.max;
2849
+ }
2850
+ if (((_i = flag.dxtOptions) == null ? void 0 : _i.default) !== void 0 && typeof flag.dxtOptions.default !== "function") {
2851
+ userConfigEntry.default = flag.dxtOptions.default;
2852
+ } else if (((_j = flag.dxtOptions) == null ? void 0 : _j.localDefault) !== void 0 && typeof flag.dxtOptions.localDefault !== "function") {
2853
+ userConfigEntry.default = flag.dxtOptions.localDefault;
2854
+ }
2855
+ userConfig[envVar] = userConfigEntry;
2324
2856
  }
2325
2857
  }
2326
2858
  }
@@ -2351,10 +2883,10 @@ export default ${JSON.stringify(buildConfig, null, 2)};
2351
2883
  );
2352
2884
  }
2353
2885
  const pathsMatcher = createPathsMatcher(tsconfig);
2354
- if (!pathsMatcher) {
2886
+ if (!pathsMatcher || typeof pathsMatcher !== "function") {
2355
2887
  if (Boolean(process.env["DEBUG"])) {
2356
2888
  console.log(
2357
- ` <${simpleChalk.gray("ts-paths")}> Failed to create paths matcher`
2889
+ ` <${simpleChalk.gray("ts-paths")}> Failed to create paths matcher or matcher is not a function`
2358
2890
  );
2359
2891
  }
2360
2892
  } else {
@@ -3064,7 +3596,8 @@ const _FlagManager = class _FlagManager {
3064
3596
  validate: parsedFromZod["validate"],
3065
3597
  enum: parsedFromZod["enum"],
3066
3598
  mandatory: parsedFromZod["mandatory"],
3067
- env: parsedFromZod["env"]
3599
+ env: parsedFromZod["env"],
3600
+ dxtOptions: parsedFromZod["dxtOptions"]
3068
3601
  };
3069
3602
  }
3070
3603
  addFlag(flag) {
@@ -3113,97 +3646,6 @@ const _FlagManager = class _FlagManager {
3113
3646
  __flags = new WeakMap();
3114
3647
  _throwForDuplicateFlags = new WeakMap();
3115
3648
  let FlagManager = _FlagManager;
3116
- function detectEntryPoint() {
3117
- try {
3118
- if (process.argv[1] && fs.existsSync(process.argv[1])) {
3119
- return process.argv[1];
3120
- }
3121
- if (typeof require !== "undefined" && require.main && require.main.filename) {
3122
- return require.main.filename;
3123
- }
3124
- return null;
3125
- } catch {
3126
- return null;
3127
- }
3128
- }
3129
- function getEntryPointFromImportMeta(importMetaUrl) {
3130
- if (importMetaUrl.startsWith("file://")) {
3131
- return decodeURIComponent(importMetaUrl.replace("file://", ""));
3132
- }
3133
- return importMetaUrl;
3134
- }
3135
- function normalizePath(path2) {
3136
- return path2.trim();
3137
- }
3138
- function resolveLogPath(logPath, fallbackEntryPoint) {
3139
- if (typeof logPath === "string") {
3140
- const normalizedPath2 = normalizePath(logPath);
3141
- if (path.isAbsolute(normalizedPath2)) {
3142
- return normalizedPath2;
3143
- }
3144
- if (normalizedPath2.startsWith("cwd:")) {
3145
- const relativePath = normalizedPath2.slice(4);
3146
- return path.resolve(process.cwd(), relativePath);
3147
- }
3148
- const entryPoint = detectEntryPoint() || fallbackEntryPoint;
3149
- if (entryPoint) {
3150
- return path.resolve(path.dirname(entryPoint), normalizedPath2);
3151
- }
3152
- console.warn(
3153
- `Warning: Could not detect entry point for log path resolution. Using process.cwd() as fallback. Path: ${normalizedPath2}`
3154
- );
3155
- return path.resolve(process.cwd(), normalizedPath2);
3156
- }
3157
- const { path: logFilePath, relativeTo = "entry", basePath } = logPath;
3158
- const normalizedPath = normalizePath(logFilePath);
3159
- switch (relativeTo) {
3160
- case "absolute":
3161
- if (basePath) {
3162
- return path.resolve(basePath, normalizedPath);
3163
- }
3164
- if (path.isAbsolute(normalizedPath)) {
3165
- return normalizedPath;
3166
- }
3167
- console.warn(
3168
- `Warning: relativeTo 'absolute' specified but no basePath provided and path is not absolute. Using process.cwd() as fallback. Path: ${normalizedPath}`
3169
- );
3170
- return path.resolve(process.cwd(), normalizedPath);
3171
- case "cwd":
3172
- return path.resolve(process.cwd(), normalizedPath);
3173
- case "entry":
3174
- default:
3175
- const entryPoint = detectEntryPoint() || fallbackEntryPoint;
3176
- if (entryPoint) {
3177
- return path.resolve(path.dirname(entryPoint), normalizedPath);
3178
- }
3179
- console.warn(
3180
- `Warning: Could not detect entry point for log path resolution. Using process.cwd() as fallback. Path: ${normalizedPath}`
3181
- );
3182
- return path.resolve(process.cwd(), normalizedPath);
3183
- }
3184
- }
3185
- function entryRelative(path2) {
3186
- return {
3187
- path: path2,
3188
- relativeTo: "entry"
3189
- };
3190
- }
3191
- function cwdRelative(path2) {
3192
- return {
3193
- path: path2,
3194
- relativeTo: "cwd"
3195
- };
3196
- }
3197
- function absolutePath(path2, basePath) {
3198
- return {
3199
- path: path2,
3200
- relativeTo: "absolute",
3201
- basePath
3202
- };
3203
- }
3204
- function legacyCwdPath(path2) {
3205
- return `cwd:${path2}`;
3206
- }
3207
3649
  class ArgParserError extends Error {
3208
3650
  constructor(message, cmdChain = []) {
3209
3651
  super(message);
@@ -3470,22 +3912,41 @@ const _ArgParserBase = class _ArgParserBase {
3470
3912
  console.log("--- End Configuration Dump ---\\n");
3471
3913
  }
3472
3914
  }
3915
+ /**
3916
+ * Detects if the current script is being executed directly (not imported)
3917
+ * Uses a robust method that works across different environments and sandboxes
3918
+ * @param importMetaUrl The import.meta.url from the calling script (optional)
3919
+ * @returns true if the script is being executed directly, false if imported
3920
+ */
3921
+ static isExecutedDirectly(importMetaUrl) {
3922
+ try {
3923
+ if (importMetaUrl) {
3924
+ const currentFile = fileURLToPath(importMetaUrl);
3925
+ const executedFile = path.resolve(process.argv[1]);
3926
+ return currentFile === executedFile;
3927
+ }
3928
+ if (typeof process !== "undefined" && process.argv && process.argv[1]) {
3929
+ return false;
3930
+ }
3931
+ return false;
3932
+ } catch {
3933
+ return false;
3934
+ }
3935
+ }
3473
3936
  async parse(processArgs, options) {
3474
- var _a, _b;
3937
+ var _a;
3475
3938
  debug.log("ArgParserBase.parse() called with args:", processArgs);
3939
+ const shouldCheckAutoExecution = (options == null ? void 0 : options.importMetaUrl) && (options == null ? void 0 : options.autoExecute) !== false;
3940
+ if (shouldCheckAutoExecution) {
3941
+ const isDirectExecution = _ArgParserBase.isExecutedDirectly(options.importMetaUrl);
3942
+ if (!isDirectExecution) {
3943
+ debug.log("Auto-execution enabled but script is imported, skipping execution");
3944
+ return {};
3945
+ }
3946
+ }
3476
3947
  if (processArgs === void 0) {
3477
3948
  if (typeof process !== "undefined" && process.argv && Array.isArray(process.argv)) {
3478
3949
  processArgs = process.argv.slice(2);
3479
- const isCliMode = !__privateGet(this, _parentParser) && !!__privateGet(this, _appCommandName);
3480
- const isMcpMode = (options == null ? void 0 : options.isMcp) || ((_a = globalThis.console) == null ? void 0 : _a.mcpError);
3481
- if (isCliMode && !isMcpMode) {
3482
- console.warn(
3483
- `Warning: parse() called without arguments. Auto-detected Node.js environment and using process.argv.slice(2).`
3484
- );
3485
- console.warn(
3486
- `For explicit control, call parse(process.argv.slice(2)) instead.`
3487
- );
3488
- }
3489
3950
  } else {
3490
3951
  throw new Error(
3491
3952
  "parse() called without arguments in non-Node.js environment. Please provide arguments explicitly: parse(['--flag', 'value'])"
@@ -3510,7 +3971,7 @@ const _ArgParserBase = class _ArgParserBase {
3510
3971
  commandChain: identifiedCommandChain,
3511
3972
  parserChain: identifiedParserChain
3512
3973
  } = __privateMethod(this, _ArgParserBase_instances, _identifyCommandChainAndParsers_fn).call(this, processArgs, this, [], [this]);
3513
- const saveToEnvResult = __privateMethod(_b = identifiedFinalParser, _ArgParserBase_instances, _handleSaveToEnvFlag_fn).call(_b, processArgs, identifiedParserChain);
3974
+ const saveToEnvResult = __privateMethod(_a = identifiedFinalParser, _ArgParserBase_instances, _handleSaveToEnvFlag_fn).call(_a, processArgs, identifiedParserChain);
3514
3975
  if (saveToEnvResult !== false) {
3515
3976
  return saveToEnvResult === true ? {} : saveToEnvResult;
3516
3977
  }
@@ -4829,7 +5290,10 @@ _startUnifiedMcpServer_fn = async function(mcpServerConfig, transportOptions) {
4829
5290
  const finalTransportOptions = {
4830
5291
  port: transportOptions.port,
4831
5292
  host: transportOptions.host || "localhost",
4832
- path: transportOptions.path || "/mcp"
5293
+ path: transportOptions.path || "/mcp",
5294
+ // Pass-through for streamable-http only; harmlessly ignored for others
5295
+ cors: transportOptions.cors,
5296
+ auth: transportOptions.auth
4833
5297
  };
4834
5298
  await mcpParser.startMcpServerWithTransport(
4835
5299
  serverInfo,
@@ -4937,6 +5401,27 @@ _parseMcpTransportOptions_fn = function(processArgs) {
4937
5401
  i++;
4938
5402
  }
4939
5403
  break;
5404
+ // Streamable HTTP extras (accept JSON string)
5405
+ case "--s-mcp-cors":
5406
+ if (nextArg && !nextArg.startsWith("-")) {
5407
+ try {
5408
+ options.cors = JSON.parse(nextArg);
5409
+ } catch {
5410
+ options.cors = nextArg;
5411
+ }
5412
+ i++;
5413
+ }
5414
+ break;
5415
+ case "--s-mcp-auth":
5416
+ if (nextArg && !nextArg.startsWith("-")) {
5417
+ try {
5418
+ options.auth = JSON.parse(nextArg);
5419
+ } catch {
5420
+ options.auth = nextArg;
5421
+ }
5422
+ i++;
5423
+ }
5424
+ break;
4940
5425
  // Backward compatibility: support old flags but with deprecation warning
4941
5426
  case "--transport":
4942
5427
  case "--port":
@@ -6974,6 +7459,34 @@ Migration guide: https://github.com/alcyone-labs/arg-parser/blob/main/docs/MCP-M
6974
7459
  parseAsync(processArgs, options) {
6975
7460
  return this.parse(processArgs, options);
6976
7461
  }
7462
+ /**
7463
+ * Convenience method for auto-execution: only runs if the script is executed directly (not imported).
7464
+ * This eliminates the need for boilerplate code to check if the script is being run directly.
7465
+ *
7466
+ * @param importMetaUrl Pass import.meta.url from your script for reliable detection
7467
+ * @param processArgs Optional arguments to parse (defaults to process.argv.slice(2))
7468
+ * @param options Additional parse options
7469
+ * @returns Promise that resolves to the parse result, or empty object if script is imported
7470
+ *
7471
+ * @example
7472
+ * ```typescript
7473
+ * // At the bottom of your CLI script:
7474
+ * await cli.parseIfExecutedDirectly(import.meta.url);
7475
+ *
7476
+ * // With error handling:
7477
+ * await cli.parseIfExecutedDirectly(import.meta.url).catch((error) => {
7478
+ * console.error("Fatal error:", error instanceof Error ? error.message : String(error));
7479
+ * process.exit(1);
7480
+ * });
7481
+ * ```
7482
+ */
7483
+ async parseIfExecutedDirectly(importMetaUrl, processArgs, options) {
7484
+ return this.parse(processArgs, {
7485
+ ...options,
7486
+ autoExecute: true,
7487
+ importMetaUrl
7488
+ });
7489
+ }
6977
7490
  addMcpSubCommand(subCommandName = "mcp-server", serverInfo, optionsOrToolOptions) {
6978
7491
  console.warn(`[DEPRECATED] addMcpSubCommand() is deprecated and will be removed in v2.0.
6979
7492
  Please use withMcp() to configure server metadata and the --s-mcp-serve system flag instead.
@@ -7252,6 +7765,7 @@ registerToolAsSubCommand_fn = function(toolConfig) {
7252
7765
  });
7253
7766
  };
7254
7767
  _startSingleTransport_fn = async function(server, serverInfo, transportConfig, logPath) {
7768
+ var _a, _b, _c, _d, _e, _f;
7255
7769
  const resolvedLogPath = resolveLogPath(logPath || "./logs/mcp.log");
7256
7770
  const logger2 = createMcpLogger("MCP Transport", resolvedLogPath);
7257
7771
  try {
@@ -7295,10 +7809,142 @@ _startSingleTransport_fn = async function(server, serverInfo, transportConfig, l
7295
7809
  const express = (await import("express")).default;
7296
7810
  const app = express();
7297
7811
  app.use(express.json());
7812
+ try {
7813
+ (_c = (_b = (_a = this._mcpServerConfig) == null ? void 0 : _a.httpServer) == null ? void 0 : _b.configureExpress) == null ? void 0 : _c.call(_b, app);
7814
+ } catch (e) {
7815
+ }
7298
7816
  const port = transportConfig.port || 3e3;
7299
7817
  const path2 = transportConfig.path || "/mcp";
7818
+ if (transportConfig.cors) {
7819
+ const cors = transportConfig.cors;
7820
+ const allowMethods = ((_d = cors.methods) == null ? void 0 : _d.join(", ")) || "GET,POST,PUT,PATCH,DELETE,OPTIONS";
7821
+ const allowHeaders = (req) => {
7822
+ var _a2;
7823
+ return ((_a2 = cors.headers) == null ? void 0 : _a2.join(", ")) || req.headers["access-control-request-headers"] || "Content-Type, Authorization, MCP-Session-Id";
7824
+ };
7825
+ const exposed = ((_e = cors.exposedHeaders) == null ? void 0 : _e.join(", ")) || void 0;
7826
+ const resolveOrigin = (req) => {
7827
+ const reqOrigin = req.headers.origin;
7828
+ const origins = cors.origins ?? "*";
7829
+ if (origins === "*") return cors.credentials ? reqOrigin : "*";
7830
+ if (!reqOrigin) return void 0;
7831
+ const list = Array.isArray(origins) ? origins : [origins];
7832
+ for (const o of list) {
7833
+ if (typeof o === "string" && o === reqOrigin) return reqOrigin;
7834
+ if (o instanceof RegExp && o.test(reqOrigin)) return reqOrigin;
7835
+ }
7836
+ return void 0;
7837
+ };
7838
+ const applyCorsHeaders = (req, res) => {
7839
+ const origin = resolveOrigin(req);
7840
+ if (origin) res.setHeader("Access-Control-Allow-Origin", origin);
7841
+ if (cors.credentials) res.setHeader("Access-Control-Allow-Credentials", "true");
7842
+ res.setHeader("Vary", "Origin");
7843
+ res.setHeader("Access-Control-Allow-Methods", allowMethods);
7844
+ const hdrs = allowHeaders(req);
7845
+ if (hdrs) res.setHeader("Access-Control-Allow-Headers", hdrs);
7846
+ if (exposed) res.setHeader("Access-Control-Expose-Headers", exposed);
7847
+ if (typeof cors.maxAge === "number") res.setHeader("Access-Control-Max-Age", String(cors.maxAge));
7848
+ };
7849
+ app.options(path2, (req, res) => {
7850
+ applyCorsHeaders(req, res);
7851
+ res.status(204).end();
7852
+ });
7853
+ app.use((req, res, next) => {
7854
+ if (req.path === path2) applyCorsHeaders(req, res);
7855
+ next();
7856
+ });
7857
+ }
7858
+ if ((_f = transportConfig.auth) == null ? void 0 : _f.customMiddleware) {
7859
+ app.use(transportConfig.auth.customMiddleware);
7860
+ }
7861
+ const authOpts = transportConfig.auth;
7862
+ const shouldRequireAuthFor = (req) => {
7863
+ if (!authOpts) return false;
7864
+ const reqPath = req.path;
7865
+ const pub = authOpts.publicPaths || [];
7866
+ const prot = authOpts.protectedPaths;
7867
+ if (pub.includes(reqPath)) return false;
7868
+ if (prot && !prot.includes(reqPath)) return false;
7869
+ return authOpts.required !== false;
7870
+ };
7871
+ const base64urlDecode = (s) => Buffer.from(s.replace(/-/g, "+").replace(/_/g, "/"), "base64");
7872
+ const verifyJwt = async (token) => {
7873
+ if (!(authOpts == null ? void 0 : authOpts.jwt)) return false;
7874
+ const [h, p, sig] = token.split(".");
7875
+ if (!h || !p || !sig) return false;
7876
+ const header = JSON.parse(base64urlDecode(h).toString("utf8"));
7877
+ const payload = JSON.parse(base64urlDecode(p).toString("utf8"));
7878
+ const alg = header.alg;
7879
+ if (authOpts.jwt.algorithms && !authOpts.jwt.algorithms.includes(alg)) return false;
7880
+ const data2 = Buffer.from(`${h}.${p}`);
7881
+ const signature = base64urlDecode(sig);
7882
+ if (alg === "HS256") {
7883
+ const secret = authOpts.jwt.secret;
7884
+ if (!secret) return false;
7885
+ const hmac = (await import("node:crypto")).createHmac("sha256", secret).update(data2).digest();
7886
+ if (!hmac.equals(signature)) return false;
7887
+ } else if (alg === "RS256") {
7888
+ const crypto = await import("node:crypto");
7889
+ let key = authOpts.jwt.publicKey;
7890
+ if (!key && authOpts.jwt.getPublicKey) {
7891
+ key = await authOpts.jwt.getPublicKey(header, payload);
7892
+ }
7893
+ if (!key) return false;
7894
+ const verify = crypto.createVerify("RSA-SHA256");
7895
+ verify.update(data2);
7896
+ verify.end();
7897
+ const ok = verify.verify(key, signature);
7898
+ if (!ok) return false;
7899
+ } else {
7900
+ return false;
7901
+ }
7902
+ if (authOpts.jwt.audience) {
7903
+ const allowed = Array.isArray(authOpts.jwt.audience) ? authOpts.jwt.audience : [authOpts.jwt.audience];
7904
+ if (!allowed.includes(payload.aud)) return false;
7905
+ }
7906
+ if (authOpts.jwt.issuer) {
7907
+ const allowed = Array.isArray(authOpts.jwt.issuer) ? authOpts.jwt.issuer : [authOpts.jwt.issuer];
7908
+ if (!allowed.includes(payload.iss)) return false;
7909
+ }
7910
+ const nowSec = Math.floor(Date.now() / 1e3);
7911
+ const tol = authOpts.jwt.clockToleranceSec || 0;
7912
+ if (payload.nbf && nowSec + tol < payload.nbf) return false;
7913
+ if (payload.exp && nowSec - tol >= payload.exp) return false;
7914
+ return true;
7915
+ };
7916
+ const authenticate = async (req) => {
7917
+ if (!authOpts) return true;
7918
+ const authz = req.headers.authorization;
7919
+ const token = (authz == null ? void 0 : authz.startsWith("Bearer ")) ? authz.slice(7) : void 0;
7920
+ if (!token) {
7921
+ if (authOpts.validator) return !!await authOpts.validator(req, token);
7922
+ return false;
7923
+ }
7924
+ if (authOpts.scheme === "jwt" || authOpts.jwt) {
7925
+ const ok = await verifyJwt(token);
7926
+ if (!ok) return false;
7927
+ } else if (authOpts.scheme === "bearer" || !authOpts.scheme) {
7928
+ if (authOpts.allowedTokens && !authOpts.allowedTokens.includes(token)) {
7929
+ if (authOpts.validator) return !!await authOpts.validator(req, token);
7930
+ return false;
7931
+ }
7932
+ }
7933
+ if (authOpts.validator) {
7934
+ const ok = await authOpts.validator(req, token);
7935
+ if (!ok) return false;
7936
+ }
7937
+ return true;
7938
+ };
7300
7939
  const transports = {};
7301
7940
  app.all(path2, async (req, res) => {
7941
+ if (shouldRequireAuthFor(req)) {
7942
+ const ok = await authenticate(req);
7943
+ if (!ok) {
7944
+ res.status(401).json({ error: "Unauthorized" });
7945
+ return;
7946
+ }
7947
+ }
7302
7948
  const sessionId = req.headers["mcp-session-id"];
7303
7949
  let transport;
7304
7950
  if (sessionId && transports[sessionId]) {
@@ -7311,9 +7957,7 @@ _startSingleTransport_fn = async function(server, serverInfo, transportConfig, l
7311
7957
  }
7312
7958
  });
7313
7959
  transport.onclose = () => {
7314
- if (transport.sessionId) {
7315
- delete transports[transport.sessionId];
7316
- }
7960
+ if (transport.sessionId) delete transports[transport.sessionId];
7317
7961
  };
7318
7962
  await server.connect(transport);
7319
7963
  }
@@ -24974,6 +25618,7 @@ export {
24974
25618
  ArgParserMcp,
24975
25619
  ConfigPlugin,
24976
25620
  ConfigPluginRegistry,
25621
+ DxtPathResolver,
24977
25622
  EnvConfigPlugin,
24978
25623
  JsonConfigPlugin,
24979
25624
  Logger,
@@ -25012,6 +25657,7 @@ export {
25012
25657
  logger,
25013
25658
  resolveLogPath,
25014
25659
  sanitizeMcpToolName,
25660
+ zodDxtOptionsSchema,
25015
25661
  zodFlagSchema
25016
25662
  };
25017
25663
  //# sourceMappingURL=index.mjs.map