negotium 0.14.3 → 0.15.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.
Files changed (66) hide show
  1. package/dist/agent-helpers.js +167 -42
  2. package/dist/agent-helpers.js.map +18 -16
  3. package/dist/background-bash.js +2 -9
  4. package/dist/background-bash.js.map +4 -4
  5. package/dist/browser-runtime.js +2 -9
  6. package/dist/browser-runtime.js.map +4 -4
  7. package/dist/{chunk-yaq63qtw.js → chunk-84b5qy2s.js} +3 -3
  8. package/dist/{chunk-yaq63qtw.js.map → chunk-84b5qy2s.js.map} +2 -2
  9. package/dist/{chunk-05a4ne6p.js → chunk-gjtgsggp.js} +1 -1
  10. package/dist/{chunk-jgeyq0p1.js → chunk-j457924j.js} +17 -11
  11. package/dist/{chunk-jgeyq0p1.js.map → chunk-j457924j.js.map} +5 -5
  12. package/dist/hosted-agent.js +23 -14
  13. package/dist/hosted-agent.js.map +7 -7
  14. package/dist/main.js +634 -438
  15. package/dist/main.js.map +25 -24
  16. package/dist/mcp-factories.js +461 -335
  17. package/dist/mcp-factories.js.map +19 -17
  18. package/dist/media.js +2 -9
  19. package/dist/media.js.map +4 -4
  20. package/dist/prompts.js +2 -19
  21. package/dist/prompts.js.map +5 -5
  22. package/dist/query-runtime.js +2 -9
  23. package/dist/query-runtime.js.map +4 -4
  24. package/dist/registry.js +5 -6
  25. package/dist/registry.js.map +3 -3
  26. package/dist/rollout.js +2 -2
  27. package/dist/runtime/cron/store.ts +37 -1
  28. package/dist/runtime/src/agents/archiver.ts +4 -6
  29. package/dist/runtime/src/agents/codex-provider.ts +8 -2
  30. package/dist/runtime/src/agents/index.ts +12 -3
  31. package/dist/runtime/src/agents/maestro-registry.ts +0 -1
  32. package/dist/runtime/src/agents/model-catalog.ts +16 -15
  33. package/dist/runtime/src/application/submit-runtime-gateway-turn.ts +21 -2
  34. package/dist/runtime/src/cron-host.ts +3 -1
  35. package/dist/runtime/src/mcp/factories/agent-health.ts +3 -2
  36. package/dist/runtime/src/node-host.ts +2 -0
  37. package/dist/runtime/src/platform/config.ts +2 -21
  38. package/dist/runtime/src/platform/mcp-config.ts +38 -16
  39. package/dist/runtime/src/runtime/turn-runner.ts +13 -0
  40. package/dist/runtime/src/runtime-gateway.ts +86 -0
  41. package/dist/runtime/src/storage/forum/repository.ts +8 -10
  42. package/dist/runtime/src/storage/token-stats.ts +5 -1
  43. package/dist/runtime/src/storage/topic-host-mcp-grants.ts +54 -0
  44. package/dist/runtime/src/topics/lifecycle.ts +2 -0
  45. package/dist/runtime/src/topics/personal-general.ts +8 -6
  46. package/dist/runtime/src/types.ts +4 -0
  47. package/dist/runtime/src/version.ts +1 -1
  48. package/dist/runtime-gateway.js +73 -1
  49. package/dist/runtime-gateway.js.map +3 -3
  50. package/dist/runtime-helpers.js +2 -9
  51. package/dist/runtime-helpers.js.map +4 -4
  52. package/dist/storage.js +6 -13
  53. package/dist/storage.js.map +5 -5
  54. package/dist/types/packages/core/src/agents/archiver.d.ts +1 -1
  55. package/dist/types/packages/core/src/agents/model-catalog.d.ts +5 -0
  56. package/dist/types/packages/core/src/platform/config.d.ts +0 -8
  57. package/dist/types/packages/core/src/platform/mcp-config.d.ts +2 -0
  58. package/dist/types/packages/core/src/runtime/turn-runner.d.ts +3 -1
  59. package/dist/types/packages/core/src/runtime-gateway.d.ts +11 -0
  60. package/dist/types/packages/core/src/storage/topic-host-mcp-grants.d.ts +5 -0
  61. package/dist/types/packages/core/src/types.d.ts +3 -0
  62. package/dist/types/packages/core/src/version.d.ts +1 -1
  63. package/dist/vault.js +2 -9
  64. package/dist/vault.js.map +4 -4
  65. package/package.json +1 -1
  66. /package/dist/{chunk-05a4ne6p.js.map → chunk-gjtgsggp.js.map} +0 -0
