negotium 0.14.3 → 0.14.4

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.
Files changed (43) hide show
  1. package/dist/agent-helpers.js +136 -6
  2. package/dist/agent-helpers.js.map +11 -9
  3. package/dist/background-bash.js.map +2 -2
  4. package/dist/browser-runtime.js.map +2 -2
  5. package/dist/{chunk-jgeyq0p1.js → chunk-er68mpja.js} +16 -3
  6. package/dist/{chunk-jgeyq0p1.js.map → chunk-er68mpja.js.map} +4 -4
  7. package/dist/{chunk-05a4ne6p.js → chunk-p7tprsvc.js} +1 -1
  8. package/dist/{chunk-yaq63qtw.js → chunk-zcazbmcs.js} +3 -3
  9. package/dist/{chunk-yaq63qtw.js.map → chunk-zcazbmcs.js.map} +2 -2
  10. package/dist/hosted-agent.js +22 -6
  11. package/dist/hosted-agent.js.map +6 -6
  12. package/dist/main.js +556 -389
  13. package/dist/main.js.map +14 -13
  14. package/dist/mcp-factories.js +136 -6
  15. package/dist/mcp-factories.js.map +11 -9
  16. package/dist/media.js.map +2 -2
  17. package/dist/prompts.js.map +2 -2
  18. package/dist/query-runtime.js.map +2 -2
  19. package/dist/registry.js +3 -3
  20. package/dist/rollout.js +2 -2
  21. package/dist/runtime/src/agents/codex-provider.ts +8 -2
  22. package/dist/runtime/src/application/submit-runtime-gateway-turn.ts +21 -2
  23. package/dist/runtime/src/node-host.ts +1 -0
  24. package/dist/runtime/src/platform/mcp-config.ts +38 -16
  25. package/dist/runtime/src/runtime/turn-runner.ts +13 -0
  26. package/dist/runtime/src/runtime-gateway.ts +86 -0
  27. package/dist/runtime/src/storage/topic-host-mcp-grants.ts +54 -0
  28. package/dist/runtime/src/topics/lifecycle.ts +2 -0
  29. package/dist/runtime/src/types.ts +4 -0
  30. package/dist/runtime/src/version.ts +1 -1
  31. package/dist/runtime-gateway.js +73 -1
  32. package/dist/runtime-gateway.js.map +3 -3
  33. package/dist/runtime-helpers.js.map +2 -2
  34. package/dist/storage.js.map +2 -2
  35. package/dist/types/packages/core/src/platform/mcp-config.d.ts +2 -0
  36. package/dist/types/packages/core/src/runtime/turn-runner.d.ts +3 -1
  37. package/dist/types/packages/core/src/runtime-gateway.d.ts +11 -0
  38. package/dist/types/packages/core/src/storage/topic-host-mcp-grants.d.ts +5 -0
  39. package/dist/types/packages/core/src/types.d.ts +3 -0
  40. package/dist/types/packages/core/src/version.d.ts +1 -1
  41. package/dist/vault.js.map +2 -2
  42. package/package.json +1 -1
  43. /package/dist/{chunk-05a4ne6p.js.map → chunk-p7tprsvc.js.map} +0 -0
@@ -1008,6 +1008,19 @@ function refreshForumCatalogViews() {
1008
1008
  requiredForumMcpServers.splice(0, requiredForumMcpServers.length, ...required);
1009
1009
  optionalForumMcpServers.splice(0, optionalForumMcpServers.length, ...optional);
1010
1010
  }
1011
+ function isReservedRuntimeMcpServerName(name) {
1012
+ return Object.hasOwn(MCP_CATALOG, name) || nodeMcpEntries.some((entry) => entry.key === name);
1013
+ }
1014
+ function mergeHostMcpServers(base, hostMcpServers) {
1015
+ if (!hostMcpServers)
1016
+ return base;
1017
+ for (const name of Object.keys(hostMcpServers)) {
1018
+ if (Object.hasOwn(base, name) || isReservedRuntimeMcpServerName(name)) {
1019
+ throw new Error(`host MCP server name conflicts with node catalog: ${name}`);
1020
+ }
1021
+ }
1022
+ return { ...base, ...hostMcpServers };
1023
+ }
1011
1024
  function buildNodeMcpSpecs(agent, filter) {
1012
1025
  const out = {};
1013
1026
  for (const entry of nodeMcpEntries) {
@@ -1184,7 +1197,7 @@ function getMcpServersForQuery(opts) {
1184
1197
  });
1185
1198
  }
