negotium 0.22.6 → 0.22.8

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 (73) hide show
  1. package/dist/agent-helpers.js +1369 -413
  2. package/dist/agent-helpers.js.map +8 -8
  3. package/dist/background-bash.js +12 -12
  4. package/dist/background-bash.js.map +2 -2
  5. package/dist/browser-runtime.js +81 -52
  6. package/dist/browser-runtime.js.map +4 -4
  7. package/dist/canonical-mcp-bridge.js +9 -8
  8. package/dist/canonical-mcp-bridge.js.map +1 -1
  9. package/dist/chunk-2mx7fq49.js +6 -0
  10. package/dist/{chunk-bnyvxss3.js.map → chunk-2mx7fq49.js.map} +1 -1
  11. package/dist/{chunk-e59kzyvy.js → chunk-5czvhd0g.js} +5 -4
  12. package/dist/{chunk-e59kzyvy.js.map → chunk-5czvhd0g.js.map} +2 -2
  13. package/dist/{chunk-1mba9m1j.js → chunk-9zn0bkc9.js} +116 -77
  14. package/dist/{chunk-1mba9m1j.js.map → chunk-9zn0bkc9.js.map} +2 -2
  15. package/dist/{chunk-ww8a4ej4.js → chunk-f7p0h1gs.js} +5 -5
  16. package/dist/{chunk-ww8a4ej4.js.map → chunk-f7p0h1gs.js.map} +2 -2
  17. package/dist/{chunk-9a50csg6.js → chunk-pr8p6pap.js} +125 -116
  18. package/dist/{chunk-9a50csg6.js.map → chunk-pr8p6pap.js.map} +7 -7
  19. package/dist/chunk-q5djsg78.js +200 -0
  20. package/dist/chunk-q5djsg78.js.map +9 -0
  21. package/dist/{chunk-1e0nxy7p.js → chunk-z4r7tt2p.js} +12 -12
  22. package/dist/{chunk-1e0nxy7p.js.map → chunk-z4r7tt2p.js.map} +2 -2
  23. package/dist/hosted-agent.js +128 -120
  24. package/dist/hosted-agent.js.map +4 -4
  25. package/dist/main.js +5191 -3270
  26. package/dist/main.js.map +12 -12
  27. package/dist/mcp-catalog.js +4 -4
  28. package/dist/mcp-catalog.js.map +1 -1
  29. package/dist/mcp-factories.js +1583 -635
  30. package/dist/mcp-factories.js.map +8 -8
  31. package/dist/mcp-servers.js +5 -5
  32. package/dist/mcp-servers.js.map +1 -1
  33. package/dist/media.js +3 -3
  34. package/dist/media.js.map +1 -1
  35. package/dist/outbox.js +15 -15
  36. package/dist/outbox.js.map +2 -2
  37. package/dist/platform-runtime.js +7 -7
  38. package/dist/platform-runtime.js.map +1 -1
  39. package/dist/prompts.js +6 -6
  40. package/dist/prompts.js.map +2 -2
  41. package/dist/query-runtime.js +18 -16
  42. package/dist/query-runtime.js.map +2 -2
  43. package/dist/registry.js +20 -19
  44. package/dist/registry.js.map +2 -2
  45. package/dist/rollout.js +41 -41
  46. package/dist/rollout.js.map +2 -2
  47. package/dist/runtime/src/mcp-runtime-host.ts +1 -0
  48. package/dist/runtime/src/platform/playwright/manager.ts +77 -15
  49. package/dist/runtime/src/runtime/visuals.ts +47 -11
  50. package/dist/runtime/src/storage/api-topics.ts +6 -0
  51. package/dist/runtime/src/storage/browser-profiles.ts +18 -0
  52. package/dist/runtime/src/topics/lifecycle.ts +2 -5
  53. package/dist/runtime/src/topics/update.ts +17 -0
  54. package/dist/runtime/src/types/api.ts +6 -0
  55. package/dist/runtime/src/version.ts +1 -1
  56. package/dist/runtime-gateway.js +12 -12
  57. package/dist/runtime-gateway.js.map +2 -2
  58. package/dist/runtime-helpers.js +54 -52
  59. package/dist/runtime-helpers.js.map +2 -2
  60. package/dist/sqlite.js +5 -3
  61. package/dist/sqlite.js.map +2 -2
  62. package/dist/storage.js +640 -664
  63. package/dist/storage.js.map +3 -3
  64. package/dist/types/packages/core/src/platform/playwright/manager.d.ts +8 -0
  65. package/dist/types/packages/core/src/runtime/visuals.d.ts +9 -2
  66. package/dist/types/packages/core/src/storage/api-topics.d.ts +1 -0
  67. package/dist/types/packages/core/src/storage/browser-profiles.d.ts +4 -0
  68. package/dist/types/packages/core/src/types/api.d.ts +6 -0
  69. package/dist/types/packages/core/src/version.d.ts +1 -1
  70. package/dist/vault.js +22 -20
  71. package/dist/vault.js.map +2 -2
  72. package/package.json +1 -1
  73. package/dist/chunk-bnyvxss3.js +0 -77
@@ -13,18 +13,9 @@ var __export = (target, all) => {
13
13
  set: __exportSetter.bind(all, name)
14
14
  });
15
15
  };
16
- var __esm = (fn, res, err) => () => {
17
- if (fn)
18
- try {
19
- res = fn(fn = 0);
20
- } catch (e) {
21
- err = [e];
22
- }
23
- if (err)
24
- throw err[0];
25
- return res;
26
- };
16
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
27
17
  var __promiseAll = (args) => Promise.all(args);
18
+ var __require = import.meta.require;
28
19
 
29
20
  // ../../packages/core/src/platform/paths.ts
30
21
  import { existsSync, realpathSync } from "fs";
@@ -193,6 +184,105 @@ var init_logger = __esm(() => {
193
184
  });
194
185
 
195
186
  // ../../packages/core/src/platform/config.ts
187
+ var exports_config = {};
188
+ __export(exports_config, {
189
+ resolveTopicWorkspaceDir: () => resolveTopicWorkspaceDir,
190
+ resolveOutputLanguage: () => resolveOutputLanguage,
191
+ resolveBrowserRsBin: () => resolveBrowserRsBin,
192
+ resolveBrowserProxy: () => resolveBrowserProxy,
193
+ resolveBrowserMcpBin: () => resolveBrowserMcpBin,
194
+ resolveBashRsBin: () => resolveBashRsBin,
195
+ isProductionEnv: () => isProductionEnv,
196
+ hostname: () => hostname,
197
+ getCleanEnv: () => getCleanEnv,
198
+ envText: () => envText,
199
+ codexAuthFilePath: () => codexAuthFilePath,
200
+ WORKSPACE_DIR: () => WORKSPACE_DIR,
201
+ WIKI_SERVER: () => WIKI_SERVER,
202
+ WHISPER_MODEL_MLX: () => WHISPER_MODEL_MLX,
203
+ WHISPER_MODEL: () => WHISPER_MODEL,
204
+ WHISPER_BACKEND: () => WHISPER_BACKEND,
205
+ VAULT_SERVER: () => VAULT_SERVER,
206
+ VAULT_MASTER_KEY: () => VAULT_MASTER_KEY,
207
+ VAULT_DIR: () => VAULT_DIR,
208
+ USERS_LOG_DIR: () => USERS_LOG_DIR,
209
+ UPLOADS_DIR: () => UPLOADS_DIR,
210
+ TSX_LOADER: () => TSX_LOADER,
211
+ TSX_BIN: () => TSX_BIN,
212
+ TSCONFIG_PATH: () => TSCONFIG_PATH,
213
+ TOPIC_WORKSPACE_DIR: () => TOPIC_WORKSPACE_DIR,
214
+ TOKEN_STATS_SERVER: () => TOKEN_STATS_SERVER,
215
+ TESSERACT_BIN: () => TESSERACT_BIN,
216
+ TASK_SERVER: () => TASK_SERVER,
217
+ SYSTEM_HEALTH_SERVER: () => SYSTEM_HEALTH_SERVER,
218
+ STATE_DIR: () => STATE_DIR,
219
+ SNIPPETS_API_URL: () => SNIPPETS_API_URL,
220
+ SHARED_WIKI_DIR: () => SHARED_WIKI_DIR,
221
+ SESSION_WORKSPACE_DIR: () => SESSION_WORKSPACE_DIR,
222
+ SESSION_INBOX_DIR: () => SESSION_INBOX_DIR,
223
+ SESSION_COMM_SERVER: () => SESSION_COMM_SERVER,
224
+ SESSION_ASKS_DIR: () => SESSION_ASKS_DIR,
225
+ SESSIONS_DB: () => SESSIONS_DB,
226
+ SECRETS_DIR: () => SECRETS_DIR,
227
+ RUN_DIR: () => RUN_DIR,
228
+ RUNTIME_MCP_SECRET: () => RUNTIME_MCP_SECRET,
229
+ RUNTIME_DIR: () => RUNTIME_DIR,
230
+ RESOURCES_DIR: () => RESOURCES_DIR,
231
+ PYTHON_BIN: () => PYTHON_BIN,
232
+ PROJECT_ROOT: () => PROJECT_ROOT,
233
+ PROGRESS_DIR: () => PROGRESS_DIR,
234
+ PLAYWRIGHT_PORTS_DIR: () => PLAYWRIGHT_PORTS_DIR,
235
+ PLAYWRIGHT_MCP_BIN: () => PLAYWRIGHT_MCP_BIN,
236
+ PLAYWRIGHT_MAX_PORT: () => PLAYWRIGHT_MAX_PORT,
237
+ PLAYWRIGHT_BASE_PORT: () => PLAYWRIGHT_BASE_PORT,
238
+ PDFTOTEXT_BIN: () => PDFTOTEXT_BIN,
239
+ NODE_ID: () => NODE_ID,
240
+ NODE_CONTROL_TOKEN: () => NODE_CONTROL_TOKEN,
241
+ NEGOTIUM_PORT: () => NEGOTIUM_PORT,
242
+ MODEL_SONNET: () => MODEL_SONNET,
243
+ MODEL_OPUS: () => MODEL_OPUS,
244
+ MODEL_HAIKU: () => MODEL_HAIKU,
245
+ MODEL_FABLE: () => MODEL_FABLE,
246
+ MODEL_DEEPSEEK_V4_PRO: () => MODEL_DEEPSEEK_V4_PRO,
247
+ MODEL_DEEPSEEK_V4_FLASH: () => MODEL_DEEPSEEK_V4_FLASH,
248
+ MLX_WHISPER_BIN: () => MLX_WHISPER_BIN,
249
+ MAX_TELL_DEPTH: () => MAX_TELL_DEPTH,
250
+ LOG_DIR: () => LOG_DIR,
251
+ FILE_TAG_REGEX: () => FILE_TAG_REGEX,
252
+ FILE_EXTENSIONS_REGEX: () => FILE_EXTENSIONS_REGEX,
253
+ FFPROBE_BIN: () => FFPROBE_BIN,
254
+ FFMPEG_BIN: () => FFMPEG_BIN,
255
+ FASTER_WHISPER_WRAPPER: () => FASTER_WHISPER_WRAPPER,
256
+ FALLBACK_MODEL: () => FALLBACK_MODEL,
257
+ FALLBACK_AGENT: () => FALLBACK_AGENT,
258
+ DM_WORKSPACE_DIR: () => DM_WORKSPACE_DIR,
259
+ DM_RESP_DIR: () => DM_RESP_DIR,
260
+ DM_CMD_DIR: () => DM_CMD_DIR,
261
+ DEFAULT_TOPIC_EFFORT: () => DEFAULT_TOPIC_EFFORT,
262
+ DEFAULT_OUTPUT_LANGUAGE: () => DEFAULT_OUTPUT_LANGUAGE,
263
+ DECISION_SERVER: () => DECISION_SERVER,
264
+ DEBUG_FILE: () => DEBUG_FILE,
265
+ DATA_DIR: () => DATA_DIR,
266
+ CRON_WORKSPACE_DIR: () => CRON_WORKSPACE_DIR,
267
+ COMPACTION_LOG_SERVER: () => COMPACTION_LOG_SERVER,
268
+ CLAUDE_EXECUTABLE: () => CLAUDE_EXECUTABLE,
269
+ CANONICAL_MCP_PROXY_SERVER: () => CANONICAL_MCP_PROXY_SERVER,
270
+ BROWSER_RS_VERSION: () => BROWSER_RS_VERSION,
271
+ BROWSER_RS_MIN_SECURE_VERSION: () => BROWSER_RS_MIN_SECURE_VERSION,
272
+ BROWSER_RS_BIN: () => BROWSER_RS_BIN,
273
+ BROWSER_PROFILES_DIR: () => BROWSER_PROFILES_DIR,
274
+ BROWSER_DIR: () => BROWSER_DIR,
275
+ BINARY_EXTENSION: () => BINARY_EXTENSION,
276
+ BINARIES_DIR: () => BINARIES_DIR,
277
+ BG_BASH_MAX_PORT: () => BG_BASH_MAX_PORT,
278
+ BG_BASH_BASE_PORT: () => BG_BASH_BASE_PORT,
279
+ BASH_RS_VERSION: () => BASH_RS_VERSION,
280
+ BASH_RS_BIN: () => BASH_RS_BIN,
281
+ BASHRS_SPILL_ROOT: () => BASHRS_SPILL_ROOT,
282
+ AGENT_HEALTH_SERVER: () => AGENT_HEALTH_SERVER,
283
+ AGENTS_PROMPTS_DIR: () => AGENTS_PROMPTS_DIR,
284
+ ACTIVE_QUERY_STALE_MS: () => ACTIVE_QUERY_STALE_MS
285
+ });
196
286
  import { execFileSync } from "child_process";
197
287
  import { randomBytes } from "crypto";
