negotium 0.2.23 → 0.2.25

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 (48) hide show
  1. package/dist/agent-helpers.js +84 -30
  2. package/dist/agent-helpers.js.map +6 -6
  3. package/dist/background-bash.js +2 -1
  4. package/dist/background-bash.js.map +3 -3
  5. package/dist/browser-runtime.js +2 -1
  6. package/dist/browser-runtime.js.map +3 -3
  7. package/dist/{chunk-rhp26p2c.js → chunk-1y2xw0xe.js} +2 -1
  8. package/dist/{chunk-rhp26p2c.js.map → chunk-1y2xw0xe.js.map} +3 -3
  9. package/dist/hosted-agent.js +3 -2
  10. package/dist/hosted-agent.js.map +4 -4
  11. package/dist/main.js +224 -366
  12. package/dist/main.js.map +27 -28
  13. package/dist/mcp-factories.js +86 -31
  14. package/dist/mcp-factories.js.map +7 -7
  15. package/dist/prompts.js +2 -1
  16. package/dist/prompts.js.map +3 -3
  17. package/dist/query-runtime.js +2 -1
  18. package/dist/query-runtime.js.map +3 -3
  19. package/dist/registry.js +3 -3
  20. package/dist/registry.js.map +2 -2
  21. package/dist/rollout.js +1 -1
  22. package/dist/runtime/src/index.ts +3 -7
  23. package/dist/runtime/src/mcp/session-comm/default-host.ts +6 -1
  24. package/dist/runtime/src/mcp/session-comm/topic-catalog.ts +17 -1
  25. package/dist/runtime/src/mcp/session-comm/topics.ts +23 -1
  26. package/dist/runtime/src/node-host.ts +4 -4
  27. package/dist/runtime/src/platform/config.ts +12 -0
  28. package/dist/runtime/src/storage/api-topics.ts +160 -52
  29. package/dist/runtime/src/storage/storage-public.ts +0 -1
  30. package/dist/runtime/src/topics/create.ts +12 -6
  31. package/dist/runtime/src/topics/derive.ts +20 -11
  32. package/dist/runtime/src/types/api.ts +8 -4
  33. package/dist/runtime/src/version.ts +1 -1
  34. package/dist/runtime-helpers.js +2 -1
  35. package/dist/runtime-helpers.js.map +3 -3
  36. package/dist/storage.js +92 -38
  37. package/dist/storage.js.map +3 -3
  38. package/dist/types/packages/core/src/mcp/session-comm/topic-catalog.d.ts +7 -0
  39. package/dist/types/packages/core/src/platform/config.d.ts +12 -0
  40. package/dist/types/packages/core/src/storage/api-topics.d.ts +34 -19
  41. package/dist/types/packages/core/src/storage/storage-public.d.ts +1 -1
  42. package/dist/types/packages/core/src/topics/derive.d.ts +13 -4
  43. package/dist/types/packages/core/src/types/api.d.ts +8 -4
  44. package/dist/types/packages/core/src/version.d.ts +1 -1
  45. package/dist/vault.js +2 -1
  46. package/dist/vault.js.map +3 -3
  47. package/package.json +1 -1
  48. package/dist/runtime/src/application/switch-topic-access-mode.ts +0 -110