@@ -331,19 +331,13 @@ function loadOrCreateLocalSecret(envKey, filename, options = {}) {
331
331
  return stored;
332
332
  }
333
333
  }
334
- function resolveModelEnv(envKey, agentConst) {
335
- return envText(envKey) ?? (agentConst === FALLBACK_AGENT ? FALLBACK_MODEL : undefined);
336
- }
337
- function resolveDefaultModel(agent, registryDefaultModel) {
338
- return agent === SESSION_AGENT && SESSION_MODEL ? SESSION_MODEL : registryDefaultModel;
339
- }
340
334
  function resolveWhisperBackend() {
341
335
  return envText("WHISPER_BACKEND") === "mlx-whisper" ? "mlx-whisper" : "faster-whisper";
342
336
  }
343
337
  function codexAuthFilePath() {
344
338
  return process.env.NEGOTIUM_CODEX_AUTH_FILE || join(process.env.CODEX_HOME || join(homedir(), ".codex"), "auth.json");
345
339
  }
346
- var HOME, PROJECT_ROOT, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR, CRON_WORKSPACE_DIR, BROWSER_DIR, BROWSER_PROFILES_DIR, BINARIES_DIR, SECRETS_DIR, DM_WORKSPACE_DIR, SESSION_WORKSPACE_DIR, CLAUDE_EXECUTABLE_ENV, CLAUDE_EXECUTABLE, DEFAULT_OUTPUT_LANGUAGE = "English", BROWSER_RS_VERSION = "v0.4.0", BROWSER_RS_MIN_SECURE_VERSION = "0.2.1", BROWSER_RS_VERSION_PROBE_TIMEOUT_MS = 15000, SNIPPETS_API_URL, BROWSER_RS_BIN, BASH_RS_VERSION = "v0.1.7", BASH_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, DECISION_SERVER, CANONICAL_MCP_PROXY_SERVER, WIKI_SERVER, TOKEN_STATS_SERVER, COMPACTION_LOG_SERVER, SYSTEM_HEALTH_SERVER, AGENT_HEALTH_SERVER, VAULT_SERVER, BG_BASH_BASE_PORT, BG_BASH_MAX_PORT, RUNTIME_MCP_SECRET, NODE_CONTROL_TOKEN, NODE_ID, VAULT_MASTER_KEY, NEGOTIUM_PORT, hostname, DATA_DIR, LOG_DIR, UPLOADS_DIR, VAULT_DIR, SESSIONS_DB, DEBUG_FILE, USERS_LOG_DIR, RUN_DIR, PROGRESS_DIR, DM_CMD_DIR, DM_RESP_DIR, SESSION_INBOX_DIR, SESSION_ASKS_DIR, BASHRS_SPILL_ROOT, PLAYWRIGHT_BASE_PORT, PLAYWRIGHT_MAX_PORT, PLAYWRIGHT_PORTS_DIR, ACTIVE_QUERY_STALE_MS, AGENTS_PROMPTS_DIR, RESOURCES_DIR, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5", MODEL_FABLE = "claude-fable-5-1", FALLBACK_AGENT, SESSION_AGENT, GATEWAY_AGENT, FALLBACK_MODEL, SESSION_MODEL, GATEWAY_MODEL, DEFAULT_TOPIC_EFFORT, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, WHISPER_BACKEND, MLX_WHISPER_BIN, WHISPER_MODEL_MLX, _envMaxTellDepth, MAX_TELL_DEPTH;
340
+ var HOME, PROJECT_ROOT, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR, CRON_WORKSPACE_DIR, BROWSER_DIR, BROWSER_PROFILES_DIR, BINARIES_DIR, SECRETS_DIR, DM_WORKSPACE_DIR, SESSION_WORKSPACE_DIR, CLAUDE_EXECUTABLE_ENV, CLAUDE_EXECUTABLE, DEFAULT_OUTPUT_LANGUAGE = "English", BROWSER_RS_VERSION = "v0.4.0", BROWSER_RS_MIN_SECURE_VERSION = "0.2.1", BROWSER_RS_VERSION_PROBE_TIMEOUT_MS = 15000, SNIPPETS_API_URL, BROWSER_RS_BIN, BASH_RS_VERSION = "v0.1.7", BASH_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, DECISION_SERVER, CANONICAL_MCP_PROXY_SERVER, WIKI_SERVER, TOKEN_STATS_SERVER, COMPACTION_LOG_SERVER, SYSTEM_HEALTH_SERVER, AGENT_HEALTH_SERVER, VAULT_SERVER, BG_BASH_BASE_PORT, BG_BASH_MAX_PORT, RUNTIME_MCP_SECRET, NODE_CONTROL_TOKEN, NODE_ID, VAULT_MASTER_KEY, NEGOTIUM_PORT, hostname, DATA_DIR, LOG_DIR, UPLOADS_DIR, VAULT_DIR, SESSIONS_DB, DEBUG_FILE, USERS_LOG_DIR, RUN_DIR, PROGRESS_DIR, DM_CMD_DIR, DM_RESP_DIR, SESSION_INBOX_DIR, SESSION_ASKS_DIR, BASHRS_SPILL_ROOT, PLAYWRIGHT_BASE_PORT, PLAYWRIGHT_MAX_PORT, PLAYWRIGHT_PORTS_DIR, ACTIVE_QUERY_STALE_MS, AGENTS_PROMPTS_DIR, RESOURCES_DIR, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5", MODEL_FABLE = "claude-fable-5-1", FALLBACK_AGENT, FALLBACK_MODEL, DEFAULT_TOPIC_EFFORT, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, WHISPER_BACKEND, MLX_WHISPER_BIN, WHISPER_MODEL_MLX, _envMaxTellDepth, MAX_TELL_DEPTH;
347
341
  var init_config = __esm(() => {
348
342
  init_config_helpers();
349
343
  init_logger();
@@ -431,12 +425,8 @@ var init_config = __esm(() => {
431
425
  AGENTS_PROMPTS_DIR = resolve2(PROJECT_ROOT, "src/prompts/agents");
432
426
  RESOURCES_DIR = resolve2(PROJECT_ROOT, "src/resources");
433
427
  FILE_TAG_REGEX = /\[FILE:(\/[^\]]+)\]/gi;
434
- FALLBACK_AGENT = resolveAgentEnv("FALLBACK_AGENT", "maestro", "DEFAULT_AGENT");
435
- SESSION_AGENT = resolveAgentEnv("SESSION_AGENT", FALLBACK_AGENT);
436
- GATEWAY_AGENT = resolveAgentEnv("GATEWAY_AGENT", FALLBACK_AGENT);
428
+ FALLBACK_AGENT = resolveAgentEnv("FALLBACK_AGENT", "claude", "DEFAULT_AGENT");
437
429
  FALLBACK_MODEL = envText("FALLBACK_MODEL") ?? envText("DEFAULT_MODEL");
438
- SESSION_MODEL = resolveModelEnv("SESSION_MODEL", SESSION_AGENT);
439
- GATEWAY_MODEL = resolveModelEnv("GATEWAY_MODEL", GATEWAY_AGENT);
440
430
  DEFAULT_TOPIC_EFFORT = (() => {
441
431
  const raw = envText("NEGOTIUM_DEFAULT_EFFORT")?.toLowerCase();
442
432
  return raw && EFFORT_VALUES.includes(raw) ? raw : "medium";
@@ -1008,6 +998,19 @@ function refreshForumCatalogViews() {
1008
998
  requiredForumMcpServers.splice(0, requiredForumMcpServers.length, ...required);
1009
999
  optionalForumMcpServers.splice(0, optionalForumMcpServers.length, ...optional);
1010
1000
  }
1001
+ function isReservedRuntimeMcpServerName(name) {
1002
+ return Object.hasOwn(MCP_CATALOG, name) || nodeMcpEntries.some((entry) => entry.key === name);
1003
+ }
1004
+ function mergeHostMcpServers(base, hostMcpServers) {
1005
+ if (!hostMcpServers)
1006
+ return base;
1007
+ for (const name of Object.keys(hostMcpServers)) {
1008
+ if (Object.hasOwn(base, name) || isReservedRuntimeMcpServerName(name)) {
1009
+ throw new Error(`host MCP server name conflicts with node catalog: ${name}`);
1010
+ }
1011
+ }
1012
+ return { ...base, ...hostMcpServers };
1013
+ }
1011
1014
  function buildNodeMcpSpecs(agent, filter) {
1012
1015
  const out = {};
1013
1016
  for (const entry of nodeMcpEntries) {
@@ -1184,7 +1187,7 @@ function getMcpServersForQuery(opts) {
1184
1187
  });
1185
1188
  }
1186
1189
  if (opts.sessionType === "manager") {
1187
- return getManagerMcpServers({
1190
+ return mergeHostMcpServers(getManagerMcpServers({
1188
1191
  userId: opts.userId || "local",
1189
1192
  session: opts.session,
1190
1193
  topicId: opts.topicId,
@@ -1199,7 +1202,7 @@ function getMcpServersForQuery(opts) {
1199
1202
  autoContinue: opts.autoContinue,
1200
1203
  visualTools: opts.visualTools,
1201
1204
  fileDeliveryTools: opts.fileDeliveryTools
1202
- });
1205
+ }), opts.hostMcpServers);
1203
1206
  }
1204
1207
  return getForumMcpServers({
1205
1208
  userId: opts.userId || "local",
@@ -3072,7 +3075,7 @@ var init_codex = __esm(async () => {
3072
3075
  });
3073
3076
 
3074
3077
  // ../../packages/core/src/version.ts
3075
- var NEGOTIUM_VERSION = "0.14.3";
3078
+ var NEGOTIUM_VERSION = "0.15.0";
3076
3079
 
3077
3080
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
3078
3081
  import { spawn as spawn2 } from "child_process";
@@ -3565,8 +3568,7 @@ var init_maestro_registry = __esm(() => {
3565
3568
  "kimi-code": "kimi-k2.7-code",
3566
3569
  glm: "glm-5.3",
3567
3570
  "glm-pro": "glm-5.3",
3568
- "glm-flash": "glm-5.3-flash",
3569
- "glm-5.2": "glm-5.2"
3571
+ "glm-flash": "glm-5.3-flash"
3570
3572
  };
3571
3573
  VALID_MODELS = new Set([...Object.keys(ALIAS_MAP2), ...Object.values(ALIAS_MAP2)]);
3572
3574
  VALID_EFFORTS3 = new Set(MAESTRO_EFFORT_VALUES);
@@ -5572,8 +5574,11 @@ function toCodexMcpServers(claudeShape) {
5572
5574
  if (typeof s.url === "string" && s.type !== "sse") {
5573
5575
  out[codexName] = withCodexMcpServerOverrides(name, {
5574
5576
  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 } : {}
5577
+ ...s.http_headers && typeof s.http_headers === "object" || s.headers && typeof s.headers === "object" ? {
5578
+ http_headers: s.http_headers ?? s.headers
5579
+ } : {},
5580
+ ...s.env_http_headers && typeof s.env_http_headers === "object" ? { env_http_headers: s.env_http_headers } : {},
5581
+ ...typeof s.timeout === "number" ? { tool_timeout_sec: Math.max(1, Math.ceil(s.timeout / 1000)) } : {}
5577
5582
  });
5578
5583
  }
5579
5584
  }
@@ -6309,17 +6314,20 @@ import { join as join14 } from "path";
6309
6314
  async function* dispatchAgent(opts) {
6310
6315
  switch (opts.agent) {
6311
6316
  case "claude": {
6312
- const { claudeProvider: claudeProvider2 } = await init_claude_provider().then(() => exports_claude_provider);
6317
+ claudeProviderImport ??= init_claude_provider().then(() => exports_claude_provider);
6318
+ const { claudeProvider: claudeProvider2 } = await claudeProviderImport;
6313
6319
  yield* claudeProvider2(opts);
6314
6320
  return;
6315
6321
  }
6316
6322
  case "codex": {
6317
- const { codexProvider: codexProvider2 } = await init_codex_provider().then(() => exports_codex_provider);
6323
+ codexProviderImport ??= init_codex_provider().then(() => exports_codex_provider);
6324
+ const { codexProvider: codexProvider2 } = await codexProviderImport;
6318
6325
  yield* codexProvider2(opts);
6319
6326
  return;
6320
6327
  }
6321
6328
  case "maestro": {
6322
- const { maestroProvider: maestroProvider2 } = await init_maestro_provider().then(() => exports_maestro_provider);
6329
+ maestroProviderImport ??= init_maestro_provider().then(() => exports_maestro_provider);
6330
+ const { maestroProvider: maestroProvider2 } = await maestroProviderImport;
6323
6331
  yield* maestroProvider2(opts);
6324
6332
  return;
6325
6333
  }
@@ -6412,6 +6420,7 @@ async function* runAgent(opts) {
6412
6420
  yield event;
6413
6421
  }
6414
6422
  }
6423
+ var claudeProviderImport, codexProviderImport, maestroProviderImport;
6415
6424
  var init_agents = __esm(async () => {
6416
6425
  await init_execution_host();
6417
6426
  await init_registry();
@@ -6695,6 +6704,7 @@ var exports_model_catalog = {};
6695
6704
  __export(exports_model_catalog, {
6696
6705
  selectableModel: () => selectableModel,
6697
6706
  resolveModelForAgent: () => resolveModelForAgent,
6707
+ resolveDefaultModel: () => resolveDefaultModel,
6698
6708
  resolveCompactionExecution: () => resolveCompactionExecution,
6699
6709
  modelOwner: () => modelOwner,
6700
6710
  formatSelectableModel: () => formatSelectableModel,
@@ -6731,8 +6741,18 @@ function modelOwner(model) {
6731
6741
  return "codex";
6732
6742
  return MODEL_OWNER[model];
6733
6743
  }
6744
+ function resolveDefaultModel(agent, registry) {
6745
+ if (agent !== FALLBACK_AGENT || !FALLBACK_MODEL)
6746
+ return registry.defaultModel;
6747
+ const candidate = canonicalModelId(FALLBACK_MODEL);
6748
+ const owner = modelOwner(candidate);
6749
+ if (owner && owner !== agent || !registry.validateModel(candidate)) {
6750
+ return registry.defaultModel;
6751
+ }
6752
+ return candidate;
6753
+ }
6734
6754
  function resolveModelForAgent(agent, requested, registry) {
6735
- const defaultModel = resolveDefaultModel(agent, registry.defaultModel);
6755
+ const defaultModel = resolveDefaultModel(agent, registry);
6736
6756
  if (!requested)
6737
6757
  return defaultModel;
6738
6758
  const candidate = canonicalModelId(requested);
@@ -6772,7 +6792,6 @@ var init_model_catalog = __esm(() => {
6772
6792
  "glm-pro": "maestro",
6773
6793
  "glm-flash": "maestro",
6774
6794
  "glm-5.3": "maestro",
6775
- "glm-5.2": "maestro",
6776
6795
  "glm-5.3-flash": "maestro"
6777
6796
  };
6778
6797
  SELECTABLE_MODELS = [
@@ -6876,16 +6895,6 @@ var init_model_catalog = __esm(() => {
6876
6895
  marginalTokenCost: "Approximate GLM API rate: $1.40/M input, $4.40/M output",
6877
6896
  estimatedUsage: "No subscription token cap; pay per token. Always uses thinking and supports a 1M-token context window; text-only input."
6878
6897
  },
6879
- {
6880
- model: "glm-5.2",
6881
- agent: "maestro",
6882
- description: "Previous-generation GLM flagship for cost-efficient everyday work.",
6883
- intelligenceTier: "sonnet",
6884
- routingSummary: "previous-gen flagship; 1M context; cost-efficient everyday work, cheaper than glm-5.3",
6885
- accessCost: "Zhipu AI pay-as-you-go API; no monthly subscription required",
6886
- marginalTokenCost: "Approximate GLM API rate: $0.95/M input, $3/M output",
6887
- estimatedUsage: "No subscription token cap; pay per token. Always uses thinking and supports a 1M-token context window; text-only input."
6888
- },
6889
6898
  {
6890
6899
  model: "glm-5.3-flash",
6891
6900
  agent: "maestro",
@@ -8487,19 +8496,19 @@ function ensurePersonalGeneral(userId, surface, opts = {}) {
8487
8496
  upsertTopic(existing);
8488
8497
  }
8489
8498
  if (!getApiTopicConfig(existing.id)) {
8490
- setApiTopicConfig(existing.id, { model: "deepseek-pro", modelLocked: true });
8499
+ setApiTopicConfig(existing.id, {});
8491
8500
  }
8492
8501
  return existing;
8493
8502
  }
8494
8503
  const now = new Date().toISOString();
8495
- const registry = getRegistry("maestro");
8504
+ const registry = getRegistry(FALLBACK_AGENT);
8496
8505
  const topic = {
8497
8506
  id: randomUUID5(),
8498
8507
  title: "General",
8499
8508
  description: PERSONAL_GENERAL_DESCRIPTION,
8500
8509
  kind: "manager",
8501
- agent: "maestro",
8502
- defaultModel: resolveDefaultModel("maestro", registry.defaultModel),
8510
+ agent: FALLBACK_AGENT,
8511
+ defaultModel: resolveDefaultModel(FALLBACK_AGENT, registry),
8503
8512
  defaultEffort: registry.defaultEffort ?? "medium",
8504
8513
  aiMode: "always",
8505
8514
  aiMention: false,
@@ -8510,7 +8519,7 @@ function ensurePersonalGeneral(userId, surface, opts = {}) {
8510
8519
  lastMessageAt: now
8511
8520
  };
8512
8521
  upsertTopic(topic);
8513
- setApiTopicConfig(topic.id, { model: "deepseek-pro", modelLocked: true });
8522
+ setApiTopicConfig(topic.id, {});
8514
8523
  return topic;
8515
8524
  }
8516
8525
  function isLegacySharedGeneral(topicId) {
@@ -8518,6 +8527,7 @@ function isLegacySharedGeneral(topicId) {
8518
8527
  }
8519
8528
  var LEGACY_PERSONAL_GENERAL_DESCRIPTION = "\uB098\uB9CC\uC758 \uAC1C\uC778 \uACF5\uAC04\uC774\uC5D0\uC694. \uB300\uD654\uC640 AI \uC791\uC5C5\uC740 \uB2E4\uB978 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uACF5\uAC1C\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.", PERSONAL_GENERAL_DESCRIPTION = "Your private General. Messages and membership are visible only to you. Workspace memory, wiki, and skills are shared with your workspace.";
8520
8529
  var init_personal_general = __esm(async () => {
8530
+ init_model_catalog();
8521
8531
  await init_registry();
8522
8532
  init_config();
8523
8533
  init_constants();
@@ -8607,7 +8617,7 @@ function createArchiverRuntime(host) {
8607
8617
  }
8608
8618
  const wikiDir = host.storage.getWikiDir();
8609
8619
  const safeTopic = host.config.sanitizeTopicName(topicTitle);
8610
- const agent = params.agent ?? "claude";
8620
+ const agent = params.agent ?? FALLBACK_AGENT;
8611
8621
  const model = params.model;
8612
8622
  const outputLanguage = resolveMemoryLanguage();
8613
8623
  const generalReplyInstruction = `Reply with a short completion message in ${outputLanguage} for display in #General. ` + "Do not include tool-call logs or raw transcripts \u2014 just briefly name the summary / brief / articles you saved.";
@@ -12561,7 +12571,7 @@ var init_token_stats = __esm(async () => {
12561
12571
  "maestro:kimi-k3": { input: 3, cacheRead: 0.3, output: 15 },
12562
12572
  "maestro:kimi-k2.7-code": { input: 0.95, cacheRead: 0.19, output: 4 },
12563
12573
  "maestro:glm-5.3": { input: 1.4, cacheRead: 1.4, output: 4.4 },
12564
- "maestro:glm-5.2": { input: 0.95, cacheRead: 0.95, output: 3 },
12574
+ "maestro:glm-5.2": { input: 1.4, cacheRead: 1.4, output: 4.4 },
12565
12575
  "maestro:glm-5.3-flash": { input: 0.15, cacheRead: 0.15, output: 0.5 },
12566
12576
  "maestro:deepseek-pro": { input: 0.435, cacheRead: 0.003625, output: 0.87 },
12567
12577
  "maestro:deepseek-flash": { input: 0.14, cacheRead: 0.0028, output: 0.28 }
@@ -15349,6 +15359,108 @@ body{font-family:system-ui,-apple-system,"Segoe UI",sans-serif;background:var(--
15349
15359
  </style>`;
15350
15360
  });
15351
15361
 
15362
+ // ../../packages/core/src/runtime-gateway.ts
15363
+ function parseHostMcpServers(value) {
15364
+ if (value === undefined)
15365
+ return;
15366
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
15367
+ throw new TypeError("hostMcpServers must be an object");
15368
+ }
15369
+ const parsedEntries = [];
15370
+ for (const [name, raw] of Object.entries(value)) {
15371
+ if (!HOST_MCP_SERVER_NAME.test(name)) {
15372
+ throw new TypeError(`invalid host MCP server name: ${name}`);
15373
+ }
15374
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
15375
+ throw new TypeError(`hostMcpServers.${name} must be an object`);
15376
+ }
15377
+ const spec = raw;
15378
+ const unsupported = Object.keys(spec).find((key) => !HOST_MCP_SERVER_KEYS.has(key));
15379
+ if (unsupported) {
15380
+ throw new TypeError(`hostMcpServers.${name}.${unsupported} is not allowed`);
15381
+ }
15382
+ if (spec.type !== "sse" && spec.type !== "http") {
15383
+ throw new TypeError(`hostMcpServers.${name}.type must be sse or http`);
15384
+ }
15385
+ if (typeof spec.url !== "string") {
15386
+ throw new TypeError(`hostMcpServers.${name}.url must be a string`);
15387
+ }
15388
+ let url;
15389
+ try {
15390
+ url = new URL(spec.url);
15391
+ } catch {
15392
+ throw new TypeError(`hostMcpServers.${name}.url must be a valid URL`);
15393
+ }
15394
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
15395
+ throw new TypeError(`hostMcpServers.${name}.url must use http or https`);
15396
+ }
15397
+ let headers;
15398
+ if (spec.headers !== undefined) {
15399
+ if (!spec.headers || typeof spec.headers !== "object" || Array.isArray(spec.headers)) {
15400
+ throw new TypeError(`hostMcpServers.${name}.headers must be an object`);
15401
+ }
15402
+ const headerEntries = [];
15403
+ for (const [key, headerValue] of Object.entries(spec.headers)) {
15404
+ if (!HTTP_HEADER_NAME.test(key) || typeof headerValue !== "string") {
15405
+ throw new TypeError(`hostMcpServers.${name}.headers must contain string values`);
15406
+ }
15407
+ try {
15408
+ new Headers([[key, headerValue]]);
15409
+ } catch {
15410
+ throw new TypeError(`hostMcpServers.${name}.headers contains an invalid header`);
15411
+ }
15412
+ headerEntries.push([key, headerValue]);
15413
+ }
15414
+ headers = Object.fromEntries(headerEntries);
15415
+ }
15416
+ if (spec.timeout !== undefined && (typeof spec.timeout !== "number" || !Number.isFinite(spec.timeout) || spec.timeout <= 0)) {
15417
+ throw new TypeError(`hostMcpServers.${name}.timeout must be a positive number`);
15418
+ }
15419
+ parsedEntries.push([
15420
+ name,
15421
+ {
15422
+ type: spec.type,
15423
+ url: url.toString(),
15424
+ ...headers ? { headers } : {},
15425
+ ...spec.timeout !== undefined ? { timeout: spec.timeout } : {}
15426
+ }
15427
+ ]);
15428
+ }
15429
+ return Object.fromEntries(parsedEntries);
15430
+ }
15431
+ var HOST_MCP_SERVER_NAME, HOST_MCP_SERVER_KEYS, HTTP_HEADER_NAME;
15432
+ var init_runtime_gateway = __esm(() => {
15433
+ HOST_MCP_SERVER_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
15434
+ HOST_MCP_SERVER_KEYS = new Set(["type", "url", "headers", "timeout"]);
15435
+ HTTP_HEADER_NAME = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
15436
+ });
15437
+
15438
+ // ../../packages/core/src/storage/topic-host-mcp-grants.ts
15439
+ function getTopicHostMcpGrant(topicId) {
15440
+ const row = db.query("SELECT servers_json FROM api_topic_host_mcp_grants WHERE topic_id = ?").get(topicId);
15441
+ if (!row)
15442
+ return null;
15443
+ try {
15444
+ return parseHostMcpServers(JSON.parse(row.servers_json)) ?? null;
15445
+ } catch {
15446
+ return null;
15447
+ }
15448
+ }
15449
+ function deleteTopicHostMcpGrant(topicId) {
15450
+ db.query("DELETE FROM api_topic_host_mcp_grants WHERE topic_id = ?").run(topicId);
15451
+ }
15452
+ var init_topic_host_mcp_grants = __esm(async () => {
15453
+ init_runtime_gateway();
15454
+ await init_forum_db();
15455
+ db.exec(`
15456
+ CREATE TABLE IF NOT EXISTS api_topic_host_mcp_grants (
15457
+ topic_id TEXT PRIMARY KEY,
15458
+ servers_json TEXT NOT NULL,
15459
+ updated_at TEXT NOT NULL
15460
+ )
15461
+ `);
15462
+ });
15463
+
15352
15464
  // ../../packages/core/src/storage/topic-tool-capabilities.ts
15353
15465
  function getTopicToolCapabilities(topicId) {
15354
15466
  const row = db.query(`SELECT visual_tools, file_delivery_tools
@@ -15527,6 +15639,7 @@ async function deleteTopicCascadeImpl(topic, userId, options, deletingAncestorId
15527
15639
  logger.warn({ err: err2, topicId, cwd }, "deleteTopicCascade: workspace cleanup failed");
15528
15640
  }
15529
15641
  deleteTopicVisuals(topicId);
15642
+ deleteTopicHostMcpGrant(topicId);
15530
15643
  deleteTopicToolCapabilities(topicId);
15531
15644
  deleteTopicArchiveState(topicId);
15532
15645
  deleteMessagesForTopic(topicId);
@@ -15589,6 +15702,7 @@ var init_lifecycle = __esm(async () => {
15589
15702
  await init_token_stats();
15590
15703
  await init_topic_archive();
15591
15704
  await init_topic_archive_state();
15705
+ await init_topic_host_mcp_grants();
15592
15706
  await init_topic_tool_capabilities();
15593
15707
  TopicArchiveRequiredError = class TopicArchiveRequiredError extends Error {
15594
15708
  code = "TOPIC_ARCHIVE_FAILED";
@@ -17059,11 +17173,13 @@ __export(exports_turn_runner, {
17059
17173
  resolveWikiMemoryMirror: () => resolveWikiMemoryMirror,
17060
17174
  resolveVisualMediaInput: () => resolveVisualMediaInput,
17061
17175
  resolveTurnToolCapabilities: () => resolveTurnToolCapabilities,
17176
+ resolveTurnHostMcpServers: () => resolveTurnHostMcpServers,
17062
17177
  resolveTopicTurnSession: () => resolveTopicTurnSession,
17063
17178
  resolveTopicTurnExecution: () => resolveTopicTurnExecution,
17064
17179
  resolveSessionRetry: () => resolveSessionRetry,
17065
17180
  resolveModelForAgent: () => resolveModelForAgent,
17066
17181
  resolveInitialTurnSessionId: () => resolveInitialTurnSessionId,
17182
+ resolveDefaultModel: () => resolveDefaultModel,
17067
17183
  resolveCompactionExecution: () => resolveCompactionExecution,
17068
17184
  renderUserTurnBatch: () => renderUserTurnBatch,
17069
17185
  renderUserPromptBatch: () => renderUserPromptBatch,
@@ -17415,6 +17531,12 @@ function resolveTurnToolCapabilities(topicId, params) {
17415
17531
  fileDeliveryTools: params.fileDeliveryTools ?? granted?.fileDeliveryTools ?? false
17416
17532
  };
17417
17533
  }
17534
+ function resolveTurnHostMcpServers(topic, sessionType) {
17535
+ const effectiveSessionType = sessionType ?? (topic.kind === "manager" ? "manager" : "forum");
17536
+ if (topic.kind !== "manager" || effectiveSessionType !== "manager")
17537
+ return;
17538
+ return getTopicHostMcpGrant(topic.id) ?? undefined;
17539
+ }
17418
17540
  function mergeSupersedingUserTurn(running, incoming) {
17419
17541
  const userMessages = [
17420
17542
  ...running.userMessages ?? [legacyUserTurnEnvelope(running.prompt, running.attachments)],
@@ -17634,6 +17756,7 @@ function startAiTurn(params) {
17634
17756
  const sessionName = params.sessionName ?? topic.title;
17635
17757
  const sessionType = params.sessionType;
17636
17758
  const { visualTools, fileDeliveryTools } = resolveTurnToolCapabilities(topicId, params);
17759
+ const hostMcpServers = resolveTurnHostMcpServers(topic, sessionType);
17637
17760
  const onSessionId = params.onSessionId;
17638
17761
  const onSessionReset = params.onSessionReset;
17639
17762
  const bridgeSessionFromHistory = params.bridgeSessionFromHistory === true;
@@ -18133,6 +18256,7 @@ function startAiTurn(params) {
18133
18256
  autoContinue: allowAutoContinue && !silent,
18134
18257
  visualTools,
18135
18258
  fileDeliveryTools,
18259
+ hostMcpServers,
18136
18260
  ...threadRootId ? { threadRootId } : {},
18137
18261
  peerBridge
18138
18262
  });
@@ -18476,6 +18600,7 @@ var init_turn_runner = __esm(async () => {
18476
18600
  await init_runtime_leases();
18477
18601
  await init_runtime_topic_state();
18478
18602
  await init_runtime_turn_requests();
18603
+ await init_topic_host_mcp_grants();
18479
18604
  await init_topic_tool_capabilities();
18480
18605
  await init_wiki();
18481
18606
  init_wiki_summary_names();
@@ -20538,4 +20663,4 @@ export {
20538
20663
  DEFAULT_SELF_CONFIG_PRODUCT
20539
20664
  };
20540
20665
 
20541
- //# debugId=4F08424E019BC37B64756E2164756E21
20666
+ //# debugId=AF4C7F4033D476D264756E2164756E21