198
288
  import {
@@ -342,6 +432,9 @@ function safeWorkspaceSegment(value, fallback) {
342
432
  function resolveTopicWorkspaceDir(topicId) {
343
433
  return join(TOPIC_WORKSPACE_DIR, safeWorkspaceSegment(topicId, "topic"));
344
434
  }
435
+ function isProductionEnv() {
436
+ return false;
437
+ }
345
438
  function loadOrCreateLocalSecret(envKey, filename, options = {}) {
346
439
  const envValue = envText(envKey);
347
440
  const secretFile = resolve3(SECRETS_DIR, filename);
@@ -376,13 +469,18 @@ function loadOrCreateLocalSecret(envKey, filename, options = {}) {
376
469
  return stored;
377
470
  }
378
471
  }
472
+ function getCleanEnv() {
473
+ const env = { ...process.env };
474
+ delete env.CLAUDECODE;
475
+ return env;
476
+ }
379
477
  function resolveWhisperBackend() {
380
478
  return envText("WHISPER_BACKEND") === "mlx-whisper" ? "mlx-whisper" : "faster-whisper";
381
479
  }
382
480
  function codexAuthFilePath() {
383
481
  return process.env.NEGOTIUM_CODEX_AUTH_FILE || join(process.env.CODEX_HOME || join(homedir(), ".codex"), "auth.json");
384
482
  }
385
- 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", BINARY_EXTENSION, BROWSER_RS_VERSION = "v0.7.7", 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.10", BASH_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER_PATH, 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, ABSOLUTE_PATH_PREFIX, FILE_EXTENSIONS_REGEX, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5-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;
483
+ 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", BINARY_EXTENSION, BROWSER_RS_VERSION = "v0.7.7", 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.10", BASH_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER_PATH, 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, RUNTIME_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, ABSOLUTE_PATH_PREFIX, FILE_EXTENSIONS_REGEX, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5-5", MODEL_HAIKU = "claude-haiku-4-5-20251001", MODEL_FABLE = "claude-fable-5-1", MODEL_DEEPSEEK_V4_PRO = "deepseek-v4-pro", MODEL_DEEPSEEK_V4_FLASH = "deepseek-v4-flash", 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;
386
484
  var init_config = __esm(() => {
387
485
  init_config_helpers();
388
486
  init_logger();
@@ -438,6 +536,7 @@ var init_config = __esm(() => {
438
536
  DEBUG_FILE = resolve3(DATA_DIR, "debug-users.json");
439
537
  USERS_LOG_DIR = resolve3(DATA_DIR, "users");
440
538
  RUN_DIR = resolveLocalStateDir("NEGOTIUM_RUN_DIR", "runtime");
539
+ RUNTIME_DIR = RUN_DIR;
441
540
  PROGRESS_DIR = resolve3(RUN_DIR, "progress");
442
541
  DM_CMD_DIR = resolve3(RUN_DIR, "dm-commands");
443
542
  DM_RESP_DIR = resolve3(RUN_DIR, "dm-responses");
@@ -670,6 +769,13 @@ function validateActorTopicScope(value) {
670
769
  }
671
770
  return { ok: true, scope };
672
771
  }
772
+ function parseActorTopicScope(value) {
773
+ const validated = validateActorTopicScope(value);
774
+ return validated.ok ? validated.scope : null;
775
+ }
776
+ function actorTopicScopeFrom(value) {
777
+ return parseActorTopicScope(value) ?? undefined;
778
+ }
673
779
  function intersectActorTopicScopes(scopes) {
674
780
  if (scopes.length === 0 || scopes.some((scope) => scope === undefined))
675
781
  return;
@@ -780,6 +886,13 @@ function validateRemoteSessionGrant(value) {
780
886
  }
781
887
  return { ok: true, grant: { hubUrl: hubUrl.url, capability } };
782
888
  }
889
+ function parseRemoteSessionGrant(value) {
890
+ const validated = validateRemoteSessionGrant(value);
891
+ return validated.ok ? validated.grant : null;
892
+ }
893
+ function remoteSessionGrantFrom(value) {
894
+ return parseRemoteSessionGrant(value) ?? undefined;
895
+ }
783
896
  function remoteSessionGrantExpiry(grant) {
784
897
  const payload = grant.capability.split(".")[1];
785
898
  if (!payload)
@@ -818,7 +931,7 @@ function encodeRemoteSessionGrantArg(grant) {
818
931
  throw new Error("remoteSession is required");
819
932
  return Buffer.from(JSON.stringify(validated.grant), "utf-8").toString("base64url");
820
933
  }
821
- var REMOTE_SESSION_GRANT_LIMITS, GRANT_KEYS, LOOPBACK_HOSTS, MAX_REMOTE_SESSION_REPLY_TOKEN_LENGTH;
934
+ var REMOTE_SESSION_GRANT_LIMITS, GRANT_KEYS, LOOPBACK_HOSTS, REMOTE_SESSION_REPLY_TOKEN_PATTERN, MAX_REMOTE_SESSION_REPLY_TOKEN_LENGTH;
822
935
  var init_remote_session_grant = __esm(() => {
823
936
  REMOTE_SESSION_GRANT_LIMITS = Object.freeze({
824
937
  maxHubUrlLength: 512,
@@ -827,6 +940,7 @@ var init_remote_session_grant = __esm(() => {
827
940
  });
828
941
  GRANT_KEYS = ["hubUrl", "capability"];
829
942
  LOOPBACK_HOSTS = new Set(["127.0.0.1", "::1", "[::1]", "localhost"]);
943
+ REMOTE_SESSION_REPLY_TOKEN_PATTERN = /^rsr1\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/;
830
944
  MAX_REMOTE_SESSION_REPLY_TOKEN_LENGTH = REMOTE_SESSION_GRANT_LIMITS.maxCapabilityLength;
831
945
  });
832
946
 
@@ -1171,12 +1285,12 @@ function createBackgroundBashManager(options = {}) {
1171
1285
  usedPorts.clear();
1172
1286
  knownContexts.clear();
1173
1287
  const deadline = now() + 3000;
1174
- await Promise.all(entries.map((instance) => new Promise((resolve) => {
1288
+ await Promise.all(entries.map((instance) => new Promise((resolve4) => {
1175
1289
  if (instance.process.exitCode !== null || instance.process.killed)
1176
- return resolve();
1177
- instance.process.once("exit", resolve);
1178
- instance.process.once("error", resolve);
1179
- const timer = setTimeout(resolve, Math.max(0, deadline - now()));
1290
+ return resolve4();
1291
+ instance.process.once("exit", resolve4);
1292
+ instance.process.once("error", resolve4);
1293
+ const timer = setTimeout(resolve4, Math.max(0, deadline - now()));
1180
1294
  timer.unref?.();
1181
1295
  })));
1182
1296
  }
@@ -1878,7 +1992,7 @@ var init_api_messages = __esm(async () => {
1878
1992
 
1879
1993
  // ../../packages/core/src/storage/topic-link-records.ts
1880
1994
  function topicLinkSchemaIsCurrent(database, nodeId) {
1881
- const objects = new Map(database.query("SELECT name, sql FROM sqlite_master WHERE type IN ('table','index','trigger')").all().map((row) => [row.name, row.sql ?? ""]));
1995
+ const objects = new Map(database.query("SELECT name, sql FROM sqlite_master WHERE type IN ('table','index','trigger')").all().map((row2) => [row2.name, row2.sql ?? ""]));
1882
1996
  for (const name of [...SCHEMA_TABLES, ...SCHEMA_INDEXES, ...SCHEMA_INDEXES_TOMBSTONES]) {
1883
1997
  if (!objects.has(name))
1884
1998
  return false;
@@ -1895,7 +2009,7 @@ function topicLinkSchemaIsCurrent(database, nodeId) {
1895
2009
  return false;
1896
2010
  }
1897
2011
  const identity = database.query("SELECT node_id, epoch_id FROM api_node_identity WHERE singleton = 1").all();
1898
- if (identity.some((row) => row.epoch_id === null))
2012
+ if (identity.some((row2) => row2.epoch_id === null))
1899
2013
  return false;
1900
2014
  if (nodeId && identity[0]?.node_id !== nodeId)
1901
2015
  return false;
@@ -2369,6 +2483,7 @@ function initializeApiTopicsSchema() {
2369
2483
  surface_scope TEXT,
2370
2484
  browser_profile TEXT NOT NULL DEFAULT 'default',
2371
2485
  browser_profile_owner TEXT,
2486
+ browser_connect_port INTEGER,
2372
2487
  session_id TEXT,
2373
2488
  CHECK (
2374
2489
  (kind = 'channel' AND response_policy = 'off' AND agent IS NULL) OR
@@ -2486,6 +2601,9 @@ function initializeApiTopicsSchema() {
2486
2601
  if (!tableColumns("api_topics").has("browser_profile_owner")) {
2487
2602
  db.exec("ALTER TABLE api_topics ADD COLUMN browser_profile_owner TEXT");
2488
2603
  }
2604
+ if (!tableColumns("api_topics").has("browser_connect_port")) {
2605
+ db.exec("ALTER TABLE api_topics ADD COLUMN browser_connect_port INTEGER");
2606
+ }
2489
2607
  if (!tableColumns("api_topics").has("subagent_report_mode")) {
2490
2608
  db.exec("ALTER TABLE api_topics ADD COLUMN subagent_report_mode TEXT NOT NULL DEFAULT 'auto'");
2491
2609
  }
@@ -2723,12 +2841,16 @@ function rowToDto2(r, participants = getTopicParticipants(r.id), tellTargets) {
2723
2841
  } : {},
2724
2842
  visibility: normalizeTopicVisibility(r.visibility),
2725
2843
  surface: normalizeTopicSurface(r.surface),
2726
- surfaceScope: normalizeSurfaceScope(r.surface_scope)
2844
+ surfaceScope: normalizeSurfaceScope(r.surface_scope),
2845
+ ...r.browser_connect_port != null ? { browserConnectPort: r.browser_connect_port } : {}
2727
2846
  };
2728
2847
  }
2729
2848
  function normalizeTopicVisibility(value) {
2730
2849
  return value === "hidden" ? "hidden" : "visible";
2731
2850
  }
2851
+ function isTopicVisible(topic) {
2852
+ return topic.visibility !== "hidden";
2853
+ }
2732
2854
  function normalizeTopicKind(value) {
2733
2855
  return value === "channel" || value === "agent" || value === "manager" ? value : null;
2734
2856
  }
@@ -5119,7 +5241,7 @@ var init_codex = __esm(async () => {
5119
5241
  });
5120
5242
 
5121
5243
  // ../../packages/core/src/version.ts
5122
- var NEGOTIUM_VERSION = "0.22.6";
5244
+ var NEGOTIUM_VERSION = "0.22.8";
5123
5245
 
5124
5246
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
5125
5247
  import { spawn as spawn2 } from "child_process";
@@ -5195,7 +5317,7 @@ async function bootstrapCodexModelCache(codexHome, cachePath) {
5195
5317
  stdio: ["pipe", "pipe", "pipe"],
5196
5318
  windowsHide: true
5197
5319
  });
5198
- const refreshed = new Promise((resolve, reject) => {
5320
+ const refreshed = new Promise((resolve7, reject) => {
5199
5321
  let settled = false;
5200
5322
  let stdoutBuffer = "";
5201
5323
  let stderr = "";
@@ -5214,7 +5336,7 @@ async function bootstrapCodexModelCache(codexHome, cachePath) {
5214
5336
  else if (!existsSync6(cachePath))
5215
5337
  reject(new Error("Codex did not create its model cache"));
5216
5338
  else
5217
- resolve();
5339
+ resolve7();
5218
5340
  };
5219
5341
  const send = (message) => {
5220
5342
  child.stdin.write(`${JSON.stringify(message)}
@@ -5280,12 +5402,12 @@ async function bootstrapCodexModelCache(codexHome, cachePath) {
5280
5402
  function waitForChildExit(child, timeoutMs) {
5281
5403
  if (child.exitCode !== null || child.signalCode !== null)
5282
5404
  return Promise.resolve();
5283
- return new Promise((resolve) => {
5284
- const timer = setTimeout(resolve, timeoutMs);
5405
+ return new Promise((resolve7) => {
5406
+ const timer = setTimeout(resolve7, timeoutMs);
5285
5407
  timer.unref?.();
5286
5408
  child.once("exit", () => {
5287
5409
  clearTimeout(timer);
5288
- resolve();
5410
+ resolve7();
5289
5411
  });
5290
5412
  });
5291
5413
  }
@@ -5375,11 +5497,16 @@ var init_codex_native_multi_agent = __esm(() => {
5375
5497
  });
5376
5498
 
5377
5499
  // ../../packages/core/src/agents/codex-app-server.ts
5500
+ var exports_codex_app_server = {};
5501
+ __export(exports_codex_app_server, {
5502
+ forkCodexSession: () => forkCodexSession,
5503
+ createCodexAppServerForker: () => createCodexAppServerForker
5504
+ });
5378
5505
  import { spawn as spawn3 } from "child_process";
5379
5506
  function createCodexAppServerForker(host) {
5380
5507
  return async (parentThreadId) => {
5381
5508
  const child = host.spawnServer();
5382
- return await new Promise((resolve, reject) => {
5509
+ return await new Promise((resolve7, reject) => {
5383
5510
  let settled = false;
5384
5511
  let stdoutBuffer = "";
5385
5512
  let stderr = "";
@@ -5396,7 +5523,7 @@ function createCodexAppServerForker(host) {
5396
5523
  if (error)
5397
5524
  reject(error);
5398
5525
  else if (result)
5399
- resolve(result);
5526
+ resolve7(result);
5400
5527
  else
5401
5528
  reject(new Error("Codex thread fork returned no result"));
5402
5529
  };
@@ -5533,8 +5660,8 @@ var init_codex_registry = __esm(async () => {
5533
5660
  return { sessionId: threadId, rolloutPath };
5534
5661
  },
5535
5662
  async forkSession({ parentSessionId }) {
5536
- await init_codex_app_server();
5537
- return await forkCodexSession(parentSessionId);
5663
+ const { forkCodexSession: forkCodexSession2 } = await init_codex_app_server().then(() => exports_codex_app_server);
5664
+ return await forkCodexSession2(parentSessionId);
5538
5665
  },
5539
5666
  async cleanupRollouts({ sessionIds }) {
5540
5667
  if (sessionIds.length === 0)
@@ -5715,6 +5842,11 @@ var init_maestro_registry = __esm(() => {
5715
5842
  });
5716
5843
 
5717
5844
  // ../../packages/core/src/agents/registry.ts
5845
+ var exports_registry = {};
5846
+ __export(exports_registry, {
5847
+ getRegistryOperations: () => getRegistryOperations,
5848
+ getRegistry: () => getRegistry
5849
+ });
5718
5850
  function getRegistry(agent) {
5719
5851
  return REGISTRIES[agent];
5720
5852
  }
@@ -6101,11 +6233,11 @@ var DEFAULT_CONTEXT_WARNING_RATIO = 0.8;
6101
6233
  // ../../packages/core/src/agents/claude-provider.ts
6102
6234
  var exports_claude_provider = {};
6103
6235
  __export(exports_claude_provider, {
6104
- buildClaudeDisallowedTools: () => buildClaudeDisallowedTools,
6105
- claudeBuiltInTools: () => claudeBuiltInTools,
6106
- claudeProvider: () => claudeProvider,
6236
+ substituteClaudeToolInput: () => substituteClaudeToolInput,
6107
6237
  spawnClaudeCodeProcessWithTreeKill: () => spawnClaudeCodeProcessWithTreeKill,
6108
- substituteClaudeToolInput: () => substituteClaudeToolInput
6238
+ claudeProvider: () => claudeProvider,
6239
+ claudeBuiltInTools: () => claudeBuiltInTools,
6240
+ buildClaudeDisallowedTools: () => buildClaudeDisallowedTools
6109
6241
  });
6110
6242
  import { spawn as spawn4 } from "child_process";
6111
6243
  import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
@@ -6186,8 +6318,8 @@ function buildClaudePrompt(opts) {
6186
6318
  }
6187
6319
  function watchClaudeProcessExit(signal) {
6188
6320
  let listener;
6189
- const exited = new Promise((resolve) => {
6190
- listener = resolve;
6321
+ const exited = new Promise((resolve8) => {
6322
+ listener = resolve8;
6191
6323
  const listeners = claudeProcessExitListeners.get(signal) ?? new Set;
6192
6324
  listeners.add(listener);
6193
6325
  claudeProcessExitListeners.set(signal, listeners);
@@ -6712,12 +6844,12 @@ function createCodexTreeManager(host, options = {}) {
6712
6844
  const previous = spawnChain;
6713
6845
  let release;
6714
6846
  let released = false;
6715
- spawnChain = new Promise((resolve) => {
6847
+ spawnChain = new Promise((resolve8) => {
6716
6848
  release = () => {
6717
6849
  if (released)
6718
6850
  return;
6719
6851
  released = true;
6720
- resolve();
6852
+ resolve8();
6721
6853
  };
6722
6854
  });
6723
6855
  await previous;
@@ -6824,7 +6956,7 @@ function createCodexTreeManager(host, options = {}) {
6824
6956
  return;
6825
6957
  const deadline = Date.now() + Math.max(0, graceMs);
6826
6958
  while (Date.now() < deadline && hasSurvivors(plan.targets)) {
6827
- await new Promise((resolve) => setTimeout(resolve, Math.min(100, Math.max(1, deadline - Date.now()))));
6959
+ await new Promise((resolve8) => setTimeout(resolve8, Math.min(100, Math.max(1, deadline - Date.now()))));
6828
6960
  }
6829
6961
  killStragglers(plan);
6830
6962
  }
@@ -7152,8 +7284,8 @@ async function createCodexVaultHookBridge(userId) {
7152
7284
  });
7153
7285
  restrictIpcEndpoint(socketPath);
7154
7286
  if (IS_WINDOWS2) {
7155
- await Promise.resolve().then(() => init_config());
7156
- const cached = await ensureCodexWindowsWrapperExe(join13(BINARIES_DIR, "codex-hook-wrapper"));
7287
+ const { BINARIES_DIR: BINARIES_DIR2 } = await Promise.resolve().then(() => (init_config(), exports_config));
7288
+ const cached = await ensureCodexWindowsWrapperExe(join13(BINARIES_DIR2, "codex-hook-wrapper"));
7157
7289
  await copyFile(cached, wrapperPath);
7158
7290
  await writeFile2(join13(root, "codex-with-hooks.cfg"), [process.execPath, codexCliScriptPath(), socketPath, token].join(`
7159
7291
  `), { encoding: "utf8", mode: 384 });
@@ -7725,9 +7857,9 @@ var init_tool_format = __esm(() => {
7725
7857
  // ../../packages/core/src/agents/codex-provider.ts
7726
7858
  var exports_codex_provider = {};
7727
7859
  __export(exports_codex_provider, {
7728
- codexProvider: () => codexProvider,
7860
+ toCodexMcpServers: () => toCodexMcpServers,
7729
7861
  normalizeCodexTurnUsage: () => normalizeCodexTurnUsage,
7730
- toCodexMcpServers: () => toCodexMcpServers
7862
+ codexProvider: () => codexProvider
7731
7863
  });
7732
7864
  import { execFileSync as execFileSync4 } from "child_process";
7733
7865
  import { existsSync as existsSync14, readFileSync as readFileSync11, realpathSync as realpathSync4, statSync as statSync5 } from "fs";
@@ -8027,9 +8159,9 @@ async function startStreamedWithTracking(thread, prompt, abortSignal, trackedPid
8027
8159
  nextP.catch(() => {});
8028
8160
  first = await Promise.race([nextP, startupTimeout]);
8029
8161
  } catch (err) {
8030
- const novel = findNewCodexChildren(baseline);
8031
- if (novel.length > 0) {
8032
- killCodexTrees(novel);
8162
+ const novel2 = findNewCodexChildren(baseline);
8163
+ if (novel2.length > 0) {
8164
+ killCodexTrees(novel2);
8033
8165
  }
8034
8166
  await closeIterator(iter);
8035
8167
  throw err;
@@ -8447,11 +8579,11 @@ var init_maestro_bootstrap_env = __esm(() => {
8447
8579
  // ../../packages/core/src/agents/maestro-provider.ts
8448
8580
  var exports_maestro_provider = {};
8449
8581
  __export(exports_maestro_provider, {
8450
- buildMaestroDisallowedTools: () => buildMaestroDisallowedTools,
8451
- buildMaestroToolHooks: () => buildMaestroToolHooks,
8452
- buildMaestroToolResultTruncation: () => buildMaestroToolResultTruncation,
8582
+ resolveMaestroApiKeyOverrides: () => resolveMaestroApiKeyOverrides,
8453
8583
  maestroProvider: () => maestroProvider,
8454
- resolveMaestroApiKeyOverrides: () => resolveMaestroApiKeyOverrides
8584
+ buildMaestroToolResultTruncation: () => buildMaestroToolResultTruncation,
8585
+ buildMaestroToolHooks: () => buildMaestroToolHooks,
8586
+ buildMaestroDisallowedTools: () => buildMaestroDisallowedTools
8455
8587
  });
8456
8588
  import { resolve as resolve11 } from "path";
8457
8589
  import { maestroProvider as sdkMaestroProvider, setMcpResolver } from "maestro-agent-sdk";
@@ -8579,18 +8711,18 @@ import { join as join15 } from "path";
8579
8711
  async function* dispatchAgent(opts) {
8580
8712
  switch (opts.agent) {
8581
8713
  case "claude": {
8582
- const { claudeProvider } = await loadClaudeProvider();
8583
- yield* claudeProvider(opts);
8714
+ const { claudeProvider: claudeProvider2 } = await loadClaudeProvider();
8715
+ yield* claudeProvider2(opts);
8584
8716
  return;
8585
8717
  }
8586
8718
  case "codex": {
8587
- const { codexProvider } = await loadCodexProvider();
8588
- yield* codexProvider(opts);
8719
+ const { codexProvider: codexProvider2 } = await loadCodexProvider();
8720
+ yield* codexProvider2(opts);
8589
8721
  return;
8590
8722
  }
8591
8723
  case "maestro": {
8592
- const { maestroProvider } = await loadMaestroProvider();
8593
- yield* maestroProvider(opts);
8724
+ const { maestroProvider: maestroProvider2 } = await loadMaestroProvider();
8725
+ yield* maestroProvider2(opts);
8594
8726
  return;
8595
8727
  }
8596
8728
  default: {
@@ -8621,8 +8753,8 @@ async function resolveSessionFileMissing(agent, sessionId, cwd) {
8621
8753
  return true;
8622
8754
  }
8623
8755
  case "maestro": {
8624
- const { hasActiveMaestroSession, maestroSessionPath } = await import("maestro-agent-sdk");
8625
- return !existsSync15(maestroSessionPath(sessionId)) && !hasActiveMaestroSession(sessionId);
8756
+ const { hasActiveMaestroSession, maestroSessionPath: maestroSessionPath2 } = await import("maestro-agent-sdk");
8757
+ return !existsSync15(maestroSessionPath2(sessionId)) && !hasActiveMaestroSession(sessionId);
8626
8758
  }
8627
8759
  default: {
8628
8760
  const _exhaustive = agent;
@@ -8701,6 +8833,24 @@ var init_agents = __esm(async () => {
8701
8833
  });
8702
8834
 
8703
8835
  // ../../packages/core/src/agents/model-catalog.ts
8836
+ var exports_model_catalog = {};
8837
+ __export(exports_model_catalog, {
8838
+ selectableModel: () => selectableModel,
8839
+ resolveWorkerModel: () => resolveWorkerModel,
8840
+ resolveWorkerDefaultModel: () => resolveWorkerDefaultModel,
8841
+ resolveModelForAgent: () => resolveModelForAgent,
8842
+ resolveDefaultModel: () => resolveDefaultModel,
8843
+ resolveCompactionExecution: () => resolveCompactionExecution,
8844
+ modelOwner: () => modelOwner,
8845
+ formatSelectableModel: () => formatSelectableModel,
8846
+ canonicalModelId: () => canonicalModelId,
8847
+ SELECTABLE_MODELS: () => SELECTABLE_MODELS,
8848
+ MODEL_OWNER: () => MODEL_OWNER,
8849
+ MODEL_COST_ROUTING_SUMMARY: () => MODEL_COST_ROUTING_SUMMARY,
8850
+ MODEL_COST_RESEARCHED_AT: () => MODEL_COST_RESEARCHED_AT,
8851
+ FALLBACK_ORDER: () => FALLBACK_ORDER,
8852
+ AGENT_DISPLAY_NAME: () => AGENT_DISPLAY_NAME
8853
+ });
8704
8854
  function canonicalModelId(value) {
8705
8855
  const trimmed = value.trim();
8706
8856
  const lower = trimmed.toLowerCase();
@@ -8710,6 +8860,10 @@ function formatSelectableModel(candidate) {
8710
8860
  const tier = `${candidate.intelligenceTier[0].toUpperCase()}${candidate.intelligenceTier.slice(1)}`;
8711
8861
  return `${candidate.agent} / \`${candidate.model}\` [${tier}-level]: ${candidate.routingSummary}`;
8712
8862
  }
8863
+ function selectableModel(value) {
8864
+ const canonical = canonicalModelId(value).toLowerCase();
8865
+ return SELECTABLE_MODELS.find((candidate) => candidate.model === canonical);
8866
+ }
8713
8867
  function modelOwner(model) {
8714
8868
  const lower = model.toLowerCase();
8715
8869
  if (lower.startsWith("claude-"))
@@ -8762,7 +8916,7 @@ function resolveCompactionExecution(agent, registry) {
8762
8916
  const effort = registry.validateEffort("medium") ? "medium" : registry.defaultEffort;
8763
8917
  return { model, ...effort ? { effort } : {} };
8764
8918
  }
8765
- var MODEL_OWNER, MODEL_COST_ROUTING_SUMMARY = "Cost basis (2026-09-05): Codex Pro 20x and Claude Max 20x are each $200/month; Maestro models are pay-per-token. DeepSeek Flash is cheapest. gpt-6-astra and Claude Fable 5.1 are the newest flagships, both priced at $10/M input / $50/M output.", CODEX_PRO_20X_COST = "ChatGPT Pro 20x subscription: $200/month", CODEX_COMMUNITY_WEEKLY = "Community plan-level observation: roughly 2\u20134B raw/cached tokens per week; fresh-input equivalent is much lower and unstable (low confidence)", CLAUDE_MAX_20X_COST = "Claude Max 20x subscription: $200/month", CLAUDE_COMMUNITY_SESSION = "Community observations vary from roughly 220\u2013250K locally displayed tokens per 5-hour session to billions of cache-heavy raw tokens per week; calibrated reports value a full weekly allowance around $680\u2013$1,900 at API rates. Recent heavy-model reports reach the weekly cap after about 4\u20135 full sessions (low confidence; not a token cap)", SELECTABLE_MODELS, SELECTABLE_MODEL_ALIASES, CANONICAL_MODEL_CASING, AGENT_DISPLAY_NAME;
8919
+ var MODEL_OWNER, MODEL_COST_RESEARCHED_AT = "2026-09-05", MODEL_COST_ROUTING_SUMMARY = "Cost basis (2026-09-05): Codex Pro 20x and Claude Max 20x are each $200/month; Maestro models are pay-per-token. DeepSeek Flash is cheapest. gpt-6-astra and Claude Fable 5.1 are the newest flagships, both priced at $10/M input / $50/M output.", CODEX_PRO_20X_COST = "ChatGPT Pro 20x subscription: $200/month", CODEX_COMMUNITY_WEEKLY = "Community plan-level observation: roughly 2\u20134B raw/cached tokens per week; fresh-input equivalent is much lower and unstable (low confidence)", CLAUDE_MAX_20X_COST = "Claude Max 20x subscription: $200/month", CLAUDE_COMMUNITY_SESSION = "Community observations vary from roughly 220\u2013250K locally displayed tokens per 5-hour session to billions of cache-heavy raw tokens per week; calibrated reports value a full weekly allowance around $680\u2013$1,900 at API rates. Recent heavy-model reports reach the weekly cap after about 4\u20135 full sessions (low confidence; not a token cap)", SELECTABLE_MODELS, SELECTABLE_MODEL_ALIASES, CANONICAL_MODEL_CASING, FALLBACK_ORDER, AGENT_DISPLAY_NAME;
8766
8920
  var init_model_catalog = __esm(() => {
8767
8921
  init_config();
8768
8922
  MODEL_OWNER = {
@@ -8934,6 +9088,20 @@ var init_model_catalog = __esm(() => {
8934
9088
  "glm-flash": "glm-5.3-flash"
8935
9089
  };
8936
9090
  CANONICAL_MODEL_CASING = Object.fromEntries(SELECTABLE_MODELS.map((candidate) => [candidate.model.toLowerCase(), candidate.model]));
9091
+ FALLBACK_ORDER = {
9092
+ claude: [
9093
+ { agent: "maestro", model: "deepseek-pro" },
9094
+ { agent: "codex", model: "gpt-6-luna" }
9095
+ ],
9096
+ codex: [
9097
+ { agent: "maestro", model: "deepseek-pro" },
9098
+ { agent: "claude", model: "sonnet" }
9099
+ ],
9100
+ maestro: [
9101
+ { agent: "codex", model: "gpt-6-luna" },
9102
+ { agent: "claude", model: "sonnet" }
9103
+ ]
9104
+ };
8937
9105
  AGENT_DISPLAY_NAME = {
8938
9106
  claude: "Claude",
8939
9107
  codex: "Codex",
@@ -9682,9 +9850,9 @@ function resolveTopicBrief(topicId, legacyTitle) {
9682
9850
  const titleBrief = getTopicBrief(titleKey);
9683
9851
  if (titleBrief)
9684
9852
  return { brief: titleBrief, storageKey: titleKey };
9685
- const current = getTopicBrief(topicId);
9686
- if (current)
9687
- return { brief: current, storageKey: topicId };
9853
+ const current2 = getTopicBrief(topicId);
9854
+ if (current2)
9855
+ return { brief: current2, storageKey: topicId };
9688
9856
  const legacy = titleKey === legacyTitle ? null : getTopicBrief(legacyTitle);
9689
9857
  return legacy ? { brief: legacy, storageKey: legacyTitle } : null;
9690
9858
  }
@@ -10304,6 +10472,11 @@ var init_archiver = __esm(async () => {
10304
10472
  });
10305
10473
 
10306
10474
  // ../../packages/core/src/agents/auth-check.ts
10475
+ var exports_auth_check = {};
10476
+ __export(exports_auth_check, {
10477
+ checkAgentModelAuth: () => checkAgentModelAuth,
10478
+ checkAgentAuth: () => checkAgentAuth
10479
+ });
10307
10480
  import { execFileSync as execFileSync5 } from "child_process";
10308
10481
  import { existsSync as existsSync17 } from "fs";
10309
10482
  import { homedir as homedir8, platform } from "os";
@@ -10635,8 +10808,8 @@ function createRoomQueryRegistry(host) {
10635
10808
  clearInterval(previousMonitor);
10636
10809
  activeByRoom.set(roomId, control);
10637
10810
  const monitor = setInterval(() => {
10638
- const current = activeByRoom.get(roomId);
10639
- if (!current || current.queryId !== control.queryId) {
10811
+ const current2 = activeByRoom.get(roomId);
10812
+ if (!current2 || current2.queryId !== control.queryId) {
10640
10813
  clearInterval(monitor);
10641
10814
  if (leaseMonitors.get(roomId) === monitor)
10642
10815
  leaseMonitors.delete(roomId);
@@ -10658,8 +10831,8 @@ function createRoomQueryRegistry(host) {
10658
10831
  return true;
10659
10832
  }
10660
10833
  function clear(roomId, queryId) {
10661
- const current = activeByRoom.get(roomId);
10662
- if (current?.queryId === queryId) {
10834
+ const current2 = activeByRoom.get(roomId);
10835
+ if (current2?.queryId === queryId) {
10663
10836
  activeByRoom.delete(roomId);
10664
10837
  const monitor = leaseMonitors.get(roomId);
10665
10838
  if (monitor)
@@ -10722,12 +10895,43 @@ var init_room_query_registry = () => {};
10722
10895
  var init_types2 = () => {};
10723
10896
 
10724
10897
  // ../../packages/core/src/query/active-rooms.ts
10898
+ var exports_active_rooms = {};
10899
+ __export(exports_active_rooms, {
10900
+ wsAbortReason: () => wsAbortReason,
10901
+ takeDeferredInject: () => takeDeferredInject,
10902
+ setRoomQuery: () => setRoomQuery,
10903
+ listRunningTopicQueries: () => listRunningTopicQueries,
10904
+ listRunningTopicIds: () => listRunningTopicIds,
10905
+ isolatedTurnRoomId: () => isolatedTurnRoomId,
10906
+ isUserOrigin: () => isUserOrigin,
10907
+ isTopicRunning: () => isTopicRunning,
10908
+ interSessionQueue: () => interSessionQueue,
10909
+ getRoomQueryStatus: () => getRoomQueryStatus,
10910
+ getRoomQuery: () => getRoomQuery,
10911
+ deferInject: () => deferInject,
10912
+ decideNewQuery: () => decideNewQuery,
10913
+ clearRoomQuery: () => clearRoomQuery,
10914
+ cancelDeferredInject: () => cancelDeferredInject,
10915
+ abortRoom: () => abortRoom,
10916
+ abortAllRooms: () => abortAllRooms,
10917
+ InterSessionQueue: () => InterSessionQueue,
10918
+ DeferredInjectBatcher: () => DeferredInjectBatcher
10919
+ });
10725
10920
  function getRoomQuery(roomId) {
10726
10921
  return roomQueryRegistry.get(roomId);
10727
10922
  }
10923
+ function listRunningTopicQueries() {
10924
+ return roomQueryRegistry.listRunningTopicQueries();
10925
+ }
10926
+ function listRunningTopicIds() {
10927
+ return roomQueryRegistry.listRunningTopicIds();
10928
+ }
10728
10929
  function isTopicRunning(topicId) {
10729
10930
  return roomQueryRegistry.isTopicRunning(topicId);
10730
10931
  }
10932
+ function getRoomQueryStatus(topicId, queryId) {
10933
+ return roomQueryRegistry.status(topicId, queryId);
10934
+ }
10731
10935
  function setRoomQuery(control) {
10732
10936
  return roomQueryRegistry.set(control);
10733
10937
  }
@@ -10737,6 +10941,9 @@ function clearRoomQuery(roomId, queryId) {
10737
10941
  function abortRoom(roomId, reason = "external" /* External */) {
10738
10942
  return roomQueryRegistry.abort(roomId, reason);
10739
10943
  }
10944
+ function abortAllRooms(reason = "external" /* External */) {
10945
+ return roomQueryRegistry.abortAll(reason);
10946
+ }
10740
10947
  function decideNewQuery(topicId, incomingOrigin) {
10741
10948
  return roomQueryRegistry.decide(topicId, incomingOrigin);
10742
10949
  }
@@ -10902,6 +11109,9 @@ function deferInject(inject) {
10902
11109
  function takeDeferredInject(topicId) {
10903
11110
  return interSessionQueue.dequeueAll(topicId);
10904
11111
  }
11112
+ function cancelDeferredInject(topicId, requestId) {
11113
+ return interSessionQueue.remove(topicId, requestId) !== undefined;
11114
+ }
10905
11115
  function wsAbortReason(reason) {
10906
11116
  return reason === "internal" /* Internal */ ? "superseded" : "stopped";
10907
11117
  }
@@ -11194,8 +11404,8 @@ function settleTopicArchiveJob(topicId, archivePath, success) {
11194
11404
  db.query("UPDATE api_topic_archive_jobs SET status = 'pending', updated_at = ? WHERE topic_id = ? AND archive_path = ?").run(new Date().toISOString(), topicId, archivePath);
11195
11405
  return;
11196
11406
  }
11197
- const current = getTopicArchiveState(topicId)?.lastArchivedRowid ?? 0;
11198
- setTopicArchiveState(topicId, Math.max(current, job.last_rowid), job.archive_path);
11407
+ const current2 = getTopicArchiveState(topicId)?.lastArchivedRowid ?? 0;
11408
+ setTopicArchiveState(topicId, Math.max(current2, job.last_rowid), job.archive_path);
11199
11409
  db.query("DELETE FROM api_topic_archive_jobs WHERE topic_id = ? AND archive_path = ?").run(topicId, archivePath);
11200
11410
  })();
11201
11411
  }
@@ -11867,7 +12077,7 @@ function createAskUserRuntime(host) {
11867
12077
  if (ask.expired || ask.selectedLabel) {
11868
12078
  return { ok: false, error: "This question is no longer awaiting an answer." };
11869
12079
  }
11870
- if (!ask.choices.some((choice) => choice.label === label)) {
12080
+ if (!ask.choices.some((choice2) => choice2.label === label)) {
11871
12081
  return { ok: false, error: "Invalid choice." };
11872
12082
  }
11873
12083
  const pending = pendingAsks.get(messageId);
@@ -12020,8 +12230,8 @@ function createAskUserRuntime(host) {
12020
12230
  return errorResult(`Error: failed to persist ask_user_question: ${error instanceof Error ? error.message : String(error)}`);
12021
12231
  }
12022
12232
  let resolveAnswer;
12023
- const promise = new Promise((resolve) => {
12024
- resolveAnswer = resolve;
12233
+ const promise = new Promise((resolve13) => {
12234
+ resolveAnswer = resolve13;
12025
12235
  });
12026
12236
  pendingAsks.set(message.id, {
12027
12237
  topicId: ctx.topicId,
@@ -12223,8 +12433,8 @@ var init_self_schedules = __esm(async () => {
12223
12433
  });
12224
12434
 
12225
12435
  // ../../packages/core/src/platform/playwright/manager-utils.ts
12226
- function isLiveOwnedChildProcess(current, expected) {
12227
- return current?.process === expected && expected.exitCode === null && expected.signalCode === null && !expected.killed;
12436
+ function isLiveOwnedChildProcess(current2, expected) {
12437
+ return current2?.process === expected && expected.exitCode === null && expected.signalCode === null && !expected.killed;
12228
12438
  }
12229
12439
  function matchesSpawnedBrowserHealth(health, expectedSpawnNonce) {
12230
12440
  if (!health || typeof health !== "object")
@@ -12468,10 +12678,10 @@ function findExecutableOnPath(command, environment = process.env) {
12468
12678
  return null;
12469
12679
  }
12470
12680
  function resolveHeadedPlaywrightSpawn(command, args, options = {}) {
12471
- const platform = options.platform ?? process.platform;
12681
+ const platform2 = options.platform ?? process.platform;
12472
12682
  const environment = options.environment ?? process.env;
12473
12683
  const hasDisplay = Boolean(environment.DISPLAY?.trim() || environment.WAYLAND_DISPLAY?.trim());
12474
- if (platform !== "linux" || hasDisplay) {
12684
+ if (platform2 !== "linux" || hasDisplay) {
12475
12685
  return { command, args: [...args], virtualDisplay: false };
12476
12686
  }
12477
12687
  const xvfbRun = (options.findExecutable ?? findExecutableOnPath)("xvfb-run", environment);
@@ -12520,7 +12730,7 @@ async function probeMcpTransport(transport, options = {}) {
12520
12730
  }
12521
12731
  }
12522
12732
  async function probePlaywrightMcpTransports(port, capability, fetchImpl = fetch) {
12523
- const query = new URLSearchParams({ owner: PROBE_OWNER });
12733
+ const query2 = new URLSearchParams({ owner: PROBE_OWNER });
12524
12734
  const baseUrl = `http://127.0.0.1:${port}`;
12525
12735
  const ownerCapability = browserOwnerCapability(capability, PROBE_OWNER);
12526
12736
  const capabilityHeaders = { "X-Browser-Capability": ownerCapability };
@@ -12529,14 +12739,14 @@ async function probePlaywrightMcpTransports(port, capability, fetchImpl = fetch)
12529
12739
  headers.set("X-Browser-Capability", ownerCapability);
12530
12740
  return fetchImpl(input, { ...init, headers });
12531
12741
  };
12532
- const sseTransport = new SSEClientTransport(new URL(`${baseUrl}/sse?${query}`), {
12742
+ const sseTransport = new SSEClientTransport(new URL(`${baseUrl}/sse?${query2}`), {
12533
12743
  fetch: authenticatedFetch,
12534
12744
  eventSourceInit: { fetch: authenticatedFetch },
12535
12745
  requestInit: { headers: capabilityHeaders }
12536
12746
  });
12537
12747
  if (!await probeMcpTransport(sseTransport))
12538
12748
  return false;
12539
- const streamableTransport = new StreamableHTTPClientTransport(new URL(`${baseUrl}/mcp?${query}`), {
12749
+ const streamableTransport = new StreamableHTTPClientTransport(new URL(`${baseUrl}/mcp?${query2}`), {
12540
12750
  fetch: authenticatedFetch,
12541
12751
  requestInit: { headers: capabilityHeaders }
12542
12752
  });
@@ -12666,9 +12876,9 @@ async function createBrowserVaultBroker(userId) {
12666
12876
  if (typeof request.tool !== "string")
12667
12877
  return { id, ok: false, error: "invalid tool" };
12668
12878
  const leaseCutoff = Date.now() - LEASE_TTL_MS;
12669
- for (const [lease, binding] of leases) {
12879
+ for (const [lease2, binding] of leases) {
12670
12880
  if (binding.createdAt < leaseCutoff)
12671
- leases.delete(lease);
12881
+ leases.delete(lease2);
12672
12882
  }
12673
12883
  if (leases.size >= MAX_ACTIVE_LEASES) {
12674
12884
  return { id, ok: false, error: "too many active leases" };
@@ -12802,6 +13012,16 @@ function getTopicBrowserProfile(topicId) {
12802
13012
  const value = db.query("SELECT browser_profile FROM api_topics WHERE id = ?").get(topicId)?.browser_profile;
12803
13013
  return value || DEFAULT_BROWSER_PROFILE;
12804
13014
  }
13015
+ function isBrowserConnectPort(value) {
13016
+ return Number.isInteger(value) && value >= 1024 && value <= 65535;
13017
+ }
13018
+ function getTopicBrowserConnectPort(topicId) {
13019
+ const value = db.query("SELECT browser_connect_port FROM api_topics WHERE id = ?").get(topicId)?.browser_connect_port;
13020
+ return isBrowserConnectPort(value) ? value : undefined;
13021
+ }
13022
+ function setTopicBrowserConnectPort(topicId, port) {
13023
+ db.query("UPDATE api_topics SET browser_connect_port = ? WHERE id = ?").run(port, topicId);
13024
+ }
12805
13025
  function hasBrowserProfileTopic(topicId) {
12806
13026
  return Boolean(db.query("SELECT id FROM api_topics WHERE id = ?").get(topicId));
12807
13027
  }
@@ -12878,6 +13098,9 @@ function resolvePlaywrightTopicBinding(userId, topic) {
12878
13098
  function defaultTopicBinding(userId, topic) {
12879
13099
  if (!topic)
12880
13100
  return managerHost.resolveNamedBinding(userId, "default");
13101
+ const connectPort = getTopicBrowserConnectPort(topic);
13102
+ if (connectPort !== undefined)
13103
+ return connectBinding(connectPort);
12881
13104
  const ownerId = getBrowserProfileOwner(topic, userId);
12882
13105
  const profile = getTopicBrowserProfile(topic);
12883
13106
  return managerHost.resolveNamedBinding(ownerId, profile);
@@ -12891,6 +13114,26 @@ function validateProfileBinding(binding) {
12891
13114
  }
12892
13115
  return Object.freeze({ ...binding });
12893
13116
  }
13117
+ function connectBinding(port) {
13118
+ return { instanceKey: `connect:${port}`, ownerId: "local", profile: `connect-${port}` };
13119
+ }
13120
+ function parseConnectInstanceKey(instanceKey) {
13121
+ const match = /^connect:(\d+)$/.exec(instanceKey);
13122
+ return match ? Number(match[1]) : undefined;
13123
+ }
13124
+ function browserRsArgs(instanceKey, port, userDataDir) {
13125
+ const connectPort = parseConnectInstanceKey(instanceKey);
13126
+ return [
13127
+ "--port",
13128
+ String(port),
13129
+ "--host",
13130
+ "127.0.0.1",
13131
+ "--headed",
13132
+ "--user-data-dir",
13133
+ userDataDir,
13134
+ ...connectPort === undefined ? [] : ["--connect", String(connectPort)]
13135
+ ];
13136
+ }
12894
13137
  function defaultNamedBinding(_ownerId, rawProfile) {
12895
13138
  const profile = normalizeBrowserProfileName(rawProfile);
12896
13139
  const instanceKey = `profile:${profile}`;
@@ -12910,6 +13153,9 @@ function defaultChildEnvironment(context) {
12910
13153
  return childEnvironment;
12911
13154
  }
12912
13155
  function parseInstanceKey(instanceKey) {
13156
+ const connectPort = parseConnectInstanceKey(instanceKey);
13157
+ if (connectPort !== undefined)
13158
+ return { ownerId: "local", profile: `_connect-${connectPort}` };
12913
13159
  const shared = /^profile:(.+)$/.exec(instanceKey);
12914
13160
  if (shared && !shared[1].includes(":")) {
12915
13161
  return { ownerId: "local", profile: normalizeBrowserProfileName(shared[1]) };
@@ -13137,15 +13383,7 @@ async function spawnPlaywright(instanceKey, ownerId, reservedPort, browserBin =
13137
13383
  const userDataDir = resolveUserDataDir(instanceKey);
13138
13384
  const port = reservedPort ?? await allocatePort();
13139
13385
  mkdirSync11(userDataDir, { recursive: true });
13140
- const mcpArgs = [
13141
- "--port",
13142
- String(port),
13143
- "--host",
13144
- "127.0.0.1",
13145
- "--headed",
13146
- "--user-data-dir",
13147
- userDataDir
13148
- ];
13386
+ const mcpArgs = browserRsArgs(instanceKey, port, userDataDir);
13149
13387
  const proxy = managerHost.resolveProxy();
13150
13388
  if (proxy) {
13151
13389
  releasePort(port);
@@ -13201,9 +13439,9 @@ async function spawnPlaywright(instanceKey, ownerId, reservedPort, browserBin =
13201
13439
  const stderrTail = captureBoundedStderr(proc);
13202
13440
  const startup = watchChildStartup(proc, stderrTail);
13203
13441
  const reapCrashedBrowser = () => {
13204
- const userDataDir = resolveUserDataDir(instanceKey);
13205
- managerHost.cleanupBrowserProcessesForDataDir(userDataDir);
13206
- cleanSingletonFiles(userDataDir);
13442
+ const userDataDir2 = resolveUserDataDir(instanceKey);
13443
+ managerHost.cleanupBrowserProcessesForDataDir(userDataDir2);
13444
+ cleanSingletonFiles(userDataDir2);
13207
13445
  };
13208
13446
  proc.once("error", (err) => {
13209
13447
  logger.error({ err, instanceKey, stderr: stderrTail() || undefined }, "Playwright MCP error");
@@ -13272,8 +13510,8 @@ ${stderrTail()}` : ""));
13272
13510
  }
13273
13511
  async function supportsOwnerCleanup(port, capability) {
13274
13512
  try {
13275
- const query = new URLSearchParams({ owner: "__negotium_capability_probe__" });
13276
- const response = await fetch(`http://127.0.0.1:${port}/owners?${query}`, {
13513
+ const query2 = new URLSearchParams({ owner: "__negotium_capability_probe__" });
13514
+ const response = await fetch(`http://127.0.0.1:${port}/owners?${query2}`, {
13277
13515
  method: "DELETE",
13278
13516
  headers: {
13279
13517
  "X-Browser-Capability": capability
@@ -13333,8 +13571,12 @@ async function waitForPortRelease(port, timeoutMs = 3000) {
13333
13571
  await delay(200);
13334
13572
  }
13335
13573
  }
13336
- async function closeBrowserOwnerTabs(ownerId, rawProfile, owner) {
13337
- const binding = resolvePlaywrightProfileBinding(ownerId, rawProfile);
13574
+ function closeTopicBrowserTabs(userId, topicId) {
13575
+ const connectPort = getTopicBrowserConnectPort(topicId);
13576
+ const binding = connectPort === undefined ? resolvePlaywrightProfileBinding(getBrowserProfileOwner(topicId, userId), getTopicBrowserProfile(topicId)) : connectBinding(connectPort);
13577
+ return closeBindingOwnerTabs(binding, `topic:${topicId}`);
13578
+ }
13579
+ async function closeBindingOwnerTabs(binding, owner) {
13338
13580
  const instanceKey = binding.instanceKey;
13339
13581
  const inProgress = spawning.get(instanceKey);
13340
13582
  if (inProgress)
@@ -13344,8 +13586,8 @@ async function closeBrowserOwnerTabs(ownerId, rawProfile, owner) {
13344
13586
  if (!instance)
13345
13587
  return 0;
13346
13588
  const port = instance.port;
13347
- const query = new URLSearchParams({ owner });
13348
- const response = await fetch(`http://127.0.0.1:${port}/owners?${query}`, {
13589
+ const query2 = new URLSearchParams({ owner });
13590
+ const response = await fetch(`http://127.0.0.1:${port}/owners?${query2}`, {
13349
13591
  method: "DELETE",
13350
13592
  headers: {
13351
13593
  "X-Browser-Capability": instance.capability
@@ -13408,6 +13650,7 @@ async function cloneProfileForChild(opts) {
13408
13650
  if (srcOwner === dstOwner && hasBrowserProfileTopic(opts.dstTopic)) {
13409
13651
  const profile = getTopicBrowserProfile(opts.srcTopic);
13410
13652
  assignTopicBrowserProfile({ topicId: opts.dstTopic, actorUserId: dstOwner, profile });
13653
+ setTopicBrowserConnectPort(opts.dstTopic, getTopicBrowserConnectPort(opts.srcTopic) ?? null);
13411
13654
  const binding = resolvePlaywrightProfileBinding(srcOwner, profile);
13412
13655
  const sharedDir = resolveUserDataDir(binding.instanceKey);
13413
13656
  return {
@@ -13424,6 +13667,9 @@ async function cloneProfileForChild(opts) {
13424
13667
  if (srcDir === dstDir) {
13425
13668
  return { copied: false, srcDir, dstDir, reason: "same-dir" };
13426
13669
  }
13670
+ if (parseConnectInstanceKey(srcKey) !== undefined || parseConnectInstanceKey(dstKey) !== undefined) {
13671
+ return { copied: false, srcDir, dstDir, reason: "connect-binding" };
13672
+ }
13427
13673
  return withPlaywrightInstanceMaintenance([srcKey, dstKey], async () => {
13428
13674
  const parentWasLive = instances.has(srcKey);
13429
13675
  if (parentWasLive) {
@@ -14040,7 +14286,7 @@ async function runIdleCompactForTopic(topicId, userId, options = {}) {
14040
14286
  return "below-threshold";
14041
14287
  }
14042
14288
  const compact = options.compact ?? (async (id, actorId, reason) => {
14043
- await init_session();
14289
+ const { compactTopicSession } = await init_session().then(() => exports_session);
14044
14290
  return compactTopicSession(id, actorId, reason, { preemptive: false });
14045
14291
  });
14046
14292
  try {
@@ -14240,40 +14486,40 @@ function beginTransientBackgroundSession(userId, session) {
14240
14486
  update(status, step) {
14241
14487
  if (finished)
14242
14488
  return;
14243
- const current = transientSessions.get(record.id);
14244
- if (current !== record)
14489
+ const current2 = transientSessions.get(record.id);
14490
+ if (current2 !== record)
14245
14491
  return;
14246
14492
  const nextStatus = text(status, 160);
14247
14493
  if (nextStatus)
14248
- current.status = nextStatus;
14494
+ current2.status = nextStatus;
14249
14495
  const nextStep = text(step);
14250
- if (nextStep && current.steps.at(-1) !== nextStep) {
14251
- current.steps.push(nextStep);
14496
+ if (nextStep && current2.steps.at(-1) !== nextStep) {
14497
+ current2.steps.push(nextStep);
14252
14498
  }
14253
14499
  },
14254
14500
  setOutput(output) {
14255
14501
  if (finished)
14256
14502
  return;
14257
- const current = transientSessions.get(record.id);
14258
- if (current !== record)
14503
+ const current2 = transientSessions.get(record.id);
14504
+ if (current2 !== record)
14259
14505
  return;
14260
- current.output = output;
14506
+ current2.output = output;
14261
14507
  },
14262
14508
  finish(status, step) {
14263
14509
  if (finished)
14264
14510
  return;
14265
14511
  this.update(status ?? record.status, step);
14266
14512
  finished = true;
14267
- const current = transientSessions.get(record.id);
14268
- if (current !== record)
14513
+ const current2 = transientSessions.get(record.id);
14514
+ if (current2 !== record)
14269
14515
  return;
14270
- current.active = false;
14271
- current.expiresAt = Date.now() + Math.max(0, retentionMs);
14272
- current.expiryTimer = setTimeout(() => {
14516
+ current2.active = false;
14517
+ current2.expiresAt = Date.now() + Math.max(0, retentionMs);
14518
+ current2.expiryTimer = setTimeout(() => {
14273
14519
  if (transientSessions.get(record.id) === record)
14274
14520
  transientSessions.delete(record.id);
14275
14521
  }, Math.max(0, retentionMs));
14276
- current.expiryTimer.unref?.();
14522
+ current2.expiryTimer.unref?.();
14277
14523
  }
14278
14524
  };
14279
14525
  }
@@ -14531,8 +14777,8 @@ function markRuntimeUserTurnMessagesLogged(topicId, requestId, ownerId, loggedUs
14531
14777
  return false;
14532
14778
  return db.transaction(() => {
14533
14779
  const requests = db.query("SELECT * FROM runtime_user_turn_requests WHERE topic_id = ? ORDER BY created_at ASC, rowid ASC").all(topicId).map(rowToRequest);
14534
- const hasLoggedPrefix = (request) => loggedUserMessages.length <= request.userMessages.length && loggedUserMessages.every((message, index) => {
14535
- const candidate = request.userMessages[index];
14780
+ const hasLoggedPrefix = (request2) => loggedUserMessages.length <= request2.userMessages.length && loggedUserMessages.every((message, index) => {
14781
+ const candidate = request2.userMessages[index];
14536
14782
  return candidate?.prompt === message.prompt && candidate.actorUserId === message.actorUserId && candidate.actorLabel === message.actorLabel && JSON.stringify(candidate.attachments ?? []) === JSON.stringify(message.attachments ?? []);
14537
14783
  });
14538
14784
  const request = requests.find((candidate) => candidate.requestId === requestId && candidate.claimedBy === ownerId && hasLoggedPrefix(candidate)) ?? requests.find((candidate) => candidate.execution?.supersededRequestIds?.includes(requestId) && hasLoggedPrefix(candidate));
@@ -14550,6 +14796,60 @@ function markRuntimeUserTurnMessagesLogged(topicId, requestId, ownerId, loggedUs
14550
14796
  return result.changes === 1;
14551
14797
  }).immediate();
14552
14798
  }
14799
+ function claimNextRuntimeUserTurnRequest(ownerId, now = Date.now()) {
14800
+ return db.transaction(() => {
14801
+ const row = db.query(`SELECT r.*
14802
+ FROM runtime_user_turn_requests r
14803
+ LEFT JOIN runtime_turn_leases l ON l.topic_id = r.topic_id
14804
+ LEFT JOIN runtime_topic_state s ON s.topic_id = r.topic_id
14805
+ WHERE (l.topic_id IS NULL OR l.heartbeat_at < ?)
14806
+ AND (s.topic_id IS NULL OR s.maintenance = 0 OR s.heartbeat_at < ?)
14807
+ AND r.topic_epoch = COALESCE(s.epoch, 0)
14808
+ AND NOT EXISTS (
14809
+ SELECT 1
14810
+ FROM runtime_user_turn_requests active
14811
+ WHERE active.topic_id = r.topic_id
14812
+ AND active.request_id <> r.request_id
14813
+ AND active.claimed_at IS NOT NULL
14814
+ AND active.claimed_at >= ?
14815
+ )
14816
+ AND (
14817
+ (r.status = 'pending' AND (r.claimed_at IS NULL OR r.claimed_at < ?))
14818
+ OR (r.status = 'running' AND (r.claimed_at IS NULL OR r.claimed_at < ?))
14819
+ )
14820
+ ORDER BY r.created_at ASC, r.rowid ASC
14821
+ LIMIT 1`).get(now - TURN_LEASE_STALE_MS, now - TOPIC_MAINTENANCE_STALE_MS, now - REQUEST_CLAIM_STALE_MS, now - REQUEST_CLAIM_STALE_MS, now - REQUEST_CLAIM_STALE_MS);
14822
+ if (!row)
14823
+ return null;
14824
+ const updated = db.query(`UPDATE runtime_user_turn_requests
14825
+ SET claimed_by = ?, claimed_at = ?
14826
+ WHERE request_id = ? AND topic_id = ?
14827
+ AND (
14828
+ (status = 'pending' AND (claimed_at IS NULL OR claimed_at < ?))
14829
+ OR (status = 'running' AND (claimed_at IS NULL OR claimed_at < ?))
14830
+ )`).run(ownerId, now, row.request_id, row.topic_id, now - REQUEST_CLAIM_STALE_MS, now - REQUEST_CLAIM_STALE_MS);
14831
+ if (Number(updated.changes ?? 0) === 0)
14832
+ return null;
14833
+ return rowToRequest({ ...row, claimed_by: ownerId, claimed_at: now });
14834
+ }).immediate();
14835
+ }
14836
+ function markRuntimeUserTurnRunning(topicId, requestId, ownerId, queryId) {
14837
+ const result = db.query(`UPDATE runtime_user_turn_requests
14838
+ SET status = 'running', running_query_id = ?, claimed_at = ?
14839
+ WHERE topic_id = ? AND request_id = ? AND claimed_by = ?`).run(queryId, Date.now(), topicId, requestId, ownerId);
14840
+ return Number(result.changes ?? 0) > 0;
14841
+ }
14842
+ function releaseRuntimeUserTurnClaim(topicId, requestId, ownerId) {
14843
+ const result = db.query(`UPDATE runtime_user_turn_requests
14844
+ SET status = 'pending', claimed_by = NULL, claimed_at = NULL, running_query_id = NULL
14845
+ WHERE topic_id = ? AND request_id = ? AND claimed_by = ?`).run(topicId, requestId, ownerId);
14846
+ return Number(result.changes ?? 0) > 0;
14847
+ }
14848
+ function completeRuntimeUserTurnRequest(topicId, requestId, ownerId) {
14849
+ const result = db.query(`DELETE FROM runtime_user_turn_requests
14850
+ WHERE topic_id = ? AND request_id = ? AND claimed_by = ?`).run(topicId, requestId, ownerId);
14851
+ return Number(result.changes ?? 0) > 0;
14852
+ }
14553
14853
  function cancelRuntimeUserTurnRequestsBeforeEpoch(topicId, epoch) {
14554
14854
  const rows = db.query("SELECT request_id FROM runtime_user_turn_requests WHERE topic_id = ? AND topic_epoch < ?").all(topicId, epoch);
14555
14855
  db.query("DELETE FROM runtime_user_turn_requests WHERE topic_id = ? AND topic_epoch < ?").run(topicId, epoch);
@@ -14587,10 +14887,36 @@ var init_runtime_turn_requests = __esm(async () => {
14587
14887
  });
14588
14888
 
14589
14889
  // ../../packages/core/src/topics/session.ts
14890
+ var exports_session = {};
14891
+ __export(exports_session, {
14892
+ splitCompactionPairs: () => splitCompactionPairs,
14893
+ shouldUseCompactionLog: () => shouldUseCompactionLog,
14894
+ shouldCompactForkEntries: () => shouldCompactForkEntries,
14895
+ restartTopicSession: () => restartTopicSession,
14896
+ createCompactedRolloutEntries: () => createCompactedRolloutEntries,
14897
+ compactTopicSession: () => compactTopicSession,
14898
+ COMPACTION_RETAINED_TAIL_TOKENS: () => COMPACTION_RETAINED_TAIL_TOKENS,
14899
+ AUTO_FORK_COMPACTION_TOKENS: () => AUTO_FORK_COMPACTION_TOKENS
14900
+ });
14590
14901
  import { randomUUID as randomUUID12 } from "crypto";
14591
14902
  import { mkdtempSync as mkdtempSync2, rmSync as rmSync4, writeFileSync as writeFileSync12 } from "fs";
14592
14903
  import { tmpdir as tmpdir4 } from "os";
14593
14904
  import { join as join23 } from "path";
14905
+ async function waitForMemoryArchive(settled, timeoutMs) {
14906
+ let timer;
14907
+ try {
14908
+ return await Promise.race([
14909
+ settled.then(() => true),
14910
+ new Promise((resolve17) => {
14911
+ timer = setTimeout(() => resolve17(false), timeoutMs);
14912
+ timer.unref?.();
14913
+ })
14914
+ ]);
14915
+ } finally {
14916
+ if (timer)
14917
+ clearTimeout(timer);
14918
+ }
14919
+ }
14594
14920
  async function fenceTopicWork(topicId, maintenance) {
14595
14921
  for (const queryId of cancelRuntimeUserTurnRequestsBeforeEpoch(topicId, maintenance.epoch)) {
14596
14922
  WsHub.get().broadcastAborted(topicId, queryId, "stopped");
@@ -14615,6 +14941,97 @@ function hasTopicWorkInFlight(topicId) {
14615
14941
  function topicIsQuiescedForNonPreemptiveWork(topicId) {
14616
14942
  return !hasTopicWorkInFlight(topicId);
14617
14943
  }
14944
+ async function restartTopicSession(topicId, userId, reason = "topic-session-restart", options = {}) {
14945
+ const topic = getTopic(topicId);
14946
+ if (!topic)
14947
+ return { text: "Topic not found.", isError: true };
14948
+ if (isLegacySharedGeneral(topic.id)) {
14949
+ return { text: "The legacy shared General session cannot be reset.", isError: true };
14950
+ }
14951
+ const owner = topic.participants.some((participant) => participant.userId === userId && participant.role === "owner");
14952
+ if (!owner)
14953
+ return { text: "Only the topic owner can reset the session.", isError: true };
14954
+ const maintenance = beginRuntimeTopicMaintenance(topicId);
14955
+ if (!maintenance)
14956
+ return { text: "Topic maintenance is already in progress.", isError: true };
14957
+ try {
14958
+ const fenceError = await fenceTopicWork(topicId, maintenance);
14959
+ if (fenceError)
14960
+ return { text: fenceError, isError: true };
14961
+ cancelIdleArchiveForTopic(topicId);
14962
+ cancelIdleCompactForTopic(topicId);
14963
+ const rawArchivePaths = [];
14964
+ try {
14965
+ for (const participantUserId of new Set([
14966
+ userId,
14967
+ ...topic.participants.map((participant) => participant.userId)
14968
+ ])) {
14969
+ const archived = archiveConversationEvents(topicId, topic.title, participantUserId, {
14970
+ reason: "reset"
14971
+ });
14972
+ if (archived)
14973
+ rawArchivePaths.push(archived.path);
14974
+ }
14975
+ } catch (error) {
14976
+ return {
14977
+ text: `Session reset could not archive the raw conversation: ${error instanceof Error ? error.message : String(error)}`,
14978
+ isError: true
14979
+ };
14980
+ }
14981
+ let settleMemoryArchive;
14982
+ const memoryArchiveSettled = new Promise((resolve17) => {
14983
+ settleMemoryArchive = resolve17;
14984
+ });
14985
+ const archiveStatus = (options.archiveMemory ?? archiveActiveTopicForMemory)(topicId, options.memoryUserId ?? userId, {
14986
+ reason: "reset",
14987
+ minMessages: 1,
14988
+ minExchanges: MIN_MEMORY_ARCHIVE_EXCHANGES,
14989
+ allowMentionOnly: true,
14990
+ skipBusyCheck: true,
14991
+ rawArchivePaths,
14992
+ onSettled: () => settleMemoryArchive?.()
14993
+ });
14994
+ if (archiveStatus === "archived") {
14995
+ const archiveFinished = await waitForMemoryArchive(memoryArchiveSettled, options.memoryArchiveWaitMs ?? RESET_MEMORY_ARCHIVE_WAIT_MS);
14996
+ if (!archiveFinished) {
14997
+ return {
14998
+ text: "Memory archiving did not finish in time. The session was not reset.",
14999
+ isError: true
15000
+ };
15001
+ }
15002
+ }
15003
+ if (!maintenance.isOwned()) {
15004
+ return { text: "Topic maintenance ownership was lost. Try again.", isError: true };
15005
+ }
15006
+ const sessionId = getTopicSessionId(topicId);
15007
+ const purgeLogs = options.purgeLogs ?? purgeTopicLogs;
15008
+ const participantUserIds = Array.from(new Set([userId, ...topic.participants.map((participant) => participant.userId)]));
15009
+ for (const [index, participantUserId] of participantUserIds.entries()) {
15010
+ let purged = false;
15011
+ try {
15012
+ purged = await purgeLogs({
15013
+ userId: participantUserId,
15014
+ topicName: topic.title,
15015
+ cwd: resolveTopicWorkspaceDir(topicId),
15016
+ extraSessions: index === 0 && topic.agent && sessionId ? [{ agent: topic.agent, sessionId }] : []
15017
+ });
15018
+ } catch (error) {
15019
+ logger.warn({ err: error, topicId, userId: participantUserId }, "restartTopicSession: participant context cleanup failed");
15020
+ }
15021
+ if (!purged) {
15022
+ return {
15023
+ text: "Session reset could not remove all provider context. The current session was kept.",
15024
+ isError: true
15025
+ };
15026
+ }
15027
+ }
15028
+ clearTopicSessionId(topicId, reason);
15029
+ clearQueryUsageAlert(userId, topicId);
15030
+ return { text: `Session reset for "${topic.title}". The next message starts fresh.` };
15031
+ } finally {
15032
+ maintenance.finish();
15033
+ }
15034
+ }
14618
15035
  function previousCompactedSummary(entries) {
14619
15036
  for (let index = entries.length - 2;index >= 0; index -= 1) {
14620
15037
  const request = entries[index]?.event;
@@ -14629,9 +15046,9 @@ The assistant response is the authoritative summary of all earlier context.` &&
14629
15046
  function withoutCompactionSentinels(entries) {
14630
15047
  const filtered = [];
14631
15048
  for (let index = 0;index < entries.length; index++) {
14632
- const current = entries[index]?.event;
15049
+ const current2 = entries[index]?.event;
14633
15050
  const next = entries[index + 1]?.event;
14634
- if (current?.type === "user_message" && current.synthetic === "compaction" && next?.type === "result") {
15051
+ if (current2?.type === "user_message" && current2.synthetic === "compaction" && next?.type === "result") {
14635
15052
  index += 1;
14636
15053
  continue;
14637
15054
  }
@@ -14681,18 +15098,18 @@ function retainedPairEntries(agent, pairs) {
14681
15098
  }
14682
15099
  return entries;
14683
15100
  }
14684
- function fitCompactionChunk(text, limit) {
14685
- if (text.length <= limit)
14686
- return text;
15101
+ function fitCompactionChunk(text2, limit) {
15102
+ if (text2.length <= limit)
15103
+ return text2;
14687
15104
  const marker = `
14688
15105
  [\u2026]
14689
15106
  `;
14690
15107
  if (limit <= marker.length)
14691
- return text.slice(0, limit);
15108
+ return text2.slice(0, limit);
14692
15109
  const available = limit - marker.length;
14693
15110
  const headChars = Math.ceil(available * 0.6);
14694
15111
  const tailChars = available - headChars;
14695
- return `${text.slice(0, headChars)}${marker}${text.slice(-tailChars)}`;
15112
+ return `${text2.slice(0, headChars)}${marker}${text2.slice(-tailChars)}`;
14696
15113
  }
14697
15114
  function buildCompactionSource(topicId, userId, entries, visibleMessages, providerPairs) {
14698
15115
  const sections = [];
@@ -15093,9 +15510,9 @@ async function compactTopicSession(topicId, userId, reason = "topic-session-comp
15093
15510
  const compactionExecution = resolveCompactionExecution(agent, registry);
15094
15511
  const cwd = resolveTopicWorkspaceDir(topicId);
15095
15512
  const oldEntries = readConversation(userId, topic.title);
15096
- let compactEntries;
15513
+ let compactEntries2;
15097
15514
  try {
15098
- compactEntries = await createCompactedRolloutEntries({
15515
+ compactEntries2 = await createCompactedRolloutEntries({
15099
15516
  topicId,
15100
15517
  topicTitle: topic.title,
15101
15518
  userId,
@@ -15121,7 +15538,7 @@ async function compactTopicSession(topicId, userId, reason = "topic-session-comp
15121
15538
  try {
15122
15539
  replacement = getRegistryOperations(agent).writeRollout({
15123
15540
  cwd,
15124
- entries: compactEntries,
15541
+ entries: compactEntries2,
15125
15542
  model,
15126
15543
  ...effort ? { effort } : {}
15127
15544
  });
@@ -15151,7 +15568,7 @@ async function compactTopicSession(topicId, userId, reason = "topic-session-comp
15151
15568
  }
15152
15569
  try {
15153
15570
  replaceConversationStrict(userId, topic.title, [
15154
- ...compactEntries,
15571
+ ...compactEntries2,
15155
15572
  ...priorSessionEntries,
15156
15573
  replacementSessionEntry
15157
15574
  ]);
@@ -15188,7 +15605,7 @@ async function compactTopicSession(topicId, userId, reason = "topic-session-comp
15188
15605
  } else {
15189
15606
  try {
15190
15607
  replaceConversationStrict(userId, topic.title, [
15191
- ...compactEntries,
15608
+ ...compactEntries2,
15192
15609
  replacementSessionEntry
15193
15610
  ]);
15194
15611
  } catch (manifestError) {
@@ -15242,11 +15659,45 @@ var init_session = __esm(async () => {
15242
15659
  });
15243
15660
 
15244
15661
  // ../../packages/core/src/topics/derive.ts
15662
+ var exports_derive = {};
15663
+ __export(exports_derive, {
15664
+ updateTopic: () => updateTopic,
15665
+ isParticipant: () => isParticipant,
15666
+ getVisibleTopics: () => getVisibleTopics,
15667
+ getTopics: () => getTopics,
15668
+ createDerivedTopic: () => createDerivedTopic,
15669
+ TopicTitleConflictError: () => TopicTitleConflictError,
15670
+ TopicForkCompactionError: () => TopicForkCompactionError,
15671
+ TopicDeriveBusyError: () => TopicDeriveBusyError
15672
+ });
15245
15673
  import { createHash as createHash9, randomUUID as randomUUID13 } from "crypto";
15246
15674
  import { mkdirSync as mkdirSync14, rmSync as rmSync5, unlinkSync as unlinkSync13 } from "fs";
15247
15675
  function getTopics(opts = {}) {
15248
15676
  return listTopics(opts).filter((topic) => !isLegacySharedGeneral(topic.id));
15249
15677
  }
15678
+ function getVisibleTopics(opts = {}) {
15679
+ return getTopics(opts).filter(isTopicVisible).map((topic) => {
15680
+ if (!topic.agent)
15681
+ return topic;
15682
+ const registry = getRegistry(topic.agent);
15683
+ const config = getApiTopicConfig(topic.id);
15684
+ const requestedEffort = config?.effort ?? topic.defaultEffort;
15685
+ return {
15686
+ ...topic,
15687
+ effectiveModel: resolveModelForAgent(topic.agent, config?.model ?? topic.defaultModel, registry),
15688
+ effectiveEffort: requestedEffort && registry.validateEffort(requestedEffort) ? requestedEffort : registry.defaultEffort
15689
+ };
15690
+ });
15691
+ }
15692
+ function updateTopic(topicId, patch) {
15693
+ const topic = getTopic(topicId);
15694
+ if (!topic)
15695
+ return false;
15696
+ Object.assign(topic, patch);
15697
+ upsertTopic(topic);
15698
+ WsHub.get().broadcastTopicUpdated(topicId);
15699
+ return true;
15700
+ }
15250
15701
  function isParticipant(topic, userId) {
15251
15702
  return topic.participants.some((p) => p.userId === userId);
15252
15703
  }
@@ -15662,9 +16113,9 @@ function subagentLineageTopicIds(currentTopicId) {
15662
16113
  const children = new Set;
15663
16114
  if (!currentTopicId)
15664
16115
  return { reachable, children };
15665
- const current = getTopic(currentTopicId);
15666
- if (current?.isSubagent && current.parentTopicId) {
15667
- reachable.add(current.parentTopicId);
16116
+ const current2 = getTopic(currentTopicId);
16117
+ if (current2?.isSubagent && current2.parentTopicId) {
16118
+ reachable.add(current2.parentTopicId);
15668
16119
  for (const id of listSubagentTellTargetIds(currentTopicId))
15669
16120
  reachable.add(id);
15670
16121
  }
@@ -15790,9 +16241,9 @@ function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
15790
16241
  try {
15791
16242
  unlinkSync15(path);
15792
16243
  deleted++;
15793
- } catch (err) {
15794
- if (err?.code !== "ENOENT") {
15795
- logger.warn({ err, path, topicId, userId }, "topic cleanup: inbox unlink failed");
16244
+ } catch (err2) {
16245
+ if (err2?.code !== "ENOENT") {
16246
+ logger.warn({ err: err2, path, topicId, userId }, "topic cleanup: inbox unlink failed");
15796
16247
  }
15797
16248
  }
15798
16249
  }
@@ -15917,9 +16368,9 @@ function hubHeaders(bearer) {
15917
16368
  };
15918
16369
  }
15919
16370
  function errorText(status, body, fallback) {
15920
- const text = body?.error;
15921
- if (typeof text === "string" && text.trim())
15922
- return text.trim();
16371
+ const text2 = body?.error;
16372
+ if (typeof text2 === "string" && text2.trim())
16373
+ return text2.trim();
15923
16374
  return `${fallback} (hub answered ${status})`;
15924
16375
  }
15925
16376
  function describeFailure(status, body) {
@@ -16015,6 +16466,19 @@ var init_actor_policy = __esm(async () => {
16015
16466
  await init_actor_topic_reach();
16016
16467
  });
16017
16468
  // ../../packages/core/src/storage/session-asks.ts
16469
+ var exports_session_asks = {};
16470
+ __export(exports_session_asks, {
16471
+ releasePendingAsk: () => releasePendingAsk,
16472
+ markPendingAskState: () => markPendingAskState,
16473
+ markPendingAskSources: () => markPendingAskSources,
16474
+ listPendingAsksForCaller: () => listPendingAsksForCaller,
16475
+ describePendingAskState: () => describePendingAskState,
16476
+ deletePendingAsksForTopic: () => deletePendingAsksForTopic,
16477
+ createPendingAsk: () => createPendingAsk,
16478
+ clearPendingAskSources: () => clearPendingAskSources,
16479
+ clearPendingAsk: () => clearPendingAsk,
16480
+ PENDING_ASK_TTL_MS: () => PENDING_ASK_TTL_MS
16481
+ });
16018
16482
  import { createHash as createHash10 } from "crypto";
16019
16483
  import {
16020
16484
  closeSync as closeSync2,
@@ -16036,8 +16500,8 @@ function encodeAskKey(key) {
16036
16500
  return JSON.stringify([key.from, key.to]);
16037
16501
  }
16038
16502
  function pendingAskPath(key) {
16039
- const digest = createHash10("sha256").update(encodeAskKey(key)).digest("hex");
16040
- return join28(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
16503
+ const digest2 = createHash10("sha256").update(encodeAskKey(key)).digest("hex");
16504
+ return join28(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest2}.pending`);
16041
16505
  }
16042
16506
  function v2PendingAskPath(key) {
16043
16507
  const encoded = Buffer.from(encodeAskKey(key), "utf8").toString("base64url");
@@ -16063,10 +16527,10 @@ function parsePendingAskFilename(fileName) {
16063
16527
  }
16064
16528
  } catch {}
16065
16529
  }
16066
- const sep = raw.indexOf("___");
16067
- if (sep < 0)
16530
+ const sep3 = raw.indexOf("___");
16531
+ if (sep3 < 0)
16068
16532
  return null;
16069
- return { from: raw.slice(0, sep), to: raw.slice(sep + 3) };
16533
+ return { from: raw.slice(0, sep3), to: raw.slice(sep3 + 3) };
16070
16534
  }
16071
16535
  function readPendingAskFile(path, fallback) {
16072
16536
  try {
@@ -16109,6 +16573,16 @@ function readPendingAskFile(path, fallback) {
16109
16573
  return null;
16110
16574
  }
16111
16575
  }
16576
+ function isStale(record, path) {
16577
+ const ts = record ? Date.parse(record.updatedAt || record.createdAt) : Number.NaN;
16578
+ if (Number.isFinite(ts))
16579
+ return Date.now() - ts > PENDING_ASK_TTL_MS;
16580
+ try {
16581
+ return Date.now() - statSync8(path).mtimeMs > PENDING_ASK_TTL_MS;
16582
+ } catch {
16583
+ return false;
16584
+ }
16585
+ }
16112
16586
  function writePendingAsk(record) {
16113
16587
  const path = pendingAskPath(record);
16114
16588
  mkdirSync16(pendingAskDir(record.userId), { recursive: true });
@@ -16134,10 +16608,10 @@ function writePendingAskIfAbsent(record) {
16134
16608
  }
16135
16609
  }
16136
16610
  function readPendingAsk(key) {
16137
- const canonicalPath = pendingAskPath(key);
16138
- const canonical = readPendingAskFile(canonicalPath, key);
16611
+ const canonicalPath2 = pendingAskPath(key);
16612
+ const canonical = readPendingAskFile(canonicalPath2, key);
16139
16613
  if (canonical && canonical.from === key.from && canonical.to === key.to) {
16140
- return { path: canonicalPath, record: canonical };
16614
+ return { path: canonicalPath2, record: canonical };
16141
16615
  }
16142
16616
  for (const compatibilityPath of [v2PendingAskPath(key), legacyPendingAskPath(key)]) {
16143
16617
  if (!compatibilityPath)
@@ -16146,17 +16620,67 @@ function readPendingAsk(key) {
16146
16620
  if (!legacy || legacy.from !== key.from || legacy.to !== key.to)
16147
16621
  continue;
16148
16622
  const migrated = writePendingAskIfAbsent(legacy);
16149
- const next = migrated ? legacy : readPendingAskFile(canonicalPath, key);
16623
+ const next = migrated ? legacy : readPendingAskFile(canonicalPath2, key);
16150
16624
  if (next && next.from === key.from && next.to === key.to) {
16151
16625
  try {
16152
16626
  unlinkSync16(compatibilityPath);
16153
16627
  } catch {}
16154
- return { path: canonicalPath, record: next };
16628
+ return { path: canonicalPath2, record: next };
16155
16629
  }
16156
16630
  return { path: compatibilityPath, record: legacy };
16157
16631
  }
16158
16632
  return null;
16159
16633
  }
16634
+ function createPendingAsk(args) {
16635
+ const migrated = readPendingAsk(args);
16636
+ if (migrated && !isStale(migrated.record, migrated.path)) {
16637
+ return { ok: false, existing: migrated.record, stale: false };
16638
+ }
16639
+ if (migrated) {
16640
+ try {
16641
+ unlinkSync16(migrated.path);
16642
+ } catch {
16643
+ return { ok: false, existing: migrated.record, stale: true };
16644
+ }
16645
+ }
16646
+ const path = pendingAskPath(args);
16647
+ const now = new Date().toISOString();
16648
+ const record = {
16649
+ userId: args.userId,
16650
+ from: args.from,
16651
+ to: args.to,
16652
+ requestId: args.requestId,
16653
+ contextId: args.contextId,
16654
+ state: "requested",
16655
+ createdAt: now,
16656
+ updatedAt: now
16657
+ };
16658
+ mkdirSync16(pendingAskDir(args.userId), { recursive: true });
16659
+ for (let attempt = 0;attempt < 2; attempt++) {
16660
+ let fd = null;
16661
+ try {
16662
+ fd = openSync2(path, "wx");
16663
+ writeFileSync14(fd, `${JSON.stringify(record)}
16664
+ `);
16665
+ return { ok: true, record };
16666
+ } catch (err2) {
16667
+ if (err2.code !== "EEXIST")
16668
+ throw err2;
16669
+ const existing = readPendingAskFile(path, args);
16670
+ if (!isStale(existing, path))
16671
+ return { ok: false, existing, stale: false };
16672
+ try {
16673
+ unlinkSync16(path);
16674
+ } catch {
16675
+ return { ok: false, existing, stale: true };
16676
+ }
16677
+ } finally {
16678
+ if (fd !== null)
16679
+ closeSync2(fd);
16680
+ }
16681
+ }
16682
+ return { ok: false, existing: readPendingAskFile(path, args), stale: true };
16683
+ }
16160
16684
  function markPendingAskState(args) {
16161
16685
  const pending = readPendingAsk(args);
16162
16686
  if (!pending)
@@ -16190,6 +16714,83 @@ function clearPendingAsk(args) {
16190
16714
  return false;
16191
16715
  }
16192
16716
  }
16717
+ function releasePendingAsk(args) {
16718
+ if (clearPendingAsk(args))
16719
+ return true;
16720
+ const still = readPendingAsk(args);
16721
+ return !still || still.record.requestId !== args.requestId;
16722
+ }
16723
+ function markPendingAskSources(args) {
16724
+ for (const source of args.sources ?? []) {
16725
+ if (!source.from)
16726
+ continue;
16727
+ markPendingAskState({
16728
+ userId: args.userId,
16729
+ from: args.callerTopic,
16730
+ to: source.from,
16731
+ requestId: source.requestId,
16732
+ state: args.state
16733
+ });
16734
+ }
16735
+ }
16736
+ function clearPendingAskSources(args) {
16737
+ for (const source of args.sources ?? []) {
16738
+ if (!source.from)
16739
+ continue;
16740
+ clearPendingAsk({
16741
+ userId: args.userId,
16742
+ from: args.callerTopic,
16743
+ to: source.from,
16744
+ requestId: source.requestId
16745
+ });
16746
+ }
16747
+ }
16748
+ function listPendingAsksForCaller(args) {
16749
+ const dir = pendingAskDir(args.userId);
16750
+ let files;
16751
+ try {
16752
+ files = readdirSync4(dir);
16753
+ } catch {
16754
+ return [];
16755
+ }
16756
+ const records = new Map;
16757
+ for (const fileName of files) {
16758
+ const isV3 = fileName.startsWith(ASK_FILENAME_PREFIX);
16759
+ const parsed = isV3 ? { from: args.from, to: "" } : parsePendingAskFilename(fileName);
16760
+ if (!parsed)
16761
+ continue;
16762
+ const path = join28(dir, fileName);
16763
+ const record = readPendingAskFile(path, {
16764
+ userId: args.userId,
16765
+ from: parsed.from,
16766
+ to: parsed.to
16767
+ });
16768
+ if (!record || record.from !== args.from)
16769
+ continue;
16770
+ if (isStale(record, path)) {
16771
+ try {
16772
+ unlinkSync16(path);
16773
+ } catch {}
16774
+ continue;
16775
+ }
16776
+ const canonical = readPendingAsk(record);
16777
+ if (!canonical || canonical.record.from !== args.from)
16778
+ continue;
16779
+ if (path !== canonical.path) {
16780
+ try {
16781
+ unlinkSync16(path);
16782
+ } catch {}
16783
+ }
16784
+ if (isStale(canonical.record, canonical.path)) {
16785
+ try {
16786
+ unlinkSync16(canonical.path);
16787
+ } catch {}
16788
+ continue;
16789
+ }
16790
+ records.set(encodeAskKey(canonical.record), canonical.record);
16791
+ }
16792
+ return [...records.values()];
16793
+ }
16193
16794
  function deletePendingAsksForTopic(args) {
16194
16795
  const dir = pendingAskDir(args.userId);
16195
16796
  let files;
@@ -16218,6 +16819,18 @@ function deletePendingAsksForTopic(args) {
16218
16819
  }
16219
16820
  return deleted;
16220
16821
  }
16822
+ function describePendingAskState(state) {
16823
+ switch (state) {
16824
+ case "requested":
16825
+ return "\uB300\uC0C1 \uC138\uC158 \uCC98\uB9AC \uC911";
16826
+ case "reply_ready":
16827
+ return "\uC751\uB2F5 \uC0DD\uC131 \uC644\uB8CC, \uC774 \uC138\uC158 \uC8FC\uC785 \uC900\uBE44 \uC911";
16828
+ case "queued_for_caller":
16829
+ return "\uC751\uB2F5 \uC0DD\uC131 \uC644\uB8CC, \uC774 \uC138\uC158 \uC2E4\uD589 \uC885\uB8CC \uD6C4 \uC8FC\uC785 \uB300\uAE30 \uC911";
16830
+ case "injecting_to_caller":
16831
+ return "\uC751\uB2F5\uC744 \uC774 \uC138\uC158\uC5D0 \uC8FC\uC785 \uC911";
16832
+ }
16833
+ }
16221
16834
  var PENDING_ASK_TTL_MS, ASK_FILENAME_PREFIX = "v3-", V2_ASK_FILENAME_PREFIX = "v2-";
16222
16835
  var init_session_asks = __esm(async () => {
16223
16836
  await init_storage_host();
@@ -16319,10 +16932,10 @@ function deferRemoteSessionReplyOutbox(args) {
16319
16932
  if (!row)
16320
16933
  return;
16321
16934
  const attempts = Number(row.attempts) + 1;
16322
- const delay = args.retryMs ?? remoteSessionRetryDelayMs(attempts, args.random);
16935
+ const delay2 = args.retryMs ?? remoteSessionRetryDelayMs(attempts, args.random);
16323
16936
  db.query(`UPDATE remote_session_reply_outbox
16324
16937
  SET attempts = ?, next_attempt_at = ?, last_error = ?
16325
- WHERE request_id = ?`).run(attempts, now + delay, args.error.slice(0, 500), args.requestId);
16938
+ WHERE request_id = ?`).run(attempts, now + delay2, args.error.slice(0, 500), args.requestId);
16326
16939
  })();
16327
16940
  }
16328
16941
  function purgeExpiredRemoteSessionReplyOutbox(now = Date.now()) {
@@ -16493,9 +17106,37 @@ var init_remote_session_reply_outbox = __esm(async () => {
16493
17106
  });
16494
17107
 
16495
17108
  // ../../packages/core/src/mcp/session-comm/peer-forward.ts
17109
+ var exports_peer_forward = {};
17110
+ __export(exports_peer_forward, {
17111
+ registerPeerSessionBridge: () => registerPeerSessionBridge,
17112
+ peerSessionsForUser: () => peerSessionsForUser,
17113
+ parseHubRemoteReplyRoute: () => parseHubRemoteReplyRoute,
17114
+ isHubRemoteReplyRoute: () => isHubRemoteReplyRoute,
17115
+ forwardToPeer: () => forwardToPeer,
17116
+ deliverPeerReply: () => deliverPeerReply
17117
+ });
16496
17118
  function isHubRemoteReplyRoute(route) {
16497
17119
  return route.via === "hub";
16498
17120
  }
17121
+ function parseHubRemoteReplyRoute(value) {
17122
+ if (!value || typeof value !== "object" || Array.isArray(value))
17123
+ return null;
17124
+ const route = value;
17125
+ if (route.via !== "hub" || typeof route.hubUrl !== "string" || typeof route.token !== "string" || typeof route.nodeName !== "string" || typeof route.topicId !== "string" || typeof route.requestId !== "string") {
17126
+ return null;
17127
+ }
17128
+ const requestId = route.requestId.trim();
17129
+ const nodeName = route.nodeName.trim();
17130
+ const topicId = route.topicId.trim();
17131
+ const token = route.token.trim();
17132
+ if (!requestId || requestId.length > MAX_ROUTE_REQUEST_ID_LENGTH || !nodeName || nodeName.length > MAX_ROUTE_LABEL_LENGTH || !topicId || topicId.length > MAX_ROUTE_LABEL_LENGTH || token.length > MAX_REMOTE_SESSION_REPLY_TOKEN_LENGTH || !REMOTE_SESSION_REPLY_TOKEN_PATTERN.test(token)) {
17133
+ return null;
17134
+ }
17135
+ const hubUrl = normalizeHubUrl(route.hubUrl.trim(), "remoteReply.hubUrl");
17136
+ if ("error" in hubUrl)
17137
+ return null;
17138
+ return { via: "hub", hubUrl: hubUrl.url, token, nodeName, topicId, requestId };
17139
+ }
16499
17140
  function loopbackBridgeConfig() {
16500
17141
  const rawUrl = process.env[PEER_BRIDGE_URL_ENV]?.trim();
16501
17142
  const token = process.env[PEER_BRIDGE_TOKEN_ENV]?.trim();
@@ -16532,6 +17173,39 @@ async function callLoopbackBridge(request) {
16532
17173
  return { configured: true, result: null };
16533
17174
  }
16534
17175
  }
17176
+ function registerPeerSessionBridge(bridge) {
17177
+ activeBridge = bridge;
17178
+ return () => {
17179
+ if (activeBridge === bridge)
17180
+ activeBridge = null;
17181
+ };
17182
+ }
17183
+ async function forwardToPeer(args) {
17184
+ if (activeBridge)
17185
+ return activeBridge.forward(args);
17186
+ const forwarded = await callLoopbackBridge({ action: "forward", args });
17187
+ if (forwarded.result)
17188
+ return forwarded.result;
17189
+ return {
17190
+ ok: false,
17191
+ error: forwarded.configured ? "remote session bridge is configured but unavailable" : "remote nodes are not connected on this negotium node (standalone mode)"
17192
+ };
17193
+ }
17194
+ async function peerSessionsForUser(userId, sourceQueryId, fromTopicId) {
17195
+ if (activeBridge)
17196
+ return activeBridge.sessions(userId, sourceQueryId, fromTopicId);
17197
+ const sessions = await callLoopbackBridge({
17198
+ action: "sessions",
17199
+ userId,
17200
+ sourceQueryId,
17201
+ fromTopicId
17202
+ });
17203
+ if (sessions.result)
17204
+ return sessions.result;
17205
+ if (sessions.configured)
17206
+ return { ok: false, nodes: [] };
17207
+ return { ok: true, nodes: [] };
17208
+ }
16535
17209
  async function deliverPeerReply(route, sourceTitle, replyText, kind) {
16536
17210
  if (isHubRemoteReplyRoute(route)) {
16537
17211
  return deliverHubRemoteReply(route, sourceTitle, replyText, kind);
@@ -16546,13 +17220,40 @@ async function deliverPeerReply(route, sourceTitle, replyText, kind) {
16546
17220
  kind
16547
17221
  })).result ?? false;
16548
17222
  }
16549
- var activeBridge = null, PEER_BRIDGE_URL_ENV = "NEGOTIUM_PEER_SESSION_BRIDGE_URL", PEER_BRIDGE_TOKEN_ENV = "NEGOTIUM_PEER_SESSION_BRIDGE_TOKEN", PEER_BRIDGE_TIMEOUT_MS = 5000;
17223
+ var MAX_ROUTE_REQUEST_ID_LENGTH = 200, MAX_ROUTE_LABEL_LENGTH = 300, activeBridge = null, PEER_BRIDGE_URL_ENV = "NEGOTIUM_PEER_SESSION_BRIDGE_URL", PEER_BRIDGE_TOKEN_ENV = "NEGOTIUM_PEER_SESSION_BRIDGE_TOKEN", PEER_BRIDGE_TIMEOUT_MS = 5000;
16550
17224
  var init_peer_forward = __esm(async () => {
16551
17225
  init_remote_session_grant();
16552
17226
  await init_remote_session_reply_outbox();
16553
17227
  });
16554
17228
 
16555
17229
  // ../../packages/core/src/runtime/ask-callbacks.ts
17230
+ var exports_ask_callbacks = {};
17231
+ __export(exports_ask_callbacks, {
17232
+ resolveAskCallback: () => resolveAskCallback,
17233
+ registerAskCallback: () => registerAskCallback,
17234
+ purgeStaleAsks: () => purgeStaleAsks,
17235
+ failInterruptedRemoteAskCallbacks: () => failInterruptedRemoteAskCallbacks,
17236
+ deleteHubRemoteAskCallbackRow: () => deleteHubRemoteAskCallbackRow,
17237
+ cancelAskCallbacksForTopic: () => cancelAskCallbacksForTopic
17238
+ });
17239
+ function registerAskCallback(entry) {
17240
+ pendingAsks.set(entry.targetQueryId, entry);
17241
+ if (entry.remoteReply) {
17242
+ const route = entry.remoteReply;
17243
+ const hub = isHubRemoteReplyRoute(route);
17244
+ db.query(`INSERT INTO remote_ask_callbacks
17245
+ (target_query_id, request_id, node_name, node_cell_id, topic_id, user_id, created_at, route_json)
17246
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
17247
+ ON CONFLICT(target_query_id) DO UPDATE SET
17248
+ request_id = excluded.request_id,
17249
+ node_name = excluded.node_name,
17250
+ node_cell_id = excluded.node_cell_id,
17251
+ topic_id = excluded.topic_id,
17252
+ user_id = excluded.user_id,
17253
+ created_at = excluded.created_at,
17254
+ route_json = excluded.route_json`).run(entry.targetQueryId, route.requestId, route.nodeName, hub ? "" : route.nodeCellId, route.topicId, hub ? "" : route.userId, entry.createdAt, hub ? JSON.stringify(route) : null);
17255
+ }
17256
+ }
16556
17257
  function resolveAskCallback(queryId) {
16557
17258
  const entry = pendingAsks.get(queryId);
16558
17259
  if (!entry)
@@ -16569,6 +17270,13 @@ function resolveAskCallback(queryId) {
16569
17270
  function deleteHubRemoteAskCallbackRow(requestId) {
16570
17271
  db.query("DELETE FROM remote_ask_callbacks WHERE request_id = ? AND route_json IS NOT NULL").run(requestId);
16571
17272
  }
17273
+ function purgeStaleAsks(now = Date.now()) {
17274
+ for (const [id, entry] of pendingAsks) {
17275
+ if (now - entry.createdAt > MAX_ASK_AGE_MS)
17276
+ pendingAsks.delete(id);
17277
+ }
17278
+ db.query("DELETE FROM remote_ask_callbacks WHERE created_at < ?").run(now - MAX_ASK_AGE_MS);
17279
+ }
16572
17280
  function cancelAskCallbacksForTopic(topicId) {
16573
17281
  let cancelled = 0;
16574
17282
  for (const [queryId, entry] of pendingAsks) {
@@ -16580,6 +17288,43 @@ function cancelAskCallbacksForTopic(topicId) {
16580
17288
  }
16581
17289
  return cancelled;
16582
17290
  }
17291
+ function durableRoute(row) {
17292
+ if (row.route_json) {
17293
+ try {
17294
+ return parseHubRemoteReplyRoute(JSON.parse(row.route_json));
17295
+ } catch {
17296
+ return null;
17297
+ }
17298
+ }
17299
+ return {
17300
+ nodeName: row.node_name,
17301
+ nodeCellId: row.node_cell_id,
17302
+ topicId: row.topic_id,
17303
+ userId: row.user_id,
17304
+ requestId: row.request_id
17305
+ };
17306
+ }
17307
+ async function failInterruptedRemoteAskCallbacks(options = {}) {
17308
+ const rows = db.query(`SELECT target_query_id, request_id, node_name, node_cell_id, topic_id, user_id, route_json
17309
+ FROM remote_ask_callbacks
17310
+ ORDER BY created_at ASC`).all();
17311
+ let failed = 0;
17312
+ for (const row of rows) {
17313
+ const route = durableRoute(row);
17314
+ if (!route) {
17315
+ db.query("DELETE FROM remote_ask_callbacks WHERE target_query_id = ?").run(row.target_query_id);
17316
+ continue;
17317
+ }
17318
+ if (options.routes === "hub" && !isHubRemoteReplyRoute(route))
17319
+ continue;
17320
+ const delivered = await deliverPeerReply(route, "peer", "The remote worker restarted before this ask completed. Please retry the request.", "error");
17321
+ if (!delivered)
17322
+ continue;
17323
+ db.query("DELETE FROM remote_ask_callbacks WHERE target_query_id = ?").run(row.target_query_id);
17324
+ failed++;
17325
+ }
17326
+ return failed;
17327
+ }
16583
17328
  var pendingAsks, MAX_ASK_AGE_MS;
16584
17329
  var init_ask_callbacks = __esm(async () => {
16585
17330
  await __promiseAll([
@@ -17005,6 +17750,14 @@ var init_topic_tool_capabilities = __esm(async () => {
17005
17750
  });
17006
17751
 
17007
17752
  // ../../packages/core/src/topics/lifecycle.ts
17753
+ var exports_lifecycle = {};
17754
+ __export(exports_lifecycle, {
17755
+ deleteTopicCascade: () => deleteTopicCascade,
17756
+ TopicTurnStillActiveError: () => TopicTurnStillActiveError,
17757
+ TopicDeleteVetoedError: () => TopicDeleteVetoedError,
17758
+ TopicCleanupRequiredError: () => TopicCleanupRequiredError,
17759
+ TopicArchiveRequiredError: () => TopicArchiveRequiredError
17760
+ });
17008
17761
  import { rmSync as rmSync6 } from "fs";
17009
17762
  async function abortAndWaitForTopic(topicId) {
17010
17763
  interSessionQueue.drop(topicId);
@@ -17037,8 +17790,8 @@ async function cleanupParticipantResources(topic, userIds, sessionId, cwd, purge
17037
17790
  cwd,
17038
17791
  extraSessions: index === 0 ? currentSessionRef(topic, sessionId) : []
17039
17792
  });
17040
- } catch (err) {
17041
- logger.warn({ err, topicId: topic.id, userId: participantUserId }, "deleteTopicCascade: participant rollout cleanup failed");
17793
+ } catch (err2) {
17794
+ logger.warn({ err: err2, topicId: topic.id, userId: participantUserId }, "deleteTopicCascade: participant rollout cleanup failed");
17042
17795
  }
17043
17796
  if (!purged)
17044
17797
  return false;
@@ -17094,12 +17847,12 @@ async function deleteTopicCascadeImpl(topic, userId, options, deletingAncestorId
17094
17847
  if (rawArchive)
17095
17848
  rawArchives.push(rawArchive.path);
17096
17849
  }
17097
- } catch (err) {
17850
+ } catch (err2) {
17098
17851
  if (!force) {
17099
- logger.warn({ err, topicId }, "deleteTopicCascade: archive failed - blocking delete unless force=true");
17100
- throw new TopicArchiveRequiredError(topicId, err);
17852
+ logger.warn({ err: err2, topicId }, "deleteTopicCascade: archive failed - blocking delete unless force=true");
17853
+ throw new TopicArchiveRequiredError(topicId, err2);
17101
17854
  }
17102
- logger.warn({ err, topicId }, "deleteTopicCascade: archive failed but force=true - continuing with hard delete");
17855
+ logger.warn({ err: err2, topicId }, "deleteTopicCascade: archive failed but force=true - continuing with hard delete");
17103
17856
  }
17104
17857
  }
17105
17858
  if (archived && meetsMemoryArchiveExchangeThreshold(archived.exchangeCount, MIN_MEMORY_ARCHIVE_EXCHANGES, topic)) {
@@ -17115,8 +17868,8 @@ async function deleteTopicCascadeImpl(topic, userId, options, deletingAncestorId
17115
17868
  ...rawArchives.length > 0 ? { rawArchivePaths: rawArchives } : {},
17116
17869
  messageCount: archived.messageCount
17117
17870
  });
17118
- } catch (err) {
17119
- logger.warn({ err, topicId, archive: archived.path }, "deleteTopicCascade: background archiver launch failed - raw archive preserved");
17871
+ } catch (err2) {
17872
+ logger.warn({ err: err2, topicId, archive: archived.path }, "deleteTopicCascade: background archiver launch failed - raw archive preserved");
17120
17873
  }
17121
17874
  }
17122
17875
  const sessionId = getTopicSessionId(topicId);
@@ -17131,25 +17884,23 @@ async function deleteTopicCascadeImpl(topic, userId, options, deletingAncestorId
17131
17884
  await deleteTopicCascadeImpl(child, userId, childOptions, deletingTopicIds);
17132
17885
  }
17133
17886
  killBgBash(userId, topicId);
17134
- const browserProfileOwner = getBrowserProfileOwner(topicId, userId);
17135
- const browserProfile = getTopicBrowserProfile(topicId);
17136
17887
  try {
17137
- await closeBrowserOwnerTabs(browserProfileOwner, browserProfile, `topic:${topicId}`);
17138
- } catch (err) {
17139
- logger.warn({ err, topicId }, "deleteTopicCascade: browser owner cleanup failed");
17888
+ await closeTopicBrowserTabs(userId, topicId);
17889
+ } catch (err2) {
17890
+ logger.warn({ err: err2, topicId }, "deleteTopicCascade: browser owner cleanup failed");
17140
17891
  }
17141
17892
  deleteTopicProfileDir(userId, topicId);
17142
17893
  cancelAskCallbacksForTopic(topicId);
17143
17894
  deleteSelfSchedulesForTopic(topicId);
17144
17895
  try {
17145
17896
  await deleteFilesForTopic(topicId);
17146
- } catch (err) {
17147
- logger.warn({ err, topicId }, "deleteTopicCascade: host file cleanup failed");
17897
+ } catch (err2) {
17898
+ logger.warn({ err: err2, topicId }, "deleteTopicCascade: host file cleanup failed");
17148
17899
  }
17149
17900
  try {
17150
17901
  rmSync6(cwd, { recursive: true, force: true });
17151
- } catch (err) {
17152
- logger.warn({ err, topicId, cwd }, "deleteTopicCascade: workspace cleanup failed");
17902
+ } catch (err2) {
17903
+ logger.warn({ err: err2, topicId, cwd }, "deleteTopicCascade: workspace cleanup failed");
17153
17904
  }
17154
17905
  deleteTopicVisuals(topicId);
17155
17906
  deleteTopicHostMcpGrant(topicId);
@@ -17191,7 +17942,7 @@ async function deleteTopicCascadeImpl(topic, userId, options, deletingAncestorId
17191
17942
  }
17192
17943
  }
17193
17944
  }
17194
- var DELETE_TURN_WAIT_MS = 5000, TopicArchiveRequiredError, TopicTurnStillActiveError, TopicCleanupRequiredError;
17945
+ var DELETE_TURN_WAIT_MS = 5000, TopicArchiveRequiredError, TopicTurnStillActiveError, TopicCleanupRequiredError, TopicDeleteVetoedError;
17195
17946
  var init_lifecycle = __esm(async () => {
17196
17947
  init_manager();
17197
17948
  init_config();
@@ -17216,7 +17967,6 @@ var init_lifecycle = __esm(async () => {
17216
17967
  init_api_topic_brief(),
17217
17968
  init_api_topic_config(),
17218
17969
  init_api_topics(),
17219
- init_browser_profiles(),
17220
17970
  init_forum_db(),
17221
17971
  init_runtime_leases(),
17222
17972
  init_runtime_topic_state(),
@@ -17258,9 +18008,19 @@ var init_lifecycle = __esm(async () => {
17258
18008
  this.topicId = topicId;
17259
18009
  }
17260
18010
  };
18011
+ TopicDeleteVetoedError = class TopicDeleteVetoedError extends Error {
18012
+ code = "TOPIC_DELETE_VETOED";
18013
+ topicId;
18014
+ constructor(topicId, reason) {
18015
+ super(`Topic delete was vetoed: ${reason}`);
18016
+ this.name = "TopicDeleteVetoedError";
18017
+ this.topicId = topicId;
18018
+ }
18019
+ };
17261
18020
  });
17262
18021
 
17263
18022
  // ../../packages/core/src/runtime/attachments.ts
18023
+ import { randomUUID as randomUUID16 } from "crypto";
17264
18024
  import { copyFileSync as copyFileSync2, mkdirSync as mkdirSync17, writeFileSync as writeFileSync15 } from "fs";
17265
18025
  import { basename as basename6, join as join29 } from "path";
17266
18026
  function workspaceCwdFor(topicId) {
@@ -17302,8 +18062,8 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
17302
18062
  sizeBytes: attachment.sizeBytes,
17303
18063
  path: destPath
17304
18064
  });
17305
- } catch (err) {
17306
- logger.warn({ topicId, queryId, fileId, err }, "ai: failed to materialize attachment");
18065
+ } catch (err2) {
18066
+ logger.warn({ topicId, queryId, fileId, err: err2 }, "ai: failed to materialize attachment");
17307
18067
  }
17308
18068
  }
17309
18069
  return out;
@@ -17321,6 +18081,24 @@ function composeAttachmentPrompt(prompt, promptLines) {
17321
18081
  function promptWithAttachments(prompt, attachments) {
17322
18082
  return composeAttachmentPrompt(prompt, attachments.map(({ filename, path }) => attachmentPromptLine(filename, path)));
17323
18083
  }
18084
+ function ingestAttachment(args) {
18085
+ const destDir = join29(UPLOADS_DIR, args.topicId);
18086
+ mkdirSync17(destDir, { recursive: true });
18087
+ const safeName = safeAttachmentFilename(args.filename, "upload");
18088
+ const destPath = join29(destDir, `${Date.now()}-${randomUUID16().slice(0, 8)}-${safeName}`);
18089
+ if (args.sourcePath !== undefined) {
18090
+ copyFileSync2(args.sourcePath, destPath);
18091
+ } else if (args.bytes !== undefined) {
18092
+ writeFileSync15(destPath, args.bytes);
18093
+ } else {
18094
+ throw new Error("ingestAttachment: provide sourcePath or bytes");
18095
+ }
18096
+ return {
18097
+ path: destPath,
18098
+ filename: args.filename,
18099
+ promptLine: attachmentPromptLine(args.filename, destPath)
18100
+ };
18101
+ }
17324
18102
  function parseAttachmentNames(raw) {
17325
18103
  if (!raw)
17326
18104
  return [];
@@ -17361,13 +18139,13 @@ function isLikelyCurrentChannelTrigger(row, userId, prompt) {
17361
18139
  return Number.isFinite(createdMs) && Date.now() - createdMs <= CHANNEL_CONTEXT_CURRENT_MESSAGE_MATCH_MS;
17362
18140
  }
17363
18141
  function formatChannelTranscriptLine(row) {
17364
- const text = row.text.trim();
18142
+ const text2 = row.text.trim();
17365
18143
  const attachments = parseAttachmentNames(row.attachments);
17366
18144
  const attachmentSuffix = attachments.length > 0 ? `
17367
18145
  [attachments: ${attachments.join(", ")}]` : "";
17368
18146
  const edited = row.edited_at ? " (edited)" : "";
17369
18147
  const thread = row.thread_root_id ? ` (in thread ${threadTag(row.thread_root_id)})` : "";
17370
- return `[${row.created_at}] ${channelTranscriptSpeaker(row)}${edited}${thread}: ${text}${attachmentSuffix}`;
18148
+ return `[${row.created_at}] ${channelTranscriptSpeaker(row)}${edited}${thread}: ${text2}${attachmentSuffix}`;
17371
18149
  }
17372
18150
  function buildMentionOnlyChannelPrompt(params) {
17373
18151
  const rows = getAllMessagesForTopic(params.topicId).filter((row) => {
@@ -17412,6 +18190,14 @@ function buildMentionOnlyChannelPrompt(params) {
17412
18190
  ].filter((line) => line !== undefined).join(`
17413
18191
  `);
17414
18192
  }
18193
+ function escapeRegExp3(s) {
18194
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
18195
+ }
18196
+ function mentionsAi(text2, label) {
18197
+ const names = ["ai", "bot", "\uBD07", label.trim()].filter(Boolean);
18198
+ const alt = names.map(escapeRegExp3).join("|");
18199
+ return new RegExp(`(^|\\s)@(${alt})(?![\\p{L}\\p{N}])`, "iu").test(text2);
18200
+ }
17415
18201
  var CHANNEL_CONTEXT_CURRENT_MESSAGE_MATCH_MS, CHANNEL_CONTEXT_MAX_MESSAGES = 500, CHANNEL_CONTEXT_MAX_CHARS = 120000;
17416
18202
  var init_channel_context = __esm(async () => {
17417
18203
  init_attachments();
@@ -17420,13 +18206,13 @@ var init_channel_context = __esm(async () => {
17420
18206
  });
17421
18207
 
17422
18208
  // ../../packages/core/src/runtime/errors.ts
17423
- function stringifyError(err) {
17424
- if (err instanceof Error)
17425
- return err.message;
17426
- if (typeof err === "string")
17427
- return err;
18209
+ function stringifyError(err2) {
18210
+ if (err2 instanceof Error)
18211
+ return err2.message;
18212
+ if (typeof err2 === "string")
18213
+ return err2;
17428
18214
  try {
17429
- return JSON.stringify(err) ?? String(err);
18215
+ return JSON.stringify(err2) ?? String(err2);
17430
18216
  } catch {
17431
18217
  return "Unknown agent error";
17432
18218
  }
@@ -17441,19 +18227,19 @@ function authRecoveryHint(agent) {
17441
18227
  return "Please check the DEEPSEEK_API_KEY, MOONSHOT_API_KEY, or GLM_API_KEY environment variable";
17442
18228
  }
17443
18229
  }
17444
- function classifyAgentError(err, agent) {
18230
+ function classifyAgentError(err2, agent) {
17445
18231
  const name = AGENT_DISPLAY_NAME[agent];
17446
18232
  const hint = authRecoveryHint(agent);
17447
- const ctor = typeof err === "object" && err !== null ? err.constructor?.name : undefined;
18233
+ const ctor = typeof err2 === "object" && err2 !== null ? err2.constructor?.name : undefined;
17448
18234
  if (ctor === "AuthenticationError")
17449
18235
  return `${name} authentication expired. ${hint}. (401)`;
17450
18236
  if (ctor === "RateLimitError")
17451
18237
  return `${name} request limit exceeded. Please try again in a moment. (429)`;
17452
18238
  if (ctor === "InternalServerError") {
17453
- const status = err.status;
18239
+ const status = err2.status;
17454
18240
  return status === 529 ? `${name} server is overloaded. Please try again in a moment. (529)` : `${name} server error occurred. Please try again in a moment. (500)`;
17455
18241
  }
17456
- const s = stringifyError(err);
18242
+ const s = stringifyError(err2);
17457
18243
  if (/401|authentication.error|invalid.*api.key|not logged|ANTHROPIC_API_KEY|DEEPSEEK_API_KEY|MOONSHOT_API_KEY|GLM_API_KEY/i.test(s)) {
17458
18244
  return `${name} authentication expired. ${hint}. (401)`;
17459
18245
  }
@@ -17476,12 +18262,12 @@ var init_errors = __esm(() => {
17476
18262
 
17477
18263
  // ../../packages/core/src/runtime/event-heartbeat.ts
17478
18264
  function nextOrHeartbeat(pending, intervalMs) {
17479
- return new Promise((resolve, reject) => {
17480
- const timer = setTimeout(() => resolve({ kind: "heartbeat" }), intervalMs);
18265
+ return new Promise((resolve17, reject) => {
18266
+ const timer = setTimeout(() => resolve17({ kind: "heartbeat" }), intervalMs);
17481
18267
  timer.unref?.();
17482
18268
  pending.then((result) => {
17483
18269
  clearTimeout(timer);
17484
- resolve({ kind: "event", result });
18270
+ resolve17({ kind: "event", result });
17485
18271
  }, (error) => {
17486
18272
  clearTimeout(timer);
17487
18273
  reject(error);
@@ -17775,7 +18561,7 @@ var init_vault_request_gates = __esm(async () => {
17775
18561
  });
17776
18562
 
17777
18563
  // ../../packages/core/src/agents/mcp-tools/request-vault.ts
17778
- import { createHash as createHash12, randomUUID as randomUUID16 } from "crypto";
18564
+ import { createHash as createHash12, randomUUID as randomUUID17 } from "crypto";
17779
18565
  import { z as z4 } from "zod";
17780
18566
  function requestBodyHash(key, description) {
17781
18567
  return createHash12("sha256").update(JSON.stringify({ key, description })).digest("hex");
@@ -18011,8 +18797,8 @@ function createRequestVaultRuntime(host) {
18011
18797
  return errorResult(`Error: failed to persist request_vault_secret: ${error instanceof Error ? error.message : String(error)}`);
18012
18798
  }
18013
18799
  let resolveAnswer;
18014
- const promise = new Promise((resolve) => {
18015
- resolveAnswer = resolve;
18800
+ const promise = new Promise((resolve17) => {
18801
+ resolveAnswer = resolve17;
18016
18802
  });
18017
18803
  pendingRequests.set(message.id, {
18018
18804
  topicId: ctx.topicId,
@@ -18073,7 +18859,7 @@ var init_request_vault = __esm(async () => {
18073
18859
  init_vault_request_gates()
18074
18860
  ]);
18075
18861
  MAX_DESCRIPTION_CHARS = VAULT_DESCRIPTION_MAX_LENGTH;
18076
- VAULT_GATE_OWNER_ID = `request-vault-${process.pid}-${randomUUID16()}`;
18862
+ VAULT_GATE_OWNER_ID = `request-vault-${process.pid}-${randomUUID17()}`;
18077
18863
  defaultRequestVaultDurabilityHost = {
18078
18864
  gates: {
18079
18865
  prepare: prepareVaultRequestGate,
@@ -18114,7 +18900,7 @@ var init_request_vault = __esm(async () => {
18114
18900
  durability: defaultRequestVaultDurabilityHost,
18115
18901
  runtime: {
18116
18902
  ownerId: VAULT_GATE_OWNER_ID,
18117
- createId: randomUUID16,
18903
+ createId: randomUUID17,
18118
18904
  now: () => new Date().toISOString()
18119
18905
  }
18120
18906
  });
@@ -18151,24 +18937,24 @@ function taskPanelMessageId(queryId) {
18151
18937
  // ../../packages/core/src/runtime/tasks.ts
18152
18938
  function upsertTaskPanelMessage(topicId, queryId, tasks, lastRenderedText) {
18153
18939
  if (tasks.length === 0) {
18154
- const hub = WsHub.get();
18155
- for (const messageId of softDeleteApiMessagesByIdPrefix(topicId, "tasks-")) {
18156
- hub.broadcastMessageUpdated(topicId, messageId, { deleted: true, text: "" });
18940
+ const hub2 = WsHub.get();
18941
+ for (const messageId2 of softDeleteApiMessagesByIdPrefix(topicId, "tasks-")) {
18942
+ hub2.broadcastMessageUpdated(topicId, messageId2, { deleted: true, text: "" });
18157
18943
  }
18158
18944
  return null;
18159
18945
  }
18160
- const text = renderTaskPanel(tasks);
18161
- if (text === lastRenderedText)
18946
+ const text2 = renderTaskPanel(tasks);
18947
+ if (text2 === lastRenderedText)
18162
18948
  return lastRenderedText;
18163
18949
  const hub = WsHub.get();
18164
18950
  const messageId = taskPanelMessageId(queryId);
18165
18951
  const existing = getApiMessage(topicId, messageId);
18166
18952
  if (existing && !existing.deleted) {
18167
18953
  const editedAt = new Date().toISOString();
18168
- const updated = updateApiMessageText(topicId, messageId, text, editedAt);
18954
+ const updated = updateApiMessageText(topicId, messageId, text2, editedAt);
18169
18955
  if (updated) {
18170
- hub.broadcastMessageUpdated(topicId, messageId, { text, editedAt });
18171
- return text;
18956
+ hub.broadcastMessageUpdated(topicId, messageId, { text: text2, editedAt });
18957
+ return text2;
18172
18958
  }
18173
18959
  }
18174
18960
  const createdAt = new Date().toISOString();
@@ -18176,12 +18962,12 @@ function upsertTaskPanelMessage(topicId, queryId, tasks, lastRenderedText) {
18176
18962
  id: messageId,
18177
18963
  topicId,
18178
18964
  authorId: "system",
18179
- text,
18965
+ text: text2,
18180
18966
  createdAt
18181
18967
  };
18182
18968
  appendApiMessage(message, { notify: false });
18183
18969
  hub.broadcastMessage(topicId, message);
18184
- return text;
18970
+ return text2;
18185
18971
  }
18186
18972
  var init_tasks2 = __esm(async () => {
18187
18973
  await __promiseAll([
@@ -18432,7 +19218,7 @@ function buildVideoHtml(mimeType) {
18432
19218
  <body><video controls playsinline preload="metadata" src="${VISUAL_MEDIA_URL_PLACEHOLDER}" data-mime="${escapeHtml2(mimeType)}"></video></body>
18433
19219
  </html>`;
18434
19220
  }
18435
- function resolveVisualMediaInput(topicId, input) {
19221
+ function locateVisualMediaInput(topicId, input) {
18436
19222
  if (typeof input.file_id === "string" && input.file_id.trim()) {
18437
19223
  const fileId = input.file_id.trim().toLowerCase();
18438
19224
  if (!isUploadFileId(fileId))
@@ -18444,11 +19230,7 @@ function resolveVisualMediaInput(topicId, input) {
18444
19230
  const filePath = resolveUploadedFilePathByFileId(fileId);
18445
19231
  if (!attachment || !filePath)
18446
19232
  return { error: `uploaded file not found: ${fileId}` };
18447
- return {
18448
- fileId: attachment.id,
18449
- mimeType: attachment.mimeType,
18450
- source: `file_id:${attachment.id}`
18451
- };
19233
+ return { kind: "upload", fileId: attachment.id, mimeType: attachment.mimeType };
18452
19234
  }
18453
19235
  if (typeof input.file_path !== "string" || !input.file_path.trim()) {
18454
19236
  return { error: "file_path or file_id is required" };
@@ -18456,18 +19238,38 @@ function resolveVisualMediaInput(topicId, input) {
18456
19238
  const rawPath = input.file_path.trim();
18457
19239
  const cwd = workspaceCwdFor(topicId);
18458
19240
  const candidate = isAbsolute6(rawPath) ? rawPath : resolve17(cwd, rawPath);
18459
- if (!isPathInside(cwd, candidate)) {
18460
- return { error: "file_path must be inside the topic workspace" };
18461
- }
18462
19241
  let realCandidate;
18463
19242
  try {
18464
19243
  realCandidate = realpathSync5(candidate);
18465
19244
  } catch {
18466
19245
  return { error: `file not found: ${rawPath}` };
18467
19246
  }
19247
+ if (!isPathInside(cwd, realCandidate)) {
19248
+ return {
19249
+ error: `file_path must be inside the topic workspace (${cwd}); copy the file into it and pass the copy`
19250
+ };
19251
+ }
18468
19252
  if (isSensitivePath(realCandidate)) {
18469
19253
  return { error: "file_path matches the sensitive-file blacklist" };
18470
19254
  }
19255
+ return { kind: "file", path: realCandidate, rawPath };
19256
+ }
19257
+ function visualMediaInputError(topicId, input) {
19258
+ const located = locateVisualMediaInput(topicId, input);
19259
+ return "error" in located ? located.error : null;
19260
+ }
19261
+ function resolveVisualMediaInput(topicId, input) {
19262
+ const located = locateVisualMediaInput(topicId, input);
19263
+ if ("error" in located)
19264
+ return located;
19265
+ if (located.kind === "upload") {
19266
+ return {
19267
+ fileId: located.fileId,
19268
+ mimeType: located.mimeType,
19269
+ source: `file_id:${located.fileId}`
19270
+ };
19271
+ }
19272
+ const { path: realCandidate, rawPath } = located;
18471
19273
  const attachment = storeLocalFileAsUpload(realCandidate, { topicId });
18472
19274
  if (!attachment)
18473
19275
  return { error: `failed to store media file: ${rawPath}` };
@@ -18494,7 +19296,7 @@ var init_visuals = __esm(async () => {
18494
19296
  });
18495
19297
 
18496
19298
  // ../../packages/core/src/runtime/turn-event-stream.ts
18497
- import { randomUUID as randomUUID17 } from "crypto";
19299
+ import { randomUUID as randomUUID18 } from "crypto";
18498
19300
  import { realpathSync as realpathSync6, statSync as statSync9 } from "fs";
18499
19301
  import { isAbsolute as isAbsolute7, resolve as resolve18 } from "path";
18500
19302
  function sessionEventMatchesCurrentExecution(topicId, queryId, agent, model) {
@@ -18563,9 +19365,9 @@ async function runTurnEventStream(topicId, topicTitle, queryId, events, control,
18563
19365
  const existing = providerToolIds.get(providerId);
18564
19366
  if (existing)
18565
19367
  return existing;
18566
- const clientId = fallback ?? providerId;
18567
- providerToolIds.set(providerId, clientId);
18568
- return clientId;
19368
+ const clientId2 = fallback ?? providerId;
19369
+ providerToolIds.set(providerId, clientId2);
19370
+ return clientId2;
18569
19371
  }
18570
19372
  const clientId = fallback ?? nextSyntheticToolUseId();
18571
19373
  anonymousToolIds.push(clientId);
@@ -18596,15 +19398,15 @@ async function runTurnEventStream(topicId, topicTitle, queryId, events, control,
18596
19398
  return providerId ? handledVisualToolResultIds.has(providerId) : false;
18597
19399
  };
18598
19400
  const emitPendingAssistantMessage = (usage) => {
18599
- const text = pendingText.trimEnd();
19401
+ const text2 = pendingText.trimEnd();
18600
19402
  pendingText = "";
18601
- if (silent || !text.trim())
19403
+ if (silent || !text2.trim())
18602
19404
  return null;
18603
19405
  const message = {
18604
- id: randomUUID17(),
19406
+ id: randomUUID18(),
18605
19407
  topicId,
18606
19408
  authorId: "ai",
18607
- text,
19409
+ text: text2,
18608
19410
  queryId,
18609
19411
  agentType,
18610
19412
  model,
@@ -18824,8 +19626,8 @@ ${JSON.stringify(event.input ?? {})}`);
18824
19626
  hub.broadcastVisual(topicId, queryId, url, vizId, title ?? null, kind);
18825
19627
  hub.broadcastToolOutput(topicId, queryId, toolUseId, `Displayed: ${url}`);
18826
19628
  markVisualToolResultHandled(event.toolUseId);
18827
- } catch (err) {
18828
- const reason = err instanceof Error ? err.message : String(err);
19629
+ } catch (err2) {
19630
+ const reason = err2 instanceof Error ? err2.message : String(err2);
18829
19631
  failMediaVisual(reason);
18830
19632
  }
18831
19633
  } else {
@@ -18936,8 +19738,8 @@ ${JSON.stringify(event.input ?? {})}`);
18936
19738
  }
18937
19739
  terminalEmitted = true;
18938
19740
  {
18939
- await init_ask_callbacks();
18940
- const pending = resolveAskCallback(queryId);
19741
+ const { resolveAskCallback: resolveAskCallback2 } = await init_ask_callbacks().then(() => exports_ask_callbacks);
19742
+ const pending = resolveAskCallback2(queryId);
18941
19743
  if (pending) {
18942
19744
  const sourceLabel = pending.sourceLabel ?? topicTitle;
18943
19745
  const replyText = pending.timedOut ? `\u26A0\uFE0F [Timeout - reply from ${sourceLabel} took too long and was dropped]` : accumulatedText.trim() || "(\uCC98\uB9AC\uB428, \uBCC4\uB3C4 \uC751\uB2F5 \uC5C6\uC74C)";
@@ -19010,8 +19812,8 @@ ${JSON.stringify(event.input ?? {})}`);
19010
19812
  if (control.injectParams)
19011
19813
  control.injectParams.sessionId = event.sessionId;
19012
19814
  onSessionId(event.sessionId);
19013
- } catch (err) {
19014
- logger.warn({ err, topicId, queryId, agentType }, "ai: isolated session owner rejected provider session id");
19815
+ } catch (err2) {
19816
+ logger.warn({ err: err2, topicId, queryId, agentType }, "ai: isolated session owner rejected provider session id");
19015
19817
  }
19016
19818
  } else if (!silent && sessionEventMatchesCurrentExecution(topicId, queryId, agentType, model)) {
19017
19819
  setTopicSessionId(topicId, event.sessionId, {
@@ -19044,14 +19846,14 @@ ${JSON.stringify(event.input ?? {})}`);
19044
19846
  settleSubagentFailure(queryId, "\uC911\uC9C0\uB428 (\uC0AC\uC6A9\uC790\uAC00 \uC2E4\uD589\uC744 \uBA48\uCDC4\uC2B5\uB2C8\uB2E4)");
19045
19847
  } else {
19046
19848
  if (control.abortReason === "internal" /* Internal */) {
19047
- await init_ask_callbacks();
19048
- resolveAskCallback(queryId);
19849
+ const { resolveAskCallback: resolveAskCallback2 } = await init_ask_callbacks().then(() => exports_ask_callbacks);
19850
+ resolveAskCallback2(queryId);
19049
19851
  }
19050
19852
  }
19051
19853
  }
19052
- } catch (err) {
19053
- const msg = stringifyError(err) || "Unknown agent error";
19054
- logger.warn({ err, topicId, queryId, agentType, model, silent }, "ai: stream failed");
19854
+ } catch (err2) {
19855
+ const msg = stringifyError(err2) || "Unknown agent error";
19856
+ logger.warn({ err: err2, topicId, queryId, agentType, model, silent }, "ai: stream failed");
19055
19857
  terminalEmitted = true;
19056
19858
  if (retryableSessionExpired && isSessionExpiredError(msg)) {
19057
19859
  outcome = { kind: "session-expired", error: msg };
@@ -19202,7 +20004,86 @@ var init_app_settings = __esm(async () => {
19202
20004
  });
19203
20005
 
19204
20006
  // ../../packages/core/src/runtime/turn-runner.ts
19205
- import { randomUUID as randomUUID18 } from "crypto";
20007
+ var exports_turn_runner = {};
20008
+ __export(exports_turn_runner, {
20009
+ workspaceCwdFor: () => workspaceCwdFor,
20010
+ withDefaultPlaywright: () => withDefaultPlaywright,
20011
+ wasLocallyRequeuedAfterUserPreemption: () => wasLocallyRequeuedAfterUserPreemption,
20012
+ visualMediaInputError: () => visualMediaInputError,
20013
+ userConversationPromptsToRecord: () => userConversationPromptsToRecord,
20014
+ upsertTaskPanelMessage: () => upsertTaskPanelMessage,
20015
+ tryReconstructTopicRollout: () => tryReconstructTopicRollout,
20016
+ triggerTopicAiTurn: () => triggerTopicAiTurn,
20017
+ topicAllowsVisualFileId: () => topicAllowsVisualFileId,
20018
+ taskPanelMessageId: () => taskPanelMessageId,
20019
+ stripMermaidFence: () => stripMermaidFence,
20020
+ stringifyError: () => stringifyError,
20021
+ streamAgentEvents: () => streamAgentEvents,
20022
+ startDurableTurnRequestWorker: () => startDurableTurnRequestWorker,
20023
+ startAiTurn: () => startAiTurn,
20024
+ selectableModel: () => selectableModel,
20025
+ sameTurnActor: () => sameTurnActor,
20026
+ safeAttachmentFilename: () => safeAttachmentFilename,
20027
+ resolveWorkerModel: () => resolveWorkerModel,
20028
+ resolveWorkerDefaultModel: () => resolveWorkerDefaultModel,
20029
+ resolveWikiMirrorPath: () => resolveWikiMirrorPath,
20030
+ resolveWikiMemoryMirror: () => resolveWikiMemoryMirror,
20031
+ resolveVisualMediaInput: () => resolveVisualMediaInput,
20032
+ resolveTurnToolCapabilities: () => resolveTurnToolCapabilities,
20033
+ resolveTurnHostMcpServers: () => resolveTurnHostMcpServers,
20034
+ resolveTopicTurnSession: () => resolveTopicTurnSession,
20035
+ resolveTopicTurnExecution: () => resolveTopicTurnExecution,
20036
+ resolveSessionRetry: () => resolveSessionRetry,
20037
+ resolveModelForAgent: () => resolveModelForAgent,
20038
+ resolveInitialTurnSessionId: () => resolveInitialTurnSessionId,
20039
+ resolveDefaultModel: () => resolveDefaultModel,
20040
+ resolveCompactionExecution: () => resolveCompactionExecution,
20041
+ renderUserTurnBatch: () => renderUserTurnBatch,
20042
+ renderUserPromptBatch: () => renderUserPromptBatch,
20043
+ renderTaskPanel: () => renderTaskPanel,
20044
+ promptWithAttachments: () => promptWithAttachments,
20045
+ prepareInjectReplayAfterUserPreemption: () => prepareInjectReplayAfterUserPreemption,
20046
+ parseAttachmentNames: () => parseAttachmentNames,
20047
+ normalizeToolUseId: () => normalizeToolUseId,
20048
+ normalizeMermaidTheme: () => normalizeMermaidTheme,
20049
+ modelOwner: () => modelOwner,
20050
+ mergeSupersedingUserTurn: () => mergeSupersedingUserTurn,
20051
+ mentionsAi: () => mentionsAi,
20052
+ materializePromptAttachments: () => materializePromptAttachments,
20053
+ isVisualsShowMermaidTool: () => isVisualsShowMermaidTool,
20054
+ isVisualsShowImageTool: () => isVisualsShowImageTool,
20055
+ isVisualsShowHtmlTool: () => isVisualsShowHtmlTool,
20056
+ isSessionExpiredError: () => isSessionExpiredError,
20057
+ isRuntimeTool: () => isRuntimeTool,
20058
+ isPathInside: () => isPathInside,
20059
+ isLikelyCurrentChannelTrigger: () => isLikelyCurrentChannelTrigger,
20060
+ ingestAttachment: () => ingestAttachment,
20061
+ formatSelectableModel: () => formatSelectableModel,
20062
+ formatChannelTranscriptLine: () => formatChannelTranscriptLine,
20063
+ escapeRegExp: () => escapeRegExp3,
20064
+ escapeHtml: () => escapeHtml2,
20065
+ deliverAskCallbackToCaller: () => deliverAskCallbackToCaller,
20066
+ composeAttachmentPrompt: () => composeAttachmentPrompt,
20067
+ classifyAgentError: () => classifyAgentError,
20068
+ channelTranscriptSpeaker: () => channelTranscriptSpeaker,
20069
+ canonicalModelId: () => canonicalModelId,
20070
+ buildVideoHtml: () => buildVideoHtml,
20071
+ buildTurnReminderQuery: () => buildTurnReminderQuery,
20072
+ buildMermaidHtml: () => buildMermaidHtml,
20073
+ buildMentionOnlyChannelPrompt: () => buildMentionOnlyChannelPrompt,
20074
+ buildImageHtml: () => buildImageHtml,
20075
+ authRecoveryHint: () => authRecoveryHint,
20076
+ attachmentPromptLine: () => attachmentPromptLine,
20077
+ activeVisualHtmlForPrompt: () => activeVisualHtmlForPrompt,
20078
+ SESSION_EXPIRED_MSG: () => SESSION_EXPIRED_MSG,
20079
+ SELECTABLE_MODELS: () => SELECTABLE_MODELS,
20080
+ MODEL_OWNER: () => MODEL_OWNER,
20081
+ MODEL_COST_ROUTING_SUMMARY: () => MODEL_COST_ROUTING_SUMMARY,
20082
+ MODEL_COST_RESEARCHED_AT: () => MODEL_COST_RESEARCHED_AT,
20083
+ FALLBACK_ORDER: () => FALLBACK_ORDER,
20084
+ AGENT_DISPLAY_NAME: () => AGENT_DISPLAY_NAME
20085
+ });
20086
+ import { randomUUID as randomUUID19 } from "crypto";
19206
20087
  import { existsSync as existsSync22, mkdirSync as mkdirSync19, readdirSync as readdirSync5, statSync as statSync10 } from "fs";
19207
20088
  import { join as join31 } from "path";
19208
20089
  function withDefaultPlaywright(configuredMcp, isManager) {
@@ -19225,12 +20106,12 @@ function buildTurnReminderQuery(agent, prompt, reminders) {
19225
20106
 
19226
20107
  ${reminderPrompt}` };
19227
20108
  }
19228
- function appendSystemMessage(topicId, text, threadRootId) {
20109
+ function appendSystemMessage(topicId, text2, threadRootId) {
19229
20110
  const message = {
19230
- id: randomUUID18(),
20111
+ id: randomUUID19(),
19231
20112
  topicId,
19232
20113
  authorId: "system",
19233
- text,
20114
+ text: text2,
19234
20115
  ...threadRootId ? { threadRootId } : {},
19235
20116
  createdAt: new Date().toISOString()
19236
20117
  };
@@ -19247,12 +20128,12 @@ function notifyPlaywrightUnavailable(topicId) {
19247
20128
  appendSystemMessage(topicId, "Playwright browser tools are unavailable this turn. Browser automation was removed from the tool catalog; retry shortly if browser interaction is required.");
19248
20129
  WsHub.get().broadcastTopicNotice(topicId, "info", "Playwright \uC0AC\uC6A9 \uBD88\uAC00");
19249
20130
  }
19250
- function appendAskReplyMessage(topicId, text, sourceLabel, body, kind, agentType, threadRootId) {
20131
+ function appendAskReplyMessage(topicId, text2, sourceLabel, body, kind, agentType, threadRootId) {
19251
20132
  const message = {
19252
- id: randomUUID18(),
20133
+ id: randomUUID19(),
19253
20134
  topicId,
19254
20135
  authorId: "ai",
19255
- text,
20136
+ text: text2,
19256
20137
  kind: "tell",
19257
20138
  tellCard: {
19258
20139
  fromLabel: sourceLabel,
@@ -19313,8 +20194,8 @@ function redispatchInject(inject) {
19313
20194
  kind: "error",
19314
20195
  error: "topic gone or AI no longer invited"
19315
20196
  });
19316
- } catch (err) {
19317
- logger.warn({ err, topicId: inject.topicId }, "ai: deferred settlement hook failed");
20197
+ } catch (err2) {
20198
+ logger.warn({ err: err2, topicId: inject.topicId }, "ai: deferred settlement hook failed");
19318
20199
  }
19319
20200
  if (inject.forkHandle)
19320
20201
  cleanupAgentFork(inject.forkHandle);
@@ -19372,28 +20253,28 @@ async function clearPendingAskFile(pending, state) {
19372
20253
  if (!pending.pendingAsk)
19373
20254
  return;
19374
20255
  try {
19375
- await init_session_asks();
20256
+ const { clearPendingAsk: clearPendingAsk2, markPendingAskState: markPendingAskState2 } = await init_session_asks().then(() => exports_session_asks);
19376
20257
  if (state)
19377
- markPendingAskState({ ...pending.pendingAsk, state });
19378
- clearPendingAsk(pending.pendingAsk);
19379
- } catch (err) {
19380
- logger.warn({ err, pendingAsk: pending.pendingAsk }, "sessions: pending ask cleanup failed");
20258
+ markPendingAskState2({ ...pending.pendingAsk, state });
20259
+ clearPendingAsk2(pending.pendingAsk);
20260
+ } catch (err2) {
20261
+ logger.warn({ err: err2, pendingAsk: pending.pendingAsk }, "sessions: pending ask cleanup failed");
19381
20262
  }
19382
20263
  }
19383
20264
  async function markPendingAskFile(pending, state) {
19384
20265
  if (!pending.pendingAsk)
19385
20266
  return;
19386
20267
  try {
19387
- await init_session_asks();
19388
- markPendingAskState({ ...pending.pendingAsk, state });
19389
- } catch (err) {
19390
- logger.warn({ err, pendingAsk: pending.pendingAsk, state }, "sessions: pending ask mark failed");
20268
+ const { markPendingAskState: markPendingAskState2 } = await init_session_asks().then(() => exports_session_asks);
20269
+ markPendingAskState2({ ...pending.pendingAsk, state });
20270
+ } catch (err2) {
20271
+ logger.warn({ err: err2, pendingAsk: pending.pendingAsk, state }, "sessions: pending ask mark failed");
19391
20272
  }
19392
20273
  }
19393
20274
  async function deliverAskCallbackToCaller(pending, sourceLabel, body, kind, options = {}) {
19394
20275
  if (pending.remoteReply) {
19395
- await init_peer_forward();
19396
- const delivered = await deliverPeerReply(pending.remoteReply, sourceLabel, body, kind);
20276
+ const { deliverPeerReply: deliverPeerReply2 } = await init_peer_forward().then(() => exports_peer_forward);
20277
+ const delivered = await deliverPeerReply2(pending.remoteReply, sourceLabel, body, kind);
19397
20278
  if (delivered)
19398
20279
  options.onRecorded?.();
19399
20280
  return delivered;
@@ -19413,8 +20294,8 @@ ${body}`;
19413
20294
  record(undefined);
19414
20295
  await clearPendingAskFile(pending);
19415
20296
  return true;
19416
- } catch (err) {
19417
- logger.warn({ err, requestId: pending.requestId, callerTopicId: pending.callerTopicId }, "sessions: ask callback direct delivery failed");
20297
+ } catch (err2) {
20298
+ logger.warn({ err: err2, requestId: pending.requestId, callerTopicId: pending.callerTopicId }, "sessions: ask callback direct delivery failed");
19418
20299
  return false;
19419
20300
  }
19420
20301
  }
@@ -19443,9 +20324,9 @@ ${body}`;
19443
20324
  if (queued) {
19444
20325
  try {
19445
20326
  record(callerTopic.agent);
19446
- } catch (err) {
20327
+ } catch (err2) {
19447
20328
  interSessionQueue.remove(pending.callerTopicId, pending.requestId);
19448
- logger.warn({ err, requestId: pending.requestId, callerTopicId: pending.callerTopicId }, "sessions: ask callback record failed after enqueue; queue entry withdrawn");
20329
+ logger.warn({ err: err2, requestId: pending.requestId, callerTopicId: pending.callerTopicId }, "sessions: ask callback record failed after enqueue; queue entry withdrawn");
19449
20330
  return false;
19450
20331
  }
19451
20332
  await markPendingAskFile(pending, "queued_for_caller");
@@ -19465,8 +20346,8 @@ ${body}`;
19465
20346
  }
19466
20347
  async function deliverAskError(queryId, sourceLabel, error) {
19467
20348
  try {
19468
- await init_ask_callbacks();
19469
- const pending = resolveAskCallback(queryId);
20349
+ const { resolveAskCallback: resolveAskCallback2 } = await init_ask_callbacks().then(() => exports_ask_callbacks);
20350
+ const pending = resolveAskCallback2(queryId);
19470
20351
  if (pending) {
19471
20352
  const prefix = pending.timedOut ? `\u26A0\uFE0F [Timeout - error notification was dropped]
19472
20353
 
@@ -19496,9 +20377,9 @@ function tryReconstructTopicRollout(opts) {
19496
20377
  entries: entries.length
19497
20378
  }, sessionId ? "ai: session expired \u2014 rollout reconstructed from unified log" : "ai: provider session bridged from shared conversation log");
19498
20379
  return { kind: "rebuilt", sessionId: result.sessionId };
19499
- } catch (err) {
19500
- logger.warn({ err, topicId, agent, sessionId }, "ai: session reconstruct failed");
19501
- return { kind: "failed", error: stringifyError(err) };
20380
+ } catch (err2) {
20381
+ logger.warn({ err: err2, topicId, agent, sessionId }, "ai: session reconstruct failed");
20382
+ return { kind: "failed", error: stringifyError(err2) };
19502
20383
  }
19503
20384
  }
19504
20385
  function resolveSessionRetry(opts) {
@@ -19607,8 +20488,8 @@ function waitToStartRemoteUserTurn(params, queryId, options) {
19607
20488
  function announceQueuedUserTurn(params, queryId) {
19608
20489
  try {
19609
20490
  params.onDispatched?.(queryId);
19610
- } catch (err) {
19611
- logger.warn({ err, topicId: params.topic.id, queryId }, "ai: queued dispatch hook failed");
20491
+ } catch (err2) {
20492
+ logger.warn({ err: err2, topicId: params.topic.id, queryId }, "ai: queued dispatch hook failed");
19612
20493
  }
19613
20494
  if (!params.silent)
19614
20495
  WsHub.get().broadcastAiActive(params.topic.id, queryId);
@@ -19629,6 +20510,81 @@ function waitToDrainRemoteInject(topicId) {
19629
20510
  timer.unref?.();
19630
20511
  remoteInjectWaiters.set(topicId, timer);
19631
20512
  }
20513
+ async function drainOneDurableUserTurn() {
20514
+ if (durableTurnWorkerBusy)
20515
+ return;
20516
+ durableTurnWorkerBusy = true;
20517
+ try {
20518
+ const request = claimNextRuntimeUserTurnRequest(RUNTIME_INSTANCE_ID);
20519
+ if (!request)
20520
+ return;
20521
+ const topic = getTopic(request.topicId);
20522
+ if (!topic?.agent) {
20523
+ completeRuntimeUserTurnRequest(request.topicId, request.requestId, RUNTIME_INSTANCE_ID);
20524
+ return;
20525
+ }
20526
+ const execution = request.execution;
20527
+ const queryId = startAiTurn({
20528
+ topic,
20529
+ userId: request.userId,
20530
+ actorUserId: execution?.actorUserId,
20531
+ actorTopicScope: actorTopicScopeFrom(execution?.actorTopicScope),
20532
+ remoteSession: remoteSessionGrantFrom(execution?.remoteSession),
20533
+ vaultUserId: execution?.vaultUserId,
20534
+ prompt: request.prompt,
20535
+ _userMessages: request.userMessages,
20536
+ _conversationPrompts: execution?.conversationPrompts ?? [request.prompt],
20537
+ _loggedUserMessageCount: execution?.loggedUserMessageCount ?? Math.max(0, request.userMessages.length - (execution?.conversationPrompts?.length ?? 1)),
20538
+ _durableRequestIds: [request.requestId],
20539
+ attachments: request.attachments,
20540
+ allowAutoContinue: request.allowAutoContinue,
20541
+ origin: "user",
20542
+ requestId: execution?.sourceRequestId,
20543
+ agentOverride: execution?.agentOverride,
20544
+ modelOverride: execution?.modelOverride,
20545
+ effortOverride: execution?.effortOverride,
20546
+ ...execution?.sessionIdSpecified ? { sessionId: execution.sessionId } : {},
20547
+ sessionScope: execution?.sessionScope,
20548
+ cwd: execution?.cwd,
20549
+ sessionName: execution?.sessionName,
20550
+ sessionType: execution?.sessionType,
20551
+ visualTools: execution?.visualTools,
20552
+ fileDeliveryTools: execution?.fileDeliveryTools,
20553
+ silent: execution?.silent,
20554
+ bridgeSessionFromHistory: execution?.bridgeSessionFromHistory,
20555
+ peerBridge: execution?.peerBridge,
20556
+ from: execution?.from,
20557
+ threadRootId: execution?.threadRootId,
20558
+ _queryId: request.requestId,
20559
+ _runtimeEpoch: execution?.runtimeEpoch ?? request.topicEpoch,
20560
+ onSettled: () => {
20561
+ completeRuntimeUserTurnRequest(request.topicId, request.requestId, RUNTIME_INSTANCE_ID);
20562
+ }
20563
+ });
20564
+ if (!queryId) {
20565
+ releaseRuntimeUserTurnClaim(request.topicId, request.requestId, RUNTIME_INSTANCE_ID);
20566
+ return;
20567
+ }
20568
+ markRuntimeUserTurnRunning(request.topicId, request.requestId, RUNTIME_INSTANCE_ID, queryId);
20569
+ } finally {
20570
+ durableTurnWorkerBusy = false;
20571
+ }
20572
+ }
20573
+ function startDurableTurnRequestWorker() {
20574
+ if (durableTurnWorker)
20575
+ return () => {};
20576
+ durableTurnWorker = setInterval(() => {
20577
+ drainOneDurableUserTurn();
20578
+ }, 100);
20579
+ durableTurnWorker.unref?.();
20580
+ drainOneDurableUserTurn();
20581
+ return () => {
20582
+ if (!durableTurnWorker)
20583
+ return;
20584
+ clearInterval(durableTurnWorker);
20585
+ durableTurnWorker = null;
20586
+ };
20587
+ }
19632
20588
  function startAiTurn(params) {
19633
20589
  const storedTopic = getTopic(params.topic.id);
19634
20590
  if (!storedTopic || !storedTopic.agent && !params.agentOverride) {
@@ -19640,8 +20596,8 @@ function startAiTurn(params) {
19640
20596
  kind: "error",
19641
20597
  error: storedTopic ? "topic no longer has an AI agent" : "topic no longer exists"
19642
20598
  });
19643
- } catch (err) {
19644
- logger.warn({ err, topicId: params.topic.id }, "ai: rejected-turn settlement hook failed");
20599
+ } catch (err2) {
20600
+ logger.warn({ err: err2, topicId: params.topic.id }, "ai: rejected-turn settlement hook failed");
19645
20601
  }
19646
20602
  return null;
19647
20603
  }
@@ -19697,7 +20653,7 @@ function startAiTurn(params) {
19697
20653
  const askReplySources = params.askReplySources;
19698
20654
  const sessionRetried = params._sessionRetried === true;
19699
20655
  const emptyResponseRetried = params._emptyResponseRetried === true;
19700
- const queryId = asTurnId(params._queryId ?? randomUUID18());
20656
+ const queryId = asTurnId(params._queryId ?? randomUUID19());
19701
20657
  const roomId = turnConcurrency === "isolated" ? isolatedTurnRoomId(topicId, queryId) : asTurnSlotKey(topicId);
19702
20658
  const currentRuntimeEpoch = getRuntimeTopicEpoch(topic.id);
19703
20659
  const runtimeEpoch = params._runtimeEpoch ?? currentRuntimeEpoch;
@@ -19709,8 +20665,8 @@ function startAiTurn(params) {
19709
20665
  }
19710
20666
  try {
19711
20667
  params.onSettled?.({ queryId, kind: "aborted", abortReason: "external" /* External */ });
19712
- } catch (err) {
19713
- logger.warn({ err, topicId: topic.id, queryId }, "ai: stale-turn settlement hook failed");
20668
+ } catch (err2) {
20669
+ logger.warn({ err: err2, topicId: topic.id, queryId }, "ai: stale-turn settlement hook failed");
19714
20670
  }
19715
20671
  logger.info({ topicId: topic.id, queryId, queuedEpoch: params._runtimeEpoch, currentRuntimeEpoch }, "ai: dropped work queued before topic reset");
19716
20672
  return null;
@@ -19760,8 +20716,8 @@ function startAiTurn(params) {
19760
20716
  cleanupAgentFork(forkHandle);
19761
20717
  try {
19762
20718
  onSettled?.({ queryId: "", kind: "error", error });
19763
- } catch (err) {
19764
- logger.warn({ err, topicId, queryId }, "ai: isolated-turn rejection hook failed");
20719
+ } catch (err2) {
20720
+ logger.warn({ err: err2, topicId, queryId }, "ai: isolated-turn rejection hook failed");
19765
20721
  }
19766
20722
  return null;
19767
20723
  };
@@ -19808,7 +20764,7 @@ function startAiTurn(params) {
19808
20764
  if (decision.action === "abort-replace") {
19809
20765
  const running = decision.running;
19810
20766
  if (isUserOrigin(running.origin) && !sameTurnActor(running.actorUserId, params.actorUserId)) {
19811
- const queuedQueryId = waitToStartRemoteUserTurn({
20767
+ const queuedQueryId2 = waitToStartRemoteUserTurn({
19812
20768
  ...params,
19813
20769
  topic,
19814
20770
  prompt,
@@ -19820,9 +20776,9 @@ function startAiTurn(params) {
19820
20776
  _durableRequestIds: durableRequestIds,
19821
20777
  _runtimeEpoch: runtimeEpoch
19822
20778
  }, queryId);
19823
- announceQueuedUserTurn({ ...params, topic }, queuedQueryId);
19824
- logger.info({ topicId, queryId: queuedQueryId, runningQueryId: running.queryId }, "ai: user turn from another actor queued behind the running turn");
19825
- return queuedQueryId;
20779
+ announceQueuedUserTurn({ ...params, topic }, queuedQueryId2);
20780
+ logger.info({ topicId, queryId: queuedQueryId2, runningQueryId: running.queryId }, "ai: user turn from another actor queued behind the running turn");
20781
+ return queuedQueryId2;
19826
20782
  }
19827
20783
  let omitRequestIds;
19828
20784
  if (isUserOrigin(running.origin)) {
@@ -19954,14 +20910,14 @@ function startAiTurn(params) {
19954
20910
  if (turnConcurrency === "topic") {
19955
20911
  try {
19956
20912
  writeQueryState(userId, topic.id, topic.title, prompt);
19957
- } catch (err) {
19958
- logger.warn({ err, topicId, userId }, "ai: failed to write active query state");
20913
+ } catch (err2) {
20914
+ logger.warn({ err: err2, topicId, userId }, "ai: failed to write active query state");
19959
20915
  }
19960
20916
  }
19961
20917
  try {
19962
20918
  onDispatched?.(queryId);
19963
- } catch (err) {
19964
- logger.warn({ err, topicId, queryId }, "ai: dispatch hook failed");
20919
+ } catch (err2) {
20920
+ logger.warn({ err: err2, topicId, queryId }, "ai: dispatch hook failed");
19965
20921
  }
19966
20922
  const override = getTopicConfig(topicId);
19967
20923
  const agentKind = execution.agent;
@@ -19988,8 +20944,8 @@ function startAiTurn(params) {
19988
20944
  control.injectParams.sessionId = bridge.sessionId;
19989
20945
  try {
19990
20946
  onSessionId?.(bridge.sessionId);
19991
- } catch (err) {
19992
- logger.warn({ err, topicId, queryId, agent: agentKind }, "ai: isolated session owner rejected bridged provider session id");
20947
+ } catch (err2) {
20948
+ logger.warn({ err: err2, topicId, queryId, agent: agentKind }, "ai: isolated session owner rejected bridged provider session id");
19993
20949
  }
19994
20950
  } else if (bridge.kind === "failed") {
19995
20951
  historyBridgeError = "Conversation history could not be encoded into a provider session; no fresh session was started.";
@@ -20058,8 +21014,8 @@ function startAiTurn(params) {
20058
21014
  const wikiDir = getSharedWikiDir();
20059
21015
  const { latestSummaryFile } = resolveWikiMemoryMirror(wikiDir, memoryTopic.id, memoryTitle);
20060
21016
  hasMemoryArchive = Boolean(resolvedBrief?.brief.latestSummaryMd || latestSummaryFile);
20061
- } catch (err) {
20062
- logger.warn({ topicId, err }, "ai: failed to inject topic brief");
21017
+ } catch (err2) {
21018
+ logger.warn({ topicId, err: err2 }, "ai: failed to inject topic brief");
20063
21019
  }
20064
21020
  systemPrompt += buildMemoryPromptSection({
20065
21021
  topicTitle: topic.title,
@@ -20135,8 +21091,8 @@ function startAiTurn(params) {
20135
21091
  control.injectParams.sessionId = prepared.forkId;
20136
21092
  control.injectParams.forkHandle = prepared;
20137
21093
  }
20138
- } catch (err) {
20139
- throw new Error(`failed to prepare isolated session: ${stringifyError(err)}`);
21094
+ } catch (err2) {
21095
+ throw new Error(`failed to prepare isolated session: ${stringifyError(err2)}`);
20140
21096
  }
20141
21097
  if (abortController.signal.aborted)
20142
21098
  return;
@@ -20155,8 +21111,8 @@ function startAiTurn(params) {
20155
21111
  throw new Error("browser MCP capability was not registered");
20156
21112
  }
20157
21113
  trackPlaywrightTurn(playwrightInstanceKey, control);
20158
- } catch (err) {
20159
- logger.warn({ topicId, err }, "ai: ensurePlaywright failed \u2014 proceeding without browser tools");
21114
+ } catch (err2) {
21115
+ logger.warn({ topicId, err: err2 }, "ai: ensurePlaywright failed \u2014 proceeding without browser tools");
20160
21116
  markPlaywrightUnavailable({
20161
21117
  userId,
20162
21118
  topic: topic.title,
@@ -20169,8 +21125,8 @@ function startAiTurn(params) {
20169
21125
  if (wantsBgBash) {
20170
21126
  try {
20171
21127
  bgBashPort = await ensureBgBash(userId, topic.id);
20172
- } catch (err) {
20173
- logger.warn({ topicId, err }, "ai: ensureBgBash failed \u2014 proceeding without background bash tools");
21128
+ } catch (err2) {
21129
+ logger.warn({ topicId, err: err2 }, "ai: ensureBgBash failed \u2014 proceeding without background bash tools");
20174
21130
  turnReminders.push("<system-reminder>Background bash tools are UNAVAILABLE this turn. The `background_bash_*` tools could not be prepared, most often because the bash-rs binary is not installed on this host. Do not attempt to call them; run short commands in the foreground instead, and tell the user if the work genuinely needs a background job.</system-reminder>");
20175
21131
  }
20176
21132
  }
@@ -20383,8 +21339,8 @@ function startAiTurn(params) {
20383
21339
  await settleSubagentFailure(queryId, error);
20384
21340
  try {
20385
21341
  onSettled?.({ queryId, kind: "error", error });
20386
- } catch (err) {
20387
- logger.warn({ err, topicId, queryId }, "ai: turn settlement hook failed");
21342
+ } catch (err2) {
21343
+ logger.warn({ err: err2, topicId, queryId }, "ai: turn settlement hook failed");
20388
21344
  }
20389
21345
  return;
20390
21346
  }
@@ -20400,8 +21356,8 @@ function startAiTurn(params) {
20400
21356
  await settleSubagentFailure(queryId, classifyAgentError(outcome.error, agentKind));
20401
21357
  try {
20402
21358
  onSettled?.({ queryId, kind: "error", error: outcome.error });
20403
- } catch (err) {
20404
- logger.warn({ err, topicId, queryId }, "ai: turn settlement hook failed");
21359
+ } catch (err2) {
21360
+ logger.warn({ err: err2, topicId, queryId }, "ai: turn settlement hook failed");
20405
21361
  }
20406
21362
  return;
20407
21363
  }
@@ -20414,12 +21370,12 @@ function startAiTurn(params) {
20414
21370
  kind: outcome.kind === "aborted" ? "aborted" : "completed",
20415
21371
  ...outcome.kind === "aborted" ? { abortReason: control.abortReason } : {}
20416
21372
  });
20417
- } catch (err) {
20418
- logger.warn({ err, topicId, queryId }, "ai: turn settlement hook failed");
21373
+ } catch (err2) {
21374
+ logger.warn({ err: err2, topicId, queryId }, "ai: turn settlement hook failed");
20419
21375
  }
20420
- }).catch(async (err) => {
20421
- const error = err instanceof Error ? err.message : "Agent process crashed";
20422
- logger.warn({ err, topicId, queryId, agent: agentKind, model: resolvedModel, silent }, "ai: background stream task failed");
21376
+ }).catch(async (err2) => {
21377
+ const error = err2 instanceof Error ? err2.message : "Agent process crashed";
21378
+ logger.warn({ err: err2, topicId, queryId, agent: agentKind, model: resolvedModel, silent }, "ai: background stream task failed");
20423
21379
  if (!silent) {
20424
21380
  WsHub.get().broadcastError(topicId, queryId, error);
20425
21381
  WsHub.get().broadcastTopicNotice(topicId, "error", "\uC751\uB2F5 \uC2E4\uD328");
@@ -20468,7 +21424,7 @@ function triggerTopicAiTurn(topicId, userId, prompt, agentType, opts) {
20468
21424
  if (!opts?.silent && !opts?.hideInjectMessage) {
20469
21425
  const now = new Date().toISOString();
20470
21426
  const injectMsg = {
20471
- id: opts?.requestId ? `tell-${opts.requestId}` : `tell-${randomUUID18()}`,
21427
+ id: opts?.requestId ? `tell-${opts.requestId}` : `tell-${randomUUID19()}`,
20472
21428
  topicId,
20473
21429
  authorId: opts?.injectAuthorId ?? userId,
20474
21430
  sourceAdapter: opts?.injectSourceAdapter,
@@ -20525,7 +21481,7 @@ function triggerTopicAiTurn(topicId, userId, prompt, agentType, opts) {
20525
21481
  from: opts?.from
20526
21482
  });
20527
21483
  }
20528
- var PLAYWRIGHT_UNAVAILABLE_NOTICE_COOLDOWN_MS, ASK_REPLY_INJECT_BATCH_MS = 500, playwrightUnavailableNoticeAt, askReplyInjectBatcher, remoteInjectWaiters;
21484
+ var PLAYWRIGHT_UNAVAILABLE_NOTICE_COOLDOWN_MS, ASK_REPLY_INJECT_BATCH_MS = 500, playwrightUnavailableNoticeAt, askReplyInjectBatcher, remoteInjectWaiters, durableTurnWorker = null, durableTurnWorkerBusy = false;
20529
21485
  var init_turn_runner = __esm(async () => {
20530
21486
  init_manager();
20531
21487
  init_constants();
@@ -20656,29 +21612,29 @@ function createSubagentLifecycle(host) {
20656
21612
  }
20657
21613
  function computeSubagentDepth(topicId) {
20658
21614
  let depth = 0;
20659
- let current = host.storage.getTopic(topicId);
21615
+ let current3 = host.storage.getTopic(topicId);
20660
21616
  const visited = new Set;
20661
- while (current) {
20662
- if (visited.has(current.id))
21617
+ while (current3) {
21618
+ if (visited.has(current3.id))
20663
21619
  return limits.maxDepth;
20664
- visited.add(current.id);
20665
- if (current.isSubagent)
21620
+ visited.add(current3.id);
21621
+ if (current3.isSubagent)
20666
21622
  depth += 1;
20667
- if (!current.parentTopicId || current.parentTopicId === current.id)
21623
+ if (!current3.parentTopicId || current3.parentTopicId === current3.id)
20668
21624
  break;
20669
- current = host.storage.getTopic(current.parentTopicId);
21625
+ current3 = host.storage.getTopic(current3.parentTopicId);
20670
21626
  }
20671
21627
  return depth;
20672
21628
  }
20673
- function canSpawnSubagentsFromTopic(topicId) {
21629
+ function canSpawnSubagentsFromTopic2(topicId) {
20674
21630
  const topic = host.storage.getTopic(topicId);
20675
21631
  return topic?.kind === "agent" && computeSubagentDepth(topicId) < limits.maxDepth;
20676
21632
  }
20677
21633
  function patchSubagentCard(parentTopicId, cardMessageId, patch) {
20678
- const current = host.storage.getMessage(parentTopicId, cardMessageId)?.subagentCard;
20679
- if (!current)
21634
+ const current3 = host.storage.getMessage(parentTopicId, cardMessageId)?.subagentCard;
21635
+ if (!current3)
20680
21636
  return;
20681
- const next = { ...current, ...patch };
21637
+ const next = { ...current3, ...patch };
20682
21638
  const editedAt = host.runtime.now();
20683
21639
  if (!host.storage.updateSubagentCard(parentTopicId, cardMessageId, next, editedAt))
20684
21640
  return;
@@ -20698,7 +21654,7 @@ function createSubagentLifecycle(host) {
20698
21654
  patchSubagentCard(watch.parentTopicId, watch.cardMessageId, { status: "running" });
20699
21655
  }
20700
21656
  }
20701
- function takeSubagentWatch(queryId) {
21657
+ function takeSubagentWatch2(queryId) {
20702
21658
  const childTopicId = childByQueryId.get(queryId);
20703
21659
  if (!childTopicId)
20704
21660
  return recoverPersistedSubagentWatch(queryId);
@@ -20742,7 +21698,7 @@ function createSubagentLifecycle(host) {
20742
21698
  if (watch.queryId)
20743
21699
  childByQueryId.delete(watch.queryId);
20744
21700
  }
20745
- function cancelSubagentWatchForDeletedTopic(childTopicId) {
21701
+ function cancelSubagentWatchForDeletedTopic2(childTopicId) {
20746
21702
  const watch = watchesByChild.get(childTopicId);
20747
21703
  if (!watch)
20748
21704
  return;
@@ -20772,8 +21728,8 @@ function createSubagentLifecycle(host) {
20772
21728
  if (!await host.sessionCommunication.notifyParent({ watch, prompt, requestId })) {
20773
21729
  appendParentSystemNote(watch, prompt);
20774
21730
  }
20775
- } catch (err) {
20776
- logger.warn({ err, parentTopicId: watch.parentTopicId, childTopicId: watch.childTopicId, noteKind }, "subagent: parent AI notify failed \u2014 falling back to system message");
21731
+ } catch (err2) {
21732
+ logger.warn({ err: err2, parentTopicId: watch.parentTopicId, childTopicId: watch.childTopicId, noteKind }, "subagent: parent AI notify failed \u2014 falling back to system message");
20777
21733
  try {
20778
21734
  appendParentSystemNote(watch, prompt);
20779
21735
  } catch (fallbackErr) {
@@ -20785,7 +21741,7 @@ function createSubagentLifecycle(host) {
20785
21741
  }
20786
21742
  }
20787
21743
  }
20788
- async function settleSubagentSuccess(watch, finalText) {
21744
+ async function settleSubagentSuccess2(watch, finalText) {
20789
21745
  const summary = finalText.replace(/\s+/g, " ").trim().slice(0, RESULT_SUMMARY_CHARS);
20790
21746
  try {
20791
21747
  patchSubagentCard(watch.parentTopicId, watch.cardMessageId, {
@@ -20793,8 +21749,8 @@ function createSubagentLifecycle(host) {
20793
21749
  resultSummary: summary || "(no text response)",
20794
21750
  finishedAt: host.runtime.now()
20795
21751
  });
20796
- } catch (err) {
20797
- logger.warn({ err, parentTopicId: watch.parentTopicId, cardMessageId: watch.cardMessageId }, "subagent: completed-card update failed");
21752
+ } catch (err2) {
21753
+ logger.warn({ err: err2, parentTopicId: watch.parentTopicId, cardMessageId: watch.cardMessageId }, "subagent: completed-card update failed");
20798
21754
  }
20799
21755
  if (watch.reportMode === "auto") {
20800
21756
  await notifyParent(watch, `[Subagent completed \u2190 ${watch.name}]
@@ -20803,8 +21759,8 @@ function createSubagentLifecycle(host) {
20803
21759
  ${finalText || "(no text response)"}`, "done");
20804
21760
  }
20805
21761
  }
20806
- async function settleSubagentFailure(queryId, reason) {
20807
- const watch = takeSubagentWatch(queryId);
21762
+ async function settleSubagentFailure2(queryId, reason) {
21763
+ const watch = takeSubagentWatch2(queryId);
20808
21764
  if (!watch)
20809
21765
  return;
20810
21766
  try {
@@ -20813,8 +21769,8 @@ ${finalText || "(no text response)"}`, "done");
20813
21769
  errorMessage: reason,
20814
21770
  finishedAt: host.runtime.now()
20815
21771
  });
20816
- } catch (err) {
20817
- logger.warn({ err, parentTopicId: watch.parentTopicId, cardMessageId: watch.cardMessageId }, "subagent: failed-card update failed");
21772
+ } catch (err2) {
21773
+ logger.warn({ err: err2, parentTopicId: watch.parentTopicId, cardMessageId: watch.cardMessageId }, "subagent: failed-card update failed");
20818
21774
  }
20819
21775
  if (watch.reportMode === "auto") {
20820
21776
  await notifyParent(watch, `[Subagent failed \u2190 ${watch.name}]
@@ -20851,7 +21807,7 @@ spawn_subagent\uB85C \uC704\uC784\uD55C \uC791\uC5C5\uC774 \uC2E4\uD328\uD588\uC
20851
21807
  function findSubagentCardMessage(childTopicId) {
20852
21808
  return host.storage.listSubagentMessages().filter((message) => message.subagentCard?.subagentTopicId === childTopicId).at(-1);
20853
21809
  }
20854
- function subagentReportMode(childTopicId) {
21810
+ function subagentReportMode2(childTopicId) {
20855
21811
  return host.storage.getTopic(childTopicId)?.subagentReportMode ?? findSubagentCardMessage(childTopicId)?.subagentCard?.reportMode ?? "auto";
20856
21812
  }
20857
21813
  async function startSubagentCard(ctx, cardMessage) {
@@ -21059,7 +22015,7 @@ ${card.task}${reportInstruction}`;
21059
22015
  for (const siblings of byParent.values()) {
21060
22016
  siblings.sort((a, b) => a.createdAt.localeCompare(b.createdAt) || a.id.localeCompare(b.id));
21061
22017
  }
21062
- const descendants = [];
22018
+ const descendants2 = [];
21063
22019
  const visited = new Set([ctx.topicId]);
21064
22020
  const visit = (parentId) => {
21065
22021
  for (const child of byParent.get(parentId) ?? []) {
@@ -21069,12 +22025,12 @@ ${card.task}${reportInstruction}`;
21069
22025
  if (!child.participants.some((participant) => participant.userId === rootOwnerId && participant.role === "owner")) {
21070
22026
  continue;
21071
22027
  }
21072
- descendants.push(child);
22028
+ descendants2.push(child);
21073
22029
  visit(child.id);
21074
22030
  }
21075
22031
  };
21076
22032
  visit(ctx.topicId);
21077
- return descendants;
22033
+ return descendants2;
21078
22034
  })() : [];
21079
22035
  const children = actorScope ? descendants.filter((child) => actorScope.visible.has(child.id)) : descendants;
21080
22036
  return {
@@ -21098,10 +22054,10 @@ ${card.task}${reportInstruction}`;
21098
22054
  return card?.status ?? "unknown";
21099
22055
  }
21100
22056
  function listMemoryTopicNames(ctx) {
21101
- const current = host.storage.getTopic(ctx.topicId);
21102
- if (!current)
22057
+ const current3 = host.storage.getTopic(ctx.topicId);
22058
+ if (!current3)
21103
22059
  return { error: `Error: topic '${ctx.topicId}' not found.` };
21104
- if (!current.participants.some((participant) => participant.userId === ctx.userId)) {
22060
+ if (!current3.participants.some((participant) => participant.userId === ctx.userId)) {
21105
22061
  return { error: "Error: user is not a member of this topic." };
21106
22062
  }
21107
22063
  const sources = new Map;
@@ -21191,8 +22147,8 @@ ${card.task}${reportInstruction}`;
21191
22147
  try {
21192
22148
  await host.topic.delete(child, ctx.userId);
21193
22149
  return textResult(`Subagent deleted: ${child.title} (${child.id})`);
21194
- } catch (err) {
21195
- const message = err instanceof Error ? err.message : String(err);
22150
+ } catch (err2) {
22151
+ const message = err2 instanceof Error ? err2.message : String(err2);
21196
22152
  return errorResult(`Error: failed to delete subagent '${child.title}': ${message}`);
21197
22153
  }
21198
22154
  }
@@ -21289,13 +22245,13 @@ ${card.task}${reportInstruction}`;
21289
22245
  }
21290
22246
  return {
21291
22247
  computeSubagentDepth,
21292
- canSpawnSubagentsFromTopic,
21293
- takeSubagentWatch,
21294
- cancelSubagentWatchForDeletedTopic,
21295
- settleSubagentSuccess,
21296
- settleSubagentFailure,
22248
+ canSpawnSubagentsFromTopic: canSpawnSubagentsFromTopic2,
22249
+ takeSubagentWatch: takeSubagentWatch2,
22250
+ cancelSubagentWatchForDeletedTopic: cancelSubagentWatchForDeletedTopic2,
22251
+ settleSubagentSuccess: settleSubagentSuccess2,
22252
+ settleSubagentFailure: settleSubagentFailure2,
21297
22253
  sweepStaleSubagentCards,
21298
- subagentReportMode,
22254
+ subagentReportMode: subagentReportMode2,
21299
22255
  createSubagentManagementToolDefinitions,
21300
22256
  createSpawnSubagentToolDefinition,
21301
22257
  createPrepareSubagentToolDefinition
@@ -21342,9 +22298,9 @@ var init_spawn_subagent = __esm(async () => {
21342
22298
  },
21343
22299
  topic: {
21344
22300
  async createDerived(input) {
21345
- await init_derive();
22301
+ const { createDerivedTopic: createDerivedTopic2, TopicDeriveBusyError: TopicDeriveBusyError2, TopicTitleConflictError: TopicTitleConflictError2 } = await init_derive().then(() => exports_derive);
21346
22302
  try {
21347
- const topic = await createDerivedTopic(input.parentTopicId, input.userId, false, {
22303
+ const topic = await createDerivedTopic2(input.parentTopicId, input.userId, false, {
21348
22304
  name: input.name,
21349
22305
  subagent: {
21350
22306
  agent: input.agent,
@@ -21354,30 +22310,30 @@ var init_spawn_subagent = __esm(async () => {
21354
22310
  });
21355
22311
  return { ok: true, topic };
21356
22312
  } catch (error) {
21357
- if (error instanceof TopicTitleConflictError) {
22313
+ if (error instanceof TopicTitleConflictError2) {
21358
22314
  return { ok: false, reason: "title-conflict", message: error.message };
21359
22315
  }
21360
- if (error instanceof TopicDeriveBusyError)
22316
+ if (error instanceof TopicDeriveBusyError2)
21361
22317
  return { ok: false, reason: "busy" };
21362
22318
  throw error;
21363
22319
  }
21364
22320
  },
21365
22321
  async delete(topic, userId) {
21366
- await init_lifecycle();
21367
- await deleteTopicCascade(topic, userId);
22322
+ const { deleteTopicCascade: deleteTopicCascade2 } = await init_lifecycle().then(() => exports_lifecycle);
22323
+ await deleteTopicCascade2(topic, userId);
21368
22324
  }
21369
22325
  },
21370
22326
  task: {
21371
22327
  async dispatch(input) {
21372
- await init_turn_runner();
21373
- await init_active_rooms();
21374
- const queryId = triggerTopicAiTurn(input.child.id, input.userId, input.prompt, undefined, {
22328
+ const { triggerTopicAiTurn: triggerTopicAiTurn2 } = await init_turn_runner().then(() => exports_turn_runner);
22329
+ const { getRoomQuery: getRoomQuery2 } = await init_active_rooms().then(() => exports_active_rooms);
22330
+ const queryId = triggerTopicAiTurn2(input.child.id, input.userId, input.prompt, undefined, {
21375
22331
  origin: `subagent-task:${input.parent.title}`,
21376
22332
  requestId: input.requestId,
21377
22333
  injectAuthorId: "ai",
21378
22334
  onDispatched: input.onDispatched
21379
22335
  });
21380
- return { accepted: Boolean(queryId || getRoomQuery(input.child.id)) };
22336
+ return { accepted: Boolean(queryId || getRoomQuery2(input.child.id)) };
21381
22337
  }
21382
22338
  },
21383
22339
  sessionCommunication: {
@@ -21385,16 +22341,16 @@ var init_spawn_subagent = __esm(async () => {
21385
22341
  const parent = getTopic(watch.parentTopicId);
21386
22342
  if (!parent)
21387
22343
  return true;
21388
- await init_turn_runner();
21389
- const queryId = parent.agent ? triggerTopicAiTurn(watch.parentTopicId, watch.userId, prompt, undefined, {
22344
+ const { triggerTopicAiTurn: triggerTopicAiTurn2 } = await init_turn_runner().then(() => exports_turn_runner);
22345
+ const queryId = parent.agent ? triggerTopicAiTurn2(watch.parentTopicId, watch.userId, prompt, undefined, {
21390
22346
  origin: `subagent:${watch.name}`,
21391
22347
  requestId,
21392
22348
  hideInjectMessage: true
21393
22349
  }) : null;
21394
22350
  if (queryId)
21395
22351
  return true;
21396
- await init_active_rooms();
21397
- return Boolean(parent.agent && interSessionQueue.hasRequest(parent.id, requestId));
22352
+ const { interSessionQueue: interSessionQueue2 } = await init_active_rooms().then(() => exports_active_rooms);
22353
+ return Boolean(parent.agent && interSessionQueue2.hasRequest(parent.id, requestId));
21398
22354
  },
21399
22355
  listTellTargetIds: listSubagentTellTargetIds,
21400
22356
  grantTellTarget: grantSubagentTellTarget,
@@ -21423,19 +22379,19 @@ var init_spawn_subagent = __esm(async () => {
21423
22379
  async resolveAgentModel({ context, agent, model, hasOverride }) {
21424
22380
  let resolvedModel = model;
21425
22381
  if (model) {
21426
- await Promise.resolve().then(() => init_model_catalog());
21427
- await init_registry();
21428
- const registry = getRegistry(agent);
22382
+ const { resolveModelForAgent: resolveModelForAgent2 } = await Promise.resolve().then(() => (init_model_catalog(), exports_model_catalog));
22383
+ const { getRegistry: getRegistry2 } = await init_registry().then(() => exports_registry);
22384
+ const registry = getRegistry2(agent);
21429
22385
  if (!registry.validateModel(model)) {
21430
22386
  return { error: `Error: model '${model}' is not valid for agent '${agent}'.` };
21431
22387
  }
21432
- resolvedModel = resolveModelForAgent(agent, model, registry);
22388
+ resolvedModel = resolveModelForAgent2(agent, model, registry);
21433
22389
  }
21434
22390
  if (hasOverride) {
21435
- await init_auth_check();
21436
- await init_registry();
21437
- const targetModel = resolvedModel ?? getRegistry(agent).defaultModel;
21438
- const auth = checkAgentModelAuth(agent, targetModel, undefined, context.userId);
22391
+ const { checkAgentModelAuth: checkAgentModelAuth2 } = await init_auth_check().then(() => exports_auth_check);
22392
+ const { getRegistry: getRegistry2 } = await init_registry().then(() => exports_registry);
22393
+ const targetModel = resolvedModel ?? getRegistry2(agent).defaultModel;
22394
+ const auth = checkAgentModelAuth2(agent, targetModel, undefined, context.userId);
21439
22395
  if (!auth.ok) {
21440
22396
  return { error: `Error: agent '${agent}' is not available: ${auth.error}` };
21441
22397
  }
@@ -21865,11 +22821,11 @@ var DEFAULT_SELF_CONFIG_PRODUCT = {
21865
22821
  derivedTopicLimit: SELF_CONFIG_DERIVED_TOPIC_LIMIT,
21866
22822
  toolDescriptions: {}
21867
22823
  };
21868
- function ok(text) {
21869
- return { text };
22824
+ function ok(text2) {
22825
+ return { text: text2 };
21870
22826
  }
21871
- function err(text) {
21872
- return { text, isError: true };
22827
+ function err(text2) {
22828
+ return { text: text2, isError: true };
21873
22829
  }
21874
22830
  function errorMessage(error) {
21875
22831
  return error instanceof Error ? error.message : String(error);
@@ -22186,8 +23142,8 @@ var defaultSelfConfigHost = {
22186
23142
  },
22187
23143
  derivedTopics: {
22188
23144
  async create(sourceTopicId, userId, copyHistory, options) {
22189
- await init_derive();
22190
- return createDerivedTopic(sourceTopicId, userId, copyHistory, options);
23145
+ const { createDerivedTopic: createDerivedTopic2 } = await init_derive().then(() => exports_derive);
23146
+ return createDerivedTopic2(sourceTopicId, userId, copyHistory, options);
22191
23147
  },
22192
23148
  link: topicMarkdownLink,
22193
23149
  isTitleConflict: (error) => error instanceof Error && error.name === "TopicTitleConflictError",
@@ -22467,58 +23423,58 @@ await __promiseAll([
22467
23423
  init_topic_cleanup()
22468
23424
  ]);
22469
23425
  export {
22470
- DEFAULT_SELF_CONFIG_PRODUCT,
22471
- MIN_MEMORY_ARCHIVE_EXCHANGES,
22472
- SELF_CONFIG_CAPABILITIES,
22473
- VISUALS_MCP_KEY,
22474
- acquireCodexSpawnLock,
22475
- applySelfConfigCapabilityFilter,
22476
- archiveActiveTopicForMemory,
22477
- buildNumberedDiffSummary,
22478
- checkAgentAuth,
22479
- checkAgentModelAuth,
22480
- classifyShellToolName,
22481
- cleanupAgentFork,
22482
- cleanupTopicRollouts,
22483
- cleanupTopicRolloutsFromEntries,
22484
- createAgentForkHelpers,
22485
- createArchiverRuntime,
22486
- createAskUserRuntime,
22487
- createCodexTreeManager,
22488
- createPublishHtmlToolDefinitions,
22489
- createSelfConfigCore,
22490
- createSelfConfigRuntime,
22491
- createSelfConfigToolDefinitionsForCore,
22492
- createSubagentLifecycle,
22493
- createTopicLogMaintenance,
22494
- defaultAskUserDurabilityHost,
22495
- explicitAgentSwitchTargets,
22496
- findNewCodexChildren,
22497
- forkAgentSession,
22498
- formatToolUse,
22499
- hasExplicitAgentSwitchRequest,
22500
- isExplicitAgentSwitchTargets,
22501
- killCodexTrees,
22502
- killOwnedCodexTreesForShutdown,
22503
- normalizeAskUserChoices,
22504
- normalizeAskUserQuestionInput,
22505
- otiumVisualToolDefinitions,
22506
- purgeTopicLogs,
22507
- registerOwnedCodexPids,
22508
- resolveTaskEventScope,
22509
- rotateTopicLogs,
22510
- showHtmlTool,
22511
- showImageTool,
22512
- showMermaidTool,
22513
- showPngTool,
22514
- snapshotCodexChildren,
22515
- summarizeDisplayText,
22516
- summarizeShellCommand,
22517
- summarizeToolInput,
22518
- unregisterOwnedCodexPids,
22519
- visualToolDefinitions,
23426
+ withTaskSnapshots,
22520
23427
  withCodexSpawnSerial,
22521
- withTaskSnapshots
23428
+ visualToolDefinitions,
23429
+ unregisterOwnedCodexPids,
23430
+ summarizeToolInput,
23431
+ summarizeShellCommand,
23432
+ summarizeDisplayText,
23433
+ snapshotCodexChildren,
23434
+ showPngTool,
23435
+ showMermaidTool,
23436
+ showImageTool,
23437
+ showHtmlTool,
23438
+ rotateTopicLogs,
23439
+ resolveTaskEventScope,
23440
+ registerOwnedCodexPids,
23441
+ purgeTopicLogs,
23442
+ otiumVisualToolDefinitions,
23443
+ normalizeAskUserQuestionInput,
23444
+ normalizeAskUserChoices,
23445
+ killOwnedCodexTreesForShutdown,
23446
+ killCodexTrees,
23447
+ isExplicitAgentSwitchTargets,
23448
+ hasExplicitAgentSwitchRequest,
23449
+ formatToolUse,
23450
+ forkAgentSession,
23451
+ findNewCodexChildren,
23452
+ explicitAgentSwitchTargets,
23453
+ defaultAskUserDurabilityHost,
23454
+ createTopicLogMaintenance,
23455
+ createSubagentLifecycle,
23456
+ createSelfConfigToolDefinitionsForCore,
23457
+ createSelfConfigRuntime,
23458
+ createSelfConfigCore,
23459
+ createPublishHtmlToolDefinitions,
23460
+ createCodexTreeManager,
23461
+ createAskUserRuntime,
23462
+ createArchiverRuntime,
23463
+ createAgentForkHelpers,
23464
+ cleanupTopicRolloutsFromEntries,
23465
+ cleanupTopicRollouts,
23466
+ cleanupAgentFork,
23467
+ classifyShellToolName,
23468
+ checkAgentModelAuth,
23469
+ checkAgentAuth,
23470
+ buildNumberedDiffSummary,
23471
+ archiveActiveTopicForMemory,
23472
+ applySelfConfigCapabilityFilter,
23473
+ acquireCodexSpawnLock,
23474
+ VISUALS_MCP_KEY,
23475
+ SELF_CONFIG_CAPABILITIES,
23476
+ MIN_MEMORY_ARCHIVE_EXCHANGES,
23477
+ DEFAULT_SELF_CONFIG_PRODUCT
22522
23478
  };
22523
23479
 
22524
- //# debugId=821FEE68439440EC64756E2164756E21
23480
+ //# debugId=160F1D6909B0DA3364756E2164756E21