@@ -351,7 +351,7 @@ function resolveDefaultModel(agent, registryDefaultModel) {
351
351
  function codexAuthFilePath() {
352
352
  return process.env.NEGOTIUM_CODEX_AUTH_FILE || join(process.env.CODEX_HOME || join(homedir(), ".codex"), "auth.json");
353
353
  }
354
- var HOME, PROJECT_ROOT, STATE_DIR_ENV, 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.1.19", BROWSER_RS_MIN_SECURE_VERSION = "0.1.15", BROWSER_RS_VERSION_PROBE_TIMEOUT_MS = 15000, SNIPPETS_API_URL, BROWSER_RS_BIN, BASH_RS_VERSION = "v0.1.5", BASH_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, BROWSER_MCP_SSE_PROXY_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, 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", FALLBACK_AGENT, SESSION_AGENT, GATEWAY_AGENT, FALLBACK_MODEL, SESSION_MODEL, GATEWAY_MODEL, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, _envMaxTellDepth, MAX_TELL_DEPTH;
354
+ var HOME, PROJECT_ROOT, STATE_DIR_ENV, 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.1.19", BROWSER_RS_MIN_SECURE_VERSION = "0.1.15", BROWSER_RS_VERSION_PROBE_TIMEOUT_MS = 15000, SNIPPETS_API_URL, BROWSER_RS_BIN, BASH_RS_VERSION = "v0.1.5", BASH_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, BROWSER_MCP_SSE_PROXY_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", FALLBACK_AGENT, SESSION_AGENT, GATEWAY_AGENT, FALLBACK_MODEL, SESSION_MODEL, GATEWAY_MODEL, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, _envMaxTellDepth, MAX_TELL_DEPTH;
355
355
  var init_config = __esm(() => {
356
356
  init_config_helpers();
357
357
  init_logger();
@@ -393,6 +393,7 @@ var init_config = __esm(() => {
393
393
  BG_BASH_MAX_PORT = parsePortEnv(process.env.BG_BASH_MAX_PORT, 9799);
394
394
  RUNTIME_MCP_SECRET = loadOrCreateLocalSecret("RUNTIME_MCP_SECRET", "runtime-mcp-secret");
395
395
  NODE_CONTROL_TOKEN = loadOrCreateLocalSecret("NEGOTIUM_CONTROL_TOKEN", "node-control-token");
396
+ NODE_ID = loadOrCreateLocalSecret("NEGOTIUM_NODE_ID", "node-id");
396
397
  VAULT_MASTER_KEY = loadOrCreateLocalSecret("NEGOTIUM_VAULT_MASTER_KEY", "vault-master-key", { persistEnvValue: true });
397
398
  delete process.env.NEGOTIUM_VAULT_MASTER_KEY;
398
399
  NEGOTIUM_PORT = parseInt(process.env.NEGOTIUM_PORT || "7777", 10);
@@ -2394,7 +2395,7 @@ var init_claude_registry = __esm(() => {
2394
2395
  });
2395
2396
 
2396
2397
  // ../../packages/core/src/version.ts
2397
- var NEGOTIUM_VERSION = "0.2.23";
2398
+ var NEGOTIUM_VERSION = "0.2.25";
2398
2399
 
2399
2400
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
2400
2401
  import { spawn as spawn2 } from "child_process";
@@ -7340,6 +7341,12 @@ var init_api_topic_config = __esm(async () => {
7340
7341
  });
7341
7342
 
7342
7343
  // ../../packages/core/src/storage/api-topics.ts
7344
+ function defaultTopicSurface() {
7345
+ return normalizeTopicSurface(process.env.NEGOTIUM_DEFAULT_SURFACE);
7346
+ }
7347
+ function normalizeTopicSurface(value) {
7348
+ return value === "telegram" || value === "otium" || value === "terminal" ? value : "terminal";
7349
+ }
7343
7350
  function tableColumns2(table) {
7344
7351
  const rows = db.query(`PRAGMA table_info(${table})`).all();
7345
7352
  return new Set(rows.map((row) => row.name));
@@ -7470,7 +7477,7 @@ function initializeApiTopicsSchema() {
7470
7477
  is_fork INTEGER NOT NULL DEFAULT 0 CHECK (is_fork IN (0,1)),
7471
7478
  is_subagent INTEGER NOT NULL DEFAULT 0 CHECK (is_subagent IN (0,1)),
7472
7479
  visibility TEXT NOT NULL DEFAULT 'visible' CHECK (visibility IN ('visible','hidden')),
7473
- access_mode TEXT NOT NULL DEFAULT 'private' CHECK (access_mode IN ('private','shared')),
7480
+ surface TEXT NOT NULL DEFAULT 'terminal' CHECK (surface IN ('terminal','telegram','otium')),
7474
7481
  browser_profile TEXT NOT NULL DEFAULT 'default',
7475
7482
  browser_profile_owner TEXT,
7476
7483
  session_id TEXT,
@@ -7516,8 +7523,8 @@ function initializeApiTopicsSchema() {
7516
7523
  const legacyBaseEffort = row.base_effort ?? row.default_effort;
7517
7524
  db.query(`INSERT INTO api_topics_next
7518
7525
  (id,title,kind,description,agent,base_model,base_effort,response_policy,
7519
- created_at,last_message_at,parent_topic_id,memory_topic_id,memory_key,is_fork,is_subagent,visibility,access_mode,session_id)
7520
- VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`).run(String(row.id), String(row.title), normalized.kind, typeof row.description === "string" ? row.description : null, normalized.agent ?? null, typeof legacyBaseModel === "string" ? legacyBaseModel : null, typeof legacyBaseEffort === "string" ? legacyBaseEffort : null, normalized.aiMode, String(row.created_at), typeof row.last_message_at === "string" ? row.last_message_at : null, typeof row.parent_topic_id === "string" ? row.parent_topic_id : null, typeof row.memory_topic_id === "string" ? row.memory_topic_id : null, typeof row.memory_key === "string" ? row.memory_key : null, Number(row.is_fork ?? 0) !== 0 ? 1 : 0, Number(row.is_subagent ?? 0) !== 0 ? 1 : 0, row.visibility === "hidden" ? "hidden" : "visible", row.access_mode === "shared" ? "shared" : "private", typeof row.session_id === "string" ? row.session_id : null);
7526
+ created_at,last_message_at,parent_topic_id,memory_topic_id,memory_key,is_fork,is_subagent,visibility,surface,session_id)
7527
+ VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`).run(String(row.id), String(row.title), normalized.kind, typeof row.description === "string" ? row.description : null, normalized.agent ?? null, typeof legacyBaseModel === "string" ? legacyBaseModel : null, typeof legacyBaseEffort === "string" ? legacyBaseEffort : null, normalized.aiMode, String(row.created_at), typeof row.last_message_at === "string" ? row.last_message_at : null, typeof row.parent_topic_id === "string" ? row.parent_topic_id : null, typeof row.memory_topic_id === "string" ? row.memory_topic_id : null, typeof row.memory_key === "string" ? row.memory_key : null, Number(row.is_fork ?? 0) !== 0 ? 1 : 0, Number(row.is_subagent ?? 0) !== 0 ? 1 : 0, row.visibility === "hidden" ? "hidden" : "visible", row.surface === undefined ? defaultTopicSurface() : normalizeTopicSurface(row.surface), typeof row.session_id === "string" ? row.session_id : null);
7521
7528
  }
7522
7529
  db.exec("DROP TABLE IF EXISTS topic_members");
7523
7530
  db.exec("DROP TABLE api_topics");
@@ -7571,8 +7578,15 @@ function initializeApiTopicsSchema() {
7571
7578
  if (!tableColumns2("api_topics").has("visibility")) {
7572
7579
  db.exec("ALTER TABLE api_topics ADD COLUMN visibility TEXT NOT NULL DEFAULT 'visible'");
7573
7580
  }
7574
- if (!tableColumns2("api_topics").has("access_mode")) {
7575
- db.exec("ALTER TABLE api_topics ADD COLUMN access_mode TEXT NOT NULL DEFAULT 'private'");
7581
+ if (!tableColumns2("api_topics").has("surface")) {
7582
+ db.exec("ALTER TABLE api_topics ADD COLUMN surface TEXT NOT NULL DEFAULT 'terminal'");
7583
+ }
7584
+ if (tableColumns2("api_topics").has("access_mode")) {
7585
+ try {
7586
+ db.exec("ALTER TABLE api_topics DROP COLUMN access_mode");
7587
+ } catch (err) {
7588
+ logger.warn({ err }, "api_topics: could not drop the retired access_mode column");
7589
+ }
7576
7590
  }
7577
7591
  if (!tableColumns2("api_topics").has("browser_profile")) {
7578
7592
  db.exec("ALTER TABLE api_topics ADD COLUMN browser_profile TEXT NOT NULL DEFAULT 'default'");
@@ -7599,7 +7613,48 @@ function initializeApiTopicsSchema() {
7599
7613
  )
7600
7614
  WHERE browser_profile_owner IS NULL
7601
7615
  `);
7616
+ backfillTopicSurfaces();
7602
7617
  db.exec("CREATE INDEX IF NOT EXISTS idx_api_topics_last_message ON api_topics(last_message_at DESC)");
7618
+ db.exec("CREATE INDEX IF NOT EXISTS idx_api_topics_surface ON api_topics(surface)");
7619
+ }
7620
+ function backfillTopicSurfaces() {
7621
+ db.exec(`
7622
+ CREATE TABLE IF NOT EXISTS api_schema_migrations (
7623
+ key TEXT PRIMARY KEY,
7624
+ applied_at TEXT NOT NULL
7625
+ )
7626
+ `);
7627
+ const applied = db.query("SELECT key FROM api_schema_migrations WHERE key = ?").get(SURFACE_BACKFILL_MIGRATION);
7628
+ if (applied)
7629
+ return;
7630
+ const surface = defaultTopicSurface();
7631
+ db.transaction(() => {
7632
+ db.query("UPDATE api_topics SET surface = ?").run(surface);
7633
+ renameSurfaceTitleCollisions();
7634
+ db.query("INSERT INTO api_schema_migrations (key, applied_at) VALUES (?, ?)").run(SURFACE_BACKFILL_MIGRATION, new Date().toISOString());
7635
+ })();
7636
+ logger.info({ surface }, "api_topics: surface backfilled");
7637
+ }
7638
+ function renameSurfaceTitleCollisions() {
7639
+ const rows = db.query("SELECT id, title, kind, surface FROM api_topics ORDER BY created_at ASC, rowid ASC").all();
7640
+ const taken = new Set;
7641
+ const update = db.query("UPDATE api_topics SET title = ? WHERE id = ?");
7642
+ for (const row of rows) {
7643
+ const key = (title) => `${row.surface}\x00${row.kind}\x00${normalizedTitle(title)}`;
7644
+ if (!taken.has(key(row.title))) {
7645
+ taken.add(key(row.title));
7646
+ continue;
7647
+ }
7648
+ let suffix = 2;
7649
+ let candidate = `${row.title} (${suffix})`;
7650
+ while (taken.has(key(candidate))) {
7651
+ suffix += 1;
7652
+ candidate = `${row.title} (${suffix})`;
7653
+ }
7654
+ taken.add(key(candidate));
7655
+ update.run(candidate, row.id);
7656
+ logger.warn({ topicId: row.id, surface: row.surface, from: row.title, to: candidate }, "api_topics: renamed a duplicate title for surface-scoped uniqueness");
7657
+ }
7603
7658
  }
7604
7659
  function shortSessionId(sessionId) {
7605
7660
  return sessionId ? sessionId.slice(0, 8) : null;
@@ -7659,12 +7714,9 @@ function rowToDto2(r, participants = getTopicParticipants(r.id), tellTargets) {
7659
7714
  subagentReportMode: r.subagent_report_mode === "tell" || r.subagent_report_mode === "status-only" ? r.subagent_report_mode : "auto"
7660
7715
  } : {},
7661
7716
  visibility: normalizeTopicVisibility(r.visibility),
7662
- accessMode: normalizeTopicAccessMode(r.access_mode)
7717
+ surface: normalizeTopicSurface(r.surface)
7663
7718
  };
7664
7719
  }
7665
- function normalizeTopicAccessMode(value) {
7666
- return value === "shared" ? "shared" : "private";
7667
- }
7668
7720
  function normalizeTopicVisibility(value) {
7669
7721
  return value === "hidden" ? "hidden" : "visible";
7670
7722
  }
@@ -7721,7 +7773,7 @@ function upsertTopic(t) {
7721
7773
  db.transaction(() => {
7722
7774
  db.query(`INSERT INTO api_topics
7723
7775
  (id,title,kind,description,agent,base_model,base_effort,response_policy,
7724
- created_at,last_message_at,parent_topic_id,memory_topic_id,memory_key,is_fork,is_subagent,visibility,access_mode,
7776
+ created_at,last_message_at,parent_topic_id,memory_topic_id,memory_key,is_fork,is_subagent,visibility,surface,
7725
7777
  subagent_report_mode)
7726
7778
  VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
7727
7779
  ON CONFLICT(id) DO UPDATE SET
@@ -7740,8 +7792,8 @@ function upsertTopic(t) {
7740
7792
  is_fork = excluded.is_fork,
7741
7793
  is_subagent = excluded.is_subagent,
7742
7794
  visibility = excluded.visibility,
7743
- access_mode = excluded.access_mode,
7744
- subagent_report_mode = excluded.subagent_report_mode`).run(t.id, t.title, normalized.kind, t.description ?? null, normalized.agent ?? null, t.defaultModel ?? null, t.defaultEffort ?? null, normalized.aiMode, t.createdAt, t.lastMessageAt ?? null, t.parentTopicId ?? null, t.memoryTopicId ?? null, t.memoryKey ?? null, t.isFork ? 1 : 0, t.isSubagent ? 1 : 0, normalizeTopicVisibility(t.visibility), normalizeTopicAccessMode(t.accessMode), t.subagentReportMode ?? "auto");
7795
+ surface = excluded.surface,
7796
+ subagent_report_mode = excluded.subagent_report_mode`).run(t.id, t.title, normalized.kind, t.description ?? null, normalized.agent ?? null, t.defaultModel ?? null, t.defaultEffort ?? null, normalized.aiMode, t.createdAt, t.lastMessageAt ?? null, t.parentTopicId ?? null, t.memoryTopicId ?? null, t.memoryKey ?? null, t.isFork ? 1 : 0, t.isSubagent ? 1 : 0, normalizeTopicVisibility(t.visibility), normalizeTopicSurface(t.surface), t.subagentReportMode ?? "auto");
7745
7797
  db.query("DELETE FROM topic_members WHERE topic_id = ?").run(t.id);
7746
7798
  for (const participant of t.participants) {
7747
7799
  db.query("INSERT INTO topic_members (topic_id,user_id,role) VALUES (?,?,?)").run(t.id, participant.userId, participant.role);
@@ -7754,8 +7806,8 @@ function upsertTopic(t) {
7754
7806
  }
7755
7807
  })();
7756
7808
  }
7757
- function listTopics() {
7758
- const rows = db.query("SELECT * FROM api_topics ORDER BY last_message_at DESC").all();
7809
+ function listTopics(opts = {}) {
7810
+ const rows = opts.surface ? db.query("SELECT * FROM api_topics WHERE surface = ? ORDER BY last_message_at DESC").all(normalizeTopicSurface(opts.surface)) : db.query("SELECT * FROM api_topics ORDER BY last_message_at DESC").all();
7759
7811
  const participants = getAllTopicParticipants();
7760
7812
  const tellTargets = rows.some((row) => row.is_subagent !== 0) ? getAllSubagentTellTargets() : undefined;
7761
7813
  return rows.map((row) => rowToDto2(row, participants.get(row.id) ?? [], tellTargets));
@@ -7798,14 +7850,15 @@ function getTopicMemoryOrigin(id) {
7798
7850
  }
7799
7851
  function findTopicTitleConflict(title, kind, opts = {}) {
7800
7852
  const wanted = normalizedTitle(title);
7853
+ const surface = normalizeTopicSurface(opts.surface ?? defaultTopicSurface());
7801
7854
  const generalTitleRequested = wanted === normalizedTitle(GENERAL_TOPIC_ID);
7802
7855
  if (generalTitleRequested && opts.excludeTopicId !== GENERAL_TOPIC_ID) {
7803
7856
  const general = db.query("SELECT * FROM api_topics WHERE id = ?").get(GENERAL_TOPIC_ID);
7804
7857
  if (general)
7805
7858
  return rowToDto2(general);
7806
7859
  }
7807
- const params = [wanted];
7808
- let sql = "SELECT * FROM api_topics WHERE LOWER(TRIM(title)) = ?";
7860
+ const params = [wanted, surface];
7861
+ let sql = "SELECT * FROM api_topics WHERE LOWER(TRIM(title)) = ? AND surface = ?";
7809
7862
  if (kind !== "manager") {
7810
7863
  sql += " AND (kind = ? OR id = ?)";
7811
7864
  params.push(kind, GENERAL_TOPIC_ID);
@@ -7890,7 +7943,7 @@ function reparentTopicChildren(deletedTopicId, replacementParentTopicId) {
7890
7943
  }
7891
7944
  return rows.map((row) => row.id);
7892
7945
  }
7893
- var DEFAULT_AGENT_ROOM_AGENT = "maestro";
7946
+ var DEFAULT_AGENT_ROOM_AGENT = "maestro", SURFACE_BACKFILL_MIGRATION = "api_topics_surface_backfill_20260808";
7894
7947
  var init_api_topics = __esm(async () => {
7895
7948
  init_constants();
7896
7949
  init_logger();
@@ -12617,11 +12670,11 @@ __export(exports_derive, {
12617
12670
  });
12618
12671
  import { createHash as createHash5, randomUUID as randomUUID12 } from "crypto";
12619
12672
  import { mkdirSync as mkdirSync13, rmSync as rmSync5, unlinkSync as unlinkSync13 } from "fs";
12620
- function getTopics() {
12621
- return listTopics().filter((topic) => !isLegacySharedGeneral(topic.id));
12673
+ function getTopics(opts = {}) {
12674
+ return listTopics(opts).filter((topic) => !isLegacySharedGeneral(topic.id));
12622
12675
  }
12623
- function getVisibleTopics() {
12624
- return getTopics().filter(isTopicVisible).map((topic) => {
12676
+ function getVisibleTopics(opts = {}) {
12677
+ return getTopics(opts).filter(isTopicVisible).map((topic) => {
12625
12678
  if (!topic.agent)
12626
12679
  return topic;
12627
12680
  const registry = getRegistry(topic.agent);
@@ -12646,8 +12699,8 @@ function updateTopic(topicId, patch) {
12646
12699
  function isParticipant(topic, userId) {
12647
12700
  return topic.participants.some((p) => p.userId === userId);
12648
12701
  }
12649
- function nextDerivedTopicTitle(sourceTitle, kind, suffix) {
12650
- const visibleTitles = new Set(listTopics().filter((topic) => topic.kind === kind).map((topic) => topic.title.toLowerCase()));
12702
+ function nextDerivedTopicTitle(sourceTitle, kind, suffix, surface) {
12703
+ const visibleTitles = new Set(listTopics(surface ? { surface } : {}).filter((topic) => topic.kind === kind).map((topic) => topic.title.toLowerCase()));
12651
12704
  let n = 1;
12652
12705
  let title = `${sourceTitle}-${suffix}-${n}`;
12653
12706
  while (visibleTitles.has(title.toLowerCase())) {
@@ -12711,8 +12764,9 @@ async function createDerivedTopicImpl(topic, sourceTopicId, userId, copyHistory,
12711
12764
  { userId, role: "owner" }
12712
12765
  ] : [{ userId, role: "owner" }];
12713
12766
  const kind = topic.kind ?? inferTopicKind(topic);
12714
- const title = opts?.name?.trim() || nextDerivedTopicTitle(topic.title, kind, suffix);
12715
- const conflict = findTopicTitleConflict(title, kind);
12767
+ const surface = topic.surface ?? defaultTopicSurface();
12768
+ const title = opts?.name?.trim() || nextDerivedTopicTitle(topic.title, kind, suffix, surface);
12769
+ const conflict = findTopicTitleConflict(title, kind, { surface });
12716
12770
  if (conflict) {
12717
12771
  logger.info({ sourceTopicId, title, kind, conflictTopicId: conflict.id }, "createDerivedTopic: title conflict");
12718
12772
  throw new TopicTitleConflictError(title);
@@ -12735,7 +12789,7 @@ async function createDerivedTopicImpl(topic, sourceTopicId, userId, copyHistory,
12735
12789
  isFork: copyHistory,
12736
12790
  ...subagent ? { isSubagent: true } : {},
12737
12791
  visibility: topic.visibility,
12738
- accessMode: topic.accessMode
12792
+ surface
12739
12793
  };
12740
12794
  let sessionId;
12741
12795
  let rollbackHandle;
@@ -12843,7 +12897,7 @@ async function createDerivedTopicImpl(topic, sourceTopicId, userId, copyHistory,
12843
12897
  if (!currentSource || currentSource.kind === "manager" || !isParticipant(currentSource, userId) || subagent && isRuntimeTopicMaintenance(sourceTopicId)) {
12844
12898
  throw new TopicDeriveBusyError("Source topic changed while deriving; try again");
12845
12899
  }
12846
- const transactionalConflict = findTopicTitleConflict(title, kind);
12900
+ const transactionalConflict = findTopicTitleConflict(title, kind, { surface });
12847
12901
  if (transactionalConflict)
12848
12902
  throw new TopicTitleConflictError(title);
12849
12903
  upsertTopic(derived);
@@ -18756,4 +18810,4 @@ export {
18756
18810
  DEFAULT_SELF_CONFIG_PRODUCT
18757
18811
  };
18758
18812
 
18759
- //# debugId=FDCB9879C6DDFD3D64756E2164756E21
18813
+ //# debugId=F0D2AC4BD6AF764E64756E2164756E21