negotium 0.2.12 → 0.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/agent-helpers.js +34 -8
  2. package/dist/agent-helpers.js.map +6 -6
  3. package/dist/background-bash.js +32 -6
  4. package/dist/background-bash.js.map +4 -4
  5. package/dist/browser-runtime.js +14 -2
  6. package/dist/browser-runtime.js.map +3 -3
  7. package/dist/{chunk-8asy22vc.js → chunk-5g5a63vv.js} +32 -6
  8. package/dist/{chunk-8asy22vc.js.map → chunk-5g5a63vv.js.map} +4 -4
  9. package/dist/hosted-agent.js +33 -7
  10. package/dist/hosted-agent.js.map +5 -5
  11. package/dist/main.js +603 -353
  12. package/dist/main.js.map +12 -11
  13. package/dist/mcp-factories.js +34 -8
  14. package/dist/mcp-factories.js.map +6 -6
  15. package/dist/mcp-servers.js +3 -2
  16. package/dist/mcp-servers.js.map +3 -3
  17. package/dist/prompts.js +14 -2
  18. package/dist/prompts.js.map +3 -3
  19. package/dist/query-runtime.js +14 -2
  20. package/dist/query-runtime.js.map +3 -3
  21. package/dist/registry.js +3 -3
  22. package/dist/registry.js.map +2 -2
  23. package/dist/rollout.js +1 -1
  24. package/dist/runtime/src/index.ts +9 -0
  25. package/dist/runtime/src/node-host.ts +9 -0
  26. package/dist/runtime/src/platform/background-bash/manager.ts +45 -5
  27. package/dist/runtime/src/platform/config.ts +35 -2
  28. package/dist/runtime/src/runtime/bashrs-completions.ts +328 -0
  29. package/dist/runtime/src/runtime/turn-runner.ts +6 -0
  30. package/dist/runtime/src/version.ts +1 -1
  31. package/dist/runtime-helpers.js +14 -2
  32. package/dist/runtime-helpers.js.map +3 -3
  33. package/dist/types/apps/negotium/src/mcp-servers.d.ts +16 -3
  34. package/dist/types/packages/core/src/platform/background-bash/manager.d.ts +6 -1
  35. package/dist/types/packages/core/src/platform/config.d.ts +21 -1
  36. package/dist/types/packages/core/src/version.d.ts +1 -1
  37. package/dist/vault.js +14 -2
  38. package/dist/vault.js.map +3 -3
  39. package/install-bash-rs.mjs +77 -0
  40. package/package.json +3 -2
  41. package/dist/runtime/src/mcp/background-bash-server.ts +0 -756
package/dist/main.js CHANGED
@@ -176,6 +176,16 @@ function resolveBrowserRsBin(envValue) {
176
176
  return;
177
177
  }
178
178
  }
