agent-comm-hub 0.8.0 → 0.8.1

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 CHANGED
@@ -226,19 +226,28 @@ Merge into `~/.gemini/settings.json`:
226
226
 
227
227
  Auto-configured by `agent-comm-hub setup`: it discovers
228
228
  `~/.dsh/profiles/*/cordis.patch.yml` and appends the `@deepseek-ai/dsh-mcp-client`
229
- row, so DSH sessions expose the tools as `mcp__agent-hub__bridge_*` after a dsh
230
- restart. Manual equivalent (or template for other profiles):
229
+ row with **`serverName: agent-comm-hub`** (not the generic `agent-hub` key other
230
+ agents use). That name is deliberate: a DSH MCP-manager plugin that dynamically
231
+ mounts `serverName: "agent-hub"` would otherwise collide
232
+ (`serverName "agent-hub" is already in use by another mcp-client instance`) and
233
+ fail the whole profile load. DSH sessions expose the tools as
234
+ `mcp__agent-comm-hub__bridge_*` after a dsh restart. Re-running `setup` rewrites
235
+ any older `serverName: agent-hub` insert to the new key. Manual equivalent:
231
236
 
232
237
  ```yaml
233
238
  - insert:
234
239
  - id: agent-comm-hub
235
240
  name: '@deepseek-ai/dsh-mcp-client'
236
241
  config:
237
- serverName: agent-hub
242
+ serverName: agent-comm-hub
238
243
  transport: streamable-http
239
244
  url: http://127.0.0.1:18764/mcp
240
245
  ```
241
246
 
247
+ If your MCP manager already owns the hub mount entirely, undo the static insert
248
+ with `agent-comm-hub setup --remove` (or only refresh skills via
249
+ `setup --agent` for other agents) and keep the dynamic mount.
250
+
242
251
  ## Tools
243
252
 
244
253
  | Tool | Purpose |
package/agents/README.md CHANGED
@@ -30,7 +30,7 @@ Codex(TOML 追加)/ zcode(`mcp.servers`)。Claude Code 和 DSH 需手动
30
30
  | Codex | `~/.codex/config.toml` | `codex/config.toml` | `~/.codex/skills/agent-comm-hub/SKILL.md` |
31
31
  | zcode | `~/.zcode/cli/config.json` | `zcode/config.json` | `~/.zcode/skills/agent-comm-hub/SKILL.md` |
32
32
  | Claude Code | 项目根 `.mcp.json`(手动复制;**不碰 `~/.claude.json`**——含凭据且无法安全往返) | `claude-code/.mcp.json` | `~/.claude/skills/agent-comm-hub/SKILL.md` |
33
- | DeepSeek Harness (DSH) | profile `cordis.patch.yml`(手动合并) | `dsh/cordis.patch.yml`(用 `@deepseek-ai/dsh-mcp-client`,工具名为 `mcp__agent-hub__bridge_*`) | `$DSH_HOME/skills/agent-comm-hub/SKILL.md` |
33
+ | DeepSeek Harness (DSH) | profile `cordis.patch.yml`(手动合并) | `dsh/cordis.patch.yml`(`@deepseek-ai/dsh-mcp-client`,**serverName: `agent-comm-hub`**,工具名为 `mcp__agent-comm-hub__bridge_*`;刻意不用 `agent-hub`,避免与 MCP 管理器动态挂载同名冲突) | `$DSH_HOME/skills/agent-comm-hub/SKILL.md` |
34
34
 
35
35
  > 各 agent 对 streamable-http MCP 的支持随版本演进,模板里的字段以官方文档为准;
36
36
  > 不支持的版本可退化为 stdio 包装(见下)。
@@ -2,6 +2,10 @@
2
2
  - id: agent-comm-hub
3
3
  name: '@deepseek-ai/dsh-mcp-client'
4
4
  config:
