xmux-bridge 1.0.41 → 1.2.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 +4 -3
- package/mcp/setup/claude.js +38 -14
- package/mcp/setup/codex.js +94 -0
- package/mcp/setup/copilot.js +9 -1
- package/mcp/setup/gemini.js +5 -2
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -151,9 +151,10 @@ shortcuts for orchestrating that runtime. The MCP command is install-scoped and
|
|
|
151
151
|
does not pin `XMUX_PROJECT_DIR`/`XMUX_STATE_DIR`; those values come from the
|
|
152
152
|
active `xmux -n <session>` lead runtime.
|
|
153
153
|
|
|
154
|
-
Provider teammates write responses through `
|
|
155
|
-
team runtime environment prepared by XMux.
|
|
156
|
-
implementation details behind Codex-led teammate
|
|
154
|
+
Provider teammates write responses through the versioned npm `xmux-bridge`
|
|
155
|
+
entrypoint, using the team runtime environment prepared by XMux. MCP and
|
|
156
|
+
mailbox paths are implementation details behind Codex-led teammate
|
|
157
|
+
orchestration.
|
|
157
158
|
|
|
158
159
|
Users can ask for teammate work in natural language. When XMux skills are
|
|
159
160
|
available in Codex, the official skill shortcuts are:
|
package/mcp/setup/claude.js
CHANGED
|
@@ -6,6 +6,8 @@ const os = require("node:os");
|
|
|
6
6
|
const path = require("node:path");
|
|
7
7
|
|
|
8
8
|
const SERVER_NAME = "xmux_bridge";
|
|
9
|
+
const DEFAULT_NPM_PACKAGE = "xmux-bridge";
|
|
10
|
+
const DEFAULT_NPX_PREFIX = path.join(os.homedir(), ".cache", "xmux", "npm-prefix");
|
|
9
11
|
const LEGACY_NAMES = new Set([
|
|
10
12
|
"xmux_bridge",
|
|
11
13
|
"xmux-bridge",
|
|
@@ -73,7 +75,7 @@ function atomicWriteJson(filePath, data) {
|
|
|
73
75
|
|
|
74
76
|
function usage() {
|
|
75
77
|
process.stderr.write(
|
|
76
|
-
"usage: claude.js <bridge_js> <project_dir> <outbox> <agent> <team> <state_dir> <install_dir>\n",
|
|
78
|
+
"usage: claude.js <bridge_js|npx> <project_dir> <outbox> <agent> <team> <state_dir> <install_dir>\n",
|
|
77
79
|
);
|
|
78
80
|
}
|
|
79
81
|
|
|
@@ -83,7 +85,8 @@ function main(argv = process.argv.slice(2)) {
|
|
|
83
85
|
return 2;
|
|
84
86
|
}
|
|
85
87
|
|
|
86
|
-
const
|
|
88
|
+
const bridgeRef = argv[0];
|
|
89
|
+
const bridgeJs = bridgeRef === "npx" ? "" : stableHomebrewXmuxFilePath(bridgeRef);
|
|
87
90
|
const projectDir = absolute(argv[1]);
|
|
88
91
|
const outbox = absolute(argv[2]);
|
|
89
92
|
const agent = argv[3];
|
|
@@ -116,20 +119,41 @@ function main(argv = process.argv.slice(2)) {
|
|
|
116
119
|
delete servers[legacyName];
|
|
117
120
|
}
|
|
118
121
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
XMUX_OUTBOX: outbox,
|
|
127
|
-
XMUX_PROJECT_DIR: projectDir,
|
|
128
|
-
XMUX_STATE_DIR: stateDir,
|
|
129
|
-
XMUX_TEAM: team,
|
|
130
|
-
},
|
|
122
|
+
const commonEnv = {
|
|
123
|
+
XMUX_AGENT: agent,
|
|
124
|
+
XMUX_INSTALL_DIR: installDir,
|
|
125
|
+
XMUX_OUTBOX: outbox,
|
|
126
|
+
XMUX_PROJECT_DIR: projectDir,
|
|
127
|
+
XMUX_STATE_DIR: stateDir,
|
|
128
|
+
XMUX_TEAM: team,
|
|
131
129
|
};
|
|
132
130
|
|
|
131
|
+
if (bridgeRef === "npx") {
|
|
132
|
+
const packageSpec = process.env.XMUX_MCP_PACKAGE_SPEC || DEFAULT_NPM_PACKAGE;
|
|
133
|
+
const npxPrefix = process.env.XMUX_MCP_NPX_PREFIX || DEFAULT_NPX_PREFIX;
|
|
134
|
+
servers[SERVER_NAME] = {
|
|
135
|
+
type: "stdio",
|
|
136
|
+
command: "npx",
|
|
137
|
+
args: [
|
|
138
|
+
"--prefix", npxPrefix,
|
|
139
|
+
"-y",
|
|
140
|
+
"-p", packageSpec,
|
|
141
|
+
"xmux-bridge",
|
|
142
|
+
"--outbox", outbox,
|
|
143
|
+
"--agent", agent,
|
|
144
|
+
"--team", team,
|
|
145
|
+
],
|
|
146
|
+
env: commonEnv,
|
|
147
|
+
};
|
|
148
|
+
} else {
|
|
149
|
+
servers[SERVER_NAME] = {
|
|
150
|
+
type: "stdio",
|
|
151
|
+
command: "node",
|
|
152
|
+
args: [bridgeJs, "--outbox", outbox, "--agent", agent, "--team", team],
|
|
153
|
+
env: commonEnv,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
133
157
|
atomicWriteJson(configPath, config);
|
|
134
158
|
return 0;
|
|
135
159
|
}
|
package/mcp/setup/codex.js
CHANGED
|
@@ -151,6 +151,20 @@ function package_spec_has_version(packageSpec) {
|
|
|
151
151
|
return text.includes("@");
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
function package_name_from_spec(packageSpec) {
|
|
155
|
+
const text = String(packageSpec || "");
|
|
156
|
+
if (text.startsWith("@")) {
|
|
157
|
+
const slash = text.indexOf("/");
|
|
158
|
+
if (slash < 0) return text;
|
|
159
|
+
const scope = text.slice(0, slash);
|
|
160
|
+
const rest = text.slice(slash + 1);
|
|
161
|
+
const versionIndex = rest.indexOf("@");
|
|
162
|
+
return `${scope}/${versionIndex < 0 ? rest : rest.slice(0, versionIndex)}`;
|
|
163
|
+
}
|
|
164
|
+
const versionIndex = text.indexOf("@");
|
|
165
|
+
return versionIndex < 0 ? text : text.slice(0, versionIndex);
|
|
166
|
+
}
|
|
167
|
+
|
|
154
168
|
function xmux_version_from_install_dir(xmuxInstallDir) {
|
|
155
169
|
const root = abs(xmuxInstallDir);
|
|
156
170
|
const content = read_text(xmux_runtime_shell_path(root)) || read_text(path.join(root, "xmux.zsh"));
|
|
@@ -246,6 +260,70 @@ function ensure_mcp_runtime_dirs(mcpConfig) {
|
|
|
246
260
|
}
|
|
247
261
|
}
|
|
248
262
|
|
|
263
|
+
function cached_package_root(mcpConfig) {
|
|
264
|
+
if (!mcpConfig || !mcpConfig.npx_prefix || !mcpConfig.package_spec) return "";
|
|
265
|
+
return path.join(abs(mcpConfig.npx_prefix), "node_modules", package_name_from_spec(mcpConfig.package_spec));
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function cached_mailbox_candidates(mcpConfig) {
|
|
269
|
+
const prefix = mcpConfig && mcpConfig.npx_prefix ? abs(mcpConfig.npx_prefix) : "";
|
|
270
|
+
const root = cached_package_root(mcpConfig);
|
|
271
|
+
return [
|
|
272
|
+
prefix ? path.join(prefix, "node_modules", ".bin", "xmux-mailbox") : "",
|
|
273
|
+
root ? path.join(root, "dist", "bin", "xmux-mailbox.js") : "",
|
|
274
|
+
].filter(Boolean);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function mailbox_source(xmuxInstallDir, mcpConfig) {
|
|
278
|
+
const explicit = process.env.XMUX_MAILBOX_NODE_CLI ? abs(process.env.XMUX_MAILBOX_NODE_CLI) : "";
|
|
279
|
+
if (explicit && fs.existsSync(explicit)) return { ok: true, kind: "env", label: explicit };
|
|
280
|
+
|
|
281
|
+
for (const candidate of cached_mailbox_candidates(mcpConfig)) {
|
|
282
|
+
if (fs.existsSync(candidate)) return { ok: true, kind: "npm-cache", label: candidate };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const bundled = path.join(abs(xmuxInstallDir), "dist", "bin", "xmux-mailbox.js");
|
|
286
|
+
if (fs.existsSync(bundled)) return { ok: true, kind: "brew-bundled", label: bundled };
|
|
287
|
+
|
|
288
|
+
const npx = spawnSync("npx", ["--version"], { encoding: "utf8" });
|
|
289
|
+
if (npx.status === 0 && mcpConfig && mcpConfig.mode === "npx" && mcpConfig.package_spec) {
|
|
290
|
+
return { ok: true, kind: "npx", label: `${mcpConfig.package_spec} via ${mcpConfig.npx_prefix}` };
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return { ok: false, kind: "missing", label: "no mailbox CLI source found" };
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function ensure_mcp_package_cache(mcpConfig, enabled = true) {
|
|
297
|
+
if (!enabled || !mcpConfig || mcpConfig.mode !== "npx") {
|
|
298
|
+
return { status: "skipped", message: "disabled" };
|
|
299
|
+
}
|
|
300
|
+
if (!mcpConfig.npx_prefix || !mcpConfig.package_spec) {
|
|
301
|
+
return { status: "skipped", message: "missing npx package metadata" };
|
|
302
|
+
}
|
|
303
|
+
ensure_mcp_runtime_dirs(mcpConfig);
|
|
304
|
+
|
|
305
|
+
const root = cached_package_root(mcpConfig);
|
|
306
|
+
if (root && fs.existsSync(root)) {
|
|
307
|
+
return { status: "ok", message: `using existing cache at ${root}` };
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const npm = spawnSync("npm", [
|
|
311
|
+
"install",
|
|
312
|
+
"--prefix",
|
|
313
|
+
abs(mcpConfig.npx_prefix),
|
|
314
|
+
"--no-save",
|
|
315
|
+
"--omit=dev",
|
|
316
|
+
mcpConfig.package_spec,
|
|
317
|
+
], { encoding: "utf8" });
|
|
318
|
+
|
|
319
|
+
if (npm.status === 0) {
|
|
320
|
+
return { status: "ok", message: `installed ${mcpConfig.package_spec} under ${mcpConfig.npx_prefix}` };
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const detail = (npm.stderr || npm.stdout || "").trim().split(/\r?\n/).slice(-2).join(" ");
|
|
324
|
+
return { status: "failed", message: detail || `npm install exited with ${npm.status}` };
|
|
325
|
+
}
|
|
326
|
+
|
|
249
327
|
function build_block(mcpConfigOrServerPath, xmuxInstallDir) {
|
|
250
328
|
const mcpConfig = normalize_mcp_config(mcpConfigOrServerPath, xmuxInstallDir);
|
|
251
329
|
const pathEnv = resolve_path_with_node();
|
|
@@ -659,6 +737,10 @@ function doctor_codex(configPath, xmuxInstallDir, mcpConfigOrServerPath, skillsD
|
|
|
659
737
|
notes.push(["OK", "legacy XMux plugin cache is absent"]);
|
|
660
738
|
}
|
|
661
739
|
|
|
740
|
+
const mailbox = mailbox_source(xmuxInstallDir, mcpConfig);
|
|
741
|
+
if (mailbox.ok) notes.push(["OK", `mailbox source: ${mailbox.kind} (${mailbox.label})`]);
|
|
742
|
+
else issues.push(`mailbox source is unavailable: ${mailbox.label}`);
|
|
743
|
+
|
|
662
744
|
const staleProcesses = stale_xmux_lead_mcp_processes(mcpConfig);
|
|
663
745
|
for (const proc of staleProcesses.slice(0, 5)) {
|
|
664
746
|
notes.push([
|
|
@@ -700,6 +782,7 @@ function parse_args(argv) {
|
|
|
700
782
|
mcp_version: "",
|
|
701
783
|
mcp_bin: DEFAULT_MCP_BIN,
|
|
702
784
|
mcp_npx_prefix: "",
|
|
785
|
+
cache_mcp: true,
|
|
703
786
|
};
|
|
704
787
|
for (let i = 0; i < argv.length;) {
|
|
705
788
|
const arg = argv[i];
|
|
@@ -711,6 +794,10 @@ function parse_args(argv) {
|
|
|
711
794
|
opts.quiet = true; i += 1;
|
|
712
795
|
} else if (arg === "--without-skills") {
|
|
713
796
|
opts.install_skills = false; i += 1;
|
|
797
|
+
} else if (arg === "--cache-mcp") {
|
|
798
|
+
opts.cache_mcp = true; i += 1;
|
|
799
|
+
} else if (arg === "--no-cache-mcp") {
|
|
800
|
+
opts.cache_mcp = false; i += 1;
|
|
714
801
|
} else if ([
|
|
715
802
|
"--skills-dir",
|
|
716
803
|
"--home",
|
|
@@ -774,6 +861,10 @@ function main(argv = process.argv.slice(2)) {
|
|
|
774
861
|
}
|
|
775
862
|
|
|
776
863
|
ensure_mcp_runtime_dirs(mcpConfig);
|
|
864
|
+
const cacheResult = ensure_mcp_package_cache(mcpConfig, opts.cache_mcp);
|
|
865
|
+
if (cacheResult.status === "failed") {
|
|
866
|
+
console.error(`[WARN] XMux MCP package cache failed: ${cacheResult.message}`);
|
|
867
|
+
}
|
|
777
868
|
|
|
778
869
|
let content = remove_xmux_blocks(read_text(configPath));
|
|
779
870
|
if (opts.remove) {
|
|
@@ -805,6 +896,8 @@ function main(argv = process.argv.slice(2)) {
|
|
|
805
896
|
|
|
806
897
|
console.log(`[OK] Wrote ${SERVER_NAME} to ${configPath}`);
|
|
807
898
|
console.log(` mcp: ${mcpConfig.label}`);
|
|
899
|
+
if (cacheResult.status === "ok") console.log(` mcp_cache: ${cacheResult.message}`);
|
|
900
|
+
else if (cacheResult.status === "skipped") console.log(` mcp_cache: ${cacheResult.message}`);
|
|
808
901
|
console.log(` xmux_install_dir: ${xmuxInstallDir}`);
|
|
809
902
|
console.log(" xmux_project_dir: inherited from xmux-launched Codex runtime");
|
|
810
903
|
console.log(" xmux_state_dir: inherited from xmux-launched Codex runtime");
|
|
@@ -830,6 +923,7 @@ module.exports = {
|
|
|
830
923
|
build_block,
|
|
831
924
|
default_mcp_package_spec,
|
|
832
925
|
default_mcp_npx_prefix,
|
|
926
|
+
mailbox_source,
|
|
833
927
|
resolve_mcp_config,
|
|
834
928
|
path_with_xmux_bin,
|
|
835
929
|
ensure_codex_shell_environment,
|
package/mcp/setup/copilot.js
CHANGED
|
@@ -6,6 +6,8 @@ const os = require("node:os");
|
|
|
6
6
|
const path = require("node:path");
|
|
7
7
|
|
|
8
8
|
const SERVER_NAME = "xmux_bridge";
|
|
9
|
+
const DEFAULT_NPM_PACKAGE = "xmux-bridge";
|
|
10
|
+
const DEFAULT_NPX_PREFIX = path.join(os.homedir(), ".cache", "xmux", "npm-prefix");
|
|
9
11
|
const LEGACY_NAMES = new Set([
|
|
10
12
|
"xmux_bridge",
|
|
11
13
|
"xmux-bridge",
|
|
@@ -57,7 +59,13 @@ function main(argv = process.argv.slice(2)) {
|
|
|
57
59
|
if (cmd.startsWith("http")) {
|
|
58
60
|
servers[SERVER_NAME] = { type: "sse", url: cmd, tools: TOOLS };
|
|
59
61
|
} else if (cmd === "npx") {
|
|
60
|
-
|
|
62
|
+
const packageSpec = process.env.XMUX_MCP_PACKAGE_SPEC || DEFAULT_NPM_PACKAGE;
|
|
63
|
+
const npxPrefix = process.env.XMUX_MCP_NPX_PREFIX || DEFAULT_NPX_PREFIX;
|
|
64
|
+
servers[SERVER_NAME] = {
|
|
65
|
+
command: "npx",
|
|
66
|
+
args: ["--prefix", npxPrefix, "-y", "-p", packageSpec, "xmux-bridge"],
|
|
67
|
+
tools: TOOLS,
|
|
68
|
+
};
|
|
61
69
|
} else {
|
|
62
70
|
servers[SERVER_NAME] = {
|
|
63
71
|
command: "node",
|
package/mcp/setup/gemini.js
CHANGED
|
@@ -14,7 +14,8 @@ const LEGACY_NAMES = new Set([
|
|
|
14
14
|
"amux_bridge",
|
|
15
15
|
"amux-bridge",
|
|
16
16
|
]);
|
|
17
|
-
const
|
|
17
|
+
const DEFAULT_NPM_PACKAGE = "xmux-bridge";
|
|
18
|
+
const DEFAULT_NPX_PREFIX = path.join(os.homedir(), ".cache", "xmux", "npm-prefix");
|
|
18
19
|
|
|
19
20
|
function stableHomebrewXmuxFilePath(inputPath) {
|
|
20
21
|
const resolved = path.resolve(inputPath.replace(/^~(?=$|\/)/, os.homedir()));
|
|
@@ -55,9 +56,11 @@ function main(argv = process.argv.slice(2)) {
|
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
if (cmd === "npx") {
|
|
59
|
+
const packageSpec = process.env.XMUX_MCP_PACKAGE_SPEC || DEFAULT_NPM_PACKAGE;
|
|
60
|
+
const npxPrefix = process.env.XMUX_MCP_NPX_PREFIX || DEFAULT_NPX_PREFIX;
|
|
58
61
|
servers[SERVER_NAME] = {
|
|
59
62
|
command: "npx",
|
|
60
|
-
args: ["-y",
|
|
63
|
+
args: ["--prefix", npxPrefix, "-y", "-p", packageSpec, "xmux-bridge"],
|
|
61
64
|
trust: true,
|
|
62
65
|
};
|
|
63
66
|
} else {
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xmux-bridge",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "MCP bridge and lead server package for XMux",
|
|
5
5
|
"bin": {
|
|
6
|
-
"xmux-lead-mcp": "
|
|
7
|
-
"xmux-bridge": "
|
|
8
|
-
"xmux-mailbox": "
|
|
6
|
+
"xmux-lead-mcp": "mcp/servers/lead.js",
|
|
7
|
+
"xmux-bridge": "mcp/servers/bridge.js",
|
|
8
|
+
"xmux-mailbox": "dist/bin/xmux-mailbox.js"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"mcp/servers",
|
|
@@ -27,6 +27,6 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"repository": {
|
|
29
29
|
"type": "git",
|
|
30
|
-
"url": "https://github.com/DwvN-Lee/XMux.git"
|
|
30
|
+
"url": "git+https://github.com/DwvN-Lee/XMux.git"
|
|
31
31
|
}
|
|
32
32
|
}
|