codexport 0.1.6 → 0.1.8
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.js +77 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { homedir, platform } from "node:os";
|
|
|
11
11
|
import path from "node:path";
|
|
12
12
|
import { spawn } from "node:child_process";
|
|
13
13
|
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
14
|
-
const VERSION = "0.1.
|
|
14
|
+
const VERSION = "0.1.8";
|
|
15
15
|
const DEFAULT_PORT = 17342;
|
|
16
16
|
const DEFAULT_TIMEOUT_MS = 5_000;
|
|
17
17
|
const CODEXPORT_DIR = ".codexport";
|
|
@@ -415,19 +415,21 @@ function rewritePortableTableKeys(table, sourceRoot, sourceHome) {
|
|
|
415
415
|
function rewritePortableMcpServer(_name, server, sourceRoot, sourceHome) {
|
|
416
416
|
if (typeof server.url === "string")
|
|
417
417
|
return;
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
418
|
+
const command = typeof server.command === "string" ? server.command : undefined;
|
|
419
|
+
const args = Array.isArray(server.args) ? server.args : [];
|
|
420
|
+
const launcher = command && mcpHasRequiredPortableEnv(_name, command, server) ? portableMcpLauncher(_name, command, args, sourceHome) : undefined;
|
|
421
|
+
if (launcher) {
|
|
422
|
+
server.command = launcher.command;
|
|
423
|
+
server.args = launcher.args.map((arg) => rewritePortablePath(arg, sourceRoot, sourceHome));
|
|
424
|
+
}
|
|
425
|
+
else if (command && isAbsoluteAnyPlatform(command)) {
|
|
426
|
+
server.enabled = false;
|
|
425
427
|
}
|
|
426
|
-
if (
|
|
427
|
-
server.command = rewritePortableCommand(
|
|
428
|
+
else if (command) {
|
|
429
|
+
server.command = rewritePortableCommand(command, sourceRoot);
|
|
428
430
|
}
|
|
429
|
-
if (
|
|
430
|
-
server.args =
|
|
431
|
+
if (!launcher && args.length) {
|
|
432
|
+
server.args = args.map((arg) => typeof arg === "string" ? rewritePortablePath(arg, sourceRoot, sourceHome) : arg);
|
|
431
433
|
}
|
|
432
434
|
if (server.env && typeof server.env === "object" && !Array.isArray(server.env)) {
|
|
433
435
|
for (const [key, value] of Object.entries(server.env)) {
|
|
@@ -436,6 +438,50 @@ function rewritePortableMcpServer(_name, server, sourceRoot, sourceHome) {
|
|
|
436
438
|
}
|
|
437
439
|
}
|
|
438
440
|
}
|
|
441
|
+
if (typeof server.command === "string" && !server.url) {
|
|
442
|
+
ensurePortablePathEnv(server);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
function portableMcpLauncher(name, command, args, sourceHome) {
|
|
446
|
+
const commandName = basenameAnyPlatform(command);
|
|
447
|
+
if (commandName === "npx" || commandName === "bunx" || commandName === "uvx") {
|
|
448
|
+
return allStrings(args) ? { command: commandName, args: args } : undefined;
|
|
449
|
+
}
|
|
450
|
+
const nodePackage = nodePackageFromServer(command, args) ?? workspacePackageFromServer(command, args, sourceHome);
|
|
451
|
+
if (nodePackage) {
|
|
452
|
+
return { command: "npx", args: ["-y", nodePackage.packageName, ...nodePackage.remainingArgs] };
|
|
453
|
+
}
|
|
454
|
+
const npmPackage = npmPackageForPortableMcp(name, commandName);
|
|
455
|
+
if (npmPackage) {
|
|
456
|
+
const remainingArgs = allStrings(args) ? args : [];
|
|
457
|
+
return { command: "npx", args: ["-y", npmPackage, ...remainingArgs] };
|
|
458
|
+
}
|
|
459
|
+
return undefined;
|
|
460
|
+
}
|
|
461
|
+
function mcpHasRequiredPortableEnv(name, command, server) {
|
|
462
|
+
if (name !== "kagi-mcp" && basenameAnyPlatform(command) !== "kagi-mcp")
|
|
463
|
+
return true;
|
|
464
|
+
const env = server.env && typeof server.env === "object" && !Array.isArray(server.env) ? server.env : undefined;
|
|
465
|
+
return typeof env?.KAGI_API_KEY === "string" && env.KAGI_API_KEY.length > 0;
|
|
466
|
+
}
|
|
467
|
+
function ensurePortablePathEnv(server) {
|
|
468
|
+
const env = server.env && typeof server.env === "object" && !Array.isArray(server.env) ? server.env : {};
|
|
469
|
+
const existingPath = typeof env.PATH === "string" ? env.PATH : undefined;
|
|
470
|
+
const portableBins = ["${home}/.bun/bin", "${home}/.local/bin", "${home}/.cargo/bin", "${home}/go/bin"];
|
|
471
|
+
env.PATH = [...portableBins, existingPath ?? process.env.PATH ?? ""].filter(Boolean).join(path.delimiter);
|
|
472
|
+
server.env = env;
|
|
473
|
+
}
|
|
474
|
+
function npmPackageForPortableMcp(name, commandName) {
|
|
475
|
+
const knownPackages = {
|
|
476
|
+
"dora": "@butttons/dora",
|
|
477
|
+
"kagi-mcp": "kagi-mcp",
|
|
478
|
+
"opensrc-mcp": "opensrc-mcp",
|
|
479
|
+
"opensrc-mcp-stdio": "opensrc-mcp",
|
|
480
|
+
"perplexity-webui": "perplexity-webui-mcp",
|
|
481
|
+
"perplexity-webui-mcp": "perplexity-webui-mcp",
|
|
482
|
+
"reddit-mcp-buddy": "reddit-mcp-buddy"
|
|
483
|
+
};
|
|
484
|
+
return knownPackages[name] ?? knownPackages[commandName];
|
|
439
485
|
}
|
|
440
486
|
function rewritePortableCommand(command, sourceRoot) {
|
|
441
487
|
const sourceRelative = rewriteSourceRootPath(command, sourceRoot);
|
|
@@ -457,13 +503,31 @@ function nodePackageFromServer(command, args) {
|
|
|
457
503
|
const [entrypoint, ...remainingArgs] = args;
|
|
458
504
|
if (typeof entrypoint !== "string" || !isAbsoluteAnyPlatform(entrypoint))
|
|
459
505
|
return undefined;
|
|
460
|
-
if (!remainingArgs
|
|
506
|
+
if (!allStrings(remainingArgs))
|
|
461
507
|
return undefined;
|
|
462
508
|
const packageName = packageNameFromNodeModulesPath(entrypoint);
|
|
463
509
|
if (!packageName)
|
|
464
510
|
return undefined;
|
|
465
511
|
return { packageName, remainingArgs: remainingArgs };
|
|
466
512
|
}
|
|
513
|
+
function workspacePackageFromServer(command, args, sourceHome) {
|
|
514
|
+
if (basenameAnyPlatform(command) !== "node")
|
|
515
|
+
return undefined;
|
|
516
|
+
const [entrypoint, ...remainingArgs] = args;
|
|
517
|
+
if (!sourceHome || typeof entrypoint !== "string" || !isAbsoluteAnyPlatform(entrypoint) || !allStrings(remainingArgs))
|
|
518
|
+
return undefined;
|
|
519
|
+
const normalizedEntry = normalizePathForCompare(entrypoint);
|
|
520
|
+
const workspacePrefix = `${normalizePathForCompare(sourceHome)}/workspace/`;
|
|
521
|
+
if (!normalizedEntry.startsWith(workspacePrefix))
|
|
522
|
+
return undefined;
|
|
523
|
+
const packageName = normalizedEntry.slice(workspacePrefix.length).split("/")[0];
|
|
524
|
+
if (!packageName)
|
|
525
|
+
return undefined;
|
|
526
|
+
return { packageName, remainingArgs: remainingArgs };
|
|
527
|
+
}
|
|
528
|
+
function allStrings(values) {
|
|
529
|
+
return values.every((value) => typeof value === "string");
|
|
530
|
+
}
|
|
467
531
|
function packageNameFromNodeModulesPath(value) {
|
|
468
532
|
const parts = normalizePathForCompare(value).split("/");
|
|
469
533
|
const nodeModulesIndex = parts.lastIndexOf("node_modules");
|