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.
- package/dist/agent-helpers.js +34 -8
- package/dist/agent-helpers.js.map +6 -6
- package/dist/background-bash.js +32 -6
- package/dist/background-bash.js.map +4 -4
- package/dist/browser-runtime.js +14 -2
- package/dist/browser-runtime.js.map +3 -3
- package/dist/{chunk-8asy22vc.js → chunk-5g5a63vv.js} +32 -6
- package/dist/{chunk-8asy22vc.js.map → chunk-5g5a63vv.js.map} +4 -4
- package/dist/hosted-agent.js +33 -7
- package/dist/hosted-agent.js.map +5 -5
- package/dist/main.js +603 -353
- package/dist/main.js.map +12 -11
- package/dist/mcp-factories.js +34 -8
- package/dist/mcp-factories.js.map +6 -6
- package/dist/mcp-servers.js +3 -2
- package/dist/mcp-servers.js.map +3 -3
- package/dist/prompts.js +14 -2
- package/dist/prompts.js.map +3 -3
- package/dist/query-runtime.js +14 -2
- package/dist/query-runtime.js.map +3 -3
- package/dist/registry.js +3 -3
- package/dist/registry.js.map +2 -2
- package/dist/rollout.js +1 -1
- package/dist/runtime/src/index.ts +9 -0
- package/dist/runtime/src/node-host.ts +9 -0
- package/dist/runtime/src/platform/background-bash/manager.ts +45 -5
- package/dist/runtime/src/platform/config.ts +35 -2
- package/dist/runtime/src/runtime/bashrs-completions.ts +328 -0
- package/dist/runtime/src/runtime/turn-runner.ts +6 -0
- package/dist/runtime/src/version.ts +1 -1
- package/dist/runtime-helpers.js +14 -2
- package/dist/runtime-helpers.js.map +3 -3
- package/dist/types/apps/negotium/src/mcp-servers.d.ts +16 -3
- package/dist/types/packages/core/src/platform/background-bash/manager.d.ts +6 -1
- package/dist/types/packages/core/src/platform/config.d.ts +21 -1
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/dist/vault.js +14 -2
- package/dist/vault.js.map +3 -3
- package/install-bash-rs.mjs +77 -0
- package/package.json +3 -2
- 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,
|
|
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.
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
|
21198
|
-
import { join as
|
|
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 =
|
|
21556
|
+
userDirs = readdirSync8(SESSION_INBOX_DIR);
|
|
21319
21557
|
} catch {
|
|
21320
21558
|
return;
|
|
21321
21559
|
}
|
|
21322
21560
|
for (const uid of userDirs) {
|
|
21323
|
-
const userInboxDir =
|
|
21561
|
+
const userInboxDir = join32(SESSION_INBOX_DIR, uid);
|
|
21324
21562
|
let entries;
|
|
21325
21563
|
try {
|
|
21326
|
-
entries =
|
|
21564
|
+
entries = readdirSync8(userInboxDir);
|
|
21327
21565
|
} catch {
|
|
21328
21566
|
continue;
|
|
21329
21567
|
}
|
|
21330
21568
|
for (const entry of entries) {
|
|
21331
|
-
const entryPath =
|
|
21569
|
+
const entryPath = join32(userInboxDir, entry);
|
|
21332
21570
|
let isDir = false;
|
|
21333
21571
|
try {
|
|
21334
|
-
isDir =
|
|
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 =
|
|
21654
|
+
userDirs = readdirSync8(SESSION_INBOX_DIR);
|
|
21417
21655
|
} catch {
|
|
21418
21656
|
return;
|
|
21419
21657
|
}
|
|
21420
21658
|
for (const userId of userDirs) {
|
|
21421
|
-
const userInboxDir =
|
|
21659
|
+
const userInboxDir = join32(SESSION_INBOX_DIR, userId);
|
|
21422
21660
|
let files;
|
|
21423
21661
|
try {
|
|
21424
|
-
files =
|
|
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 =
|
|
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
|
|
21788
|
-
if (
|
|
21789
|
-
|
|
21790
|
-
|
|
22025
|
+
function stopLeaderResources2() {
|
|
22026
|
+
if (watcher2) {
|
|
22027
|
+
watcher2.close();
|
|
22028
|
+
watcher2 = null;
|
|
21791
22029
|
}
|
|
21792
|
-
if (
|
|
21793
|
-
clearInterval(
|
|
21794
|
-
|
|
22030
|
+
if (fallbackTimer2) {
|
|
22031
|
+
clearInterval(fallbackTimer2);
|
|
22032
|
+
fallbackTimer2 = null;
|
|
21795
22033
|
}
|
|
21796
|
-
|
|
22034
|
+
debouncedTrigger2 = null;
|
|
21797
22035
|
}
|
|
21798
22036
|
function tryBecomeSessionInboxLeader() {
|
|
21799
|
-
if (!
|
|
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 (
|
|
22042
|
+
if (workerLease2 !== acquired)
|
|
21805
22043
|
return;
|
|
21806
|
-
|
|
21807
|
-
|
|
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
|
-
|
|
21814
|
-
|
|
21815
|
-
|
|
21816
|
-
|
|
21817
|
-
|
|
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 (
|
|
22060
|
+
if (workerStarted2)
|
|
21823
22061
|
return () => {};
|
|
21824
|
-
|
|
22062
|
+
workerStarted2 = true;
|
|
21825
22063
|
tryBecomeSessionInboxLeader();
|
|
21826
|
-
|
|
21827
|
-
|
|
22064
|
+
leadershipTimer2 = setInterval(tryBecomeSessionInboxLeader, PROCESS_LEASE_HEARTBEAT_MS);
|
|
22065
|
+
leadershipTimer2.unref?.();
|
|
21828
22066
|
return () => {
|
|
21829
|
-
if (!
|
|
22067
|
+
if (!workerStarted2)
|
|
21830
22068
|
return;
|
|
21831
|
-
|
|
21832
|
-
if (
|
|
21833
|
-
clearInterval(
|
|
21834
|
-
|
|
22069
|
+
workerStarted2 = false;
|
|
22070
|
+
if (leadershipTimer2) {
|
|
22071
|
+
clearInterval(leadershipTimer2);
|
|
22072
|
+
leadershipTimer2 = null;
|
|
21835
22073
|
}
|
|
21836
|
-
|
|
21837
|
-
|
|
21838
|
-
|
|
22074
|
+
stopLeaderResources2();
|
|
22075
|
+
workerLease2?.stop();
|
|
22076
|
+
workerLease2 = null;
|
|
21839
22077
|
logger.info("session-inbox: worker stopped");
|
|
21840
22078
|
};
|
|
21841
22079
|
}
|
|
21842
|
-
var topicWorkerBusy,
|
|
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
|
|
22160
|
-
import { dirname as dirname15, join as
|
|
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
|
|
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 =
|
|
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
|
|
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) || !
|
|
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 =
|
|
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,${
|
|
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
|
|
23211
|
-
import { join as
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
|
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 =
|
|
23747
|
-
const candidates = [
|
|
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(
|
|
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
|
|
24645
|
+
closeSync as closeSync4,
|
|
24400
24646
|
existsSync as existsSync26,
|
|
24401
24647
|
mkdirSync as mkdirSync24,
|
|
24402
|
-
openSync as
|
|
24403
|
-
readdirSync as
|
|
24404
|
-
readFileSync as
|
|
24405
|
-
renameSync as
|
|
24406
|
-
statSync as
|
|
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
|
|
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 =
|
|
24690
|
+
const fd = openSync4(guardPath, "wx");
|
|
24445
24691
|
try {
|
|
24446
24692
|
writeFileSync17(fd, ownerToken, "utf-8");
|
|
24447
24693
|
} catch (error2) {
|
|
24448
|
-
|
|
24694
|
+
closeSync4(fd);
|
|
24449
24695
|
try {
|
|
24450
24696
|
unlinkSync18(guardPath);
|
|
24451
24697
|
} catch {}
|
|
24452
24698
|
throw error2;
|
|
24453
24699
|
}
|
|
24454
24700
|
return () => {
|
|
24455
|
-
|
|
24701
|
+
closeSync4(fd);
|
|
24456
24702
|
try {
|
|
24457
|
-
if (
|
|
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 =
|
|
24723
|
+
const fd = openSync4(lockPath, "wx");
|
|
24478
24724
|
try {
|
|
24479
24725
|
writeFileSync17(fd, ownerToken, "utf-8");
|
|
24480
24726
|
} catch (error2) {
|
|
24481
|
-
|
|
24727
|
+
closeSync4(fd);
|
|
24482
24728
|
try {
|
|
24483
24729
|
unlinkSync18(lockPath);
|
|
24484
24730
|
} catch {}
|
|
24485
24731
|
throw error2;
|
|
24486
24732
|
}
|
|
24487
24733
|
return () => {
|
|
24488
|
-
|
|
24734
|
+
closeSync4(fd);
|
|
24489
24735
|
const releaseGuard = acquireRecoveryGuard(lockPath);
|
|
24490
24736
|
try {
|
|
24491
|
-
if (
|
|
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 =
|
|
24504
|
-
if (Date.now() -
|
|
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
|
-
|
|
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
|
|
24803
|
+
for (const entry of readdirSync10(dir, { withFileTypes: true })) {
|
|
24558
24804
|
if (entry.isDirectory()) {
|
|
24559
|
-
const sub =
|
|
24805
|
+
const sub = join36(dir, entry.name);
|
|
24560
24806
|
if (label === "articles" || label === "skills") {
|
|
24561
24807
|
try {
|
|
24562
|
-
for (const f of
|
|
24808
|
+
for (const f of readdirSync10(sub, { withFileTypes: true })) {
|
|
24563
24809
|
if (!f.isFile() || !f.name.endsWith(".md"))
|
|
24564
24810
|
continue;
|
|
24565
|
-
const fp =
|
|
24811
|
+
const fp = join36(sub, f.name);
|
|
24566
24812
|
try {
|
|
24567
|
-
const text2 =
|
|
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 =
|
|
24824
|
+
const fp = join36(dir, entry.name);
|
|
24579
24825
|
try {
|
|
24580
|
-
const text2 =
|
|
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) ?
|
|
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) ?
|
|
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) &&
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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) ?
|
|
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 =
|
|
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
|
|
25256
|
-
renameSync as
|
|
25257
|
-
statSync as
|
|
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
|
|
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 =
|
|
25521
|
+
const file = join37(logDir, `${entry.userId}_${safeSession}_${sidShort}.jsonl`);
|
|
25276
25522
|
try {
|
|
25277
|
-
const stat =
|
|
25523
|
+
const stat = statSync16(file);
|
|
25278
25524
|
if (stat.size >= MAX_FILE_SIZE) {
|
|
25279
25525
|
const rotated = file.replace(/\.jsonl$/, `.${Date.now()}.jsonl`);
|
|
25280
|
-
|
|
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 =
|
|
25539
|
+
const files = readdirSync11(logDir).filter((f) => f.endsWith(".jsonl")).map((f) => {
|
|
25294
25540
|
try {
|
|
25295
|
-
const stat =
|
|
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(
|
|
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 =
|
|
25569
|
+
const dir = join37(resolveStorageUsersLogDir(), String(entry.userId));
|
|
25324
25570
|
mkdirSync25(dir, { recursive: true });
|
|
25325
|
-
const file =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
|
26970
|
-
readFileSync as
|
|
26971
|
-
renameSync as
|
|
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
|
|
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 =
|
|
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(
|
|
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 =
|
|
27534
|
+
const file = join38(this.portsDir, fileName);
|
|
27289
27535
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
27290
27536
|
writeFileSync20(tmp, String(port));
|
|
27291
|
-
|
|
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(
|
|
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
|
|
27406
|
-
rmSync as
|
|
27407
|
-
statSync as
|
|
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
|
|
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 =
|
|
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
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
27729
|
+
const savedPath = join39(this.uploadDir, savedName);
|
|
27484
27730
|
try {
|
|
27485
|
-
const stats =
|
|
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
|
-
|
|
27502
|
-
|
|
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 =
|
|
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
|
-
|
|
27535
|
-
|
|
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
|
|
27689
|
-
renameSync as
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
30800
|
+
path = join40(home, frag.slice(2));
|
|
30551
30801
|
else if (frag.startsWith("/"))
|
|
30552
30802
|
path = frag;
|
|
30553
30803
|
else
|
|
30554
|
-
path =
|
|
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(
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
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
|
|
30939
|
+
return join40(home, frag.slice(2));
|
|
30690
30940
|
if (frag.startsWith("/"))
|
|
30691
30941
|
return frag;
|
|
30692
|
-
return
|
|
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
|
|
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 ??
|
|
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(
|
|
39500
|
-
joinConfig =
|
|
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
|
|
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
|
|
39663
|
-
readFileSync as
|
|
39664
|
-
renameSync as
|
|
39665
|
-
rmSync as
|
|
39666
|
-
statSync as
|
|
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 =
|
|
40001
|
+
const ownerFd = openSync5(ownerPath, "r");
|
|
39752
40002
|
try {
|
|
39753
40003
|
fsyncSync2(ownerFd);
|
|
39754
40004
|
} finally {
|
|
39755
|
-
|
|
40005
|
+
closeSync5(ownerFd);
|
|
39756
40006
|
}
|
|
39757
40007
|
break;
|
|
39758
40008
|
} catch (error2) {
|
|
39759
40009
|
if (created) {
|
|
39760
|
-
|
|
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(
|
|
40017
|
+
current3 = JSON.parse(readFileSync27(ownerPath, "utf8"));
|
|
39768
40018
|
} catch {}
|
|
39769
40019
|
let ageMs;
|
|
39770
40020
|
try {
|
|
39771
|
-
ageMs = Date.now() -
|
|
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
|
-
|
|
39786
|
-
|
|
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(
|
|
40047
|
+
const current3 = JSON.parse(readFileSync27(ownerPath, "utf8"));
|
|
39798
40048
|
if (current3.pid === owner.pid && current3.token === owner.token) {
|
|
39799
|
-
|
|
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(
|
|
40057
|
+
function normalizedJoin(join42) {
|
|
39808
40058
|
return normalizeJoin({
|
|
39809
|
-
v:
|
|
39810
|
-
central:
|
|
39811
|
-
relay:
|
|
39812
|
-
cellId:
|
|
39813
|
-
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(
|
|
39817
|
-
return createHash10("sha256").update(JSON.stringify(normalizedJoin(
|
|
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(
|
|
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(
|
|
40078
|
+
function isJoinPersisted(join42) {
|
|
39829
40079
|
try {
|
|
39830
40080
|
const persisted = readPersistedJoin();
|
|
39831
|
-
return persisted !== null && joinsEqual(persisted, normalizedJoin(
|
|
40081
|
+
return persisted !== null && joinsEqual(persisted, normalizedJoin(join42));
|
|
39832
40082
|
} catch {
|
|
39833
40083
|
return false;
|
|
39834
40084
|
}
|
|
39835
40085
|
}
|
|
39836
|
-
function saveJoinWhileLocked(
|
|
40086
|
+
function saveJoinWhileLocked(join42, options = {}) {
|
|
39837
40087
|
const path = joinFilePath();
|
|
39838
40088
|
const directory = dirname21(path);
|
|
39839
|
-
const normalized = normalizedJoin(
|
|
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 =
|
|
40105
|
+
const fileFd = openSync5(path, "r");
|
|
39856
40106
|
try {
|
|
39857
40107
|
fsyncSync2(fileFd);
|
|
39858
40108
|
} finally {
|
|
39859
|
-
|
|
40109
|
+
closeSync5(fileFd);
|
|
39860
40110
|
}
|
|
39861
|
-
const directoryFd =
|
|
40111
|
+
const directoryFd = openSync5(directory, "r");
|
|
39862
40112
|
try {
|
|
39863
40113
|
fsyncSync2(directoryFd);
|
|
39864
40114
|
} finally {
|
|
39865
|
-
|
|
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 =
|
|
40126
|
+
fd = openSync5(temporaryPath, "wx", 384);
|
|
39877
40127
|
writeFileSync23(fd, `${JSON.stringify(normalized, null, 2)}
|
|
39878
40128
|
`, "utf8");
|
|
39879
40129
|
fsyncSync2(fd);
|
|
39880
|
-
|
|
40130
|
+
closeSync5(fd);
|
|
39881
40131
|
fd = undefined;
|
|
39882
40132
|
if (options.replaceExisting) {
|
|
39883
|
-
|
|
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 =
|
|
40139
|
+
const directoryFd = openSync5(directory, "r");
|
|
39890
40140
|
try {
|
|
39891
40141
|
fsyncSync2(directoryFd);
|
|
39892
40142
|
} finally {
|
|
39893
|
-
|
|
40143
|
+
closeSync5(directoryFd);
|
|
39894
40144
|
}
|
|
39895
40145
|
} catch (error2) {
|
|
39896
40146
|
if (fd !== undefined)
|
|
39897
|
-
|
|
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(
|
|
39905
|
-
return withJoinCredentialLock(() => saveJoinWhileLocked(
|
|
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 =
|
|
40166
|
+
const directoryFd = openSync5(dirname21(path), "r");
|
|
39917
40167
|
try {
|
|
39918
40168
|
fsyncSync2(directoryFd);
|
|
39919
40169
|
} finally {
|
|
39920
|
-
|
|
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(
|
|
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
|
|
40923
|
-
import { basename as basename13, extname as extname6, join as
|
|
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 =
|
|
41243
|
+
const path = join42(PEER_FILES_DIR, `${id}-${safeFilename(args.filename)}`);
|
|
40994
41244
|
copyFileSync5(args.sourcePath, path);
|
|
40995
|
-
return recordFile({ id, path, sizeBytes:
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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(
|
|
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(
|
|
42056
|
+
setTimeout(() => void reconcileTopic(join43, topicId), RETRY_MS).unref?.();
|
|
41807
42057
|
}
|
|
41808
42058
|
}
|
|
41809
|
-
async function unpublishTopic(
|
|
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(
|
|
42075
|
+
setTimeout(() => void reconcileTopic(join43, topicId), RETRY_MS).unref?.();
|
|
41826
42076
|
}
|
|
41827
42077
|
}
|
|
41828
|
-
async function reconcileTopic(
|
|
42078
|
+
async function reconcileTopic(join43, topicId, explicit = false) {
|
|
41829
42079
|
if (!otiumCentralConfig())
|
|
41830
42080
|
return;
|
|
41831
|
-
if (!explicit && isPeerDetached(
|
|
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(
|
|
41839
|
-
return unpublishTopic(
|
|
42088
|
+
return publishTopic(join43, topicId, target);
|
|
42089
|
+
return unpublishTopic(join43, topicId, target);
|
|
41840
42090
|
}
|
|
41841
|
-
function disconnectSharedTopics(
|
|
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(
|
|
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(
|
|
42117
|
+
async function checkPeerAttachment(join43) {
|
|
41868
42118
|
const nodes = await listPeerNodes({ fresh: true });
|
|
41869
|
-
if (nodes.some((node) => node.cellId ===
|
|
42119
|
+
if (nodes.some((node) => node.cellId === join43.cellId))
|
|
41870
42120
|
return true;
|
|
41871
|
-
downgradeSharedTopicsForHub(
|
|
42121
|
+
downgradeSharedTopicsForHub(join43.cellId);
|
|
41872
42122
|
return false;
|
|
41873
42123
|
}
|
|
41874
|
-
function startSharedTopicSync(
|
|
42124
|
+
function startSharedTopicSync(join43) {
|
|
41875
42125
|
let stopped = false;
|
|
41876
|
-
let detached = isPeerDetached(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
42668
|
-
readFileSync as
|
|
42669
|
-
renameSync as
|
|
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(
|
|
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(
|
|
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 =
|
|
42977
|
+
fd = openSync6(temporaryPath, "wx", 384);
|
|
42728
42978
|
writeFileSync24(fd, `${JSON.stringify(pending2, null, 2)}
|
|
42729
42979
|
`, "utf8");
|
|
42730
42980
|
fsyncSync3(fd);
|
|
42731
|
-
|
|
42981
|
+
closeSync6(fd);
|
|
42732
42982
|
fd = undefined;
|
|
42733
42983
|
linkSync2(temporaryPath, path);
|
|
42734
42984
|
unlinkSync23(temporaryPath);
|
|
42735
42985
|
chmodSync7(path, 384);
|
|
42736
|
-
const directoryFd =
|
|
42986
|
+
const directoryFd = openSync6(dirname22(path), "r");
|
|
42737
42987
|
try {
|
|
42738
42988
|
fsyncSync3(directoryFd);
|
|
42739
42989
|
} finally {
|
|
42740
|
-
|
|
42990
|
+
closeSync6(directoryFd);
|
|
42741
42991
|
}
|
|
42742
42992
|
} catch (error2) {
|
|
42743
42993
|
if (fd !== undefined)
|
|
42744
|
-
|
|
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(
|
|
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 =
|
|
43012
|
+
fd = openSync6(temporaryPath, "wx", 384);
|
|
42763
43013
|
writeFileSync24(fd, `${JSON.stringify(pending2, null, 2)}
|
|
42764
43014
|
`, "utf8");
|
|
42765
43015
|
fsyncSync3(fd);
|
|
42766
|
-
|
|
43016
|
+
closeSync6(fd);
|
|
42767
43017
|
fd = undefined;
|
|
42768
|
-
|
|
42769
|
-
const directoryFd =
|
|
43018
|
+
renameSync17(temporaryPath, path);
|
|
43019
|
+
const directoryFd = openSync6(directory, "r");
|
|
42770
43020
|
try {
|
|
42771
43021
|
fsyncSync3(directoryFd);
|
|
42772
43022
|
} finally {
|
|
42773
|
-
|
|
43023
|
+
closeSync6(directoryFd);
|
|
42774
43024
|
}
|
|
42775
43025
|
} catch (error2) {
|
|
42776
43026
|
if (fd !== undefined)
|
|
42777
|
-
|
|
43027
|
+
closeSync6(fd);
|
|
42778
43028
|
if (existsSync37(temporaryPath))
|
|
42779
43029
|
unlinkSync23(temporaryPath);
|
|
42780
43030
|
throw error2;
|
|
42781
43031
|
}
|
|
42782
43032
|
}
|
|
42783
|
-
function recordClaimedCredential(pending2,
|
|
43033
|
+
function recordClaimedCredential(pending2, join43) {
|
|
42784
43034
|
withJoinCredentialLock(() => {
|
|
42785
|
-
const current3 = JSON.parse(
|
|
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(
|
|
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
|
|
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 (!
|
|
43104
|
+
if (!join43.relay || !join43.cellId || join43.cellId === "undefined") {
|
|
42855
43105
|
throw new Error("central returned an incomplete enrollment response");
|
|
42856
43106
|
}
|
|
42857
|
-
assertSecureRelayUrl(
|
|
42858
|
-
recordClaimedCredential(pending2,
|
|
42859
|
-
return
|
|
43107
|
+
assertSecureRelayUrl(join43.relay);
|
|
43108
|
+
recordClaimedCredential(pending2, join43);
|
|
43109
|
+
return join43;
|
|
42860
43110
|
}
|
|
42861
|
-
function commitEnrollment(
|
|
43111
|
+
function commitEnrollment(join43, options = {}) {
|
|
42862
43112
|
return withJoinCredentialLock(() => {
|
|
42863
43113
|
const pendingPath = pendingEnrollmentPath();
|
|
42864
|
-
const pending2 = existsSync37(pendingPath) ? JSON.parse(
|
|
42865
|
-
const digest = joinCredentialDigest(
|
|
42866
|
-
if (pending2 && (!pending2.claimed || pending2.claimed.digest !== digest || pending2.claimed.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(
|
|
42870
|
-
if (!isJoinPersisted(
|
|
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 =
|
|
43126
|
+
const directoryFd = openSync6(dirname22(pendingPath), "r");
|
|
42877
43127
|
try {
|
|
42878
43128
|
fsyncSync3(directoryFd);
|
|
42879
43129
|
} finally {
|
|
42880
|
-
|
|
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:
|
|
43762
|
-
configureOtiumCentral(
|
|
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(
|
|
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:
|
|
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:
|
|
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
|
|
43922
|
-
if (!
|
|
44171
|
+
const join43 = loadJoin();
|
|
44172
|
+
if (!join43)
|
|
43923
44173
|
return null;
|
|
43924
|
-
const runtime2 = startOtiumNodeRuntime({ join:
|
|
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
|
|
44225
|
+
let join43;
|
|
43976
44226
|
let productionEnrollment = false;
|
|
43977
44227
|
if (args.includes("--legacy")) {
|
|
43978
44228
|
try {
|
|
43979
|
-
|
|
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
|
-
|
|
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(
|
|
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: ${
|
|
44025
|
-
console.log(` cellId: ${
|
|
44026
|
-
configureOtiumCentral(
|
|
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
|
|
44082
|
-
if (!
|
|
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() ||
|
|
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:
|
|
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
|
|
44209
|
-
if (!
|
|
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(
|
|
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
|
|
44283
|
-
if (!
|
|
44532
|
+
const join43 = loadJoin2();
|
|
44533
|
+
if (!join43)
|
|
44284
44534
|
throw new Error("not joined to an Otium workspace");
|
|
44285
|
-
configureOtiumCentral2(
|
|
44535
|
+
configureOtiumCentral2(join43);
|
|
44286
44536
|
try {
|
|
44287
|
-
await disconnectSharedTopics2(
|
|
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=
|
|
45314
|
+
//# debugId=C6B36BE30E72B26A64756E2164756E21
|