@sleep2agi/commhub-server 0.9.0-preview.105 → 0.9.0-preview.106
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/package.json +1 -1
- package/src/create-node-validate.test.ts +36 -1
- package/src/create-node-validate.ts +27 -1
- package/src/tools.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sleep2agi/commhub-server",
|
|
3
|
-
"version": "0.9.0-preview.
|
|
3
|
+
"version": "0.9.0-preview.106",
|
|
4
4
|
"description": "CommHub Server — AI Agent communication hub with MCP protocol, multi-network isolation, user auth, and MCP tools (17 collaboration-core + node/provider ops tools; authoritative list: docs-site/docs/api/mcp-tools.md).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
ValidationError,
|
|
4
4
|
validateName, validateRuntime, validateModel, validateFlagValue, RUNTIMES,
|
|
5
5
|
validateEnvRefs, validateChannelsP1, serializeEnvLocal, buildAnetArgs,
|
|
6
|
-
MAX_ENV_KEYS_PER_NODE,
|
|
6
|
+
MAX_ENV_KEYS_PER_NODE, validateFlagsForRuntime, COPRESENCE_FLAG_RUNTIMES,
|
|
7
7
|
} from "./create-node-validate.js";
|
|
8
8
|
|
|
9
9
|
const okSecret = (k: string, _net: string, key: string) => k === key ? `value-of-${k}` : undefined;
|
|
@@ -273,3 +273,38 @@ describe("#1298 RUNTIMES —— 七个都放行,且与 CLI 侧一致", () => {
|
|
|
273
273
|
expect(() => validateRuntime("")).toThrow();
|
|
274
274
|
});
|
|
275
275
|
});
|
|
276
|
+
|
|
277
|
+
// #584 —— app「Codex(TUI 共存)」经 daemon 建出来的是无头节点:create_node 没有任何字段能表达「要共存」。
|
|
278
|
+
describe("#584 flags.copresence —— 建节点时的共存开关", () => {
|
|
279
|
+
test("is a known flag key and must be boolean", () => {
|
|
280
|
+
expect(() => validateFlagValue("copresence", true)).not.toThrow();
|
|
281
|
+
expect(() => validateFlagValue("copresence", false)).not.toThrow();
|
|
282
|
+
for (const bad of ["true", 1, null, {}]) {
|
|
283
|
+
try { validateFlagValue("copresence", bad); throw new Error("did not throw"); }
|
|
284
|
+
catch (e) { expect((e as ValidationError).code).toBe("flag_value_invalid"); }
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
test("only codex-app-server accepts it — elsewhere it would be swallowed silently", () => {
|
|
288
|
+
expect(() => validateFlagsForRuntime("codex-app-server", { copresence: true })).not.toThrow();
|
|
289
|
+
expect(() => validateFlagsForRuntime("claude-agent-sdk", { permissionMode: "default" })).not.toThrow();
|
|
290
|
+
expect(() => validateFlagsForRuntime("claude-agent-sdk", undefined)).not.toThrow();
|
|
291
|
+
for (const rt of ["claude-agent-sdk", "claude-code-cli", "codex-sdk", "grok-build-acp", "grok-build-cli", "opencode-cli"]) {
|
|
292
|
+
try { validateFlagsForRuntime(rt, { copresence: true }); throw new Error(`did not throw for ${rt}`); }
|
|
293
|
+
catch (e) {
|
|
294
|
+
expect((e as ValidationError).code).toBe("flag_not_applicable_to_runtime");
|
|
295
|
+
expect((e as ValidationError).detail).toMatchObject({ field: "copresence", runtime: rt, applicable: [...COPRESENCE_FLAG_RUNTIMES] });
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
test("buildAnetArgs emits the CLI's boolean `--copresence` (no value), and nothing for false", () => {
|
|
300
|
+
expect(buildAnetArgs({ name: "cx", runtime: "codex-app-server", flags: { copresence: true } }))
|
|
301
|
+
.toEqual(["node", "create", "cx", "--runtime", "codex-app-server", "--copresence"]);
|
|
302
|
+
expect(buildAnetArgs({ name: "cx", runtime: "codex-app-server", flags: { copresence: false } }))
|
|
303
|
+
.toEqual(["node", "create", "cx", "--runtime", "codex-app-server"]);
|
|
304
|
+
expect(() => buildAnetArgs({ name: "cx", runtime: "codex-sdk", flags: { copresence: true } })).toThrow(ValidationError);
|
|
305
|
+
});
|
|
306
|
+
test("the old request shape (no flag) is unchanged", () => {
|
|
307
|
+
expect(buildAnetArgs({ name: "cx", runtime: "codex-app-server", flags: { permissionMode: "default" } }))
|
|
308
|
+
.toEqual(["node", "create", "cx", "--runtime", "codex-app-server", "--permission-mode", "default"]);
|
|
309
|
+
});
|
|
310
|
+
});
|
|
@@ -46,7 +46,16 @@ export const RUNTIMES = [
|
|
|
46
46
|
] as const;
|
|
47
47
|
export type Runtime = typeof RUNTIMES[number];
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
// #584 —— `copresence` 是**建节点时**的开关,不是 agent 的运行参数:为 true 时 daemon 把它写成子节点
|
|
50
|
+
// config 的 `codexCopresence: true`,之后一条 `anet node start` 就起共享 TUI(app 向导的「Codex(TUI 共存)」)。
|
|
51
|
+
// 🔴 故意放在 flags 里而不是 node_spec 顶层:老 hub 的 zod 会静默丢弃未知顶层字段、老 daemon 也静默忽略
|
|
52
|
+
// —— 那正是 #584 的形状(用户选了共存,拿到无头节点,没有任何报错)。flags 的未知键在老 hub(这份
|
|
53
|
+
// FLAG_KEYS)和老 daemon(buildAnetArgsDaemon)都**拒绝**,新 app 撞到老组件得到的是一条报错。
|
|
54
|
+
export const FLAG_KEYS = ["permissionMode", "dangerouslySkipPermissions", "maxTurns", "budget", "timeout", "copresence"] as const;
|
|
55
|
+
|
|
56
|
+
/** #584 —— 只有这些 runtime 认 `flags.copresence`。目前只有 codex-app-server 的共存靠 config 字段
|
|
57
|
+
* (`codexCopresence`)决定;grok-build-cli / opencode-cli 各有自己的字段,接进来之前一律拒,不静默吞。 */
|
|
58
|
+
export const COPRESENCE_FLAG_RUNTIMES = ["codex-app-server"] as const;
|
|
50
59
|
export type FlagKey = typeof FLAG_KEYS[number];
|
|
51
60
|
|
|
52
61
|
export const PERMISSION_MODES = ["default", "acceptEdits", "plan", "bypassPermissions"] as const;
|
|
@@ -124,11 +133,25 @@ export function validateFlagValue(k: string, v: unknown): void {
|
|
|
124
133
|
throw new ValidationError("flag_value_invalid", { field: k, reason: "must be integer 1..86400" });
|
|
125
134
|
}
|
|
126
135
|
return;
|
|
136
|
+
case "copresence":
|
|
137
|
+
if (typeof v !== "boolean") throw new ValidationError("flag_value_invalid", { field: k, reason: "must be boolean" });
|
|
138
|
+
return;
|
|
127
139
|
default:
|
|
128
140
|
throw new ValidationError("flag_key_unknown", { field: k });
|
|
129
141
|
}
|
|
130
142
|
}
|
|
131
143
|
|
|
144
|
+
/** #584 —— 逐键校验之外的跨字段一条:`copresence` 只对 COPRESENCE_FLAG_RUNTIMES 有意义。
|
|
145
|
+
* 在别的 runtime 上收下它而什么都不做,就是又一个「选了共存、拿到无头」。 */
|
|
146
|
+
export function validateFlagsForRuntime(runtime: string, flags: Record<string, unknown> | undefined | null): void {
|
|
147
|
+
if (!flags || !Object.prototype.hasOwnProperty.call(flags, "copresence")) return;
|
|
148
|
+
if (!(COPRESENCE_FLAG_RUNTIMES as readonly string[]).includes(runtime)) {
|
|
149
|
+
throw new ValidationError("flag_not_applicable_to_runtime", {
|
|
150
|
+
field: "copresence", runtime, applicable: [...COPRESENCE_FLAG_RUNTIMES],
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
132
155
|
// §4.4.7 — env_refs 7-step gate. networkSecretsGet is injected so
|
|
133
156
|
// callers can supply either a real DB lookup (hub) or a fixture (tests).
|
|
134
157
|
// The 6th step also reports the resolved value size; we return the
|
|
@@ -281,8 +304,11 @@ export function buildAnetArgs(spec: NodeSpec): string[] {
|
|
|
281
304
|
throw new ValidationError("flag_key_unknown", { field: k });
|
|
282
305
|
}
|
|
283
306
|
validateFlagValue(k, v);
|
|
307
|
+
// `anet node create --copresence` 是布尔开关,不吃值。
|
|
308
|
+
if (k === "copresence") { if (v === true) args.push("--copresence"); continue; }
|
|
284
309
|
args.push(`--${kebab(k)}`, String(v));
|
|
285
310
|
}
|
|
311
|
+
validateFlagsForRuntime(spec.runtime, spec.flags);
|
|
286
312
|
}
|
|
287
313
|
return args;
|
|
288
314
|
}
|
package/src/tools.ts
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
validateEnvRefs,
|
|
31
31
|
FLAG_KEYS,
|
|
32
32
|
validateFlagValue,
|
|
33
|
+
validateFlagsForRuntime,
|
|
33
34
|
ValidationError,
|
|
34
35
|
} from "./create-node-validate.js";
|
|
35
36
|
import {
|
|
@@ -4252,6 +4253,7 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
|
|
|
4252
4253
|
if (!(FLAG_KEYS as readonly string[]).includes(k)) throw new ValidationError("flag_key_unknown", { field: k });
|
|
4253
4254
|
validateFlagValue(k, v);
|
|
4254
4255
|
}
|
|
4256
|
+
validateFlagsForRuntime(node_spec.runtime, node_spec.flags);
|
|
4255
4257
|
} catch (e) {
|
|
4256
4258
|
return validationFailReply(e);
|
|
4257
4259
|
}
|