negotium 0.2.2 → 0.2.3

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.
package/dist/main.js CHANGED
@@ -1005,8 +1005,7 @@ function renderUserPromptBatch(prompts) {
1005
1005
 
1006
1006
  // ../../packages/core/src/agents/rollout/shared.ts
1007
1007
  import { mkdirSync as mkdirSync3 } from "fs";
1008
- import { dirname as dirname2, join as join4, resolve as resolve2 } from "path";
1009
- import { fileURLToPath as fileURLToPath2 } from "url";
1008
+ import { resolve as resolve2 } from "path";
1010
1009
  function clone(obj) {
1011
1010
  return structuredClone(obj);
1012
1011
  }
@@ -1137,18 +1136,17 @@ ${toolBuffer.join(`
1137
1136
  flushAssistant();
1138
1137
  return pairs;
1139
1138
  }
1140
- var __dirname2, trustedWorkspaceRoots, FIXTURES_DIR, UUID_RE;
1139
+ var trustedWorkspaceRoots, FIXTURES_DIR, UUID_RE;
1141
1140
  var init_shared = __esm(() => {
1142
1141
  init_config();
1143
1142
  init_logger();
1144
- __dirname2 = dirname2(fileURLToPath2(import.meta.url));
1145
1143
  trustedWorkspaceRoots = [
1146
1144
  WORKSPACE_DIR,
1147
1145
  DM_WORKSPACE_DIR,
1148
1146
  SESSION_WORKSPACE_DIR,
1149
1147
  TOPIC_WORKSPACE_DIR
1150
1148
  ].map((root) => resolve2(root));
1151
- FIXTURES_DIR = join4(__dirname2, "..", "fixtures");
1149
+ FIXTURES_DIR = resolve2(PROJECT_ROOT, "src", "agents", "fixtures");
1152
1150
  UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1153
1151
  });
1154
1152
 
@@ -1191,7 +1189,7 @@ import {
1191
1189
  unlinkSync as unlinkSync2,
1192
1190
  writeFileSync as writeFileSync2
1193
1191
  } from "fs";
1194
- import { dirname as dirname3 } from "path";
1192
+ import { dirname as dirname2 } from "path";
1195
1193
  function readJsonlLines(filePath) {
1196
1194
  return readFileSync2(filePath, "utf-8").trim().split(`
1197
1195
  `).filter(Boolean);
@@ -1239,7 +1237,7 @@ function appendJsonlEntry(filePath, entry) {
1239
1237
  `);
1240
1238
  }
1241
1239
  function appendJsonlLine(filePath, line) {
1242
- mkdirSync4(dirname3(filePath), { recursive: true });
1240
+ mkdirSync4(dirname2(filePath), { recursive: true });
1243
1241
  const lockPath = `${filePath}${LOCK_SUFFIX}`;
1244
1242
  const payload = line.endsWith(`
1245
1243
  `) ? line : `${line}
@@ -1270,7 +1268,7 @@ function appendJsonlLine(filePath, line) {
1270
1268
  }
1271
1269
  }
1272
1270
  function writeJsonlFile(filePath, entries) {
1273
- const dir = dirname3(filePath);
1271
+ const dir = dirname2(filePath);
1274
1272
  mkdirSync4(dir, { recursive: true });
1275
1273
  const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
1276
1274
  const payload = `${entries.map((e) => JSON.stringify(e)).join(`
@@ -1330,11 +1328,11 @@ var init_jsonl = __esm(() => {
1330
1328
  import { randomUUID } from "crypto";
1331
1329
  import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
1332
1330
  import { homedir as homedir3 } from "os";
1333
- import { join as join5 } from "path";
1331
+ import { join as join4 } from "path";
1334
1332
  function loadClaudeAttachments() {
1335
1333
  if (_attachmentsCache)
1336
1334
  return _attachmentsCache;
1337
- const raw = readFileSync3(join5(FIXTURES_DIR, "claude-attachments.jsonl"), "utf8");
1335
+ const raw = readFileSync3(join4(FIXTURES_DIR, "claude-attachments.jsonl"), "utf8");
1338
1336
  const lines = parseJsonlText(raw);
1339
1337
  if (lines.length < 2) {
1340
1338
  throw new Error(`loadClaudeAttachments: expected >=2 entries in claude-attachments.jsonl, got ${lines.length}`);
@@ -1435,8 +1433,8 @@ function writeClaudeRollout(opts) {
1435
1433
  });
1436
1434
  lastUuid = assistantUuid;
1437
1435
  }
1438
- const projectsDir = join5(homedir3(), ".claude", "projects", encodeClaudeCwd(opts.cwd));
1439
- const path = join5(projectsDir, `${sessionId}.jsonl`);
1436
+ const projectsDir = join4(homedir3(), ".claude", "projects", encodeClaudeCwd(opts.cwd));
1437
+ const path = join4(projectsDir, `${sessionId}.jsonl`);
1440
1438
  writeJsonlFile(path, lines);
1441
1439
  logger.info({ sessionId, path, pairs: pairs.length }, "writeClaudeRollout: synthetic rollout placed");
1442
1440
  return { sessionId, rolloutPath: path };
@@ -1451,7 +1449,7 @@ var init_claude = __esm(() => {
1451
1449
  // ../../packages/core/src/agents/claude-registry.ts
1452
1450
  import { existsSync as existsSync4, mkdirSync as mkdirSync5, readdirSync, renameSync as renameSync2, unlinkSync as unlinkSync3 } from "fs";
1453
1451
  import { homedir as homedir4 } from "os";
1454
- import { join as join6 } from "path";
1452
+ import { join as join5 } from "path";
1455
1453
  var ALIAS_MAP, VALID_ALIASES, VALID_EFFORTS, claudeRegistry, claudeRegistryOperations;
1456
1454
  var init_claude_registry = __esm(() => {
1457
1455
  init_claude();
@@ -1498,11 +1496,11 @@ var init_claude_registry = __esm(() => {
1498
1496
  const result = await forkSession(parentSessionId, {
1499
1497
  ...title ? { title } : {}
1500
1498
  });
1501
- const projectsRoot = join6(homedir4(), ".claude", "projects");
1502
- const destDir = join6(projectsRoot, encodeClaudeCwd(cwd));
1503
- const destPath = join6(destDir, `${result.sessionId}.jsonl`);
1499
+ const projectsRoot = join5(homedir4(), ".claude", "projects");
1500
+ const destDir = join5(projectsRoot, encodeClaudeCwd(cwd));
1501
+ const destPath = join5(destDir, `${result.sessionId}.jsonl`);
1504
1502
  if (!existsSync4(destPath)) {
1505
- const sourcePath = readdirSync(projectsRoot).map((d) => join6(projectsRoot, d, `${result.sessionId}.jsonl`)).find((p) => existsSync4(p));
1503
+ const sourcePath = readdirSync(projectsRoot).map((d) => join5(projectsRoot, d, `${result.sessionId}.jsonl`)).find((p) => existsSync4(p));
1506
1504
  if (!sourcePath) {
1507
1505
  throw new Error(`claude forkSession: fork rollout ${result.sessionId}.jsonl not found under ${projectsRoot}`);
1508
1506
  }
@@ -1515,10 +1513,10 @@ var init_claude_registry = __esm(() => {
1515
1513
  };
1516
1514
  },
1517
1515
  async cleanupRollouts({ cwd, sessionIds }) {
1518
- const projectsDir = join6(homedir4(), ".claude", "projects", encodeClaudeCwd(cwd));
1516
+ const projectsDir = join5(homedir4(), ".claude", "projects", encodeClaudeCwd(cwd));
1519
1517
  const failures = [];
1520
1518
  for (const sid of sessionIds) {
1521
- const path = join6(projectsDir, `${sid}.jsonl`);
1519
+ const path = join5(projectsDir, `${sid}.jsonl`);
1522
1520
  try {
1523
1521
  unlinkSync3(path);
1524
1522
  } catch (e) {
@@ -1539,14 +1537,14 @@ var init_claude_registry = __esm(() => {
1539
1537
  import { randomBytes as randomBytes3 } from "crypto";
1540
1538
  import { existsSync as existsSync5, readFileSync as readFileSync4, realpathSync, statSync as statSync2, unlinkSync as unlinkSync4 } from "fs";
1541
1539
  import { homedir as homedir5 } from "os";
1542
- import { basename, dirname as dirname4, join as join7, resolve as resolve3 } from "path";
1540
+ import { basename, dirname as dirname3, join as join6, resolve as resolve3 } from "path";
1543
1541
  function codexSessionsDir() {
1544
- return join7(process.env.CODEX_HOME || join7(homedir5(), ".codex"), "sessions");
1542
+ return join6(process.env.CODEX_HOME || join6(homedir5(), ".codex"), "sessions");
1545
1543
  }
1546
1544
  function loadCodexShell() {
1547
1545
  if (_shellCache)
1548
1546
  return _shellCache;
1549
- const raw = readFileSync4(join7(FIXTURES_DIR, "codex-shell.jsonl"), "utf8");
1547
+ const raw = readFileSync4(join6(FIXTURES_DIR, "codex-shell.jsonl"), "utf8");
1550
1548
  const lines = parseJsonlText(raw);
1551
1549
  if (lines.length < 5) {
1552
1550
  throw new Error(`loadCodexShell: expected >=5 entries in codex-shell.jsonl, got ${lines.length}`);
@@ -1610,7 +1608,7 @@ function canonicalFilePath(path) {
1610
1608
  return realpathSync(absolute);
1611
1609
  } catch {
1612
1610
  try {
1613
- return join7(realpathSync(dirname4(absolute)), basename(absolute));
1611
+ return join6(realpathSync(dirname3(absolute)), basename(absolute));
1614
1612
  } catch {
1615
1613
  return absolute;
1616
1614
  }
@@ -1799,19 +1797,19 @@ function latestCodexRolloutPath(threadId) {
1799
1797
  try {
1800
1798
  if (buckets) {
1801
1799
  for (const bucket of buckets) {
1802
- const dir = join7(sessionsDir, bucket);
1800
+ const dir = join6(sessionsDir, bucket);
1803
1801
  if (!existsSync5(dir))
1804
1802
  continue;
1805
1803
  const glob = new Bun.Glob(`rollout-*-${threadId}.jsonl`);
1806
1804
  for (const rel of glob.scanSync({ cwd: dir, onlyFiles: true })) {
1807
- candidates.push(join7(dir, rel));
1805
+ candidates.push(join6(dir, rel));
1808
1806
  }
1809
1807
  }
1810
1808
  }
1811
1809
  if (candidates.length === 0) {
1812
1810
  const glob = new Bun.Glob(`**/rollout-*-${threadId}.jsonl`);
1813
1811
  for (const rel of glob.scanSync({ cwd: sessionsDir, onlyFiles: true })) {
1814
- candidates.push(join7(sessionsDir, rel));
1812
+ candidates.push(join6(sessionsDir, rel));
1815
1813
  }
1816
1814
  }
1817
1815
  return candidates.sort((a, b) => statSync2(b).mtimeMs - statSync2(a).mtimeMs)[0];
@@ -1920,8 +1918,8 @@ function writeCodexRollout(opts) {
1920
1918
  const mm = String(now.getUTCMonth() + 1).padStart(2, "0");
1921
1919
  const dd = String(now.getUTCDate()).padStart(2, "0");
1922
1920
  const tsStr = tsIso.replace(/[:.]/g, "-").slice(0, 19);
1923
- const dir = join7(codexSessionsDir(), String(yyyy), mm, dd);
1924
- const path = join7(dir, `rollout-${tsStr}-${threadId}.jsonl`);
1921
+ const dir = join6(codexSessionsDir(), String(yyyy), mm, dd);
1922
+ const path = join6(dir, `rollout-${tsStr}-${threadId}.jsonl`);
1925
1923
  if (opts.threadId) {
1926
1924
  sweepPriorRolloutsForThread(opts.threadId);
1927
1925
  }
@@ -1937,13 +1935,13 @@ function sweepPriorRolloutsForThread(threadId) {
1937
1935
  return;
1938
1936
  }
1939
1937
  for (const bucket of buckets) {
1940
- const dir = join7(sessionsDir, bucket);
1938
+ const dir = join6(sessionsDir, bucket);
1941
1939
  if (!existsSync5(dir))
1942
1940
  continue;
1943
1941
  try {
1944
1942
  const glob = new Bun.Glob(`rollout-*-${threadId}.jsonl`);
1945
1943
  for (const rel of glob.scanSync({ cwd: dir, onlyFiles: true })) {
1946
- const fullPath = join7(dir, rel);
1944
+ const fullPath = join6(dir, rel);
1947
1945
  try {
1948
1946
  unlinkSync4(fullPath);
1949
1947
  } catch (e) {
@@ -1961,7 +1959,7 @@ function sweepPriorRolloutsFullTree(threadId, sessionsDir) {
1961
1959
  try {
1962
1960
  const glob = new Bun.Glob(`**/rollout-*-${threadId}.jsonl`);
1963
1961
  for (const rel of glob.scanSync({ cwd: sessionsDir, onlyFiles: true })) {
1964
- const fullPath = join7(sessionsDir, rel);
1962
+ const fullPath = join6(sessionsDir, rel);
1965
1963
  try {
1966
1964
  unlinkSync4(fullPath);
1967
1965
  } catch (e) {
@@ -2039,29 +2037,29 @@ function sanitizeId(id) {
2039
2037
  // ../../packages/core/src/storage/storage-host.ts
2040
2038
  import { mkdirSync as mkdirSync6 } from "fs";
2041
2039
  import { homedir as homedir6 } from "os";
2042
- import { dirname as dirname5, join as join8, resolve as resolve4 } from "path";
2040
+ import { dirname as dirname4, join as join7, resolve as resolve4 } from "path";
2043
2041
  function envPath(name, fallback) {
2044
2042
  const value = process.env[name]?.trim();
2045
2043
  return resolve4(value || fallback);
2046
2044
  }
2047
2045
  function defaultStateDir() {
2048
- return envPath("NEGOTIUM_STATE_DIR", join8(homedir6(), ".negotium"));
2046
+ return envPath("NEGOTIUM_STATE_DIR", join7(homedir6(), ".negotium"));
2049
2047
  }
2050
2048
  function defaultDataDir() {
2051
- return envPath("NEGOTIUM_DATA_DIR", join8(defaultStateDir(), "data"));
2049
+ return envPath("NEGOTIUM_DATA_DIR", join7(defaultStateDir(), "data"));
2052
2050
  }
2053
2051
  function defaultLogDir() {
2054
- return envPath("NEGOTIUM_LOG_DIR", join8(defaultStateDir(), "logs"));
2052
+ return envPath("NEGOTIUM_LOG_DIR", join7(defaultStateDir(), "logs"));
2055
2053
  }
2056
2054
  function defaultWorkspaceDir() {
2057
- return envPath("NEGOTIUM_WORKSPACE_DIR", join8(defaultStateDir(), "workspace"));
2055
+ return envPath("NEGOTIUM_WORKSPACE_DIR", join7(defaultStateDir(), "workspace"));
2058
2056
  }
2059
2057
  function defaultSessionAsksDir() {
2060
- const runDir = envPath("NEGOTIUM_RUN_DIR", join8(defaultStateDir(), "runtime"));
2061
- return join8(runDir, "session-asks");
2058
+ const runDir = envPath("NEGOTIUM_RUN_DIR", join7(defaultStateDir(), "runtime"));
2059
+ return join7(runDir, "session-asks");
2062
2060
  }
2063
2061
  function defaultSessionsDatabasePath() {
2064
- return envPath("SESSIONS_DB_PATH", join8(resolveStorageDataDir(), "sessions.db"));
2062
+ return envPath("SESSIONS_DB_PATH", join7(resolveStorageDataDir(), "sessions.db"));
2065
2063
  }
2066
2064
  function initializeDatabase(database) {
2067
2065
  database.exec("PRAGMA busy_timeout = 5000");
@@ -2078,7 +2076,7 @@ function defaultDatabase() {
2078
2076
  return fallbackDatabase;
2079
2077
  if (fallbackDatabase)
2080
2078
  fallbackDatabase.close();
2081
- mkdirSync6(dirname5(path), { recursive: true });
2079
+ mkdirSync6(dirname4(path), { recursive: true });
2082
2080
  fallbackDatabase = new Database(path, { create: true });
2083
2081
  fallbackDatabasePath = path;
2084
2082
  initializeDatabase(fallbackDatabase);
@@ -2100,10 +2098,10 @@ function resolveStorageWorkspaceDir() {
2100
2098
  return configuredHost.workspaceDir ?? defaultWorkspaceDir();
2101
2099
  }
2102
2100
  function resolveStorageSharedWikiDir() {
2103
- return configuredHost.sharedWikiDir ?? join8(resolveStorageWorkspaceDir(), "wiki");
2101
+ return configuredHost.sharedWikiDir ?? join7(resolveStorageWorkspaceDir(), "wiki");
2104
2102
  }
2105
2103
  function resolveStorageUsersLogDir() {
2106
- return configuredHost.usersLogDir ?? join8(resolveStorageDataDir(), "users");
2104
+ return configuredHost.usersLogDir ?? join7(resolveStorageDataDir(), "users");
2107
2105
  }
2108
2106
  function normalizeStorageHostPatch(options) {
2109
2107
  const patch = {};
@@ -2237,16 +2235,16 @@ import {
2237
2235
  unlinkSync as unlinkSync5,
2238
2236
  writeFileSync as writeFileSync4
2239
2237
  } from "fs";
2240
- import { dirname as dirname6, join as join9 } from "path";
2238
+ import { dirname as dirname5, join as join8 } from "path";
2241
2239
  function conversationDir(_userId) {
2242
- return join9(resolveStorageDataDir(), "conversations");
2240
+ return join8(resolveStorageDataDir(), "conversations");
2243
2241
  }
2244
2242
  function topicFilename(topicName) {
2245
2243
  const t = sanitizeTopicName(topicName, true);
2246
2244
  return `${t}.jsonl`;
2247
2245
  }
2248
2246
  function getConversationPath(userId, topicName) {
2249
- return join9(conversationDir(userId), topicFilename(topicName));
2247
+ return join8(conversationDir(userId), topicFilename(topicName));
2250
2248
  }
2251
2249
  function getActiveConversationPath(userId, topicName) {
2252
2250
  const rawPath = getConversationPath(userId, topicName);
@@ -2272,7 +2270,7 @@ function appendConversationEventStrict(userId, topicName, agent, event) {
2272
2270
  event
2273
2271
  };
2274
2272
  const line = JSON.stringify(entry);
2275
- mkdirSync7(dirname6(path), { recursive: true });
2273
+ mkdirSync7(dirname5(path), { recursive: true });
2276
2274
  appendJsonlLine(path, line);
2277
2275
  const activePath = getActiveConversationPath(userId, topicName);
2278
2276
  if (existsSync6(activePath)) {
@@ -2290,7 +2288,7 @@ function appendRawConversationEventStrict(userId, topicName, agent, event) {
2290
2288
  agent,
2291
2289
  event
2292
2290
  };
2293
- mkdirSync7(dirname6(path), { recursive: true });
2291
+ mkdirSync7(dirname5(path), { recursive: true });
2294
2292
  appendJsonlLine(path, JSON.stringify(entry));
2295
2293
  }
2296
2294
  function readConversationPath(path) {
@@ -2331,7 +2329,7 @@ function replaceRawConversationStrict(userId, topicName, entries) {
2331
2329
  }
2332
2330
  function replaceConversationPathStrict(path, entries) {
2333
2331
  const tempPath = `${path}.${process.pid}.${Date.now()}.tmp`;
2334
- mkdirSync7(dirname6(path), { recursive: true });
2332
+ mkdirSync7(dirname5(path), { recursive: true });
2335
2333
  try {
2336
2334
  writeFileSync4(tempPath, entries.length > 0 ? `${entries.map((entry) => JSON.stringify(entry)).join(`
2337
2335
  `)}
@@ -2358,7 +2356,7 @@ function cloneConversationLog(opts) {
2358
2356
  const body = `${entries.map((e) => JSON.stringify(e)).join(`
2359
2357
  `)}
2360
2358
  `;
2361
- mkdirSync7(dirname6(dstPath), { recursive: true });
2359
+ mkdirSync7(dirname5(dstPath), { recursive: true });
2362
2360
  writeFileSync4(dstPath, body);
2363
2361
  const srcActivePath = getActiveConversationPath(userId, srcTopic);
2364
2362
  if (existsSync6(srcActivePath)) {
@@ -2400,7 +2398,7 @@ var init_conversations = __esm(async () => {
2400
2398
  // ../../packages/core/src/agents/codex-registry.ts
2401
2399
  import { existsSync as existsSync7, unlinkSync as unlinkSync6 } from "fs";
2402
2400
  import { homedir as homedir7 } from "os";
2403
- import { join as join10 } from "path";
2401
+ import { join as join9 } from "path";
2404
2402
  var VALID_EFFORTS2, codexRegistry, codexRegistryOperations;
2405
2403
  var init_codex_registry = __esm(async () => {
2406
2404
  init_codex();
@@ -2449,7 +2447,7 @@ var init_codex_registry = __esm(async () => {
2449
2447
  async cleanupRollouts({ sessionIds }) {
2450
2448
  if (sessionIds.length === 0)
2451
2449
  return;
2452
- const sessionsDir = join10(process.env.CODEX_HOME || join10(homedir7(), ".codex"), "sessions");
2450
+ const sessionsDir = join9(process.env.CODEX_HOME || join9(homedir7(), ".codex"), "sessions");
2453
2451
  if (!existsSync7(sessionsDir))
2454
2452
  return;
2455
2453
  const failures = [];
@@ -2457,7 +2455,7 @@ var init_codex_registry = __esm(async () => {
2457
2455
  try {
2458
2456
  const glob = new Bun.Glob(`**/rollout-*-${tid}.jsonl`);
2459
2457
  for await (const rel of glob.scan({ cwd: sessionsDir, onlyFiles: true })) {
2460
- const path = join10(sessionsDir, rel);
2458
+ const path = join9(sessionsDir, rel);
2461
2459
  try {
2462
2460
  unlinkSync6(path);
2463
2461
  } catch (e) {
@@ -2483,15 +2481,15 @@ var init_codex_registry = __esm(async () => {
2483
2481
  import { randomUUID as randomUUID2 } from "crypto";
2484
2482
  import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
2485
2483
  import { homedir as homedir8 } from "os";
2486
- import { join as join11, resolve as resolve5 } from "path";
2484
+ import { join as join10, resolve as resolve5 } from "path";
2487
2485
  function maestroSessionsDir() {
2488
- return join11(process.env.MAESTRO_DATA_DIR ? resolve5(process.env.MAESTRO_DATA_DIR) : join11(homedir8(), ".maestro"), "sessions");
2486
+ return join10(process.env.MAESTRO_DATA_DIR ? resolve5(process.env.MAESTRO_DATA_DIR) : join10(homedir8(), ".maestro"), "sessions");
2489
2487
  }
2490
2488
  function maestroSessionPath(sessionId) {
2491
- return join11(maestroSessionsDir(), `${sessionId}.jsonl`);
2489
+ return join10(maestroSessionsDir(), `${sessionId}.jsonl`);
2492
2490
  }
2493
2491
  function maestroActiveSessionPath(sessionId) {
2494
- return join11(maestroSessionsDir(), `${sessionId}.active.jsonl`);
2492
+ return join10(maestroSessionsDir(), `${sessionId}.active.jsonl`);
2495
2493
  }
2496
2494
  function existingCreatedAt(path) {
2497
2495
  if (!existsSync8(path))
@@ -2697,7 +2695,7 @@ __export(exports_tasks, {
2697
2695
  TASK_STATUS_VALUES: () => TASK_STATUS_VALUES
2698
2696
  });
2699
2697
  import { existsSync as existsSync10, mkdirSync as mkdirSync9, readFileSync as readFileSync7, renameSync as renameSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
2700
- import { dirname as dirname7, join as join12 } from "path";
2698
+ import { dirname as dirname6, join as join11 } from "path";
2701
2699
  function safeTaskScopeKey(scopeKey) {
2702
2700
  const safe = sanitizeFileName(scopeKey);
2703
2701
  if (!safe || safe === "." || safe === "..") {
@@ -2709,7 +2707,7 @@ function taskScopeKey(opts) {
2709
2707
  return opts.topicId?.trim() || opts.session || "default";
2710
2708
  }
2711
2709
  function getTaskFilePath(userId, scopeKey) {
2712
- return join12(resolveStorageDataDir(), "tasks", `${safeTaskScopeKey(scopeKey)}.json`);
2710
+ return join11(resolveStorageDataDir(), "tasks", `${safeTaskScopeKey(scopeKey)}.json`);
2713
2711
  }
2714
2712
  function readTasks(userId, scopeKey) {
2715
2713
  const path = getTaskFilePath(userId, scopeKey);
@@ -2725,7 +2723,7 @@ function readTasks(userId, scopeKey) {
2725
2723
  }
2726
2724
  function writeTasks(userId, scopeKey, tasks) {
2727
2725
  const path = getTaskFilePath(userId, scopeKey);
2728
- mkdirSync9(dirname7(path), { recursive: true });
2726
+ mkdirSync9(dirname6(path), { recursive: true });
2729
2727
  const payload = { version: 1, tasks };
2730
2728
  const tmp = `${path}.${process.pid}.tmp`;
2731
2729
  writeFileSync6(tmp, JSON.stringify(payload, null, 2), "utf-8");
@@ -4594,7 +4592,7 @@ var exports_version = {};
4594
4592
  __export(exports_version, {
4595
4593
  NEGOTIUM_VERSION: () => NEGOTIUM_VERSION
4596
4594
  });
4597
- var NEGOTIUM_VERSION = "0.2.2";
4595
+ var NEGOTIUM_VERSION = "0.2.3";
4598
4596
 
4599
4597
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
4600
4598
  import { spawn as spawn3 } from "child_process";
@@ -4612,7 +4610,7 @@ import {
4612
4610
  } from "fs";
4613
4611
  import { createRequire as createRequire2 } from "module";
4614
4612
  import { tmpdir } from "os";
4615
- import { dirname as dirname8, join as join13 } from "path";
4613
+ import { dirname as dirname7, join as join12 } from "path";
4616
4614
  function readPackageVersion(packageJsonPath) {
4617
4615
  const parsed = JSON.parse(readFileSync9(packageJsonPath, "utf8"));
4618
4616
  if (typeof parsed.version !== "string" || !parsed.version.trim()) {
@@ -4621,7 +4619,7 @@ function readPackageVersion(packageJsonPath) {
4621
4619
  return parsed.version;
4622
4620
  }
4623
4621
  function codexCliScriptPath() {
4624
- return join13(dirname8(bundledCodexPackagePath), "bin", "codex.js");
4622
+ return join12(dirname7(bundledCodexPackagePath), "bin", "codex.js");
4625
4623
  }
4626
4624
  function parseCodexModelCache(contents, sourcePath) {
4627
4625
  let parsed;
@@ -4662,7 +4660,7 @@ function writePrivateFileAtomic(path, contents) {
4662
4660
  }
4663
4661
  }
4664
4662
  function bundledCodexModelCachePath(authFilePath) {
4665
- return join13(dirname8(authFilePath), NEGOTIUM_MODEL_CACHE);
4663
+ return join12(dirname7(authFilePath), NEGOTIUM_MODEL_CACHE);
4666
4664
  }
4667
4665
  async function bootstrapCodexModelCache(codexHome, cachePath) {
4668
4666
  const child = spawn3(process.execPath, [codexCliScriptPath(), "app-server", "--stdio"], {
@@ -4747,16 +4745,16 @@ async function bootstrapCodexModelCache(codexHome, cachePath) {
4747
4745
  });
4748
4746
  }
4749
4747
  async function bootstrapIsolatedCodexModelCache(authFilePath, bootstrap) {
4750
- const sourceHome = dirname8(authFilePath);
4751
- const isolatedHome = mkdtempSync(join13(tmpdir(), "negotium-codex-models-"));
4752
- const isolatedCachePath = join13(isolatedHome, "models_cache.json");
4748
+ const sourceHome = dirname7(authFilePath);
4749
+ const isolatedHome = mkdtempSync(join12(tmpdir(), "negotium-codex-models-"));
4750
+ const isolatedCachePath = join12(isolatedHome, "models_cache.json");
4753
4751
  try {
4754
- const isolatedAuthPath = join13(isolatedHome, "auth.json");
4752
+ const isolatedAuthPath = join12(isolatedHome, "auth.json");
4755
4753
  copyFileSync(authFilePath, isolatedAuthPath);
4756
4754
  chmodSync3(isolatedAuthPath, 384);
4757
- const sourceConfigPath = join13(sourceHome, "config.toml");
4755
+ const sourceConfigPath = join12(sourceHome, "config.toml");
4758
4756
  if (existsSync12(sourceConfigPath)) {
4759
- const isolatedConfigPath = join13(isolatedHome, "config.toml");
4757
+ const isolatedConfigPath = join12(isolatedHome, "config.toml");
4760
4758
  copyFileSync(sourceConfigPath, isolatedConfigPath);
4761
4759
  chmodSync3(isolatedConfigPath, 384);
4762
4760
  }
@@ -4767,7 +4765,7 @@ async function bootstrapIsolatedCodexModelCache(authFilePath, bootstrap) {
4767
4765
  }
4768
4766
  }
4769
4767
  async function ensureCodexModelCache(authFilePath, bootstrap = bootstrapCodexModelCache) {
4770
- const codexHome = dirname8(authFilePath);
4768
+ const codexHome = dirname7(authFilePath);
4771
4769
  const configuredCachePath = process.env.NEGOTIUM_CODEX_MODELS_CACHE_FILE;
4772
4770
  if (configuredCachePath) {
4773
4771
  if (!existsSync12(configuredCachePath)) {
@@ -4777,7 +4775,7 @@ async function ensureCodexModelCache(authFilePath, bootstrap = bootstrapCodexMod
4777
4775
  return configuredCachePath;
4778
4776
  }
4779
4777
  const bundledCachePath = bundledCodexModelCachePath(authFilePath);
4780
- const sharedCachePath = join13(codexHome, "models_cache.json");
4778
+ const sharedCachePath = join12(codexHome, "models_cache.json");
4781
4779
  if (existsSync12(sharedCachePath)) {
4782
4780
  try {
4783
4781
  const shared = readCompatibleCodexModelCache(sharedCachePath);
@@ -4796,8 +4794,8 @@ async function ensureCodexModelCache(authFilePath, bootstrap = bootstrapCodexMod
4796
4794
  return bundledCachePath;
4797
4795
  }
4798
4796
  function writeCodexCatalogWithNativeMultiAgentDisabled(authFilePath, sourcePath) {
4799
- const codexHome = dirname8(authFilePath);
4800
- const outputPath = join13(codexHome, NEGOTIUM_MODEL_CATALOG);
4797
+ const codexHome = dirname7(authFilePath);
4798
+ const outputPath = join12(codexHome, NEGOTIUM_MODEL_CATALOG);
4801
4799
  const parsed = readCodexModelCache(sourcePath).parsed;
4802
4800
  const models = parsed.models.map((model, index) => {
4803
4801
  if (!model || typeof model !== "object" || Array.isArray(model)) {
@@ -5346,7 +5344,7 @@ __export(exports_codex_provider, {
5346
5344
  });
5347
5345
  import { execFileSync as execFileSync5 } from "child_process";
5348
5346
  import { existsSync as existsSync13, readFileSync as readFileSync11, realpathSync as realpathSync3, statSync as statSync5 } from "fs";
5349
- import { dirname as dirname9, isAbsolute as isAbsolute2, join as join14, relative, resolve as resolve8 } from "path";
5347
+ import { dirname as dirname8, isAbsolute as isAbsolute2, join as join13, relative, resolve as resolve8 } from "path";
5350
5348
  import { Codex } from "@openai/codex-sdk";
5351
5349
  function mapEffort(effort) {
5352
5350
  if (!effort)
@@ -5360,7 +5358,7 @@ function codexMcpServerName(name) {
5360
5358
  return CODEX_MCP_SERVER_NAME_OVERRIDES[name] ?? name;
5361
5359
  }
5362
5360
  function globalCodexMcpServerNames(authFilePath) {
5363
- const configPath = join14(dirname9(authFilePath), "config.toml");
5361
+ const configPath = join13(dirname8(authFilePath), "config.toml");
5364
5362
  if (!existsSync13(configPath))
5365
5363
  return [];
5366
5364
  try {
@@ -6151,7 +6149,7 @@ var init_maestro_provider = __esm(async () => {
6151
6149
  // ../../packages/core/src/agents/index.ts
6152
6150
  import { existsSync as existsSync14 } from "fs";
6153
6151
  import { homedir as homedir9 } from "os";
6154
- import { join as join15 } from "path";
6152
+ import { join as join14 } from "path";
6155
6153
  async function* dispatchAgent(opts) {
6156
6154
  switch (opts.agent) {
6157
6155
  case "claude": {
@@ -6185,11 +6183,11 @@ async function resolveSessionFileMissing(agent, sessionId, cwd) {
6185
6183
  switch (agent) {
6186
6184
  case "claude": {
6187
6185
  const encodedCwd = encodeClaudeCwd(cwd);
6188
- const path = join15(homedir9(), ".claude", "projects", encodedCwd, `${sessionId}.jsonl`);
6186
+ const path = join14(homedir9(), ".claude", "projects", encodedCwd, `${sessionId}.jsonl`);
6189
6187
  return !existsSync14(path);
6190
6188
  }
6191
6189
  case "codex": {
6192
- const sessionsDir = join15(process.env.CODEX_HOME || join15(homedir9(), ".codex"), "sessions");
6190
+ const sessionsDir = join14(process.env.CODEX_HOME || join14(homedir9(), ".codex"), "sessions");
6193
6191
  const glob = new Bun.Glob(`**/rollout-*-${sessionId}.jsonl`);
6194
6192
  for await (const _rel of glob.scan({ cwd: sessionsDir, onlyFiles: true })) {
6195
6193
  return false;
@@ -9497,7 +9495,7 @@ import { randomBytes as randomBytes5, timingSafeEqual as timingSafeEqual2 } from
9497
9495
  import { chmodSync as chmodSync4 } from "fs";
9498
9496
  import { createServer as createServer2 } from "net";
9499
9497
  import { tmpdir as tmpdir2 } from "os";
9500
- import { join as join16 } from "path";
9498
+ import { join as join15 } from "path";
9501
9499
  function deepMapStrings2(value, transform) {
9502
9500
  if (typeof value === "string")
9503
9501
  return transform(value);
@@ -9584,7 +9582,7 @@ function authorized(actual, expected) {
9584
9582
  }
9585
9583
  async function createBrowserVaultBroker(userId) {
9586
9584
  const token = randomBytes5(32).toString("hex");
9587
- const socketPath = join16(process.platform === "win32" ? tmpdir2() : "/tmp", `negotium-browser-vault-${process.pid}-${randomBytes5(8).toString("hex")}.sock`);
9585
+ const socketPath = join15(process.platform === "win32" ? tmpdir2() : "/tmp", `negotium-browser-vault-${process.pid}-${randomBytes5(8).toString("hex")}.sock`);
9588
9586
  const retainedForms = new Map;
9589
9587
  const leases = new Map;
9590
9588
  const sockets = new Set;
@@ -9815,7 +9813,7 @@ import {
9815
9813
  unlinkSync as unlinkSync11,
9816
9814
  writeFileSync as writeFileSync8
9817
9815
  } from "fs";
9818
- import { dirname as dirname10, join as join17, resolve as resolve12 } from "path";
9816
+ import { dirname as dirname9, join as join16, resolve as resolve12 } from "path";
9819
9817
  function makeInstanceKey(userId, topic) {
9820
9818
  return resolvePlaywrightTopicBinding(userId, topic).instanceKey;
9821
9819
  }
@@ -9895,14 +9893,14 @@ function portFileName(instanceKey) {
9895
9893
  function writePortFile(instanceKey, port) {
9896
9894
  try {
9897
9895
  mkdirSync10(managerHost.portsDir, { recursive: true });
9898
- writeFileSync8(join17(managerHost.portsDir, portFileName(instanceKey)), String(port));
9896
+ writeFileSync8(join16(managerHost.portsDir, portFileName(instanceKey)), String(port));
9899
9897
  } catch (e) {
9900
9898
  logger.warn({ err: e, instanceKey, port }, "Failed to save playwright port file");
9901
9899
  }
9902
9900
  }
9903
9901
  function deletePortFile(instanceKey) {
9904
9902
  try {
9905
- unlinkSync11(join17(managerHost.portsDir, portFileName(instanceKey)));
9903
+ unlinkSync11(join16(managerHost.portsDir, portFileName(instanceKey)));
9906
9904
  } catch (e) {
9907
9905
  logger.warn({ err: e, instanceKey }, "Failed to delete playwright port file");
9908
9906
  }
@@ -10392,7 +10390,7 @@ async function cloneProfileForChild(opts) {
10392
10390
  if (existsSync15(dstDir)) {
10393
10391
  rmSync2(dstDir, { recursive: true, force: true });
10394
10392
  }
10395
- mkdirSync10(dirname10(dstDir), { recursive: true });
10393
+ mkdirSync10(dirname9(dstDir), { recursive: true });
10396
10394
  if (process.platform === "darwin") {
10397
10395
  try {
10398
10396
  execFileSync7("cp", ["-cR", srcDir, dstDir], { stdio: "pipe" });
@@ -11483,32 +11481,32 @@ __export(exports_wiki, {
11483
11481
  getSharedWikiDir: () => getSharedWikiDir
11484
11482
  });
11485
11483
  import { existsSync as existsSync16, readdirSync as readdirSync3, statSync as statSync6 } from "fs";
11486
- import { basename as basename2, dirname as dirname11, join as join18 } from "path";
11484
+ import { basename as basename2, dirname as dirname10, join as join17 } from "path";
11487
11485
  function getWikiDir(_userId, workspaceDir = resolveStorageWorkspaceDir()) {
11488
- return join18(workspaceDir, "wiki");
11486
+ return join17(workspaceDir, "wiki");
11489
11487
  }
11490
11488
  function getSharedWikiDir(workspaceDir = resolveStorageWorkspaceDir()) {
11491
- return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() : join18(workspaceDir, "wiki");
11489
+ return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() : join17(workspaceDir, "wiki");
11492
11490
  }
11493
11491
  function findLatestSummaryFile(wikiDir, safeTopic) {
11494
- const summariesDir = join18(wikiDir, "summaries");
11492
+ const summariesDir = join17(wikiDir, "summaries");
11495
11493
  if (!existsSync16(summariesDir))
11496
11494
  return null;
11497
11495
  const files = readdirSync3(summariesDir).filter((f) => f.endsWith(".md") && f.match(new RegExp(`^\\d{4}-\\d{2}-\\d{2}-${safeTopic}(\\.md|~\\d+\\.md)$`)) && !f.endsWith("-sent-files.md")).sort((left, right) => {
11498
- const mtimeDelta = statSync6(join18(summariesDir, right)).mtimeMs - statSync6(join18(summariesDir, left)).mtimeMs;
11496
+ const mtimeDelta = statSync6(join17(summariesDir, right)).mtimeMs - statSync6(join17(summariesDir, left)).mtimeMs;
11499
11497
  return mtimeDelta || right.localeCompare(left, undefined, { numeric: true });
11500
11498
  });
11501
- return files.length > 0 ? join18(summariesDir, files[0]) : null;
11499
+ return files.length > 0 ? join17(summariesDir, files[0]) : null;
11502
11500
  }
11503
11501
  function getTopicMemoryFilePaths(_userId, topicName, forkOrigin, workspaceDir = resolveStorageWorkspaceDir()) {
11504
11502
  const wikiDir = getSharedWikiDir(workspaceDir);
11505
11503
  const resolveBrief = (name) => {
11506
11504
  const safe = sanitizeTopicName(name, true);
11507
- const brief = join18(wikiDir, "topic", `${safe}.md`);
11505
+ const brief = join17(wikiDir, "topic", `${safe}.md`);
11508
11506
  const latestSummary = findLatestSummaryFile(wikiDir, safe);
11509
11507
  return { brief, latestSummary };
11510
11508
  };
11511
- const archiveDir = join18(wikiDir, "archive");
11509
+ const archiveDir = join17(wikiDir, "archive");
11512
11510
  const archiveExistsFor = (name) => {
11513
11511
  const safe = sanitizeTopicName(name);
11514
11512
  return existsSync16(archiveDir) && readdirSync3(archiveDir).some((f) => f.endsWith(".jsonl") && f.startsWith(`${safe}_`));
@@ -11518,14 +11516,14 @@ function getTopicMemoryFilePaths(_userId, topicName, forkOrigin, workspaceDir =
11518
11516
  const target = resolveBrief(sourceTopic);
11519
11517
  if (existsSync16(target.brief)) {
11520
11518
  return {
11521
- memoryDir: dirname11(target.brief),
11519
+ memoryDir: dirname10(target.brief),
11522
11520
  memoryFiles: [basename2(target.brief)],
11523
11521
  ...target.latestSummary ? { latestSummaryFile: target.latestSummary } : {},
11524
11522
  ...hasArchive ? { hasArchive: true } : {}
11525
11523
  };
11526
11524
  }
11527
11525
  return {
11528
- memoryDir: join18(wikiDir, "topic"),
11526
+ memoryDir: join17(wikiDir, "topic"),
11529
11527
  memoryFiles: [],
11530
11528
  ...target.latestSummary ? { latestSummaryFile: target.latestSummary } : {},
11531
11529
  ...hasArchive ? { hasArchive: true } : {}
@@ -11538,7 +11536,7 @@ var init_wiki = __esm(async () => {
11538
11536
  // ../../packages/core/src/agents/archiver.ts
11539
11537
  import { randomUUID as randomUUID10 } from "crypto";
11540
11538
  import { existsSync as existsSync17, readdirSync as readdirSync4, readFileSync as readFileSync14, statSync as statSync7 } from "fs";
11541
- import { join as join19 } from "path";
11539
+ import { join as join18 } from "path";
11542
11540
  function resolveMemoryLanguage() {
11543
11541
  const override = process.env.NEGOTIUM_MEMORY_LANG?.trim();
11544
11542
  return override && override.length > 0 ? override : resolveOutputLanguage();
@@ -11789,10 +11787,10 @@ function distillOneLine(summaryMd) {
11789
11787
  return "";
11790
11788
  }
11791
11789
  function findSummaryFile(storage, topicTitle, date, sinceMs, topicId) {
11792
- const dir = join19(storage.getWikiDir(), "summaries");
11790
+ const dir = join18(storage.getWikiDir(), "summaries");
11793
11791
  if (!storage.fileExists(dir))
11794
11792
  return null;
11795
- const predicted = join19(dir, wikiSummaryFilename(date, topicTitle, topicId));
11793
+ const predicted = join18(dir, wikiSummaryFilename(date, topicTitle, topicId));
11796
11794
  if (storage.fileExists(predicted) && storage.fileModifiedAt(predicted) >= sinceMs)
11797
11795
  return predicted;
11798
11796
  let best = null;
@@ -11800,7 +11798,7 @@ function findSummaryFile(storage, topicTitle, date, sinceMs, topicId) {
11800
11798
  if (!f.startsWith(`${date}-`) || !isTopicSummaryFile(f, topicId ?? "", topicTitle)) {
11801
11799
  continue;
11802
11800
  }
11803
- const p = join19(dir, f);
11801
+ const p = join18(dir, f);
11804
11802
  try {
11805
11803
  const m = storage.fileModifiedAt(p);
11806
11804
  if (m >= sinceMs && (!best || m > best.mtime))
@@ -12010,13 +12008,13 @@ __export(exports_topic_archive, {
12010
12008
  archiveConversationEvents: () => archiveConversationEvents
12011
12009
  });
12012
12010
  import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync9 } from "fs";
12013
- import { join as join20 } from "path";
12011
+ import { join as join19 } from "path";
12014
12012
  function archiveTopicMessages(topicId, topicTitle, options = {}) {
12015
12013
  const rows = options.afterRowid !== undefined ? getMessagesForTopicAfterRowid(topicId, options.afterRowid) : getAllMessagesForTopic(topicId);
12016
12014
  if (rows.length === 0)
12017
12015
  return null;
12018
12016
  const safeTopic = sanitizeTopicName(topicTitle, true);
12019
- const archiveDir = join20(getSharedWikiDir(), "archive");
12017
+ const archiveDir = join19(getSharedWikiDir(), "archive");
12020
12018
  mkdirSync11(archiveDir, { recursive: true });
12021
12019
  const date = new Date().toISOString().slice(0, 10);
12022
12020
  const reasonSuffix = options.reason && options.reason !== "delete" ? `_${options.reason}` : "";
@@ -12029,7 +12027,7 @@ function archiveTopicMessages(topicId, topicTitle, options = {}) {
12029
12027
  let path;
12030
12028
  while (true) {
12031
12029
  filename = `${safeTopic}_${date}${reasonSuffix}${counter === 1 ? "" : `_${counter}`}.jsonl`;
12032
- path = join20(archiveDir, filename);
12030
+ path = join19(archiveDir, filename);
12033
12031
  try {
12034
12032
  writeFileSync9(path, body, { flag: "wx" });
12035
12033
  break;
@@ -12074,7 +12072,7 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
12074
12072
  const entries = readRawConversation(userId, topicTitle);
12075
12073
  if (entries.length === 0)
12076
12074
  return null;
12077
- const archiveDir = join20(getSharedWikiDir(), "archive");
12075
+ const archiveDir = join19(getSharedWikiDir(), "archive");
12078
12076
  mkdirSync11(archiveDir, { recursive: true });
12079
12077
  const safeTopic = sanitizeTopicName(topicTitle, true);
12080
12078
  const date = new Date().toISOString().slice(0, 10);
@@ -12102,7 +12100,7 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
12102
12100
  let counter = 1;
12103
12101
  while (true) {
12104
12102
  const suffix = counter === 1 ? "" : `_${counter}`;
12105
- const path = join20(archiveDir, `${safeTopic}_${date}${reasonSuffix}_events${suffix}.jsonl`);
12103
+ const path = join19(archiveDir, `${safeTopic}_${date}${reasonSuffix}_events${suffix}.jsonl`);
12106
12104
  try {
12107
12105
  writeFileSync9(path, body, { flag: "wx" });
12108
12106
  logger.info({ topicId, topicTitle, archive: path, eventCount: entries.length }, "archiveConversationEvents: archived raw conversation events");
@@ -12434,7 +12432,7 @@ var init_idle_archiver = __esm(async () => {
12434
12432
 
12435
12433
  // ../../packages/core/src/agents/topic-cleanup.ts
12436
12434
  import { mkdirSync as mkdirSync12, renameSync as renameSync6, unlinkSync as unlinkSync12, writeFileSync as writeFileSync10 } from "fs";
12437
- import { dirname as dirname12 } from "path";
12435
+ import { dirname as dirname11 } from "path";
12438
12436
  function collectSessionIdsByAgent(entries, extraSessions = []) {
12439
12437
  const out = new Map;
12440
12438
  for (const e of entries) {
@@ -12500,7 +12498,7 @@ function createTopicLogMaintenance(host) {
12500
12498
  const path = runtimeHost.activeConversationPath(opts.userId, opts.topicName);
12501
12499
  const tempPath = `${path}.${process.pid}.${Date.now()}.tmp`;
12502
12500
  try {
12503
- mkdirSync12(dirname12(path), { recursive: true });
12501
+ mkdirSync12(dirname11(path), { recursive: true });
12504
12502
  writeFileSync10(tempPath, retained.length > 0 ? `${retained.map((entry) => JSON.stringify(entry)).join(`
12505
12503
  `)}
12506
12504
  ` : "", { flag: "wx" });
@@ -13114,7 +13112,7 @@ var init_runtime_turn_requests = __esm(async () => {
13114
13112
  import { randomUUID as randomUUID12 } from "crypto";
13115
13113
  import { mkdtempSync as mkdtempSync2, rmSync as rmSync4, writeFileSync as writeFileSync11 } from "fs";
13116
13114
  import { tmpdir as tmpdir3 } from "os";
13117
- import { join as join21 } from "path";
13115
+ import { join as join20 } from "path";
13118
13116
  async function waitForMemoryArchive(settled, timeoutMs) {
13119
13117
  let timer;
13120
13118
  try {
@@ -13367,7 +13365,7 @@ function formatCompactElapsed(startedAt) {
13367
13365
  async function summarizeTopicContext(request) {
13368
13366
  const startedAt = Date.now();
13369
13367
  const sessionIds = [];
13370
- const compactCwd = mkdtempSync2(join21(tmpdir3(), "negotium-compact-"));
13368
+ const compactCwd = mkdtempSync2(join20(tmpdir3(), "negotium-compact-"));
13371
13369
  const abortController = new AbortController;
13372
13370
  const relayAbort = () => abortController.abort(request.signal?.reason);
13373
13371
  if (request.signal?.aborted)
@@ -13394,7 +13392,7 @@ async function summarizeTopicContext(request) {
13394
13392
  let error = "";
13395
13393
  let toolViolation = false;
13396
13394
  let compactionLogCalls = 0;
13397
- const compactionLogPath = join21(compactCwd, "conversation.log");
13395
+ const compactionLogPath = join20(compactCwd, "conversation.log");
13398
13396
  try {
13399
13397
  const compactionMcp = useCompactionLog ? {
13400
13398
  compact_log: {
@@ -14694,14 +14692,14 @@ var init_self_config = __esm(async () => {
14694
14692
  });
14695
14693
 
14696
14694
  // ../../packages/core/src/query/session-inbox-path.ts
14697
- import { join as join22 } from "path";
14695
+ import { join as join21 } from "path";
14698
14696
  function sessionInboxPath(userId, topicId) {
14699
14697
  const key = Buffer.from(topicId, "utf8").toString("base64url");
14700
- return join22(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${JSONL_SUFFIX}`);
14698
+ return join21(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${JSONL_SUFFIX}`);
14701
14699
  }
14702
14700
  function scheduledSessionInboxPath(userId, topicId) {
14703
14701
  const key = Buffer.from(topicId, "utf8").toString("base64url");
14704
- return join22(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${SCHEDULE_SUFFIX}`);
14702
+ return join21(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${SCHEDULE_SUFFIX}`);
14705
14703
  }
14706
14704
  function decodeTopicIdFileName(fileName, suffix) {
14707
14705
  if (!fileName.startsWith(TOPIC_ID_FILE_PREFIX) || !fileName.endsWith(suffix))
@@ -14729,13 +14727,13 @@ var init_session_inbox_path = __esm(() => {
14729
14727
 
14730
14728
  // ../../packages/core/src/query/session-inbox-cleanup.ts
14731
14729
  import { unlinkSync as unlinkSync14 } from "fs";
14732
- import { basename as basename3, join as join23 } from "path";
14730
+ import { basename as basename3, join as join22 } from "path";
14733
14731
  function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
14734
14732
  const live = sessionInboxPath(userId, topicId);
14735
14733
  const scheduled = scheduledSessionInboxPath(userId, topicId);
14736
14734
  const candidates = new Set([live, `${live}.processing`, scheduled, `${scheduled}.processing`]);
14737
14735
  if (legacyTopicTitle && legacyTopicTitle !== "." && legacyTopicTitle !== ".." && basename3(legacyTopicTitle) === legacyTopicTitle) {
14738
- const legacyBase = join23(SESSION_INBOX_DIR, userId, legacyTopicTitle);
14736
+ const legacyBase = join22(SESSION_INBOX_DIR, userId, legacyTopicTitle);
14739
14737
  for (const suffix of [".jsonl", ".jsonl.processing", ".schedule", ".schedule.processing"]) {
14740
14738
  candidates.add(`${legacyBase}${suffix}`);
14741
14739
  }
@@ -14761,16 +14759,16 @@ var init_session_inbox_cleanup = __esm(() => {
14761
14759
 
14762
14760
  // ../../packages/core/src/query/state.ts
14763
14761
  import { mkdirSync as mkdirSync14, renameSync as renameSync7, unlinkSync as unlinkSync15, writeFileSync as writeFileSync12 } from "fs";
14764
- import { basename as basename4, join as join24 } from "path";
14762
+ import { basename as basename4, join as join23 } from "path";
14765
14763
  function createQueryStateStore(options) {
14766
14764
  const sanitize = options.sanitizeTopicId ?? sanitizeId;
14767
- const queryStateDirPath = (userId) => join24(options.usersLogDir, String(userId), "active-queries");
14768
- const queryStateFile = (userId, topicId) => join24(queryStateDirPath(userId), `${sanitize(topicId)}.json`);
14765
+ const queryStateDirPath = (userId) => join23(options.usersLogDir, String(userId), "active-queries");
14766
+ const queryStateFile = (userId, topicId) => join23(queryStateDirPath(userId), `${sanitize(topicId)}.json`);
14769
14767
  const legacyQueryStateFile = (userId, topicName) => {
14770
14768
  if (!topicName || topicName === "." || topicName === ".." || basename4(topicName) !== topicName) {
14771
14769
  return null;
14772
14770
  }
14773
- return join24(queryStateDirPath(userId), `${topicName}.json`);
14771
+ return join23(queryStateDirPath(userId), `${topicName}.json`);
14774
14772
  };
14775
14773
  return {
14776
14774
  write(userId, topicId, topicName, task) {
@@ -14930,30 +14928,30 @@ import {
14930
14928
  unlinkSync as unlinkSync16,
14931
14929
  writeFileSync as writeFileSync13
14932
14930
  } from "fs";
14933
- import { dirname as dirname13, join as join25 } from "path";
14931
+ import { dirname as dirname12, join as join24 } from "path";
14934
14932
  function pendingAskDir(userId) {
14935
14933
  const rawUserId = String(userId);
14936
14934
  const safeUserId = /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash5("sha256").update(rawUserId).digest("hex")}`;
14937
- return join25(resolveStorageSessionAsksDir(), safeUserId);
14935
+ return join24(resolveStorageSessionAsksDir(), safeUserId);
14938
14936
  }
14939
14937
  function encodeAskKey(key) {
14940
14938
  return JSON.stringify([key.from, key.to]);
14941
14939
  }
14942
14940
  function pendingAskPath(key) {
14943
14941
  const digest = createHash5("sha256").update(encodeAskKey(key)).digest("hex");
14944
- return join25(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
14942
+ return join24(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
14945
14943
  }
14946
14944
  function v2PendingAskPath(key) {
14947
14945
  const encoded = Buffer.from(encodeAskKey(key), "utf8").toString("base64url");
14948
- return join25(pendingAskDir(key.userId), `${V2_ASK_FILENAME_PREFIX}${encoded}.pending`);
14946
+ return join24(pendingAskDir(key.userId), `${V2_ASK_FILENAME_PREFIX}${encoded}.pending`);
14949
14947
  }
14950
14948
  function legacyPendingAskPath(key) {
14951
14949
  if (key.from.includes("/") || key.from.includes("\\") || key.to.includes("/") || key.to.includes("\\") || key.from.includes("\x00") || key.to.includes("\x00")) {
14952
14950
  return null;
14953
14951
  }
14954
14952
  const dir = pendingAskDir(key.userId);
14955
- const candidate = join25(dir, `${key.from}___${key.to}.pending`);
14956
- return dirname13(candidate) === dir ? candidate : null;
14953
+ const candidate = join24(dir, `${key.from}___${key.to}.pending`);
14954
+ return dirname12(candidate) === dir ? candidate : null;
14957
14955
  }
14958
14956
  function parsePendingAskFilename(fileName) {
14959
14957
  if (!fileName.endsWith(".pending"))
@@ -15193,7 +15191,7 @@ function listPendingAsksForCaller(args) {
15193
15191
  const parsed = isV3 ? { from: args.from, to: "" } : parsePendingAskFilename(fileName);
15194
15192
  if (!parsed)
15195
15193
  continue;
15196
- const path = join25(dir, fileName);
15194
+ const path = join24(dir, fileName);
15197
15195
  const record = readPendingAskFile(path, {
15198
15196
  userId: args.userId,
15199
15197
  from: parsed.from,
@@ -15235,7 +15233,7 @@ function deletePendingAsksForTopic(args) {
15235
15233
  }
15236
15234
  let deleted = 0;
15237
15235
  for (const fileName of files) {
15238
- const path = join25(dir, fileName);
15236
+ const path = join24(dir, fileName);
15239
15237
  const parsed = parsePendingAskFilename(fileName);
15240
15238
  const record = readPendingAskFile(path, {
15241
15239
  userId: args.userId,
@@ -15876,7 +15874,7 @@ var init_lifecycle = __esm(async () => {
15876
15874
  // ../../packages/core/src/runtime/attachments.ts
15877
15875
  import { randomUUID as randomUUID15 } from "crypto";
15878
15876
  import { copyFileSync as copyFileSync2, mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "fs";
15879
- import { basename as basename5, join as join26 } from "path";
15877
+ import { basename as basename5, join as join25 } from "path";
15880
15878
  function workspaceCwdFor(topicId) {
15881
15879
  return resolveTopicWorkspaceDir(topicId);
15882
15880
  }
@@ -15889,7 +15887,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
15889
15887
  if (!attachmentIds?.length)
15890
15888
  return [];
15891
15889
  const out = [];
15892
- const destDir = join26(workspaceCwdFor(topicId), "attachments", queryId);
15890
+ const destDir = join25(workspaceCwdFor(topicId), "attachments", queryId);
15893
15891
  for (const rawId of attachmentIds) {
15894
15892
  if (typeof rawId !== "string")
15895
15893
  continue;
@@ -15906,7 +15904,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
15906
15904
  mkdirSync16(destDir, { recursive: true });
15907
15905
  const index = String(out.length + 1).padStart(2, "0");
15908
15906
  const safeName = safeAttachmentFilename(attachment.filename, fileId);
15909
- const destPath = join26(destDir, `${index}-${fileId.slice(0, 8)}-${safeName}`);
15907
+ const destPath = join25(destDir, `${index}-${fileId.slice(0, 8)}-${safeName}`);
15910
15908
  copyFileSync2(sourcePath, destPath);
15911
15909
  out.push({
15912
15910
  id: attachment.id,
@@ -15936,10 +15934,10 @@ function promptWithAttachments(prompt, attachments) {
15936
15934
  return composeAttachmentPrompt(prompt, attachments.map(({ filename, path }) => attachmentPromptLine(filename, path)));
15937
15935
  }
15938
15936
  function ingestAttachment(args) {
15939
- const destDir = join26(UPLOADS_DIR, args.topicId);
15937
+ const destDir = join25(UPLOADS_DIR, args.topicId);
15940
15938
  mkdirSync16(destDir, { recursive: true });
15941
15939
  const safeName = safeAttachmentFilename(args.filename, "upload");
15942
- const destPath = join26(destDir, `${Date.now()}-${randomUUID15().slice(0, 8)}-${safeName}`);
15940
+ const destPath = join25(destDir, `${Date.now()}-${randomUUID15().slice(0, 8)}-${safeName}`);
15943
15941
  if (args.sourcePath !== undefined) {
15944
15942
  copyFileSync2(args.sourcePath, destPath);
15945
15943
  } else if (args.bytes !== undefined) {
@@ -16553,7 +16551,7 @@ __export(exports_token_stats, {
16553
16551
  });
16554
16552
  import { createHash as createHash6 } from "crypto";
16555
16553
  import { mkdirSync as mkdirSync17 } from "fs";
16556
- import { join as join27 } from "path";
16554
+ import { join as join26 } from "path";
16557
16555
  function emptyBucket() {
16558
16556
  return {
16559
16557
  inputTokens: 0,
@@ -16571,7 +16569,7 @@ function queriesPath(userId) {
16571
16569
  const fileId = tokenStatsFileId(userId);
16572
16570
  const logDir = resolveStorageLogDir();
16573
16571
  mkdirSync17(logDir, { recursive: true });
16574
- return join27(logDir, `token-queries-${fileId}.jsonl`);
16572
+ return join26(logDir, `token-queries-${fileId}.jsonl`);
16575
16573
  }
16576
16574
  function loadRecords(userId) {
16577
16575
  try {
@@ -17231,9 +17229,9 @@ __export(exports_app_settings, {
17231
17229
  DEFAULT_AI_NAME: () => DEFAULT_AI_NAME
17232
17230
  });
17233
17231
  import { existsSync as existsSync18, mkdirSync as mkdirSync18, readFileSync as readFileSync16, writeFileSync as writeFileSync15 } from "fs";
17234
- import { dirname as dirname14, join as join28 } from "path";
17232
+ import { dirname as dirname13, join as join27 } from "path";
17235
17233
  function settingsFile() {
17236
- return join28(resolveStorageDataDir(), "otium-settings.json");
17234
+ return join27(resolveStorageDataDir(), "otium-settings.json");
17237
17235
  }
17238
17236
  function ensureSettingsLoaded() {
17239
17237
  const path = settingsFile();
@@ -17259,7 +17257,7 @@ function setGlobalAiName(name) {
17259
17257
  const path = ensureSettingsLoaded();
17260
17258
  aiName = name.trim() || DEFAULT_AI_NAME;
17261
17259
  try {
17262
- mkdirSync18(dirname14(path), { recursive: true });
17260
+ mkdirSync18(dirname13(path), { recursive: true });
17263
17261
  writeFileSync15(path, JSON.stringify({ aiName }, null, 2));
17264
17262
  } catch {}
17265
17263
  return aiName;
@@ -17342,7 +17340,7 @@ __export(exports_turn_runner, {
17342
17340
  });
17343
17341
  import { randomUUID as randomUUID17 } from "crypto";
17344
17342
  import { existsSync as existsSync19, mkdirSync as mkdirSync19, readdirSync as readdirSync6, statSync as statSync10 } from "fs";
17345
- import { join as join29 } from "path";
17343
+ import { join as join28 } from "path";
17346
17344
  function withDefaultPlaywright(configuredMcp, isManager) {
17347
17345
  if (isManager)
17348
17346
  return configuredMcp;
@@ -17385,7 +17383,7 @@ function appendAskReplyMessage(topicId, text2, agentType) {
17385
17383
  return message;
17386
17384
  }
17387
17385
  function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, matchesTitle, preferExact = true) {
17388
- const preferred = join29(directory, preferredFilename);
17386
+ const preferred = join28(directory, preferredFilename);
17389
17387
  if (preferExact && existsSync19(preferred))
17390
17388
  return preferred;
17391
17389
  let newestLegacyId = null;
@@ -17396,7 +17394,7 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
17396
17394
  const legacyIdMatch = !titleMatch && matchesLegacyId(filename);
17397
17395
  if (!titleMatch && !legacyIdMatch)
17398
17396
  continue;
17399
- const path = join29(directory, filename);
17397
+ const path = join28(directory, filename);
17400
17398
  const mtimeMs = statSync10(path).mtimeMs;
17401
17399
  if (titleMatch) {
17402
17400
  if (!newestTitle || mtimeMs > newestTitle.mtimeMs) {
@@ -17410,9 +17408,9 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
17410
17408
  return newestTitle?.path ?? newestLegacyId?.path ?? preferred;
17411
17409
  }
17412
17410
  function resolveWikiMemoryMirror(wikiDir, topicId, topicTitle) {
17413
- const briefFile = resolveWikiMirrorPath(join29(wikiDir, "topic"), `${wikiBriefStorageKey(topicTitle, topicId)}.md`, (filename) => isTopicBriefFile(filename, topicId), (filename) => isTopicBriefFile(filename, topicId, topicTitle));
17411
+ const briefFile = resolveWikiMirrorPath(join28(wikiDir, "topic"), `${wikiBriefStorageKey(topicTitle, topicId)}.md`, (filename) => isTopicBriefFile(filename, topicId), (filename) => isTopicBriefFile(filename, topicId, topicTitle));
17414
17412
  const hasBriefFile = existsSync19(briefFile) && statSync10(briefFile).isFile();
17415
- const latestSummaryCandidate = resolveWikiMirrorPath(join29(wikiDir, "summaries"), `__missing__-${wikiSummaryFilename("0000-00-00", topicTitle, topicId)}`, (filename) => isTopicSummaryFile(filename, topicId), (filename) => isTopicSummaryFile(filename, topicId, topicTitle), false);
17413
+ const latestSummaryCandidate = resolveWikiMirrorPath(join28(wikiDir, "summaries"), `__missing__-${wikiSummaryFilename("0000-00-00", topicTitle, topicId)}`, (filename) => isTopicSummaryFile(filename, topicId), (filename) => isTopicSummaryFile(filename, topicId, topicTitle), false);
17416
17414
  const latestSummaryFile = existsSync19(latestSummaryCandidate) && statSync10(latestSummaryCandidate).isFile() ? latestSummaryCandidate : null;
17417
17415
  return { briefFile, hasBriefFile, latestSummaryFile };
17418
17416
  }
@@ -20092,7 +20090,7 @@ var init_vault_command = __esm(async () => {
20092
20090
  import { execFile } from "child_process";
20093
20091
  import { existsSync as existsSync20, mkdirSync as mkdirSync21, readFileSync as readFileSync17, rmSync as rmSync7 } from "fs";
20094
20092
  import { readFile } from "fs/promises";
20095
- import { extname, join as join30 } from "path";
20093
+ import { extname, join as join29 } from "path";
20096
20094
  import { promisify } from "util";
20097
20095
  async function extractText(filePath) {
20098
20096
  const ext = extname(filePath).toLowerCase();
@@ -20209,7 +20207,7 @@ async function extractFromAudio(filePath, opts = {}) {
20209
20207
  const tmpDir = `${filePath}_whisper_tmp`;
20210
20208
  try {
20211
20209
  mkdirSync21(tmpDir, { recursive: true });
20212
- const mp3Path = join30(tmpDir, "audio.mp3");
20210
+ const mp3Path = join29(tmpDir, "audio.mp3");
20213
20211
  await execFileAsync(opts.ffmpegBin ?? FFMPEG_BIN2, [
20214
20212
  "-y",
20215
20213
  "-i",
@@ -20236,7 +20234,7 @@ async function extractFromAudio(filePath, opts = {}) {
20236
20234
  "--output-format",
20237
20235
  "txt"
20238
20236
  ], { timeout: 120000 });
20239
- const txtPath = join30(tmpDir, "audio.txt");
20237
+ const txtPath = join29(tmpDir, "audio.txt");
20240
20238
  const text2 = existsSync20(txtPath) ? readFileSync17(txtPath, "utf-8").trim() : null;
20241
20239
  if (!text2) {
20242
20240
  return { text: null, method: "whisper", error: "Whisper produced no text" };
@@ -20759,7 +20757,7 @@ var init_utils = __esm(() => {
20759
20757
  // ../../packages/core/src/runtime/inbox.ts
20760
20758
  import { createHash as createHash7, randomUUID as randomUUID21 } from "crypto";
20761
20759
  import { readdirSync as readdirSync7, statSync as statSync11, writeFileSync as writeFileSync16 } from "fs";
20762
- import { join as join31 } from "path";
20760
+ import { join as join30 } from "path";
20763
20761
  async function createAskForkPlan(options) {
20764
20762
  const snapshot = structuredClone(options.entries);
20765
20763
  const prepareSession = async () => options.synthesize(structuredClone(snapshot));
@@ -20884,7 +20882,7 @@ async function flushSessionInbox() {
20884
20882
  return;
20885
20883
  }
20886
20884
  for (const uid of userDirs) {
20887
- const userInboxDir = join31(SESSION_INBOX_DIR, uid);
20885
+ const userInboxDir = join30(SESSION_INBOX_DIR, uid);
20888
20886
  let entries;
20889
20887
  try {
20890
20888
  entries = readdirSync7(userInboxDir);
@@ -20892,7 +20890,7 @@ async function flushSessionInbox() {
20892
20890
  continue;
20893
20891
  }
20894
20892
  for (const entry of entries) {
20895
- const entryPath = join31(userInboxDir, entry);
20893
+ const entryPath = join30(userInboxDir, entry);
20896
20894
  let isDir = false;
20897
20895
  try {
20898
20896
  isDir = statSync11(entryPath).isDirectory();
@@ -20982,7 +20980,7 @@ function sweepScheduledSessionInbox(nowMs = Date.now()) {
20982
20980
  return;
20983
20981
  }
20984
20982
  for (const userId of userDirs) {
20985
- const userInboxDir = join31(SESSION_INBOX_DIR, userId);
20983
+ const userInboxDir = join30(SESSION_INBOX_DIR, userId);
20986
20984
  let files;
20987
20985
  try {
20988
20986
  files = readdirSync7(userInboxDir);
@@ -20994,7 +20992,7 @@ function sweepScheduledSessionInbox(nowMs = Date.now()) {
20994
20992
  const topicId = topicIdFromScheduledSessionInboxFileName(file);
20995
20993
  if (!topicId)
20996
20994
  continue;
20997
- const schedulePath = join31(userInboxDir, file);
20995
+ const schedulePath = join30(userInboxDir, file);
20998
20996
  const hasProcessingClaim = files.includes(`${file}.processing`);
20999
20997
  if (!hasProcessingClaim && !scheduledFileNeedsClaim(schedulePath, nowMs))
21000
20998
  continue;
@@ -21718,7 +21716,7 @@ var init_src = __esm(async () => {
21718
21716
 
21719
21717
  // ../../packages/core/src/storage/conversation-migration.ts
21720
21718
  import { copyFileSync as copyFileSync3, existsSync as existsSync22, mkdirSync as mkdirSync23, readFileSync as readFileSync19 } from "fs";
21721
- import { dirname as dirname15, join as join32 } from "path";
21719
+ import { dirname as dirname14, join as join31 } from "path";
21722
21720
  function readEntries(path) {
21723
21721
  const entries = [];
21724
21722
  for (const [index, line] of readFileSync19(path, "utf8").split(`
@@ -21785,7 +21783,7 @@ function migrateLegacyCompactedConversations() {
21785
21783
  result.skipped++;
21786
21784
  continue;
21787
21785
  }
21788
- const backupPath = join32(resolveStorageDataDir(), "conversation-migration-backups", MIGRATION_NAME, userId, `${sanitizeTopicName(topic.title, true)}.jsonl`);
21786
+ const backupPath = join31(resolveStorageDataDir(), "conversation-migration-backups", MIGRATION_NAME, userId, `${sanitizeTopicName(topic.title, true)}.jsonl`);
21789
21787
  const sourcePath = existsSync22(backupPath) ? backupPath : rawPath;
21790
21788
  const legacyEntries = readEntries(sourcePath);
21791
21789
  const compactIndex = compactionEntryIndex(legacyEntries);
@@ -21794,7 +21792,7 @@ function migrateLegacyCompactedConversations() {
21794
21792
  continue;
21795
21793
  }
21796
21794
  if (!existsSync22(backupPath)) {
21797
- mkdirSync23(dirname15(backupPath), { recursive: true });
21795
+ mkdirSync23(dirname14(backupPath), { recursive: true });
21798
21796
  copyFileSync3(rawPath, backupPath);
21799
21797
  }
21800
21798
  const compactedAt = legacyEntries[compactIndex]?.ts;
@@ -22520,7 +22518,7 @@ __export(exports_agent_health, {
22520
22518
  });
22521
22519
  import { spawn as spawn5 } from "child_process";
22522
22520
  import { existsSync as existsSync23, readdirSync as readdirSync8 } from "fs";
22523
- import { join as join33 } from "path";
22521
+ import { join as join32 } from "path";
22524
22522
  import { McpServer as McpServer4 } from "@modelcontextprotocol/sdk/server/mcp.js";
22525
22523
  import { z as z8 } from "zod";
22526
22524
  function signalProcessTree2(child, signal) {
@@ -22764,7 +22762,7 @@ ${results.every((result) => result.ok) ? "All agents healthy" : "Some agents fai
22764
22762
  server.tool("list_active_queries", "\uD604\uC7AC \uC0AC\uC6A9\uC790 \uBC94\uC704\uC5D0\uC11C \uC2E4\uD589 \uC911\uC778 \uD1A0\uD53D \uCFFC\uB9AC \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4.", {}, async () => {
22765
22763
  if (!context.userId)
22766
22764
  return mcpOk("\uC2E4\uD589 \uC911\uC778 \uCFFC\uB9AC \uC870\uD68C \uBD88\uAC00 (user context \uC5C6\uC74C)");
22767
- const stateDir = join33(USERS_LOG_DIR, context.userId, "active-queries");
22765
+ const stateDir = join32(USERS_LOG_DIR, context.userId, "active-queries");
22768
22766
  if (!existsSync23(stateDir))
22769
22767
  return mcpOk("\uC2E4\uD589 \uC911\uC778 \uCFFC\uB9AC \uC5C6\uC74C");
22770
22768
  let files;
@@ -22777,7 +22775,7 @@ ${results.every((result) => result.ok) ? "All agents healthy" : "Some agents fai
22777
22775
  const entries = files.flatMap((file) => {
22778
22776
  if (!file.endsWith(".json"))
22779
22777
  return [];
22780
- const state = readJsonFile(join33(stateDir, file));
22778
+ const state = readJsonFile(join32(stateDir, file));
22781
22779
  if (!state)
22782
22780
  return [];
22783
22781
  const sinceMs = new Date(state.since).getTime();
@@ -22986,7 +22984,7 @@ var exports_default_host = {};
22986
22984
  __export(exports_default_host, {
22987
22985
  createDefaultSessionCommMcpHost: () => createDefaultSessionCommMcpHost
22988
22986
  });
22989
- import { basename as basename6, join as join34 } from "path";
22987
+ import { basename as basename6, join as join33 } from "path";
22990
22988
  function ok2(text2) {
22991
22989
  return { content: [{ type: "text", text: text2 }] };
22992
22990
  }
@@ -23028,10 +23026,10 @@ function remoteTarget(context, to) {
23028
23026
  return { node: to.slice(0, slash), topic: to.slice(slash + 1) };
23029
23027
  }
23030
23028
  function activeQuery(context, topicId, title) {
23031
- const dir = join34(USERS_LOG_DIR, context.userId, "active-queries");
23032
- const candidates = [join34(dir, `${sanitizeId(topicId)}.json`)];
23029
+ const dir = join33(USERS_LOG_DIR, context.userId, "active-queries");
23030
+ const candidates = [join33(dir, `${sanitizeId(topicId)}.json`)];
23033
23031
  if (title && basename6(title) === title && title !== "." && title !== "..") {
23034
- candidates.push(join34(dir, `${title}.json`));
23032
+ candidates.push(join33(dir, `${title}.json`));
23035
23033
  }
23036
23034
  for (const path of candidates) {
23037
23035
  const state = readJsonFile(path);
@@ -23676,7 +23674,7 @@ import {
23676
23674
  unlinkSync as unlinkSync18,
23677
23675
  writeFileSync as writeFileSync17
23678
23676
  } from "fs";
23679
- import { basename as basename7, dirname as dirname16, join as join35, resolve as resolve16 } from "path";
23677
+ import { basename as basename7, dirname as dirname15, join as join34, resolve as resolve16 } from "path";
23680
23678
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
23681
23679
  import { StdioServerTransport as StdioServerTransport2 } from "@modelcontextprotocol/sdk/server/stdio.js";
23682
23680
  import {
@@ -23825,13 +23823,13 @@ function wikiQuery(args) {
23825
23823
  try {
23826
23824
  for (const entry of readdirSync9(dir, { withFileTypes: true })) {
23827
23825
  if (entry.isDirectory()) {
23828
- const sub = join35(dir, entry.name);
23826
+ const sub = join34(dir, entry.name);
23829
23827
  if (label === "articles" || label === "skills") {
23830
23828
  try {
23831
23829
  for (const f of readdirSync9(sub, { withFileTypes: true })) {
23832
23830
  if (!f.isFile() || !f.name.endsWith(".md"))
23833
23831
  continue;
23834
- const fp = join35(sub, f.name);
23832
+ const fp = join34(sub, f.name);
23835
23833
  try {
23836
23834
  const text2 = readFileSync20(fp, "utf-8");
23837
23835
  scored.push({
@@ -23844,7 +23842,7 @@ function wikiQuery(args) {
23844
23842
  } catch {}
23845
23843
  }
23846
23844
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
23847
- const fp = join35(dir, entry.name);
23845
+ const fp = join34(dir, entry.name);
23848
23846
  try {
23849
23847
  const text2 = readFileSync20(fp, "utf-8");
23850
23848
  scored.push({
@@ -24193,7 +24191,7 @@ function saveTopicBrief(args) {
24193
24191
  const topicId = runtime().topicId;
24194
24192
  const fileSlug = wikiBriefStorageKey(rawTopic, topicId);
24195
24193
  const briefPath = resolve16(runtime().topicsDir, `${fileSlug}.md`);
24196
- ensureDir(dirname16(briefPath));
24194
+ ensureDir(dirname15(briefPath));
24197
24195
  const existed = existsSync24(briefPath);
24198
24196
  writeFileSync17(briefPath, content, "utf-8");
24199
24197
  const setTopicBrief2 = runtime().host.setTopicBrief;
@@ -24231,7 +24229,7 @@ function indexUpsert(args) {
24231
24229
  return resolve16(runtime().wikiDir, "skill-index.md");
24232
24230
  return resolve16(runtime().wikiDir, "article-index.md");
24233
24231
  })();
24234
- ensureDir(dirname16(indexPath));
24232
+ ensureDir(dirname15(indexPath));
24235
24233
  const releaseLock = acquireFileLock(indexPath);
24236
24234
  try {
24237
24235
  let index;
@@ -24529,7 +24527,7 @@ import {
24529
24527
  unlinkSync as unlinkSync19,
24530
24528
  writeFileSync as writeFileSync18
24531
24529
  } from "fs";
24532
- import { basename as basename8, join as join36 } from "path";
24530
+ import { basename as basename8, join as join35 } from "path";
24533
24531
  function startLogRotation() {
24534
24532
  if (rotationTimer)
24535
24533
  return;
@@ -24543,7 +24541,7 @@ function writeLog(entry) {
24543
24541
  mkdirSync25(logDir, { recursive: true });
24544
24542
  const safeSession = sanitizeTopicName(entry.session);
24545
24543
  const sidShort = entry.sessionId ? entry.sessionId.slice(0, 8) : "new";
24546
- const file = join36(logDir, `${entry.userId}_${safeSession}_${sidShort}.jsonl`);
24544
+ const file = join35(logDir, `${entry.userId}_${safeSession}_${sidShort}.jsonl`);
24547
24545
  try {
24548
24546
  const stat = statSync13(file);
24549
24547
  if (stat.size >= MAX_FILE_SIZE) {
@@ -24563,7 +24561,7 @@ function rotateOldLogs() {
24563
24561
  try {
24564
24562
  const files = readdirSync10(logDir).filter((f) => f.endsWith(".jsonl")).map((f) => {
24565
24563
  try {
24566
- const stat = statSync13(join36(logDir, f));
24564
+ const stat = statSync13(join35(logDir, f));
24567
24565
  return { name: f, size: stat.size, mtimeMs: stat.mtimeMs };
24568
24566
  } catch {
24569
24567
  return null;
@@ -24579,7 +24577,7 @@ function rotateOldLogs() {
24579
24577
  if (freed >= toFree)
24580
24578
  break;
24581
24579
  try {
24582
- unlinkSync19(join36(logDir, file.name));
24580
+ unlinkSync19(join35(logDir, file.name));
24583
24581
  freed += file.size;
24584
24582
  logger.info({ file: file.name, sizeKB: (file.size / 1024).toFixed(0) }, "Rotated out old log");
24585
24583
  } catch (e) {
@@ -24591,9 +24589,9 @@ function rotateOldLogs() {
24591
24589
  }
24592
24590
  }
24593
24591
  function writeSentFileLog(entry) {
24594
- const dir = join36(resolveStorageUsersLogDir(), String(entry.userId));
24592
+ const dir = join35(resolveStorageUsersLogDir(), String(entry.userId));
24595
24593
  mkdirSync25(dir, { recursive: true });
24596
- const file = join36(dir, "sent-files.jsonl");
24594
+ const file = join35(dir, "sent-files.jsonl");
24597
24595
  try {
24598
24596
  appendJsonlEntry(file, { ...entry, fileName: basename8(entry.filePath) });
24599
24597
  } catch (e) {
@@ -24604,7 +24602,7 @@ function entryMatchesTopic(e, topicName) {
24604
24602
  return e.topicName === topicName;
24605
24603
  }
24606
24604
  function readSentFilesForTopic(userId, topicName) {
24607
- const file = join36(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
24605
+ const file = join35(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
24608
24606
  if (!existsSync25(file))
24609
24607
  return [];
24610
24608
  try {
@@ -24615,7 +24613,7 @@ function readSentFilesForTopic(userId, topicName) {
24615
24613
  }
24616
24614
  }
24617
24615
  function removeSentFilesForTopic(userId, topicName) {
24618
- const file = join36(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
24616
+ const file = join35(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
24619
24617
  if (!existsSync25(file))
24620
24618
  return;
24621
24619
  try {
@@ -26137,7 +26135,7 @@ var init_spec = __esm(() => {
26137
26135
 
26138
26136
  // ../../packages/mcp-host/src/manifest.ts
26139
26137
  import { existsSync as existsSync26, mkdirSync as mkdirSync26, readFileSync as readFileSync21, renameSync as renameSync11, writeFileSync as writeFileSync19 } from "fs";
26140
- import { dirname as dirname17 } from "path";
26138
+ import { dirname as dirname16 } from "path";
26141
26139
  import { z as z13 } from "zod";
26142
26140
 
26143
26141
  class McpManifest {
@@ -26197,7 +26195,7 @@ class McpManifest {
26197
26195
  }
26198
26196
  }
26199
26197
  save() {
26200
- mkdirSync26(dirname17(this.file), { recursive: true });
26198
+ mkdirSync26(dirname16(this.file), { recursive: true });
26201
26199
  const payload = {
26202
26200
  version: 1,
26203
26201
  servers: [...this.entries.values()]
@@ -26241,7 +26239,7 @@ import {
26241
26239
  writeFileSync as writeFileSync20
26242
26240
  } from "fs";
26243
26241
  import { connect, createServer as createServer3 } from "net";
26244
- import { join as join37 } from "path";
26242
+ import { join as join36 } from "path";
26245
26243
  function regKey(key, instanceKey) {
26246
26244
  return `${key}\x00${instanceKey}`;
26247
26245
  }
@@ -26543,7 +26541,7 @@ class McpHost {
26543
26541
  if (file.includes(".tmp-"))
26544
26542
  continue;
26545
26543
  try {
26546
- const port = Number.parseInt(readFileSync22(join37(this.portsDir, file), "utf8").trim(), 10);
26544
+ const port = Number.parseInt(readFileSync22(join36(this.portsDir, file), "utf8").trim(), 10);
26547
26545
  if (!Number.isNaN(port))
26548
26546
  claims.set(file, port);
26549
26547
  } catch {}
@@ -26553,7 +26551,7 @@ class McpHost {
26553
26551
  writePortFile(fileName, port) {
26554
26552
  try {
26555
26553
  mkdirSync27(this.portsDir, { recursive: true });
26556
- const file = join37(this.portsDir, fileName);
26554
+ const file = join36(this.portsDir, fileName);
26557
26555
  const tmp = `${file}.tmp-${process.pid}`;
26558
26556
  writeFileSync20(tmp, String(port));
26559
26557
  renameSync12(tmp, file);
@@ -26563,7 +26561,7 @@ class McpHost {
26563
26561
  }
26564
26562
  deletePortFile(fileName) {
26565
26563
  try {
26566
- unlinkSync20(join37(this.portsDir, fileName));
26564
+ unlinkSync20(join36(this.portsDir, fileName));
26567
26565
  } catch {}
26568
26566
  }
26569
26567
  cleanupRunning(rkey, inst) {
@@ -26675,7 +26673,7 @@ import {
26675
26673
  statSync as statSync15,
26676
26674
  writeFileSync as writeFileSync21
26677
26675
  } from "fs";
26678
- import { basename as basename10, extname as extname3, join as join38 } from "path";
26676
+ import { basename as basename10, extname as extname3, join as join37 } from "path";
26679
26677
  function safeExtension(filename) {
26680
26678
  const extension = extname3(basename10(filename));
26681
26679
  return /^\.[A-Za-z0-9]{1,16}$/.test(extension) ? extension.toLowerCase() : "";
@@ -26693,14 +26691,14 @@ function contentDisposition(filename) {
26693
26691
 
26694
26692
  class NodeFileStore {
26695
26693
  uploadDir;
26696
- constructor(uploadDir = join38(DATA_DIR, "uploads")) {
26694
+ constructor(uploadDir = join37(DATA_DIR, "uploads")) {
26697
26695
  this.uploadDir = uploadDir;
26698
26696
  }
26699
26697
  #ensureDir() {
26700
26698
  mkdirSync28(this.uploadDir, { recursive: true });
26701
26699
  }
26702
26700
  #metadataPath(fileId) {
26703
- return join38(this.uploadDir, `${fileId}.meta.json`);
26701
+ return join37(this.uploadDir, `${fileId}.meta.json`);
26704
26702
  }
26705
26703
  #metadata(fileId) {
26706
26704
  if (!FILE_ID_RE.test(fileId))
@@ -26729,7 +26727,7 @@ class NodeFileStore {
26729
26727
  hooks = {
26730
26728
  resolveAttachmentByFileId: (fileId) => {
26731
26729
  const metadata = this.#metadata(fileId);
26732
- if (!metadata || !existsSync27(join38(this.uploadDir, metadata.savedName)))
26730
+ if (!metadata || !existsSync27(join37(this.uploadDir, metadata.savedName)))
26733
26731
  return null;
26734
26732
  return this.#attachment(fileId, metadata);
26735
26733
  },
@@ -26737,7 +26735,7 @@ class NodeFileStore {
26737
26735
  const metadata = this.#metadata(fileId);
26738
26736
  if (!metadata)
26739
26737
  return null;
26740
- const path = join38(this.uploadDir, metadata.savedName);
26738
+ const path = join37(this.uploadDir, metadata.savedName);
26741
26739
  return existsSync27(path) ? path : null;
26742
26740
  },
26743
26741
  storeLocalFileAsUpload: (absPath, access = {}) => this.store(absPath, access),
@@ -26748,7 +26746,7 @@ class NodeFileStore {
26748
26746
  const fileId = randomUUID25();
26749
26747
  const extension = safeExtension(absPath);
26750
26748
  const savedName = `${fileId}${extension}`;
26751
- const savedPath = join38(this.uploadDir, savedName);
26749
+ const savedPath = join37(this.uploadDir, savedName);
26752
26750
  try {
26753
26751
  const stats = statSync15(absPath);
26754
26752
  if (!stats.isFile() || stats.size > MAX_UPLOAD_BYTES)
@@ -26780,7 +26778,7 @@ class NodeFileStore {
26780
26778
  const allowed = metadata.visibility === "workspace" || metadata.ownerUserId === userId || Boolean(topic && isParticipant(topic, userId));
26781
26779
  if (!allowed)
26782
26780
  return null;
26783
- const path = join38(this.uploadDir, metadata.savedName);
26781
+ const path = join37(this.uploadDir, metadata.savedName);
26784
26782
  if (!existsSync27(path))
26785
26783
  return null;
26786
26784
  return new Response(Bun.file(path), {
@@ -26799,7 +26797,7 @@ class NodeFileStore {
26799
26797
  const metadata = this.#metadata(fileId);
26800
26798
  if (metadata?.topicId !== topicId)
26801
26799
  continue;
26802
- rmSync8(join38(this.uploadDir, metadata.savedName), { force: true });
26800
+ rmSync8(join37(this.uploadDir, metadata.savedName), { force: true });
26803
26801
  rmSync8(this.#metadataPath(fileId), { force: true });
26804
26802
  }
26805
26803
  }
@@ -26958,7 +26956,7 @@ import {
26958
26956
  unlinkSync as unlinkSync21,
26959
26957
  writeFileSync as writeFileSync22
26960
26958
  } from "fs";
26961
- import { dirname as dirname18, resolve as resolve20 } from "path";
26959
+ import { dirname as dirname17, resolve as resolve20 } from "path";
26962
26960
  function jsonError(status, error2) {
26963
26961
  return Response.json({ ok: false, error: error2 }, { status });
26964
26962
  }
@@ -27444,7 +27442,7 @@ function writeNodeDaemonInfo(port, startedAt) {
27444
27442
  stateDir: STATE_DIR,
27445
27443
  startedAt
27446
27444
  };
27447
- mkdirSync29(dirname18(NODE_DAEMON_INFO_PATH), { recursive: true });
27445
+ mkdirSync29(dirname17(NODE_DAEMON_INFO_PATH), { recursive: true });
27448
27446
  const temporary = `${NODE_DAEMON_INFO_PATH}.${process.pid}.${randomUUID26()}.tmp`;
27449
27447
  writeFileSync22(temporary, `${JSON.stringify(info, null, 2)}
27450
27448
  `, { mode: 384 });
@@ -29002,7 +29000,7 @@ var init_scheduler = __esm(async () => {
29002
29000
 
29003
29001
  // ../../packages/module-cron/src/module.ts
29004
29002
  import { existsSync as existsSync30 } from "fs";
29005
- import { fileURLToPath as fileURLToPath3 } from "url";
29003
+ import { fileURLToPath as fileURLToPath2 } from "url";
29006
29004
  function envMs(name, fallback) {
29007
29005
  const parsed = Number.parseInt(process.env[name] ?? "", 10);
29008
29006
  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
@@ -29127,8 +29125,8 @@ var init_module = __esm(async () => {
29127
29125
  init_scripts(),
29128
29126
  init_store()
29129
29127
  ]);
29130
- SOURCE_MCP_SERVER_FILE = fileURLToPath3(new URL("./mcp-server.ts", import.meta.url));
29131
- PACKAGED_MCP_SERVER_FILE = fileURLToPath3(new URL("./runtime/cron/mcp-server.ts", import.meta.url));
29128
+ SOURCE_MCP_SERVER_FILE = fileURLToPath2(new URL("./mcp-server.ts", import.meta.url));
29129
+ PACKAGED_MCP_SERVER_FILE = fileURLToPath2(new URL("./runtime/cron/mcp-server.ts", import.meta.url));
29132
29130
  });
29133
29131
 
29134
29132
  // ../../packages/module-cron/src/summarize.ts
@@ -29708,7 +29706,7 @@ var init_commands = __esm(() => {
29708
29706
  import { execFile as execFile3 } from "child_process";
29709
29707
  import { existsSync as existsSync31, readdirSync as readdirSync13, statSync as statSync16 } from "fs";
29710
29708
  import { homedir as homedir11 } from "os";
29711
- import { basename as basename11, dirname as dirname19, join as join39, sep as sep3 } from "path";
29709
+ import { basename as basename11, dirname as dirname18, join as join38, sep as sep3 } from "path";
29712
29710
  import { promisify as promisify3 } from "util";
29713
29711
  function indexRecursivePaths(files) {
29714
29712
  const paths = [];
@@ -29809,15 +29807,15 @@ function resolveFragment(frag) {
29809
29807
  else if (frag === "~/")
29810
29808
  path = home;
29811
29809
  else if (frag.startsWith("~/"))
29812
- path = join39(home, frag.slice(2));
29810
+ path = join38(home, frag.slice(2));
29813
29811
  else if (frag.startsWith("/"))
29814
29812
  path = frag;
29815
29813
  else
29816
- path = join39(home, frag);
29814
+ path = join38(home, frag);
29817
29815
  if (frag.endsWith("/") || frag === "" || frag === "~") {
29818
29816
  return { dir: path, prefix: "" };
29819
29817
  }
29820
- return { dir: dirname19(path), prefix: basename11(path) };
29818
+ return { dir: dirname18(path), prefix: basename11(path) };
29821
29819
  }
29822
29820
  function toToken(fullPath, isDir) {
29823
29821
  const home = homedir11();
@@ -29842,7 +29840,7 @@ function rankAndSlice(dir, candidates) {
29842
29840
  });
29843
29841
  return candidates.slice(0, MAX_SUGGESTIONS).map(({ relPath, isDir }) => ({
29844
29842
  label: `${relPath}${isDir ? "/" : ""}`,
29845
- value: toToken(join39(dir, relPath), isDir),
29843
+ value: toToken(join38(dir, relPath), isDir),
29846
29844
  isDir
29847
29845
  }));
29848
29846
  }
@@ -29921,7 +29919,7 @@ function pathSuggestions(lineText, col) {
29921
29919
  let isDir = entry.isDirectory();
29922
29920
  if (!isDir && entry.isSymbolicLink()) {
29923
29921
  try {
29924
- isDir = statSync16(join39(dir, entry.name)).isDirectory();
29922
+ isDir = statSync16(join38(dir, entry.name)).isDirectory();
29925
29923
  } catch {}
29926
29924
  }
29927
29925
  return {
@@ -29948,10 +29946,10 @@ function fragmentToAbsolutePath(frag) {
29948
29946
  if (frag === "~" || frag === "~/")
29949
29947
  return home;
29950
29948
  if (frag.startsWith("~/"))
29951
- return join39(home, frag.slice(2));
29949
+ return join38(home, frag.slice(2));
29952
29950
  if (frag.startsWith("/"))
29953
29951
  return frag;
29954
- return join39(home, frag);
29952
+ return join38(home, frag);
29955
29953
  }
29956
29954
  function fragmentResolves(frag) {
29957
29955
  try {
@@ -36825,7 +36823,7 @@ var init_commands2 = __esm(async () => {
36825
36823
  // ../../adapters/telegram/src/mapping-store.ts
36826
36824
  import { Database as Database2 } from "bun:sqlite";
36827
36825
  import { mkdirSync as mkdirSync31 } from "fs";
36828
- import { dirname as dirname20, join as join40 } from "path";
36826
+ import { dirname as dirname19, join as join39 } from "path";
36829
36827
  function outboxRowToEntry(row) {
36830
36828
  return {
36831
36829
  id: row.id,
@@ -36891,9 +36889,9 @@ function migrateOutboxSchema(db4) {
36891
36889
  db4.run("CREATE INDEX IF NOT EXISTS idx_telegram_outbox_runtime_message ON outbox(runtime_message_id)");
36892
36890
  }
36893
36891
  function openMappingStore(path) {
36894
- const dbPath = path ?? join40(DATA_DIR, "adapter-telegram.db");
36892
+ const dbPath = path ?? join39(DATA_DIR, "adapter-telegram.db");
36895
36893
  if (dbPath !== ":memory:")
36896
- mkdirSync31(dirname20(dbPath), { recursive: true });
36894
+ mkdirSync31(dirname19(dbPath), { recursive: true });
36897
36895
  const db4 = new Database2(dbPath);
36898
36896
  migrateLegacySchema(db4);
36899
36897
  createTables(db4);
@@ -38754,8 +38752,8 @@ __export(exports_central, {
38754
38752
  listPeerNodes: () => listPeerNodes,
38755
38753
  configureOtiumCentral: () => configureOtiumCentral
38756
38754
  });
38757
- function configureOtiumCentral(join41) {
38758
- joinConfig = join41;
38755
+ function configureOtiumCentral(join40) {
38756
+ joinConfig = join40;
38759
38757
  resetPeerCentralCaches();
38760
38758
  }
38761
38759
  function otiumCentralConfig() {
@@ -38925,7 +38923,7 @@ import {
38925
38923
  unlinkSync as unlinkSync22,
38926
38924
  writeFileSync as writeFileSync23
38927
38925
  } from "fs";
38928
- import { dirname as dirname21, resolve as resolve22 } from "path";
38926
+ import { dirname as dirname20, resolve as resolve22 } from "path";
38929
38927
  function joinFilePath() {
38930
38928
  return resolve22(DATA_DIR, "otium-join.json");
38931
38929
  }
@@ -38998,7 +38996,7 @@ function withJoinCredentialLock(operation) {
38998
38996
  const lockPath = joinLockPath();
38999
38997
  const ownerPath = resolve22(lockPath, "owner.json");
39000
38998
  const owner = { pid: process.pid, token: randomUUID28() };
39001
- mkdirSync32(dirname21(lockPath), { recursive: true });
38999
+ mkdirSync32(dirname20(lockPath), { recursive: true });
39002
39000
  for (let attempt = 0;; attempt += 1) {
39003
39001
  let created = false;
39004
39002
  try {
@@ -39062,17 +39060,17 @@ function withJoinCredentialLock(operation) {
39062
39060
  function joinsEqual(left, right) {
39063
39061
  return left.central === right.central && left.relay === right.relay && left.cellId === right.cellId && left.secret === right.secret;
39064
39062
  }
39065
- function normalizedJoin(join41) {
39063
+ function normalizedJoin(join40) {
39066
39064
  return normalizeJoin({
39067
- v: join41.v,
39068
- central: join41.central,
39069
- relay: join41.relay,
39070
- cellId: join41.cellId,
39071
- secret: join41.secret
39065
+ v: join40.v,
39066
+ central: join40.central,
39067
+ relay: join40.relay,
39068
+ cellId: join40.cellId,
39069
+ secret: join40.secret
39072
39070
  });
39073
39071
  }
39074
- function joinCredentialDigest(join41) {
39075
- return createHash9("sha256").update(JSON.stringify(normalizedJoin(join41))).digest("base64url");
39072
+ function joinCredentialDigest(join40) {
39073
+ return createHash9("sha256").update(JSON.stringify(normalizedJoin(join40))).digest("base64url");
39076
39074
  }
39077
39075
  function readPersistedJoin(path = joinFilePath()) {
39078
39076
  if (!existsSync33(path))
@@ -39083,18 +39081,18 @@ function readPersistedJoin(path = joinFilePath()) {
39083
39081
  }
39084
39082
  return normalizeJoin(parsed);
39085
39083
  }
39086
- function isJoinPersisted(join41) {
39084
+ function isJoinPersisted(join40) {
39087
39085
  try {
39088
39086
  const persisted = readPersistedJoin();
39089
- return persisted !== null && joinsEqual(persisted, normalizedJoin(join41));
39087
+ return persisted !== null && joinsEqual(persisted, normalizedJoin(join40));
39090
39088
  } catch {
39091
39089
  return false;
39092
39090
  }
39093
39091
  }
39094
- function saveJoinWhileLocked(join41, options = {}) {
39092
+ function saveJoinWhileLocked(join40, options = {}) {
39095
39093
  const path = joinFilePath();
39096
- const directory = dirname21(path);
39097
- const normalized = normalizedJoin(join41);
39094
+ const directory = dirname20(path);
39095
+ const normalized = normalizedJoin(join40);
39098
39096
  mkdirSync32(directory, { recursive: true });
39099
39097
  if (existsSync33(path)) {
39100
39098
  if (lstatSync(path).isSymbolicLink()) {
@@ -39159,8 +39157,8 @@ function saveJoinWhileLocked(join41, options = {}) {
39159
39157
  }
39160
39158
  return path;
39161
39159
  }
39162
- function saveJoin(join41, options = {}) {
39163
- return withJoinCredentialLock(() => saveJoinWhileLocked(join41, options));
39160
+ function saveJoin(join40, options = {}) {
39161
+ return withJoinCredentialLock(() => saveJoinWhileLocked(join40, options));
39164
39162
  }
39165
39163
  function removeJoin() {
39166
39164
  return withJoinCredentialLock(() => {
@@ -39171,7 +39169,7 @@ function removeJoin() {
39171
39169
  throw new Error(`refusing to remove symlinked Otium join file at ${path}`);
39172
39170
  }
39173
39171
  unlinkSync22(path);
39174
- const directoryFd = openSync4(dirname21(path), "r");
39172
+ const directoryFd = openSync4(dirname20(path), "r");
39175
39173
  try {
39176
39174
  fsyncSync2(directoryFd);
39177
39175
  } finally {
@@ -40178,7 +40176,7 @@ var init_event_backflow = __esm(async () => {
40178
40176
  // ../../adapters/otium/src/peer-files.ts
40179
40177
  import { randomUUID as randomUUID30 } from "crypto";
40180
40178
  import { copyFileSync as copyFileSync5, mkdirSync as mkdirSync33, rmSync as rmSync10, statSync as statSync18 } from "fs";
40181
- import { basename as basename13, extname as extname5, join as join41 } from "path";
40179
+ import { basename as basename13, extname as extname5, join as join40 } from "path";
40182
40180
  function fileType(mimeType) {
40183
40181
  if (mimeType.startsWith("image/"))
40184
40182
  return "image";
@@ -40248,7 +40246,7 @@ function recordFile(args) {
40248
40246
  function insertLocalFile(args) {
40249
40247
  const id = randomUUID30();
40250
40248
  mkdirSync33(PEER_FILES_DIR, { recursive: true });
40251
- const path = join41(PEER_FILES_DIR, `${id}-${safeFilename(args.filename)}`);
40249
+ const path = join40(PEER_FILES_DIR, `${id}-${safeFilename(args.filename)}`);
40252
40250
  copyFileSync5(args.sourcePath, path);
40253
40251
  return recordFile({ id, path, sizeBytes: statSync18(path).size, ...args });
40254
40252
  }
@@ -40262,7 +40260,7 @@ async function storePeerInputFile(file, access) {
40262
40260
  const id = randomUUID30();
40263
40261
  mkdirSync33(PEER_FILES_DIR, { recursive: true });
40264
40262
  const filename = file.name || "upload";
40265
- const path = join41(PEER_FILES_DIR, `${id}-${safeFilename(filename)}`);
40263
+ const path = join40(PEER_FILES_DIR, `${id}-${safeFilename(filename)}`);
40266
40264
  const sizeBytes = await Bun.write(path, file);
40267
40265
  return recordFile({
40268
40266
  id,
@@ -40309,7 +40307,7 @@ function installPeerFileHooks() {
40309
40307
  var PEER_FILES_DIR;
40310
40308
  var init_peer_files = __esm(async () => {
40311
40309
  await init_src();
40312
- PEER_FILES_DIR = join41(DATA_DIR, "otium-peer-files");
40310
+ PEER_FILES_DIR = join40(DATA_DIR, "otium-peer-files");
40313
40311
  db.exec(`
40314
40312
  CREATE TABLE IF NOT EXISTS otium_peer_files (
40315
40313
  id TEXT PRIMARY KEY,
@@ -41013,7 +41011,7 @@ function messageEnvelope(message) {
41013
41011
  ...message.kind ? { kind: message.kind } : {}
41014
41012
  };
41015
41013
  }
41016
- async function publishTopic(join42, topicId, node) {
41014
+ async function publishTopic(join41, topicId, node) {
41017
41015
  const topic = getTopic(topicId);
41018
41016
  if (!topic || topic.kind !== "agent" || !topic.agent || !isTopicShared(topic) || !topic.visibility || topic.visibility === "hidden" || isMirrorTopic(topicId))
41019
41017
  return;
@@ -41061,10 +41059,10 @@ async function publishTopic(join42, topicId, node) {
41061
41059
  }
41062
41060
  } catch (error2) {
41063
41061
  logger.warn({ error: error2, topicId }, "otium: shared topic publish deferred");
41064
- setTimeout(() => void reconcileTopic(join42, topicId), RETRY_MS).unref?.();
41062
+ setTimeout(() => void reconcileTopic(join41, topicId), RETRY_MS).unref?.();
41065
41063
  }
41066
41064
  }
41067
- async function unpublishTopic(join42, topicId, node) {
41065
+ async function unpublishTopic(join41, topicId, node) {
41068
41066
  const state2 = getSharedTopicState(topicId);
41069
41067
  if (!state2)
41070
41068
  return;
@@ -41080,26 +41078,26 @@ async function unpublishTopic(join42, topicId, node) {
41080
41078
  deleteSharedTopicState(topicId);
41081
41079
  } catch (error2) {
41082
41080
  logger.warn({ error: error2, topicId }, "otium: shared topic unpublish deferred");
41083
- setTimeout(() => void reconcileTopic(join42, topicId), RETRY_MS).unref?.();
41081
+ setTimeout(() => void reconcileTopic(join41, topicId), RETRY_MS).unref?.();
41084
41082
  }
41085
41083
  }
41086
- async function reconcileTopic(join42, topicId, explicit = false) {
41084
+ async function reconcileTopic(join41, topicId, explicit = false) {
41087
41085
  if (!otiumCentralConfig())
41088
41086
  return;
41089
- if (!explicit && isPeerDetached(join42.cellId))
41087
+ if (!explicit && isPeerDetached(join41.cellId))
41090
41088
  return;
41091
41089
  const target = (await listPeerNodes()).find((node) => node.isPrimary) ?? null;
41092
41090
  if (!target)
41093
41091
  return;
41094
41092
  const topic = getTopic(topicId);
41095
41093
  if (topic?.kind === "agent" && topic.agent && isTopicShared(topic) && topic.visibility !== "hidden" && !isMirrorTopic(topicId))
41096
- return publishTopic(join42, topicId, target);
41097
- return unpublishTopic(join42, topicId, target);
41094
+ return publishTopic(join41, topicId, target);
41095
+ return unpublishTopic(join41, topicId, target);
41098
41096
  }
41099
- function disconnectSharedTopics(join42) {
41097
+ function disconnectSharedTopics(join41) {
41100
41098
  const states = listSharedTopicStates();
41101
41099
  const hubPromise = listPeerNodes({ fresh: true }).then((nodes) => nodes.find((node) => node.isPrimary) ?? null, () => null);
41102
- const updated = downgradeSharedTopicsLocally(join42.cellId);
41100
+ const updated = downgradeSharedTopicsLocally(join41.cellId);
41103
41101
  for (const topicId of updated)
41104
41102
  WsHub.get().broadcastTopicUpdated(topicId);
41105
41103
  const deletions = states.map(async (state2) => {
@@ -41122,16 +41120,16 @@ function downgradeSharedTopicsForHub(hubNodeId) {
41122
41120
  WsHub.get().broadcastTopicUpdated(topicId);
41123
41121
  return updated.length;
41124
41122
  }
41125
- async function checkPeerAttachment(join42) {
41123
+ async function checkPeerAttachment(join41) {
41126
41124
  const nodes = await listPeerNodes({ fresh: true });
41127
- if (nodes.some((node) => node.cellId === join42.cellId))
41125
+ if (nodes.some((node) => node.cellId === join41.cellId))
41128
41126
  return true;
41129
- downgradeSharedTopicsForHub(join42.cellId);
41127
+ downgradeSharedTopicsForHub(join41.cellId);
41130
41128
  return false;
41131
41129
  }
41132
- function startSharedTopicSync(join42) {
41130
+ function startSharedTopicSync(join41) {
41133
41131
  let stopped = false;
41134
- let detached = isPeerDetached(join42.cellId);
41132
+ let detached = isPeerDetached(join41.cellId);
41135
41133
  const queue = new Set;
41136
41134
  const schedule = (topicId, explicit = false) => {
41137
41135
  if (stopped || queue.has(topicId))
@@ -41140,7 +41138,7 @@ function startSharedTopicSync(join42) {
41140
41138
  queueMicrotask(async () => {
41141
41139
  queue.delete(topicId);
41142
41140
  try {
41143
- await reconcileTopic(join42, topicId, explicit);
41141
+ await reconcileTopic(join41, topicId, explicit);
41144
41142
  } catch (error2) {
41145
41143
  logger.warn({ error: error2, topicId }, "otium: shared topic reconciliation failed");
41146
41144
  }
@@ -41154,7 +41152,7 @@ function startSharedTopicSync(join42) {
41154
41152
  if (stopped || detached)
41155
41153
  return;
41156
41154
  try {
41157
- if (!await checkPeerAttachment(join42))
41155
+ if (!await checkPeerAttachment(join41))
41158
41156
  detached = true;
41159
41157
  } catch {}
41160
41158
  }, 30000);
@@ -41166,7 +41164,7 @@ function startSharedTopicSync(join42) {
41166
41164
  const message = event.payload;
41167
41165
  if (!message.sourceNode) {
41168
41166
  schedule(event.topicId);
41169
- forwardSharedTopicMessage(join42, message).catch((error2) => logger.warn({ error: error2, topicId: event.topicId }, "otium: shared message deferred"));
41167
+ forwardSharedTopicMessage(join41, message).catch((error2) => logger.warn({ error: error2, topicId: event.topicId }, "otium: shared message deferred"));
41170
41168
  }
41171
41169
  }
41172
41170
  });
@@ -41928,7 +41926,7 @@ import {
41928
41926
  unlinkSync as unlinkSync23,
41929
41927
  writeFileSync as writeFileSync24
41930
41928
  } from "fs";
41931
- import { dirname as dirname22, resolve as resolve24 } from "path";
41929
+ import { dirname as dirname21, resolve as resolve24 } from "path";
41932
41930
  function parseEnrollmentInvite(code) {
41933
41931
  let parsed;
41934
41932
  try {
@@ -41978,8 +41976,8 @@ function loadOrCreatePending(invite, nodeName) {
41978
41976
  publicKey: pair.publicKey.export({ format: "der", type: "spki" }).toString("base64url"),
41979
41977
  ...nodeName ? { nodeName } : {}
41980
41978
  };
41981
- mkdirSync34(dirname22(path), { recursive: true });
41982
- const temporaryPath = resolve24(dirname22(path), `.otium-enrollment-pending.json.${process.pid}.${randomUUID32()}.tmp`);
41979
+ mkdirSync34(dirname21(path), { recursive: true });
41980
+ const temporaryPath = resolve24(dirname21(path), `.otium-enrollment-pending.json.${process.pid}.${randomUUID32()}.tmp`);
41983
41981
  let fd;
41984
41982
  try {
41985
41983
  fd = openSync5(temporaryPath, "wx", 384);
@@ -41991,7 +41989,7 @@ function loadOrCreatePending(invite, nodeName) {
41991
41989
  linkSync2(temporaryPath, path);
41992
41990
  unlinkSync23(temporaryPath);
41993
41991
  chmodSync7(path, 384);
41994
- const directoryFd = openSync5(dirname22(path), "r");
41992
+ const directoryFd = openSync5(dirname21(path), "r");
41995
41993
  try {
41996
41994
  fsyncSync3(directoryFd);
41997
41995
  } finally {
@@ -42013,7 +42011,7 @@ function loadOrCreatePending(invite, nodeName) {
42013
42011
  }
42014
42012
  function replacePendingEnrollment(pending2) {
42015
42013
  const path = pendingEnrollmentPath();
42016
- const directory = dirname22(path);
42014
+ const directory = dirname21(path);
42017
42015
  const temporaryPath = resolve24(directory, `.otium-enrollment-pending.json.${process.pid}.${randomUUID32()}.tmp`);
42018
42016
  let fd;
42019
42017
  try {
@@ -42038,13 +42036,13 @@ function replacePendingEnrollment(pending2) {
42038
42036
  throw error2;
42039
42037
  }
42040
42038
  }
42041
- function recordClaimedCredential(pending2, join42) {
42039
+ function recordClaimedCredential(pending2, join41) {
42042
42040
  withJoinCredentialLock(() => {
42043
42041
  const current3 = JSON.parse(readFileSync26(pendingEnrollmentPath(), "utf8"));
42044
42042
  if (current3.central !== pending2.central || current3.token !== pending2.token || current3.idempotencyKey !== pending2.idempotencyKey || current3.publicKey !== pending2.publicKey) {
42045
42043
  throw new Error("pending Otium enrollment changed while its claim was in flight");
42046
42044
  }
42047
- const claimed = { digest: joinCredentialDigest(join42), cellId: join42.cellId };
42045
+ const claimed = { digest: joinCredentialDigest(join41), cellId: join41.cellId };
42048
42046
  if (current3.claimed && (current3.claimed.digest !== claimed.digest || current3.claimed.cellId !== claimed.cellId)) {
42049
42047
  throw new Error("central returned different credentials for an idempotent enrollment claim");
42050
42048
  }
@@ -42102,36 +42100,36 @@ async function claimEnrollment(invite, nodeName) {
42102
42100
  const secret = openCredential(credential, pending2.privateKey);
42103
42101
  if (!secret.startsWith("rcs_"))
42104
42102
  throw new Error("central returned an invalid runtime credential");
42105
- const join42 = {
42103
+ const join41 = {
42106
42104
  v: 2,
42107
42105
  central: invite.central,
42108
42106
  relay: String(response.relayUrl),
42109
42107
  cellId: String(response.cell?.id),
42110
42108
  secret
42111
42109
  };
42112
- if (!join42.relay || !join42.cellId || join42.cellId === "undefined") {
42110
+ if (!join41.relay || !join41.cellId || join41.cellId === "undefined") {
42113
42111
  throw new Error("central returned an incomplete enrollment response");
42114
42112
  }
42115
- assertSecureRelayUrl(join42.relay);
42116
- recordClaimedCredential(pending2, join42);
42117
- return join42;
42113
+ assertSecureRelayUrl(join41.relay);
42114
+ recordClaimedCredential(pending2, join41);
42115
+ return join41;
42118
42116
  }
42119
- function commitEnrollment(join42, options = {}) {
42117
+ function commitEnrollment(join41, options = {}) {
42120
42118
  return withJoinCredentialLock(() => {
42121
42119
  const pendingPath = pendingEnrollmentPath();
42122
42120
  const pending2 = existsSync35(pendingPath) ? JSON.parse(readFileSync26(pendingPath, "utf8")) : null;
42123
- const digest = joinCredentialDigest(join42);
42124
- if (pending2 && (!pending2.claimed || pending2.claimed.digest !== digest || pending2.claimed.cellId !== join42.cellId)) {
42121
+ const digest = joinCredentialDigest(join41);
42122
+ if (pending2 && (!pending2.claimed || pending2.claimed.digest !== digest || pending2.claimed.cellId !== join41.cellId)) {
42125
42123
  throw new Error(`pending Otium enrollment at ${pendingPath} does not match these credentials`);
42126
42124
  }
42127
- const path = saveJoinWhileLocked(join42, options);
42128
- if (!isJoinPersisted(join42)) {
42125
+ const path = saveJoinWhileLocked(join41, options);
42126
+ if (!isJoinPersisted(join41)) {
42129
42127
  throw new Error("Otium join credentials were not durably persisted");
42130
42128
  }
42131
42129
  if (!pending2)
42132
42130
  return path;
42133
42131
  unlinkSync23(pendingPath);
42134
- const directoryFd = openSync5(dirname22(pendingPath), "r");
42132
+ const directoryFd = openSync5(dirname21(pendingPath), "r");
42135
42133
  try {
42136
42134
  fsyncSync3(directoryFd);
42137
42135
  } finally {
@@ -43016,14 +43014,14 @@ var init_peer_server = __esm(async () => {
43016
43014
 
43017
43015
  // ../../adapters/otium/src/index.ts
43018
43016
  function startOtiumNodeRuntime(options) {
43019
- const { join: join42 } = options;
43020
- configureOtiumCentral(join42);
43017
+ const { join: join41 } = options;
43018
+ configureOtiumCentral(join41);
43021
43019
  const failed = failInterruptedPeerTurnRequestsOnStartup();
43022
43020
  if (failed > 0) {
43023
43021
  logger.warn({ failed }, "otium: failed interrupted peer turns from previous process");
43024
43022
  }
43025
43023
  const stopBackflow = startEventBackflow();
43026
- const stopSharedTopicSync = startSharedTopicSync(join42);
43024
+ const stopSharedTopicSync = startSharedTopicSync(join41);
43027
43025
  const unregisterRuntimeBridge = registerPeerRuntimeBridge(otiumPeerRuntimeBridge);
43028
43026
  const unregisterSessionBridge = registerPeerSessionBridge(otiumPeerSessionBridge);
43029
43027
  const sessionBridgeIpc = startPeerSessionBridgeIpc(otiumPeerSessionBridge);
@@ -43044,7 +43042,7 @@ function startOtiumNodeRuntime(options) {
43044
43042
  }
43045
43043
  });
43046
43044
  let stopped = false;
43047
- logger.info({ central: join42.central, cellId: join42.cellId }, "otium: worker mode enabled");
43045
+ logger.info({ central: join41.central, cellId: join41.cellId }, "otium: worker mode enabled");
43048
43046
  selfPeerNode().then((self) => {
43049
43047
  if (self) {
43050
43048
  logger.info({ nodeName: self.nodeName, baseUrl: self.baseUrl }, "otium: attached to workspace");
@@ -43054,7 +43052,7 @@ function startOtiumNodeRuntime(options) {
43054
43052
  });
43055
43053
  return {
43056
43054
  name: "otium",
43057
- join: join42,
43055
+ join: join41,
43058
43056
  stop: () => {
43059
43057
  if (stopped)
43060
43058
  return;
@@ -43176,10 +43174,10 @@ async function handleOtiumAdapterControlRequest(req) {
43176
43174
  return await handleOtiumPeerRequest(new Request(peerUrl.toString(), { method: req.method, headers, body, signal: req.signal })) ?? Response.json({ ok: false, error: "Otium route not found" }, { status: 404 });
43177
43175
  }
43178
43176
  function mountConfiguredOtiumNodeRuntime() {
43179
- const join42 = loadJoin();
43180
- if (!join42)
43177
+ const join41 = loadJoin();
43178
+ if (!join41)
43181
43179
  return null;
43182
- const runtime2 = startOtiumNodeRuntime({ join: join42 });
43180
+ const runtime2 = startOtiumNodeRuntime({ join: join41 });
43183
43181
  registerNodeRequestHandler("otium-adapter-control", handleOtiumAdapterControlRequest);
43184
43182
  let stopped = false;
43185
43183
  return {
@@ -43230,11 +43228,11 @@ async function joinCommand(args) {
43230
43228
  process.exitCode = 1;
43231
43229
  return;
43232
43230
  }
43233
- let join42;
43231
+ let join41;
43234
43232
  let productionEnrollment = false;
43235
43233
  if (args.includes("--legacy")) {
43236
43234
  try {
43237
- join42 = parseInviteCode(code);
43235
+ join41 = parseInviteCode(code);
43238
43236
  } catch (err2) {
43239
43237
  console.error(`invalid legacy invite code: ${err2 instanceof Error ? err2.message : err2}`);
43240
43238
  process.exitCode = 1;
@@ -43261,7 +43259,7 @@ async function joinCommand(args) {
43261
43259
  return;
43262
43260
  }
43263
43261
  }
43264
- join42 = await claimEnrollment(invite, nodeName);
43262
+ join41 = await claimEnrollment(invite, nodeName);
43265
43263
  productionEnrollment = true;
43266
43264
  } catch (err2) {
43267
43265
  console.error(`enrollment failed: ${err2 instanceof Error ? err2.message : err2}`);
@@ -43272,16 +43270,16 @@ async function joinCommand(args) {
43272
43270
  let path;
43273
43271
  try {
43274
43272
  const saveOptions = { replaceExisting: args.includes("--replace") };
43275
- path = productionEnrollment ? commitEnrollment(join42, saveOptions) : saveJoin(join42, saveOptions);
43273
+ path = productionEnrollment ? commitEnrollment(join41, saveOptions) : saveJoin(join41, saveOptions);
43276
43274
  } catch (err2) {
43277
43275
  console.error(`could not save join credentials: ${err2 instanceof Error ? err2.message : err2}`);
43278
43276
  process.exitCode = 1;
43279
43277
  return;
43280
43278
  }
43281
43279
  console.log(`otium join credentials saved to ${path}`);
43282
- console.log(` central: ${join42.central}`);
43283
- console.log(` cellId: ${join42.cellId}`);
43284
- configureOtiumCentral(join42);
43280
+ console.log(` central: ${join41.central}`);
43281
+ console.log(` cellId: ${join41.cellId}`);
43282
+ configureOtiumCentral(join41);
43285
43283
  try {
43286
43284
  const self = await selfPeerNode();
43287
43285
  if (self) {
@@ -43336,8 +43334,8 @@ async function proxyOtiumPeerRequest(req, dependencies = {}) {
43336
43334
  }
43337
43335
  }
43338
43336
  async function runOtiumSidecar(options) {
43339
- const join42 = loadJoin();
43340
- if (!join42) {
43337
+ const join41 = loadJoin();
43338
+ if (!join41) {
43341
43339
  throw new Error("not joined to an Otium workspace \u2014 run `negotium otium join <code>` first");
43342
43340
  }
43343
43341
  const initialNode = await inspectNodeDaemon();
@@ -43369,10 +43367,10 @@ async function runOtiumSidecar(options) {
43369
43367
  lease.stop();
43370
43368
  throw error2;
43371
43369
  }
43372
- const selectedRelay = options.relayUrl?.trim() || join42.relay || process.env.OTIUM_RELAY_URL?.trim();
43370
+ const selectedRelay = options.relayUrl?.trim() || join41.relay || process.env.OTIUM_RELAY_URL?.trim();
43373
43371
  const tunnel = selectedRelay ? new TunnelClient({
43374
43372
  relayUrl: selectedRelay,
43375
- token: join42.secret,
43373
+ token: join41.secret,
43376
43374
  targetOrigin: `http://127.0.0.1:${server.port}`,
43377
43375
  nodeVersion: `negotium@${NEGOTIUM_VERSION}`,
43378
43376
  logger
@@ -43463,10 +43461,10 @@ async function resolveHostNodeId(explicit) {
43463
43461
  init_central().then(() => exports_central),
43464
43462
  init_join().then(() => exports_join)
43465
43463
  ]);
43466
- const join42 = loadJoin2();
43467
- if (!join42)
43464
+ const join41 = loadJoin2();
43465
+ if (!join41)
43468
43466
  throw new Error("not joined to an Otium workspace; pass --host-node or join first");
43469
- configureOtiumCentral2(join42);
43467
+ configureOtiumCentral2(join41);
43470
43468
  try {
43471
43469
  const nodes = await listPeerNodes2({ fresh: true });
43472
43470
  const primary = nodes.find((node) => node.isPrimary && !node.self) ?? nodes.find((node) => node.isPrimary);
@@ -43535,12 +43533,12 @@ async function runOtiumCli(args = process.argv.slice(2)) {
43535
43533
  const { configureOtiumCentral: configureOtiumCentral2 } = await init_central().then(() => exports_central);
43536
43534
  const { loadJoin: loadJoin2, removeJoin: removeJoin2 } = await init_join().then(() => exports_join);
43537
43535
  const { disconnectSharedTopics: disconnectSharedTopics2 } = await init_shared_topic_sync().then(() => exports_shared_topic_sync);
43538
- const join42 = loadJoin2();
43539
- if (!join42)
43536
+ const join41 = loadJoin2();
43537
+ if (!join41)
43540
43538
  throw new Error("not joined to an Otium workspace");
43541
- configureOtiumCentral2(join42);
43539
+ configureOtiumCentral2(join41);
43542
43540
  try {
43543
- await disconnectSharedTopics2(join42);
43541
+ await disconnectSharedTopics2(join41);
43544
43542
  removeJoin2();
43545
43543
  } finally {
43546
43544
  configureOtiumCentral2(null);
@@ -43650,620 +43648,6 @@ var init_init = __esm(async () => {
43650
43648
  await init_src();
43651
43649
  });
43652
43650
 
43653
- // ../../packages/core/src/migration/single-user.ts
43654
- import { createHash as createHash11, randomUUID as randomUUID34 } from "crypto";
43655
- import {
43656
- chmodSync as chmodSync8,
43657
- copyFileSync as copyFileSync6,
43658
- existsSync as existsSync36,
43659
- mkdirSync as mkdirSync35,
43660
- readdirSync as readdirSync14,
43661
- readFileSync as readFileSync27,
43662
- renameSync as renameSync16,
43663
- rmSync as rmSync11,
43664
- statSync as statSync19,
43665
- writeFileSync as writeFileSync25
43666
- } from "fs";
43667
- import { homedir as homedir12 } from "os";
43668
- import { basename as basename14, dirname as dirname23, join as join42, resolve as resolve25 } from "path";
43669
- function entries(path) {
43670
- return existsSync36(path) && statSync19(path).isDirectory() ? readdirSync14(path) : [];
43671
- }
43672
- function processIsAlive2(pid) {
43673
- if (!Number.isInteger(pid) || pid <= 0)
43674
- return false;
43675
- try {
43676
- process.kill(pid, 0);
43677
- return true;
43678
- } catch (error2) {
43679
- return error2.code === "EPERM";
43680
- }
43681
- }
43682
- function assertNoActiveNode(stateDir2) {
43683
- for (const runtimeName of ["run", "runtime"]) {
43684
- const infoPath = join42(stateDir2, runtimeName, "node-daemon.json");
43685
- if (!existsSync36(infoPath))
43686
- continue;
43687
- try {
43688
- const value = JSON.parse(readFileSync27(infoPath, "utf8"));
43689
- if (typeof value.pid === "number" && processIsAlive2(value.pid)) {
43690
- throw new Error(`Refusing migration while Negotium pid ${value.pid} is active.`);
43691
- }
43692
- } catch (error2) {
43693
- if (error2 instanceof SyntaxError) {
43694
- throw new Error(`Refusing migration: unreadable process metadata at ${infoPath}.`);
43695
- }
43696
- throw error2;
43697
- }
43698
- }
43699
- const dbPath = join42(stateDir2, "data", "sessions.db");
43700
- if (!existsSync36(dbPath))
43701
- return;
43702
- const database = new Database(dbPath, { readonly: true });
43703
- try {
43704
- const hasLeases = database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='runtime_process_leases'").get();
43705
- if (!hasLeases)
43706
- return;
43707
- const leases = database.query("SELECT role, pid FROM runtime_process_leases").all();
43708
- const active2 = leases.find((lease) => processIsAlive2(lease.pid));
43709
- if (active2)
43710
- throw new Error(`Refusing migration while ${active2.role} pid ${active2.pid} is active.`);
43711
- } finally {
43712
- database.close();
43713
- }
43714
- }
43715
- function oldOwnerDirectory(ownerId) {
43716
- const digest = createHash11("sha256").update(ownerId).digest("hex").slice(0, 16);
43717
- return `${sanitizeTopicName(ownerId).slice(0, 24)}_${digest}`;
43718
- }
43719
- function addDirectoryContents(operations, sourceDir, destinationDir, stagingDir) {
43720
- for (const name of entries(sourceDir)) {
43721
- operations.push({
43722
- source: join42(sourceDir, name),
43723
- staged: join42(stagingDir, randomUUID34()),
43724
- ...destinationDir ? { destination: join42(destinationDir, name) } : {},
43725
- state: "pending"
43726
- });
43727
- }
43728
- }
43729
- function pathWithin(path, root) {
43730
- return path === root || path.startsWith(`${root}/`);
43731
- }
43732
- function collisionPolicy(operation, stateDir2) {
43733
- const destination = operation.destination;
43734
- if (!destination || !existsSync36(destination))
43735
- return;
43736
- if (pathWithin(destination, join42(stateDir2, "runtime")))
43737
- return "keep-destination";
43738
- if (pathWithin(destination, join42(stateDir2, "binaries")))
43739
- return "keep-destination";
43740
- if (pathWithin(destination, join42(stateDir2, "secrets")))
43741
- return "replace-destination";
43742
- if (destination === join42(stateDir2, "data", "vault", "vault.db")) {
43743
- return "replace-destination";
43744
- }
43745
- if (pathWithin(destination, join42(stateDir2, "browser", "profiles"))) {
43746
- return "replace-destination";
43747
- }
43748
- if (pathWithin(destination, join42(stateDir2, "data", "conversations")) && destination.endsWith(".jsonl")) {
43749
- return "merge-jsonl";
43750
- }
43751
- if (pathWithin(destination, join42(stateDir2, "data", "tasks")) && destination.endsWith(".json")) {
43752
- return "merge-tasks";
43753
- }
43754
- if (statSync19(operation.source).isFile() && statSync19(destination).isFile() && readFileSync27(operation.source).equals(readFileSync27(destination))) {
43755
- return "keep-destination";
43756
- }
43757
- throw new Error(`Migration collision at ${destination}.`);
43758
- }
43759
- function configureCollisions(operations, stateDir2, stagingRoot) {
43760
- const destinations = new Set;
43761
- for (const operation of operations) {
43762
- if (!operation.destination)
43763
- continue;
43764
- if (destinations.has(operation.destination)) {
43765
- throw new Error(`Multiple legacy paths target ${operation.destination}.`);
43766
- }
43767
- destinations.add(operation.destination);
43768
- operation.collision = collisionPolicy(operation, stateDir2);
43769
- if (operation.collision && operation.collision !== "keep-destination") {
43770
- operation.destinationStaged = join42(stagingRoot, randomUUID34());
43771
- }
43772
- }
43773
- }
43774
- function writeJournal(path, journal) {
43775
- writeFileSync25(path, `${JSON.stringify(journal, null, 2)}
43776
- `, { mode: 384 });
43777
- }
43778
- function rollbackFilesystem(journal, journalPath) {
43779
- for (const operation of [...journal.operations].reverse()) {
43780
- if (operation.state === "placed") {
43781
- if (operation.collision === "keep-destination" || !operation.destination) {
43782
- if (existsSync36(operation.staged) && !existsSync36(operation.source)) {
43783
- mkdirSync35(dirname23(operation.source), { recursive: true });
43784
- renameSync16(operation.staged, operation.source);
43785
- }
43786
- } else if (operation.destination && existsSync36(operation.destination)) {
43787
- if (operation.collision === "merge-jsonl" || operation.collision === "merge-tasks") {
43788
- rmSync11(operation.destination, { recursive: true, force: true });
43789
- if (existsSync36(operation.staged) && !existsSync36(operation.source)) {
43790
- mkdirSync35(dirname23(operation.source), { recursive: true });
43791
- renameSync16(operation.staged, operation.source);
43792
- }
43793
- } else if (!existsSync36(operation.source)) {
43794
- mkdirSync35(dirname23(operation.source), { recursive: true });
43795
- renameSync16(operation.destination, operation.source);
43796
- }
43797
- }
43798
- } else if (existsSync36(operation.staged) && !existsSync36(operation.source)) {
43799
- mkdirSync35(dirname23(operation.source), { recursive: true });
43800
- renameSync16(operation.staged, operation.source);
43801
- }
43802
- if (operation.destination && operation.destinationStaged && existsSync36(operation.destinationStaged) && !existsSync36(operation.destination)) {
43803
- mkdirSync35(dirname23(operation.destination), { recursive: true });
43804
- renameSync16(operation.destinationStaged, operation.destination);
43805
- }
43806
- operation.state = "pending";
43807
- }
43808
- journal.phase = "filesystem";
43809
- writeJournal(journalPath, journal);
43810
- }
43811
- function mergedJsonl(source, destination) {
43812
- const lines = new Set;
43813
- for (const path of [source, destination]) {
43814
- for (const line2 of readFileSync27(path, "utf8").split(/\r?\n/)) {
43815
- if (line2)
43816
- lines.add(line2);
43817
- }
43818
- }
43819
- return lines.size > 0 ? `${[...lines].join(`
43820
- `)}
43821
- ` : "";
43822
- }
43823
- function readTaskFile(path) {
43824
- const parsed = JSON.parse(readFileSync27(path, "utf8"));
43825
- if (parsed.version !== 1 || !Array.isArray(parsed.tasks)) {
43826
- throw new Error(`Invalid task file during migration: ${path}`);
43827
- }
43828
- return parsed;
43829
- }
43830
- function mergedTasks(source, destination) {
43831
- const legacy = readTaskFile(source).tasks;
43832
- const current3 = readTaskFile(destination).tasks;
43833
- const merged = legacy.map((task) => ({ ...task }));
43834
- const usedIds = new Set(merged.map((task) => String(task.id)));
43835
- let nextId = Math.max(0, ...[...usedIds].map(Number).filter(Number.isInteger)) + 1;
43836
- const remapped = new Map;
43837
- for (const task of current3) {
43838
- const originalId = String(task.id);
43839
- const exact = merged.find((candidate) => candidate.id === originalId && JSON.stringify(candidate) === JSON.stringify(task));
43840
- if (exact) {
43841
- remapped.set(originalId, originalId);
43842
- continue;
43843
- }
43844
- const id = usedIds.has(originalId) ? String(nextId++) : originalId;
43845
- usedIds.add(id);
43846
- remapped.set(originalId, id);
43847
- merged.push({ ...task, id });
43848
- }
43849
- for (const task of merged.slice(legacy.length)) {
43850
- if (task.blockedBy)
43851
- task.blockedBy = task.blockedBy.map((id) => remapped.get(id) ?? id);
43852
- }
43853
- return `${JSON.stringify({ version: 1, tasks: merged }, null, 2)}
43854
- `;
43855
- }
43856
- function placeOperation(operation) {
43857
- if (!operation.destination || operation.collision === "keep-destination")
43858
- return;
43859
- mkdirSync35(dirname23(operation.destination), { recursive: true });
43860
- if (operation.collision === "merge-jsonl") {
43861
- writeFileSync25(operation.destination, mergedJsonl(operation.staged, operation.destinationStaged));
43862
- return;
43863
- }
43864
- if (operation.collision === "merge-tasks") {
43865
- writeFileSync25(operation.destination, mergedTasks(operation.staged, operation.destinationStaged));
43866
- return;
43867
- }
43868
- renameSync16(operation.staged, operation.destination);
43869
- }
43870
- function tablesWithColumn(database, columnName) {
43871
- const tables = database.query("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'").all();
43872
- return tables.map((row) => row.name).filter((table) => database.query(`PRAGMA table_info("${table.replaceAll('"', '""')}")`).all().some((column) => column.name === columnName));
43873
- }
43874
- function selectedTopicIds(dbPath, source) {
43875
- if (!existsSync36(dbPath))
43876
- return null;
43877
- const database = new Database(dbPath, { readonly: true });
43878
- try {
43879
- const hasMemberships = database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='topic_members'").get();
43880
- if (!hasMemberships)
43881
- return null;
43882
- return new Set(database.query("SELECT topic_id FROM topic_members WHERE user_id = ?").all(source).map((row) => row.topic_id));
43883
- } finally {
43884
- database.close();
43885
- }
43886
- }
43887
- function migrateDatabase(dbPath, source, masterKey, legacyTopicProfiles = []) {
43888
- if (!existsSync36(dbPath))
43889
- return [];
43890
- const database = new Database(dbPath);
43891
- const userTables = tablesWithColumn(database, "user_id");
43892
- const ownerUserTables = tablesWithColumn(database, "owner_user_id");
43893
- const migratedTables = [...new Set([...userTables, ...ownerUserTables])];
43894
- const retainedTopicIds = selectedTopicIds(dbPath, source);
43895
- const quote = (name) => `"${name.replaceAll('"', '""')}"`;
43896
- try {
43897
- if (source !== CANONICAL_LOCAL_USER_ID) {
43898
- for (const [column, tables] of [
43899
- ["user_id", userTables],
43900
- ["owner_user_id", ownerUserTables]
43901
- ]) {
43902
- for (const table of tables) {
43903
- const collision = database.query(`SELECT COUNT(*) AS count FROM ${quote(table)} WHERE ${column} = ?`).get(CANONICAL_LOCAL_USER_ID)?.count;
43904
- if (collision)
43905
- throw new Error(`Database collision: ${table}.${column} already contains local rows.`);
43906
- }
43907
- }
43908
- const hasUsers = database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='users'").get();
43909
- if (hasUsers) {
43910
- const localUser = database.query("SELECT 1 FROM users WHERE id = ?").get(CANONICAL_LOCAL_USER_ID);
43911
- if (localUser)
43912
- throw new Error("Database collision: users already contains canonical local.");
43913
- }
43914
- }
43915
- database.exec("PRAGMA foreign_keys = OFF");
43916
- database.exec("BEGIN IMMEDIATE");
43917
- for (const table of userTables) {
43918
- database.query(`DELETE FROM ${quote(table)} WHERE user_id <> ?`).run(source);
43919
- if (table === "vault" && source !== CANONICAL_LOCAL_USER_ID) {
43920
- if (!masterKey)
43921
- throw new Error("Cannot migrate encrypted vault rows without vault-master-key.");
43922
- const rows = database.query("SELECT key, value FROM vault WHERE user_id = ?").all(source);
43923
- for (const row of rows) {
43924
- const plaintext = decryptVaultValueWithKey(source, row.key, row.value, masterKey).value;
43925
- database.query("UPDATE vault SET value = ? WHERE user_id = ? AND key = ?").run(encryptVaultValueWithKey(CANONICAL_LOCAL_USER_ID, row.key, plaintext, masterKey), source, row.key);
43926
- }
43927
- }
43928
- database.query(`UPDATE ${quote(table)} SET user_id = ? WHERE user_id = ?`).run(CANONICAL_LOCAL_USER_ID, source);
43929
- }
43930
- for (const table of ownerUserTables) {
43931
- database.query(`DELETE FROM ${quote(table)} WHERE owner_user_id <> ?`).run(source);
43932
- database.query(`UPDATE ${quote(table)} SET owner_user_id = ? WHERE owner_user_id = ?`).run(CANONICAL_LOCAL_USER_ID, source);
43933
- }
43934
- if (retainedTopicIds) {
43935
- database.exec("CREATE TEMP TABLE migration_selected_topics (id TEXT PRIMARY KEY)");
43936
- for (const topicId of retainedTopicIds) {
43937
- database.query("INSERT INTO migration_selected_topics (id) VALUES (?)").run(topicId);
43938
- }
43939
- const topicTables = database.query("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'").all().map((row) => row.name).filter((table) => database.query(`PRAGMA table_info(${quote(table)})`).all().some((column) => column.name === "topic_id"));
43940
- for (const table of topicTables) {
43941
- database.query(`DELETE FROM ${quote(table)} WHERE topic_id NOT IN (SELECT id FROM migration_selected_topics)`).run();
43942
- }
43943
- if (database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='api_topics'").get()) {
43944
- database.query("DELETE FROM api_topics WHERE id NOT IN (SELECT id FROM migration_selected_topics)").run();
43945
- }
43946
- }
43947
- if (database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='browser_profiles'").get()) {
43948
- database.query("DELETE FROM browser_profiles WHERE owner_id <> ?").run(source);
43949
- database.query("UPDATE browser_profiles SET owner_id = ? WHERE owner_id = ?").run(CANONICAL_LOCAL_USER_ID, source);
43950
- }
43951
- if (database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='api_topics'").get() && database.query("PRAGMA table_info(api_topics)").all().some((column) => column.name === "browser_profile_owner")) {
43952
- database.query("UPDATE api_topics SET browser_profile_owner = ? WHERE browser_profile_owner = ?").run(CANONICAL_LOCAL_USER_ID, source);
43953
- if (retainedTopicIds) {
43954
- database.query("UPDATE api_topics SET browser_profile_owner = ? WHERE browser_profile_owner IS NOT NULL").run(CANONICAL_LOCAL_USER_ID);
43955
- } else {
43956
- database.query("DELETE FROM api_topics WHERE browser_profile_owner IS NOT NULL AND browser_profile_owner <> ?").run(CANONICAL_LOCAL_USER_ID);
43957
- }
43958
- for (const binding of legacyTopicProfiles) {
43959
- database.query("UPDATE api_topics SET browser_profile = ?, browser_profile_owner = ? WHERE id = ?").run(binding.profile, CANONICAL_LOCAL_USER_ID, binding.topicId);
43960
- }
43961
- }
43962
- if (database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='users'").get()) {
43963
- database.query("DELETE FROM users WHERE id <> ?").run(source);
43964
- database.query("UPDATE users SET id = ? WHERE id = ?").run(CANONICAL_LOCAL_USER_ID, source);
43965
- }
43966
- database.exec("COMMIT");
43967
- database.exec("PRAGMA foreign_keys = ON");
43968
- const fkErrors = database.query("PRAGMA foreign_key_check").all();
43969
- if (fkErrors.length > 0)
43970
- throw new Error("Database migration left foreign-key violations.");
43971
- return migratedTables;
43972
- } catch (error2) {
43973
- try {
43974
- database.exec("ROLLBACK");
43975
- } catch {}
43976
- throw error2;
43977
- } finally {
43978
- database.close();
43979
- }
43980
- }
43981
- function migrateSingleUserState(options) {
43982
- const stateDir2 = resolve25(options.stateDir ?? process.env.NEGOTIUM_STATE_DIR ?? join42(homedir12(), ".negotium"));
43983
- const source = options.sourcePrincipal?.trim() || CANONICAL_LOCAL_USER_ID;
43984
- if (!source || /[/\\]|\.\./.test(source))
43985
- throw new Error("Invalid source principal.");
43986
- if (!options.deleteOtherUsers || !options.confirmed) {
43987
- throw new Error("Migration requires --delete-other-users and --yes; other principals are permanently deleted.");
43988
- }
43989
- const markerPath = join42(stateDir2, ".migration-0.2.0-single-user.json");
43990
- if (existsSync36(markerPath)) {
43991
- const marker = JSON.parse(readFileSync27(markerPath, "utf8"));
43992
- if (marker.id !== SINGLE_USER_MIGRATION_ID)
43993
- throw new Error(`Unexpected migration marker at ${markerPath}.`);
43994
- return {
43995
- status: "already-completed",
43996
- markerPath,
43997
- sourcePrincipal: marker.sourcePrincipal ?? source,
43998
- movedPaths: marker.movedPaths ?? 0,
43999
- deletedPaths: marker.deletedPaths ?? 0,
44000
- migratedTables: marker.migratedTables ?? []
44001
- };
44002
- }
44003
- assertNoActiveNode(stateDir2);
44004
- mkdirSync35(stateDir2, { recursive: true });
44005
- const stagingRoot = join42(stateDir2, ".migration-0.2.0-staging");
44006
- const journalPath = join42(stagingRoot, "journal.json");
44007
- mkdirSync35(stagingRoot, { recursive: true, mode: 448 });
44008
- let journal;
44009
- if (existsSync36(journalPath)) {
44010
- journal = JSON.parse(readFileSync27(journalPath, "utf8"));
44011
- if (journal.sourcePrincipal !== source)
44012
- throw new Error("Interrupted migration used a different source principal.");
44013
- } else {
44014
- const operations = [];
44015
- const retainedTopicIds = selectedTopicIds(join42(stateDir2, "data", "sessions.db"), source);
44016
- addDirectoryContents(operations, join42(stateDir2, "run"), join42(stateDir2, "runtime"), stagingRoot);
44017
- addDirectoryContents(operations, join42(stateDir2, "bin"), join42(stateDir2, "binaries"), stagingRoot);
44018
- for (const secret of ["node-control-token", "runtime-mcp-secret", "vault-master-key"]) {
44019
- const sourcePath = join42(stateDir2, secret);
44020
- if (existsSync36(sourcePath))
44021
- operations.push({
44022
- source: sourcePath,
44023
- staged: join42(stagingRoot, randomUUID34()),
44024
- destination: join42(stateDir2, "secrets", secret),
44025
- state: "pending"
44026
- });
44027
- }
44028
- const legacyVaultDb = join42(stateDir2, "data", "vault.db");
44029
- if (existsSync36(legacyVaultDb)) {
44030
- operations.push({
44031
- source: legacyVaultDb,
44032
- staged: join42(stagingRoot, randomUUID34()),
44033
- destination: join42(stateDir2, "data", "vault", "vault.db"),
44034
- state: "pending"
44035
- });
44036
- }
44037
- for (const store of ["conversations", "tasks", "users"]) {
44038
- const root = join42(stateDir2, "data", store);
44039
- addDirectoryContents(operations, join42(root, source), root, stagingRoot);
44040
- for (const owner of entries(root)) {
44041
- const ownerPath = join42(root, owner);
44042
- if (owner !== source && statSync19(ownerPath).isDirectory()) {
44043
- operations.push({
44044
- source: ownerPath,
44045
- staged: join42(stagingRoot, randomUUID34()),
44046
- state: "pending"
44047
- });
44048
- }
44049
- }
44050
- }
44051
- for (const legacyWorkspaceDir of ["contexts", "dm", "sessions"]) {
44052
- addDirectoryContents(operations, join42(stateDir2, "workspace", legacyWorkspaceDir), join42(stateDir2, "data", legacyWorkspaceDir), stagingRoot);
44053
- }
44054
- for (const topicId of entries(join42(stateDir2, "workspace", "topics"))) {
44055
- const topicPath = join42(stateDir2, "workspace", "topics", topicId);
44056
- if (retainedTopicIds && !retainedTopicIds.has(topicId)) {
44057
- operations.push({
44058
- source: topicPath,
44059
- staged: join42(stagingRoot, randomUUID34()),
44060
- state: "pending"
44061
- });
44062
- } else {
44063
- addDirectoryContents(operations, join42(topicPath, "uploads"), join42(stateDir2, "data", "uploads", topicId), stagingRoot);
44064
- }
44065
- }
44066
- if (retainedTopicIds) {
44067
- for (const topicId of entries(join42(stateDir2, "workspace", "wiki"))) {
44068
- if (retainedTopicIds.has(topicId))
44069
- continue;
44070
- operations.push({
44071
- source: join42(stateDir2, "workspace", "wiki", topicId),
44072
- staged: join42(stagingRoot, randomUUID34()),
44073
- state: "pending"
44074
- });
44075
- }
44076
- }
44077
- const legacyBrowserRoot = join42(stateDir2, "workspace", "browser-profiles");
44078
- const selectedProfiles = join42(legacyBrowserRoot, "profiles", oldOwnerDirectory(source));
44079
- addDirectoryContents(operations, selectedProfiles, join42(stateDir2, "browser", "profiles"), stagingRoot);
44080
- for (const owner of entries(join42(legacyBrowserRoot, "profiles"))) {
44081
- const ownerPath = join42(legacyBrowserRoot, "profiles", owner);
44082
- if (ownerPath !== selectedProfiles) {
44083
- operations.push({
44084
- source: ownerPath,
44085
- staged: join42(stagingRoot, randomUUID34()),
44086
- state: "pending"
44087
- });
44088
- }
44089
- }
44090
- for (const topicId of entries(legacyBrowserRoot).filter((name) => name !== "profiles")) {
44091
- if (retainedTopicIds && !retainedTopicIds.has(topicId)) {
44092
- operations.push({
44093
- source: join42(legacyBrowserRoot, topicId),
44094
- staged: join42(stagingRoot, randomUUID34()),
44095
- state: "pending"
44096
- });
44097
- continue;
44098
- }
44099
- const profile = `legacy_${createHash11("sha256").update(topicId).digest("hex").slice(0, 12)}`;
44100
- operations.push({
44101
- source: join42(legacyBrowserRoot, topicId),
44102
- staged: join42(stagingRoot, randomUUID34()),
44103
- destination: join42(stateDir2, "browser", "profiles", profile),
44104
- state: "pending"
44105
- });
44106
- }
44107
- configureCollisions(operations, stateDir2, stagingRoot);
44108
- journal = {
44109
- id: SINGLE_USER_MIGRATION_ID,
44110
- sourcePrincipal: source,
44111
- createdAt: new Date().toISOString(),
44112
- phase: "filesystem",
44113
- operations
44114
- };
44115
- writeJournal(journalPath, journal);
44116
- }
44117
- const dbPath = join42(stateDir2, "data", "sessions.db");
44118
- const dbBackup = join42(stagingRoot, "sessions.db.rollback");
44119
- const vaultDbPath = join42(stateDir2, "data", "vault", "vault.db");
44120
- const vaultDbBackup = join42(stagingRoot, "vault.db.rollback");
44121
- try {
44122
- for (const operation of journal.operations) {
44123
- if (operation.state === "staged")
44124
- operation.state = "source-staged";
44125
- if (operation.state === "pending" && !existsSync36(operation.source)) {
44126
- if (existsSync36(operation.staged))
44127
- operation.state = "source-staged";
44128
- else if (operation.destination && existsSync36(operation.destination)) {
44129
- operation.state = "placed";
44130
- }
44131
- }
44132
- if (operation.state === "pending") {
44133
- mkdirSync35(dirname23(operation.staged), { recursive: true });
44134
- renameSync16(operation.source, operation.staged);
44135
- operation.state = "source-staged";
44136
- writeJournal(journalPath, journal);
44137
- }
44138
- if (operation.state === "source-staged" && operation.collision === "replace-destination" && operation.destination && operation.destinationStaged && !existsSync36(operation.staged) && existsSync36(operation.destination) && existsSync36(operation.destinationStaged)) {
44139
- operation.state = "placed";
44140
- writeJournal(journalPath, journal);
44141
- }
44142
- if (operation.state === "destination-staged" && operation.collision !== "merge-jsonl" && operation.collision !== "merge-tasks" && operation.collision !== "keep-destination" && operation.destination && !existsSync36(operation.staged) && existsSync36(operation.destination)) {
44143
- operation.state = "placed";
44144
- writeJournal(journalPath, journal);
44145
- }
44146
- if (operation.state === "source-staged") {
44147
- if (operation.destination && operation.destinationStaged) {
44148
- if (existsSync36(operation.destination) && !existsSync36(operation.destinationStaged)) {
44149
- renameSync16(operation.destination, operation.destinationStaged);
44150
- }
44151
- if (!existsSync36(operation.destinationStaged)) {
44152
- throw new Error(`Missing collision backup for ${operation.destination}.`);
44153
- }
44154
- }
44155
- operation.state = "destination-staged";
44156
- writeJournal(journalPath, journal);
44157
- }
44158
- if (operation.state === "destination-staged") {
44159
- placeOperation(operation);
44160
- operation.state = "placed";
44161
- writeJournal(journalPath, journal);
44162
- }
44163
- }
44164
- journal.phase = "database";
44165
- writeJournal(journalPath, journal);
44166
- if (existsSync36(dbPath) && !existsSync36(dbBackup))
44167
- copyFileSync6(dbPath, dbBackup);
44168
- if (existsSync36(vaultDbPath) && !existsSync36(vaultDbBackup))
44169
- copyFileSync6(vaultDbPath, vaultDbBackup);
44170
- const masterKeyPath = join42(stateDir2, "secrets", "vault-master-key");
44171
- const masterKey = existsSync36(masterKeyPath) ? readFileSync27(masterKeyPath, "utf8").trim() : undefined;
44172
- const legacyBrowserRoot = join42(stateDir2, "workspace", "browser-profiles");
44173
- const legacyTopicProfiles = journal.operations.filter((operation) => dirname23(operation.source) === legacyBrowserRoot && operation.destination).map((operation) => ({
44174
- topicId: basename14(operation.source),
44175
- profile: basename14(operation.destination)
44176
- }));
44177
- const migratedTables = migrateDatabase(dbPath, source, masterKey, legacyTopicProfiles);
44178
- const migratedVaultTables = migrateDatabase(vaultDbPath, source, masterKey);
44179
- for (const table of migratedVaultTables)
44180
- if (!migratedTables.includes(table))
44181
- migratedTables.push(table);
44182
- mkdirSync35(join42(stateDir2, "secrets"), { recursive: true, mode: 448 });
44183
- chmodSync8(join42(stateDir2, "secrets"), 448);
44184
- for (const secret of ["node-control-token", "runtime-mcp-secret", "vault-master-key"]) {
44185
- const path = join42(stateDir2, "secrets", secret);
44186
- if (existsSync36(path))
44187
- chmodSync8(path, 384);
44188
- }
44189
- const deletedPaths = journal.operations.filter((operation) => !operation.destination).length;
44190
- const movedPaths = journal.operations.length - deletedPaths;
44191
- const marker = {
44192
- id: SINGLE_USER_MIGRATION_ID,
44193
- version: "0.2.0",
44194
- completedAt: new Date().toISOString(),
44195
- sourcePrincipal: source,
44196
- canonicalPrincipal: CANONICAL_LOCAL_USER_ID,
44197
- movedPaths,
44198
- deletedPaths,
44199
- migratedTables
44200
- };
44201
- for (const store of ["conversations", "tasks", "users"]) {
44202
- rmSync11(join42(stateDir2, "data", store, source), {
44203
- recursive: true,
44204
- force: true
44205
- });
44206
- }
44207
- rmSync11(join42(stateDir2, "run"), { recursive: true, force: true });
44208
- rmSync11(join42(stateDir2, "bin"), { recursive: true, force: true });
44209
- rmSync11(join42(stateDir2, "workspace", "browser-profiles"), {
44210
- recursive: true,
44211
- force: true
44212
- });
44213
- writeFileSync25(markerPath, `${JSON.stringify(marker, null, 2)}
44214
- `, {
44215
- mode: 384,
44216
- flag: "wx"
44217
- });
44218
- journal.phase = "complete";
44219
- rmSync11(stagingRoot, { recursive: true, force: true });
44220
- return {
44221
- status: "completed",
44222
- markerPath,
44223
- sourcePrincipal: source,
44224
- movedPaths,
44225
- deletedPaths,
44226
- migratedTables
44227
- };
44228
- } catch (error2) {
44229
- if (existsSync36(dbBackup))
44230
- copyFileSync6(dbBackup, dbPath);
44231
- if (existsSync36(vaultDbBackup))
44232
- copyFileSync6(vaultDbBackup, vaultDbPath);
44233
- rollbackFilesystem(journal, journalPath);
44234
- throw error2;
44235
- }
44236
- }
44237
- var CANONICAL_LOCAL_USER_ID = "local", SINGLE_USER_MIGRATION_ID = "negotium-0.2.0-single-user";
44238
- var init_single_user = __esm(async () => {
44239
- init_vault_crypto_core();
44240
- await init_sqlite();
44241
- });
44242
-
44243
- // ../cli/src/commands/migrate.ts
44244
- var exports_migrate = {};
44245
- __export(exports_migrate, {
44246
- migrateCommand: () => migrateCommand
44247
- });
44248
- function option3(args, name) {
44249
- const prefix = `--${name}=`;
44250
- return args.find((arg) => arg.startsWith(prefix))?.slice(prefix.length);
44251
- }
44252
- function migrateCommand(args) {
44253
- if (args[0] !== "single-user") {
44254
- throw new Error("usage: negotium migrate single-user [--source=local] --delete-other-users --yes");
44255
- }
44256
- const result = migrateSingleUserState({
44257
- sourcePrincipal: option3(args, "source"),
44258
- deleteOtherUsers: args.includes("--delete-other-users"),
44259
- confirmed: args.includes("--yes")
44260
- });
44261
- console.log(`${result.status}: ${result.markerPath}`);
44262
- }
44263
- var init_migrate = __esm(async () => {
44264
- await init_single_user();
44265
- });
44266
-
44267
43651
  // ../cli/src/commands/topics.ts
44268
43652
  var exports_topics = {};
44269
43653
  __export(exports_topics, {
@@ -44365,12 +43749,12 @@ function vaultCommand(args) {
44365
43749
  switch (sub) {
44366
43750
  case undefined:
44367
43751
  case "list": {
44368
- const entries2 = vaultListWithValues(DEFAULT_USER);
44369
- if (entries2.length === 0) {
43752
+ const entries = vaultListWithValues(DEFAULT_USER);
43753
+ if (entries.length === 0) {
44370
43754
  console.log("vault is empty \u2014 `negotium vault set MY_KEY <value> [description]`");
44371
43755
  return;
44372
43756
  }
44373
- for (const entry of entries2) {
43757
+ for (const entry of entries) {
44374
43758
  console.log(`${entry.key} ${entry.description || ""}`.trimEnd());
44375
43759
  }
44376
43760
  return;
@@ -44694,12 +44078,6 @@ var CLI_COMMANDS = [
44694
44078
  description: "bootstrap ~/.negotium and check agent auth",
44695
44079
  group: "Setup"
44696
44080
  },
44697
- {
44698
- name: "migrate",
44699
- usage: "migrate single-user [--source=local] --delete-other-users --yes",
44700
- description: "explicitly migrate a 0.1 state tree to the 0.2 single-user layout",
44701
- group: "Setup"
44702
- },
44703
44081
  {
44704
44082
  name: "serve",
44705
44083
  usage: "serve [otium]",
@@ -44806,7 +44184,7 @@ async function runCanonicalNode(port) {
44806
44184
  });
44807
44185
  console.log(`negotium node listening on 127.0.0.1:${node.port} (ctrl-c to stop)`);
44808
44186
  await node.completed;
44809
- await new Promise((resolve26) => setImmediate(resolve26));
44187
+ await new Promise((resolve25) => setImmediate(resolve25));
44810
44188
  process.exit(0);
44811
44189
  }
44812
44190
  async function stopAdapter(name) {
@@ -44829,11 +44207,6 @@ switch (command) {
44829
44207
  initCommand2();
44830
44208
  break;
44831
44209
  }
44832
- case "migrate": {
44833
- const { migrateCommand: migrateCommand2 } = await init_migrate().then(() => exports_migrate);
44834
- migrateCommand2(args);
44835
- break;
44836
- }
44837
44210
  case "-v":
44838
44211
  case "--version": {
44839
44212
  const { NEGOTIUM_VERSION: NEGOTIUM_VERSION2 } = await Promise.resolve().then(() => exports_version);
@@ -44942,4 +44315,4 @@ switch (command) {
44942
44315
  }
44943
44316
  }
44944
44317
 
44945
- //# debugId=29CE1495263F2C6864756E2164756E21
44318
+ //# debugId=C9823B7F89627C9D64756E2164756E21