negotium 0.5.11 → 0.5.14

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 (52) hide show
  1. package/dist/agent-helpers.js +88 -38
  2. package/dist/agent-helpers.js.map +10 -8
  3. package/dist/background-bash.js +7 -3
  4. package/dist/background-bash.js.map +3 -3
  5. package/dist/browser-runtime.js +7 -3
  6. package/dist/browser-runtime.js.map +3 -3
  7. package/dist/{chunk-n9g0wk3p.js → chunk-qgm6m2hc.js} +7 -3
  8. package/dist/{chunk-n9g0wk3p.js.map → chunk-qgm6m2hc.js.map} +3 -3
  9. package/dist/hosted-agent.js +8 -4
  10. package/dist/hosted-agent.js.map +4 -4
  11. package/dist/main.js +892 -512
  12. package/dist/main.js.map +22 -19
  13. package/dist/mcp-factories.js +90 -40
  14. package/dist/mcp-factories.js.map +10 -8
  15. package/dist/media.js +7 -3
  16. package/dist/media.js.map +3 -3
  17. package/dist/outbox.js +103 -21
  18. package/dist/outbox.js.map +5 -4
  19. package/dist/prompts.js +7 -3
  20. package/dist/prompts.js.map +3 -3
  21. package/dist/query-runtime.js +7 -3
  22. package/dist/query-runtime.js.map +3 -3
  23. package/dist/registry.js +3 -3
  24. package/dist/registry.js.map +2 -2
  25. package/dist/rollout.js +1 -1
  26. package/dist/runtime/src/index.ts +6 -0
  27. package/dist/runtime/src/mcp/session-comm/default-host.ts +35 -23
  28. package/dist/runtime/src/mcp/session-comm/server.ts +24 -20
  29. package/dist/runtime/src/mcp-runtime-host.ts +1 -0
  30. package/dist/runtime/src/outbox/coalescing-runner.ts +157 -0
  31. package/dist/runtime/src/outbox/index.ts +6 -0
  32. package/dist/runtime/src/platform/config.ts +11 -2
  33. package/dist/runtime/src/platform/lifecycle.ts +3 -0
  34. package/dist/runtime/src/query/session-inbox-cleanup.ts +2 -1
  35. package/dist/runtime/src/query/session-inbox-path.ts +1 -1
  36. package/dist/runtime/src/runtime/bashrs-completions.ts +13 -9
  37. package/dist/runtime/src/runtime/inbox.ts +235 -117
  38. package/dist/runtime/src/runtime/turn-runner.ts +10 -4
  39. package/dist/runtime/src/storage/session-inbox-signal.ts +76 -0
  40. package/dist/runtime/src/storage/session-inbox.ts +161 -0
  41. package/dist/runtime/src/version.ts +1 -1
  42. package/dist/runtime-helpers.js +95 -23
  43. package/dist/runtime-helpers.js.map +8 -7
  44. package/dist/types/packages/core/src/outbox/coalescing-runner.d.ts +68 -0
  45. package/dist/types/packages/core/src/outbox/index.d.ts +1 -0
  46. package/dist/types/packages/core/src/query/session-inbox-path.d.ts +1 -1
  47. package/dist/types/packages/core/src/storage/session-inbox-signal.d.ts +35 -0
  48. package/dist/types/packages/core/src/storage/session-inbox.d.ts +36 -0
  49. package/dist/types/packages/core/src/version.d.ts +1 -1
  50. package/dist/vault.js +7 -3
  51. package/dist/vault.js.map +3 -3
  52. package/package.json +1 -1
@@ -175,6 +175,11 @@ function resolveAgentEnv(envKey, fallback, legacyEnvKey) {
175
175
  const value = envText(envKey) ?? (legacyEnvKey ? envText(legacyEnvKey) : undefined);
176
176
  return isAgentKind(value) ? value : fallback;
177
177
  }