5
- serverName: agent-hub
5
+ # Distinct from the generic `agent-hub` key other agents use: a DSH
6
+ # MCP-manager plugin that dynamically mounts serverName "agent-hub"
7
+ # would otherwise collide ("serverName already in use") and fail the
8
+ # whole profile load.
9
+ serverName: agent-comm-hub
6
10
  transport: streamable-http
7
11
  url: http://127.0.0.1:18764/mcp
@@ -110,12 +110,14 @@
110
110
  {
111
111
  "id": "dsh",
112
112
  "probe": [],
113
+ "serverName": "agent-comm-hub",
113
114
  "configs": [
114
115
  {
115
116
  "file": "~/.dsh/profiles/*/cordis.patch.yml",
116
117
  "section": null,
117
118
  "strategy": "dsh",
118
- "entry": null
119
+ "entry": null,
120
+ "serverName": "agent-comm-hub"
119
121
  }
120
122
  ],
121
123
  "skill": "~/.dsh/skills",
package/lib/cli.js CHANGED
@@ -2512,7 +2512,7 @@ var SQLiteStateStore = class {
2512
2512
 
2513
2513
  // src/index.ts
2514
2514
  var SERVER_NAME = "agent-comm-hub";
2515
- var SERVER_VERSION = "0.8.0";
2515
+ var SERVER_VERSION = "0.8.1";
2516
2516
  var DEFAULT_HOST = "127.0.0.1";
2517
2517
  var DEFAULT_PORT = 18764;
2518
2518
  var DEFAULT_PATH = "/mcp";
@@ -2883,6 +2883,9 @@ function validateRegistry(registry) {
2883
2883
  if (agent.skill !== null && (typeof agent.skill !== "string" || !agent.skill.startsWith("~/"))) {
2884
2884
  throw new Error(`registry: ${agent.id}: skill must be '~'-relative or null`);
2885
2885
  }
2886
+ if (agent.serverName !== void 0 && (typeof agent.serverName !== "string" || agent.serverName === "")) {
2887
+ throw new Error(`registry: ${agent.id}: serverName must be a non-empty string`);
2888
+ }
2886
2889
  if (agent.os !== void 0 && (!Array.isArray(agent.os) || agent.os.some((os2) => !["win32", "darwin", "linux"].includes(os2)))) {
2887
2890
  throw new Error(`registry: ${agent.id}: invalid os list`);
2888
2891
  }
@@ -3134,7 +3137,7 @@ async function mergeDshPatch(file, opts) {
3134
3137
  return "removed";
3135
3138
  }
3136
3139
  const ranges = hubEntryRanges();
3137
- if (ranges.length === 1 && lines.slice(ranges[0].start, ranges[0].end).some((line) => line.includes(`url: ${opts.url}`))) {
3140
+ if (ranges.length === 1 && lines.slice(ranges[0].start, ranges[0].end).some((line) => line.includes(`url: ${opts.url}`)) && lines.slice(ranges[0].start, ranges[0].end).some((line) => line.includes(`serverName: ${opts.serverName}`))) {
3138
3141
  return "unchanged";
3139
3142
  }
3140
3143
  await backup(file);
@@ -3205,9 +3208,10 @@ async function runSetup(options = {}) {
3205
3208
  }
3206
3209
  for (const agent of targetAgents) {
3207
3210
  for (const config of agent.configs) {
3211
+ const nameFor = config.serverName ?? agent.serverName ?? serverName;
3208
3212
  for (const file of expandConfigFile(config.file, home)) {
3209
3213
  try {
3210
- const status = config.strategy === "json" ? await mergeJsonServer(file, config.section, substitute(config.entry, { url, serverName }), { serverName, url, remove }) : config.strategy === "toml" ? await mergeTomlSection(file, { serverName, url, remove }) : await mergeDshPatch(file, { serverName, url, remove });
3214
+ const status = config.strategy === "json" ? await mergeJsonServer(file, config.section, substitute(config.entry, { url, serverName: nameFor }), { serverName: nameFor, url, remove }) : config.strategy === "toml" ? await mergeTomlSection(file, { serverName: nameFor, url, remove }) : await mergeDshPatch(file, { serverName: nameFor, url, remove });
3211
3215
  record(status, agent.id, file);
3212
3216
  } catch (error) {
3213
3217
  summary.errors.push(`${agent.id}: ${file} \u2014 ${error.message}`);
package/lib/index.js CHANGED
@@ -2518,7 +2518,7 @@ var SQLiteStateStore = class {
2518
2518
 
2519
2519
  // src/index.ts
2520
2520
  var SERVER_NAME = "agent-comm-hub";
2521
- var SERVER_VERSION = "0.8.0";
2521
+ var SERVER_VERSION = "0.8.1";
2522
2522
  var DEFAULT_HOST = "127.0.0.1";
2523
2523
  var DEFAULT_PORT = 18764;
2524
2524
  var DEFAULT_PATH = "/mcp";
package/lib/setup.js CHANGED
@@ -62,6 +62,9 @@ function validateRegistry(registry) {
62
62
  if (agent.skill !== null && (typeof agent.skill !== "string" || !agent.skill.startsWith("~/"))) {
63
63
  throw new Error(`registry: ${agent.id}: skill must be '~'-relative or null`);
64
64
  }
65
+ if (agent.serverName !== void 0 && (typeof agent.serverName !== "string" || agent.serverName === "")) {
66
+ throw new Error(`registry: ${agent.id}: serverName must be a non-empty string`);
67
+ }
65
68
  if (agent.os !== void 0 && (!Array.isArray(agent.os) || agent.os.some((os) => !["win32", "darwin", "linux"].includes(os)))) {
66
69
  throw new Error(`registry: ${agent.id}: invalid os list`);
67
70
  }
@@ -302,7 +305,7 @@ async function mergeDshPatch(file, opts) {
302
305
  return "removed";
303
306
  }
304
307
  const ranges = hubEntryRanges();
305
- if (ranges.length === 1 && lines.slice(ranges[0].start, ranges[0].end).some((line) => line.includes(`url: ${opts.url}`))) {
308
+ if (ranges.length === 1 && lines.slice(ranges[0].start, ranges[0].end).some((line) => line.includes(`url: ${opts.url}`)) && lines.slice(ranges[0].start, ranges[0].end).some((line) => line.includes(`serverName: ${opts.serverName}`))) {
306
309
  return "unchanged";
307
310
  }
308
311
  await backup(file);
@@ -373,9 +376,10 @@ async function runSetup(options = {}) {
373
376
  }
374
377
  for (const agent of targetAgents) {
375
378
  for (const config of agent.configs) {
379
+ const nameFor = config.serverName ?? agent.serverName ?? serverName;
376
380
  for (const file of expandConfigFile(config.file, home)) {
377
381
  try {
378
- const status = config.strategy === "json" ? await mergeJsonServer(file, config.section, substitute(config.entry, { url, serverName }), { serverName, url, remove }) : config.strategy === "toml" ? await mergeTomlSection(file, { serverName, url, remove }) : await mergeDshPatch(file, { serverName, url, remove });
382
+ const status = config.strategy === "json" ? await mergeJsonServer(file, config.section, substitute(config.entry, { url, serverName: nameFor }), { serverName: nameFor, url, remove }) : config.strategy === "toml" ? await mergeTomlSection(file, { serverName: nameFor, url, remove }) : await mergeDshPatch(file, { serverName: nameFor, url, remove });
379
383
  record(status, agent.id, file);
380
384
  } catch (error) {
381
385
  summary.errors.push(`${agent.id}: ${file} \u2014 ${error.message}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-comm-hub",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Generic multi-peer MCP hub: any MCP-capable agent (MiniMax Code, Claude Code, opencode, Codex, Gemini CLI, DSH, ...) connects to one local streamable-http endpoint and they chat, delegate tasks, and acknowledge in real time",
5
5
  "keywords": [
6
6
  "mcp",