1186
1199
  if (opts.sessionType === "manager") {
1187
- return getManagerMcpServers({
1200
+ return mergeHostMcpServers(getManagerMcpServers({
1188
1201
  userId: opts.userId || "local",
1189
1202
  session: opts.session,
1190
1203
  topicId: opts.topicId,
@@ -1199,7 +1212,7 @@ function getMcpServersForQuery(opts) {
1199
1212
  autoContinue: opts.autoContinue,
1200
1213
  visualTools: opts.visualTools,
1201
1214
  fileDeliveryTools: opts.fileDeliveryTools
1202
- });
1215
+ }), opts.hostMcpServers);
1203
1216
  }
1204
1217
  return getForumMcpServers({
1205
1218
  userId: opts.userId || "local",
@@ -3072,7 +3085,7 @@ var init_codex = __esm(async () => {
3072
3085
  });
3073
3086
 
3074
3087
  // ../../packages/core/src/version.ts
3075
- var NEGOTIUM_VERSION = "0.14.3";
3088
+ var NEGOTIUM_VERSION = "0.14.4";
3076
3089
 
3077
3090
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
3078
3091
  import { spawn as spawn2 } from "child_process";
@@ -5572,8 +5585,11 @@ function toCodexMcpServers(claudeShape) {
5572
5585
  if (typeof s.url === "string" && s.type !== "sse") {
5573
5586
  out[codexName] = withCodexMcpServerOverrides(name, {
5574
5587
  url: s.url,
5575
- ...s.http_headers && typeof s.http_headers === "object" ? { http_headers: s.http_headers } : {},
5576
- ...s.env_http_headers && typeof s.env_http_headers === "object" ? { env_http_headers: s.env_http_headers } : {}
5588
+ ...s.http_headers && typeof s.http_headers === "object" || s.headers && typeof s.headers === "object" ? {
5589
+ http_headers: s.http_headers ?? s.headers
5590
+ } : {},
5591
+ ...s.env_http_headers && typeof s.env_http_headers === "object" ? { env_http_headers: s.env_http_headers } : {},
5592
+ ...typeof s.timeout === "number" ? { tool_timeout_sec: Math.max(1, Math.ceil(s.timeout / 1000)) } : {}
5577
5593
  });
5578
5594
  }
5579
5595
  }
@@ -15349,6 +15365,108 @@ body{font-family:system-ui,-apple-system,"Segoe UI",sans-serif;background:var(--
15349
15365
  </style>`;
15350
15366
  });
15351
15367
 
15368
+ // ../../packages/core/src/runtime-gateway.ts
15369
+ function parseHostMcpServers(value) {
15370
+ if (value === undefined)
15371
+ return;
15372
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
15373
+ throw new TypeError("hostMcpServers must be an object");
15374
+ }
15375
+ const parsedEntries = [];
15376
+ for (const [name, raw] of Object.entries(value)) {
15377
+ if (!HOST_MCP_SERVER_NAME.test(name)) {
15378
+ throw new TypeError(`invalid host MCP server name: ${name}`);
15379
+ }
15380
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
15381
+ throw new TypeError(`hostMcpServers.${name} must be an object`);
15382
+ }
15383
+ const spec = raw;
15384
+ const unsupported = Object.keys(spec).find((key) => !HOST_MCP_SERVER_KEYS.has(key));
15385
+ if (unsupported) {
15386
+ throw new TypeError(`hostMcpServers.${name}.${unsupported} is not allowed`);
15387
+ }
15388
+ if (spec.type !== "sse" && spec.type !== "http") {
15389
+ throw new TypeError(`hostMcpServers.${name}.type must be sse or http`);
15390
+ }
15391
+ if (typeof spec.url !== "string") {
15392
+ throw new TypeError(`hostMcpServers.${name}.url must be a string`);
15393
+ }
15394
+ let url;
15395
+ try {
15396
+ url = new URL(spec.url);
15397
+ } catch {
15398
+ throw new TypeError(`hostMcpServers.${name}.url must be a valid URL`);
15399
+ }
15400
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
15401
+ throw new TypeError(`hostMcpServers.${name}.url must use http or https`);
15402
+ }
15403
+ let headers;
15404
+ if (spec.headers !== undefined) {
15405
+ if (!spec.headers || typeof spec.headers !== "object" || Array.isArray(spec.headers)) {
15406
+ throw new TypeError(`hostMcpServers.${name}.headers must be an object`);
15407
+ }
15408
+ const headerEntries = [];
15409
+ for (const [key, headerValue] of Object.entries(spec.headers)) {
15410
+ if (!HTTP_HEADER_NAME.test(key) || typeof headerValue !== "string") {
15411
+ throw new TypeError(`hostMcpServers.${name}.headers must contain string values`);
15412
+ }
15413
+ try {
15414
+ new Headers([[key, headerValue]]);
15415
+ } catch {
15416
+ throw new TypeError(`hostMcpServers.${name}.headers contains an invalid header`);
15417
+ }
15418
+ headerEntries.push([key, headerValue]);
15419
+ }
15420
+ headers = Object.fromEntries(headerEntries);
15421
+ }
15422
+ if (spec.timeout !== undefined && (typeof spec.timeout !== "number" || !Number.isFinite(spec.timeout) || spec.timeout <= 0)) {
15423
+ throw new TypeError(`hostMcpServers.${name}.timeout must be a positive number`);
15424
+ }
15425
+ parsedEntries.push([
15426
+ name,
15427
+ {
15428
+ type: spec.type,
15429
+ url: url.toString(),
15430
+ ...headers ? { headers } : {},
15431
+ ...spec.timeout !== undefined ? { timeout: spec.timeout } : {}
15432
+ }
15433
+ ]);
15434
+ }
15435
+ return Object.fromEntries(parsedEntries);
15436
+ }
15437
+ var HOST_MCP_SERVER_NAME, HOST_MCP_SERVER_KEYS, HTTP_HEADER_NAME;
15438
+ var init_runtime_gateway = __esm(() => {
15439
+ HOST_MCP_SERVER_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
15440
+ HOST_MCP_SERVER_KEYS = new Set(["type", "url", "headers", "timeout"]);
15441
+ HTTP_HEADER_NAME = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
15442
+ });
15443
+
15444
+ // ../../packages/core/src/storage/topic-host-mcp-grants.ts
15445
+ function getTopicHostMcpGrant(topicId) {
15446
+ const row = db.query("SELECT servers_json FROM api_topic_host_mcp_grants WHERE topic_id = ?").get(topicId);
15447
+ if (!row)
15448
+ return null;
15449
+ try {
15450
+ return parseHostMcpServers(JSON.parse(row.servers_json)) ?? null;
15451
+ } catch {
15452
+ return null;
15453
+ }
15454
+ }
15455
+ function deleteTopicHostMcpGrant(topicId) {
15456
+ db.query("DELETE FROM api_topic_host_mcp_grants WHERE topic_id = ?").run(topicId);
15457
+ }
15458
+ var init_topic_host_mcp_grants = __esm(async () => {
15459
+ init_runtime_gateway();
15460
+ await init_forum_db();
15461
+ db.exec(`
15462
+ CREATE TABLE IF NOT EXISTS api_topic_host_mcp_grants (
15463
+ topic_id TEXT PRIMARY KEY,
15464
+ servers_json TEXT NOT NULL,
15465
+ updated_at TEXT NOT NULL
15466
+ )
15467
+ `);
15468
+ });
15469
+
15352
15470
  // ../../packages/core/src/storage/topic-tool-capabilities.ts
15353
15471
  function getTopicToolCapabilities(topicId) {
15354
15472
  const row = db.query(`SELECT visual_tools, file_delivery_tools
@@ -15527,6 +15645,7 @@ async function deleteTopicCascadeImpl(topic, userId, options, deletingAncestorId
15527
15645
  logger.warn({ err: err2, topicId, cwd }, "deleteTopicCascade: workspace cleanup failed");
15528
15646
  }
15529
15647
  deleteTopicVisuals(topicId);
15648
+ deleteTopicHostMcpGrant(topicId);
15530
15649
  deleteTopicToolCapabilities(topicId);
15531
15650
  deleteTopicArchiveState(topicId);
15532
15651
  deleteMessagesForTopic(topicId);
@@ -15589,6 +15708,7 @@ var init_lifecycle = __esm(async () => {
15589
15708
  await init_token_stats();
15590
15709
  await init_topic_archive();
15591
15710
  await init_topic_archive_state();
15711
+ await init_topic_host_mcp_grants();
15592
15712
  await init_topic_tool_capabilities();
15593
15713
  TopicArchiveRequiredError = class TopicArchiveRequiredError extends Error {
15594
15714
  code = "TOPIC_ARCHIVE_FAILED";
@@ -17059,6 +17179,7 @@ __export(exports_turn_runner, {
17059
17179
  resolveWikiMemoryMirror: () => resolveWikiMemoryMirror,
17060
17180
  resolveVisualMediaInput: () => resolveVisualMediaInput,
17061
17181
  resolveTurnToolCapabilities: () => resolveTurnToolCapabilities,
17182
+ resolveTurnHostMcpServers: () => resolveTurnHostMcpServers,
17062
17183
  resolveTopicTurnSession: () => resolveTopicTurnSession,
17063
17184
  resolveTopicTurnExecution: () => resolveTopicTurnExecution,
17064
17185
  resolveSessionRetry: () => resolveSessionRetry,
@@ -17415,6 +17536,12 @@ function resolveTurnToolCapabilities(topicId, params) {
17415
17536
  fileDeliveryTools: params.fileDeliveryTools ?? granted?.fileDeliveryTools ?? false
17416
17537
  };
17417
17538
  }
17539
+ function resolveTurnHostMcpServers(topic, sessionType) {
17540
+ const effectiveSessionType = sessionType ?? (topic.kind === "manager" ? "manager" : "forum");
17541
+ if (topic.kind !== "manager" || effectiveSessionType !== "manager")
17542
+ return;
17543
+ return getTopicHostMcpGrant(topic.id) ?? undefined;
17544
+ }
17418
17545
  function mergeSupersedingUserTurn(running, incoming) {
17419
17546
  const userMessages = [
17420
17547
  ...running.userMessages ?? [legacyUserTurnEnvelope(running.prompt, running.attachments)],
@@ -17634,6 +17761,7 @@ function startAiTurn(params) {
17634
17761
  const sessionName = params.sessionName ?? topic.title;
17635
17762
  const sessionType = params.sessionType;
17636
17763
  const { visualTools, fileDeliveryTools } = resolveTurnToolCapabilities(topicId, params);
17764
+ const hostMcpServers = resolveTurnHostMcpServers(topic, sessionType);
17637
17765
  const onSessionId = params.onSessionId;
17638
17766
  const onSessionReset = params.onSessionReset;
17639
17767
  const bridgeSessionFromHistory = params.bridgeSessionFromHistory === true;
@@ -18133,6 +18261,7 @@ function startAiTurn(params) {
18133
18261
  autoContinue: allowAutoContinue && !silent,
18134
18262
  visualTools,
18135
18263
  fileDeliveryTools,
18264
+ hostMcpServers,
18136
18265
  ...threadRootId ? { threadRootId } : {},
18137
18266
  peerBridge
18138
18267
  });
@@ -18476,6 +18605,7 @@ var init_turn_runner = __esm(async () => {
18476
18605
  await init_runtime_leases();
18477
18606
  await init_runtime_topic_state();
18478
18607
  await init_runtime_turn_requests();
18608
+ await init_topic_host_mcp_grants();
18479
18609
  await init_topic_tool_capabilities();
18480
18610
  await init_wiki();
18481
18611
  init_wiki_summary_names();
@@ -20538,4 +20668,4 @@ export {
20538
20668
  DEFAULT_SELF_CONFIG_PRODUCT
20539
20669
  };
20540
20670
 
20541
- //# debugId=4F08424E019BC37B64756E2164756E21
20671
+ //# debugId=631A95CB99797D8064756E2164756E21