178
+ function resolveStateDir() {
179
+ const configured = envText("NEGOTIUM_STATE_DIR");
180
+ if (false) {}
181
+ return configured ? resolve2(configured) : resolve2(HOME, ".negotium");
182
+ }
178
183
  function resolveProjectRoot() {
179
184
  const moduleDir = dirname(fileURLToPath(import.meta.url));
180
185
  const packagedRuntime = resolve2(moduleDir, "runtime");
@@ -338,15 +343,14 @@ function resolveWhisperBackend() {
338
343
  function codexAuthFilePath() {
339
344
  return process.env.NEGOTIUM_CODEX_AUTH_FILE || join(process.env.CODEX_HOME || join(homedir(), ".codex"), "auth.json");
340
345
  }
341
- var HOME, PROJECT_ROOT, STATE_DIR_ENV, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR, CRON_WORKSPACE_DIR, BROWSER_DIR, BROWSER_PROFILES_DIR, BINARIES_DIR, SECRETS_DIR, DM_WORKSPACE_DIR, SESSION_WORKSPACE_DIR, CLAUDE_EXECUTABLE_ENV, CLAUDE_EXECUTABLE, DEFAULT_OUTPUT_LANGUAGE = "English", BROWSER_RS_VERSION = "v0.1.23", BROWSER_RS_MIN_SECURE_VERSION = "0.1.15", BROWSER_RS_VERSION_PROBE_TIMEOUT_MS = 15000, SNIPPETS_API_URL, BROWSER_RS_BIN, BASH_RS_VERSION = "v0.1.7", BASH_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, DECISION_SERVER, CANONICAL_MCP_PROXY_SERVER, WIKI_SERVER, TOKEN_STATS_SERVER, COMPACTION_LOG_SERVER, SYSTEM_HEALTH_SERVER, AGENT_HEALTH_SERVER, VAULT_SERVER, BG_BASH_BASE_PORT, BG_BASH_MAX_PORT, RUNTIME_MCP_SECRET, NODE_CONTROL_TOKEN, NODE_ID, VAULT_MASTER_KEY, NEGOTIUM_PORT, hostname, DATA_DIR, LOG_DIR, UPLOADS_DIR, VAULT_DIR, SESSIONS_DB, DEBUG_FILE, USERS_LOG_DIR, RUN_DIR, PROGRESS_DIR, DM_CMD_DIR, DM_RESP_DIR, SESSION_INBOX_DIR, SESSION_ASKS_DIR, BASHRS_SPILL_ROOT, PLAYWRIGHT_BASE_PORT, PLAYWRIGHT_MAX_PORT, PLAYWRIGHT_PORTS_DIR, ACTIVE_QUERY_STALE_MS, AGENTS_PROMPTS_DIR, RESOURCES_DIR, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5", MODEL_FABLE = "claude-fable-5", FALLBACK_AGENT, SESSION_AGENT, GATEWAY_AGENT, FALLBACK_MODEL, SESSION_MODEL, GATEWAY_MODEL, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, WHISPER_BACKEND, MLX_WHISPER_BIN, WHISPER_MODEL_MLX, _envMaxTellDepth, MAX_TELL_DEPTH;
346
+ var HOME, PROJECT_ROOT, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR, CRON_WORKSPACE_DIR, BROWSER_DIR, BROWSER_PROFILES_DIR, BINARIES_DIR, SECRETS_DIR, DM_WORKSPACE_DIR, SESSION_WORKSPACE_DIR, CLAUDE_EXECUTABLE_ENV, CLAUDE_EXECUTABLE, DEFAULT_OUTPUT_LANGUAGE = "English", BROWSER_RS_VERSION = "v0.1.23", BROWSER_RS_MIN_SECURE_VERSION = "0.1.15", BROWSER_RS_VERSION_PROBE_TIMEOUT_MS = 15000, SNIPPETS_API_URL, BROWSER_RS_BIN, BASH_RS_VERSION = "v0.1.7", BASH_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, DECISION_SERVER, CANONICAL_MCP_PROXY_SERVER, WIKI_SERVER, TOKEN_STATS_SERVER, COMPACTION_LOG_SERVER, SYSTEM_HEALTH_SERVER, AGENT_HEALTH_SERVER, VAULT_SERVER, BG_BASH_BASE_PORT, BG_BASH_MAX_PORT, RUNTIME_MCP_SECRET, NODE_CONTROL_TOKEN, NODE_ID, VAULT_MASTER_KEY, NEGOTIUM_PORT, hostname, DATA_DIR, LOG_DIR, UPLOADS_DIR, VAULT_DIR, SESSIONS_DB, DEBUG_FILE, USERS_LOG_DIR, RUN_DIR, PROGRESS_DIR, DM_CMD_DIR, DM_RESP_DIR, SESSION_INBOX_DIR, SESSION_ASKS_DIR, BASHRS_SPILL_ROOT, PLAYWRIGHT_BASE_PORT, PLAYWRIGHT_MAX_PORT, PLAYWRIGHT_PORTS_DIR, ACTIVE_QUERY_STALE_MS, AGENTS_PROMPTS_DIR, RESOURCES_DIR, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5", MODEL_FABLE = "claude-fable-5", FALLBACK_AGENT, SESSION_AGENT, GATEWAY_AGENT, FALLBACK_MODEL, SESSION_MODEL, GATEWAY_MODEL, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, WHISPER_BACKEND, MLX_WHISPER_BIN, WHISPER_MODEL_MLX, _envMaxTellDepth, MAX_TELL_DEPTH;
342
347
  var init_config = __esm(() => {
343
348
  init_config_helpers();
344
349
  init_logger();
345
350
  init_types();
346
351
  HOME = homedir();
347
352
  PROJECT_ROOT = resolveProjectRoot();
348
- STATE_DIR_ENV = envText("NEGOTIUM_STATE_DIR");
349
- STATE_DIR = STATE_DIR_ENV ? resolve2(STATE_DIR_ENV) : resolve2(HOME, ".negotium");
353
+ STATE_DIR = resolveStateDir();
350
354
  WORKSPACE_DIR = resolveLocalStateDir("NEGOTIUM_WORKSPACE_DIR", "workspace");
351
355
  TOPIC_WORKSPACE_DIR = resolve2(WORKSPACE_DIR, "topics");
352
356
  SHARED_WIKI_DIR = resolve2(WORKSPACE_DIR, "wiki");
@@ -2439,7 +2443,7 @@ var init_claude_registry = __esm(() => {
2439
2443
  });
2440
2444
 
2441
2445
  // ../../packages/core/src/version.ts
2442
- var NEGOTIUM_VERSION = "0.5.11";
2446
+ var NEGOTIUM_VERSION = "0.5.14";
2443
2447
 
2444
2448
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
2445
2449
  import { spawn as spawn2 } from "child_process";
@@ -13304,20 +13308,60 @@ var init_session_inbox_path = __esm(() => {
13304
13308
  init_config();
13305
13309
  });
13306
13310
 
13311
+ // ../../packages/core/src/storage/session-inbox-signal.ts
13312
+ import { join as join23 } from "path";
13313
+ var SESSION_INBOX_WAKE_FILE, listeners;
13314
+ var init_session_inbox_signal = __esm(() => {
13315
+ init_config();
13316
+ init_logger();
13317
+ SESSION_INBOX_WAKE_FILE = join23(SESSION_INBOX_DIR, ".wake");
13318
+ listeners = new Set;
13319
+ });
13320
+
13321
+ // ../../packages/core/src/storage/session-inbox.ts
13322
+ function deleteSessionInboxForTopic(topicId) {
13323
+ return Number(db.run("DELETE FROM session_inbox WHERE topic_id = ?", [topicId]).changes ?? 0);
13324
+ }
13325
+ var init_session_inbox = __esm(async () => {
13326
+ await init_forum_db();
13327
+ init_session_inbox_signal();
13328
+ await init_storage_host();
13329
+ registerStorageSchemaInitializer((database) => {
13330
+ database.exec(`
13331
+ CREATE TABLE IF NOT EXISTS session_inbox (
13332
+ sequence INTEGER PRIMARY KEY AUTOINCREMENT,
13333
+ id TEXT NOT NULL UNIQUE,
13334
+ user_id TEXT NOT NULL,
13335
+ topic_id TEXT NOT NULL,
13336
+ payload TEXT NOT NULL,
13337
+ status TEXT NOT NULL DEFAULT 'pending'
13338
+ CHECK (status IN ('pending', 'processing')),
13339
+ claimed_by TEXT,
13340
+ claimed_at INTEGER,
13341
+ created_at INTEGER NOT NULL
13342
+ );
13343
+ CREATE INDEX IF NOT EXISTS idx_session_inbox_ready
13344
+ ON session_inbox(status, user_id, topic_id, sequence);
13345
+ CREATE INDEX IF NOT EXISTS idx_session_inbox_topic
13346
+ ON session_inbox(topic_id);
13347
+ `);
13348
+ }, 35);
13349
+ });
13350
+
13307
13351
  // ../../packages/core/src/query/session-inbox-cleanup.ts
13308
13352
  import { unlinkSync as unlinkSync14 } from "fs";
13309
- import { basename as basename3, join as join23 } from "path";
13353
+ import { basename as basename3, join as join24 } from "path";
13310
13354
  function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
13311
13355
  const live = sessionInboxPath(userId, topicId);
13312
13356
  const scheduled = scheduledSessionInboxPath(userId, topicId);
13313
13357
  const candidates = new Set([live, `${live}.processing`, scheduled, `${scheduled}.processing`]);
13314
13358
  if (legacyTopicTitle && legacyTopicTitle !== "." && legacyTopicTitle !== ".." && basename3(legacyTopicTitle) === legacyTopicTitle) {
13315
- const legacyBase = join23(SESSION_INBOX_DIR, userId, legacyTopicTitle);
13359
+ const legacyBase = join24(SESSION_INBOX_DIR, userId, legacyTopicTitle);
13316
13360
  for (const suffix of [".jsonl", ".jsonl.processing", ".schedule", ".schedule.processing"]) {
13317
13361
  candidates.add(`${legacyBase}${suffix}`);
13318
13362
  }
13319
13363
  }
13320
- let deleted = 0;
13364
+ let deleted = deleteSessionInboxForTopic(topicId);
13321
13365
  for (const path of candidates) {
13322
13366
  try {
13323
13367
  unlinkSync14(path);
@@ -13330,24 +13374,25 @@ function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
13330
13374
  }
13331
13375
  return deleted;
13332
13376
  }
13333
- var init_session_inbox_cleanup = __esm(() => {
13377
+ var init_session_inbox_cleanup = __esm(async () => {
13334
13378
  init_config();
13335
13379
  init_logger();
13336
13380
  init_session_inbox_path();
13381
+ await init_session_inbox();
13337
13382
  });
13338
13383
 
13339
13384
  // ../../packages/core/src/query/state.ts
13340
13385
  import { mkdirSync as mkdirSync14, renameSync as renameSync7, unlinkSync as unlinkSync15, writeFileSync as writeFileSync12 } from "fs";
13341
- import { basename as basename4, join as join24 } from "path";
13386
+ import { basename as basename4, join as join25 } from "path";
13342
13387
  function createQueryStateStore(options) {
13343
13388
  const sanitize = options.sanitizeTopicId ?? sanitizeId;
13344
- const queryStateDirPath = (userId) => join24(options.usersLogDir, String(userId), "active-queries");
13345
- const queryStateFile = (userId, topicId) => join24(queryStateDirPath(userId), `${sanitize(topicId)}.json`);
13389
+ const queryStateDirPath = (userId) => join25(options.usersLogDir, String(userId), "active-queries");
13390
+ const queryStateFile = (userId, topicId) => join25(queryStateDirPath(userId), `${sanitize(topicId)}.json`);
13346
13391
  const legacyQueryStateFile = (userId, topicName) => {
13347
13392
  if (!topicName || topicName === "." || topicName === ".." || basename4(topicName) !== topicName) {
13348
13393
  return null;
13349
13394
  }
13350
- return join24(queryStateDirPath(userId), `${topicName}.json`);
13395
+ return join25(queryStateDirPath(userId), `${topicName}.json`);
13351
13396
  };
13352
13397
  return {
13353
13398
  write(userId, topicId, topicName, task) {
@@ -13508,29 +13553,29 @@ import {
13508
13553
  unlinkSync as unlinkSync16,
13509
13554
  writeFileSync as writeFileSync13
13510
13555
  } from "fs";
13511
- import { dirname as dirname14, join as join25 } from "path";
13556
+ import { dirname as dirname14, join as join26 } from "path";
13512
13557
  function pendingAskDir(userId) {
13513
13558
  const rawUserId = String(userId);
13514
13559
  const safeUserId = /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash6("sha256").update(rawUserId).digest("hex")}`;
13515
- return join25(resolveStorageSessionAsksDir(), safeUserId);
13560
+ return join26(resolveStorageSessionAsksDir(), safeUserId);
13516
13561
  }
13517
13562
  function encodeAskKey(key) {
13518
13563
  return JSON.stringify([key.from, key.to]);
13519
13564
  }
13520
13565
  function pendingAskPath(key) {
13521
13566
  const digest = createHash6("sha256").update(encodeAskKey(key)).digest("hex");
13522
- return join25(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
13567
+ return join26(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
13523
13568
  }
13524
13569
  function v2PendingAskPath(key) {
13525
13570
  const encoded = Buffer.from(encodeAskKey(key), "utf8").toString("base64url");
13526
- return join25(pendingAskDir(key.userId), `${V2_ASK_FILENAME_PREFIX}${encoded}.pending`);
13571
+ return join26(pendingAskDir(key.userId), `${V2_ASK_FILENAME_PREFIX}${encoded}.pending`);
13527
13572
  }
13528
13573
  function legacyPendingAskPath(key) {
13529
13574
  if (key.from.includes("/") || key.from.includes("\\") || key.to.includes("/") || key.to.includes("\\") || key.from.includes("\x00") || key.to.includes("\x00")) {
13530
13575
  return null;
13531
13576
  }
13532
13577
  const dir = pendingAskDir(key.userId);
13533
- const candidate = join25(dir, `${key.from}___${key.to}.pending`);
13578
+ const candidate = join26(dir, `${key.from}___${key.to}.pending`);
13534
13579
  return dirname14(candidate) === dir ? candidate : null;
13535
13580
  }
13536
13581
  function parsePendingAskFilename(fileName) {
@@ -13771,7 +13816,7 @@ function listPendingAsksForCaller(args) {
13771
13816
  const parsed = isV3 ? { from: args.from, to: "" } : parsePendingAskFilename(fileName);
13772
13817
  if (!parsed)
13773
13818
  continue;
13774
- const path = join25(dir, fileName);
13819
+ const path = join26(dir, fileName);
13775
13820
  const record = readPendingAskFile(path, {
13776
13821
  userId: args.userId,
13777
13822
  from: parsed.from,
@@ -13813,7 +13858,7 @@ function deletePendingAsksForTopic(args) {
13813
13858
  }
13814
13859
  let deleted = 0;
13815
13860
  for (const fileName of files) {
13816
- const path = join25(dir, fileName);
13861
+ const path = join26(dir, fileName);
13817
13862
  const parsed = parsePendingAskFilename(fileName);
13818
13863
  const record = readPendingAskFile(path, {
13819
13864
  userId: args.userId,
@@ -14213,7 +14258,7 @@ body{font-family:system-ui,-apple-system,"Segoe UI",sans-serif;background:var(--
14213
14258
  // ../../packages/core/src/storage/token-stats.ts
14214
14259
  import { createHash as createHash7 } from "crypto";
14215
14260
  import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "fs";
14216
- import { join as join26 } from "path";
14261
+ import { join as join27 } from "path";
14217
14262
  function tokenStatsFileId(userId) {
14218
14263
  const rawUserId = String(userId);
14219
14264
  return /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash7("sha256").update(rawUserId).digest("hex")}`;
@@ -14222,7 +14267,7 @@ function queriesPath(userId) {
14222
14267
  const fileId = tokenStatsFileId(userId);
14223
14268
  const logDir = resolveStorageLogDir();
14224
14269
  mkdirSync16(logDir, { recursive: true });
14225
- return join26(logDir, `token-queries-${fileId}.jsonl`);
14270
+ return join27(logDir, `token-queries-${fileId}.jsonl`);
14226
14271
  }
14227
14272
  function estimateUsageCost(agent, model, usage) {
14228
14273
  const prices = TOKEN_PRICES[`${agent}:${model}`];
@@ -14513,7 +14558,7 @@ var init_lifecycle = __esm(async () => {
14513
14558
  init_logger();
14514
14559
  await init_manager2();
14515
14560
  await init_active_rooms();
14516
- init_session_inbox_cleanup();
14561
+ await init_session_inbox_cleanup();
14517
14562
  init_state();
14518
14563
  await init_ask_callbacks();
14519
14564
  init_file_hooks();
@@ -14566,7 +14611,7 @@ var init_lifecycle = __esm(async () => {
14566
14611
  // ../../packages/core/src/runtime/attachments.ts
14567
14612
  import { randomUUID as randomUUID14 } from "crypto";
14568
14613
  import { copyFileSync as copyFileSync2, mkdirSync as mkdirSync17, writeFileSync as writeFileSync15 } from "fs";
14569
- import { basename as basename5, join as join27 } from "path";
14614
+ import { basename as basename5, join as join28 } from "path";
14570
14615
  function workspaceCwdFor(topicId) {
14571
14616
  return resolveTopicWorkspaceDir(topicId);
14572
14617
  }
@@ -14579,7 +14624,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
14579
14624
  if (!attachmentIds?.length)
14580
14625
  return [];
14581
14626
  const out = [];
14582
- const destDir = join27(workspaceCwdFor(topicId), "attachments", queryId);
14627
+ const destDir = join28(workspaceCwdFor(topicId), "attachments", queryId);
14583
14628
  for (const rawId of attachmentIds) {
14584
14629
  if (typeof rawId !== "string")
14585
14630
  continue;
@@ -14596,7 +14641,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
14596
14641
  mkdirSync17(destDir, { recursive: true });
14597
14642
  const index = String(out.length + 1).padStart(2, "0");
14598
14643
  const safeName = safeAttachmentFilename(attachment.filename, fileId);
14599
- const destPath = join27(destDir, `${index}-${fileId.slice(0, 8)}-${safeName}`);
14644
+ const destPath = join28(destDir, `${index}-${fileId.slice(0, 8)}-${safeName}`);
14600
14645
  copyFileSync2(sourcePath, destPath);
14601
14646
  out.push({
14602
14647
  id: attachment.id,
@@ -14626,10 +14671,10 @@ function promptWithAttachments(prompt, attachments) {
14626
14671
  return composeAttachmentPrompt(prompt, attachments.map(({ filename, path }) => attachmentPromptLine(filename, path)));
14627
14672
  }
14628
14673
  function ingestAttachment(args) {
14629
- const destDir = join27(UPLOADS_DIR, args.topicId);
14674
+ const destDir = join28(UPLOADS_DIR, args.topicId);
14630
14675
  mkdirSync17(destDir, { recursive: true });
14631
14676
  const safeName = safeAttachmentFilename(args.filename, "upload");
14632
- const destPath = join27(destDir, `${Date.now()}-${randomUUID14().slice(0, 8)}-${safeName}`);
14677
+ const destPath = join28(destDir, `${Date.now()}-${randomUUID14().slice(0, 8)}-${safeName}`);
14633
14678
  if (args.sourcePath !== undefined) {
14634
14679
  copyFileSync2(args.sourcePath, destPath);
14635
14680
  } else if (args.bytes !== undefined) {
@@ -15924,9 +15969,9 @@ var init_turn_session = __esm(async () => {
15924
15969
 
15925
15970
  // ../../packages/core/src/storage/app-settings.ts
15926
15971
  import { existsSync as existsSync19, mkdirSync as mkdirSync18, readFileSync as readFileSync17, writeFileSync as writeFileSync16 } from "fs";
15927
- import { dirname as dirname15, join as join28 } from "path";
15972
+ import { dirname as dirname15, join as join29 } from "path";
15928
15973
  function settingsFile() {
15929
- return join28(resolveStorageDataDir(), "otium-settings.json");
15974
+ return join29(resolveStorageDataDir(), "otium-settings.json");
15930
15975
  }
15931
15976
  function getGlobalAiName() {
15932
15977
  const path = settingsFile();
@@ -16021,7 +16066,7 @@ __export(exports_turn_runner, {
16021
16066
  });
16022
16067
  import { randomUUID as randomUUID16 } from "crypto";
16023
16068
  import { existsSync as existsSync20, mkdirSync as mkdirSync19, readdirSync as readdirSync5, statSync as statSync10 } from "fs";
16024
- import { join as join29 } from "path";
16069
+ import { join as join30 } from "path";
16025
16070
  function withDefaultPlaywright(configuredMcp, isManager) {
16026
16071
  if (isManager)
16027
16072
  return configuredMcp;
@@ -16076,7 +16121,7 @@ function appendAskReplyMessage(topicId, text2, agentType) {
16076
16121
  return message;
16077
16122
  }
16078
16123
  function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, matchesTitle, preferExact = true) {
16079
- const preferred = join29(directory, preferredFilename);
16124
+ const preferred = join30(directory, preferredFilename);
16080
16125
  if (preferExact && existsSync20(preferred))
16081
16126
  return preferred;
16082
16127
  let newestLegacyId = null;
@@ -16087,7 +16132,7 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
16087
16132
  const legacyIdMatch = !titleMatch && matchesLegacyId(filename);
16088
16133
  if (!titleMatch && !legacyIdMatch)
16089
16134
  continue;
16090
- const path = join29(directory, filename);
16135
+ const path = join30(directory, filename);
16091
16136
  const mtimeMs = statSync10(path).mtimeMs;
16092
16137
  if (titleMatch) {
16093
16138
  if (!newestTitle || mtimeMs > newestTitle.mtimeMs) {
@@ -16101,9 +16146,9 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
16101
16146
  return newestTitle?.path ?? newestLegacyId?.path ?? preferred;
16102
16147
  }
16103
16148
  function resolveWikiMemoryMirror(wikiDir, topicId, topicTitle) {
16104
- const briefFile = resolveWikiMirrorPath(join29(wikiDir, "topic"), `${wikiBriefStorageKey(topicTitle, topicId)}.md`, (filename) => isTopicBriefFile(filename, topicId), (filename) => isTopicBriefFile(filename, topicId, topicTitle));
16149
+ const briefFile = resolveWikiMirrorPath(join30(wikiDir, "topic"), `${wikiBriefStorageKey(topicTitle, topicId)}.md`, (filename) => isTopicBriefFile(filename, topicId), (filename) => isTopicBriefFile(filename, topicId, topicTitle));
16105
16150
  const hasBriefFile = existsSync20(briefFile) && statSync10(briefFile).isFile();
16106
- const latestSummaryCandidate = resolveWikiMirrorPath(join29(wikiDir, "summaries"), `__missing__-${wikiSummaryFilename("0000-00-00", topicTitle, topicId)}`, (filename) => isTopicSummaryFile(filename, topicId), (filename) => isTopicSummaryFile(filename, topicId, topicTitle), false);
16151
+ const latestSummaryCandidate = resolveWikiMirrorPath(join30(wikiDir, "summaries"), `__missing__-${wikiSummaryFilename("0000-00-00", topicTitle, topicId)}`, (filename) => isTopicSummaryFile(filename, topicId), (filename) => isTopicSummaryFile(filename, topicId, topicTitle), false);
16107
16152
  const latestSummaryFile = existsSync20(latestSummaryCandidate) && statSync10(latestSummaryCandidate).isFile() ? latestSummaryCandidate : null;
16108
16153
  return { briefFile, hasBriefFile, latestSummaryFile };
16109
16154
  }
@@ -17194,7 +17239,7 @@ function triggerTopicAiTurn(topicId, userId, prompt, agentType, opts) {
17194
17239
  if (!opts?.silent && !opts?.hideInjectMessage) {
17195
17240
  const now = new Date().toISOString();
17196
17241
  const injectMsg = {
17197
- id: `tell-${randomUUID16()}`,
17242
+ id: opts?.requestId ? `tell-${opts.requestId}` : `tell-${randomUUID16()}`,
17198
17243
  topicId,
17199
17244
  authorId: opts?.injectAuthorId ?? userId,
17200
17245
  sourceAdapter: opts?.injectSourceAdapter,
@@ -17206,8 +17251,13 @@ function triggerTopicAiTurn(topicId, userId, prompt, agentType, opts) {
17206
17251
  model: execution.model,
17207
17252
  createdAt: now
17208
17253
  };
17209
- appendApiMessage(injectMsg);
17210
- WsHub.get().broadcastMessage(topicId, injectMsg);
17254
+ try {
17255
+ appendApiMessage(injectMsg);
17256
+ WsHub.get().broadcastMessage(topicId, injectMsg);
17257
+ } catch (error) {
17258
+ if (!opts?.requestId || !getApiMessage(topicId, injectMsg.id))
17259
+ throw error;
17260
+ }
17211
17261
  }
17212
17262
  return startAiTurn({
17213
17263
  topic: topicCfg,
@@ -19180,4 +19230,4 @@ export {
19180
19230
  DEFAULT_SELF_CONFIG_PRODUCT
19181
19231
  };
19182
19232
 
19183
- //# debugId=45ECD1D1620CDA8E64756E2164756E21
19233
+ //# debugId=A34C5AACD9F421F064756E2164756E21