negotium 0.4.1 → 0.4.2

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
@@ -1869,7 +1869,7 @@ var exports_version = {};
1869
1869
  __export(exports_version, {
1870
1870
  NEGOTIUM_VERSION: () => NEGOTIUM_VERSION
1871
1871
  });
1872
- var NEGOTIUM_VERSION = "0.4.1";
1872
+ var NEGOTIUM_VERSION = "0.4.2";
1873
1873
 
1874
1874
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
1875
1875
  import { spawn } from "child_process";
@@ -2654,7 +2654,8 @@ var init_mcp_catalog_policy = __esm(() => {
2654
2654
  "system-health": { scopes: ["dm", "forum", "manager", "cron"], forumRequired: true },
2655
2655
  "background-bash": { scopes: ["forum"], forumRequired: true },
2656
2656
  "agent-health": { scopes: ["forum", "manager", "cron"], forumRequired: true },
2657
- vault: { scopes: ["dm", "forum", "manager", "cron"], forumRequired: true }
2657
+ vault: { scopes: ["dm", "forum", "manager", "cron"], forumRequired: true },
2658
+ "cua-rs": { scopes: ["dm", "forum", "fork"], forumRequired: false }
2658
2659
  };
2659
2660
  });
2660
2661
 
@@ -2666,6 +2667,9 @@ function browserOwnerCapability(capability, owner) {
2666
2667
  var init_capability = () => {};
2667
2668
 
2668
2669
  // ../../packages/core/src/platform/mcp-config.ts
2670
+ import { accessSync as accessSync2, constants as fsConstants } from "fs";
2671
+ import { homedir as homedir6 } from "os";
2672
+ import { join as join8 } from "path";
2669
2673
  function buildStdioMcpServer(agent, serverFile, serverArgs, env) {
2670
2674
  if (agent === "codex") {
2671
2675
  return {
@@ -2781,6 +2785,27 @@ function backgroundBashTransport(agent, port, userId, topic) {
2781
2785
  }
2782
2786
  return { type: "sse", url: `http://127.0.0.1:${port}/sse`, headers };
2783
2787
  }
2788
+ function cuaRsArgs() {
2789
+ const raw = envText("NEGOTIUM_CUA_RS_ALLOW_HID")?.trim().toLowerCase();
2790
+ const on = raw === "1" || raw === "true" || raw === "yes";
2791
+ return on ? ["--allow-hid"] : [];
2792
+ }
2793
+ function resolveCuaRsBinary(platform2 = process.platform) {
2794
+ if (platform2 !== "darwin")
2795
+ return null;
2796
+ const candidates = [
2797
+ envText("NEGOTIUM_CUA_RS_BIN"),
2798
+ join8(homedir6(), ".local", "bin", "cua-rs"),
2799
+ "/usr/local/bin/cua-rs"
2800
+ ].filter((p) => Boolean(p));
2801
+ for (const candidate of candidates) {
2802
+ try {
2803
+ accessSync2(candidate, fsConstants.X_OK);
2804
+ return candidate;
2805
+ } catch {}
2806
+ }
2807
+ return null;
2808
+ }
2784
2809
  function refreshForumCatalogViews() {
2785
2810
  const { all, required, optional } = classifyForumMcpServers(MCP_CATALOG);
2786
2811
  allForumMcpServerNames.splice(0, allForumMcpServerNames.length, ...all);
@@ -3240,6 +3265,15 @@ var init_mcp_config = __esm(() => {
3240
3265
  args.push("--list-only=true");
3241
3266
  return buildBuiltinMcpServer("vault", { ...ctx, userId: vaultUserId ?? userId }, () => buildStdioMcpServer(agent, VAULT_SERVER, args));
3242
3267
  }
3268
+ },
3269
+ "cua-rs": {
3270
+ ...commonRuntimeMcpPolicy("cua-rs"),
3271
+ build() {
3272
+ const bin = resolveCuaRsBinary();
3273
+ if (!bin)
3274
+ return null;
3275
+ return { command: bin, args: cuaRsArgs() };
3276
+ }
3243
3277
  }
3244
3278
  };
3245
3279
  allForumMcpServerNames = [];
@@ -3311,14 +3345,14 @@ var init_execution_host = __esm(async () => {
3311
3345
  // ../../packages/core/src/agents/rollout/codex.ts
3312
3346
  import { randomBytes as randomBytes4 } from "crypto";
3313
3347
  import { existsSync as existsSync6, readFileSync as readFileSync5, realpathSync as realpathSync2, statSync as statSync2, unlinkSync as unlinkSync5 } from "fs";
3314
- import { basename, dirname as dirname6, join as join8, resolve as resolve5 } from "path";
3348
+ import { basename, dirname as dirname6, join as join9, resolve as resolve5 } from "path";
3315
3349
  function codexSessionsDir() {
3316
- return join8(hostedCodexHomePath(), "sessions");
3350
+ return join9(hostedCodexHomePath(), "sessions");
3317
3351
  }
3318
3352
  function loadCodexShell() {
3319
3353
  if (_shellCache)
3320
3354
  return _shellCache;
3321
- const raw = readFileSync5(join8(FIXTURES_DIR, "codex-shell.jsonl"), "utf8");
3355
+ const raw = readFileSync5(join9(FIXTURES_DIR, "codex-shell.jsonl"), "utf8");
3322
3356
  const lines = parseJsonlText(raw);
3323
3357
  if (lines.length < 5) {
3324
3358
  throw new Error(`loadCodexShell: expected >=5 entries in codex-shell.jsonl, got ${lines.length}`);
@@ -3385,8 +3419,8 @@ function codexRolloutPath(threadId, fallback) {
3385
3419
  const hh = String(createdAt.getHours()).padStart(2, "0");
3386
3420
  const min = String(createdAt.getMinutes()).padStart(2, "0");
3387
3421
  const ss = String(createdAt.getSeconds()).padStart(2, "0");
3388
- const dir = join8(codexSessionsDir(), yyyy, mm, dd);
3389
- return join8(dir, `rollout-${yyyy}-${mm}-${dd}T${hh}-${min}-${ss}-${threadId}.jsonl`);
3422
+ const dir = join9(codexSessionsDir(), yyyy, mm, dd);
3423
+ return join9(dir, `rollout-${yyyy}-${mm}-${dd}T${hh}-${min}-${ss}-${threadId}.jsonl`);
3390
3424
  }
3391
3425
  function canonicalFilePath(path) {
3392
3426
  const absolute = resolve5(path);
@@ -3394,7 +3428,7 @@ function canonicalFilePath(path) {
3394
3428
  return realpathSync2(absolute);
3395
3429
  } catch {
3396
3430
  try {
3397
- return join8(realpathSync2(dirname6(absolute)), basename(absolute));
3431
+ return join9(realpathSync2(dirname6(absolute)), basename(absolute));
3398
3432
  } catch {
3399
3433
  return absolute;
3400
3434
  }
@@ -3624,19 +3658,19 @@ function latestCodexRolloutPath(threadId) {
3624
3658
  try {
3625
3659
  if (buckets) {
3626
3660
  for (const bucket of buckets) {
3627
- const dir = join8(sessionsDir, bucket);
3661
+ const dir = join9(sessionsDir, bucket);
3628
3662
  if (!existsSync6(dir))
3629
3663
  continue;
3630
3664
  const glob = new Bun.Glob(`rollout-*-${threadId}.jsonl`);
3631
3665
  for (const rel of glob.scanSync({ cwd: dir, onlyFiles: true })) {
3632
- candidates.push(join8(dir, rel));
3666
+ candidates.push(join9(dir, rel));
3633
3667
  }
3634
3668
  }
3635
3669
  }
3636
3670
  if (candidates.length === 0) {
3637
3671
  const glob = new Bun.Glob(`**/rollout-*-${threadId}.jsonl`);
3638
3672
  for (const rel of glob.scanSync({ cwd: sessionsDir, onlyFiles: true })) {
3639
- candidates.push(join8(sessionsDir, rel));
3673
+ candidates.push(join9(sessionsDir, rel));
3640
3674
  }
3641
3675
  }
3642
3676
  return candidates.sort((a, b) => statSync2(b).mtimeMs - statSync2(a).mtimeMs)[0];
@@ -3757,13 +3791,13 @@ function sweepPriorRolloutsForThread(threadId) {
3757
3791
  return;
3758
3792
  }
3759
3793
  for (const bucket of buckets) {
3760
- const dir = join8(sessionsDir, bucket);
3794
+ const dir = join9(sessionsDir, bucket);
3761
3795
  if (!existsSync6(dir))
3762
3796
  continue;
3763
3797
  try {
3764
3798
  const glob = new Bun.Glob(`rollout-*-${threadId}.jsonl`);
3765
3799
  for (const rel of glob.scanSync({ cwd: dir, onlyFiles: true })) {
3766
- const fullPath = join8(dir, rel);
3800
+ const fullPath = join9(dir, rel);
3767
3801
  try {
3768
3802
  unlinkSync5(fullPath);
3769
3803
  } catch (e) {
@@ -3781,7 +3815,7 @@ function sweepPriorRolloutsFullTree(threadId, sessionsDir) {
3781
3815
  try {
3782
3816
  const glob = new Bun.Glob(`**/rollout-*-${threadId}.jsonl`);
3783
3817
  for (const rel of glob.scanSync({ cwd: sessionsDir, onlyFiles: true })) {
3784
- const fullPath = join8(sessionsDir, rel);
3818
+ const fullPath = join9(sessionsDir, rel);
3785
3819
  try {
3786
3820
  unlinkSync5(fullPath);
3787
3821
  } catch (e) {
@@ -3959,7 +3993,7 @@ var init_codex_app_server = __esm(async () => {
3959
3993
 
3960
3994
  // ../../packages/core/src/agents/codex-registry.ts
3961
3995
  import { existsSync as existsSync7, unlinkSync as unlinkSync6 } from "fs";
3962
- import { join as join9 } from "path";
3996
+ import { join as join10 } from "path";
3963
3997
  var VALID_EFFORTS2, codexRegistry, codexRegistryOperations;
3964
3998
  var init_codex_registry = __esm(async () => {
3965
3999
  await init_codex_app_server();
@@ -4002,7 +4036,7 @@ var init_codex_registry = __esm(async () => {
4002
4036
  async cleanupRollouts({ sessionIds }) {
4003
4037
  if (sessionIds.length === 0)
4004
4038
  return;
4005
- const sessionsDir = join9(hostedCodexHomePath(), "sessions");
4039
+ const sessionsDir = join10(hostedCodexHomePath(), "sessions");
4006
4040
  if (!existsSync7(sessionsDir))
4007
4041
  return;
4008
4042
  const failures = [];
@@ -4010,7 +4044,7 @@ var init_codex_registry = __esm(async () => {
4010
4044
  try {
4011
4045
  const glob = new Bun.Glob(`**/rollout-*-${tid}.jsonl`);
4012
4046
  for await (const rel of glob.scan({ cwd: sessionsDir, onlyFiles: true })) {
4013
- const path = join9(sessionsDir, rel);
4047
+ const path = join10(sessionsDir, rel);
4014
4048
  try {
4015
4049
  unlinkSync6(path);
4016
4050
  } catch (e) {
@@ -4035,16 +4069,16 @@ var init_codex_registry = __esm(async () => {
4035
4069
  // ../../packages/core/src/agents/maestro-registry.ts
4036
4070
  import { randomUUID as randomUUID3 } from "crypto";
4037
4071
  import { existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
4038
- import { homedir as homedir6 } from "os";
4039
- import { join as join10, resolve as resolve6 } from "path";
4072
+ import { homedir as homedir7 } from "os";
4073
+ import { join as join11, resolve as resolve6 } from "path";
4040
4074
  function maestroSessionsDir() {
4041
- return join10(process.env.MAESTRO_DATA_DIR ? resolve6(process.env.MAESTRO_DATA_DIR) : join10(homedir6(), ".maestro"), "sessions");
4075
+ return join11(process.env.MAESTRO_DATA_DIR ? resolve6(process.env.MAESTRO_DATA_DIR) : join11(homedir7(), ".maestro"), "sessions");
4042
4076
  }
4043
4077
  function maestroSessionPath(sessionId) {
4044
- return join10(maestroSessionsDir(), `${sessionId}.jsonl`);
4078
+ return join11(maestroSessionsDir(), `${sessionId}.jsonl`);
4045
4079
  }
4046
4080
  function maestroActiveSessionPath(sessionId) {
4047
- return join10(maestroSessionsDir(), `${sessionId}.active.jsonl`);
4081
+ return join11(maestroSessionsDir(), `${sessionId}.active.jsonl`);
4048
4082
  }
4049
4083
  function existingCreatedAt(path) {
4050
4084
  if (!existsSync8(path))
@@ -4283,7 +4317,7 @@ __export(exports_tasks, {
4283
4317
  TASK_STATUS_VALUES: () => TASK_STATUS_VALUES
4284
4318
  });
4285
4319
  import { existsSync as existsSync10, mkdirSync as mkdirSync8, readFileSync as readFileSync7, renameSync as renameSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
4286
- import { dirname as dirname7, join as join11 } from "path";
4320
+ import { dirname as dirname7, join as join12 } from "path";
4287
4321
  function safeTaskScopeKey(scopeKey) {
4288
4322
  const safe = sanitizeFileName(scopeKey);
4289
4323
  if (!safe || safe === "." || safe === "..") {
@@ -4295,7 +4329,7 @@ function taskScopeKey(opts) {
4295
4329
  return opts.topicId?.trim() || opts.session || "default";
4296
4330
  }
4297
4331
  function getTaskFilePath(userId, scopeKey) {
4298
- return join11(resolveStorageDataDir(), "tasks", `${safeTaskScopeKey(scopeKey)}.json`);
4332
+ return join12(resolveStorageDataDir(), "tasks", `${safeTaskScopeKey(scopeKey)}.json`);
4299
4333
  }
4300
4334
  function readTasks(userId, scopeKey) {
4301
4335
  const path = getTaskFilePath(userId, scopeKey);
@@ -4479,16 +4513,16 @@ import {
4479
4513
  unlinkSync as unlinkSync8,
4480
4514
  writeFileSync as writeFileSync7
4481
4515
  } from "fs";
4482
- import { dirname as dirname8, join as join12 } from "path";
4516
+ import { dirname as dirname8, join as join13 } from "path";
4483
4517
  function conversationDir(_userId) {
4484
- return join12(resolveStorageDataDir(), "conversations");
4518
+ return join13(resolveStorageDataDir(), "conversations");
4485
4519
  }
4486
4520
  function topicFilename(topicName) {
4487
4521
  const t = sanitizeTopicName(topicName, true);
4488
4522
  return `${t}.jsonl`;
4489
4523
  }
4490
4524
  function getConversationPath(userId, topicName) {
4491
- return join12(conversationDir(userId), topicFilename(topicName));
4525
+ return join13(conversationDir(userId), topicFilename(topicName));
4492
4526
  }
4493
4527
  function getActiveConversationPath(userId, topicName) {
4494
4528
  const rawPath = getConversationPath(userId, topicName);
@@ -5245,7 +5279,7 @@ import { existsSync as existsSync13 } from "fs";
5245
5279
  import { chmod, mkdtemp, rm, writeFile } from "fs/promises";
5246
5280
  import { createServer } from "net";
5247
5281
  import { tmpdir as tmpdir2 } from "os";
5248
- import { dirname as dirname9, join as join13, resolve as resolve7 } from "path";
5282
+ import { dirname as dirname9, join as join14, resolve as resolve7 } from "path";
5249
5283
  import { fileURLToPath as fileURLToPath2 } from "url";
5250
5284
  function evaluateCodexVaultPreToolUse(input, userId, operations) {
5251
5285
  if (operations.referencesSensitiveStorage(input.tool_input)) {
@@ -5298,10 +5332,10 @@ function privateCodexWrapper(codexScript, socketPath, token) {
5298
5332
  `);
5299
5333
  }
5300
5334
  async function createCodexVaultHookBridge(userId) {
5301
- const root = await mkdtemp(join13(tmpdir2(), "negotium-codex-vault-"));
5335
+ const root = await mkdtemp(join14(tmpdir2(), "negotium-codex-vault-"));
5302
5336
  await chmod(root, 448);
5303
- const socketPath = join13(root, "hook.sock");
5304
- const wrapperPath = join13(root, "codex-with-hooks");
5337
+ const socketPath = join14(root, "hook.sock");
5338
+ const wrapperPath = join14(root, "codex-with-hooks");
5305
5339
  const token = randomBytes5(32).toString("hex");
5306
5340
  const connections = new Set;
5307
5341
  const server = createServer((socket) => {
@@ -5918,8 +5952,8 @@ __export(exports_codex_provider, {
5918
5952
  });
5919
5953
  import { execFileSync as execFileSync5 } from "child_process";
5920
5954
  import { existsSync as existsSync14, readFileSync as readFileSync11, realpathSync as realpathSync3, statSync as statSync5 } from "fs";
5921
- import { homedir as homedir7 } from "os";
5922
- import { dirname as dirname10, isAbsolute as isAbsolute2, join as join14, relative, resolve as resolve9 } from "path";
5955
+ import { homedir as homedir8 } from "os";
5956
+ import { dirname as dirname10, isAbsolute as isAbsolute2, join as join15, relative, resolve as resolve9 } from "path";
5923
5957
  import { Codex } from "@openai/codex-sdk";
5924
5958
  function sameCodexUsage(usage, total) {
5925
5959
  return usage.input_tokens === total.inputTokens && usage.output_tokens === total.outputTokens && (usage.cached_input_tokens ?? 0) === total.cachedInputTokens && (usage.cache_write_input_tokens ?? 0) === total.cacheWriteInputTokens;
@@ -5947,7 +5981,7 @@ function codexMcpServerName(name) {
5947
5981
  return CODEX_MCP_SERVER_NAME_OVERRIDES[name] ?? name;
5948
5982
  }
5949
5983
  function globalCodexMcpServerNames(authFilePath) {
5950
- const configPath = join14(dirname10(authFilePath), "config.toml");
5984
+ const configPath = join15(dirname10(authFilePath), "config.toml");
5951
5985
  if (!existsSync14(configPath))
5952
5986
  return [];
5953
5987
  try {
@@ -6305,7 +6339,7 @@ async function* codexProvider(opts) {
6305
6339
  mcpServerCount: Object.keys(codexMcpServers).length
6306
6340
  }, "codexProvider: starting turn");
6307
6341
  const hostedCodexHome = hostedCodexHomePath();
6308
- const inheritedCodexHome = process.env.CODEX_HOME || join14(homedir7(), ".codex");
6342
+ const inheritedCodexHome = process.env.CODEX_HOME || join15(homedir8(), ".codex");
6309
6343
  const codexEnvironment = scopedBrowserCapability || resolve9(hostedCodexHome) !== resolve9(inheritedCodexHome) ? {
6310
6344
  ...Object.fromEntries(Object.entries(process.env).filter((entry) => typeof entry[1] === "string")),
6311
6345
  CODEX_HOME: hostedCodexHome,
@@ -6759,8 +6793,8 @@ var init_maestro_provider = __esm(async () => {
6759
6793
 
6760
6794
  // ../../packages/core/src/agents/index.ts
6761
6795
  import { existsSync as existsSync15 } from "fs";
6762
- import { homedir as homedir8 } from "os";
6763
- import { join as join15 } from "path";
6796
+ import { homedir as homedir9 } from "os";
6797
+ import { join as join16 } from "path";
6764
6798
  async function* dispatchAgent(opts) {
6765
6799
  switch (opts.agent) {
6766
6800
  case "claude": {
@@ -6794,11 +6828,11 @@ async function resolveSessionFileMissing(agent, sessionId, cwd) {
6794
6828
  switch (agent) {
6795
6829
  case "claude": {
6796
6830
  const encodedCwd = encodeClaudeCwd(cwd);
6797
- const path = join15(homedir8(), ".claude", "projects", encodedCwd, `${sessionId}.jsonl`);
6831
+ const path = join16(homedir9(), ".claude", "projects", encodedCwd, `${sessionId}.jsonl`);
6798
6832
  return !existsSync15(path);
6799
6833
  }
6800
6834
  case "codex": {
6801
- const sessionsDir = join15(hostedCodexHomePath(), "sessions");
6835
+ const sessionsDir = join16(hostedCodexHomePath(), "sessions");
6802
6836
  const glob = new Bun.Glob(`**/rollout-*-${sessionId}.jsonl`);
6803
6837
  for await (const _rel of glob.scan({ cwd: sessionsDir, onlyFiles: true })) {
6804
6838
  return false;
@@ -10127,13 +10161,13 @@ var init_browser_processes = __esm(async () => {
10127
10161
  });
10128
10162
 
10129
10163
  // ../../packages/core/src/platform/playwright/headed-launch.ts
10130
- import { accessSync as accessSync2, constants as constants2 } from "fs";
10164
+ import { accessSync as accessSync3, constants as constants2 } from "fs";
10131
10165
  import { delimiter, isAbsolute as isAbsolute3, resolve as resolve12 } from "path";
10132
10166
  function findExecutableOnPath(command, environment = process.env) {
10133
10167
  const candidates = isAbsolute3(command) ? [command] : (environment.PATH ?? "").split(delimiter).filter(Boolean).map((directory) => resolve12(directory, command));
10134
10168
  for (const candidate of candidates) {
10135
10169
  try {
10136
- accessSync2(candidate, constants2.X_OK);
10170
+ accessSync3(candidate, constants2.X_OK);
10137
10171
  return candidate;
10138
10172
  } catch {}
10139
10173
  }
@@ -10255,7 +10289,7 @@ import { randomBytes as randomBytes6, timingSafeEqual as timingSafeEqual2 } from
10255
10289
  import { chmodSync as chmodSync4 } from "fs";
10256
10290
  import { createServer as createServer3 } from "net";
10257
10291
  import { tmpdir as tmpdir3 } from "os";
10258
- import { join as join16 } from "path";
10292
+ import { join as join17 } from "path";
10259
10293
  function deepMapStrings2(value, transform) {
10260
10294
  if (typeof value === "string")
10261
10295
  return transform(value);
@@ -10342,7 +10376,7 @@ function authorized(actual, expected) {
10342
10376
  }
10343
10377
  async function createBrowserVaultBroker(userId) {
10344
10378
  const token = randomBytes6(32).toString("hex");
10345
- const socketPath = join16(process.platform === "win32" ? tmpdir3() : "/tmp", `negotium-browser-vault-${process.pid}-${randomBytes6(8).toString("hex")}.sock`);
10379
+ const socketPath = join17(process.platform === "win32" ? tmpdir3() : "/tmp", `negotium-browser-vault-${process.pid}-${randomBytes6(8).toString("hex")}.sock`);
10346
10380
  const retainedForms = new Map;
10347
10381
  const leases = new Map;
10348
10382
  const sockets = new Set;
@@ -10608,7 +10642,7 @@ import {
10608
10642
  unlinkSync as unlinkSync11,
10609
10643
  writeFileSync as writeFileSync8
10610
10644
  } from "fs";
10611
- import { dirname as dirname11, join as join17, resolve as resolve13 } from "path";
10645
+ import { dirname as dirname11, join as join18, resolve as resolve13 } from "path";
10612
10646
  function removeDefaultProfileDataDir(userDataDir) {
10613
10647
  const root = resolve13(BROWSER_PROFILES_DIR);
10614
10648
  const target = resolve13(userDataDir);
@@ -10698,14 +10732,14 @@ function portFileName(instanceKey) {
10698
10732
  function writePortFile(instanceKey, port) {
10699
10733
  try {
10700
10734
  mkdirSync10(managerHost.portsDir, { recursive: true });
10701
- writeFileSync8(join17(managerHost.portsDir, portFileName(instanceKey)), String(port));
10735
+ writeFileSync8(join18(managerHost.portsDir, portFileName(instanceKey)), String(port));
10702
10736
  } catch (e) {
10703
10737
  logger.warn({ err: e, instanceKey, port }, "Failed to save playwright port file");
10704
10738
  }
10705
10739
  }
10706
10740
  function deletePortFile(instanceKey) {
10707
10741
  try {
10708
- unlinkSync11(join17(managerHost.portsDir, portFileName(instanceKey)));
10742
+ unlinkSync11(join18(managerHost.portsDir, portFileName(instanceKey)));
10709
10743
  } catch (e) {
10710
10744
  if (e.code === "ENOENT")
10711
10745
  return;
@@ -12251,32 +12285,32 @@ __export(exports_wiki, {
12251
12285
  getSharedWikiDir: () => getSharedWikiDir
12252
12286
  });
12253
12287
  import { existsSync as existsSync17, readdirSync as readdirSync3, statSync as statSync6 } from "fs";
12254
- import { basename as basename2, dirname as dirname12, join as join18 } from "path";
12288
+ import { basename as basename2, dirname as dirname12, join as join19 } from "path";
12255
12289
  function getWikiDir(_userId, workspaceDir = resolveStorageWorkspaceDir()) {
12256
- return join18(workspaceDir, "wiki");
12290
+ return join19(workspaceDir, "wiki");
12257
12291
  }
12258
12292
  function getSharedWikiDir(workspaceDir = resolveStorageWorkspaceDir()) {
12259
- return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() : join18(workspaceDir, "wiki");
12293
+ return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() : join19(workspaceDir, "wiki");
12260
12294
  }
12261
12295
  function findLatestSummaryFile(wikiDir, safeTopic) {
12262
- const summariesDir = join18(wikiDir, "summaries");
12296
+ const summariesDir = join19(wikiDir, "summaries");
12263
12297
  if (!existsSync17(summariesDir))
12264
12298
  return null;
12265
12299
  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) => {
12266
- const mtimeDelta = statSync6(join18(summariesDir, right)).mtimeMs - statSync6(join18(summariesDir, left)).mtimeMs;
12300
+ const mtimeDelta = statSync6(join19(summariesDir, right)).mtimeMs - statSync6(join19(summariesDir, left)).mtimeMs;
12267
12301
  return mtimeDelta || right.localeCompare(left, undefined, { numeric: true });
12268
12302
  });
12269
- return files.length > 0 ? join18(summariesDir, files[0]) : null;
12303
+ return files.length > 0 ? join19(summariesDir, files[0]) : null;
12270
12304
  }
12271
12305
  function getTopicMemoryFilePaths(_userId, topicName, forkOrigin, workspaceDir = resolveStorageWorkspaceDir()) {
12272
12306
  const wikiDir = getSharedWikiDir(workspaceDir);
12273
12307
  const resolveBrief = (name) => {
12274
12308
  const safe = sanitizeTopicName(name, true);
12275
- const brief = join18(wikiDir, "topic", `${safe}.md`);
12309
+ const brief = join19(wikiDir, "topic", `${safe}.md`);
12276
12310
  const latestSummary = findLatestSummaryFile(wikiDir, safe);
12277
12311
  return { brief, latestSummary };
12278
12312
  };
12279
- const archiveDir = join18(wikiDir, "archive");
12313
+ const archiveDir = join19(wikiDir, "archive");
12280
12314
  const archiveExistsFor = (name) => {
12281
12315
  const safe = sanitizeTopicName(name);
12282
12316
  return existsSync17(archiveDir) && readdirSync3(archiveDir).some((f) => f.endsWith(".jsonl") && f.startsWith(`${safe}_`));
@@ -12293,7 +12327,7 @@ function getTopicMemoryFilePaths(_userId, topicName, forkOrigin, workspaceDir =
12293
12327
  };
12294
12328
  }
12295
12329
  return {
12296
- memoryDir: join18(wikiDir, "topic"),
12330
+ memoryDir: join19(wikiDir, "topic"),
12297
12331
  memoryFiles: [],
12298
12332
  ...target.latestSummary ? { latestSummaryFile: target.latestSummary } : {},
12299
12333
  ...hasArchive ? { hasArchive: true } : {}
@@ -12306,7 +12340,7 @@ var init_wiki = __esm(async () => {
12306
12340
  // ../../packages/core/src/agents/archiver.ts
12307
12341
  import { randomUUID as randomUUID10 } from "crypto";
12308
12342
  import { existsSync as existsSync18, readdirSync as readdirSync4, readFileSync as readFileSync14, statSync as statSync7 } from "fs";
12309
- import { join as join19 } from "path";
12343
+ import { join as join20 } from "path";
12310
12344
  function resolveMemoryLanguage() {
12311
12345
  const override = process.env.NEGOTIUM_MEMORY_LANG?.trim();
12312
12346
  return override && override.length > 0 ? override : resolveOutputLanguage();
@@ -12557,10 +12591,10 @@ function distillOneLine(summaryMd) {
12557
12591
  return "";
12558
12592
  }
12559
12593
  function findSummaryFile(storage, topicTitle, date, sinceMs, topicId) {
12560
- const dir = join19(storage.getWikiDir(), "summaries");
12594
+ const dir = join20(storage.getWikiDir(), "summaries");
12561
12595
  if (!storage.fileExists(dir))
12562
12596
  return null;
12563
- const predicted = join19(dir, wikiSummaryFilename(date, topicTitle, topicId));
12597
+ const predicted = join20(dir, wikiSummaryFilename(date, topicTitle, topicId));
12564
12598
  if (storage.fileExists(predicted) && storage.fileModifiedAt(predicted) >= sinceMs)
12565
12599
  return predicted;
12566
12600
  let best = null;
@@ -12568,7 +12602,7 @@ function findSummaryFile(storage, topicTitle, date, sinceMs, topicId) {
12568
12602
  if (!f.startsWith(`${date}-`) || !isTopicSummaryFile(f, topicId ?? "", topicTitle)) {
12569
12603
  continue;
12570
12604
  }
12571
- const p = join19(dir, f);
12605
+ const p = join20(dir, f);
12572
12606
  try {
12573
12607
  const m = storage.fileModifiedAt(p);
12574
12608
  if (m >= sinceMs && (!best || m > best.mtime))
@@ -12784,13 +12818,13 @@ __export(exports_topic_archive, {
12784
12818
  archiveConversationEvents: () => archiveConversationEvents
12785
12819
  });
12786
12820
  import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync9 } from "fs";
12787
- import { join as join20 } from "path";
12821
+ import { join as join21 } from "path";
12788
12822
  function archiveTopicMessages(topicId, topicTitle, options = {}) {
12789
12823
  const rows = options.afterRowid !== undefined ? getMessagesForTopicAfterRowid(topicId, options.afterRowid) : getAllMessagesForTopic(topicId);
12790
12824
  if (rows.length === 0)
12791
12825
  return null;
12792
12826
  const safeTopic = sanitizeTopicName(topicTitle, true);
12793
- const archiveDir = join20(getSharedWikiDir(), "archive");
12827
+ const archiveDir = join21(getSharedWikiDir(), "archive");
12794
12828
  mkdirSync11(archiveDir, { recursive: true });
12795
12829
  const date = new Date().toISOString().slice(0, 10);
12796
12830
  const reasonSuffix = options.reason && options.reason !== "delete" ? `_${options.reason}` : "";
@@ -12803,7 +12837,7 @@ function archiveTopicMessages(topicId, topicTitle, options = {}) {
12803
12837
  let path;
12804
12838
  while (true) {
12805
12839
  filename = `${safeTopic}_${date}${reasonSuffix}${counter === 1 ? "" : `_${counter}`}.jsonl`;
12806
- path = join20(archiveDir, filename);
12840
+ path = join21(archiveDir, filename);
12807
12841
  try {
12808
12842
  writeFileSync9(path, body, { flag: "wx" });
12809
12843
  break;
@@ -12848,7 +12882,7 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
12848
12882
  const entries = readRawConversation(userId, topicTitle);
12849
12883
  if (entries.length === 0)
12850
12884
  return null;
12851
- const archiveDir = join20(getSharedWikiDir(), "archive");
12885
+ const archiveDir = join21(getSharedWikiDir(), "archive");
12852
12886
  mkdirSync11(archiveDir, { recursive: true });
12853
12887
  const safeTopic = sanitizeTopicName(topicTitle, true);
12854
12888
  const date = new Date().toISOString().slice(0, 10);
@@ -12876,7 +12910,7 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
12876
12910
  let counter = 1;
12877
12911
  while (true) {
12878
12912
  const suffix = counter === 1 ? "" : `_${counter}`;
12879
- const path = join20(archiveDir, `${safeTopic}_${date}${reasonSuffix}_events${suffix}.jsonl`);
12913
+ const path = join21(archiveDir, `${safeTopic}_${date}${reasonSuffix}_events${suffix}.jsonl`);
12880
12914
  try {
12881
12915
  writeFileSync9(path, body, { flag: "wx" });
12882
12916
  logger.info({ topicId, topicTitle, archive: path, eventCount: entries.length }, "archiveConversationEvents: archived raw conversation events");
@@ -13887,7 +13921,7 @@ var init_runtime_turn_requests = __esm(async () => {
13887
13921
  import { randomUUID as randomUUID11 } from "crypto";
13888
13922
  import { mkdtempSync as mkdtempSync2, rmSync as rmSync4, writeFileSync as writeFileSync11 } from "fs";
13889
13923
  import { tmpdir as tmpdir4 } from "os";
13890
- import { join as join21 } from "path";
13924
+ import { join as join22 } from "path";
13891
13925
  async function waitForMemoryArchive(settled, timeoutMs) {
13892
13926
  let timer;
13893
13927
  try {
@@ -14140,7 +14174,7 @@ function formatCompactElapsed(startedAt) {
14140
14174
  async function summarizeTopicContext(request) {
14141
14175
  const startedAt = Date.now();
14142
14176
  const sessionIds = [];
14143
- const compactCwd = mkdtempSync2(join21(tmpdir4(), "negotium-compact-"));
14177
+ const compactCwd = mkdtempSync2(join22(tmpdir4(), "negotium-compact-"));
14144
14178
  const abortController = new AbortController;
14145
14179
  const relayAbort = () => abortController.abort(request.signal?.reason);
14146
14180
  if (request.signal?.aborted)
@@ -14167,7 +14201,7 @@ async function summarizeTopicContext(request) {
14167
14201
  let error = "";
14168
14202
  let toolViolation = false;
14169
14203
  let compactionLogCalls = 0;
14170
- const compactionLogPath = join21(compactCwd, "conversation.log");
14204
+ const compactionLogPath = join22(compactCwd, "conversation.log");
14171
14205
  try {
14172
14206
  const compactionMcp = useCompactionLog ? {
14173
14207
  compact_log: {
@@ -15488,14 +15522,14 @@ var init_self_config = __esm(async () => {
15488
15522
  });
15489
15523
 
15490
15524
  // ../../packages/core/src/query/session-inbox-path.ts
15491
- import { join as join22 } from "path";
15525
+ import { join as join23 } from "path";
15492
15526
  function sessionInboxPath(userId, topicId) {
15493
15527
  const key = Buffer.from(topicId, "utf8").toString("base64url");
15494
- return join22(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${JSONL_SUFFIX}`);
15528
+ return join23(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${JSONL_SUFFIX}`);
15495
15529
  }
15496
15530
  function scheduledSessionInboxPath(userId, topicId) {
15497
15531
  const key = Buffer.from(topicId, "utf8").toString("base64url");
15498
- return join22(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${SCHEDULE_SUFFIX}`);
15532
+ return join23(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${SCHEDULE_SUFFIX}`);
15499
15533
  }
15500
15534
  function decodeTopicIdFileName(fileName, suffix) {
15501
15535
  if (!fileName.startsWith(TOPIC_ID_FILE_PREFIX) || !fileName.endsWith(suffix))
@@ -15523,13 +15557,13 @@ var init_session_inbox_path = __esm(() => {
15523
15557
 
15524
15558
  // ../../packages/core/src/query/session-inbox-cleanup.ts
15525
15559
  import { unlinkSync as unlinkSync14 } from "fs";
15526
- import { basename as basename3, join as join23 } from "path";
15560
+ import { basename as basename3, join as join24 } from "path";
15527
15561
  function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
15528
15562
  const live = sessionInboxPath(userId, topicId);
15529
15563
  const scheduled = scheduledSessionInboxPath(userId, topicId);
15530
15564
  const candidates = new Set([live, `${live}.processing`, scheduled, `${scheduled}.processing`]);
15531
15565
  if (legacyTopicTitle && legacyTopicTitle !== "." && legacyTopicTitle !== ".." && basename3(legacyTopicTitle) === legacyTopicTitle) {
15532
- const legacyBase = join23(SESSION_INBOX_DIR, userId, legacyTopicTitle);
15566
+ const legacyBase = join24(SESSION_INBOX_DIR, userId, legacyTopicTitle);
15533
15567
  for (const suffix of [".jsonl", ".jsonl.processing", ".schedule", ".schedule.processing"]) {
15534
15568
  candidates.add(`${legacyBase}${suffix}`);
15535
15569
  }
@@ -15555,16 +15589,16 @@ var init_session_inbox_cleanup = __esm(() => {
15555
15589
 
15556
15590
  // ../../packages/core/src/query/state.ts
15557
15591
  import { mkdirSync as mkdirSync14, renameSync as renameSync7, unlinkSync as unlinkSync15, writeFileSync as writeFileSync12 } from "fs";
15558
- import { basename as basename4, join as join24 } from "path";
15592
+ import { basename as basename4, join as join25 } from "path";
15559
15593
  function createQueryStateStore(options) {
15560
15594
  const sanitize = options.sanitizeTopicId ?? sanitizeId;
15561
- const queryStateDirPath = (userId) => join24(options.usersLogDir, String(userId), "active-queries");
15562
- const queryStateFile = (userId, topicId) => join24(queryStateDirPath(userId), `${sanitize(topicId)}.json`);
15595
+ const queryStateDirPath = (userId) => join25(options.usersLogDir, String(userId), "active-queries");
15596
+ const queryStateFile = (userId, topicId) => join25(queryStateDirPath(userId), `${sanitize(topicId)}.json`);
15563
15597
  const legacyQueryStateFile = (userId, topicName) => {
15564
15598
  if (!topicName || topicName === "." || topicName === ".." || basename4(topicName) !== topicName) {
15565
15599
  return null;
15566
15600
  }
15567
- return join24(queryStateDirPath(userId), `${topicName}.json`);
15601
+ return join25(queryStateDirPath(userId), `${topicName}.json`);
15568
15602
  };
15569
15603
  return {
15570
15604
  write(userId, topicId, topicName, task) {
@@ -15725,29 +15759,29 @@ import {
15725
15759
  unlinkSync as unlinkSync16,
15726
15760
  writeFileSync as writeFileSync13
15727
15761
  } from "fs";
15728
- import { dirname as dirname14, join as join25 } from "path";
15762
+ import { dirname as dirname14, join as join26 } from "path";
15729
15763
  function pendingAskDir(userId) {
15730
15764
  const rawUserId = String(userId);
15731
15765
  const safeUserId = /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash6("sha256").update(rawUserId).digest("hex")}`;
15732
- return join25(resolveStorageSessionAsksDir(), safeUserId);
15766
+ return join26(resolveStorageSessionAsksDir(), safeUserId);
15733
15767
  }
15734
15768
  function encodeAskKey(key) {
15735
15769
  return JSON.stringify([key.from, key.to]);
15736
15770
  }
15737
15771
  function pendingAskPath(key) {
15738
15772
  const digest = createHash6("sha256").update(encodeAskKey(key)).digest("hex");
15739
- return join25(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
15773
+ return join26(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
15740
15774
  }
15741
15775
  function v2PendingAskPath(key) {
15742
15776
  const encoded = Buffer.from(encodeAskKey(key), "utf8").toString("base64url");
15743
- return join25(pendingAskDir(key.userId), `${V2_ASK_FILENAME_PREFIX}${encoded}.pending`);
15777
+ return join26(pendingAskDir(key.userId), `${V2_ASK_FILENAME_PREFIX}${encoded}.pending`);
15744
15778
  }
15745
15779
  function legacyPendingAskPath(key) {
15746
15780
  if (key.from.includes("/") || key.from.includes("\\") || key.to.includes("/") || key.to.includes("\\") || key.from.includes("\x00") || key.to.includes("\x00")) {
15747
15781
  return null;
15748
15782
  }
15749
15783
  const dir = pendingAskDir(key.userId);
15750
- const candidate = join25(dir, `${key.from}___${key.to}.pending`);
15784
+ const candidate = join26(dir, `${key.from}___${key.to}.pending`);
15751
15785
  return dirname14(candidate) === dir ? candidate : null;
15752
15786
  }
15753
15787
  function parsePendingAskFilename(fileName) {
@@ -15988,7 +16022,7 @@ function listPendingAsksForCaller(args) {
15988
16022
  const parsed = isV3 ? { from: args.from, to: "" } : parsePendingAskFilename(fileName);
15989
16023
  if (!parsed)
15990
16024
  continue;
15991
- const path = join25(dir, fileName);
16025
+ const path = join26(dir, fileName);
15992
16026
  const record = readPendingAskFile(path, {
15993
16027
  userId: args.userId,
15994
16028
  from: parsed.from,
@@ -16030,7 +16064,7 @@ function deletePendingAsksForTopic(args) {
16030
16064
  }
16031
16065
  let deleted = 0;
16032
16066
  for (const fileName of files) {
16033
- const path = join25(dir, fileName);
16067
+ const path = join26(dir, fileName);
16034
16068
  const parsed = parsePendingAskFilename(fileName);
16035
16069
  const record = readPendingAskFile(path, {
16036
16070
  userId: args.userId,
@@ -16448,7 +16482,7 @@ __export(exports_token_stats, {
16448
16482
  });
16449
16483
  import { createHash as createHash7 } from "crypto";
16450
16484
  import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "fs";
16451
- import { join as join26 } from "path";
16485
+ import { join as join27 } from "path";
16452
16486
  function emptyBucket() {
16453
16487
  return {
16454
16488
  inputTokens: 0,
@@ -16467,7 +16501,7 @@ function queriesPath(userId) {
16467
16501
  const fileId = tokenStatsFileId(userId);
16468
16502
  const logDir = resolveStorageLogDir();
16469
16503
  mkdirSync16(logDir, { recursive: true });
16470
- return join26(logDir, `token-queries-${fileId}.jsonl`);
16504
+ return join27(logDir, `token-queries-${fileId}.jsonl`);
16471
16505
  }
16472
16506
  function loadRecords(userId) {
16473
16507
  try {
@@ -16896,7 +16930,7 @@ var init_lifecycle = __esm(async () => {
16896
16930
  // ../../packages/core/src/runtime/attachments.ts
16897
16931
  import { randomUUID as randomUUID14 } from "crypto";
16898
16932
  import { copyFileSync as copyFileSync2, mkdirSync as mkdirSync17, writeFileSync as writeFileSync15 } from "fs";
16899
- import { basename as basename5, join as join27 } from "path";
16933
+ import { basename as basename5, join as join28 } from "path";
16900
16934
  function workspaceCwdFor(topicId) {
16901
16935
  return resolveTopicWorkspaceDir(topicId);
16902
16936
  }
@@ -16909,7 +16943,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
16909
16943
  if (!attachmentIds?.length)
16910
16944
  return [];
16911
16945
  const out = [];
16912
- const destDir = join27(workspaceCwdFor(topicId), "attachments", queryId);
16946
+ const destDir = join28(workspaceCwdFor(topicId), "attachments", queryId);
16913
16947
  for (const rawId of attachmentIds) {
16914
16948
  if (typeof rawId !== "string")
16915
16949
  continue;
@@ -16926,7 +16960,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
16926
16960
  mkdirSync17(destDir, { recursive: true });
16927
16961
  const index = String(out.length + 1).padStart(2, "0");
16928
16962
  const safeName = safeAttachmentFilename(attachment.filename, fileId);
16929
- const destPath = join27(destDir, `${index}-${fileId.slice(0, 8)}-${safeName}`);
16963
+ const destPath = join28(destDir, `${index}-${fileId.slice(0, 8)}-${safeName}`);
16930
16964
  copyFileSync2(sourcePath, destPath);
16931
16965
  out.push({
16932
16966
  id: attachment.id,
@@ -16956,10 +16990,10 @@ function promptWithAttachments(prompt, attachments) {
16956
16990
  return composeAttachmentPrompt(prompt, attachments.map(({ filename, path }) => attachmentPromptLine(filename, path)));
16957
16991
  }
16958
16992
  function ingestAttachment(args) {
16959
- const destDir = join27(UPLOADS_DIR, args.topicId);
16993
+ const destDir = join28(UPLOADS_DIR, args.topicId);
16960
16994
  mkdirSync17(destDir, { recursive: true });
16961
16995
  const safeName = safeAttachmentFilename(args.filename, "upload");
16962
- const destPath = join27(destDir, `${Date.now()}-${randomUUID14().slice(0, 8)}-${safeName}`);
16996
+ const destPath = join28(destDir, `${Date.now()}-${randomUUID14().slice(0, 8)}-${safeName}`);
16963
16997
  if (args.sourcePath !== undefined) {
16964
16998
  copyFileSync2(args.sourcePath, destPath);
16965
16999
  } else if (args.bytes !== undefined) {
@@ -18270,9 +18304,9 @@ __export(exports_app_settings, {
18270
18304
  DEFAULT_AI_NAME: () => DEFAULT_AI_NAME
18271
18305
  });
18272
18306
  import { existsSync as existsSync19, mkdirSync as mkdirSync18, readFileSync as readFileSync16, writeFileSync as writeFileSync16 } from "fs";
18273
- import { dirname as dirname15, join as join28 } from "path";
18307
+ import { dirname as dirname15, join as join29 } from "path";
18274
18308
  function settingsFile() {
18275
- return join28(resolveStorageDataDir(), "otium-settings.json");
18309
+ return join29(resolveStorageDataDir(), "otium-settings.json");
18276
18310
  }
18277
18311
  function getGlobalAiName() {
18278
18312
  const path = settingsFile();
@@ -18376,7 +18410,7 @@ __export(exports_turn_runner, {
18376
18410
  });
18377
18411
  import { randomUUID as randomUUID16 } from "crypto";
18378
18412
  import { existsSync as existsSync20, mkdirSync as mkdirSync19, readdirSync as readdirSync6, statSync as statSync10 } from "fs";
18379
- import { join as join29 } from "path";
18413
+ import { join as join30 } from "path";
18380
18414
  function withDefaultPlaywright(configuredMcp, isManager) {
18381
18415
  if (isManager)
18382
18416
  return configuredMcp;
@@ -18431,7 +18465,7 @@ function appendAskReplyMessage(topicId, text2, agentType) {
18431
18465
  return message;
18432
18466
  }
18433
18467
  function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, matchesTitle, preferExact = true) {
18434
- const preferred = join29(directory, preferredFilename);
18468
+ const preferred = join30(directory, preferredFilename);
18435
18469
  if (preferExact && existsSync20(preferred))
18436
18470
  return preferred;
18437
18471
  let newestLegacyId = null;
@@ -18442,7 +18476,7 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
18442
18476
  const legacyIdMatch = !titleMatch && matchesLegacyId(filename);
18443
18477
  if (!titleMatch && !legacyIdMatch)
18444
18478
  continue;
18445
- const path = join29(directory, filename);
18479
+ const path = join30(directory, filename);
18446
18480
  const mtimeMs = statSync10(path).mtimeMs;
18447
18481
  if (titleMatch) {
18448
18482
  if (!newestTitle || mtimeMs > newestTitle.mtimeMs) {
@@ -18456,9 +18490,9 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
18456
18490
  return newestTitle?.path ?? newestLegacyId?.path ?? preferred;
18457
18491
  }
18458
18492
  function resolveWikiMemoryMirror(wikiDir, topicId, topicTitle) {
18459
- const briefFile = resolveWikiMirrorPath(join29(wikiDir, "topic"), `${wikiBriefStorageKey(topicTitle, topicId)}.md`, (filename) => isTopicBriefFile(filename, topicId), (filename) => isTopicBriefFile(filename, topicId, topicTitle));
18493
+ const briefFile = resolveWikiMirrorPath(join30(wikiDir, "topic"), `${wikiBriefStorageKey(topicTitle, topicId)}.md`, (filename) => isTopicBriefFile(filename, topicId), (filename) => isTopicBriefFile(filename, topicId, topicTitle));
18460
18494
  const hasBriefFile = existsSync20(briefFile) && statSync10(briefFile).isFile();
18461
- const latestSummaryCandidate = resolveWikiMirrorPath(join29(wikiDir, "summaries"), `__missing__-${wikiSummaryFilename("0000-00-00", topicTitle, topicId)}`, (filename) => isTopicSummaryFile(filename, topicId), (filename) => isTopicSummaryFile(filename, topicId, topicTitle), false);
18495
+ const latestSummaryCandidate = resolveWikiMirrorPath(join30(wikiDir, "summaries"), `__missing__-${wikiSummaryFilename("0000-00-00", topicTitle, topicId)}`, (filename) => isTopicSummaryFile(filename, topicId), (filename) => isTopicSummaryFile(filename, topicId, topicTitle), false);
18462
18496
  const latestSummaryFile = existsSync20(latestSummaryCandidate) && statSync10(latestSummaryCandidate).isFile() ? latestSummaryCandidate : null;
18463
18497
  return { briefFile, hasBriefFile, latestSummaryFile };
18464
18498
  }
@@ -21208,7 +21242,7 @@ var init_vault_command = __esm(async () => {
21208
21242
  import { execFile } from "child_process";
21209
21243
  import { existsSync as existsSync21, mkdirSync as mkdirSync21, readFileSync as readFileSync17, rmSync as rmSync7 } from "fs";
21210
21244
  import { readFile } from "fs/promises";
21211
- import { extname, join as join30 } from "path";
21245
+ import { extname, join as join31 } from "path";
21212
21246
  import { promisify } from "util";
21213
21247
  async function extractText(filePath) {
21214
21248
  const ext = extname(filePath).toLowerCase();
@@ -21325,7 +21359,7 @@ async function extractFromAudio(filePath, opts = {}) {
21325
21359
  const tmpDir = `${filePath}_whisper_tmp`;
21326
21360
  try {
21327
21361
  mkdirSync21(tmpDir, { recursive: true });
21328
- const mp3Path = join30(tmpDir, "audio.mp3");
21362
+ const mp3Path = join31(tmpDir, "audio.mp3");
21329
21363
  await execFileAsync(opts.ffmpegBin ?? FFMPEG_BIN2, [
21330
21364
  "-y",
21331
21365
  "-i",
@@ -21352,7 +21386,7 @@ async function extractFromAudio(filePath, opts = {}) {
21352
21386
  "--output-format",
21353
21387
  "txt"
21354
21388
  ], { timeout: 120000 });
21355
- const txtPath = join30(tmpDir, "audio.txt");
21389
+ const txtPath = join31(tmpDir, "audio.txt");
21356
21390
  const text2 = existsSync21(txtPath) ? readFileSync17(txtPath, "utf-8").trim() : null;
21357
21391
  if (!text2) {
21358
21392
  return { text: null, method: "whisper", error: "Whisper produced no text" };
@@ -21525,7 +21559,7 @@ var init_lifecycle2 = __esm(() => {
21525
21559
 
21526
21560
  // ../../packages/core/src/platform/log-rotation.ts
21527
21561
  import { existsSync as existsSync22, renameSync as renameSync8, statSync as statSync11 } from "fs";
21528
- import { join as join31 } from "path";
21562
+ import { join as join32 } from "path";
21529
21563
  function rotateOversizedLog(logPath, maxBytes = DEFAULT_DAEMON_LOG_ROTATE_BYTES) {
21530
21564
  try {
21531
21565
  if (!existsSync22(logPath))
@@ -21534,9 +21568,9 @@ function rotateOversizedLog(logPath, maxBytes = DEFAULT_DAEMON_LOG_ROTATE_BYTES)
21534
21568
  if (size < maxBytes)
21535
21569
  return;
21536
21570
  const stamp = new Date().toISOString().replace(/[:.]/g, "-");
21537
- const dir = join31(logPath, "..");
21571
+ const dir = join32(logPath, "..");
21538
21572
  const base = logPath.slice(dir.length + 1);
21539
- renameSync8(logPath, join31(dir, `${base}.${stamp}`));
21573
+ renameSync8(logPath, join32(dir, `${base}.${stamp}`));
21540
21574
  } catch {}
21541
21575
  }
21542
21576
  var DEFAULT_DAEMON_LOG_ROTATE_BYTES;
@@ -21729,7 +21763,7 @@ import {
21729
21763
  rmSync as rmSync8,
21730
21764
  statSync as statSync12
21731
21765
  } from "fs";
21732
- import { join as join32 } from "path";
21766
+ import { join as join33 } from "path";
21733
21767
  function setBashrsCompletionSink(sink) {
21734
21768
  completionSink = sink ?? defaultSink;
21735
21769
  }
@@ -21756,15 +21790,15 @@ function readTail(filePath) {
21756
21790
  }
21757
21791
  }
21758
21792
  function buildMessage(dir, result) {
21759
- const stdout = readTail(join32(dir, "stdout.log"));
21760
- const stderr = readTail(join32(dir, "stderr.log"));
21793
+ const stdout = readTail(join33(dir, "stdout.log"));
21794
+ const stderr = readTail(join33(dir, "stderr.log"));
21761
21795
  const parts = [];
21762
21796
  if (stdout.text.trim() || stdout.truncated) {
21763
- parts.push(`stdout${stdout.truncated ? ` (truncated, full output: ${join32(dir, "stdout.log")})` : ""}:
21797
+ parts.push(`stdout${stdout.truncated ? ` (truncated, full output: ${join33(dir, "stdout.log")})` : ""}:
21764
21798
  ${stdout.text.trim()}`);
21765
21799
  }
21766
21800
  if (stderr.text.trim() || stderr.truncated) {
21767
- parts.push(`stderr${stderr.truncated ? ` (truncated, full output: ${join32(dir, "stderr.log")})` : ""}:
21801
+ parts.push(`stderr${stderr.truncated ? ` (truncated, full output: ${join33(dir, "stderr.log")})` : ""}:
21768
21802
  ${stderr.text.trim()}`);
21769
21803
  }
21770
21804
  const header = watchHeader(result) ?? `[background_bash ${result.bash_id} finished]`;
@@ -21798,7 +21832,7 @@ function parseOwner(owner) {
21798
21832
  return { userId, topicId };
21799
21833
  }
21800
21834
  function injectedMarker(dir) {
21801
- return join32(dir, "result.json.injected");
21835
+ return join33(dir, "result.json.injected");
21802
21836
  }
21803
21837
  async function flushBashrsCompletions() {
21804
21838
  let entries;
@@ -21809,8 +21843,8 @@ async function flushBashrsCompletions() {
21809
21843
  }
21810
21844
  const now = Date.now();
21811
21845
  for (const bashId of entries) {
21812
- const dir = join32(BASHRS_SPILL_ROOT, bashId);
21813
- const resultPath = join32(dir, "result.json");
21846
+ const dir = join33(BASHRS_SPILL_ROOT, bashId);
21847
+ const resultPath = join33(dir, "result.json");
21814
21848
  const marker = injectedMarker(dir);
21815
21849
  try {
21816
21850
  const markerStat = statSync12(marker);
@@ -22108,7 +22142,7 @@ var init_file_ops = __esm(() => {
22108
22142
  // ../../packages/core/src/runtime/inbox.ts
22109
22143
  import { createHash as createHash9, randomUUID as randomUUID20 } from "crypto";
22110
22144
  import { readdirSync as readdirSync8, statSync as statSync13, writeFileSync as writeFileSync17 } from "fs";
22111
- import { join as join33 } from "path";
22145
+ import { join as join34 } from "path";
22112
22146
  async function createAskForkPlan(options) {
22113
22147
  const snapshot = structuredClone(options.entries);
22114
22148
  const prepareSession = async () => options.synthesize(structuredClone(snapshot));
@@ -22248,7 +22282,7 @@ async function flushSessionInbox() {
22248
22282
  return;
22249
22283
  }
22250
22284
  for (const uid of userDirs) {
22251
- const userInboxDir = join33(SESSION_INBOX_DIR, uid);
22285
+ const userInboxDir = join34(SESSION_INBOX_DIR, uid);
22252
22286
  let entries;
22253
22287
  try {
22254
22288
  entries = readdirSync8(userInboxDir);
@@ -22256,7 +22290,7 @@ async function flushSessionInbox() {
22256
22290
  continue;
22257
22291
  }
22258
22292
  for (const entry of entries) {
22259
- const entryPath = join33(userInboxDir, entry);
22293
+ const entryPath = join34(userInboxDir, entry);
22260
22294
  let isDir = false;
22261
22295
  try {
22262
22296
  isDir = statSync13(entryPath).isDirectory();
@@ -22346,7 +22380,7 @@ function sweepScheduledSessionInbox(nowMs = Date.now()) {
22346
22380
  return;
22347
22381
  }
22348
22382
  for (const userId of userDirs) {
22349
- const userInboxDir = join33(SESSION_INBOX_DIR, userId);
22383
+ const userInboxDir = join34(SESSION_INBOX_DIR, userId);
22350
22384
  let files;
22351
22385
  try {
22352
22386
  files = readdirSync8(userInboxDir);
@@ -22358,7 +22392,7 @@ function sweepScheduledSessionInbox(nowMs = Date.now()) {
22358
22392
  const topicId = topicIdFromScheduledSessionInboxFileName(file);
22359
22393
  if (!topicId)
22360
22394
  continue;
22361
- const schedulePath = join33(userInboxDir, file);
22395
+ const schedulePath = join34(userInboxDir, file);
22362
22396
  const hasProcessingClaim = files.includes(`${file}.processing`);
22363
22397
  if (!hasProcessingClaim && !scheduledFileNeedsClaim(schedulePath, nowMs))
22364
22398
  continue;
@@ -23195,7 +23229,7 @@ var init_src = __esm(async () => {
23195
23229
 
23196
23230
  // ../../packages/core/src/storage/conversation-migration.ts
23197
23231
  import { copyFileSync as copyFileSync3, existsSync as existsSync24, mkdirSync as mkdirSync23, readFileSync as readFileSync20 } from "fs";
23198
- import { dirname as dirname16, join as join34 } from "path";
23232
+ import { dirname as dirname16, join as join35 } from "path";
23199
23233
  function readEntries(path) {
23200
23234
  const entries = [];
23201
23235
  for (const [index, line] of readFileSync20(path, "utf8").split(`
@@ -23262,7 +23296,7 @@ function migrateLegacyCompactedConversations() {
23262
23296
  result.skipped++;
23263
23297
  continue;
23264
23298
  }
23265
- const backupPath = join34(resolveStorageDataDir(), "conversation-migration-backups", MIGRATION_NAME, userId, `${sanitizeTopicName(topic.title, true)}.jsonl`);
23299
+ const backupPath = join35(resolveStorageDataDir(), "conversation-migration-backups", MIGRATION_NAME, userId, `${sanitizeTopicName(topic.title, true)}.jsonl`);
23266
23300
  const sourcePath = existsSync24(backupPath) ? backupPath : rawPath;
23267
23301
  const legacyEntries = readEntries(sourcePath);
23268
23302
  const compactIndex = compactionEntryIndex(legacyEntries);
@@ -23322,7 +23356,7 @@ __export(exports_decisions, {
23322
23356
  DECISION_STATUS_VALUES: () => DECISION_STATUS_VALUES
23323
23357
  });
23324
23358
  import { existsSync as existsSync25, mkdirSync as mkdirSync24, readFileSync as readFileSync21, renameSync as renameSync11, writeFileSync as writeFileSync18 } from "fs";
23325
- import { dirname as dirname17, join as join35 } from "path";
23359
+ import { dirname as dirname17, join as join36 } from "path";
23326
23360
  function safeDecisionScopeKey(scopeKey) {
23327
23361
  const safe = sanitizeFileName(scopeKey);
23328
23362
  if (!safe || safe === "." || safe === "..") {
@@ -23334,10 +23368,10 @@ function decisionScopeKey(opts) {
23334
23368
  return opts.topicId?.trim() || opts.session || "default";
23335
23369
  }
23336
23370
  function getDecisionFilePath(userId, scopeKey) {
23337
- return join35(resolveStorageDataDir(), "decisions", `${safeDecisionScopeKey(scopeKey)}.json`);
23371
+ return join36(resolveStorageDataDir(), "decisions", `${safeDecisionScopeKey(scopeKey)}.json`);
23338
23372
  }
23339
23373
  function getDecisionGraphSvgPath(userId, scopeKey) {
23340
- return join35(resolveStorageDataDir(), "decision-renders", safeDecisionScopeKey(scopeKey), "latest.svg");
23374
+ return join36(resolveStorageDataDir(), "decision-renders", safeDecisionScopeKey(scopeKey), "latest.svg");
23341
23375
  }
23342
23376
  function writeDecisionGraphSvg(userId, scopeKey, svg) {
23343
23377
  const path = getDecisionGraphSvgPath(userId, scopeKey);
@@ -24597,7 +24631,7 @@ __export(exports_agent_health, {
24597
24631
  });
24598
24632
  import { spawn as spawn6 } from "child_process";
24599
24633
  import { existsSync as existsSync27, readdirSync as readdirSync9 } from "fs";
24600
- import { join as join36 } from "path";
24634
+ import { join as join37 } from "path";
24601
24635
  import { McpServer as McpServer5 } from "@modelcontextprotocol/sdk/server/mcp.js";
24602
24636
  import { z as z10 } from "zod";
24603
24637
  function signalProcessTree2(child, signal) {
@@ -24841,7 +24875,7 @@ ${results.every((result) => result.ok) ? "All agents healthy" : "Some agents fai
24841
24875
  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 () => {
24842
24876
  if (!context.userId)
24843
24877
  return mcpOk("\uC2E4\uD589 \uC911\uC778 \uCFFC\uB9AC \uC870\uD68C \uBD88\uAC00 (user context \uC5C6\uC74C)");
24844
- const stateDir = join36(USERS_LOG_DIR, context.userId, "active-queries");
24878
+ const stateDir = join37(USERS_LOG_DIR, context.userId, "active-queries");
24845
24879
  if (!existsSync27(stateDir))
24846
24880
  return mcpOk("\uC2E4\uD589 \uC911\uC778 \uCFFC\uB9AC \uC5C6\uC74C");
24847
24881
  let files;
@@ -24854,7 +24888,7 @@ ${results.every((result) => result.ok) ? "All agents healthy" : "Some agents fai
24854
24888
  const entries = files.flatMap((file) => {
24855
24889
  if (!file.endsWith(".json"))
24856
24890
  return [];
24857
- const state = readJsonFile(join36(stateDir, file));
24891
+ const state = readJsonFile(join37(stateDir, file));
24858
24892
  if (!state)
24859
24893
  return [];
24860
24894
  const sinceMs = new Date(state.since).getTime();
@@ -25087,7 +25121,7 @@ var exports_default_host = {};
25087
25121
  __export(exports_default_host, {
25088
25122
  createDefaultSessionCommMcpHost: () => createDefaultSessionCommMcpHost
25089
25123
  });
25090
- import { basename as basename6, join as join37 } from "path";
25124
+ import { basename as basename6, join as join38 } from "path";
25091
25125
  function ok2(text2) {
25092
25126
  return { content: [{ type: "text", text: text2 }] };
25093
25127
  }
@@ -25134,10 +25168,10 @@ function remoteTarget(context, to) {
25134
25168
  return { node: to.slice(0, slash), topic: to.slice(slash + 1) };
25135
25169
  }
25136
25170
  function activeQuery(context, topicId, title) {
25137
- const dir = join37(USERS_LOG_DIR, context.userId, "active-queries");
25138
- const candidates = [join37(dir, `${sanitizeId(topicId)}.json`)];
25171
+ const dir = join38(USERS_LOG_DIR, context.userId, "active-queries");
25172
+ const candidates = [join38(dir, `${sanitizeId(topicId)}.json`)];
25139
25173
  if (title && basename6(title) === title && title !== "." && title !== "..") {
25140
- candidates.push(join37(dir, `${title}.json`));
25174
+ candidates.push(join38(dir, `${title}.json`));
25141
25175
  }
25142
25176
  for (const path of candidates) {
25143
25177
  const state = readJsonFile(path);
@@ -25686,7 +25720,7 @@ import {
25686
25720
  unlinkSync as unlinkSync19,
25687
25721
  writeFileSync as writeFileSync19
25688
25722
  } from "fs";
25689
- import { basename as basename7, dirname as dirname18, join as join38, relative as relative2, resolve as resolve18 } from "path";
25723
+ import { basename as basename7, dirname as dirname18, join as join39, relative as relative2, resolve as resolve18 } from "path";
25690
25724
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
25691
25725
  import { StdioServerTransport as StdioServerTransport2 } from "@modelcontextprotocol/sdk/server/stdio.js";
25692
25726
  import {
@@ -26136,13 +26170,13 @@ function wikiQuery(args) {
26136
26170
  try {
26137
26171
  for (const entry of readdirSync10(dir, { withFileTypes: true })) {
26138
26172
  if (entry.isDirectory()) {
26139
- const sub = join38(dir, entry.name);
26173
+ const sub = join39(dir, entry.name);
26140
26174
  if (label === "articles" || label === "skills") {
26141
26175
  try {
26142
26176
  for (const f of readdirSync10(sub, { withFileTypes: true })) {
26143
26177
  if (!f.isFile() || !f.name.endsWith(".md"))
26144
26178
  continue;
26145
- const fp = join38(sub, f.name);
26179
+ const fp = join39(sub, f.name);
26146
26180
  try {
26147
26181
  const text2 = readFileSync24(fp, "utf-8");
26148
26182
  const key = `${entry.name}/${f.name.replace(/\.md$/i, "")}`;
@@ -26163,7 +26197,7 @@ function wikiQuery(args) {
26163
26197
  if (label === "topic" && canReadTopicMemory && !canReadTopicMemory(entry.name.replace(/\.md$/i, ""), runtime().userId)) {
26164
26198
  continue;
26165
26199
  }
26166
- const fp = join38(dir, entry.name);
26200
+ const fp = join39(dir, entry.name);
26167
26201
  try {
26168
26202
  const text2 = readFileSync24(fp, "utf-8");
26169
26203
  const key = entry.name.replace(/\.md$/i, "");
@@ -26884,21 +26918,21 @@ function collectIndexableDocuments() {
26884
26918
  }
26885
26919
  for (const entry of entries) {
26886
26920
  if (entry.isFile() && entry.name.endsWith(".md")) {
26887
- add(kind, entry.name.replace(/\.md$/i, ""), join38(root, entry.name));
26921
+ add(kind, entry.name.replace(/\.md$/i, ""), join39(root, entry.name));
26888
26922
  continue;
26889
26923
  }
26890
26924
  if (!entry.isDirectory() || !allowSubdirectories)
26891
26925
  continue;
26892
26926
  let nested;
26893
26927
  try {
26894
- nested = readdirSync10(join38(root, entry.name), { withFileTypes: true });
26928
+ nested = readdirSync10(join39(root, entry.name), { withFileTypes: true });
26895
26929
  } catch {
26896
26930
  continue;
26897
26931
  }
26898
26932
  for (const file of nested) {
26899
26933
  if (!file.isFile() || !file.name.endsWith(".md"))
26900
26934
  continue;
26901
- add(kind, `${entry.name}/${file.name.replace(/\.md$/i, "")}`, join38(root, entry.name, file.name));
26935
+ add(kind, `${entry.name}/${file.name.replace(/\.md$/i, "")}`, join39(root, entry.name, file.name));
26902
26936
  }
26903
26937
  }
26904
26938
  }
@@ -27407,7 +27441,7 @@ import {
27407
27441
  unlinkSync as unlinkSync20,
27408
27442
  writeFileSync as writeFileSync20
27409
27443
  } from "fs";
27410
- import { basename as basename8, join as join39 } from "path";
27444
+ import { basename as basename8, join as join40 } from "path";
27411
27445
  function startLogRotation() {
27412
27446
  if (rotationTimer)
27413
27447
  return;
@@ -27421,7 +27455,7 @@ function writeLog(entry) {
27421
27455
  mkdirSync26(logDir, { recursive: true });
27422
27456
  const safeSession = sanitizeTopicName(entry.session);
27423
27457
  const sidShort = entry.sessionId ? entry.sessionId.slice(0, 8) : "new";
27424
- const file = join39(logDir, `${entry.userId}_${safeSession}_${sidShort}.jsonl`);
27458
+ const file = join40(logDir, `${entry.userId}_${safeSession}_${sidShort}.jsonl`);
27425
27459
  try {
27426
27460
  const stat = statSync16(file);
27427
27461
  if (stat.size >= MAX_FILE_SIZE) {
@@ -27441,7 +27475,7 @@ function rotateOldLogs() {
27441
27475
  try {
27442
27476
  const files = readdirSync11(logDir).filter((f) => f.endsWith(".jsonl")).map((f) => {
27443
27477
  try {
27444
- const stat = statSync16(join39(logDir, f));
27478
+ const stat = statSync16(join40(logDir, f));
27445
27479
  return { name: f, size: stat.size, mtimeMs: stat.mtimeMs };
27446
27480
  } catch {
27447
27481
  return null;
@@ -27457,7 +27491,7 @@ function rotateOldLogs() {
27457
27491
  if (freed >= toFree)
27458
27492
  break;
27459
27493
  try {
27460
- unlinkSync20(join39(logDir, file.name));
27494
+ unlinkSync20(join40(logDir, file.name));
27461
27495
  freed += file.size;
27462
27496
  logger.info({ file: file.name, sizeKB: (file.size / 1024).toFixed(0) }, "Rotated out old log");
27463
27497
  } catch (e) {
@@ -27469,9 +27503,9 @@ function rotateOldLogs() {
27469
27503
  }
27470
27504
  }
27471
27505
  function writeSentFileLog(entry) {
27472
- const dir = join39(resolveStorageUsersLogDir(), String(entry.userId));
27506
+ const dir = join40(resolveStorageUsersLogDir(), String(entry.userId));
27473
27507
  mkdirSync26(dir, { recursive: true });
27474
- const file = join39(dir, "sent-files.jsonl");
27508
+ const file = join40(dir, "sent-files.jsonl");
27475
27509
  try {
27476
27510
  appendJsonlEntry(file, { ...entry, fileName: basename8(entry.filePath) });
27477
27511
  } catch (e) {
@@ -27482,7 +27516,7 @@ function entryMatchesTopic(e, topicName) {
27482
27516
  return e.topicName === topicName;
27483
27517
  }
27484
27518
  function readSentFilesForTopic(userId, topicName) {
27485
- const file = join39(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
27519
+ const file = join40(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
27486
27520
  if (!existsSync30(file))
27487
27521
  return [];
27488
27522
  try {
@@ -27493,7 +27527,7 @@ function readSentFilesForTopic(userId, topicName) {
27493
27527
  }
27494
27528
  }
27495
27529
  function removeSentFilesForTopic(userId, topicName) {
27496
- const file = join39(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
27530
+ const file = join40(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
27497
27531
  if (!existsSync30(file))
27498
27532
  return;
27499
27533
  try {
@@ -28980,11 +29014,11 @@ var init_src2 = __esm(async () => {
28980
29014
  });
28981
29015
 
28982
29016
  // ../../packages/mcp-host/src/paths.ts
28983
- import { homedir as homedir9 } from "os";
29017
+ import { homedir as homedir10 } from "os";
28984
29018
  import { resolve as resolve21 } from "path";
28985
29019
  function stateDir() {
28986
29020
  const env = process.env.NEGOTIUM_STATE_DIR?.trim();
28987
- return env ? resolve21(env) : resolve21(homedir9(), ".negotium");
29021
+ return env ? resolve21(env) : resolve21(homedir10(), ".negotium");
28988
29022
  }
28989
29023
  function defaultPortsDir() {
28990
29024
  return resolve21(stateDir(), "run", "mcp-ports");
@@ -29137,7 +29171,7 @@ import {
29137
29171
  writeFileSync as writeFileSync22
29138
29172
  } from "fs";
29139
29173
  import { connect, createServer as createServer4 } from "net";
29140
- import { join as join40 } from "path";
29174
+ import { join as join41 } from "path";
29141
29175
  function regKey(key, instanceKey) {
29142
29176
  return `${key}\x00${instanceKey}`;
29143
29177
  }
@@ -29439,7 +29473,7 @@ class McpHost {
29439
29473
  if (file.includes(".tmp-"))
29440
29474
  continue;
29441
29475
  try {
29442
- const port = Number.parseInt(readFileSync26(join40(this.portsDir, file), "utf8").trim(), 10);
29476
+ const port = Number.parseInt(readFileSync26(join41(this.portsDir, file), "utf8").trim(), 10);
29443
29477
  if (!Number.isNaN(port))
29444
29478
  claims.set(file, port);
29445
29479
  } catch {}
@@ -29449,7 +29483,7 @@ class McpHost {
29449
29483
  writePortFile(fileName, port) {
29450
29484
  try {
29451
29485
  mkdirSync28(this.portsDir, { recursive: true });
29452
- const file = join40(this.portsDir, fileName);
29486
+ const file = join41(this.portsDir, fileName);
29453
29487
  const tmp = `${file}.tmp-${process.pid}`;
29454
29488
  writeFileSync22(tmp, String(port));
29455
29489
  renameSync15(tmp, file);
@@ -29459,7 +29493,7 @@ class McpHost {
29459
29493
  }
29460
29494
  deletePortFile(fileName) {
29461
29495
  try {
29462
- unlinkSync21(join40(this.portsDir, fileName));
29496
+ unlinkSync21(join41(this.portsDir, fileName));
29463
29497
  } catch {}
29464
29498
  }
29465
29499
  cleanupRunning(rkey, inst) {
@@ -29571,7 +29605,7 @@ import {
29571
29605
  statSync as statSync18,
29572
29606
  writeFileSync as writeFileSync23
29573
29607
  } from "fs";
29574
- import { basename as basename10, extname as extname4, join as join41 } from "path";
29608
+ import { basename as basename10, extname as extname4, join as join42 } from "path";
29575
29609
  function safeExtension(filename) {
29576
29610
  const extension = extname4(basename10(filename));
29577
29611
  return /^\.[A-Za-z0-9]{1,16}$/.test(extension) ? extension.toLowerCase() : "";
@@ -29589,14 +29623,14 @@ function contentDisposition(filename) {
29589
29623
 
29590
29624
  class NodeFileStore {
29591
29625
  uploadDir;
29592
- constructor(uploadDir = join41(DATA_DIR, "uploads")) {
29626
+ constructor(uploadDir = join42(DATA_DIR, "uploads")) {
29593
29627
  this.uploadDir = uploadDir;
29594
29628
  }
29595
29629
  #ensureDir() {
29596
29630
  mkdirSync29(this.uploadDir, { recursive: true });
29597
29631
  }
29598
29632
  #metadataPath(fileId) {
29599
- return join41(this.uploadDir, `${fileId}.meta.json`);
29633
+ return join42(this.uploadDir, `${fileId}.meta.json`);
29600
29634
  }
29601
29635
  #metadata(fileId) {
29602
29636
  if (!FILE_ID_RE.test(fileId))
@@ -29625,7 +29659,7 @@ class NodeFileStore {
29625
29659
  hooks = {
29626
29660
  resolveAttachmentByFileId: (fileId) => {
29627
29661
  const metadata = this.#metadata(fileId);
29628
- if (!metadata || !existsSync32(join41(this.uploadDir, metadata.savedName)))
29662
+ if (!metadata || !existsSync32(join42(this.uploadDir, metadata.savedName)))
29629
29663
  return null;
29630
29664
  return this.#attachment(fileId, metadata);
29631
29665
  },
@@ -29633,7 +29667,7 @@ class NodeFileStore {
29633
29667
  const metadata = this.#metadata(fileId);
29634
29668
  if (!metadata)
29635
29669
  return null;
29636
- const path = join41(this.uploadDir, metadata.savedName);
29670
+ const path = join42(this.uploadDir, metadata.savedName);
29637
29671
  return existsSync32(path) ? path : null;
29638
29672
  },
29639
29673
  storeLocalFileAsUpload: (absPath, access = {}) => this.store(absPath, access),
@@ -29648,11 +29682,11 @@ class NodeFileStore {
29648
29682
  const mimeType = file.type || MIME_BY_EXT2[extension] || "application/octet-stream";
29649
29683
  const existing = this.#metadata(fileId);
29650
29684
  if (existing) {
29651
- const matches = existing.filename === filename && existing.mimeType === mimeType && existing.sizeBytes === file.size && existing.ownerUserId === access.ownerUserId && existing.topicId === access.topicId && existsSync32(join41(this.uploadDir, existing.savedName));
29685
+ const matches = existing.filename === filename && existing.mimeType === mimeType && existing.sizeBytes === file.size && existing.ownerUserId === access.ownerUserId && existing.topicId === access.topicId && existsSync32(join42(this.uploadDir, existing.savedName));
29652
29686
  return matches ? this.#attachment(fileId, existing) : null;
29653
29687
  }
29654
29688
  const savedName = `${fileId}${extension}`;
29655
- const savedPath = join41(this.uploadDir, savedName);
29689
+ const savedPath = join42(this.uploadDir, savedName);
29656
29690
  try {
29657
29691
  const sizeBytes = await Bun.write(savedPath, file);
29658
29692
  if (sizeBytes !== file.size)
@@ -29677,14 +29711,14 @@ class NodeFileStore {
29677
29711
  }
29678
29712
  allows(fileId, access) {
29679
29713
  const metadata = this.#metadata(fileId);
29680
- return Boolean(metadata && metadata.ownerUserId === access.ownerUserId && metadata.topicId === access.topicId && existsSync32(join41(this.uploadDir, metadata.savedName)));
29714
+ return Boolean(metadata && metadata.ownerUserId === access.ownerUserId && metadata.topicId === access.topicId && existsSync32(join42(this.uploadDir, metadata.savedName)));
29681
29715
  }
29682
29716
  store(absPath, access = {}) {
29683
29717
  this.#ensureDir();
29684
29718
  const fileId = randomUUID24();
29685
29719
  const extension = safeExtension(absPath);
29686
29720
  const savedName = `${fileId}${extension}`;
29687
- const savedPath = join41(this.uploadDir, savedName);
29721
+ const savedPath = join42(this.uploadDir, savedName);
29688
29722
  try {
29689
29723
  const stats = statSync18(absPath);
29690
29724
  if (!stats.isFile() || stats.size > MAX_NODE_UPLOAD_BYTES)
@@ -29716,7 +29750,7 @@ class NodeFileStore {
29716
29750
  const allowed = metadata.visibility === "workspace" || metadata.ownerUserId === userId || Boolean(topic && isParticipant(topic, userId));
29717
29751
  if (!allowed)
29718
29752
  return null;
29719
- const path = join41(this.uploadDir, metadata.savedName);
29753
+ const path = join42(this.uploadDir, metadata.savedName);
29720
29754
  if (!existsSync32(path))
29721
29755
  return null;
29722
29756
  return new Response(Bun.file(path), {
@@ -29735,7 +29769,7 @@ class NodeFileStore {
29735
29769
  const metadata = this.#metadata(fileId);
29736
29770
  if (metadata?.topicId !== topicId)
29737
29771
  continue;
29738
- rmSync9(join41(this.uploadDir, metadata.savedName), { force: true });
29772
+ rmSync9(join42(this.uploadDir, metadata.savedName), { force: true });
29739
29773
  rmSync9(this.#metadataPath(fileId), { force: true });
29740
29774
  }
29741
29775
  }
@@ -33858,8 +33892,8 @@ var init_context_usage = __esm(async () => {
33858
33892
  // ../../adapters/terminal/src/path-suggest.ts
33859
33893
  import { execFile as execFile3 } from "child_process";
33860
33894
  import { existsSync as existsSync36, readdirSync as readdirSync14, statSync as statSync19 } from "fs";
33861
- import { homedir as homedir10 } from "os";
33862
- import { basename as basename11, dirname as dirname21, join as join42, sep as sep3 } from "path";
33895
+ import { homedir as homedir11 } from "os";
33896
+ import { basename as basename11, dirname as dirname21, join as join43, sep as sep3 } from "path";
33863
33897
  import { promisify as promisify3 } from "util";
33864
33898
  function indexRecursivePaths(files) {
33865
33899
  const paths = [];
@@ -33953,25 +33987,25 @@ function activeAtToken(lineText, col) {
33953
33987
  return { start: col - frag.length - 1, frag };
33954
33988
  }
33955
33989
  function resolveFragment(frag) {
33956
- const home = homedir10();
33990
+ const home = homedir11();
33957
33991
  let path;
33958
33992
  if (frag === "" || frag === "~")
33959
33993
  path = home;
33960
33994
  else if (frag === "~/")
33961
33995
  path = home;
33962
33996
  else if (frag.startsWith("~/"))
33963
- path = join42(home, frag.slice(2));
33997
+ path = join43(home, frag.slice(2));
33964
33998
  else if (frag.startsWith("/"))
33965
33999
  path = frag;
33966
34000
  else
33967
- path = join42(home, frag);
34001
+ path = join43(home, frag);
33968
34002
  if (frag.endsWith("/") || frag === "" || frag === "~") {
33969
34003
  return { dir: path, prefix: "" };
33970
34004
  }
33971
34005
  return { dir: dirname21(path), prefix: basename11(path) };
33972
34006
  }
33973
34007
  function toToken(fullPath, isDir) {
33974
- const home = homedir10();
34008
+ const home = homedir11();
33975
34009
  let shown = fullPath;
33976
34010
  if (fullPath === home)
33977
34011
  shown = "~";
@@ -33993,7 +34027,7 @@ function rankAndSlice(dir, candidates) {
33993
34027
  });
33994
34028
  return candidates.slice(0, MAX_SUGGESTIONS).map(({ relPath, isDir }) => ({
33995
34029
  label: `${relPath}${isDir ? "/" : ""}`,
33996
- value: toToken(join42(dir, relPath), isDir),
34030
+ value: toToken(join43(dir, relPath), isDir),
33997
34031
  isDir
33998
34032
  }));
33999
34033
  }
@@ -34072,7 +34106,7 @@ function pathSuggestions(lineText, col) {
34072
34106
  let isDir = entry.isDirectory();
34073
34107
  if (!isDir && entry.isSymbolicLink()) {
34074
34108
  try {
34075
- isDir = statSync19(join42(dir, entry.name)).isDirectory();
34109
+ isDir = statSync19(join43(dir, entry.name)).isDirectory();
34076
34110
  } catch {}
34077
34111
  }
34078
34112
  return {
@@ -34095,14 +34129,14 @@ function pathSuggestions(lineText, col) {
34095
34129
  };
34096
34130
  }
34097
34131
  function fragmentToAbsolutePath(frag) {
34098
- const home = homedir10();
34132
+ const home = homedir11();
34099
34133
  if (frag === "~" || frag === "~/")
34100
34134
  return home;
34101
34135
  if (frag.startsWith("~/"))
34102
- return join42(home, frag.slice(2));
34136
+ return join43(home, frag.slice(2));
34103
34137
  if (frag.startsWith("/"))
34104
34138
  return frag;
34105
- return join42(home, frag);
34139
+ return join43(home, frag);
34106
34140
  }
34107
34141
  function fragmentResolves(frag) {
34108
34142
  try {
@@ -40608,7 +40642,7 @@ var init_commands2 = __esm(async () => {
40608
40642
  // ../../adapters/telegram/src/mapping-store.ts
40609
40643
  import { Database as Database2 } from "bun:sqlite";
40610
40644
  import { mkdirSync as mkdirSync32 } from "fs";
40611
- import { dirname as dirname22, join as join43 } from "path";
40645
+ import { dirname as dirname22, join as join44 } from "path";
40612
40646
  function outboxRowToEntry(row) {
40613
40647
  return {
40614
40648
  id: row.id,
@@ -40674,7 +40708,7 @@ function migrateOutboxSchema(db4) {
40674
40708
  db4.run("CREATE INDEX IF NOT EXISTS idx_telegram_outbox_runtime_message ON outbox(runtime_message_id)");
40675
40709
  }
40676
40710
  function openMappingStore(path) {
40677
- const dbPath = path ?? join43(DATA_DIR, "adapter-telegram.db");
40711
+ const dbPath = path ?? join44(DATA_DIR, "adapter-telegram.db");
40678
40712
  if (dbPath !== ":memory:")
40679
40713
  mkdirSync32(dirname22(dbPath), { recursive: true });
40680
40714
  const db4 = new Database2(dbPath);
@@ -42574,9 +42608,9 @@ function firstCell() {
42574
42608
  return cell;
42575
42609
  return null;
42576
42610
  }
42577
- function attachOtiumCentralCell(join44) {
42578
- cells.set(join44.cellId, {
42579
- join: join44,
42611
+ function attachOtiumCentralCell(join45) {
42612
+ cells.set(join45.cellId, {
42613
+ join: join45,
42580
42614
  nodesCache: null,
42581
42615
  verifyCache: new Map,
42582
42616
  tokenCache: new Map
@@ -42588,10 +42622,10 @@ function detachOtiumCentralCell(cellId) {
42588
42622
  function attachedOtiumCells() {
42589
42623
  return [...cells.values()].map((cell) => cell.join);
42590
42624
  }
42591
- function configureOtiumCentral(join44) {
42625
+ function configureOtiumCentral(join45) {
42592
42626
  cells.clear();
42593
- if (join44)
42594
- attachOtiumCentralCell(join44);
42627
+ if (join45)
42628
+ attachOtiumCentralCell(join45);
42595
42629
  }
42596
42630
  function isOtiumCentralConfigured() {
42597
42631
  return cells.size > 0;
@@ -43155,17 +43189,17 @@ function withJoinCredentialLock(operation) {
43155
43189
  function joinsEqual(left, right) {
43156
43190
  return left.central === right.central && left.relay === right.relay && left.cellId === right.cellId && left.secret === right.secret;
43157
43191
  }
43158
- function normalizedJoin(join44) {
43192
+ function normalizedJoin(join45) {
43159
43193
  return normalizeJoin({
43160
- v: join44.v,
43161
- central: join44.central,
43162
- relay: join44.relay,
43163
- cellId: join44.cellId,
43164
- secret: join44.secret
43194
+ v: join45.v,
43195
+ central: join45.central,
43196
+ relay: join45.relay,
43197
+ cellId: join45.cellId,
43198
+ secret: join45.secret
43165
43199
  });
43166
43200
  }
43167
- function joinCredentialDigest(join44) {
43168
- return createHash11("sha256").update(JSON.stringify(normalizedJoin(join44))).digest("base64url");
43201
+ function joinCredentialDigest(join45) {
43202
+ return createHash11("sha256").update(JSON.stringify(normalizedJoin(join45))).digest("base64url");
43169
43203
  }
43170
43204
  function readPersistedJoins(path = joinFilePath()) {
43171
43205
  if (!existsSync39(path))
@@ -43184,9 +43218,9 @@ function readPersistedJoins(path = joinFilePath()) {
43184
43218
  return normalizeJoin(entry);
43185
43219
  });
43186
43220
  }
43187
- function isJoinPersisted(join44) {
43221
+ function isJoinPersisted(join45) {
43188
43222
  try {
43189
- const normalized = normalizedJoin(join44);
43223
+ const normalized = normalizedJoin(join45);
43190
43224
  return readPersistedJoins().some((persisted) => joinsEqual(persisted, normalized));
43191
43225
  } catch {
43192
43226
  return false;
@@ -43230,10 +43264,10 @@ function writeJoins(joins, allowOverwrite) {
43230
43264
  }
43231
43265
  return path;
43232
43266
  }
43233
- function saveJoinWhileLocked(join44, options = {}) {
43267
+ function saveJoinWhileLocked(join45, options = {}) {
43234
43268
  const path = joinFilePath();
43235
43269
  const directory = dirname23(path);
43236
- const normalized = normalizedJoin(join44);
43270
+ const normalized = normalizedJoin(join45);
43237
43271
  mkdirSync33(directory, { recursive: true });
43238
43272
  if (!existsSync39(path))
43239
43273
  return writeJoins([normalized], false);
@@ -43263,8 +43297,8 @@ function saveJoinWhileLocked(join44, options = {}) {
43263
43297
  const next = conflict ? existing.map((persisted) => persisted.cellId === normalized.cellId ? normalized : persisted) : [...existing, normalized];
43264
43298
  return writeJoins(next, true);
43265
43299
  }
43266
- function saveJoin(join44, options = {}) {
43267
- return withJoinCredentialLock(() => saveJoinWhileLocked(join44, options));
43300
+ function saveJoin(join45, options = {}) {
43301
+ return withJoinCredentialLock(() => saveJoinWhileLocked(join45, options));
43268
43302
  }
43269
43303
  function removeJoin(cellId) {
43270
43304
  return withJoinCredentialLock(() => {
@@ -43277,7 +43311,7 @@ function removeJoin(cellId) {
43277
43311
  if (cellId) {
43278
43312
  let remaining;
43279
43313
  try {
43280
- remaining = readPersistedJoins(path).filter((join44) => join44.cellId !== cellId);
43314
+ remaining = readPersistedJoins(path).filter((join45) => join45.cellId !== cellId);
43281
43315
  } catch {
43282
43316
  return false;
43283
43317
  }
@@ -43330,7 +43364,7 @@ var init_join = __esm(async () => {
43330
43364
  // ../../adapters/otium/src/peer-files.ts
43331
43365
  import { randomUUID as randomUUID29 } from "crypto";
43332
43366
  import { copyFileSync as copyFileSync5, mkdirSync as mkdirSync34, rmSync as rmSync11, statSync as statSync21 } from "fs";
43333
- import { basename as basename13, extname as extname6, join as join44 } from "path";
43367
+ import { basename as basename13, extname as extname6, join as join45 } from "path";
43334
43368
  function fileType(mimeType) {
43335
43369
  if (mimeType.startsWith("image/"))
43336
43370
  return "image";
@@ -43396,7 +43430,7 @@ function recordFile(args) {
43396
43430
  function insertLocalFile(args) {
43397
43431
  const id = randomUUID29();
43398
43432
  mkdirSync34(PEER_FILES_DIR, { recursive: true });
43399
- const path = join44(PEER_FILES_DIR, `${id}-${safeFilename(args.filename)}`);
43433
+ const path = join45(PEER_FILES_DIR, `${id}-${safeFilename(args.filename)}`);
43400
43434
  copyFileSync5(args.sourcePath, path);
43401
43435
  return recordFile({ id, path, sizeBytes: statSync21(path).size, ...args });
43402
43436
  }
@@ -43442,7 +43476,7 @@ function installPeerFileHooks() {
43442
43476
  var PEER_FILES_DIR;
43443
43477
  var init_peer_files = __esm(async () => {
43444
43478
  await init_src();
43445
- PEER_FILES_DIR = join44(DATA_DIR, "otium-peer-files");
43479
+ PEER_FILES_DIR = join45(DATA_DIR, "otium-peer-files");
43446
43480
  db.exec(`
43447
43481
  CREATE TABLE IF NOT EXISTS otium_peer_files (
43448
43482
  id TEXT PRIMARY KEY,
@@ -43854,19 +43888,19 @@ function readCache() {
43854
43888
  return {};
43855
43889
  }
43856
43890
  }
43857
- function cachedSurfaceScope(join45) {
43858
- const record = readCache()[join45.cellId];
43859
- if (!record || record.central !== join45.central || !record.workspaceId)
43891
+ function cachedSurfaceScope(join46) {
43892
+ const record = readCache()[join46.cellId];
43893
+ if (!record || record.central !== join46.central || !record.workspaceId)
43860
43894
  return null;
43861
43895
  return surfaceScopeFor(record.central, record.workspaceId);
43862
43896
  }
43863
- function cacheSurfaceScope(join45, workspaceId) {
43864
- const scope = surfaceScopeFor(join45.central, workspaceId);
43897
+ function cacheSurfaceScope(join46, workspaceId) {
43898
+ const scope = surfaceScopeFor(join46.central, workspaceId);
43865
43899
  const path = scopeCachePath();
43866
43900
  try {
43867
43901
  mkdirSync35(dirname24(path), { recursive: true });
43868
43902
  const cache = readCache();
43869
- cache[join45.cellId] = { central: join45.central, workspaceId, scope };
43903
+ cache[join46.cellId] = { central: join46.central, workspaceId, scope };
43870
43904
  writeFileSync26(path, `${JSON.stringify(cache, null, 2)}
43871
43905
  `, { mode: 384 });
43872
43906
  } catch (err2) {
@@ -43874,23 +43908,23 @@ function cacheSurfaceScope(join45, workspaceId) {
43874
43908
  }
43875
43909
  return scope;
43876
43910
  }
43877
- async function resolveSurfaceScope(join45) {
43878
- const cached = cachedSurfaceScope(join45);
43911
+ async function resolveSurfaceScope(join46) {
43912
+ const cached = cachedSurfaceScope(join46);
43879
43913
  if (cached)
43880
43914
  return cached;
43881
43915
  try {
43882
- const workspaceId = await peerWorkspaceIdForCell(join45.cellId);
43916
+ const workspaceId = await peerWorkspaceIdForCell(join46.cellId);
43883
43917
  if (!workspaceId)
43884
43918
  return null;
43885
- return cacheSurfaceScope(join45, workspaceId);
43919
+ return cacheSurfaceScope(join46, workspaceId);
43886
43920
  } catch (err2) {
43887
43921
  logger.warn({ err: err2 }, "otium: workspace scope unresolved (will retry on the next contact)");
43888
43922
  return null;
43889
43923
  }
43890
43924
  }
43891
43925
  function surfaceScopeForCell(cellId) {
43892
- const join45 = attachedOtiumCells().find((candidate) => candidate.cellId === cellId);
43893
- return join45 ? cachedSurfaceScope(join45) : null;
43926
+ const join46 = attachedOtiumCells().find((candidate) => candidate.cellId === cellId);
43927
+ return join46 ? cachedSurfaceScope(join46) : null;
43894
43928
  }
43895
43929
  function unscopedRoomsAddressable() {
43896
43930
  return attachedOtiumCells().length < 2;
@@ -45023,13 +45057,13 @@ function replacePendingEnrollment(pending2) {
45023
45057
  throw error2;
45024
45058
  }
45025
45059
  }
45026
- function recordClaimedCredential(pending2, join45) {
45060
+ function recordClaimedCredential(pending2, join46) {
45027
45061
  withJoinCredentialLock(() => {
45028
45062
  const current3 = JSON.parse(readFileSync31(pendingEnrollmentPath(), "utf8"));
45029
45063
  if (current3.central !== pending2.central || current3.token !== pending2.token || current3.idempotencyKey !== pending2.idempotencyKey || current3.publicKey !== pending2.publicKey) {
45030
45064
  throw new Error("pending Otium enrollment changed while its claim was in flight");
45031
45065
  }
45032
- const claimed = { digest: joinCredentialDigest(join45), cellId: join45.cellId };
45066
+ const claimed = { digest: joinCredentialDigest(join46), cellId: join46.cellId };
45033
45067
  if (current3.claimed && (current3.claimed.digest !== claimed.digest || current3.claimed.cellId !== claimed.cellId)) {
45034
45068
  throw new Error("central returned different credentials for an idempotent enrollment claim");
45035
45069
  }
@@ -45087,30 +45121,30 @@ async function claimEnrollment(invite, nodeName) {
45087
45121
  const secret = openCredential(credential, pending2.privateKey);
45088
45122
  if (!secret.startsWith("rcs_"))
45089
45123
  throw new Error("central returned an invalid runtime credential");
45090
- const join45 = {
45124
+ const join46 = {
45091
45125
  v: 2,
45092
45126
  central: invite.central,
45093
45127
  relay: String(response.relayUrl),
45094
45128
  cellId: String(response.cell?.id),
45095
45129
  secret
45096
45130
  };
45097
- if (!join45.relay || !join45.cellId || join45.cellId === "undefined") {
45131
+ if (!join46.relay || !join46.cellId || join46.cellId === "undefined") {
45098
45132
  throw new Error("central returned an incomplete enrollment response");
45099
45133
  }
45100
- assertSecureRelayUrl(join45.relay);
45101
- recordClaimedCredential(pending2, join45);
45102
- return join45;
45134
+ assertSecureRelayUrl(join46.relay);
45135
+ recordClaimedCredential(pending2, join46);
45136
+ return join46;
45103
45137
  }
45104
- function commitEnrollment(join45, options = {}) {
45138
+ function commitEnrollment(join46, options = {}) {
45105
45139
  return withJoinCredentialLock(() => {
45106
45140
  const pendingPath = pendingEnrollmentPath();
45107
45141
  const pending2 = existsSync40(pendingPath) ? JSON.parse(readFileSync31(pendingPath, "utf8")) : null;
45108
- const digest = joinCredentialDigest(join45);
45109
- if (pending2 && (!pending2.claimed || pending2.claimed.digest !== digest || pending2.claimed.cellId !== join45.cellId)) {
45142
+ const digest = joinCredentialDigest(join46);
45143
+ if (pending2 && (!pending2.claimed || pending2.claimed.digest !== digest || pending2.claimed.cellId !== join46.cellId)) {
45110
45144
  throw new Error(`pending Otium enrollment at ${pendingPath} does not match these credentials`);
45111
45145
  }
45112
- const path = saveJoinWhileLocked(join45, options);
45113
- if (!isJoinPersisted(join45)) {
45146
+ const path = saveJoinWhileLocked(join46, options);
45147
+ if (!isJoinPersisted(join46)) {
45114
45148
  throw new Error("Otium join credentials were not durably persisted");
45115
45149
  }
45116
45150
  if (!pending2)
@@ -45704,24 +45738,24 @@ function refreshDefaultSurfaceScope() {
45704
45738
  setSurfaceScopeRequired(scopes.length > 1);
45705
45739
  }
45706
45740
  function startOtiumNodeRuntime(options) {
45707
- const { join: join45 } = options;
45708
- attachOtiumCentralCell(join45);
45741
+ const { join: join46 } = options;
45742
+ attachOtiumCentralCell(join46);
45709
45743
  const releaseGlobals = acquireGlobalOtiumServices();
45710
45744
  let stopped = false;
45711
- logger.info({ central: join45.central, cellId: join45.cellId }, "otium: worker mode enabled");
45712
- mountedScopes.set(join45.cellId, cachedSurfaceScope(join45));
45745
+ logger.info({ central: join46.central, cellId: join46.cellId }, "otium: worker mode enabled");
45746
+ mountedScopes.set(join46.cellId, cachedSurfaceScope(join46));
45713
45747
  refreshDefaultSurfaceScope();
45714
- selfPeerNodeForCell(join45.cellId).then((self) => {
45748
+ selfPeerNodeForCell(join46.cellId).then((self) => {
45715
45749
  if (self) {
45716
45750
  logger.info({ nodeName: self.nodeName, baseUrl: self.baseUrl }, "otium: attached to workspace");
45717
45751
  }
45718
45752
  }).catch((err2) => {
45719
45753
  logger.warn({ err: err2 }, "otium: self check against central failed (will retry per request)");
45720
45754
  });
45721
- resolveSurfaceScope(join45).then((scope) => {
45755
+ resolveSurfaceScope(join46).then((scope) => {
45722
45756
  if (!scope || stopped)
45723
45757
  return;
45724
- mountedScopes.set(join45.cellId, scope);
45758
+ mountedScopes.set(join46.cellId, scope);
45725
45759
  refreshDefaultSurfaceScope();
45726
45760
  if (mountedScopes.size === 1)
45727
45761
  stampUnscopedOtiumTopics(scope);
@@ -45730,14 +45764,14 @@ function startOtiumNodeRuntime(options) {
45730
45764
  });
45731
45765
  return {
45732
45766
  name: "otium",
45733
- join: join45,
45767
+ join: join46,
45734
45768
  stop: () => {
45735
45769
  if (stopped)
45736
45770
  return;
45737
45771
  stopped = true;
45738
- mountedScopes.delete(join45.cellId);
45772
+ mountedScopes.delete(join46.cellId);
45739
45773
  refreshDefaultSurfaceScope();
45740
- detachOtiumCentralCell(join45.cellId);
45774
+ detachOtiumCentralCell(join46.cellId);
45741
45775
  releaseGlobals();
45742
45776
  }
45743
45777
  };
@@ -45832,14 +45866,14 @@ __export(exports_node_runtime, {
45832
45866
  function sameCredentials(left, right) {
45833
45867
  return left.central === right.central && left.relay === right.relay && left.secret === right.secret;
45834
45868
  }
45835
- function attachOtiumWorkspace(join45) {
45836
- const current3 = mounted.get(join45.cellId);
45869
+ function attachOtiumWorkspace(join46) {
45870
+ const current3 = mounted.get(join46.cellId);
45837
45871
  if (current3) {
45838
- if (sameCredentials(current3.join, join45))
45872
+ if (sameCredentials(current3.join, join46))
45839
45873
  return false;
45840
- detachOtiumWorkspace(join45.cellId);
45874
+ detachOtiumWorkspace(join46.cellId);
45841
45875
  }
45842
- mounted.set(join45.cellId, startOtiumNodeRuntime({ join: join45 }));
45876
+ mounted.set(join46.cellId, startOtiumNodeRuntime({ join: join46 }));
45843
45877
  return true;
45844
45878
  }
45845
45879
  function detachOtiumWorkspace(cellId) {
@@ -45854,7 +45888,7 @@ function mountedOtiumWorkspaces() {
45854
45888
  return [...mounted.values()].map((runtime2) => runtime2.join);
45855
45889
  }
45856
45890
  function reconcileOtiumWorkspaces(joins = loadJoins()) {
45857
- const wanted = new Map(joins.map((join45) => [join45.cellId, join45]));
45891
+ const wanted = new Map(joins.map((join46) => [join46.cellId, join46]));
45858
45892
  const detached = [];
45859
45893
  for (const cellId of [...mounted.keys()]) {
45860
45894
  if (wanted.has(cellId))
@@ -45863,8 +45897,8 @@ function reconcileOtiumWorkspaces(joins = loadJoins()) {
45863
45897
  detached.push(cellId);
45864
45898
  }
45865
45899
  const attached = [];
45866
- for (const [cellId, join45] of wanted) {
45867
- if (attachOtiumWorkspace(join45))
45900
+ for (const [cellId, join46] of wanted) {
45901
+ if (attachOtiumWorkspace(join46))
45868
45902
  attached.push(cellId);
45869
45903
  }
45870
45904
  if (attached.length > 0 || detached.length > 0) {
@@ -45887,9 +45921,9 @@ async function handleOtiumAdapterControlRequest(req) {
45887
45921
  if (req.method === "GET") {
45888
45922
  return Response.json({
45889
45923
  ok: true,
45890
- workspaces: mountedOtiumWorkspaces().map((join45) => ({
45891
- cellId: join45.cellId,
45892
- central: join45.central
45924
+ workspaces: mountedOtiumWorkspaces().map((join46) => ({
45925
+ cellId: join46.cellId,
45926
+ central: join46.central
45893
45927
  }))
45894
45928
  });
45895
45929
  }
@@ -45910,8 +45944,8 @@ function mountConfiguredOtiumNodeRuntime() {
45910
45944
  const joins = loadJoins();
45911
45945
  if (joins.length === 0)
45912
45946
  return null;
45913
- for (const join45 of joins)
45914
- attachOtiumWorkspace(join45);
45947
+ for (const join46 of joins)
45948
+ attachOtiumWorkspace(join46);
45915
45949
  registerNodeRequestHandler("otium-adapter-control", handleOtiumAdapterControlRequest);
45916
45950
  let stopped = false;
45917
45951
  return {
@@ -46023,11 +46057,11 @@ async function joinCommand(args) {
46023
46057
  process.exitCode = 1;
46024
46058
  return;
46025
46059
  }
46026
- let join45;
46060
+ let join46;
46027
46061
  let productionEnrollment = false;
46028
46062
  if (args.includes("--legacy")) {
46029
46063
  try {
46030
- join45 = parseInviteCode(code);
46064
+ join46 = parseInviteCode(code);
46031
46065
  } catch (err2) {
46032
46066
  console.error(`invalid legacy invite code: ${err2 instanceof Error ? err2.message : err2}`);
46033
46067
  process.exitCode = 1;
@@ -46053,7 +46087,7 @@ async function joinCommand(args) {
46053
46087
  return;
46054
46088
  }
46055
46089
  }
46056
- join45 = await claimEnrollment(invite, nodeName);
46090
+ join46 = await claimEnrollment(invite, nodeName);
46057
46091
  productionEnrollment = true;
46058
46092
  } catch (err2) {
46059
46093
  console.error(`enrollment failed: ${err2 instanceof Error ? err2.message : err2}`);
@@ -46064,16 +46098,16 @@ async function joinCommand(args) {
46064
46098
  let path;
46065
46099
  try {
46066
46100
  const saveOptions = { replaceExisting: args.includes("--replace") };
46067
- path = productionEnrollment ? commitEnrollment(join45, saveOptions) : saveJoin(join45, saveOptions);
46101
+ path = productionEnrollment ? commitEnrollment(join46, saveOptions) : saveJoin(join46, saveOptions);
46068
46102
  } catch (err2) {
46069
46103
  console.error(`could not save join credentials: ${err2 instanceof Error ? err2.message : err2}`);
46070
46104
  process.exitCode = 1;
46071
46105
  return;
46072
46106
  }
46073
46107
  console.log(`otium join credentials saved to ${path}`);
46074
- console.log(` central: ${join45.central}`);
46075
- console.log(` cellId: ${join45.cellId}`);
46076
- configureOtiumCentral(join45);
46108
+ console.log(` central: ${join46.central}`);
46109
+ console.log(` cellId: ${join46.cellId}`);
46110
+ configureOtiumCentral(join46);
46077
46111
  try {
46078
46112
  const self = await selfPeerNode();
46079
46113
  if (self) {
@@ -46115,19 +46149,19 @@ async function statusCommand() {
46115
46149
  return;
46116
46150
  }
46117
46151
  configureOtiumCentral(joins[0] ?? null);
46118
- for (const join45 of joins.slice(1))
46119
- attachOtiumCentralCell(join45);
46120
- for (const [index, join45] of joins.entries()) {
46152
+ for (const join46 of joins.slice(1))
46153
+ attachOtiumCentralCell(join46);
46154
+ for (const [index, join46] of joins.entries()) {
46121
46155
  if (index > 0)
46122
46156
  console.log("");
46123
- console.log(`cellId: ${join45.cellId}`);
46124
- console.log(`central: ${join45.central}`);
46125
- if (join45.relay)
46126
- console.log(`relay: ${join45.relay}`);
46157
+ console.log(`cellId: ${join46.cellId}`);
46158
+ console.log(`central: ${join46.central}`);
46159
+ if (join46.relay)
46160
+ console.log(`relay: ${join46.relay}`);
46127
46161
  try {
46128
- const self = await selfPeerNodeForCell(join45.cellId);
46162
+ const self = await selfPeerNodeForCell(join46.cellId);
46129
46163
  if (self) {
46130
- console.log(`node: ${self.nodeName ?? join45.cellId}${self.isPrimary ? " (primary)" : ""}`);
46164
+ console.log(`node: ${self.nodeName ?? join46.cellId}${self.isPrimary ? " (primary)" : ""}`);
46131
46165
  console.log(`baseUrl: ${self.baseUrl}`);
46132
46166
  } else {
46133
46167
  console.warn(" warning: central answered but this cell has no visible assignment yet \u2014 check the workspace assignment");
@@ -46163,13 +46197,13 @@ function resolveTunnelTargets(joins, relayOverride) {
46163
46197
  const targets = [];
46164
46198
  const skippedNoRelay = [];
46165
46199
  const envRelay = process.env.OTIUM_RELAY_URL?.trim();
46166
- for (const join45 of joins) {
46167
- const relayUrl = relayOverride?.trim() || join45.relay || envRelay;
46200
+ for (const join46 of joins) {
46201
+ const relayUrl = relayOverride?.trim() || join46.relay || envRelay;
46168
46202
  if (!relayUrl) {
46169
- skippedNoRelay.push(join45.cellId);
46203
+ skippedNoRelay.push(join46.cellId);
46170
46204
  continue;
46171
46205
  }
46172
- targets.push({ cellId: join45.cellId, relayUrl, secret: join45.secret });
46206
+ targets.push({ cellId: join46.cellId, relayUrl, secret: join46.secret });
46173
46207
  }
46174
46208
  return { targets, skippedNoRelay };
46175
46209
  }
@@ -46406,9 +46440,9 @@ async function runOtiumCli(args = process.argv.slice(2)) {
46406
46440
  if (joins.length === 0)
46407
46441
  throw new Error("not joined to an Otium workspace");
46408
46442
  if (!targetCellId && joins.length > 1) {
46409
- throw new Error(`this node is joined to ${joins.length} workspaces; name one to leave: ${joins.map((join45) => join45.cellId).join(", ")}`);
46443
+ throw new Error(`this node is joined to ${joins.length} workspaces; name one to leave: ${joins.map((join46) => join46.cellId).join(", ")}`);
46410
46444
  }
46411
- if (targetCellId && !joins.some((join45) => join45.cellId === targetCellId)) {
46445
+ if (targetCellId && !joins.some((join46) => join46.cellId === targetCellId)) {
46412
46446
  throw new Error(`not joined as ${targetCellId}`);
46413
46447
  }
46414
46448
  removeJoin2(targetCellId);
@@ -47195,4 +47229,4 @@ switch (command) {
47195
47229
  }
47196
47230
  }
47197
47231
 
47198
- //# debugId=A4A68C691DEC1BCD64756E2164756E21
47232
+ //# debugId=805E32726887103964756E2164756E21