179
+ function resolveBashRsBin(envValue) {
180
+ const override = envValue?.trim();
181
+ const candidate = override ? resolve(override) : resolve(BINARIES_DIR, "bash-rs", BASH_RS_VERSION, "bash-rs");
182
+ try {
183
+ accessSync(candidate, constants.X_OK);
184
+ return candidate;
185
+ } catch {
186
+ return;
187
+ }
188
+ }
179
189
  function resolveBrowserMcpBin(envValue) {
180
190
  const override = envValue?.trim();
181
191
  if (override)
@@ -253,7 +263,7 @@ function resolveDefaultModel(agent, registryDefaultModel) {
253
263
  function codexAuthFilePath() {
254
264
  return process.env.NEGOTIUM_CODEX_AUTH_FILE || join(process.env.CODEX_HOME || join(homedir(), ".codex"), "auth.json");
255
265
  }
256
- var HOME, PROJECT_ROOT, STATE_DIR_ENV, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR, CRON_WORKSPACE_DIR, BROWSER_DIR, BROWSER_PROFILES_DIR, BINARIES_DIR, SECRETS_DIR, DM_WORKSPACE_DIR, SESSION_WORKSPACE_DIR, CLAUDE_EXECUTABLE_ENV, CLAUDE_EXECUTABLE, DEFAULT_OUTPUT_LANGUAGE = "English", BROWSER_RS_VERSION = "v0.1.19", BROWSER_RS_MIN_SECURE_VERSION = "0.1.15", SNIPPETS_API_URL, BROWSER_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, BROWSER_MCP_SSE_PROXY_SERVER, CANONICAL_MCP_PROXY_SERVER, WIKI_SERVER, TOKEN_STATS_SERVER, COMPACTION_LOG_SERVER, SYSTEM_HEALTH_SERVER, AGENT_HEALTH_SERVER, BACKGROUND_BASH_SERVER, VAULT_SERVER, BG_BASH_BASE_PORT, BG_BASH_MAX_PORT, RUNTIME_MCP_SECRET, NODE_CONTROL_TOKEN, VAULT_MASTER_KEY, NEGOTIUM_PORT, hostname, DATA_DIR, LOG_DIR, UPLOADS_DIR, VAULT_DIR, SESSIONS_DB, DEBUG_FILE, USERS_LOG_DIR, RUN_DIR, PROGRESS_DIR, DM_CMD_DIR, DM_RESP_DIR, SESSION_INBOX_DIR, SESSION_ASKS_DIR, PLAYWRIGHT_BASE_PORT, PLAYWRIGHT_MAX_PORT, PLAYWRIGHT_PORTS_DIR, ACTIVE_QUERY_STALE_MS, AGENTS_PROMPTS_DIR, RESOURCES_DIR, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5", MODEL_FABLE = "claude-fable-5", FALLBACK_AGENT, SESSION_AGENT, GATEWAY_AGENT, FALLBACK_MODEL, SESSION_MODEL, GATEWAY_MODEL, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, _envMaxTellDepth, MAX_TELL_DEPTH;
266
+ var HOME, PROJECT_ROOT, STATE_DIR_ENV, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR, CRON_WORKSPACE_DIR, BROWSER_DIR, BROWSER_PROFILES_DIR, BINARIES_DIR, SECRETS_DIR, DM_WORKSPACE_DIR, SESSION_WORKSPACE_DIR, CLAUDE_EXECUTABLE_ENV, CLAUDE_EXECUTABLE, DEFAULT_OUTPUT_LANGUAGE = "English", BROWSER_RS_VERSION = "v0.1.19", BROWSER_RS_MIN_SECURE_VERSION = "0.1.15", SNIPPETS_API_URL, BROWSER_RS_BIN, BASH_RS_VERSION = "v0.1.5", BASH_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, BROWSER_MCP_SSE_PROXY_SERVER, CANONICAL_MCP_PROXY_SERVER, WIKI_SERVER, TOKEN_STATS_SERVER, COMPACTION_LOG_SERVER, SYSTEM_HEALTH_SERVER, AGENT_HEALTH_SERVER, VAULT_SERVER, BG_BASH_BASE_PORT, BG_BASH_MAX_PORT, RUNTIME_MCP_SECRET, NODE_CONTROL_TOKEN, VAULT_MASTER_KEY, NEGOTIUM_PORT, hostname, DATA_DIR, LOG_DIR, UPLOADS_DIR, VAULT_DIR, SESSIONS_DB, DEBUG_FILE, USERS_LOG_DIR, RUN_DIR, PROGRESS_DIR, DM_CMD_DIR, DM_RESP_DIR, SESSION_INBOX_DIR, SESSION_ASKS_DIR, BASHRS_SPILL_ROOT, PLAYWRIGHT_BASE_PORT, PLAYWRIGHT_MAX_PORT, PLAYWRIGHT_PORTS_DIR, ACTIVE_QUERY_STALE_MS, AGENTS_PROMPTS_DIR, RESOURCES_DIR, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5", MODEL_FABLE = "claude-fable-5", FALLBACK_AGENT, SESSION_AGENT, GATEWAY_AGENT, FALLBACK_MODEL, SESSION_MODEL, GATEWAY_MODEL, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, _envMaxTellDepth, MAX_TELL_DEPTH;
257
267
  var init_config = __esm(() => {
258
268
  init_config_helpers();
259
269
  init_logger();
@@ -276,6 +286,7 @@ var init_config = __esm(() => {
276
286
  CLAUDE_EXECUTABLE = CLAUDE_EXECUTABLE_ENV ? resolve(CLAUDE_EXECUTABLE_ENV) : undefined;
277
287
  SNIPPETS_API_URL = (envText("NEGOTIUM_SNIPPETS_API_URL") ?? envText("SNIPPETS_API_URL") ?? "").replace(/\/+$/, "");
278
288
  BROWSER_RS_BIN = resolveBrowserRsBin(envText("NEGOTIUM_BROWSER_RS_BIN"));
289
+ BASH_RS_BIN = resolveBashRsBin(envText("NEGOTIUM_BASH_RS_BIN"));
279
290
  PLAYWRIGHT_MCP_BIN = resolveBrowserMcpBin(envText("NEGOTIUM_BROWSER_MCP_BIN"));
280
291
  TSX_BIN = resolveDependencyBin("tsx");
281
292
  TSX_LOADER = createRequire(import.meta.url).resolve("tsx");
@@ -289,7 +300,6 @@ var init_config = __esm(() => {
289
300
  COMPACTION_LOG_SERVER = resolve(PROJECT_ROOT, "src/mcp/compaction-log-server.ts");
290
301
  SYSTEM_HEALTH_SERVER = resolve(PROJECT_ROOT, "src/mcp/system-health-server.ts");
291
302
  AGENT_HEALTH_SERVER = resolve(PROJECT_ROOT, "src/mcp/agent-health-server.ts");
292
- BACKGROUND_BASH_SERVER = resolve(PROJECT_ROOT, "src/mcp/background-bash-server.ts");
293
303
  VAULT_SERVER = resolve(PROJECT_ROOT, "src/mcp/vault-server.ts");
294
304
  BG_BASH_BASE_PORT = parsePortEnv(process.env.BG_BASH_BASE_PORT, 9700);
295
305
  BG_BASH_MAX_PORT = parsePortEnv(process.env.BG_BASH_MAX_PORT, 9799);
@@ -312,6 +322,7 @@ var init_config = __esm(() => {
312
322
  DM_RESP_DIR = resolve(RUN_DIR, "dm-responses");
313
323
  SESSION_INBOX_DIR = resolve(RUN_DIR, "session-inbox");
314
324
  SESSION_ASKS_DIR = resolve(RUN_DIR, "session-asks");
325
+ BASHRS_SPILL_ROOT = resolve(RUN_DIR, "bashrs");
315
326
  PLAYWRIGHT_BASE_PORT = parsePortEnv(process.env.PLAYWRIGHT_BASE_PORT, 9100);
316
327
  PLAYWRIGHT_MAX_PORT = parsePortEnv(process.env.PLAYWRIGHT_MAX_PORT, 9499);
317
328
  PLAYWRIGHT_PORTS_DIR = resolve(RUN_DIR, "playwright-ports");
@@ -1561,7 +1572,7 @@ var exports_version = {};
1561
1572
  __export(exports_version, {
1562
1573
  NEGOTIUM_VERSION: () => NEGOTIUM_VERSION
1563
1574
  });
1564
- var NEGOTIUM_VERSION = "0.2.12";
1575
+ var NEGOTIUM_VERSION = "0.2.14";
1565
1576
 
1566
1577
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
1567
1578
  import { spawn } from "child_process";
@@ -2105,7 +2116,7 @@ function createBackgroundBashManager(options = {}) {
2105
2116
  const knownContexts = new Map;
2106
2117
  const runtimeCapability = options.capability ?? randomBytes3(32).toString("hex");
2107
2118
  const runtimeServerId = options.serverId ?? randomBytes3(16).toString("hex");
2108
- const serverFile = options.serverFile ?? BACKGROUND_BASH_SERVER;
2119
+ const bashRsBin = options.bashRsBin ?? BASH_RS_BIN;
2109
2120
  const basePort = options.basePort ?? BG_BASH_BASE_PORT;
2110
2121
  const maxPort = options.maxPort ?? BG_BASH_MAX_PORT;
2111
2122
  const fetchImpl = options.fetch ?? globalThis.fetch;
@@ -2137,7 +2148,15 @@ function createBackgroundBashManager(options = {}) {
2137
2148
  const response = await fetchImpl(`http://127.0.0.1:${port}/health`, {
2138
2149
  signal: AbortSignal.timeout(2000)
2139
2150
  });
2140
- return response.ok && await response.text() === runtimeServerId;
2151
+ if (!response.ok)
2152
+ return false;
2153
+ const body = await response.text();
2154
+ try {
2155
+ const parsed = JSON.parse(body);
2156
+ return Boolean(parsed) && typeof parsed === "object" && parsed.instance_id === runtimeServerId;
2157
+ } catch {
2158
+ return false;
2159
+ }
2141
2160
  } catch {
2142
2161
  return false;
2143
2162
  }
@@ -2155,14 +2174,20 @@ function createBackgroundBashManager(options = {}) {
2155
2174
  logger.info({ key, port: instance.port }, "background-bash server killed");
2156
2175
  }
2157
2176
  async function spawnServer(key, reservedPort, excludedPorts = new Set) {
2177
+ if (!bashRsBin) {
2178
+ throw new Error(`background-bash requires the bash-rs ${BASH_RS_VERSION} binary; run install-bash-rs.mjs (or set NEGOTIUM_BASH_RS_BIN)`);
2179
+ }
2158
2180
  const port = reservedPort ?? await allocatePort(excludedPorts);
2159
- const process2 = spawnImpl("bun", ["run", serverFile, `--port=${port}`], {
2181
+ const process2 = spawnImpl(bashRsBin, [String(port)], {
2160
2182
  stdio: "ignore",
2161
2183
  detached: false,
2162
2184
  env: {
2163
2185
  ...options.env ?? globalThis.process.env,
2164
2186
  NEGOTIUM_BG_BASH_CAPABILITY: runtimeCapability,
2165
- NEGOTIUM_BG_BASH_SERVER_ID: runtimeServerId
2187
+ NEGOTIUM_BG_BASH_SERVER_ID: runtimeServerId,
2188
+ BASHRS_HTTP_CAPABILITY: runtimeCapability,
2189
+ BASHRS_INSTANCE_ID: runtimeServerId,
2190
+ BASHRS_SPILL_ROOT
2166
2191
  }
2167
2192
  });
2168
2193
  process2.once("error", (error) => {
@@ -18617,6 +18642,7 @@ function startAiTurn(params) {
18617
18642
  bgBashPort = await ensureBgBash(userId, topic.id);
18618
18643
  } catch (err2) {
18619
18644
  logger.warn({ topicId, err: err2 }, "ai: ensureBgBash failed \u2014 proceeding without background bash tools");
18645
+ turnReminders.push("<system-reminder>Background bash tools are UNAVAILABLE this turn. The `background_bash_*` tools could not be prepared, most often because the bash-rs binary is not installed on this host. Do not attempt to call them; run short commands in the foreground instead, and tell the user if the work genuinely needs a background job.</system-reminder>");
18620
18646
  }
18621
18647
  }
18622
18648
  if (playwrightRequested && !browserProfileOwner) {
@@ -20959,6 +20985,276 @@ var init_node_plugins = __esm(() => {
20959
20985
  plugins = [];
20960
20986
  });
20961
20987
 
20988
+ // ../../packages/core/src/outbox/utils.ts
20989
+ import { mkdirSync as mkdirSync22, watch } from "fs";
20990
+ function createOutboxWatchOps(host) {
20991
+ function debouncedFlush(fn, label, delayMs) {
20992
+ let timer = null;
20993
+ let running = false;
20994
+ let pending = false;
20995
+ async function run() {
20996
+ if (running) {
20997
+ pending = true;
20998
+ return;
20999
+ }
21000
+ while (true) {
21001
+ running = true;
21002
+ pending = false;
21003
+ try {
21004
+ await fn();
21005
+ } catch (e) {
21006
+ host.logger.error({ err: e }, `${label}: Unhandled error`);
21007
+ } finally {
21008
+ running = false;
21009
+ }
21010
+ if (!pending)
21011
+ break;
21012
+ }
21013
+ }
21014
+ return () => {
21015
+ if (timer)
21016
+ clearTimeout(timer);
21017
+ timer = setTimeout(() => {
21018
+ timer = null;
21019
+ run();
21020
+ }, delayMs);
21021
+ };
21022
+ }
21023
+ function watchDir(dir, onChange) {
21024
+ try {
21025
+ mkdirSync22(dir, { recursive: true });
21026
+ const watcher = watch(dir, { recursive: true }, () => onChange());
21027
+ watcher.on("error", (e) => {
21028
+ host.logger.warn({ err: e, dir }, "outbox: fs.watch error");
21029
+ });
21030
+ return watcher;
21031
+ } catch (e) {
21032
+ host.logger.warn({ err: e, dir }, "outbox: Failed to watch dir");
21033
+ return null;
21034
+ }
21035
+ }
21036
+ return { debouncedFlush, watchDir };
21037
+ }
21038
+ var FALLBACK_INTERVAL_MS = 5000, defaultWatchOps, debouncedFlush, watchDir;
21039
+ var init_utils = __esm(() => {
21040
+ init_logger();
21041
+ defaultWatchOps = createOutboxWatchOps({ logger });
21042
+ debouncedFlush = defaultWatchOps.debouncedFlush;
21043
+ watchDir = defaultWatchOps.watchDir;
21044
+ });
21045
+
21046
+ // ../../packages/core/src/runtime/bashrs-completions.ts
21047
+ import {
21048
+ closeSync as closeSync3,
21049
+ openSync as openSync3,
21050
+ readdirSync as readdirSync7,
21051
+ readFileSync as readFileSync18,
21052
+ readSync,
21053
+ renameSync as renameSync9,
21054
+ rmSync as rmSync8,
21055
+ statSync as statSync12
21056
+ } from "fs";
21057
+ import { join as join31 } from "path";
21058
+ function setBashrsCompletionSink(sink) {
21059
+ completionSink = sink ?? defaultSink;
21060
+ }
21061
+ function isJobResult(value) {
21062
+ if (!value || typeof value !== "object")
21063
+ return false;
21064
+ const v = value;
21065
+ return typeof v.bash_id === "string" && typeof v.owner === "string";
21066
+ }
21067
+ function readTail(filePath) {
21068
+ try {
21069
+ const { size } = statSync12(filePath);
21070
+ const fd = openSync3(filePath, "r");
21071
+ try {
21072
+ const start = Math.max(0, size - TAIL_BYTES);
21073
+ const buf = Buffer.alloc(size - start);
21074
+ readSync(fd, buf, 0, buf.length, start);
21075
+ return { text: buf.toString("utf8"), truncated: start > 0 };
21076
+ } finally {
21077
+ closeSync3(fd);
21078
+ }
21079
+ } catch {
21080
+ return { text: "", truncated: false };
21081
+ }
21082
+ }
21083
+ function buildMessage(dir, result) {
21084
+ const stdout = readTail(join31(dir, "stdout.log"));
21085
+ const stderr = readTail(join31(dir, "stderr.log"));
21086
+ const parts = [];
21087
+ if (stdout.text.trim() || stdout.truncated) {
21088
+ parts.push(`stdout${stdout.truncated ? ` (truncated, full output: ${join31(dir, "stdout.log")})` : ""}:
21089
+ ${stdout.text.trim()}`);
21090
+ }
21091
+ if (stderr.text.trim() || stderr.truncated) {
21092
+ parts.push(`stderr${stderr.truncated ? ` (truncated, full output: ${join31(dir, "stderr.log")})` : ""}:
21093
+ ${stderr.text.trim()}`);
21094
+ }
21095
+ const header = watchHeader(result) ?? `[background_bash ${result.bash_id} finished]`;
21096
+ const exitLine = result.unknown ? "exit code: unknown (bash-rs restarted while this job was running)" : `exit code: ${result.exit_code ?? "unknown"}`;
21097
+ return `${header}
21098
+ ${exitLine}
21099
+ ${parts.join(`
21100
+ `) || "(no output)"}`;
21101
+ }
21102
+ function watchHeader(result) {
21103
+ if (result.matched_line) {
21104
+ return `[background_bash_watch ${result.bash_id} matched]
21105
+ matched line: ${result.matched_line.slice(0, 500)}`;
21106
+ }
21107
+ if (result.watch_outcome === "timeout") {
21108
+ return `[background_bash_watch ${result.bash_id} timed out without a match]`;
21109
+ }
21110
+ if (result.watch_outcome === "exited") {
21111
+ return `[background_bash_watch ${result.bash_id} exited before matching]`;
21112
+ }
21113
+ return null;
21114
+ }
21115
+ function parseOwner(owner) {
21116
+ const nul = owner.indexOf("\x00");
21117
+ if (nul < 0)
21118
+ return null;
21119
+ const userId = owner.slice(0, nul);
21120
+ const topicId = owner.slice(nul + 1);
21121
+ if (!userId || !topicId)
21122
+ return null;
21123
+ return { userId, topicId };
21124
+ }
21125
+ function injectedMarker(dir) {
21126
+ return join31(dir, "result.json.injected");
21127
+ }
21128
+ async function flushBashrsCompletions() {
21129
+ let entries;
21130
+ try {
21131
+ entries = readdirSync7(BASHRS_SPILL_ROOT);
21132
+ } catch {
21133
+ return;
21134
+ }
21135
+ const now = Date.now();
21136
+ for (const bashId of entries) {
21137
+ const dir = join31(BASHRS_SPILL_ROOT, bashId);
21138
+ const resultPath = join31(dir, "result.json");
21139
+ const marker = injectedMarker(dir);
21140
+ try {
21141
+ const markerStat = statSync12(marker);
21142
+ if (now - markerStat.mtimeMs > RETENTION_MS) {
21143
+ rmSync8(dir, { recursive: true, force: true });
21144
+ }
21145
+ continue;
21146
+ } catch {}
21147
+ let raw;
21148
+ try {
21149
+ raw = readFileSync18(resultPath, "utf8");
21150
+ } catch {
21151
+ continue;
21152
+ }
21153
+ let result;
21154
+ try {
21155
+ result = JSON.parse(raw);
21156
+ } catch (err2) {
21157
+ logger.warn({ err: err2, dir }, "bashrs-completions: corrupt result.json, skipping");
21158
+ continue;
21159
+ }
21160
+ if (!isJobResult(result)) {
21161
+ logger.warn({ dir }, "bashrs-completions: result.json missing bash_id/owner, skipping");
21162
+ continue;
21163
+ }
21164
+ const parsed = parseOwner(result.owner);
21165
+ if (!parsed) {
21166
+ continue;
21167
+ }
21168
+ try {
21169
+ completionSink({
21170
+ userId: parsed.userId,
21171
+ topicId: parsed.topicId,
21172
+ bashId: result.bash_id,
21173
+ message: buildMessage(dir, result)
21174
+ });
21175
+ renameSync9(resultPath, marker);
21176
+ logger.info({ bashId: result.bash_id, userId: parsed.userId, topicId: parsed.topicId }, "bashrs-completions: delivered");
21177
+ } catch (err2) {
21178
+ logger.warn({ err: err2, dir }, "bashrs-completions: delivery failed, will retry");
21179
+ }
21180
+ }
21181
+ }
21182
+ function stopLeaderResources() {
21183
+ if (watcher) {
21184
+ watcher.close();
21185
+ watcher = null;
21186
+ }
21187
+ if (fallbackTimer) {
21188
+ clearInterval(fallbackTimer);
21189
+ fallbackTimer = null;
21190
+ }
21191
+ debouncedTrigger = null;
21192
+ }
21193
+ function tryBecomeLeader() {
21194
+ if (!workerStarted || workerLease)
21195
+ return;
21196
+ const acquired = acquireRuntimeProcessLease(PROCESS_ROLE, {
21197
+ onLost: () => {
21198
+ if (workerLease !== acquired)
21199
+ return;
21200
+ workerLease = null;
21201
+ stopLeaderResources();
21202
+ logger.warn("bashrs-completions: worker leadership lost");
21203
+ }
21204
+ });
21205
+ if (!acquired)
21206
+ return;
21207
+ workerLease = acquired;
21208
+ debouncedTrigger = debouncedFlush(flushBashrsCompletions, "bashrs-completions", 200);
21209
+ watcher = watchDir(BASHRS_SPILL_ROOT, () => debouncedTrigger?.());
21210
+ fallbackTimer = setInterval(() => debouncedTrigger?.(), FALLBACK_INTERVAL_MS);
21211
+ fallbackTimer.unref?.();
21212
+ logger.info({ dir: BASHRS_SPILL_ROOT, role: PROCESS_ROLE }, "bashrs-completions: worker leadership acquired");
21213
+ flushBashrsCompletions();
21214
+ }
21215
+ function startBashrsCompletionsWorker() {
21216
+ if (workerStarted)
21217
+ return () => {};
21218
+ workerStarted = true;
21219
+ tryBecomeLeader();
21220
+ leadershipTimer = setInterval(tryBecomeLeader, PROCESS_LEASE_HEARTBEAT_MS);
21221
+ leadershipTimer.unref?.();
21222
+ return () => {
21223
+ if (!workerStarted)
21224
+ return;
21225
+ workerStarted = false;
21226
+ if (leadershipTimer) {
21227
+ clearInterval(leadershipTimer);
21228
+ leadershipTimer = null;
21229
+ }
21230
+ stopLeaderResources();
21231
+ workerLease?.stop();
21232
+ workerLease = null;
21233
+ logger.info("bashrs-completions: worker stopped");
21234
+ };
21235
+ }
21236
+ var defaultSink = ({ userId, topicId, bashId, message }) => {
21237
+ appendJsonlEntry(sessionInboxPath(userId, topicId), {
21238
+ type: "tell",
21239
+ from: "__bg_bash__",
21240
+ message,
21241
+ depth: 0,
21242
+ requestId: bashId,
21243
+ timestamp: new Date().toISOString()
21244
+ });
21245
+ }, completionSink, PROCESS_ROLE = "worker:bashrs-completions", RETENTION_MS, TAIL_BYTES, watcher = null, fallbackTimer = null, debouncedTrigger = null, leadershipTimer = null, workerLease = null, workerStarted = false;
21246
+ var init_bashrs_completions = __esm(async () => {
21247
+ init_utils();
21248
+ init_config();
21249
+ init_jsonl();
21250
+ init_logger();
21251
+ init_session_inbox_path();
21252
+ await init_runtime_process_leases();
21253
+ completionSink = defaultSink;
21254
+ RETENTION_MS = 15 * 60000;
21255
+ TAIL_BYTES = 8 * 1024;
21256
+ });
21257
+
20962
21258
  // ../../packages/core/src/runtime/delivery-ack.ts
20963
21259
  function signalForMessage(payload, messageId) {
20964
21260
  if (!payload || typeof payload !== "object")
@@ -21045,7 +21341,7 @@ function renderTurnFooter(msg) {
21045
21341
 
21046
21342
  // ../../packages/core/src/outbox/file-ops.ts
21047
21343
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
21048
- import { appendFileSync as appendFileSync2, existsSync as existsSync22, readFileSync as readFileSync18, renameSync as renameSync9, unlinkSync as unlinkSync17 } from "fs";
21344
+ import { appendFileSync as appendFileSync2, existsSync as existsSync22, readFileSync as readFileSync19, renameSync as renameSync10, unlinkSync as unlinkSync17 } from "fs";
21049
21345
  function host() {
21050
21346
  return hostContext.getStore() ?? defaultHost2;
21051
21347
  }
@@ -21072,7 +21368,7 @@ function drainOutboxFile(filePath, label) {
21072
21368
  else
21073
21369
  host().logger.info(logCtx, logMsg);
21074
21370
  try {
21075
- const leftover = readFileSync18(processingPath, "utf-8");
21371
+ const leftover = readFileSync19(processingPath, "utf-8");
21076
21372
  if (leftover)
21077
21373
  appendFileSync2(filePath, leftover.endsWith(`
21078
21374
  `) ? leftover : `${leftover}
@@ -21086,7 +21382,7 @@ function drainOutboxFile(filePath, label) {
21086
21382
  if (!existsSync22(filePath))
21087
21383
  return null;
21088
21384
  try {
21089
- renameSync9(filePath, processingPath);
21385
+ renameSync10(filePath, processingPath);
21090
21386
  } catch (e) {
21091
21387
  host().logger.warn({ err: e, filePath }, `${label}: failed to rename for processing`);
21092
21388
  return null;
@@ -21134,68 +21430,10 @@ var init_file_ops = __esm(() => {
21134
21430
  hostContext = new AsyncLocalStorage2;
21135
21431
  });
21136
21432
 
21137
- // ../../packages/core/src/outbox/utils.ts
21138
- import { mkdirSync as mkdirSync22, watch } from "fs";
21139
- function createOutboxWatchOps(host2) {
21140
- function debouncedFlush(fn, label, delayMs) {
21141
- let timer = null;
21142
- let running = false;
21143
- let pending = false;
21144
- async function run() {
21145
- if (running) {
21146
- pending = true;
21147
- return;
21148
- }
21149
- while (true) {
21150
- running = true;
21151
- pending = false;
21152
- try {
21153
- await fn();
21154
- } catch (e) {
21155
- host2.logger.error({ err: e }, `${label}: Unhandled error`);
21156
- } finally {
21157
- running = false;
21158
- }
21159
- if (!pending)
21160
- break;
21161
- }
21162
- }
21163
- return () => {
21164
- if (timer)
21165
- clearTimeout(timer);
21166
- timer = setTimeout(() => {
21167
- timer = null;
21168
- run();
21169
- }, delayMs);
21170
- };
21171
- }
21172
- function watchDir(dir, onChange) {
21173
- try {
21174
- mkdirSync22(dir, { recursive: true });
21175
- const watcher = watch(dir, { recursive: true }, () => onChange());
21176
- watcher.on("error", (e) => {
21177
- host2.logger.warn({ err: e, dir }, "outbox: fs.watch error");
21178
- });
21179
- return watcher;
21180
- } catch (e) {
21181
- host2.logger.warn({ err: e, dir }, "outbox: Failed to watch dir");
21182
- return null;
21183
- }
21184
- }
21185
- return { debouncedFlush, watchDir };
21186
- }
21187
- var FALLBACK_INTERVAL_MS = 5000, defaultWatchOps, debouncedFlush, watchDir;
21188
- var init_utils = __esm(() => {
21189
- init_logger();
21190
- defaultWatchOps = createOutboxWatchOps({ logger });
21191
- debouncedFlush = defaultWatchOps.debouncedFlush;
21192
- watchDir = defaultWatchOps.watchDir;
21193
- });
21194
-
21195
21433
  // ../../packages/core/src/runtime/inbox.ts
21196
21434
  import { createHash as createHash8, randomUUID as randomUUID20 } from "crypto";
21197
- import { readdirSync as readdirSync7, statSync as statSync12, writeFileSync as writeFileSync16 } from "fs";
21198
- import { join as join31 } from "path";
21435
+ import { readdirSync as readdirSync8, statSync as statSync13, writeFileSync as writeFileSync16 } from "fs";
21436
+ import { join as join32 } from "path";
21199
21437
  async function createAskForkPlan(options) {
21200
21438
  const snapshot = structuredClone(options.entries);
21201
21439
  const prepareSession = async () => options.synthesize(structuredClone(snapshot));
@@ -21315,23 +21553,23 @@ async function flushSessionInbox() {
21315
21553
  sweepScheduledSessionInbox();
21316
21554
  let userDirs;
21317
21555
  try {
21318
- userDirs = readdirSync7(SESSION_INBOX_DIR);
21556
+ userDirs = readdirSync8(SESSION_INBOX_DIR);
21319
21557
  } catch {
21320
21558
  return;
21321
21559
  }
21322
21560
  for (const uid of userDirs) {
21323
- const userInboxDir = join31(SESSION_INBOX_DIR, uid);
21561
+ const userInboxDir = join32(SESSION_INBOX_DIR, uid);
21324
21562
  let entries;
21325
21563
  try {
21326
- entries = readdirSync7(userInboxDir);
21564
+ entries = readdirSync8(userInboxDir);
21327
21565
  } catch {
21328
21566
  continue;
21329
21567
  }
21330
21568
  for (const entry of entries) {
21331
- const entryPath = join31(userInboxDir, entry);
21569
+ const entryPath = join32(userInboxDir, entry);
21332
21570
  let isDir = false;
21333
21571
  try {
21334
- isDir = statSync12(entryPath).isDirectory();
21572
+ isDir = statSync13(entryPath).isDirectory();
21335
21573
  } catch {
21336
21574
  continue;
21337
21575
  }
@@ -21413,15 +21651,15 @@ ${schedule.message}`, topic.agent, {
21413
21651
  function sweepScheduledSessionInbox(nowMs = Date.now()) {
21414
21652
  let userDirs;
21415
21653
  try {
21416
- userDirs = readdirSync7(SESSION_INBOX_DIR);
21654
+ userDirs = readdirSync8(SESSION_INBOX_DIR);
21417
21655
  } catch {
21418
21656
  return;
21419
21657
  }
21420
21658
  for (const userId of userDirs) {
21421
- const userInboxDir = join31(SESSION_INBOX_DIR, userId);
21659
+ const userInboxDir = join32(SESSION_INBOX_DIR, userId);
21422
21660
  let files;
21423
21661
  try {
21424
- files = readdirSync7(userInboxDir);
21662
+ files = readdirSync8(userInboxDir);
21425
21663
  } catch {
21426
21664
  continue;
21427
21665
  }
@@ -21430,7 +21668,7 @@ function sweepScheduledSessionInbox(nowMs = Date.now()) {
21430
21668
  const topicId = topicIdFromScheduledSessionInboxFileName(file);
21431
21669
  if (!topicId)
21432
21670
  continue;
21433
- const schedulePath = join31(userInboxDir, file);
21671
+ const schedulePath = join32(userInboxDir, file);
21434
21672
  const hasProcessingClaim = files.includes(`${file}.processing`);
21435
21673
  if (!hasProcessingClaim && !scheduledFileNeedsClaim(schedulePath, nowMs))
21436
21674
  continue;
@@ -21784,62 +22022,62 @@ ${entry.message}
21784
22022
  });
21785
22023
  logger.info({ topicName, from: entry.from, requestId, callerTopicId }, "session-inbox: ask delivered");
21786
22024
  }
21787
- function stopLeaderResources() {
21788
- if (watcher) {
21789
- watcher.close();
21790
- watcher = null;
22025
+ function stopLeaderResources2() {
22026
+ if (watcher2) {
22027
+ watcher2.close();
22028
+ watcher2 = null;
21791
22029
  }
21792
- if (fallbackTimer) {
21793
- clearInterval(fallbackTimer);
21794
- fallbackTimer = null;
22030
+ if (fallbackTimer2) {
22031
+ clearInterval(fallbackTimer2);
22032
+ fallbackTimer2 = null;
21795
22033
  }
21796
- debouncedTrigger = null;
22034
+ debouncedTrigger2 = null;
21797
22035
  }
21798
22036
  function tryBecomeSessionInboxLeader() {
21799
- if (!workerStarted || workerLease)
22037
+ if (!workerStarted2 || workerLease2)
21800
22038
  return;
21801
22039
  let acquired = null;
21802
22040
  acquired = acquireRuntimeProcessLease(SESSION_INBOX_PROCESS_ROLE, {
21803
22041
  onLost: () => {
21804
- if (workerLease !== acquired)
22042
+ if (workerLease2 !== acquired)
21805
22043
  return;
21806
- workerLease = null;
21807
- stopLeaderResources();
22044
+ workerLease2 = null;
22045
+ stopLeaderResources2();
21808
22046
  logger.warn("session-inbox: worker leadership lost");
21809
22047
  }
21810
22048
  });
21811
22049
  if (!acquired)
21812
22050
  return;
21813
- workerLease = acquired;
21814
- debouncedTrigger = debouncedFlush(flushSessionInbox, "session-inbox", 200);
21815
- watcher = watchDir(SESSION_INBOX_DIR, () => debouncedTrigger?.());
21816
- fallbackTimer = setInterval(() => debouncedTrigger?.(), FALLBACK_INTERVAL_MS);
21817
- fallbackTimer.unref?.();
22051
+ workerLease2 = acquired;
22052
+ debouncedTrigger2 = debouncedFlush(flushSessionInbox, "session-inbox", 200);
22053
+ watcher2 = watchDir(SESSION_INBOX_DIR, () => debouncedTrigger2?.());
22054
+ fallbackTimer2 = setInterval(() => debouncedTrigger2?.(), FALLBACK_INTERVAL_MS);
22055
+ fallbackTimer2.unref?.();
21818
22056
  logger.info({ dir: SESSION_INBOX_DIR, role: SESSION_INBOX_PROCESS_ROLE }, "session-inbox: worker leadership acquired");
21819
22057
  flushSessionInbox();
21820
22058
  }
21821
22059
  function startSessionInboxWorker() {
21822
- if (workerStarted)
22060
+ if (workerStarted2)
21823
22061
  return () => {};
21824
- workerStarted = true;
22062
+ workerStarted2 = true;
21825
22063
  tryBecomeSessionInboxLeader();
21826
- leadershipTimer = setInterval(tryBecomeSessionInboxLeader, PROCESS_LEASE_HEARTBEAT_MS);
21827
- leadershipTimer.unref?.();
22064
+ leadershipTimer2 = setInterval(tryBecomeSessionInboxLeader, PROCESS_LEASE_HEARTBEAT_MS);
22065
+ leadershipTimer2.unref?.();
21828
22066
  return () => {
21829
- if (!workerStarted)
22067
+ if (!workerStarted2)
21830
22068
  return;
21831
- workerStarted = false;
21832
- if (leadershipTimer) {
21833
- clearInterval(leadershipTimer);
21834
- leadershipTimer = null;
22069
+ workerStarted2 = false;
22070
+ if (leadershipTimer2) {
22071
+ clearInterval(leadershipTimer2);
22072
+ leadershipTimer2 = null;
21835
22073
  }
21836
- stopLeaderResources();
21837
- workerLease?.stop();
21838
- workerLease = null;
22074
+ stopLeaderResources2();
22075
+ workerLease2?.stop();
22076
+ workerLease2 = null;
21839
22077
  logger.info("session-inbox: worker stopped");
21840
22078
  };
21841
22079
  }
21842
- var topicWorkerBusy, watcher = null, fallbackTimer = null, debouncedTrigger = null, leadershipTimer = null, workerLease = null, workerStarted = false, SESSION_INBOX_PROCESS_ROLE = "worker:session-inbox";
22080
+ var topicWorkerBusy, watcher2 = null, fallbackTimer2 = null, debouncedTrigger2 = null, leadershipTimer2 = null, workerLease2 = null, workerStarted2 = false, SESSION_INBOX_PROCESS_ROLE = "worker:session-inbox";
21843
22081
  var init_inbox = __esm(async () => {
21844
22082
  init_file_ops();
21845
22083
  init_utils();
@@ -21891,6 +22129,7 @@ __export(exports_src, {
21891
22129
  startSessionInboxWorker: () => startSessionInboxWorker,
21892
22130
  startNegotiumNodeModules: () => startNegotiumNodeModules,
21893
22131
  startDurableTurnRequestWorker: () => startDurableTurnRequestWorker,
22132
+ startBashrsCompletionsWorker: () => startBashrsCompletionsWorker,
21894
22133
  startAskUserQuestionGateOwner: () => startAskUserQuestionGateOwner,
21895
22134
  startAiTurn: () => startAiTurn,
21896
22135
  setTopicSessionId: () => setTopicSessionId,
@@ -21899,6 +22138,7 @@ __export(exports_src, {
21899
22138
  setPlaywrightUnavailableNotifier: () => setPlaywrightUnavailableNotifier,
21900
22139
  setNodeMcpServers: () => setNodeMcpServers,
21901
22140
  setFileHooks: () => setFileHooks,
22141
+ setBashrsCompletionSink: () => setBashrsCompletionSink,
21902
22142
  setApiTopicConfig: () => setApiTopicConfig,
21903
22143
  sessionInboxPath: () => sessionInboxPath,
21904
22144
  selectableModel: () => selectableModel,
@@ -21991,6 +22231,7 @@ __export(exports_src, {
21991
22231
  forkAgentSession: () => forkAgentSession,
21992
22232
  flushSessionInbox: () => flushSessionInbox,
21993
22233
  flushPeerRuntimeEvents: () => flushPeerRuntimeEvents,
22234
+ flushBashrsCompletions: () => flushBashrsCompletions,
21994
22235
  findTopicTitleConflict: () => findTopicTitleConflict,
21995
22236
  fileHooks: () => fileHooks,
21996
22237
  failInterruptedRemoteAskCallbacks: () => failInterruptedRemoteAskCallbacks,
@@ -22133,6 +22374,7 @@ var init_src = __esm(async () => {
22133
22374
  init_active_rooms(),
22134
22375
  init_ask_callbacks(),
22135
22376
  init_background_sessions(),
22377
+ init_bashrs_completions(),
22136
22378
  init_delivery_ack(),
22137
22379
  init_inbox(),
22138
22380
  init_turn_runner(),
@@ -22156,11 +22398,11 @@ var init_src = __esm(async () => {
22156
22398
  });
22157
22399
 
22158
22400
  // ../../packages/core/src/storage/conversation-migration.ts
22159
- import { copyFileSync as copyFileSync3, existsSync as existsSync23, mkdirSync as mkdirSync23, readFileSync as readFileSync19 } from "fs";
22160
- import { dirname as dirname15, join as join32 } from "path";
22401
+ import { copyFileSync as copyFileSync3, existsSync as existsSync23, mkdirSync as mkdirSync23, readFileSync as readFileSync20 } from "fs";
22402
+ import { dirname as dirname15, join as join33 } from "path";
22161
22403
  function readEntries(path) {
22162
22404
  const entries = [];
22163
- for (const [index, line] of readFileSync19(path, "utf8").split(`
22405
+ for (const [index, line] of readFileSync20(path, "utf8").split(`
22164
22406
  `).entries()) {
22165
22407
  if (!line.trim())
22166
22408
  continue;
@@ -22224,7 +22466,7 @@ function migrateLegacyCompactedConversations() {
22224
22466
  result.skipped++;
22225
22467
  continue;
22226
22468
  }
22227
- const backupPath = join32(resolveStorageDataDir(), "conversation-migration-backups", MIGRATION_NAME, userId, `${sanitizeTopicName(topic.title, true)}.jsonl`);
22469
+ const backupPath = join33(resolveStorageDataDir(), "conversation-migration-backups", MIGRATION_NAME, userId, `${sanitizeTopicName(topic.title, true)}.jsonl`);
22228
22470
  const sourcePath = existsSync23(backupPath) ? backupPath : rawPath;
22229
22471
  const legacyEntries = readEntries(sourcePath);
22230
22472
  const compactIndex = compactionEntryIndex(legacyEntries);
@@ -22283,11 +22525,13 @@ __export(exports_node_host, {
22283
22525
  startSessionInboxWorker: () => startSessionInboxWorker,
22284
22526
  startNegotiumNodeModules: () => startNegotiumNodeModules,
22285
22527
  startDurableTurnRequestWorker: () => startDurableTurnRequestWorker,
22528
+ startBashrsCompletionsWorker: () => startBashrsCompletionsWorker,
22286
22529
  startAskUserQuestionGateOwner: () => startAskUserQuestionGateOwner,
22287
22530
  startAiTurn: () => startAiTurn,
22288
22531
  setRuntimeMcpPort: () => setRuntimeMcpPort,
22289
22532
  setNodeMcpServers: () => setNodeMcpServers,
22290
22533
  setFileHooks: () => setFileHooks,
22534
+ setBashrsCompletionSink: () => setBashrsCompletionSink,
22291
22535
  saveVaultEntry: () => saveVaultEntry,
22292
22536
  runtimeBus: () => runtimeBus,
22293
22537
  runShutdown: () => runShutdown,
@@ -22310,6 +22554,7 @@ __export(exports_node_host, {
22310
22554
  isParticipant: () => isParticipant,
22311
22555
  getVisibleTopics: () => getVisibleTopics,
22312
22556
  getTopic: () => getTopic,
22557
+ flushBashrsCompletions: () => flushBashrsCompletions,
22313
22558
  executeVaultCommand: () => executeVaultCommand,
22314
22559
  ensurePersonalGeneral: () => ensurePersonalGeneral,
22315
22560
  deleteVaultEntry: () => deleteVaultEntry,
@@ -22355,6 +22600,7 @@ var init_node_host = __esm(async () => {
22355
22600
  init_manager2(),
22356
22601
  init_active_rooms(),
22357
22602
  init_background_sessions(),
22603
+ init_bashrs_completions(),
22358
22604
  init_inbox(),
22359
22605
  init_turn_runner(),
22360
22606
  init_api_messages(),
@@ -22368,7 +22614,7 @@ var init_node_host = __esm(async () => {
22368
22614
  });
22369
22615
 
22370
22616
  // ../../packages/core/src/agents/mcp-tools/inline-assets.ts
22371
- import { existsSync as existsSync24, readFileSync as readFileSync20, statSync as statSync13 } from "fs";
22617
+ import { existsSync as existsSync24, readFileSync as readFileSync21, statSync as statSync14 } from "fs";
22372
22618
  import { extname as extname2, isAbsolute as isAbsolute6, resolve as resolve16 } from "path";
22373
22619
  function isNonLocal(ref) {
22374
22620
  return /^(?:[a-z][a-z0-9+.-]*:|\/\/|#)/i.test(ref.trim());
@@ -22396,12 +22642,12 @@ function inlineLocalAssets(html, options) {
22396
22642
  const abs = isAbsolute6(relPath) ? relPath : resolve16(baseDir, relPath);
22397
22643
  let bytes;
22398
22644
  try {
22399
- if (!existsSync24(abs) || !statSync13(abs).isFile()) {
22645
+ if (!existsSync24(abs) || !statSync14(abs).isFile()) {
22400
22646
  unresolved.push(ref);
22401
22647
  cache.set(ref, null);
22402
22648
  return null;
22403
22649
  }
22404
- bytes = statSync13(abs).size;
22650
+ bytes = statSync14(abs).size;
22405
22651
  } catch {
22406
22652
  unresolved.push(ref);
22407
22653
  cache.set(ref, null);
@@ -22421,7 +22667,7 @@ function inlineLocalAssets(html, options) {
22421
22667
  let uri;
22422
22668
  try {
22423
22669
  const mime = MIME_BY_EXT[extname2(abs).toLowerCase()] ?? "application/octet-stream";
22424
- uri = `data:${mime};base64,${readFileSync20(abs).toString("base64")}`;
22670
+ uri = `data:${mime};base64,${readFileSync21(abs).toString("base64")}`;
22425
22671
  } catch {
22426
22672
  unresolved.push(ref);
22427
22673
  cache.set(ref, null);
@@ -23207,8 +23453,8 @@ __export(exports_agent_health, {
23207
23453
  createAgentHealthMcpServer: () => createAgentHealthMcpServer
23208
23454
  });
23209
23455
  import { spawn as spawn6 } from "child_process";
23210
- import { existsSync as existsSync25, readdirSync as readdirSync8 } from "fs";
23211
- import { join as join33 } from "path";
23456
+ import { existsSync as existsSync25, readdirSync as readdirSync9 } from "fs";
23457
+ import { join as join34 } from "path";
23212
23458
  import { McpServer as McpServer4 } from "@modelcontextprotocol/sdk/server/mcp.js";
23213
23459
  import { z as z9 } from "zod";
23214
23460
  function signalProcessTree2(child, signal) {
@@ -23452,12 +23698,12 @@ ${results.every((result) => result.ok) ? "All agents healthy" : "Some agents fai
23452
23698
  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 () => {
23453
23699
  if (!context.userId)
23454
23700
  return mcpOk("\uC2E4\uD589 \uC911\uC778 \uCFFC\uB9AC \uC870\uD68C \uBD88\uAC00 (user context \uC5C6\uC74C)");
23455
- const stateDir = join33(USERS_LOG_DIR, context.userId, "active-queries");
23701
+ const stateDir = join34(USERS_LOG_DIR, context.userId, "active-queries");
23456
23702
  if (!existsSync25(stateDir))
23457
23703
  return mcpOk("\uC2E4\uD589 \uC911\uC778 \uCFFC\uB9AC \uC5C6\uC74C");
23458
23704
  let files;
23459
23705
  try {
23460
- files = readdirSync8(stateDir);
23706
+ files = readdirSync9(stateDir);
23461
23707
  } catch {
23462
23708
  return mcpOk("\uC2E4\uD589 \uC911\uC778 \uCFFC\uB9AC \uC5C6\uC74C");
23463
23709
  }
@@ -23465,7 +23711,7 @@ ${results.every((result) => result.ok) ? "All agents healthy" : "Some agents fai
23465
23711
  const entries = files.flatMap((file) => {
23466
23712
  if (!file.endsWith(".json"))
23467
23713
  return [];
23468
- const state = readJsonFile(join33(stateDir, file));
23714
+ const state = readJsonFile(join34(stateDir, file));
23469
23715
  if (!state)
23470
23716
  return [];
23471
23717
  const sinceMs = new Date(state.since).getTime();
@@ -23701,7 +23947,7 @@ var exports_default_host = {};
23701
23947
  __export(exports_default_host, {
23702
23948
  createDefaultSessionCommMcpHost: () => createDefaultSessionCommMcpHost
23703
23949
  });
23704
- import { basename as basename6, join as join34 } from "path";
23950
+ import { basename as basename6, join as join35 } from "path";
23705
23951
  function ok2(text2) {
23706
23952
  return { content: [{ type: "text", text: text2 }] };
23707
23953
  }
@@ -23743,10 +23989,10 @@ function remoteTarget(context, to) {
23743
23989
  return { node: to.slice(0, slash), topic: to.slice(slash + 1) };
23744
23990
  }
23745
23991
  function activeQuery(context, topicId, title) {
23746
- const dir = join34(USERS_LOG_DIR, context.userId, "active-queries");
23747
- const candidates = [join34(dir, `${sanitizeId(topicId)}.json`)];
23992
+ const dir = join35(USERS_LOG_DIR, context.userId, "active-queries");
23993
+ const candidates = [join35(dir, `${sanitizeId(topicId)}.json`)];
23748
23994
  if (title && basename6(title) === title && title !== "." && title !== "..") {
23749
- candidates.push(join34(dir, `${title}.json`));
23995
+ candidates.push(join35(dir, `${title}.json`));
23750
23996
  }
23751
23997
  for (const path of candidates) {
23752
23998
  const state = readJsonFile(path);
@@ -24396,18 +24642,18 @@ __export(exports_wiki_server, {
24396
24642
  import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
24397
24643
  import { randomUUID as randomUUID21 } from "crypto";
24398
24644
  import {
24399
- closeSync as closeSync3,
24645
+ closeSync as closeSync4,
24400
24646
  existsSync as existsSync26,
24401
24647
  mkdirSync as mkdirSync24,
24402
- openSync as openSync3,
24403
- readdirSync as readdirSync9,
24404
- readFileSync as readFileSync21,
24405
- renameSync as renameSync10,
24406
- statSync as statSync14,
24648
+ openSync as openSync4,
24649
+ readdirSync as readdirSync10,
24650
+ readFileSync as readFileSync22,
24651
+ renameSync as renameSync11,
24652
+ statSync as statSync15,
24407
24653
  unlinkSync as unlinkSync18,
24408
24654
  writeFileSync as writeFileSync17
24409
24655
  } from "fs";
24410
- import { basename as basename7, dirname as dirname16, join as join35, resolve as resolve17 } from "path";
24656
+ import { basename as basename7, dirname as dirname16, join as join36, resolve as resolve17 } from "path";
24411
24657
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
24412
24658
  import { StdioServerTransport as StdioServerTransport2 } from "@modelcontextprotocol/sdk/server/stdio.js";
24413
24659
  import {
@@ -24441,20 +24687,20 @@ function acquireRecoveryGuard(lockPath) {
24441
24687
  const deadline = Date.now() + FILE_LOCK_TIMEOUT_MS;
24442
24688
  while (true) {
24443
24689
  try {
24444
- const fd = openSync3(guardPath, "wx");
24690
+ const fd = openSync4(guardPath, "wx");
24445
24691
  try {
24446
24692
  writeFileSync17(fd, ownerToken, "utf-8");
24447
24693
  } catch (error2) {
24448
- closeSync3(fd);
24694
+ closeSync4(fd);
24449
24695
  try {
24450
24696
  unlinkSync18(guardPath);
24451
24697
  } catch {}
24452
24698
  throw error2;
24453
24699
  }
24454
24700
  return () => {
24455
- closeSync3(fd);
24701
+ closeSync4(fd);
24456
24702
  try {
24457
- if (readFileSync21(guardPath, "utf-8") === ownerToken)
24703
+ if (readFileSync22(guardPath, "utf-8") === ownerToken)
24458
24704
  unlinkSync18(guardPath);
24459
24705
  } catch {}
24460
24706
  };
@@ -24474,21 +24720,21 @@ function acquireFileLock(path) {
24474
24720
  const deadline = Date.now() + FILE_LOCK_TIMEOUT_MS;
24475
24721
  while (true) {
24476
24722
  try {
24477
- const fd = openSync3(lockPath, "wx");
24723
+ const fd = openSync4(lockPath, "wx");
24478
24724
  try {
24479
24725
  writeFileSync17(fd, ownerToken, "utf-8");
24480
24726
  } catch (error2) {
24481
- closeSync3(fd);
24727
+ closeSync4(fd);
24482
24728
  try {
24483
24729
  unlinkSync18(lockPath);
24484
24730
  } catch {}
24485
24731
  throw error2;
24486
24732
  }
24487
24733
  return () => {
24488
- closeSync3(fd);
24734
+ closeSync4(fd);
24489
24735
  const releaseGuard = acquireRecoveryGuard(lockPath);
24490
24736
  try {
24491
- if (readFileSync21(lockPath, "utf-8") === ownerToken)
24737
+ if (readFileSync22(lockPath, "utf-8") === ownerToken)
24492
24738
  unlinkSync18(lockPath);
24493
24739
  } catch {} finally {
24494
24740
  releaseGuard();
@@ -24500,8 +24746,8 @@ function acquireFileLock(path) {
24500
24746
  const releaseGuard = acquireRecoveryGuard(lockPath);
24501
24747
  try {
24502
24748
  try {
24503
- const staleToken = readFileSync21(lockPath, "utf-8");
24504
- if (Date.now() - statSync14(lockPath).mtimeMs > FILE_LOCK_STALE_MS && readFileSync21(lockPath, "utf-8") === staleToken) {
24749
+ const staleToken = readFileSync22(lockPath, "utf-8");
24750
+ if (Date.now() - statSync15(lockPath).mtimeMs > FILE_LOCK_STALE_MS && readFileSync22(lockPath, "utf-8") === staleToken) {
24505
24751
  unlinkSync18(lockPath);
24506
24752
  continue;
24507
24753
  }
@@ -24522,7 +24768,7 @@ function atomicWriteFile(path, content) {
24522
24768
  const temporaryPath = `${path}.tmp.${process.pid}.${Date.now()}`;
24523
24769
  writeFileSync17(temporaryPath, content, "utf-8");
24524
24770
  try {
24525
- renameSync10(temporaryPath, path);
24771
+ renameSync11(temporaryPath, path);
24526
24772
  } catch (error2) {
24527
24773
  try {
24528
24774
  unlinkSync18(temporaryPath);
@@ -24554,17 +24800,17 @@ function wikiQuery(args) {
24554
24800
  function scan(dir, label) {
24555
24801
  ensureDir(dir);
24556
24802
  try {
24557
- for (const entry of readdirSync9(dir, { withFileTypes: true })) {
24803
+ for (const entry of readdirSync10(dir, { withFileTypes: true })) {
24558
24804
  if (entry.isDirectory()) {
24559
- const sub = join35(dir, entry.name);
24805
+ const sub = join36(dir, entry.name);
24560
24806
  if (label === "articles" || label === "skills") {
24561
24807
  try {
24562
- for (const f of readdirSync9(sub, { withFileTypes: true })) {
24808
+ for (const f of readdirSync10(sub, { withFileTypes: true })) {
24563
24809
  if (!f.isFile() || !f.name.endsWith(".md"))
24564
24810
  continue;
24565
- const fp = join35(sub, f.name);
24811
+ const fp = join36(sub, f.name);
24566
24812
  try {
24567
- const text2 = readFileSync21(fp, "utf-8");
24813
+ const text2 = readFileSync22(fp, "utf-8");
24568
24814
  scored.push({
24569
24815
  score: scoreMatch(text2),
24570
24816
  path: `${label}/${entry.name}/${f.name}`,
@@ -24575,9 +24821,9 @@ function wikiQuery(args) {
24575
24821
  } catch {}
24576
24822
  }
24577
24823
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
24578
- const fp = join35(dir, entry.name);
24824
+ const fp = join36(dir, entry.name);
24579
24825
  try {
24580
- const text2 = readFileSync21(fp, "utf-8");
24826
+ const text2 = readFileSync22(fp, "utf-8");
24581
24827
  scored.push({
24582
24828
  score: scoreMatch(text2),
24583
24829
  path: `${label}/${entry.name}`,
@@ -24685,18 +24931,18 @@ function wikiLastConversation(args) {
24685
24931
  const name = slugify(topicNameFrom(rawTopic));
24686
24932
  const archiveDir = resolve17(runtime().archiveDir, name);
24687
24933
  try {
24688
- let files = existsSync26(archiveDir) ? readdirSync9(archiveDir).filter((f) => f.endsWith(".jsonl")).sort().reverse() : [];
24934
+ let files = existsSync26(archiveDir) ? readdirSync10(archiveDir).filter((f) => f.endsWith(".jsonl")).sort().reverse() : [];
24689
24935
  if (files.length === 0) {
24690
- files = existsSync26(runtime().archiveDir) ? readdirSync9(runtime().archiveDir).filter((f) => f.startsWith(name) && f.endsWith(".jsonl")).sort().reverse() : [];
24936
+ files = existsSync26(runtime().archiveDir) ? readdirSync10(runtime().archiveDir).filter((f) => f.startsWith(name) && f.endsWith(".jsonl")).sort().reverse() : [];
24691
24937
  }
24692
24938
  if (files.length === 0) {
24693
24939
  return {
24694
24940
  content: [{ type: "text", text: `No archive found for topic: ${rawTopic}` }]
24695
24941
  };
24696
24942
  }
24697
- const actualPath = files[0].includes("/") ? files[0] : resolve17(existsSync26(archiveDir) && readdirSync9(archiveDir).includes(files[0]) ? archiveDir : runtime().archiveDir, files[0]);
24943
+ const actualPath = files[0].includes("/") ? files[0] : resolve17(existsSync26(archiveDir) && readdirSync10(archiveDir).includes(files[0]) ? archiveDir : runtime().archiveDir, files[0]);
24698
24944
  try {
24699
- const raw = readFileSync21(actualPath, "utf-8");
24945
+ const raw = readFileSync22(actualPath, "utf-8");
24700
24946
  const lines = raw.trim().split(`
24701
24947
  `).filter(Boolean);
24702
24948
  const turns2 = [];
@@ -24762,14 +25008,14 @@ function skillQuery(args) {
24762
25008
  ensureDir(runtime().skillsDir);
24763
25009
  const matches = [];
24764
25010
  try {
24765
- for (const entry of readdirSync9(runtime().skillsDir, {
25011
+ for (const entry of readdirSync10(runtime().skillsDir, {
24766
25012
  withFileTypes: true
24767
25013
  })) {
24768
25014
  if (!entry.isDirectory())
24769
25015
  continue;
24770
25016
  const skillFile = resolve17(runtime().skillsDir, entry.name, "skill.md");
24771
25017
  try {
24772
- const text2 = readFileSync21(skillFile, "utf-8");
25018
+ const text2 = readFileSync22(skillFile, "utf-8");
24773
25019
  const lower = text2.toLowerCase();
24774
25020
  let score = 0;
24775
25021
  for (const w of query2.split(/\s+/).filter(Boolean)) {
@@ -24840,7 +25086,7 @@ ${fresh.join(`
24840
25086
  const skillPath = resolve17(skillDir, "skill.md");
24841
25087
  let finalContent = content;
24842
25088
  try {
24843
- const existing = readFileSync21(skillPath, "utf-8");
25089
+ const existing = readFileSync22(skillPath, "utf-8");
24844
25090
  finalContent = mergeGotchas(content, extractGotchas(existing));
24845
25091
  } catch {}
24846
25092
  writeFileSync17(skillPath, finalContent, "utf-8");
@@ -24888,7 +25134,7 @@ function saveWikiEntry(args) {
24888
25134
  if (topicId && setTopicBrief2) {
24889
25135
  try {
24890
25136
  const briefPath = resolve17(runtime().topicsDir, `${fileSlug}.md`);
24891
- let briefMd = existsSync26(briefPath) ? readFileSync21(briefPath, "utf-8") : undefined;
25137
+ let briefMd = existsSync26(briefPath) ? readFileSync22(briefPath, "utf-8") : undefined;
24892
25138
  if (briefMd === undefined && getTopicBrief2 && !getTopicBrief2(fileSlug)?.briefMd) {
24893
25139
  const legacy = getTopicBrief2(topicId)?.briefMd;
24894
25140
  if (legacy)
@@ -24965,7 +25211,7 @@ function indexUpsert(args) {
24965
25211
  try {
24966
25212
  let index;
24967
25213
  try {
24968
- index = readFileSync21(indexPath, "utf-8");
25214
+ index = readFileSync22(indexPath, "utf-8");
24969
25215
  } catch {
24970
25216
  index = "";
24971
25217
  }
@@ -25252,13 +25498,13 @@ __export(exports_activity_log, {
25252
25498
  import {
25253
25499
  existsSync as existsSync27,
25254
25500
  mkdirSync as mkdirSync25,
25255
- readdirSync as readdirSync10,
25256
- renameSync as renameSync11,
25257
- statSync as statSync15,
25501
+ readdirSync as readdirSync11,
25502
+ renameSync as renameSync12,
25503
+ statSync as statSync16,
25258
25504
  unlinkSync as unlinkSync19,
25259
25505
  writeFileSync as writeFileSync18
25260
25506
  } from "fs";
25261
- import { basename as basename8, join as join36 } from "path";
25507
+ import { basename as basename8, join as join37 } from "path";
25262
25508
  function startLogRotation() {
25263
25509
  if (rotationTimer)
25264
25510
  return;
@@ -25272,12 +25518,12 @@ function writeLog(entry) {
25272
25518
  mkdirSync25(logDir, { recursive: true });
25273
25519
  const safeSession = sanitizeTopicName(entry.session);
25274
25520
  const sidShort = entry.sessionId ? entry.sessionId.slice(0, 8) : "new";
25275
- const file = join36(logDir, `${entry.userId}_${safeSession}_${sidShort}.jsonl`);
25521
+ const file = join37(logDir, `${entry.userId}_${safeSession}_${sidShort}.jsonl`);
25276
25522
  try {
25277
- const stat = statSync15(file);
25523
+ const stat = statSync16(file);
25278
25524
  if (stat.size >= MAX_FILE_SIZE) {
25279
25525
  const rotated = file.replace(/\.jsonl$/, `.${Date.now()}.jsonl`);
25280
- renameSync11(file, rotated);
25526
+ renameSync12(file, rotated);
25281
25527
  }
25282
25528
  } catch {}
25283
25529
  try {
@@ -25290,9 +25536,9 @@ function rotateOldLogs() {
25290
25536
  const logDir = resolveStorageLogDir();
25291
25537
  mkdirSync25(logDir, { recursive: true });
25292
25538
  try {
25293
- const files = readdirSync10(logDir).filter((f) => f.endsWith(".jsonl")).map((f) => {
25539
+ const files = readdirSync11(logDir).filter((f) => f.endsWith(".jsonl")).map((f) => {
25294
25540
  try {
25295
- const stat = statSync15(join36(logDir, f));
25541
+ const stat = statSync16(join37(logDir, f));
25296
25542
  return { name: f, size: stat.size, mtimeMs: stat.mtimeMs };
25297
25543
  } catch {
25298
25544
  return null;
@@ -25308,7 +25554,7 @@ function rotateOldLogs() {
25308
25554
  if (freed >= toFree)
25309
25555
  break;
25310
25556
  try {
25311
- unlinkSync19(join36(logDir, file.name));
25557
+ unlinkSync19(join37(logDir, file.name));
25312
25558
  freed += file.size;
25313
25559
  logger.info({ file: file.name, sizeKB: (file.size / 1024).toFixed(0) }, "Rotated out old log");
25314
25560
  } catch (e) {
@@ -25320,9 +25566,9 @@ function rotateOldLogs() {
25320
25566
  }
25321
25567
  }
25322
25568
  function writeSentFileLog(entry) {
25323
- const dir = join36(resolveStorageUsersLogDir(), String(entry.userId));
25569
+ const dir = join37(resolveStorageUsersLogDir(), String(entry.userId));
25324
25570
  mkdirSync25(dir, { recursive: true });
25325
- const file = join36(dir, "sent-files.jsonl");
25571
+ const file = join37(dir, "sent-files.jsonl");
25326
25572
  try {
25327
25573
  appendJsonlEntry(file, { ...entry, fileName: basename8(entry.filePath) });
25328
25574
  } catch (e) {
@@ -25333,7 +25579,7 @@ function entryMatchesTopic(e, topicName) {
25333
25579
  return e.topicName === topicName;
25334
25580
  }
25335
25581
  function readSentFilesForTopic(userId, topicName) {
25336
- const file = join36(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
25582
+ const file = join37(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
25337
25583
  if (!existsSync27(file))
25338
25584
  return [];
25339
25585
  try {
@@ -25344,7 +25590,7 @@ function readSentFilesForTopic(userId, topicName) {
25344
25590
  }
25345
25591
  }
25346
25592
  function removeSentFilesForTopic(userId, topicName) {
25347
- const file = join36(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
25593
+ const file = join37(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
25348
25594
  if (!existsSync27(file))
25349
25595
  return;
25350
25596
  try {
@@ -26304,7 +26550,7 @@ var init_sse_transport = () => {};
26304
26550
 
26305
26551
  // ../../packages/mcp/src/server.ts
26306
26552
  import { createHash as createHash9, randomUUID as randomUUID23 } from "crypto";
26307
- import { realpathSync as realpathSync6, statSync as statSync16 } from "fs";
26553
+ import { realpathSync as realpathSync6, statSync as statSync17 } from "fs";
26308
26554
  import { basename as basename9, extname as extname3, resolve as resolve19 } from "path";
26309
26555
  import { McpServer as McpServer7 } from "@modelcontextprotocol/sdk/server/mcp.js";
26310
26556
  import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
@@ -26341,7 +26587,7 @@ function localFileInfo(ctx, filePath) {
26341
26587
  return { error: "Access denied. Path matches the sensitive-file blacklist." };
26342
26588
  }
26343
26589
  try {
26344
- const stats = statSync16(normalizedPath);
26590
+ const stats = statSync17(normalizedPath);
26345
26591
  if (!stats.isFile())
26346
26592
  return { error: `${filePath} is not a file` };
26347
26593
  return {
@@ -26868,7 +27114,7 @@ var init_spec = __esm(() => {
26868
27114
  });
26869
27115
 
26870
27116
  // ../../packages/mcp-host/src/manifest.ts
26871
- import { existsSync as existsSync28, mkdirSync as mkdirSync26, readFileSync as readFileSync22, renameSync as renameSync12, writeFileSync as writeFileSync19 } from "fs";
27117
+ import { existsSync as existsSync28, mkdirSync as mkdirSync26, readFileSync as readFileSync23, renameSync as renameSync13, writeFileSync as writeFileSync19 } from "fs";
26872
27118
  import { dirname as dirname17 } from "path";
26873
27119
  import { z as z14 } from "zod";
26874
27120
 
@@ -26917,7 +27163,7 @@ class McpManifest {
26917
27163
  return;
26918
27164
  let parsed;
26919
27165
  try {
26920
- parsed = manifestFileSchema.parse(JSON.parse(readFileSync22(this.file, "utf8")));
27166
+ parsed = manifestFileSchema.parse(JSON.parse(readFileSync23(this.file, "utf8")));
26921
27167
  } catch (e) {
26922
27168
  throw new Error(`Invalid MCP manifest at ${this.file}: ${e instanceof Error ? e.message : String(e)}`);
26923
27169
  }
@@ -26937,7 +27183,7 @@ class McpManifest {
26937
27183
  const tmp = `${this.file}.tmp-${process.pid}`;
26938
27184
  writeFileSync19(tmp, `${JSON.stringify(payload, null, 2)}
26939
27185
  `);
26940
- renameSync12(tmp, this.file);
27186
+ renameSync13(tmp, this.file);
26941
27187
  }
26942
27188
  }
26943
27189
  var manifestEntrySchema, manifestFileSchema;
@@ -26966,14 +27212,14 @@ function sanitizePathComponent(name) {
26966
27212
  import { execFileSync as execFileSync8, spawn as spawn8 } from "child_process";
26967
27213
  import {
26968
27214
  mkdirSync as mkdirSync27,
26969
- readdirSync as readdirSync11,
26970
- readFileSync as readFileSync23,
26971
- renameSync as renameSync13,
27215
+ readdirSync as readdirSync12,
27216
+ readFileSync as readFileSync24,
27217
+ renameSync as renameSync14,
26972
27218
  unlinkSync as unlinkSync20,
26973
27219
  writeFileSync as writeFileSync20
26974
27220
  } from "fs";
26975
27221
  import { connect, createServer as createServer3 } from "net";
26976
- import { join as join37 } from "path";
27222
+ import { join as join38 } from "path";
26977
27223
  function regKey(key, instanceKey) {
26978
27224
  return `${key}\x00${instanceKey}`;
26979
27225
  }
@@ -27267,7 +27513,7 @@ class McpHost {
27267
27513
  const claims = new Map;
27268
27514
  let files;
27269
27515
  try {
27270
- files = readdirSync11(this.portsDir);
27516
+ files = readdirSync12(this.portsDir);
27271
27517
  } catch {
27272
27518
  return claims;
27273
27519
  }
@@ -27275,7 +27521,7 @@ class McpHost {
27275
27521
  if (file.includes(".tmp-"))
27276
27522
  continue;
27277
27523
  try {
27278
- const port = Number.parseInt(readFileSync23(join37(this.portsDir, file), "utf8").trim(), 10);
27524
+ const port = Number.parseInt(readFileSync24(join38(this.portsDir, file), "utf8").trim(), 10);
27279
27525
  if (!Number.isNaN(port))
27280
27526
  claims.set(file, port);
27281
27527
  } catch {}
@@ -27285,17 +27531,17 @@ class McpHost {
27285
27531
  writePortFile(fileName, port) {
27286
27532
  try {
27287
27533
  mkdirSync27(this.portsDir, { recursive: true });
27288
- const file = join37(this.portsDir, fileName);
27534
+ const file = join38(this.portsDir, fileName);
27289
27535
  const tmp = `${file}.tmp-${process.pid}`;
27290
27536
  writeFileSync20(tmp, String(port));
27291
- renameSync13(tmp, file);
27537
+ renameSync14(tmp, file);
27292
27538
  } catch (e) {
27293
27539
  this.log("warn", "Failed to write MCP port file", { fileName, port, err: String(e) });
27294
27540
  }
27295
27541
  }
27296
27542
  deletePortFile(fileName) {
27297
27543
  try {
27298
- unlinkSync20(join37(this.portsDir, fileName));
27544
+ unlinkSync20(join38(this.portsDir, fileName));
27299
27545
  } catch {}
27300
27546
  }
27301
27547
  cleanupRunning(rkey, inst) {
@@ -27402,12 +27648,12 @@ import {
27402
27648
  copyFileSync as copyFileSync4,
27403
27649
  existsSync as existsSync29,
27404
27650
  mkdirSync as mkdirSync28,
27405
- readFileSync as readFileSync24,
27406
- rmSync as rmSync8,
27407
- statSync as statSync17,
27651
+ readFileSync as readFileSync25,
27652
+ rmSync as rmSync9,
27653
+ statSync as statSync18,
27408
27654
  writeFileSync as writeFileSync21
27409
27655
  } from "fs";
27410
- import { basename as basename10, extname as extname4, join as join38 } from "path";
27656
+ import { basename as basename10, extname as extname4, join as join39 } from "path";
27411
27657
  function safeExtension(filename) {
27412
27658
  const extension = extname4(basename10(filename));
27413
27659
  return /^\.[A-Za-z0-9]{1,16}$/.test(extension) ? extension.toLowerCase() : "";
@@ -27425,20 +27671,20 @@ function contentDisposition(filename) {
27425
27671
 
27426
27672
  class NodeFileStore {
27427
27673
  uploadDir;
27428
- constructor(uploadDir = join38(DATA_DIR, "uploads")) {
27674
+ constructor(uploadDir = join39(DATA_DIR, "uploads")) {
27429
27675
  this.uploadDir = uploadDir;
27430
27676
  }
27431
27677
  #ensureDir() {
27432
27678
  mkdirSync28(this.uploadDir, { recursive: true });
27433
27679
  }
27434
27680
  #metadataPath(fileId) {
27435
- return join38(this.uploadDir, `${fileId}.meta.json`);
27681
+ return join39(this.uploadDir, `${fileId}.meta.json`);
27436
27682
  }
27437
27683
  #metadata(fileId) {
27438
27684
  if (!FILE_ID_RE.test(fileId))
27439
27685
  return null;
27440
27686
  try {
27441
- const parsed = JSON.parse(readFileSync24(this.#metadataPath(fileId), "utf8"));
27687
+ const parsed = JSON.parse(readFileSync25(this.#metadataPath(fileId), "utf8"));
27442
27688
  if (typeof parsed.filename !== "string" || typeof parsed.mimeType !== "string" || typeof parsed.sizeBytes !== "number" || typeof parsed.savedName !== "string") {
27443
27689
  return null;
27444
27690
  }
@@ -27461,7 +27707,7 @@ class NodeFileStore {
27461
27707
  hooks = {
27462
27708
  resolveAttachmentByFileId: (fileId) => {
27463
27709
  const metadata = this.#metadata(fileId);
27464
- if (!metadata || !existsSync29(join38(this.uploadDir, metadata.savedName)))
27710
+ if (!metadata || !existsSync29(join39(this.uploadDir, metadata.savedName)))
27465
27711
  return null;
27466
27712
  return this.#attachment(fileId, metadata);
27467
27713
  },
@@ -27469,7 +27715,7 @@ class NodeFileStore {
27469
27715
  const metadata = this.#metadata(fileId);
27470
27716
  if (!metadata)
27471
27717
  return null;
27472
- const path = join38(this.uploadDir, metadata.savedName);
27718
+ const path = join39(this.uploadDir, metadata.savedName);
27473
27719
  return existsSync29(path) ? path : null;
27474
27720
  },
27475
27721
  storeLocalFileAsUpload: (absPath, access = {}) => this.store(absPath, access),
@@ -27480,9 +27726,9 @@ class NodeFileStore {
27480
27726
  const fileId = randomUUID24();
27481
27727
  const extension = safeExtension(absPath);
27482
27728
  const savedName = `${fileId}${extension}`;
27483
- const savedPath = join38(this.uploadDir, savedName);
27729
+ const savedPath = join39(this.uploadDir, savedName);
27484
27730
  try {
27485
- const stats = statSync17(absPath);
27731
+ const stats = statSync18(absPath);
27486
27732
  if (!stats.isFile() || stats.size > MAX_UPLOAD_BYTES)
27487
27733
  return null;
27488
27734
  const metadata = {
@@ -27498,8 +27744,8 @@ class NodeFileStore {
27498
27744
  writeFileSync21(this.#metadataPath(fileId), JSON.stringify(metadata), { mode: 384 });
27499
27745
  return this.#attachment(fileId, metadata);
27500
27746
  } catch (error2) {
27501
- rmSync8(savedPath, { force: true });
27502
- rmSync8(this.#metadataPath(fileId), { force: true });
27747
+ rmSync9(savedPath, { force: true });
27748
+ rmSync9(this.#metadataPath(fileId), { force: true });
27503
27749
  logger.warn({ err: error2, absPath }, "node files: failed to store local upload");
27504
27750
  return null;
27505
27751
  }
@@ -27512,7 +27758,7 @@ class NodeFileStore {
27512
27758
  const allowed = metadata.visibility === "workspace" || metadata.ownerUserId === userId || Boolean(topic && isParticipant(topic, userId));
27513
27759
  if (!allowed)
27514
27760
  return null;
27515
- const path = join38(this.uploadDir, metadata.savedName);
27761
+ const path = join39(this.uploadDir, metadata.savedName);
27516
27762
  if (!existsSync29(path))
27517
27763
  return null;
27518
27764
  return new Response(Bun.file(path), {
@@ -27531,8 +27777,8 @@ class NodeFileStore {
27531
27777
  const metadata = this.#metadata(fileId);
27532
27778
  if (metadata?.topicId !== topicId)
27533
27779
  continue;
27534
- rmSync8(join38(this.uploadDir, metadata.savedName), { force: true });
27535
- rmSync8(this.#metadataPath(fileId), { force: true });
27780
+ rmSync9(join39(this.uploadDir, metadata.savedName), { force: true });
27781
+ rmSync9(this.#metadataPath(fileId), { force: true });
27536
27782
  }
27537
27783
  }
27538
27784
  }
@@ -27685,8 +27931,8 @@ import {
27685
27931
  chmodSync as chmodSync5,
27686
27932
  existsSync as existsSync30,
27687
27933
  mkdirSync as mkdirSync29,
27688
- readFileSync as readFileSync25,
27689
- renameSync as renameSync14,
27934
+ readFileSync as readFileSync26,
27935
+ renameSync as renameSync15,
27690
27936
  unlinkSync as unlinkSync21,
27691
27937
  writeFileSync as writeFileSync22
27692
27938
  } from "fs";
@@ -28187,7 +28433,7 @@ function writeNodeDaemonInfo(port, startedAt) {
28187
28433
  writeFileSync22(temporary, `${JSON.stringify(info, null, 2)}
28188
28434
  `, { mode: 384 });
28189
28435
  chmodSync5(temporary, 384);
28190
- renameSync14(temporary, NODE_DAEMON_INFO_PATH);
28436
+ renameSync15(temporary, NODE_DAEMON_INFO_PATH);
28191
28437
  chmodSync5(NODE_DAEMON_INFO_PATH, 384);
28192
28438
  return info;
28193
28439
  }
@@ -28195,7 +28441,7 @@ function readNodeDaemonInfo() {
28195
28441
  if (!existsSync30(NODE_DAEMON_INFO_PATH))
28196
28442
  return null;
28197
28443
  try {
28198
- const value = JSON.parse(readFileSync25(NODE_DAEMON_INFO_PATH, "utf8"));
28444
+ const value = JSON.parse(readFileSync26(NODE_DAEMON_INFO_PATH, "utf8"));
28199
28445
  if (value?.schemaVersion !== 1 || value.stateDir !== STATE_DIR || !Number.isInteger(value.protocolVersion) || !Number.isInteger(value.pid) || !Number.isInteger(value.port) || value.port <= 0) {
28200
28446
  return null;
28201
28447
  }
@@ -28483,7 +28729,7 @@ var init_schedule = __esm(() => {
28483
28729
 
28484
28730
  // ../../packages/module-cron/src/scripts.ts
28485
28731
  import { spawn as spawn9 } from "child_process";
28486
- import { existsSync as existsSync31, mkdirSync as mkdirSync30, readdirSync as readdirSync12 } from "fs";
28732
+ import { existsSync as existsSync31, mkdirSync as mkdirSync30, readdirSync as readdirSync13 } from "fs";
28487
28733
  import { resolve as resolve22, sep as sep2 } from "path";
28488
28734
  function validateCronScriptName(script) {
28489
28735
  if (!/^[A-Za-z0-9_][A-Za-z0-9_.-]*\.py$/.test(script) || script.includes("..") || script.includes("/") || script.includes("\\")) {
@@ -28502,7 +28748,7 @@ function resolveCronScriptPath(script) {
28502
28748
  }
28503
28749
  function listCronScripts() {
28504
28750
  mkdirSync30(CRON_JOBS_DIR, { recursive: true });
28505
- return readdirSync12(CRON_JOBS_DIR, { withFileTypes: true }).filter((entry) => entry.isFile() && validateCronScriptName(entry.name).ok).map((entry) => entry.name).sort();
28751
+ return readdirSync13(CRON_JOBS_DIR, { withFileTypes: true }).filter((entry) => entry.isFile() && validateCronScriptName(entry.name).ok).map((entry) => entry.name).sort();
28506
28752
  }
28507
28753
  function cronScriptExists(script) {
28508
28754
  try {
@@ -30184,6 +30430,7 @@ function startNode(opts = {}) {
30184
30430
  setRuntimeMcpPort(port);
30185
30431
  const stopTurnRequests = startDurableTurnRequestWorker();
30186
30432
  const stopInbox = startSessionInboxWorker();
30433
+ const stopBashrsCompletions = startBashrsCompletionsWorker();
30187
30434
  let modules;
30188
30435
  try {
30189
30436
  modules = startNegotiumNodeModules(opts.modules ?? [], {
@@ -30197,6 +30444,7 @@ function startNode(opts = {}) {
30197
30444
  } catch (error2) {
30198
30445
  stopTurnRequests();
30199
30446
  stopInbox();
30447
+ stopBashrsCompletions();
30200
30448
  server.stop(true);
30201
30449
  processLease?.stop();
30202
30450
  stopAskUserQuestionGateOwner();
@@ -30216,6 +30464,7 @@ function startNode(opts = {}) {
30216
30464
  stopSweeper();
30217
30465
  stopTurnRequests();
30218
30466
  stopInbox();
30467
+ stopBashrsCompletions();
30219
30468
  server.stop(true);
30220
30469
  processLease?.stop();
30221
30470
  stopAskUserQuestionGateOwner();
@@ -30227,6 +30476,7 @@ function startNode(opts = {}) {
30227
30476
  onShutdown("node-server", 130, () => {
30228
30477
  stopTurnRequests();
30229
30478
  stopInbox();
30479
+ stopBashrsCompletions();
30230
30480
  server.stop(true);
30231
30481
  });
30232
30482
  if (advertised) {
@@ -30444,9 +30694,9 @@ var init_commands = __esm(() => {
30444
30694
 
30445
30695
  // ../../adapters/terminal/src/path-suggest.ts
30446
30696
  import { execFile as execFile3 } from "child_process";
30447
- import { existsSync as existsSync33, readdirSync as readdirSync13, statSync as statSync18 } from "fs";
30697
+ import { existsSync as existsSync33, readdirSync as readdirSync14, statSync as statSync19 } from "fs";
30448
30698
  import { homedir as homedir10 } from "os";
30449
- import { basename as basename11, dirname as dirname19, join as join39, sep as sep3 } from "path";
30699
+ import { basename as basename11, dirname as dirname19, join as join40, sep as sep3 } from "path";
30450
30700
  import { promisify as promisify3 } from "util";
30451
30701
  function indexRecursivePaths(files) {
30452
30702
  const paths = [];
@@ -30547,11 +30797,11 @@ function resolveFragment(frag) {
30547
30797
  else if (frag === "~/")
30548
30798
  path = home;
30549
30799
  else if (frag.startsWith("~/"))
30550
- path = join39(home, frag.slice(2));
30800
+ path = join40(home, frag.slice(2));
30551
30801
  else if (frag.startsWith("/"))
30552
30802
  path = frag;
30553
30803
  else
30554
- path = join39(home, frag);
30804
+ path = join40(home, frag);
30555
30805
  if (frag.endsWith("/") || frag === "" || frag === "~") {
30556
30806
  return { dir: path, prefix: "" };
30557
30807
  }
@@ -30580,7 +30830,7 @@ function rankAndSlice(dir, candidates) {
30580
30830
  });
30581
30831
  return candidates.slice(0, MAX_SUGGESTIONS).map(({ relPath, isDir }) => ({
30582
30832
  label: `${relPath}${isDir ? "/" : ""}`,
30583
- value: toToken(join39(dir, relPath), isDir),
30833
+ value: toToken(join40(dir, relPath), isDir),
30584
30834
  isDir
30585
30835
  }));
30586
30836
  }
@@ -30627,7 +30877,7 @@ async function warmPathSuggestions(lineText, col, loader = listFilesWithRipgrep)
30627
30877
  return false;
30628
30878
  const { dir } = resolveFragment(token.frag);
30629
30879
  try {
30630
- if (!statSync18(dir).isDirectory())
30880
+ if (!statSync19(dir).isDirectory())
30631
30881
  return false;
30632
30882
  } catch {
30633
30883
  return false;
@@ -30641,7 +30891,7 @@ function pathSuggestions(lineText, col) {
30641
30891
  const { dir, prefix } = resolveFragment(token.frag);
30642
30892
  let entries;
30643
30893
  try {
30644
- entries = readdirSync13(dir, { withFileTypes: true });
30894
+ entries = readdirSync14(dir, { withFileTypes: true });
30645
30895
  } catch {
30646
30896
  return { start: token.start, end: col, items: [], truncated: 0, searching: false };
30647
30897
  }
@@ -30659,7 +30909,7 @@ function pathSuggestions(lineText, col) {
30659
30909
  let isDir = entry.isDirectory();
30660
30910
  if (!isDir && entry.isSymbolicLink()) {
30661
30911
  try {
30662
- isDir = statSync18(join39(dir, entry.name)).isDirectory();
30912
+ isDir = statSync19(join40(dir, entry.name)).isDirectory();
30663
30913
  } catch {}
30664
30914
  }
30665
30915
  return {
@@ -30686,10 +30936,10 @@ function fragmentToAbsolutePath(frag) {
30686
30936
  if (frag === "~" || frag === "~/")
30687
30937
  return home;
30688
30938
  if (frag.startsWith("~/"))
30689
- return join39(home, frag.slice(2));
30939
+ return join40(home, frag.slice(2));
30690
30940
  if (frag.startsWith("/"))
30691
30941
  return frag;
30692
- return join39(home, frag);
30942
+ return join40(home, frag);
30693
30943
  }
30694
30944
  function fragmentResolves(frag) {
30695
30945
  try {
@@ -37565,7 +37815,7 @@ var init_commands2 = __esm(async () => {
37565
37815
  // ../../adapters/telegram/src/mapping-store.ts
37566
37816
  import { Database as Database2 } from "bun:sqlite";
37567
37817
  import { mkdirSync as mkdirSync31 } from "fs";
37568
- import { dirname as dirname20, join as join40 } from "path";
37818
+ import { dirname as dirname20, join as join41 } from "path";
37569
37819
  function outboxRowToEntry(row) {
37570
37820
  return {
37571
37821
  id: row.id,
@@ -37631,7 +37881,7 @@ function migrateOutboxSchema(db4) {
37631
37881
  db4.run("CREATE INDEX IF NOT EXISTS idx_telegram_outbox_runtime_message ON outbox(runtime_message_id)");
37632
37882
  }
37633
37883
  function openMappingStore(path) {
37634
- const dbPath = path ?? join40(DATA_DIR, "adapter-telegram.db");
37884
+ const dbPath = path ?? join41(DATA_DIR, "adapter-telegram.db");
37635
37885
  if (dbPath !== ":memory:")
37636
37886
  mkdirSync31(dirname20(dbPath), { recursive: true });
37637
37887
  const db4 = new Database2(dbPath);
@@ -39496,8 +39746,8 @@ __export(exports_central, {
39496
39746
  listPeerNodes: () => listPeerNodes,
39497
39747
  configureOtiumCentral: () => configureOtiumCentral
39498
39748
  });
39499
- function configureOtiumCentral(join41) {
39500
- joinConfig = join41;
39749
+ function configureOtiumCentral(join42) {
39750
+ joinConfig = join42;
39501
39751
  resetPeerCentralCaches();
39502
39752
  }
39503
39753
  function otiumCentralConfig() {
@@ -39653,17 +39903,17 @@ __export(exports_join, {
39653
39903
  import { createHash as createHash10, randomUUID as randomUUID27 } from "crypto";
39654
39904
  import {
39655
39905
  chmodSync as chmodSync6,
39656
- closeSync as closeSync4,
39906
+ closeSync as closeSync5,
39657
39907
  existsSync as existsSync35,
39658
39908
  fsyncSync as fsyncSync2,
39659
39909
  linkSync,
39660
39910
  lstatSync,
39661
39911
  mkdirSync as mkdirSync32,
39662
- openSync as openSync4,
39663
- readFileSync as readFileSync26,
39664
- renameSync as renameSync15,
39665
- rmSync as rmSync9,
39666
- statSync as statSync19,
39912
+ openSync as openSync5,
39913
+ readFileSync as readFileSync27,
39914
+ renameSync as renameSync16,
39915
+ rmSync as rmSync10,
39916
+ statSync as statSync20,
39667
39917
  unlinkSync as unlinkSync22,
39668
39918
  writeFileSync as writeFileSync23
39669
39919
  } from "fs";
@@ -39748,27 +39998,27 @@ function withJoinCredentialLock(operation) {
39748
39998
  created = true;
39749
39999
  writeFileSync23(ownerPath, `${JSON.stringify(owner)}
39750
40000
  `, { mode: 384 });
39751
- const ownerFd = openSync4(ownerPath, "r");
40001
+ const ownerFd = openSync5(ownerPath, "r");
39752
40002
  try {
39753
40003
  fsyncSync2(ownerFd);
39754
40004
  } finally {
39755
- closeSync4(ownerFd);
40005
+ closeSync5(ownerFd);
39756
40006
  }
39757
40007
  break;
39758
40008
  } catch (error2) {
39759
40009
  if (created) {
39760
- rmSync9(lockPath, { recursive: true, force: true });
40010
+ rmSync10(lockPath, { recursive: true, force: true });
39761
40011
  throw error2;
39762
40012
  }
39763
40013
  if (error2.code !== "EEXIST")
39764
40014
  throw error2;
39765
40015
  let current3 = null;
39766
40016
  try {
39767
- current3 = JSON.parse(readFileSync26(ownerPath, "utf8"));
40017
+ current3 = JSON.parse(readFileSync27(ownerPath, "utf8"));
39768
40018
  } catch {}
39769
40019
  let ageMs;
39770
40020
  try {
39771
- ageMs = Date.now() - statSync19(lockPath).mtimeMs;
40021
+ ageMs = Date.now() - statSync20(lockPath).mtimeMs;
39772
40022
  } catch (statError) {
39773
40023
  if (statError.code === "ENOENT")
39774
40024
  continue;
@@ -39782,8 +40032,8 @@ function withJoinCredentialLock(operation) {
39782
40032
  }
39783
40033
  const stalePath = `${lockPath}.stale.${process.pid}.${randomUUID27()}`;
39784
40034
  try {
39785
- renameSync15(lockPath, stalePath);
39786
- rmSync9(stalePath, { recursive: true, force: true });
40035
+ renameSync16(lockPath, stalePath);
40036
+ rmSync10(stalePath, { recursive: true, force: true });
39787
40037
  } catch (staleError) {
39788
40038
  if (staleError.code !== "ENOENT")
39789
40039
  throw staleError;
@@ -39794,9 +40044,9 @@ function withJoinCredentialLock(operation) {
39794
40044
  return operation();
39795
40045
  } finally {
39796
40046
  try {
39797
- const current3 = JSON.parse(readFileSync26(ownerPath, "utf8"));
40047
+ const current3 = JSON.parse(readFileSync27(ownerPath, "utf8"));
39798
40048
  if (current3.pid === owner.pid && current3.token === owner.token) {
39799
- rmSync9(lockPath, { recursive: true, force: true });
40049
+ rmSync10(lockPath, { recursive: true, force: true });
39800
40050
  }
39801
40051
  } catch {}
39802
40052
  }
@@ -39804,39 +40054,39 @@ function withJoinCredentialLock(operation) {
39804
40054
  function joinsEqual(left, right) {
39805
40055
  return left.central === right.central && left.relay === right.relay && left.cellId === right.cellId && left.secret === right.secret;
39806
40056
  }
39807
- function normalizedJoin(join41) {
40057
+ function normalizedJoin(join42) {
39808
40058
  return normalizeJoin({
39809
- v: join41.v,
39810
- central: join41.central,
39811
- relay: join41.relay,
39812
- cellId: join41.cellId,
39813
- secret: join41.secret
40059
+ v: join42.v,
40060
+ central: join42.central,
40061
+ relay: join42.relay,
40062
+ cellId: join42.cellId,
40063
+ secret: join42.secret
39814
40064
  });
39815
40065
  }
39816
- function joinCredentialDigest(join41) {
39817
- return createHash10("sha256").update(JSON.stringify(normalizedJoin(join41))).digest("base64url");
40066
+ function joinCredentialDigest(join42) {
40067
+ return createHash10("sha256").update(JSON.stringify(normalizedJoin(join42))).digest("base64url");
39818
40068
  }
39819
40069
  function readPersistedJoin(path = joinFilePath()) {
39820
40070
  if (!existsSync35(path))
39821
40071
  return null;
39822
- const parsed = JSON.parse(readFileSync26(path, "utf-8"));
40072
+ const parsed = JSON.parse(readFileSync27(path, "utf-8"));
39823
40073
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
39824
40074
  throw new Error("persisted join credentials are not a JSON object");
39825
40075
  }
39826
40076
  return normalizeJoin(parsed);
39827
40077
  }
39828
- function isJoinPersisted(join41) {
40078
+ function isJoinPersisted(join42) {
39829
40079
  try {
39830
40080
  const persisted = readPersistedJoin();
39831
- return persisted !== null && joinsEqual(persisted, normalizedJoin(join41));
40081
+ return persisted !== null && joinsEqual(persisted, normalizedJoin(join42));
39832
40082
  } catch {
39833
40083
  return false;
39834
40084
  }
39835
40085
  }
39836
- function saveJoinWhileLocked(join41, options = {}) {
40086
+ function saveJoinWhileLocked(join42, options = {}) {
39837
40087
  const path = joinFilePath();
39838
40088
  const directory = dirname21(path);
39839
- const normalized = normalizedJoin(join41);
40089
+ const normalized = normalizedJoin(join42);
39840
40090
  mkdirSync32(directory, { recursive: true });
39841
40091
  if (existsSync35(path)) {
39842
40092
  if (lstatSync(path).isSymbolicLink()) {
@@ -39852,17 +40102,17 @@ function saveJoinWhileLocked(join41, options = {}) {
39852
40102
  }
39853
40103
  if (existing && joinsEqual(existing, normalized)) {
39854
40104
  chmodSync6(path, 384);
39855
- const fileFd = openSync4(path, "r");
40105
+ const fileFd = openSync5(path, "r");
39856
40106
  try {
39857
40107
  fsyncSync2(fileFd);
39858
40108
  } finally {
39859
- closeSync4(fileFd);
40109
+ closeSync5(fileFd);
39860
40110
  }
39861
- const directoryFd = openSync4(directory, "r");
40111
+ const directoryFd = openSync5(directory, "r");
39862
40112
  try {
39863
40113
  fsyncSync2(directoryFd);
39864
40114
  } finally {
39865
- closeSync4(directoryFd);
40115
+ closeSync5(directoryFd);
39866
40116
  }
39867
40117
  return path;
39868
40118
  }
@@ -39873,36 +40123,36 @@ function saveJoinWhileLocked(join41, options = {}) {
39873
40123
  const temporaryPath = resolve23(directory, `.otium-join.json.${process.pid}.${randomUUID27()}.tmp`);
39874
40124
  let fd;
39875
40125
  try {
39876
- fd = openSync4(temporaryPath, "wx", 384);
40126
+ fd = openSync5(temporaryPath, "wx", 384);
39877
40127
  writeFileSync23(fd, `${JSON.stringify(normalized, null, 2)}
39878
40128
  `, "utf8");
39879
40129
  fsyncSync2(fd);
39880
- closeSync4(fd);
40130
+ closeSync5(fd);
39881
40131
  fd = undefined;
39882
40132
  if (options.replaceExisting) {
39883
- renameSync15(temporaryPath, path);
40133
+ renameSync16(temporaryPath, path);
39884
40134
  } else {
39885
40135
  linkSync(temporaryPath, path);
39886
40136
  unlinkSync22(temporaryPath);
39887
40137
  }
39888
40138
  chmodSync6(path, 384);
39889
- const directoryFd = openSync4(directory, "r");
40139
+ const directoryFd = openSync5(directory, "r");
39890
40140
  try {
39891
40141
  fsyncSync2(directoryFd);
39892
40142
  } finally {
39893
- closeSync4(directoryFd);
40143
+ closeSync5(directoryFd);
39894
40144
  }
39895
40145
  } catch (error2) {
39896
40146
  if (fd !== undefined)
39897
- closeSync4(fd);
40147
+ closeSync5(fd);
39898
40148
  if (existsSync35(temporaryPath))
39899
40149
  unlinkSync22(temporaryPath);
39900
40150
  throw error2;
39901
40151
  }
39902
40152
  return path;
39903
40153
  }
39904
- function saveJoin(join41, options = {}) {
39905
- return withJoinCredentialLock(() => saveJoinWhileLocked(join41, options));
40154
+ function saveJoin(join42, options = {}) {
40155
+ return withJoinCredentialLock(() => saveJoinWhileLocked(join42, options));
39906
40156
  }
39907
40157
  function removeJoin() {
39908
40158
  return withJoinCredentialLock(() => {
@@ -39913,11 +40163,11 @@ function removeJoin() {
39913
40163
  throw new Error(`refusing to remove symlinked Otium join file at ${path}`);
39914
40164
  }
39915
40165
  unlinkSync22(path);
39916
- const directoryFd = openSync4(dirname21(path), "r");
40166
+ const directoryFd = openSync5(dirname21(path), "r");
39917
40167
  try {
39918
40168
  fsyncSync2(directoryFd);
39919
40169
  } finally {
39920
- closeSync4(directoryFd);
40170
+ closeSync5(directoryFd);
39921
40171
  }
39922
40172
  return true;
39923
40173
  });
@@ -39942,7 +40192,7 @@ function loadJoin() {
39942
40192
  if (!existsSync35(path))
39943
40193
  return null;
39944
40194
  try {
39945
- const parsed = JSON.parse(readFileSync26(path, "utf-8"));
40195
+ const parsed = JSON.parse(readFileSync27(path, "utf-8"));
39946
40196
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
39947
40197
  return null;
39948
40198
  return normalizeJoin(parsed);
@@ -40919,8 +41169,8 @@ var init_event_backflow = __esm(async () => {
40919
41169
 
40920
41170
  // ../../adapters/otium/src/peer-files.ts
40921
41171
  import { randomUUID as randomUUID29 } from "crypto";
40922
- import { copyFileSync as copyFileSync5, mkdirSync as mkdirSync33, rmSync as rmSync10, statSync as statSync20 } from "fs";
40923
- import { basename as basename13, extname as extname6, join as join41 } from "path";
41172
+ import { copyFileSync as copyFileSync5, mkdirSync as mkdirSync33, rmSync as rmSync11, statSync as statSync21 } from "fs";
41173
+ import { basename as basename13, extname as extname6, join as join42 } from "path";
40924
41174
  function fileType(mimeType) {
40925
41175
  if (mimeType.startsWith("image/"))
40926
41176
  return "image";
@@ -40990,21 +41240,21 @@ function recordFile(args) {
40990
41240
  function insertLocalFile(args) {
40991
41241
  const id = randomUUID29();
40992
41242
  mkdirSync33(PEER_FILES_DIR, { recursive: true });
40993
- const path = join41(PEER_FILES_DIR, `${id}-${safeFilename(args.filename)}`);
41243
+ const path = join42(PEER_FILES_DIR, `${id}-${safeFilename(args.filename)}`);
40994
41244
  copyFileSync5(args.sourcePath, path);
40995
- return recordFile({ id, path, sizeBytes: statSync20(path).size, ...args });
41245
+ return recordFile({ id, path, sizeBytes: statSync21(path).size, ...args });
40996
41246
  }
40997
41247
  function deletePeerFilesForTopic(topicId) {
40998
41248
  const rows = db.query("SELECT path FROM otium_peer_files WHERE topic_id = ?").all(topicId);
40999
41249
  db.run("DELETE FROM otium_peer_files WHERE topic_id = ?", [topicId]);
41000
41250
  for (const row of rows)
41001
- rmSync10(row.path, { force: true });
41251
+ rmSync11(row.path, { force: true });
41002
41252
  }
41003
41253
  async function storePeerInputFile(file, access) {
41004
41254
  const id = randomUUID29();
41005
41255
  mkdirSync33(PEER_FILES_DIR, { recursive: true });
41006
41256
  const filename = file.name || "upload";
41007
- const path = join41(PEER_FILES_DIR, `${id}-${safeFilename(filename)}`);
41257
+ const path = join42(PEER_FILES_DIR, `${id}-${safeFilename(filename)}`);
41008
41258
  const sizeBytes = await Bun.write(path, file);
41009
41259
  return recordFile({
41010
41260
  id,
@@ -41051,7 +41301,7 @@ function installPeerFileHooks() {
41051
41301
  var PEER_FILES_DIR;
41052
41302
  var init_peer_files = __esm(async () => {
41053
41303
  await init_src();
41054
- PEER_FILES_DIR = join41(DATA_DIR, "otium-peer-files");
41304
+ PEER_FILES_DIR = join42(DATA_DIR, "otium-peer-files");
41055
41305
  db.exec(`
41056
41306
  CREATE TABLE IF NOT EXISTS otium_peer_files (
41057
41307
  id TEXT PRIMARY KEY,
@@ -41755,7 +42005,7 @@ function messageEnvelope(message) {
41755
42005
  ...message.kind ? { kind: message.kind } : {}
41756
42006
  };
41757
42007
  }
41758
- async function publishTopic(join42, topicId, node) {
42008
+ async function publishTopic(join43, topicId, node) {
41759
42009
  const topic = getTopic(topicId);
41760
42010
  if (!topic || topic.kind !== "agent" || !topic.agent || !isTopicShared(topic) || !topic.visibility || topic.visibility === "hidden" || isMirrorTopic(topicId))
41761
42011
  return;
@@ -41803,10 +42053,10 @@ async function publishTopic(join42, topicId, node) {
41803
42053
  }
41804
42054
  } catch (error2) {
41805
42055
  logger.warn({ error: error2, topicId }, "otium: shared topic publish deferred");
41806
- setTimeout(() => void reconcileTopic(join42, topicId), RETRY_MS).unref?.();
42056
+ setTimeout(() => void reconcileTopic(join43, topicId), RETRY_MS).unref?.();
41807
42057
  }
41808
42058
  }
41809
- async function unpublishTopic(join42, topicId, node) {
42059
+ async function unpublishTopic(join43, topicId, node) {
41810
42060
  const state2 = getSharedTopicState(topicId);
41811
42061
  if (!state2)
41812
42062
  return;
@@ -41822,26 +42072,26 @@ async function unpublishTopic(join42, topicId, node) {
41822
42072
  deleteSharedTopicState(topicId);
41823
42073
  } catch (error2) {
41824
42074
  logger.warn({ error: error2, topicId }, "otium: shared topic unpublish deferred");
41825
- setTimeout(() => void reconcileTopic(join42, topicId), RETRY_MS).unref?.();
42075
+ setTimeout(() => void reconcileTopic(join43, topicId), RETRY_MS).unref?.();
41826
42076
  }
41827
42077
  }
41828
- async function reconcileTopic(join42, topicId, explicit = false) {
42078
+ async function reconcileTopic(join43, topicId, explicit = false) {
41829
42079
  if (!otiumCentralConfig())
41830
42080
  return;
41831
- if (!explicit && isPeerDetached(join42.cellId))
42081
+ if (!explicit && isPeerDetached(join43.cellId))
41832
42082
  return;
41833
42083
  const target = (await listPeerNodes()).find((node) => node.isPrimary) ?? null;
41834
42084
  if (!target)
41835
42085
  return;
41836
42086
  const topic = getTopic(topicId);
41837
42087
  if (topic?.kind === "agent" && topic.agent && isTopicShared(topic) && topic.visibility !== "hidden" && !isMirrorTopic(topicId))
41838
- return publishTopic(join42, topicId, target);
41839
- return unpublishTopic(join42, topicId, target);
42088
+ return publishTopic(join43, topicId, target);
42089
+ return unpublishTopic(join43, topicId, target);
41840
42090
  }
41841
- function disconnectSharedTopics(join42) {
42091
+ function disconnectSharedTopics(join43) {
41842
42092
  const states = listSharedTopicStates();
41843
42093
  const hubPromise = listPeerNodes({ fresh: true }).then((nodes) => nodes.find((node) => node.isPrimary) ?? null, () => null);
41844
- const updated = downgradeSharedTopicsLocally(join42.cellId);
42094
+ const updated = downgradeSharedTopicsLocally(join43.cellId);
41845
42095
  for (const topicId of updated)
41846
42096
  WsHub.get().broadcastTopicUpdated(topicId);
41847
42097
  const deletions = states.map(async (state2) => {
@@ -41864,16 +42114,16 @@ function downgradeSharedTopicsForHub(hubNodeId) {
41864
42114
  WsHub.get().broadcastTopicUpdated(topicId);
41865
42115
  return updated.length;
41866
42116
  }
41867
- async function checkPeerAttachment(join42) {
42117
+ async function checkPeerAttachment(join43) {
41868
42118
  const nodes = await listPeerNodes({ fresh: true });
41869
- if (nodes.some((node) => node.cellId === join42.cellId))
42119
+ if (nodes.some((node) => node.cellId === join43.cellId))
41870
42120
  return true;
41871
- downgradeSharedTopicsForHub(join42.cellId);
42121
+ downgradeSharedTopicsForHub(join43.cellId);
41872
42122
  return false;
41873
42123
  }
41874
- function startSharedTopicSync(join42) {
42124
+ function startSharedTopicSync(join43) {
41875
42125
  let stopped = false;
41876
- let detached = isPeerDetached(join42.cellId);
42126
+ let detached = isPeerDetached(join43.cellId);
41877
42127
  const queue = new Set;
41878
42128
  const schedule = (topicId, explicit = false) => {
41879
42129
  if (stopped || queue.has(topicId))
@@ -41882,7 +42132,7 @@ function startSharedTopicSync(join42) {
41882
42132
  queueMicrotask(async () => {
41883
42133
  queue.delete(topicId);
41884
42134
  try {
41885
- await reconcileTopic(join42, topicId, explicit);
42135
+ await reconcileTopic(join43, topicId, explicit);
41886
42136
  } catch (error2) {
41887
42137
  logger.warn({ error: error2, topicId }, "otium: shared topic reconciliation failed");
41888
42138
  }
@@ -41896,7 +42146,7 @@ function startSharedTopicSync(join42) {
41896
42146
  if (stopped || detached)
41897
42147
  return;
41898
42148
  try {
41899
- if (!await checkPeerAttachment(join42))
42149
+ if (!await checkPeerAttachment(join43))
41900
42150
  detached = true;
41901
42151
  } catch {}
41902
42152
  }, 30000);
@@ -41908,7 +42158,7 @@ function startSharedTopicSync(join42) {
41908
42158
  const message = event.payload;
41909
42159
  if (!message.sourceNode) {
41910
42160
  schedule(event.topicId);
41911
- forwardSharedTopicMessage(join42, message).catch((error2) => logger.warn({ error: error2, topicId: event.topicId }, "otium: shared message deferred"));
42161
+ forwardSharedTopicMessage(join43, message).catch((error2) => logger.warn({ error: error2, topicId: event.topicId }, "otium: shared message deferred"));
41912
42162
  }
41913
42163
  }
41914
42164
  });
@@ -42659,14 +42909,14 @@ import {
42659
42909
  } from "crypto";
42660
42910
  import {
42661
42911
  chmodSync as chmodSync7,
42662
- closeSync as closeSync5,
42912
+ closeSync as closeSync6,
42663
42913
  existsSync as existsSync37,
42664
42914
  fsyncSync as fsyncSync3,
42665
42915
  linkSync as linkSync2,
42666
42916
  mkdirSync as mkdirSync34,
42667
- openSync as openSync5,
42668
- readFileSync as readFileSync27,
42669
- renameSync as renameSync16,
42917
+ openSync as openSync6,
42918
+ readFileSync as readFileSync28,
42919
+ renameSync as renameSync17,
42670
42920
  unlinkSync as unlinkSync23,
42671
42921
  writeFileSync as writeFileSync24
42672
42922
  } from "fs";
@@ -42698,7 +42948,7 @@ function isEnrollmentPending(invite) {
42698
42948
  if (!existsSync37(path))
42699
42949
  return false;
42700
42950
  try {
42701
- const saved = JSON.parse(readFileSync27(path, "utf8"));
42951
+ const saved = JSON.parse(readFileSync28(path, "utf8"));
42702
42952
  return saved.central === invite.central && saved.token === invite.token;
42703
42953
  } catch {
42704
42954
  return false;
@@ -42707,7 +42957,7 @@ function isEnrollmentPending(invite) {
42707
42957
  function loadOrCreatePending(invite, nodeName) {
42708
42958
  const path = pendingEnrollmentPath();
42709
42959
  if (existsSync37(path)) {
42710
- const saved = JSON.parse(readFileSync27(path, "utf8"));
42960
+ const saved = JSON.parse(readFileSync28(path, "utf8"));
42711
42961
  if (saved.central === invite.central && saved.token === invite.token)
42712
42962
  return saved;
42713
42963
  throw new Error(`another Otium enrollment is pending at ${path}`);
@@ -42724,28 +42974,28 @@ function loadOrCreatePending(invite, nodeName) {
42724
42974
  const temporaryPath = resolve25(dirname22(path), `.otium-enrollment-pending.json.${process.pid}.${randomUUID31()}.tmp`);
42725
42975
  let fd;
42726
42976
  try {
42727
- fd = openSync5(temporaryPath, "wx", 384);
42977
+ fd = openSync6(temporaryPath, "wx", 384);
42728
42978
  writeFileSync24(fd, `${JSON.stringify(pending2, null, 2)}
42729
42979
  `, "utf8");
42730
42980
  fsyncSync3(fd);
42731
- closeSync5(fd);
42981
+ closeSync6(fd);
42732
42982
  fd = undefined;
42733
42983
  linkSync2(temporaryPath, path);
42734
42984
  unlinkSync23(temporaryPath);
42735
42985
  chmodSync7(path, 384);
42736
- const directoryFd = openSync5(dirname22(path), "r");
42986
+ const directoryFd = openSync6(dirname22(path), "r");
42737
42987
  try {
42738
42988
  fsyncSync3(directoryFd);
42739
42989
  } finally {
42740
- closeSync5(directoryFd);
42990
+ closeSync6(directoryFd);
42741
42991
  }
42742
42992
  } catch (error2) {
42743
42993
  if (fd !== undefined)
42744
- closeSync5(fd);
42994
+ closeSync6(fd);
42745
42995
  if (existsSync37(temporaryPath))
42746
42996
  unlinkSync23(temporaryPath);
42747
42997
  if (error2.code === "EEXIST" && existsSync37(path)) {
42748
- const saved = JSON.parse(readFileSync27(path, "utf8"));
42998
+ const saved = JSON.parse(readFileSync28(path, "utf8"));
42749
42999
  if (saved.central === invite.central && saved.token === invite.token)
42750
43000
  return saved;
42751
43001
  }
@@ -42759,34 +43009,34 @@ function replacePendingEnrollment(pending2) {
42759
43009
  const temporaryPath = resolve25(directory, `.otium-enrollment-pending.json.${process.pid}.${randomUUID31()}.tmp`);
42760
43010
  let fd;
42761
43011
  try {
42762
- fd = openSync5(temporaryPath, "wx", 384);
43012
+ fd = openSync6(temporaryPath, "wx", 384);
42763
43013
  writeFileSync24(fd, `${JSON.stringify(pending2, null, 2)}
42764
43014
  `, "utf8");
42765
43015
  fsyncSync3(fd);
42766
- closeSync5(fd);
43016
+ closeSync6(fd);
42767
43017
  fd = undefined;
42768
- renameSync16(temporaryPath, path);
42769
- const directoryFd = openSync5(directory, "r");
43018
+ renameSync17(temporaryPath, path);
43019
+ const directoryFd = openSync6(directory, "r");
42770
43020
  try {
42771
43021
  fsyncSync3(directoryFd);
42772
43022
  } finally {
42773
- closeSync5(directoryFd);
43023
+ closeSync6(directoryFd);
42774
43024
  }
42775
43025
  } catch (error2) {
42776
43026
  if (fd !== undefined)
42777
- closeSync5(fd);
43027
+ closeSync6(fd);
42778
43028
  if (existsSync37(temporaryPath))
42779
43029
  unlinkSync23(temporaryPath);
42780
43030
  throw error2;
42781
43031
  }
42782
43032
  }
42783
- function recordClaimedCredential(pending2, join42) {
43033
+ function recordClaimedCredential(pending2, join43) {
42784
43034
  withJoinCredentialLock(() => {
42785
- const current3 = JSON.parse(readFileSync27(pendingEnrollmentPath(), "utf8"));
43035
+ const current3 = JSON.parse(readFileSync28(pendingEnrollmentPath(), "utf8"));
42786
43036
  if (current3.central !== pending2.central || current3.token !== pending2.token || current3.idempotencyKey !== pending2.idempotencyKey || current3.publicKey !== pending2.publicKey) {
42787
43037
  throw new Error("pending Otium enrollment changed while its claim was in flight");
42788
43038
  }
42789
- const claimed = { digest: joinCredentialDigest(join42), cellId: join42.cellId };
43039
+ const claimed = { digest: joinCredentialDigest(join43), cellId: join43.cellId };
42790
43040
  if (current3.claimed && (current3.claimed.digest !== claimed.digest || current3.claimed.cellId !== claimed.cellId)) {
42791
43041
  throw new Error("central returned different credentials for an idempotent enrollment claim");
42792
43042
  }
@@ -42844,40 +43094,40 @@ async function claimEnrollment(invite, nodeName) {
42844
43094
  const secret = openCredential(credential, pending2.privateKey);
42845
43095
  if (!secret.startsWith("rcs_"))
42846
43096
  throw new Error("central returned an invalid runtime credential");
42847
- const join42 = {
43097
+ const join43 = {
42848
43098
  v: 2,
42849
43099
  central: invite.central,
42850
43100
  relay: String(response.relayUrl),
42851
43101
  cellId: String(response.cell?.id),
42852
43102
  secret
42853
43103
  };
42854
- if (!join42.relay || !join42.cellId || join42.cellId === "undefined") {
43104
+ if (!join43.relay || !join43.cellId || join43.cellId === "undefined") {
42855
43105
  throw new Error("central returned an incomplete enrollment response");
42856
43106
  }
42857
- assertSecureRelayUrl(join42.relay);
42858
- recordClaimedCredential(pending2, join42);
42859
- return join42;
43107
+ assertSecureRelayUrl(join43.relay);
43108
+ recordClaimedCredential(pending2, join43);
43109
+ return join43;
42860
43110
  }
42861
- function commitEnrollment(join42, options = {}) {
43111
+ function commitEnrollment(join43, options = {}) {
42862
43112
  return withJoinCredentialLock(() => {
42863
43113
  const pendingPath = pendingEnrollmentPath();
42864
- const pending2 = existsSync37(pendingPath) ? JSON.parse(readFileSync27(pendingPath, "utf8")) : null;
42865
- const digest = joinCredentialDigest(join42);
42866
- if (pending2 && (!pending2.claimed || pending2.claimed.digest !== digest || pending2.claimed.cellId !== join42.cellId)) {
43114
+ const pending2 = existsSync37(pendingPath) ? JSON.parse(readFileSync28(pendingPath, "utf8")) : null;
43115
+ const digest = joinCredentialDigest(join43);
43116
+ if (pending2 && (!pending2.claimed || pending2.claimed.digest !== digest || pending2.claimed.cellId !== join43.cellId)) {
42867
43117
  throw new Error(`pending Otium enrollment at ${pendingPath} does not match these credentials`);
42868
43118
  }
42869
- const path = saveJoinWhileLocked(join42, options);
42870
- if (!isJoinPersisted(join42)) {
43119
+ const path = saveJoinWhileLocked(join43, options);
43120
+ if (!isJoinPersisted(join43)) {
42871
43121
  throw new Error("Otium join credentials were not durably persisted");
42872
43122
  }
42873
43123
  if (!pending2)
42874
43124
  return path;
42875
43125
  unlinkSync23(pendingPath);
42876
- const directoryFd = openSync5(dirname22(pendingPath), "r");
43126
+ const directoryFd = openSync6(dirname22(pendingPath), "r");
42877
43127
  try {
42878
43128
  fsyncSync3(directoryFd);
42879
43129
  } finally {
42880
- closeSync5(directoryFd);
43130
+ closeSync6(directoryFd);
42881
43131
  }
42882
43132
  return path;
42883
43133
  });
@@ -43758,14 +44008,14 @@ var init_peer_server = __esm(async () => {
43758
44008
 
43759
44009
  // ../../adapters/otium/src/index.ts
43760
44010
  function startOtiumNodeRuntime(options) {
43761
- const { join: join42 } = options;
43762
- configureOtiumCentral(join42);
44011
+ const { join: join43 } = options;
44012
+ configureOtiumCentral(join43);
43763
44013
  const failed = failInterruptedPeerTurnRequestsOnStartup();
43764
44014
  if (failed > 0) {
43765
44015
  logger.warn({ failed }, "otium: failed interrupted peer turns from previous process");
43766
44016
  }
43767
44017
  const stopBackflow = startEventBackflow();
43768
- const stopSharedTopicSync = startSharedTopicSync(join42);
44018
+ const stopSharedTopicSync = startSharedTopicSync(join43);
43769
44019
  const unregisterRuntimeBridge = registerPeerRuntimeBridge(otiumPeerRuntimeBridge);
43770
44020
  const unregisterSessionBridge = registerPeerSessionBridge(otiumPeerSessionBridge);
43771
44021
  const sessionBridgeIpc = startPeerSessionBridgeIpc(otiumPeerSessionBridge);
@@ -43786,7 +44036,7 @@ function startOtiumNodeRuntime(options) {
43786
44036
  }
43787
44037
  });
43788
44038
  let stopped = false;
43789
- logger.info({ central: join42.central, cellId: join42.cellId }, "otium: worker mode enabled");
44039
+ logger.info({ central: join43.central, cellId: join43.cellId }, "otium: worker mode enabled");
43790
44040
  selfPeerNode().then((self) => {
43791
44041
  if (self) {
43792
44042
  logger.info({ nodeName: self.nodeName, baseUrl: self.baseUrl }, "otium: attached to workspace");
@@ -43796,7 +44046,7 @@ function startOtiumNodeRuntime(options) {
43796
44046
  });
43797
44047
  return {
43798
44048
  name: "otium",
43799
- join: join42,
44049
+ join: join43,
43800
44050
  stop: () => {
43801
44051
  if (stopped)
43802
44052
  return;
@@ -43918,10 +44168,10 @@ async function handleOtiumAdapterControlRequest(req) {
43918
44168
  return await handleOtiumPeerRequest(new Request(peerUrl.toString(), { method: req.method, headers, body, signal: req.signal })) ?? Response.json({ ok: false, error: "Otium route not found" }, { status: 404 });
43919
44169
  }
43920
44170
  function mountConfiguredOtiumNodeRuntime() {
43921
- const join42 = loadJoin();
43922
- if (!join42)
44171
+ const join43 = loadJoin();
44172
+ if (!join43)
43923
44173
  return null;
43924
- const runtime2 = startOtiumNodeRuntime({ join: join42 });
44174
+ const runtime2 = startOtiumNodeRuntime({ join: join43 });
43925
44175
  registerNodeRequestHandler("otium-adapter-control", handleOtiumAdapterControlRequest);
43926
44176
  let stopped = false;
43927
44177
  return {
@@ -43972,11 +44222,11 @@ async function joinCommand(args) {
43972
44222
  process.exitCode = 1;
43973
44223
  return;
43974
44224
  }
43975
- let join42;
44225
+ let join43;
43976
44226
  let productionEnrollment = false;
43977
44227
  if (args.includes("--legacy")) {
43978
44228
  try {
43979
- join42 = parseInviteCode(code);
44229
+ join43 = parseInviteCode(code);
43980
44230
  } catch (err2) {
43981
44231
  console.error(`invalid legacy invite code: ${err2 instanceof Error ? err2.message : err2}`);
43982
44232
  process.exitCode = 1;
@@ -44003,7 +44253,7 @@ async function joinCommand(args) {
44003
44253
  return;
44004
44254
  }
44005
44255
  }
44006
- join42 = await claimEnrollment(invite, nodeName);
44256
+ join43 = await claimEnrollment(invite, nodeName);
44007
44257
  productionEnrollment = true;
44008
44258
  } catch (err2) {
44009
44259
  console.error(`enrollment failed: ${err2 instanceof Error ? err2.message : err2}`);
@@ -44014,16 +44264,16 @@ async function joinCommand(args) {
44014
44264
  let path;
44015
44265
  try {
44016
44266
  const saveOptions = { replaceExisting: args.includes("--replace") };
44017
- path = productionEnrollment ? commitEnrollment(join42, saveOptions) : saveJoin(join42, saveOptions);
44267
+ path = productionEnrollment ? commitEnrollment(join43, saveOptions) : saveJoin(join43, saveOptions);
44018
44268
  } catch (err2) {
44019
44269
  console.error(`could not save join credentials: ${err2 instanceof Error ? err2.message : err2}`);
44020
44270
  process.exitCode = 1;
44021
44271
  return;
44022
44272
  }
44023
44273
  console.log(`otium join credentials saved to ${path}`);
44024
- console.log(` central: ${join42.central}`);
44025
- console.log(` cellId: ${join42.cellId}`);
44026
- configureOtiumCentral(join42);
44274
+ console.log(` central: ${join43.central}`);
44275
+ console.log(` cellId: ${join43.cellId}`);
44276
+ configureOtiumCentral(join43);
44027
44277
  try {
44028
44278
  const self = await selfPeerNode();
44029
44279
  if (self) {
@@ -44078,8 +44328,8 @@ async function proxyOtiumPeerRequest(req, dependencies = {}) {
44078
44328
  }
44079
44329
  }
44080
44330
  async function runOtiumSidecar(options) {
44081
- const join42 = loadJoin();
44082
- if (!join42) {
44331
+ const join43 = loadJoin();
44332
+ if (!join43) {
44083
44333
  throw new Error("not joined to an Otium workspace \u2014 run `negotium otium join <code>` first");
44084
44334
  }
44085
44335
  const initialNode = await inspectNodeDaemon();
@@ -44111,10 +44361,10 @@ async function runOtiumSidecar(options) {
44111
44361
  lease.stop();
44112
44362
  throw error2;
44113
44363
  }
44114
- const selectedRelay = options.relayUrl?.trim() || join42.relay || process.env.OTIUM_RELAY_URL?.trim();
44364
+ const selectedRelay = options.relayUrl?.trim() || join43.relay || process.env.OTIUM_RELAY_URL?.trim();
44115
44365
  const tunnel = selectedRelay ? new TunnelClient({
44116
44366
  relayUrl: selectedRelay,
44117
- token: join42.secret,
44367
+ token: join43.secret,
44118
44368
  targetOrigin: `http://127.0.0.1:${server.port}`,
44119
44369
  nodeVersion: `negotium@${NEGOTIUM_VERSION}`,
44120
44370
  logger
@@ -44205,10 +44455,10 @@ async function resolveHostNodeId(explicit) {
44205
44455
  init_central().then(() => exports_central),
44206
44456
  init_join().then(() => exports_join)
44207
44457
  ]);
44208
- const join42 = loadJoin2();
44209
- if (!join42)
44458
+ const join43 = loadJoin2();
44459
+ if (!join43)
44210
44460
  throw new Error("not joined to an Otium workspace; pass --host-node or join first");
44211
- configureOtiumCentral2(join42);
44461
+ configureOtiumCentral2(join43);
44212
44462
  try {
44213
44463
  const nodes = await listPeerNodes2({ fresh: true });
44214
44464
  const primary = nodes.find((node) => node.isPrimary && !node.self) ?? nodes.find((node) => node.isPrimary);
@@ -44279,12 +44529,12 @@ async function runOtiumCli(args = process.argv.slice(2)) {
44279
44529
  const { configureOtiumCentral: configureOtiumCentral2 } = await init_central().then(() => exports_central);
44280
44530
  const { loadJoin: loadJoin2, removeJoin: removeJoin2 } = await init_join().then(() => exports_join);
44281
44531
  const { disconnectSharedTopics: disconnectSharedTopics2 } = await init_shared_topic_sync().then(() => exports_shared_topic_sync);
44282
- const join42 = loadJoin2();
44283
- if (!join42)
44532
+ const join43 = loadJoin2();
44533
+ if (!join43)
44284
44534
  throw new Error("not joined to an Otium workspace");
44285
- configureOtiumCentral2(join42);
44535
+ configureOtiumCentral2(join43);
44286
44536
  try {
44287
- await disconnectSharedTopics2(join42);
44537
+ await disconnectSharedTopics2(join43);
44288
44538
  removeJoin2();
44289
44539
  } finally {
44290
44540
  configureOtiumCentral2(null);
@@ -45061,4 +45311,4 @@ switch (command) {
45061
45311
  }
45062
45312
  }
45063
45313
 
45064
- //# debugId=3049BACCAD484D0864756E2164756E21
45314
+ //# debugId=C6B36BE30E72B26A64756E2164756E21