negotium 0.1.48 → 0.2.0
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/README.md +1 -1
- package/dist/agent-helpers.js +58 -74
- package/dist/agent-helpers.js.map +15 -15
- package/dist/background-bash.js +22 -10
- package/dist/background-bash.js.map +3 -3
- package/dist/browser-runtime.js +35 -68
- package/dist/browser-runtime.js.map +7 -7
- package/dist/{chunk-d9jyt6xe.js → chunk-kc5kmr95.js} +162 -12
- package/dist/{chunk-d9jyt6xe.js.map → chunk-kc5kmr95.js.map} +4 -4
- package/dist/hosted-agent.js +36 -18
- package/dist/hosted-agent.js.map +7 -7
- package/dist/main.js +562 -98
- package/dist/main.js.map +21 -19
- package/dist/mcp-factories.js +602 -223
- package/dist/mcp-factories.js.map +16 -16
- package/dist/prompts.js +22 -10
- package/dist/prompts.js.map +3 -3
- package/dist/query-runtime.js +22 -10
- package/dist/query-runtime.js.map +4 -4
- package/dist/registry.js +286 -10
- package/dist/registry.js.map +9 -7
- package/dist/rollout.js +14 -2
- package/dist/rollout.js.map +3 -3
- package/dist/runtime/src/agents/maestro-registry.ts +1 -1
- package/dist/runtime/src/agents/rollout/shared.ts +12 -4
- package/dist/runtime/src/mcp/mcp-helpers.ts +1 -1
- package/dist/runtime/src/mcp/wiki-server.ts +1 -1
- package/dist/runtime/src/migration/single-user.ts +621 -0
- package/dist/runtime/src/platform/config.ts +24 -11
- package/dist/runtime/src/platform/mcp-config.ts +4 -4
- package/dist/runtime/src/platform/playwright/manager.ts +10 -28
- package/dist/runtime/src/runtime/attachments.ts +3 -3
- package/dist/runtime/src/storage/browser-profiles.ts +11 -9
- package/dist/runtime/src/storage/conversations.ts +5 -18
- package/dist/runtime/src/storage/storage-host.ts +1 -1
- package/dist/runtime/src/storage/tasks.ts +2 -14
- package/dist/runtime/src/storage/vault.ts +3 -2
- package/dist/runtime/src/version.ts +1 -1
- package/dist/runtime-helpers.js +22 -10
- package/dist/runtime-helpers.js.map +5 -5
- package/dist/storage.js +5 -19
- package/dist/storage.js.map +5 -5
- package/dist/types/packages/core/src/mcp/mcp-helpers.d.ts +1 -1
- package/dist/types/packages/core/src/platform/config.d.ts +9 -1
- package/dist/types/packages/core/src/runtime/attachments.d.ts +1 -1
- package/dist/types/packages/core/src/storage/conversations.d.ts +2 -2
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/dist/vault.js +25 -12
- package/dist/vault.js.map +4 -4
- package/install-browser-rs.mjs +1 -1
- package/package.json +2 -2
package/dist/mcp-factories.js
CHANGED
|
@@ -155,7 +155,7 @@ function resolveBrowserRsBin(envValue) {
|
|
|
155
155
|
if (!override && !versionAtLeast(BROWSER_RS_VERSION.replace(/^v/, ""), BROWSER_RS_MIN_SECURE_VERSION)) {
|
|
156
156
|
return;
|
|
157
157
|
}
|
|
158
|
-
const candidate = override ? resolve(override) : resolve(
|
|
158
|
+
const candidate = override ? resolve(override) : resolve(BINARIES_DIR, "browser-rs", BROWSER_RS_VERSION, "browser-rs");
|
|
159
159
|
try {
|
|
160
160
|
accessSync(candidate, constants.X_OK);
|
|
161
161
|
return browserRsMeetsMinimumVersion(candidate) ? candidate : undefined;
|
|
@@ -167,7 +167,7 @@ function resolveBrowserMcpBin(envValue) {
|
|
|
167
167
|
const override = envValue?.trim();
|
|
168
168
|
if (override)
|
|
169
169
|
return resolve(override);
|
|
170
|
-
return BROWSER_RS_BIN ?? resolve(
|
|
170
|
+
return BROWSER_RS_BIN ?? resolve(BINARIES_DIR, "browser-rs", BROWSER_RS_VERSION, "browser-rs");
|
|
171
171
|
}
|
|
172
172
|
function resolveBrowserProxy() {
|
|
173
173
|
const raw = envText("BROWSER_PROXY_URL");
|
|
@@ -199,7 +199,7 @@ function resolveTopicWorkspaceDir(topicId) {
|
|
|
199
199
|
}
|
|
200
200
|
function loadOrCreateLocalSecret(envKey, filename, options = {}) {
|
|
201
201
|
const envValue = envText(envKey);
|
|
202
|
-
const secretFile = resolve(
|
|
202
|
+
const secretFile = resolve(SECRETS_DIR, filename);
|
|
203
203
|
mkdirSync(dirname(secretFile), { recursive: true });
|
|
204
204
|
if (envValue) {
|
|
205
205
|
if (options.persistEnvValue) {
|
|
@@ -240,7 +240,7 @@ function resolveDefaultModel(agent, registryDefaultModel) {
|
|
|
240
240
|
function codexAuthFilePath() {
|
|
241
241
|
return process.env.NEGOTIUM_CODEX_AUTH_FILE || join(homedir(), ".codex", "auth.json");
|
|
242
242
|
}
|
|
243
|
-
var HOME, PROJECT_ROOT, STATE_DIR_ENV, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR,
|
|
243
|
+
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, CONTEXTS_DIR, DM_WORKSPACE_DIR, SESSION_WORKSPACE_DIR, CLAUDE_EXECUTABLE_ENV, CLAUDE_EXECUTABLE, DEFAULT_OUTPUT_LANGUAGE = "English", BROWSER_RS_VERSION = "v0.1.16", BROWSER_RS_MIN_SECURE_VERSION = "0.1.15", BROWSER_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, BROWSER_MCP_SSE_PROXY_SERVER, CANONICAL_MCP_PROXY_SERVER, WIKI_SERVER, TOKEN_STATS_SERVER, COMPACTION_LOG_SERVER, SYSTEM_HEALTH_SERVER, AGENT_HEALTH_SERVER, BACKGROUND_BASH_SERVER, VAULT_SERVER, BG_BASH_BASE_PORT, BG_BASH_MAX_PORT, RUNTIME_MCP_SECRET, NODE_CONTROL_TOKEN, VAULT_MASTER_KEY, NEGOTIUM_PORT, hostname, DATA_DIR, LOG_DIR, UPLOADS_DIR, VAULT_DIR, SESSIONS_DB, DEBUG_FILE, USERS_LOG_DIR, RUN_DIR, PROGRESS_DIR, DM_CMD_DIR, DM_RESP_DIR, SESSION_INBOX_DIR, SESSION_ASKS_DIR, PLAYWRIGHT_BASE_PORT, PLAYWRIGHT_MAX_PORT, PLAYWRIGHT_PORTS_DIR, ACTIVE_QUERY_STALE_MS, AGENTS_PROMPTS_DIR, RESOURCES_DIR, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5", MODEL_FABLE = "claude-fable-5", FALLBACK_AGENT, SESSION_AGENT, GATEWAY_AGENT, FALLBACK_MODEL, SESSION_MODEL, GATEWAY_MODEL, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, _envMaxTellDepth, MAX_TELL_DEPTH;
|
|
244
244
|
var init_config = __esm(() => {
|
|
245
245
|
init_config_helpers();
|
|
246
246
|
init_logger();
|
|
@@ -252,10 +252,14 @@ var init_config = __esm(() => {
|
|
|
252
252
|
WORKSPACE_DIR = resolveLocalStateDir("NEGOTIUM_WORKSPACE_DIR", "workspace");
|
|
253
253
|
TOPIC_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "topics");
|
|
254
254
|
SHARED_WIKI_DIR = resolve(WORKSPACE_DIR, "wiki");
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
255
|
+
CRON_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "cron");
|
|
256
|
+
BROWSER_DIR = resolveLocalStateDir("NEGOTIUM_BROWSER_DIR", "browser");
|
|
257
|
+
BROWSER_PROFILES_DIR = resolve(BROWSER_DIR, "profiles");
|
|
258
|
+
BINARIES_DIR = resolve(STATE_DIR, "binaries");
|
|
259
|
+
SECRETS_DIR = resolve(STATE_DIR, "secrets");
|
|
260
|
+
CONTEXTS_DIR = resolve(STATE_DIR, "data", "contexts");
|
|
261
|
+
DM_WORKSPACE_DIR = resolve(STATE_DIR, "data", "dm");
|
|
262
|
+
SESSION_WORKSPACE_DIR = resolve(STATE_DIR, "data", "sessions");
|
|
259
263
|
CLAUDE_EXECUTABLE_ENV = envText("NEGOTIUM_CLAUDE_EXECUTABLE");
|
|
260
264
|
CLAUDE_EXECUTABLE = CLAUDE_EXECUTABLE_ENV ? resolve(CLAUDE_EXECUTABLE_ENV) : undefined;
|
|
261
265
|
BROWSER_RS_BIN = resolveBrowserRsBin(envText("NEGOTIUM_BROWSER_RS_BIN"));
|
|
@@ -284,10 +288,12 @@ var init_config = __esm(() => {
|
|
|
284
288
|
hostname = process.env.HOSTNAME || "127.0.0.1";
|
|
285
289
|
DATA_DIR = resolveLocalStateDir("NEGOTIUM_DATA_DIR", "data");
|
|
286
290
|
LOG_DIR = resolveLocalStateDir("NEGOTIUM_LOG_DIR", "logs");
|
|
291
|
+
UPLOADS_DIR = resolve(DATA_DIR, "uploads");
|
|
292
|
+
VAULT_DIR = resolve(DATA_DIR, "vault");
|
|
287
293
|
SESSIONS_DB = process.env.SESSIONS_DB_PATH ? resolve(process.env.SESSIONS_DB_PATH) : resolve(DATA_DIR, "sessions.db");
|
|
288
294
|
DEBUG_FILE = resolve(DATA_DIR, "debug-users.json");
|
|
289
295
|
USERS_LOG_DIR = resolve(DATA_DIR, "users");
|
|
290
|
-
RUN_DIR = resolveLocalStateDir("NEGOTIUM_RUN_DIR", "
|
|
296
|
+
RUN_DIR = resolveLocalStateDir("NEGOTIUM_RUN_DIR", "runtime");
|
|
291
297
|
PROGRESS_DIR = resolve(RUN_DIR, "progress");
|
|
292
298
|
DM_CMD_DIR = resolve(RUN_DIR, "dm-commands");
|
|
293
299
|
DM_RESP_DIR = resolve(RUN_DIR, "dm-responses");
|
|
@@ -298,6 +304,8 @@ var init_config = __esm(() => {
|
|
|
298
304
|
PLAYWRIGHT_PORTS_DIR = resolve(RUN_DIR, "playwright-ports");
|
|
299
305
|
mkdirSync(STATE_DIR, { recursive: true });
|
|
300
306
|
mkdirSync(DATA_DIR, { recursive: true });
|
|
307
|
+
mkdirSync(UPLOADS_DIR, { recursive: true });
|
|
308
|
+
mkdirSync(VAULT_DIR, { recursive: true, mode: 448 });
|
|
301
309
|
mkdirSync(LOG_DIR, { recursive: true });
|
|
302
310
|
mkdirSync(PROGRESS_DIR, { recursive: true });
|
|
303
311
|
mkdirSync(DM_CMD_DIR, { recursive: true });
|
|
@@ -308,10 +316,14 @@ var init_config = __esm(() => {
|
|
|
308
316
|
mkdirSync(WORKSPACE_DIR, { recursive: true });
|
|
309
317
|
mkdirSync(TOPIC_WORKSPACE_DIR, { recursive: true });
|
|
310
318
|
mkdirSync(SHARED_WIKI_DIR, { recursive: true });
|
|
319
|
+
mkdirSync(CRON_WORKSPACE_DIR, { recursive: true });
|
|
311
320
|
mkdirSync(CONTEXTS_DIR, { recursive: true });
|
|
312
|
-
mkdirSync(BROWSER_PROFILES_DIR, { recursive: true });
|
|
313
321
|
mkdirSync(DM_WORKSPACE_DIR, { recursive: true });
|
|
314
322
|
mkdirSync(SESSION_WORKSPACE_DIR, { recursive: true });
|
|
323
|
+
mkdirSync(BROWSER_DIR, { recursive: true });
|
|
324
|
+
mkdirSync(BROWSER_PROFILES_DIR, { recursive: true });
|
|
325
|
+
mkdirSync(BINARIES_DIR, { recursive: true });
|
|
326
|
+
mkdirSync(SECRETS_DIR, { recursive: true, mode: 448 });
|
|
315
327
|
ACTIVE_QUERY_STALE_MS = 10 * 60 * 1000;
|
|
316
328
|
AGENTS_PROMPTS_DIR = resolve(PROJECT_ROOT, "src/prompts/agents");
|
|
317
329
|
RESOURCES_DIR = resolve(PROJECT_ROOT, "src/resources");
|
|
@@ -530,7 +542,12 @@ var init_shared = __esm(() => {
|
|
|
530
542
|
init_config();
|
|
531
543
|
init_logger();
|
|
532
544
|
__dirname2 = dirname3(fileURLToPath2(import.meta.url));
|
|
533
|
-
trustedWorkspaceRoots = [
|
|
545
|
+
trustedWorkspaceRoots = [
|
|
546
|
+
WORKSPACE_DIR,
|
|
547
|
+
DM_WORKSPACE_DIR,
|
|
548
|
+
SESSION_WORKSPACE_DIR,
|
|
549
|
+
TOPIC_WORKSPACE_DIR
|
|
550
|
+
].map((root) => resolve3(root));
|
|
534
551
|
FIXTURES_DIR = join3(__dirname2, "..", "fixtures");
|
|
535
552
|
UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
536
553
|
});
|
|
@@ -583,6 +600,13 @@ function parseJsonlText(raw) {
|
|
|
583
600
|
return raw.trim().split(`
|
|
584
601
|
`).filter(Boolean).map((line) => JSON.parse(line));
|
|
585
602
|
}
|
|
603
|
+
function readJsonFile(filePath) {
|
|
604
|
+
try {
|
|
605
|
+
return JSON.parse(readFileSync3(filePath, "utf-8"));
|
|
606
|
+
} catch {
|
|
607
|
+
return null;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
586
610
|
function lockStaleMs() {
|
|
587
611
|
const raw = Number.parseInt(process.env.NEGOTIUM_JSONL_LOCK_STALE_MS ?? "", 10);
|
|
588
612
|
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_LOCK_STALE_MS;
|
|
@@ -1486,7 +1510,7 @@ function defaultWorkspaceDir() {
|
|
|
1486
1510
|
return envPath("NEGOTIUM_WORKSPACE_DIR", join7(defaultStateDir(), "workspace"));
|
|
1487
1511
|
}
|
|
1488
1512
|
function defaultSessionAsksDir() {
|
|
1489
|
-
const runDir = envPath("NEGOTIUM_RUN_DIR", join7(defaultStateDir(), "
|
|
1513
|
+
const runDir = envPath("NEGOTIUM_RUN_DIR", join7(defaultStateDir(), "runtime"));
|
|
1490
1514
|
return join7(runDir, "session-asks");
|
|
1491
1515
|
}
|
|
1492
1516
|
function defaultSessionsDatabasePath() {
|
|
@@ -1592,15 +1616,8 @@ import {
|
|
|
1592
1616
|
writeFileSync as writeFileSync5
|
|
1593
1617
|
} from "fs";
|
|
1594
1618
|
import { dirname as dirname7, join as join8 } from "path";
|
|
1595
|
-
function
|
|
1596
|
-
|
|
1597
|
-
if (!str || /[/\\]|\.\./.test(str)) {
|
|
1598
|
-
throw new Error(`conversations: refusing unsafe userId path component: ${str}`);
|
|
1599
|
-
}
|
|
1600
|
-
return str;
|
|
1601
|
-
}
|
|
1602
|
-
function conversationDir(userId) {
|
|
1603
|
-
return join8(resolveStorageDataDir(), "conversations", safeUserIdComponent(userId));
|
|
1619
|
+
function conversationDir(_userId) {
|
|
1620
|
+
return join8(resolveStorageDataDir(), "conversations");
|
|
1604
1621
|
}
|
|
1605
1622
|
function topicFilename(topicName) {
|
|
1606
1623
|
const t = sanitizeTopicName(topicName, true);
|
|
@@ -1838,7 +1855,7 @@ function writeRollout(options) {
|
|
|
1838
1855
|
version: 1,
|
|
1839
1856
|
cwd: options.cwd,
|
|
1840
1857
|
createdAt: existingCreatedAt(path) ?? new Date().toISOString(),
|
|
1841
|
-
sdkVersion: "0.1.
|
|
1858
|
+
sdkVersion: "0.1.54"
|
|
1842
1859
|
}
|
|
1843
1860
|
},
|
|
1844
1861
|
...messages
|
|
@@ -3498,7 +3515,7 @@ var init_registry = __esm(async () => {
|
|
|
3498
3515
|
});
|
|
3499
3516
|
|
|
3500
3517
|
// ../../packages/core/src/agents/fork.ts
|
|
3501
|
-
import { existsSync as
|
|
3518
|
+
import { existsSync as existsSync10, unlinkSync as unlinkSync8 } from "fs";
|
|
3502
3519
|
function createAgentForkHelpers(host) {
|
|
3503
3520
|
return {
|
|
3504
3521
|
async forkAgentSession(options) {
|
|
@@ -3530,7 +3547,7 @@ var init_fork = __esm(async () => {
|
|
|
3530
3547
|
await init_registry();
|
|
3531
3548
|
defaultForkHelpers = createAgentForkHelpers({
|
|
3532
3549
|
forkSession: (agent, options) => getRegistryOperations(agent).forkSession(options),
|
|
3533
|
-
exists:
|
|
3550
|
+
exists: existsSync10,
|
|
3534
3551
|
unlink: unlinkSync8,
|
|
3535
3552
|
warn: (details, message) => logger.warn(details, message)
|
|
3536
3553
|
});
|
|
@@ -3923,7 +3940,7 @@ var init_runtime_process_leases = __esm(async () => {
|
|
|
3923
3940
|
|
|
3924
3941
|
// ../../packages/core/src/platform/playwright/browser-processes.ts
|
|
3925
3942
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
3926
|
-
import { readdirSync as
|
|
3943
|
+
import { readdirSync as readdirSync4, unlinkSync as unlinkSync9 } from "fs";
|
|
3927
3944
|
import { createServer } from "net";
|
|
3928
3945
|
import { resolve as resolve7, sep } from "path";
|
|
3929
3946
|
function isPortInUse(port) {
|
|
@@ -4048,7 +4065,7 @@ function reapOrphanBrowsers(liveUserDataDirs) {
|
|
|
4048
4065
|
}
|
|
4049
4066
|
function cleanSingletonFiles(userDataDir) {
|
|
4050
4067
|
try {
|
|
4051
|
-
const files =
|
|
4068
|
+
const files = readdirSync4(userDataDir);
|
|
4052
4069
|
for (const f of files) {
|
|
4053
4070
|
if (f.startsWith("Singleton")) {
|
|
4054
4071
|
try {
|
|
@@ -4239,7 +4256,7 @@ var init_vault_crypto = __esm(() => {
|
|
|
4239
4256
|
|
|
4240
4257
|
// ../../packages/core/src/storage/vault.ts
|
|
4241
4258
|
import { chmodSync as chmodSync2, mkdirSync as mkdirSync9 } from "fs";
|
|
4242
|
-
import { join as
|
|
4259
|
+
import { join as join12 } from "path";
|
|
4243
4260
|
function initializeVaultDatabase(database) {
|
|
4244
4261
|
database.exec("PRAGMA journal_mode = WAL");
|
|
4245
4262
|
database.exec("PRAGMA busy_timeout = 5000");
|
|
@@ -4274,8 +4291,9 @@ function initializeVaultDatabase(database) {
|
|
|
4274
4291
|
}
|
|
4275
4292
|
}
|
|
4276
4293
|
function openVaultDatabase(dataDir) {
|
|
4277
|
-
const
|
|
4278
|
-
|
|
4294
|
+
const vaultDir = join12(dataDir, "vault");
|
|
4295
|
+
const path = join12(vaultDir, "vault.db");
|
|
4296
|
+
mkdirSync9(vaultDir, { recursive: true, mode: 448 });
|
|
4279
4297
|
const database = new Database(path, { create: true });
|
|
4280
4298
|
chmodSync2(path, 384);
|
|
4281
4299
|
initializeVaultDatabase(database);
|
|
@@ -4381,7 +4399,7 @@ import { randomBytes as randomBytes4, timingSafeEqual } from "crypto";
|
|
|
4381
4399
|
import { chmodSync as chmodSync3 } from "fs";
|
|
4382
4400
|
import { createServer as createServer2 } from "net";
|
|
4383
4401
|
import { tmpdir } from "os";
|
|
4384
|
-
import { join as
|
|
4402
|
+
import { join as join13 } from "path";
|
|
4385
4403
|
function deepMapStrings(value2, transform) {
|
|
4386
4404
|
if (typeof value2 === "string")
|
|
4387
4405
|
return transform(value2);
|
|
@@ -4468,7 +4486,7 @@ function authorized(actual, expected) {
|
|
|
4468
4486
|
}
|
|
4469
4487
|
async function createBrowserVaultBroker(userId) {
|
|
4470
4488
|
const token = randomBytes4(32).toString("hex");
|
|
4471
|
-
const socketPath =
|
|
4489
|
+
const socketPath = join13(process.platform === "win32" ? tmpdir() : "/tmp", `negotium-browser-vault-${process.pid}-${randomBytes4(8).toString("hex")}.sock`);
|
|
4472
4490
|
const retainedForms = new Map;
|
|
4473
4491
|
const leases = new Map;
|
|
4474
4492
|
const sockets = new Set;
|
|
@@ -4628,7 +4646,7 @@ function createBrowserProfile(ownerId, rawName) {
|
|
|
4628
4646
|
const name = normalizeBrowserProfileName(rawName);
|
|
4629
4647
|
if (name === DEFAULT_BROWSER_PROFILE)
|
|
4630
4648
|
return name;
|
|
4631
|
-
db.query("INSERT OR IGNORE INTO browser_profiles (owner_id, name, created_at) VALUES (?, ?, ?)").run(
|
|
4649
|
+
db.query("INSERT OR IGNORE INTO browser_profiles (owner_id, name, created_at) VALUES (?, ?, ?)").run("local", name, new Date().toISOString());
|
|
4632
4650
|
return name;
|
|
4633
4651
|
}
|
|
4634
4652
|
function assignTopicBrowserProfile(opts) {
|
|
@@ -4661,19 +4679,18 @@ var init_browser_profiles = __esm(async () => {
|
|
|
4661
4679
|
});
|
|
4662
4680
|
|
|
4663
4681
|
// ../../packages/core/src/platform/playwright/manager.ts
|
|
4664
|
-
import { execFileSync as execFileSync3, spawn as
|
|
4682
|
+
import { execFileSync as execFileSync3, spawn as spawn3 } from "child_process";
|
|
4665
4683
|
import { createHash as createHash2, randomBytes as randomBytes5, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
4666
4684
|
import {
|
|
4667
4685
|
cpSync,
|
|
4668
|
-
existsSync as
|
|
4686
|
+
existsSync as existsSync11,
|
|
4669
4687
|
mkdirSync as mkdirSync10,
|
|
4670
|
-
readFileSync as
|
|
4671
|
-
renameSync as renameSync5,
|
|
4688
|
+
readFileSync as readFileSync9,
|
|
4672
4689
|
rmSync,
|
|
4673
4690
|
unlinkSync as unlinkSync10,
|
|
4674
4691
|
writeFileSync as writeFileSync7
|
|
4675
4692
|
} from "fs";
|
|
4676
|
-
import { dirname as dirname8, join as
|
|
4693
|
+
import { dirname as dirname8, join as join14, resolve as resolve9 } from "path";
|
|
4677
4694
|
function makeInstanceKey(userId, topic) {
|
|
4678
4695
|
return resolvePlaywrightTopicBinding(userId, topic).instanceKey;
|
|
4679
4696
|
}
|
|
@@ -4684,7 +4701,7 @@ function defaultTopicBinding(userId, topic) {
|
|
|
4684
4701
|
if (!topic)
|
|
4685
4702
|
return managerHost.resolveNamedBinding(userId, "default");
|
|
4686
4703
|
const ownerId = getBrowserProfileOwner(topic, userId);
|
|
4687
|
-
const profile =
|
|
4704
|
+
const profile = getTopicBrowserProfile(topic);
|
|
4688
4705
|
return managerHost.resolveNamedBinding(ownerId, profile);
|
|
4689
4706
|
}
|
|
4690
4707
|
function resolvePlaywrightProfileBinding(ownerId, rawProfile) {
|
|
@@ -4696,34 +4713,15 @@ function validateProfileBinding(binding) {
|
|
|
4696
4713
|
}
|
|
4697
4714
|
return Object.freeze({ ...binding });
|
|
4698
4715
|
}
|
|
4699
|
-
function defaultNamedBinding(
|
|
4716
|
+
function defaultNamedBinding(_ownerId, rawProfile) {
|
|
4700
4717
|
const profile = normalizeBrowserProfileName(rawProfile);
|
|
4701
|
-
const instanceKey = `profile:${
|
|
4718
|
+
const instanceKey = `profile:${profile}`;
|
|
4702
4719
|
return {
|
|
4703
4720
|
instanceKey,
|
|
4704
|
-
ownerId,
|
|
4721
|
+
ownerId: "local",
|
|
4705
4722
|
profile
|
|
4706
4723
|
};
|
|
4707
4724
|
}
|
|
4708
|
-
function legacyBrowserProfileName(topic) {
|
|
4709
|
-
return `legacy_${createHash2("sha256").update(topic).digest("hex").slice(0, 12)}`;
|
|
4710
|
-
}
|
|
4711
|
-
function migrateLegacyTopicProfile(ownerId, topic) {
|
|
4712
|
-
const current2 = getTopicBrowserProfile(topic);
|
|
4713
|
-
if (current2 !== "default" || !hasBrowserProfileTopic(topic))
|
|
4714
|
-
return current2;
|
|
4715
|
-
const legacyDir = resolve9(BROWSER_PROFILES_DIR, sanitizeTopicName(topic));
|
|
4716
|
-
if (!existsSync10(legacyDir))
|
|
4717
|
-
return current2;
|
|
4718
|
-
const profile = legacyBrowserProfileName(topic);
|
|
4719
|
-
const profileDir = defaultProfileDir(ownerId, profile);
|
|
4720
|
-
mkdirSync10(dirname8(profileDir), { recursive: true });
|
|
4721
|
-
if (!existsSync10(profileDir))
|
|
4722
|
-
renameSync5(legacyDir, profileDir);
|
|
4723
|
-
assignTopicBrowserProfile({ topicId: topic, actorUserId: ownerId, profile });
|
|
4724
|
-
logger.info({ ownerId, topic, profile }, "Adopted legacy topic browser profile");
|
|
4725
|
-
return profile;
|
|
4726
|
-
}
|
|
4727
4725
|
function defaultChildEnvironment(context) {
|
|
4728
4726
|
const childEnvironment = {};
|
|
4729
4727
|
for (const key of [
|
|
@@ -4754,6 +4752,10 @@ function defaultChildEnvironment(context) {
|
|
|
4754
4752
|
return childEnvironment;
|
|
4755
4753
|
}
|
|
4756
4754
|
function parseInstanceKey(instanceKey) {
|
|
4755
|
+
const shared = /^profile:(.+)$/.exec(instanceKey);
|
|
4756
|
+
if (shared && !shared[1].includes(":")) {
|
|
4757
|
+
return { ownerId: "local", profile: normalizeBrowserProfileName(shared[1]) };
|
|
4758
|
+
}
|
|
4757
4759
|
const match = /^profile:([^:]+):(.+)$/.exec(instanceKey);
|
|
4758
4760
|
if (!match)
|
|
4759
4761
|
return { ownerId: "legacy", profile: sanitizeTopicName(instanceKey) };
|
|
@@ -4768,14 +4770,14 @@ function portFileName(instanceKey) {
|
|
|
4768
4770
|
function writePortFile(instanceKey, port) {
|
|
4769
4771
|
try {
|
|
4770
4772
|
mkdirSync10(managerHost.portsDir, { recursive: true });
|
|
4771
|
-
writeFileSync7(
|
|
4773
|
+
writeFileSync7(join14(managerHost.portsDir, portFileName(instanceKey)), String(port));
|
|
4772
4774
|
} catch (e) {
|
|
4773
4775
|
logger.warn({ err: e, instanceKey, port }, "Failed to save playwright port file");
|
|
4774
4776
|
}
|
|
4775
4777
|
}
|
|
4776
4778
|
function deletePortFile(instanceKey) {
|
|
4777
4779
|
try {
|
|
4778
|
-
unlinkSync10(
|
|
4780
|
+
unlinkSync10(join14(managerHost.portsDir, portFileName(instanceKey)));
|
|
4779
4781
|
} catch (e) {
|
|
4780
4782
|
logger.warn({ err: e, instanceKey }, "Failed to delete playwright port file");
|
|
4781
4783
|
}
|
|
@@ -4896,12 +4898,8 @@ async function allocatePort() {
|
|
|
4896
4898
|
function releasePort(port) {
|
|
4897
4899
|
usedPorts.delete(port);
|
|
4898
4900
|
}
|
|
4899
|
-
function
|
|
4900
|
-
|
|
4901
|
-
return `${sanitizeTopicName(ownerId).slice(0, 24)}_${digest}`;
|
|
4902
|
-
}
|
|
4903
|
-
function defaultProfileDir(ownerId, profile) {
|
|
4904
|
-
return resolve9(BROWSER_PROFILES_DIR, "profiles", ownerDirectory(ownerId), profile);
|
|
4901
|
+
function defaultProfileDir(_ownerId, profile) {
|
|
4902
|
+
return resolve9(BROWSER_PROFILES_DIR, profile);
|
|
4905
4903
|
}
|
|
4906
4904
|
function resolveUserDataDir(instanceKey) {
|
|
4907
4905
|
return managerHost.resolveInstanceDataDir(instanceKey);
|
|
@@ -5029,7 +5027,7 @@ async function spawnPlaywright(instanceKey, ownerId, reservedPort, browserBin =
|
|
|
5029
5027
|
}
|
|
5030
5028
|
let proc;
|
|
5031
5029
|
try {
|
|
5032
|
-
proc =
|
|
5030
|
+
proc = spawn3(spawnSpec.command, spawnSpec.args, {
|
|
5033
5031
|
stdio: ["ignore", "ignore", "pipe"],
|
|
5034
5032
|
detached: false,
|
|
5035
5033
|
env: childEnv
|
|
@@ -5262,11 +5260,11 @@ async function cloneProfileForChild(opts) {
|
|
|
5262
5260
|
killInstance(dstKey);
|
|
5263
5261
|
await delay(500);
|
|
5264
5262
|
}
|
|
5265
|
-
if (!
|
|
5263
|
+
if (!existsSync11(srcDir)) {
|
|
5266
5264
|
return { copied: false, srcDir, dstDir, reason: "src-missing" };
|
|
5267
5265
|
}
|
|
5268
5266
|
try {
|
|
5269
|
-
if (
|
|
5267
|
+
if (existsSync11(dstDir)) {
|
|
5270
5268
|
rmSync(dstDir, { recursive: true, force: true });
|
|
5271
5269
|
}
|
|
5272
5270
|
mkdirSync10(dirname8(dstDir), { recursive: true });
|
|
@@ -5945,15 +5943,8 @@ RULES:
|
|
|
5945
5943
|
- Keep the entire summary under 1500 words.`, CHARS_PER_TEXT_TOKEN = 3.5, CHARS_PER_CJK_TOKEN = 0.9;
|
|
5946
5944
|
|
|
5947
5945
|
// ../../packages/core/src/storage/tasks.ts
|
|
5948
|
-
import { existsSync as
|
|
5949
|
-
import { dirname as dirname9, join as
|
|
5950
|
-
function safeUserIdComponent2(userId) {
|
|
5951
|
-
const str = String(userId);
|
|
5952
|
-
if (!str || /[/\\]|\.\./.test(str)) {
|
|
5953
|
-
throw new Error(`tasks: refusing unsafe userId path component: ${str}`);
|
|
5954
|
-
}
|
|
5955
|
-
return str;
|
|
5956
|
-
}
|
|
5946
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync11, readFileSync as readFileSync10, renameSync as renameSync5, statSync as statSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
5947
|
+
import { dirname as dirname9, join as join15 } from "path";
|
|
5957
5948
|
function safeTaskScopeKey(scopeKey) {
|
|
5958
5949
|
const safe = sanitizeFileName(scopeKey);
|
|
5959
5950
|
if (!safe || safe === "." || safe === "..") {
|
|
@@ -5965,14 +5956,14 @@ function taskScopeKey(opts) {
|
|
|
5965
5956
|
return opts.topicId?.trim() || opts.session || "default";
|
|
5966
5957
|
}
|
|
5967
5958
|
function getTaskFilePath(userId, scopeKey) {
|
|
5968
|
-
return
|
|
5959
|
+
return join15(resolveStorageDataDir(), "tasks", `${safeTaskScopeKey(scopeKey)}.json`);
|
|
5969
5960
|
}
|
|
5970
5961
|
function readTasks(userId, scopeKey) {
|
|
5971
5962
|
const path = getTaskFilePath(userId, scopeKey);
|
|
5972
|
-
if (!
|
|
5963
|
+
if (!existsSync12(path))
|
|
5973
5964
|
return [];
|
|
5974
5965
|
try {
|
|
5975
|
-
const parsed = JSON.parse(
|
|
5966
|
+
const parsed = JSON.parse(readFileSync10(path, "utf-8"));
|
|
5976
5967
|
return Array.isArray(parsed?.tasks) ? parsed.tasks : [];
|
|
5977
5968
|
} catch (e) {
|
|
5978
5969
|
logger.warn({ err: e, path }, "tasks: failed to read task store");
|
|
@@ -5985,7 +5976,7 @@ function writeTasks(userId, scopeKey, tasks) {
|
|
|
5985
5976
|
const payload = { version: 1, tasks };
|
|
5986
5977
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
5987
5978
|
writeFileSync8(tmp, JSON.stringify(payload, null, 2), "utf-8");
|
|
5988
|
-
|
|
5979
|
+
renameSync5(tmp, path);
|
|
5989
5980
|
}
|
|
5990
5981
|
function taskFileMtimeNs(userId, scopeKey) {
|
|
5991
5982
|
try {
|
|
@@ -6141,14 +6132,14 @@ function deepMapStrings2(value2, fn) {
|
|
|
6141
6132
|
}
|
|
6142
6133
|
|
|
6143
6134
|
// ../../packages/core/src/security/sensitive-path.ts
|
|
6144
|
-
import { realpathSync as
|
|
6135
|
+
import { realpathSync as realpathSync3 } from "fs";
|
|
6145
6136
|
import { resolve as resolve10 } from "path";
|
|
6146
6137
|
function isSensitivePath(filePath) {
|
|
6147
6138
|
const normalized = resolve10(filePath);
|
|
6148
6139
|
if (SENSITIVE_PATH_PATTERNS.some((p) => p.test(normalized)))
|
|
6149
6140
|
return true;
|
|
6150
6141
|
try {
|
|
6151
|
-
const real =
|
|
6142
|
+
const real = realpathSync3(normalized);
|
|
6152
6143
|
if (real !== normalized)
|
|
6153
6144
|
return SENSITIVE_PATH_PATTERNS.some((p) => p.test(real));
|
|
6154
6145
|
} catch {}
|
|
@@ -6331,7 +6322,7 @@ function deriveBgBashContextCapability(runtimeCapability, userId, topic) {
|
|
|
6331
6322
|
var init_context = () => {};
|
|
6332
6323
|
|
|
6333
6324
|
// ../../packages/core/src/platform/background-bash/manager.ts
|
|
6334
|
-
import { execFileSync as execFileSync4, spawn as
|
|
6325
|
+
import { execFileSync as execFileSync4, spawn as spawn4 } from "child_process";
|
|
6335
6326
|
import { randomBytes as randomBytes6 } from "crypto";
|
|
6336
6327
|
function makeBgBashKey(_userId, _topic) {
|
|
6337
6328
|
return "runtime";
|
|
@@ -6358,7 +6349,7 @@ function createBackgroundBashManager(options = {}) {
|
|
|
6358
6349
|
const now = options.now ?? Date.now;
|
|
6359
6350
|
const wait = options.delay ?? delay;
|
|
6360
6351
|
const portPids = options.portPids ?? defaultPortPids;
|
|
6361
|
-
const spawnImpl = options.spawn ?? ((command, args, spawnOptions) =>
|
|
6352
|
+
const spawnImpl = options.spawn ?? ((command, args, spawnOptions) => spawn4(command, [...args], spawnOptions));
|
|
6362
6353
|
function contextKey(userId, topic) {
|
|
6363
6354
|
return `${userId}\x00${topic}`;
|
|
6364
6355
|
}
|
|
@@ -6809,7 +6800,7 @@ function getMcpServersForQuery(opts) {
|
|
|
6809
6800
|
if (!opts.topicId)
|
|
6810
6801
|
throw new Error("getMcpServersForQuery: cron sessionType requires topicId");
|
|
6811
6802
|
return getCronMcpServers({
|
|
6812
|
-
userId: opts.userId || "
|
|
6803
|
+
userId: opts.userId || "local",
|
|
6813
6804
|
session: opts.session || "cron",
|
|
6814
6805
|
topicId: opts.topicId,
|
|
6815
6806
|
queryId: opts.queryId,
|
|
@@ -6826,7 +6817,7 @@ function getMcpServersForQuery(opts) {
|
|
|
6826
6817
|
}
|
|
6827
6818
|
if (opts.sessionType === "dm" || opts.sessionType === "ephemeral") {
|
|
6828
6819
|
return getDmMcpServers({
|
|
6829
|
-
userId: opts.userId || "
|
|
6820
|
+
userId: opts.userId || "local",
|
|
6830
6821
|
agent: opts.agent,
|
|
6831
6822
|
playwrightPort: opts.playwrightPort,
|
|
6832
6823
|
playwrightCapability: opts.playwrightCapability
|
|
@@ -6834,7 +6825,7 @@ function getMcpServersForQuery(opts) {
|
|
|
6834
6825
|
}
|
|
6835
6826
|
if (opts.sessionType === "manager") {
|
|
6836
6827
|
return getManagerMcpServers({
|
|
6837
|
-
userId: opts.userId || "
|
|
6828
|
+
userId: opts.userId || "local",
|
|
6838
6829
|
session: opts.session,
|
|
6839
6830
|
topicId: opts.topicId,
|
|
6840
6831
|
queryId: opts.queryId,
|
|
@@ -6851,7 +6842,7 @@ function getMcpServersForQuery(opts) {
|
|
|
6851
6842
|
});
|
|
6852
6843
|
}
|
|
6853
6844
|
return getForumMcpServers({
|
|
6854
|
-
userId: opts.userId || "
|
|
6845
|
+
userId: opts.userId || "local",
|
|
6855
6846
|
session: opts.session || "default",
|
|
6856
6847
|
topicId: opts.topicId,
|
|
6857
6848
|
subagentParentTopicId: opts.subagentParentTopicId,
|
|
@@ -7209,8 +7200,8 @@ __export(exports_claude_provider, {
|
|
|
7209
7200
|
claudeBuiltInTools: () => claudeBuiltInTools,
|
|
7210
7201
|
buildClaudeDisallowedTools: () => buildClaudeDisallowedTools
|
|
7211
7202
|
});
|
|
7212
|
-
import { spawn as
|
|
7213
|
-
import { existsSync as
|
|
7203
|
+
import { spawn as spawn5 } from "child_process";
|
|
7204
|
+
import { existsSync as existsSync13, readFileSync as readFileSync11 } from "fs";
|
|
7214
7205
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
7215
7206
|
function claudeBuiltInTools(opts) {
|
|
7216
7207
|
return opts.toolPolicy ? [] : undefined;
|
|
@@ -7263,7 +7254,7 @@ function buildClaudePrompt(opts) {
|
|
|
7263
7254
|
source: {
|
|
7264
7255
|
type: "base64",
|
|
7265
7256
|
media_type: attachment.mimeType,
|
|
7266
|
-
data:
|
|
7257
|
+
data: readFileSync11(attachment.path).toString("base64")
|
|
7267
7258
|
}
|
|
7268
7259
|
});
|
|
7269
7260
|
} catch (err) {
|
|
@@ -7286,7 +7277,7 @@ function buildClaudePrompt(opts) {
|
|
|
7286
7277
|
parent_tool_use_id: null
|
|
7287
7278
|
});
|
|
7288
7279
|
}
|
|
7289
|
-
function
|
|
7280
|
+
function signalProcessTree2(pid, signal) {
|
|
7290
7281
|
try {
|
|
7291
7282
|
process.kill(-pid, signal);
|
|
7292
7283
|
return true;
|
|
@@ -7301,7 +7292,7 @@ function signalProcessTree(pid, signal) {
|
|
|
7301
7292
|
}
|
|
7302
7293
|
}
|
|
7303
7294
|
function spawnClaudeCodeProcessWithTreeKill(options) {
|
|
7304
|
-
const child =
|
|
7295
|
+
const child = spawn5(options.command, options.args, {
|
|
7305
7296
|
cwd: options.cwd,
|
|
7306
7297
|
detached: true,
|
|
7307
7298
|
env: options.env,
|
|
@@ -7321,13 +7312,13 @@ function spawnClaudeCodeProcessWithTreeKill(options) {
|
|
|
7321
7312
|
const kill = (signal) => {
|
|
7322
7313
|
if (!child.pid)
|
|
7323
7314
|
return child.kill(signal);
|
|
7324
|
-
const ok =
|
|
7315
|
+
const ok = signalProcessTree2(child.pid, signal);
|
|
7325
7316
|
if (signal !== "SIGKILL") {
|
|
7326
7317
|
clearKillTimer();
|
|
7327
7318
|
killTimer = setTimeout(() => {
|
|
7328
7319
|
if (!exited && child.pid) {
|
|
7329
7320
|
logger.warn({ pid: child.pid }, "Claude process tree still alive after SIGTERM; SIGKILL");
|
|
7330
|
-
|
|
7321
|
+
signalProcessTree2(child.pid, "SIGKILL");
|
|
7331
7322
|
}
|
|
7332
7323
|
}, CLAUDE_ABORT_SIGKILL_DELAY_MS);
|
|
7333
7324
|
killTimer.unref?.();
|
|
@@ -7391,7 +7382,7 @@ function isAbortError(err) {
|
|
|
7391
7382
|
}
|
|
7392
7383
|
async function* claudeProvider(opts) {
|
|
7393
7384
|
const claudeExecutable = hostedClaudeCodeExecutablePath();
|
|
7394
|
-
if (claudeExecutable && !
|
|
7385
|
+
if (claudeExecutable && !existsSync13(claudeExecutable)) {
|
|
7395
7386
|
yield {
|
|
7396
7387
|
type: "error",
|
|
7397
7388
|
content: `Claude CLI not found at ${claudeExecutable}. Install Claude Code or configure the executable path.`
|
|
@@ -7686,34 +7677,34 @@ var init_claude_provider = __esm(async () => {
|
|
|
7686
7677
|
});
|
|
7687
7678
|
|
|
7688
7679
|
// ../../packages/core/src/version.ts
|
|
7689
|
-
var NEGOTIUM_VERSION = "0.
|
|
7680
|
+
var NEGOTIUM_VERSION = "0.2.0";
|
|
7690
7681
|
|
|
7691
7682
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
7692
|
-
import { spawn as
|
|
7683
|
+
import { spawn as spawn6 } from "child_process";
|
|
7693
7684
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
7694
7685
|
import {
|
|
7695
7686
|
chmodSync as chmodSync4,
|
|
7696
7687
|
copyFileSync,
|
|
7697
|
-
existsSync as
|
|
7688
|
+
existsSync as existsSync14,
|
|
7698
7689
|
mkdtempSync,
|
|
7699
|
-
readFileSync as
|
|
7700
|
-
renameSync as
|
|
7690
|
+
readFileSync as readFileSync12,
|
|
7691
|
+
renameSync as renameSync6,
|
|
7701
7692
|
rmSync as rmSync2,
|
|
7702
7693
|
unlinkSync as unlinkSync11,
|
|
7703
7694
|
writeFileSync as writeFileSync9
|
|
7704
7695
|
} from "fs";
|
|
7705
7696
|
import { createRequire as createRequire2 } from "module";
|
|
7706
7697
|
import { tmpdir as tmpdir2 } from "os";
|
|
7707
|
-
import { dirname as dirname10, join as
|
|
7698
|
+
import { dirname as dirname10, join as join16 } from "path";
|
|
7708
7699
|
function readPackageVersion(packageJsonPath) {
|
|
7709
|
-
const parsed = JSON.parse(
|
|
7700
|
+
const parsed = JSON.parse(readFileSync12(packageJsonPath, "utf8"));
|
|
7710
7701
|
if (typeof parsed.version !== "string" || !parsed.version.trim()) {
|
|
7711
7702
|
throw new Error(`Codex package has no valid version: ${packageJsonPath}`);
|
|
7712
7703
|
}
|
|
7713
7704
|
return parsed.version;
|
|
7714
7705
|
}
|
|
7715
7706
|
function codexCliScriptPath() {
|
|
7716
|
-
return
|
|
7707
|
+
return join16(dirname10(bundledCodexPackagePath), "bin", "codex.js");
|
|
7717
7708
|
}
|
|
7718
7709
|
function parseCodexModelCache(contents, sourcePath) {
|
|
7719
7710
|
let parsed;
|
|
@@ -7728,7 +7719,7 @@ function parseCodexModelCache(contents, sourcePath) {
|
|
|
7728
7719
|
return parsed;
|
|
7729
7720
|
}
|
|
7730
7721
|
function readCodexModelCache(cachePath) {
|
|
7731
|
-
const contents =
|
|
7722
|
+
const contents = readFileSync12(cachePath, "utf8");
|
|
7732
7723
|
return { contents, parsed: parseCodexModelCache(contents, cachePath) };
|
|
7733
7724
|
}
|
|
7734
7725
|
function readCompatibleCodexModelCache(cachePath) {
|
|
@@ -7740,12 +7731,12 @@ function readCompatibleCodexModelCache(cachePath) {
|
|
|
7740
7731
|
return cache;
|
|
7741
7732
|
}
|
|
7742
7733
|
function writePrivateFileAtomic(path, contents) {
|
|
7743
|
-
if (
|
|
7734
|
+
if (existsSync14(path) && readFileSync12(path, "utf8") === contents)
|
|
7744
7735
|
return;
|
|
7745
7736
|
const tempPath = `${path}.${process.pid}.${randomUUID8()}.tmp`;
|
|
7746
7737
|
try {
|
|
7747
7738
|
writeFileSync9(tempPath, contents, { encoding: "utf8", mode: 384 });
|
|
7748
|
-
|
|
7739
|
+
renameSync6(tempPath, path);
|
|
7749
7740
|
chmodSync4(path, 384);
|
|
7750
7741
|
} finally {
|
|
7751
7742
|
try {
|
|
@@ -7754,10 +7745,10 @@ function writePrivateFileAtomic(path, contents) {
|
|
|
7754
7745
|
}
|
|
7755
7746
|
}
|
|
7756
7747
|
function bundledCodexModelCachePath(authFilePath) {
|
|
7757
|
-
return
|
|
7748
|
+
return join16(dirname10(authFilePath), NEGOTIUM_MODEL_CACHE);
|
|
7758
7749
|
}
|
|
7759
7750
|
async function bootstrapCodexModelCache(codexHome, cachePath) {
|
|
7760
|
-
const child =
|
|
7751
|
+
const child = spawn6(process.execPath, [codexCliScriptPath(), "app-server", "--stdio"], {
|
|
7761
7752
|
env: { ...process.env, CODEX_HOME: codexHome },
|
|
7762
7753
|
stdio: ["pipe", "pipe", "pipe"]
|
|
7763
7754
|
});
|
|
@@ -7777,7 +7768,7 @@ async function bootstrapCodexModelCache(codexHome, cachePath) {
|
|
|
7777
7768
|
} catch {}
|
|
7778
7769
|
if (error)
|
|
7779
7770
|
reject(error);
|
|
7780
|
-
else if (!
|
|
7771
|
+
else if (!existsSync14(cachePath))
|
|
7781
7772
|
reject(new Error("Codex did not create its model cache"));
|
|
7782
7773
|
else
|
|
7783
7774
|
resolve11();
|
|
@@ -7840,15 +7831,15 @@ async function bootstrapCodexModelCache(codexHome, cachePath) {
|
|
|
7840
7831
|
}
|
|
7841
7832
|
async function bootstrapIsolatedCodexModelCache(authFilePath, bootstrap) {
|
|
7842
7833
|
const sourceHome = dirname10(authFilePath);
|
|
7843
|
-
const isolatedHome = mkdtempSync(
|
|
7844
|
-
const isolatedCachePath =
|
|
7834
|
+
const isolatedHome = mkdtempSync(join16(tmpdir2(), "negotium-codex-models-"));
|
|
7835
|
+
const isolatedCachePath = join16(isolatedHome, "models_cache.json");
|
|
7845
7836
|
try {
|
|
7846
|
-
const isolatedAuthPath =
|
|
7837
|
+
const isolatedAuthPath = join16(isolatedHome, "auth.json");
|
|
7847
7838
|
copyFileSync(authFilePath, isolatedAuthPath);
|
|
7848
7839
|
chmodSync4(isolatedAuthPath, 384);
|
|
7849
|
-
const sourceConfigPath =
|
|
7850
|
-
if (
|
|
7851
|
-
const isolatedConfigPath =
|
|
7840
|
+
const sourceConfigPath = join16(sourceHome, "config.toml");
|
|
7841
|
+
if (existsSync14(sourceConfigPath)) {
|
|
7842
|
+
const isolatedConfigPath = join16(isolatedHome, "config.toml");
|
|
7852
7843
|
copyFileSync(sourceConfigPath, isolatedConfigPath);
|
|
7853
7844
|
chmodSync4(isolatedConfigPath, 384);
|
|
7854
7845
|
}
|
|
@@ -7862,22 +7853,22 @@ async function ensureCodexModelCache(authFilePath, bootstrap = bootstrapCodexMod
|
|
|
7862
7853
|
const codexHome = dirname10(authFilePath);
|
|
7863
7854
|
const configuredCachePath = process.env.NEGOTIUM_CODEX_MODELS_CACHE_FILE;
|
|
7864
7855
|
if (configuredCachePath) {
|
|
7865
|
-
if (!
|
|
7856
|
+
if (!existsSync14(configuredCachePath)) {
|
|
7866
7857
|
throw new Error(`Configured Codex model cache does not exist: ${configuredCachePath}`);
|
|
7867
7858
|
}
|
|
7868
7859
|
readCompatibleCodexModelCache(configuredCachePath);
|
|
7869
7860
|
return configuredCachePath;
|
|
7870
7861
|
}
|
|
7871
7862
|
const bundledCachePath = bundledCodexModelCachePath(authFilePath);
|
|
7872
|
-
const sharedCachePath =
|
|
7873
|
-
if (
|
|
7863
|
+
const sharedCachePath = join16(codexHome, "models_cache.json");
|
|
7864
|
+
if (existsSync14(sharedCachePath)) {
|
|
7874
7865
|
try {
|
|
7875
7866
|
const shared = readCompatibleCodexModelCache(sharedCachePath);
|
|
7876
7867
|
writePrivateFileAtomic(bundledCachePath, shared.contents);
|
|
7877
7868
|
return bundledCachePath;
|
|
7878
7869
|
} catch {}
|
|
7879
7870
|
}
|
|
7880
|
-
if (
|
|
7871
|
+
if (existsSync14(bundledCachePath)) {
|
|
7881
7872
|
try {
|
|
7882
7873
|
readCompatibleCodexModelCache(bundledCachePath);
|
|
7883
7874
|
return bundledCachePath;
|
|
@@ -7889,7 +7880,7 @@ async function ensureCodexModelCache(authFilePath, bootstrap = bootstrapCodexMod
|
|
|
7889
7880
|
}
|
|
7890
7881
|
function writeCodexCatalogWithNativeMultiAgentDisabled(authFilePath, sourcePath) {
|
|
7891
7882
|
const codexHome = dirname10(authFilePath);
|
|
7892
|
-
const outputPath =
|
|
7883
|
+
const outputPath = join16(codexHome, NEGOTIUM_MODEL_CATALOG);
|
|
7893
7884
|
const parsed = readCodexModelCache(sourcePath).parsed;
|
|
7894
7885
|
const models = parsed.models.map((model, index) => {
|
|
7895
7886
|
if (!model || typeof model !== "object" || Array.isArray(model)) {
|
|
@@ -8136,7 +8127,7 @@ var init_codex_tree_kill = __esm(() => {
|
|
|
8136
8127
|
});
|
|
8137
8128
|
|
|
8138
8129
|
// ../../packages/core/src/agents/tool-format.ts
|
|
8139
|
-
import { readFileSync as
|
|
8130
|
+
import { readFileSync as readFileSync13, statSync as statSync5 } from "fs";
|
|
8140
8131
|
import { isAbsolute as isAbsolute2, resolve as resolve11 } from "path";
|
|
8141
8132
|
import { diffLines as computeLineDiff } from "diff";
|
|
8142
8133
|
function summarizeDisplayText(value2) {
|
|
@@ -8465,7 +8456,7 @@ function sourceStartLine(input, before, after, cwd) {
|
|
|
8465
8456
|
try {
|
|
8466
8457
|
if (statSync5(path).size > TOOL_DIFF_SOURCE_MAX_BYTES)
|
|
8467
8458
|
return 1;
|
|
8468
|
-
const source =
|
|
8459
|
+
const source = readFileSync13(path, "utf8").replace(/\r\n?/g, `
|
|
8469
8460
|
`);
|
|
8470
8461
|
for (const candidate of [before, after].filter(Boolean)) {
|
|
8471
8462
|
const index = source.indexOf(candidate);
|
|
@@ -8658,8 +8649,8 @@ __export(exports_codex_provider, {
|
|
|
8658
8649
|
codexProvider: () => codexProvider
|
|
8659
8650
|
});
|
|
8660
8651
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
8661
|
-
import { existsSync as
|
|
8662
|
-
import { dirname as dirname11, isAbsolute as isAbsolute3, join as
|
|
8652
|
+
import { existsSync as existsSync15, readFileSync as readFileSync14, realpathSync as realpathSync4, statSync as statSync6 } from "fs";
|
|
8653
|
+
import { dirname as dirname11, isAbsolute as isAbsolute3, join as join17, relative, resolve as resolve12 } from "path";
|
|
8663
8654
|
import { Codex } from "@openai/codex-sdk";
|
|
8664
8655
|
function mapEffort(effort) {
|
|
8665
8656
|
if (!effort)
|
|
@@ -8673,12 +8664,12 @@ function codexMcpServerName(name) {
|
|
|
8673
8664
|
return CODEX_MCP_SERVER_NAME_OVERRIDES[name] ?? name;
|
|
8674
8665
|
}
|
|
8675
8666
|
function globalCodexMcpServerNames(authFilePath) {
|
|
8676
|
-
const configPath =
|
|
8677
|
-
if (!
|
|
8667
|
+
const configPath = join17(dirname11(authFilePath), "config.toml");
|
|
8668
|
+
if (!existsSync15(configPath))
|
|
8678
8669
|
return [];
|
|
8679
8670
|
try {
|
|
8680
8671
|
const names = new Set;
|
|
8681
|
-
for (const line of
|
|
8672
|
+
for (const line of readFileSync14(configPath, "utf8").split(`
|
|
8682
8673
|
`)) {
|
|
8683
8674
|
const match = line.match(/^\s*\[\s*mcp_servers\.((?:"(?:\\.|[^"])*")|(?:'[^']*')|[^.\]\s]+)(?:[.\]])/);
|
|
8684
8675
|
const raw = match?.[1];
|
|
@@ -8769,19 +8760,19 @@ function summarizeMcpToolCallResult(item) {
|
|
|
8769
8760
|
}
|
|
8770
8761
|
function canonicalPath(path) {
|
|
8771
8762
|
try {
|
|
8772
|
-
return
|
|
8763
|
+
return realpathSync4(resolve12(path));
|
|
8773
8764
|
} catch {
|
|
8774
8765
|
return resolve12(path);
|
|
8775
8766
|
}
|
|
8776
8767
|
}
|
|
8777
8768
|
function textFile(path, maxBytes = CODEX_DIFF_FILE_LIMIT) {
|
|
8778
|
-
if (!
|
|
8769
|
+
if (!existsSync15(path))
|
|
8779
8770
|
return null;
|
|
8780
8771
|
try {
|
|
8781
8772
|
const byteLimit = Math.min(CODEX_DIFF_FILE_LIMIT, Math.max(0, maxBytes));
|
|
8782
8773
|
if (statSync6(path).size > byteLimit)
|
|
8783
8774
|
return;
|
|
8784
|
-
const content =
|
|
8775
|
+
const content = readFileSync14(path);
|
|
8785
8776
|
if (content.byteLength > byteLimit || content.includes(0))
|
|
8786
8777
|
return;
|
|
8787
8778
|
return content.toString("utf8");
|
|
@@ -8987,7 +8978,7 @@ async function* codexProvider(opts) {
|
|
|
8987
8978
|
const filePreviews = new CodexFilePreviewTracker(opts.cwd);
|
|
8988
8979
|
const consumedPatchCallIds = new Set(opts.sessionId ? readCodexPatchCallIds(opts.sessionId) : []);
|
|
8989
8980
|
const codexAuthPath = hostedCodexAuthFilePath();
|
|
8990
|
-
if (!
|
|
8981
|
+
if (!existsSync15(codexAuthPath)) {
|
|
8991
8982
|
yield {
|
|
8992
8983
|
type: "error",
|
|
8993
8984
|
content: `Codex auth file not found at ${codexAuthPath}. Run \`codex login\` to authenticate.`
|
|
@@ -9026,7 +9017,7 @@ async function* codexProvider(opts) {
|
|
|
9026
9017
|
model: opts.model ?? "(sdk default)",
|
|
9027
9018
|
effort: opts.effort ?? "(off)",
|
|
9028
9019
|
cwd: opts.cwd,
|
|
9029
|
-
cwdExists:
|
|
9020
|
+
cwdExists: existsSync15(opts.cwd),
|
|
9030
9021
|
resume: Boolean(opts.sessionId),
|
|
9031
9022
|
mcpServerCount: Object.keys(codexMcpServers).length
|
|
9032
9023
|
}, "codexProvider: starting turn");
|
|
@@ -9467,9 +9458,9 @@ var init_maestro_provider = __esm(async () => {
|
|
|
9467
9458
|
});
|
|
9468
9459
|
|
|
9469
9460
|
// ../../packages/core/src/agents/index.ts
|
|
9470
|
-
import { existsSync as
|
|
9461
|
+
import { existsSync as existsSync16 } from "fs";
|
|
9471
9462
|
import { homedir as homedir8 } from "os";
|
|
9472
|
-
import { join as
|
|
9463
|
+
import { join as join18 } from "path";
|
|
9473
9464
|
async function* dispatchAgent(opts) {
|
|
9474
9465
|
switch (opts.agent) {
|
|
9475
9466
|
case "claude": {
|
|
@@ -9503,11 +9494,11 @@ async function resolveSessionFileMissing(agent, sessionId, cwd) {
|
|
|
9503
9494
|
switch (agent) {
|
|
9504
9495
|
case "claude": {
|
|
9505
9496
|
const encodedCwd = encodeClaudeCwd(cwd);
|
|
9506
|
-
const path =
|
|
9507
|
-
return !
|
|
9497
|
+
const path = join18(homedir8(), ".claude", "projects", encodedCwd, `${sessionId}.jsonl`);
|
|
9498
|
+
return !existsSync16(path);
|
|
9508
9499
|
}
|
|
9509
9500
|
case "codex": {
|
|
9510
|
-
const sessionsDir =
|
|
9501
|
+
const sessionsDir = join18(process.env.CODEX_HOME || join18(homedir8(), ".codex"), "sessions");
|
|
9511
9502
|
const glob = new Bun.Glob(`**/rollout-*-${sessionId}.jsonl`);
|
|
9512
9503
|
for await (const _rel of glob.scan({ cwd: sessionsDir, onlyFiles: true })) {
|
|
9513
9504
|
return false;
|
|
@@ -9516,7 +9507,7 @@ async function resolveSessionFileMissing(agent, sessionId, cwd) {
|
|
|
9516
9507
|
}
|
|
9517
9508
|
case "maestro": {
|
|
9518
9509
|
const { hasActiveMaestroSession, maestroSessionPath: maestroSessionPath2 } = await import("maestro-agent-sdk");
|
|
9519
|
-
return !
|
|
9510
|
+
return !existsSync16(maestroSessionPath2(sessionId)) && !hasActiveMaestroSession(sessionId);
|
|
9520
9511
|
}
|
|
9521
9512
|
default: {
|
|
9522
9513
|
const _exhaustive = agent;
|
|
@@ -9582,10 +9573,10 @@ var init_agents = __esm(async () => {
|
|
|
9582
9573
|
});
|
|
9583
9574
|
|
|
9584
9575
|
// ../../packages/core/src/prompts/builders.ts
|
|
9585
|
-
import { readFileSync as
|
|
9576
|
+
import { readFileSync as readFileSync15 } from "fs";
|
|
9586
9577
|
import { resolve as resolve14 } from "path";
|
|
9587
9578
|
function loadPrompt(filename, dir = SESSIONS_DIR) {
|
|
9588
|
-
const raw =
|
|
9579
|
+
const raw = readFileSync15(resolve14(dir, filename), "utf-8");
|
|
9589
9580
|
return raw.replace(/\{\{RESOURCES_DIR\}\}/g, RESOURCES_DIR);
|
|
9590
9581
|
}
|
|
9591
9582
|
function replaceVars(template, vars) {
|
|
@@ -9634,7 +9625,7 @@ function visualDesignGuide() {
|
|
|
9634
9625
|
return _visualDesignGuide;
|
|
9635
9626
|
}
|
|
9636
9627
|
function loadAgentPrompt(filename) {
|
|
9637
|
-
const raw =
|
|
9628
|
+
const raw = readFileSync15(resolve14(AGENTS_PROMPTS_DIR, filename), "utf-8");
|
|
9638
9629
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
9639
9630
|
if (!match)
|
|
9640
9631
|
throw new Error(`Agent prompt ${filename} is missing frontmatter`);
|
|
@@ -10023,9 +10014,9 @@ var init_api_topic_brief = __esm(async () => {
|
|
|
10023
10014
|
});
|
|
10024
10015
|
|
|
10025
10016
|
// ../../packages/core/src/storage/wiki.ts
|
|
10026
|
-
import { basename as basename3, dirname as dirname12, join as
|
|
10017
|
+
import { basename as basename3, dirname as dirname12, join as join19 } from "path";
|
|
10027
10018
|
function getSharedWikiDir(workspaceDir = resolveStorageWorkspaceDir()) {
|
|
10028
|
-
return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() :
|
|
10019
|
+
return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() : join19(workspaceDir, "wiki");
|
|
10029
10020
|
}
|
|
10030
10021
|
var init_wiki = __esm(async () => {
|
|
10031
10022
|
await init_storage_host();
|
|
@@ -10033,8 +10024,8 @@ var init_wiki = __esm(async () => {
|
|
|
10033
10024
|
|
|
10034
10025
|
// ../../packages/core/src/agents/archiver.ts
|
|
10035
10026
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
10036
|
-
import { existsSync as
|
|
10037
|
-
import { join as
|
|
10027
|
+
import { existsSync as existsSync17, readdirSync as readdirSync5, readFileSync as readFileSync16, statSync as statSync7 } from "fs";
|
|
10028
|
+
import { join as join20 } from "path";
|
|
10038
10029
|
function resolveMemoryLanguage() {
|
|
10039
10030
|
const override = process.env.NEGOTIUM_MEMORY_LANG?.trim();
|
|
10040
10031
|
return override && override.length > 0 ? override : resolveOutputLanguage();
|
|
@@ -10285,10 +10276,10 @@ function distillOneLine(summaryMd) {
|
|
|
10285
10276
|
return "";
|
|
10286
10277
|
}
|
|
10287
10278
|
function findSummaryFile(storage, topicTitle, date, sinceMs, topicId) {
|
|
10288
|
-
const dir =
|
|
10279
|
+
const dir = join20(storage.getWikiDir(), "summaries");
|
|
10289
10280
|
if (!storage.fileExists(dir))
|
|
10290
10281
|
return null;
|
|
10291
|
-
const predicted =
|
|
10282
|
+
const predicted = join20(dir, wikiSummaryFilename(date, topicTitle, topicId));
|
|
10292
10283
|
if (storage.fileExists(predicted) && storage.fileModifiedAt(predicted) >= sinceMs)
|
|
10293
10284
|
return predicted;
|
|
10294
10285
|
let best = null;
|
|
@@ -10296,7 +10287,7 @@ function findSummaryFile(storage, topicTitle, date, sinceMs, topicId) {
|
|
|
10296
10287
|
if (!f.startsWith(`${date}-`) || !isTopicSummaryFile(f, topicId ?? "", topicTitle)) {
|
|
10297
10288
|
continue;
|
|
10298
10289
|
}
|
|
10299
|
-
const p =
|
|
10290
|
+
const p = join20(dir, f);
|
|
10300
10291
|
try {
|
|
10301
10292
|
const m = storage.fileModifiedAt(p);
|
|
10302
10293
|
if (m >= sinceMs && (!best || m > best.mtime))
|
|
@@ -10378,9 +10369,9 @@ var init_archiver = __esm(async () => {
|
|
|
10378
10369
|
defaultArchiverRuntime = createArchiverRuntime({
|
|
10379
10370
|
storage: {
|
|
10380
10371
|
getWikiDir: getSharedWikiDir,
|
|
10381
|
-
fileExists:
|
|
10382
|
-
listDirectory:
|
|
10383
|
-
readTextFile: (path) =>
|
|
10372
|
+
fileExists: existsSync17,
|
|
10373
|
+
listDirectory: readdirSync5,
|
|
10374
|
+
readTextFile: (path) => readFileSync16(path, "utf-8"),
|
|
10384
10375
|
fileSize: (path) => statSync7(path).size,
|
|
10385
10376
|
fileModifiedAt: (path) => statSync7(path).mtimeMs,
|
|
10386
10377
|
getGeneralTopicId: (userId) => ensurePersonalGeneral(userId).id,
|
|
@@ -10494,13 +10485,13 @@ function formatTopicArchiveTranscriptRecord(row, topicTitle, index) {
|
|
|
10494
10485
|
|
|
10495
10486
|
// ../../packages/core/src/storage/topic-archive.ts
|
|
10496
10487
|
import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
10497
|
-
import { join as
|
|
10488
|
+
import { join as join21 } from "path";
|
|
10498
10489
|
function archiveTopicMessages(topicId, topicTitle, options = {}) {
|
|
10499
10490
|
const rows = options.afterRowid !== undefined ? getMessagesForTopicAfterRowid(topicId, options.afterRowid) : getAllMessagesForTopic(topicId);
|
|
10500
10491
|
if (rows.length === 0)
|
|
10501
10492
|
return null;
|
|
10502
10493
|
const safeTopic = sanitizeTopicName(topicTitle, true);
|
|
10503
|
-
const archiveDir =
|
|
10494
|
+
const archiveDir = join21(getSharedWikiDir(), "archive");
|
|
10504
10495
|
mkdirSync12(archiveDir, { recursive: true });
|
|
10505
10496
|
const date = new Date().toISOString().slice(0, 10);
|
|
10506
10497
|
const reasonSuffix = options.reason && options.reason !== "delete" ? `_${options.reason}` : "";
|
|
@@ -10513,7 +10504,7 @@ function archiveTopicMessages(topicId, topicTitle, options = {}) {
|
|
|
10513
10504
|
let path;
|
|
10514
10505
|
while (true) {
|
|
10515
10506
|
filename = `${safeTopic}_${date}${reasonSuffix}${counter === 1 ? "" : `_${counter}`}.jsonl`;
|
|
10516
|
-
path =
|
|
10507
|
+
path = join21(archiveDir, filename);
|
|
10517
10508
|
try {
|
|
10518
10509
|
writeFileSync10(path, body, { flag: "wx" });
|
|
10519
10510
|
break;
|
|
@@ -10558,7 +10549,7 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
|
|
|
10558
10549
|
const entries = readRawConversation(userId, topicTitle);
|
|
10559
10550
|
if (entries.length === 0)
|
|
10560
10551
|
return null;
|
|
10561
|
-
const archiveDir =
|
|
10552
|
+
const archiveDir = join21(getSharedWikiDir(), "archive");
|
|
10562
10553
|
mkdirSync12(archiveDir, { recursive: true });
|
|
10563
10554
|
const safeTopic = sanitizeTopicName(topicTitle, true);
|
|
10564
10555
|
const date = new Date().toISOString().slice(0, 10);
|
|
@@ -10586,7 +10577,7 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
|
|
|
10586
10577
|
let counter = 1;
|
|
10587
10578
|
while (true) {
|
|
10588
10579
|
const suffix = counter === 1 ? "" : `_${counter}`;
|
|
10589
|
-
const path =
|
|
10580
|
+
const path = join21(archiveDir, `${safeTopic}_${date}${reasonSuffix}_events${suffix}.jsonl`);
|
|
10590
10581
|
try {
|
|
10591
10582
|
writeFileSync10(path, body, { flag: "wx" });
|
|
10592
10583
|
logger.info({ topicId, topicTitle, archive: path, eventCount: entries.length }, "archiveConversationEvents: archived raw conversation events");
|
|
@@ -10909,7 +10900,7 @@ var init_idle_archiver = __esm(async () => {
|
|
|
10909
10900
|
});
|
|
10910
10901
|
|
|
10911
10902
|
// ../../packages/core/src/agents/topic-cleanup.ts
|
|
10912
|
-
import { mkdirSync as mkdirSync13, renameSync as
|
|
10903
|
+
import { mkdirSync as mkdirSync13, renameSync as renameSync7, unlinkSync as unlinkSync12, writeFileSync as writeFileSync11 } from "fs";
|
|
10913
10904
|
import { dirname as dirname13 } from "path";
|
|
10914
10905
|
function collectSessionIdsByAgent(entries, extraSessions = []) {
|
|
10915
10906
|
const out = new Map;
|
|
@@ -10980,7 +10971,7 @@ function createTopicLogMaintenance(host) {
|
|
|
10980
10971
|
writeFileSync11(tempPath, retained.length > 0 ? `${retained.map((entry) => JSON.stringify(entry)).join(`
|
|
10981
10972
|
`)}
|
|
10982
10973
|
` : "", { flag: "wx" });
|
|
10983
|
-
|
|
10974
|
+
renameSync7(tempPath, path);
|
|
10984
10975
|
} catch (e) {
|
|
10985
10976
|
try {
|
|
10986
10977
|
unlinkSync12(tempPath);
|
|
@@ -11143,7 +11134,7 @@ var init_usage_alert = __esm(() => {
|
|
|
11143
11134
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
11144
11135
|
import { mkdtempSync as mkdtempSync2, rmSync as rmSync4, writeFileSync as writeFileSync12 } from "fs";
|
|
11145
11136
|
import { tmpdir as tmpdir3 } from "os";
|
|
11146
|
-
import { join as
|
|
11137
|
+
import { join as join22 } from "path";
|
|
11147
11138
|
function previousCompactedSummary(entries) {
|
|
11148
11139
|
for (let index = entries.length - 2;index >= 0; index -= 1) {
|
|
11149
11140
|
const request = entries[index]?.event;
|
|
@@ -11273,7 +11264,7 @@ function formatCompactElapsed(startedAt) {
|
|
|
11273
11264
|
async function summarizeTopicContext(request) {
|
|
11274
11265
|
const startedAt = Date.now();
|
|
11275
11266
|
const sessionIds = [];
|
|
11276
|
-
const compactCwd = mkdtempSync2(
|
|
11267
|
+
const compactCwd = mkdtempSync2(join22(tmpdir3(), "negotium-compact-"));
|
|
11277
11268
|
const abortController = new AbortController;
|
|
11278
11269
|
const relayAbort = () => abortController.abort(request.signal?.reason);
|
|
11279
11270
|
if (request.signal?.aborted)
|
|
@@ -11300,7 +11291,7 @@ async function summarizeTopicContext(request) {
|
|
|
11300
11291
|
let error = "";
|
|
11301
11292
|
let toolViolation = false;
|
|
11302
11293
|
let compactionLogCalls = 0;
|
|
11303
|
-
const compactionLogPath =
|
|
11294
|
+
const compactionLogPath = join22(compactCwd, "conversation.log");
|
|
11304
11295
|
try {
|
|
11305
11296
|
const compactionMcp = useCompactionLog ? {
|
|
11306
11297
|
compact_log: {
|
|
@@ -11896,14 +11887,14 @@ var init_derive = __esm(async () => {
|
|
|
11896
11887
|
});
|
|
11897
11888
|
|
|
11898
11889
|
// ../../packages/core/src/query/session-inbox-path.ts
|
|
11899
|
-
import { join as
|
|
11890
|
+
import { join as join23 } from "path";
|
|
11900
11891
|
function sessionInboxPath(userId, topicId) {
|
|
11901
11892
|
const key = Buffer.from(topicId, "utf8").toString("base64url");
|
|
11902
|
-
return
|
|
11893
|
+
return join23(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${JSONL_SUFFIX}`);
|
|
11903
11894
|
}
|
|
11904
11895
|
function scheduledSessionInboxPath(userId, topicId) {
|
|
11905
11896
|
const key = Buffer.from(topicId, "utf8").toString("base64url");
|
|
11906
|
-
return
|
|
11897
|
+
return join23(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${SCHEDULE_SUFFIX}`);
|
|
11907
11898
|
}
|
|
11908
11899
|
var TOPIC_ID_FILE_PREFIX = "topic-id-", JSONL_SUFFIX = ".jsonl", SCHEDULE_SUFFIX = ".schedule";
|
|
11909
11900
|
var init_session_inbox_path = __esm(() => {
|
|
@@ -11912,13 +11903,13 @@ var init_session_inbox_path = __esm(() => {
|
|
|
11912
11903
|
|
|
11913
11904
|
// ../../packages/core/src/query/session-inbox-cleanup.ts
|
|
11914
11905
|
import { unlinkSync as unlinkSync14 } from "fs";
|
|
11915
|
-
import { basename as basename4, join as
|
|
11906
|
+
import { basename as basename4, join as join24 } from "path";
|
|
11916
11907
|
function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
|
|
11917
11908
|
const live = sessionInboxPath(userId, topicId);
|
|
11918
11909
|
const scheduled = scheduledSessionInboxPath(userId, topicId);
|
|
11919
11910
|
const candidates = new Set([live, `${live}.processing`, scheduled, `${scheduled}.processing`]);
|
|
11920
11911
|
if (legacyTopicTitle && legacyTopicTitle !== "." && legacyTopicTitle !== ".." && basename4(legacyTopicTitle) === legacyTopicTitle) {
|
|
11921
|
-
const legacyBase =
|
|
11912
|
+
const legacyBase = join24(SESSION_INBOX_DIR, userId, legacyTopicTitle);
|
|
11922
11913
|
for (const suffix of [".jsonl", ".jsonl.processing", ".schedule", ".schedule.processing"]) {
|
|
11923
11914
|
candidates.add(`${legacyBase}${suffix}`);
|
|
11924
11915
|
}
|
|
@@ -11943,17 +11934,17 @@ var init_session_inbox_cleanup = __esm(() => {
|
|
|
11943
11934
|
});
|
|
11944
11935
|
|
|
11945
11936
|
// ../../packages/core/src/query/state.ts
|
|
11946
|
-
import { mkdirSync as mkdirSync15, renameSync as
|
|
11947
|
-
import { basename as basename5, join as
|
|
11937
|
+
import { mkdirSync as mkdirSync15, renameSync as renameSync8, unlinkSync as unlinkSync15, writeFileSync as writeFileSync13 } from "fs";
|
|
11938
|
+
import { basename as basename5, join as join25 } from "path";
|
|
11948
11939
|
function createQueryStateStore(options) {
|
|
11949
11940
|
const sanitize = options.sanitizeTopicId ?? sanitizeId;
|
|
11950
|
-
const queryStateDirPath = (userId) =>
|
|
11951
|
-
const queryStateFile = (userId, topicId) =>
|
|
11941
|
+
const queryStateDirPath = (userId) => join25(options.usersLogDir, String(userId), "active-queries");
|
|
11942
|
+
const queryStateFile = (userId, topicId) => join25(queryStateDirPath(userId), `${sanitize(topicId)}.json`);
|
|
11952
11943
|
const legacyQueryStateFile = (userId, topicName) => {
|
|
11953
11944
|
if (!topicName || topicName === "." || topicName === ".." || basename5(topicName) !== topicName) {
|
|
11954
11945
|
return null;
|
|
11955
11946
|
}
|
|
11956
|
-
return
|
|
11947
|
+
return join25(queryStateDirPath(userId), `${topicName}.json`);
|
|
11957
11948
|
};
|
|
11958
11949
|
return {
|
|
11959
11950
|
write(userId, topicId, topicName, task) {
|
|
@@ -11965,7 +11956,7 @@ function createQueryStateStore(options) {
|
|
|
11965
11956
|
const target = queryStateFile(userId, topicId);
|
|
11966
11957
|
const tmp = `${target}.${process.pid}.${Date.now()}.tmp`;
|
|
11967
11958
|
writeFileSync13(tmp, JSON.stringify(state));
|
|
11968
|
-
|
|
11959
|
+
renameSync8(tmp, target);
|
|
11969
11960
|
},
|
|
11970
11961
|
clear(userId, topicId, legacyTopicName) {
|
|
11971
11962
|
const paths = [
|
|
@@ -12107,35 +12098,35 @@ import {
|
|
|
12107
12098
|
closeSync as closeSync3,
|
|
12108
12099
|
mkdirSync as mkdirSync16,
|
|
12109
12100
|
openSync as openSync3,
|
|
12110
|
-
readdirSync as
|
|
12111
|
-
readFileSync as
|
|
12101
|
+
readdirSync as readdirSync6,
|
|
12102
|
+
readFileSync as readFileSync17,
|
|
12112
12103
|
statSync as statSync8,
|
|
12113
12104
|
unlinkSync as unlinkSync16,
|
|
12114
12105
|
writeFileSync as writeFileSync14
|
|
12115
12106
|
} from "fs";
|
|
12116
|
-
import { dirname as dirname14, join as
|
|
12107
|
+
import { dirname as dirname14, join as join26 } from "path";
|
|
12117
12108
|
function pendingAskDir(userId) {
|
|
12118
12109
|
const rawUserId = String(userId);
|
|
12119
12110
|
const safeUserId = /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash4("sha256").update(rawUserId).digest("hex")}`;
|
|
12120
|
-
return
|
|
12111
|
+
return join26(resolveStorageSessionAsksDir(), safeUserId);
|
|
12121
12112
|
}
|
|
12122
12113
|
function encodeAskKey(key) {
|
|
12123
12114
|
return JSON.stringify([key.from, key.to]);
|
|
12124
12115
|
}
|
|
12125
12116
|
function pendingAskPath(key) {
|
|
12126
12117
|
const digest = createHash4("sha256").update(encodeAskKey(key)).digest("hex");
|
|
12127
|
-
return
|
|
12118
|
+
return join26(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
|
|
12128
12119
|
}
|
|
12129
12120
|
function v2PendingAskPath(key) {
|
|
12130
12121
|
const encoded = Buffer.from(encodeAskKey(key), "utf8").toString("base64url");
|
|
12131
|
-
return
|
|
12122
|
+
return join26(pendingAskDir(key.userId), `${V2_ASK_FILENAME_PREFIX}${encoded}.pending`);
|
|
12132
12123
|
}
|
|
12133
12124
|
function legacyPendingAskPath(key) {
|
|
12134
12125
|
if (key.from.includes("/") || key.from.includes("\\") || key.to.includes("/") || key.to.includes("\\") || key.from.includes("\x00") || key.to.includes("\x00")) {
|
|
12135
12126
|
return null;
|
|
12136
12127
|
}
|
|
12137
12128
|
const dir = pendingAskDir(key.userId);
|
|
12138
|
-
const candidate =
|
|
12129
|
+
const candidate = join26(dir, `${key.from}___${key.to}.pending`);
|
|
12139
12130
|
return dirname14(candidate) === dir ? candidate : null;
|
|
12140
12131
|
}
|
|
12141
12132
|
function parsePendingAskFilename(fileName) {
|
|
@@ -12157,7 +12148,7 @@ function parsePendingAskFilename(fileName) {
|
|
|
12157
12148
|
}
|
|
12158
12149
|
function readPendingAskFile(path, fallback) {
|
|
12159
12150
|
try {
|
|
12160
|
-
const raw =
|
|
12151
|
+
const raw = readFileSync17(path, "utf8").trim();
|
|
12161
12152
|
if (!raw)
|
|
12162
12153
|
return null;
|
|
12163
12154
|
if (!raw.startsWith("{")) {
|
|
@@ -12366,7 +12357,7 @@ function listPendingAsksForCaller(args) {
|
|
|
12366
12357
|
const dir = pendingAskDir(args.userId);
|
|
12367
12358
|
let files;
|
|
12368
12359
|
try {
|
|
12369
|
-
files =
|
|
12360
|
+
files = readdirSync6(dir);
|
|
12370
12361
|
} catch {
|
|
12371
12362
|
return [];
|
|
12372
12363
|
}
|
|
@@ -12376,7 +12367,7 @@ function listPendingAsksForCaller(args) {
|
|
|
12376
12367
|
const parsed = isV3 ? { from: args.from, to: "" } : parsePendingAskFilename(fileName);
|
|
12377
12368
|
if (!parsed)
|
|
12378
12369
|
continue;
|
|
12379
|
-
const path =
|
|
12370
|
+
const path = join26(dir, fileName);
|
|
12380
12371
|
const record = readPendingAskFile(path, {
|
|
12381
12372
|
userId: args.userId,
|
|
12382
12373
|
from: parsed.from,
|
|
@@ -12412,13 +12403,13 @@ function deletePendingAsksForTopic(args) {
|
|
|
12412
12403
|
const dir = pendingAskDir(args.userId);
|
|
12413
12404
|
let files;
|
|
12414
12405
|
try {
|
|
12415
|
-
files =
|
|
12406
|
+
files = readdirSync6(dir);
|
|
12416
12407
|
} catch {
|
|
12417
12408
|
return 0;
|
|
12418
12409
|
}
|
|
12419
12410
|
let deleted = 0;
|
|
12420
12411
|
for (const fileName of files) {
|
|
12421
|
-
const path =
|
|
12412
|
+
const path = join26(dir, fileName);
|
|
12422
12413
|
const parsed = parsePendingAskFilename(fileName);
|
|
12423
12414
|
const record = readPendingAskFile(path, {
|
|
12424
12415
|
userId: args.userId,
|
|
@@ -13087,7 +13078,7 @@ var init_lifecycle = __esm(async () => {
|
|
|
13087
13078
|
// ../../packages/core/src/runtime/attachments.ts
|
|
13088
13079
|
import { randomUUID as randomUUID13 } from "crypto";
|
|
13089
13080
|
import { copyFileSync as copyFileSync2, mkdirSync as mkdirSync17, writeFileSync as writeFileSync15 } from "fs";
|
|
13090
|
-
import { basename as basename6, join as
|
|
13081
|
+
import { basename as basename6, join as join27 } from "path";
|
|
13091
13082
|
function workspaceCwdFor(topicId) {
|
|
13092
13083
|
return resolveTopicWorkspaceDir(topicId);
|
|
13093
13084
|
}
|
|
@@ -13100,7 +13091,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
|
|
|
13100
13091
|
if (!attachmentIds?.length)
|
|
13101
13092
|
return [];
|
|
13102
13093
|
const out = [];
|
|
13103
|
-
const destDir =
|
|
13094
|
+
const destDir = join27(workspaceCwdFor(topicId), "attachments", queryId);
|
|
13104
13095
|
for (const rawId of attachmentIds) {
|
|
13105
13096
|
if (typeof rawId !== "string")
|
|
13106
13097
|
continue;
|
|
@@ -13117,7 +13108,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
|
|
|
13117
13108
|
mkdirSync17(destDir, { recursive: true });
|
|
13118
13109
|
const index = String(out.length + 1).padStart(2, "0");
|
|
13119
13110
|
const safeName = safeAttachmentFilename(attachment.filename, fileId);
|
|
13120
|
-
const destPath =
|
|
13111
|
+
const destPath = join27(destDir, `${index}-${fileId.slice(0, 8)}-${safeName}`);
|
|
13121
13112
|
copyFileSync2(sourcePath, destPath);
|
|
13122
13113
|
out.push({
|
|
13123
13114
|
id: attachment.id,
|
|
@@ -13147,10 +13138,10 @@ function promptWithAttachments(prompt, attachments) {
|
|
|
13147
13138
|
return composeAttachmentPrompt(prompt, attachments.map(({ filename, path }) => attachmentPromptLine(filename, path)));
|
|
13148
13139
|
}
|
|
13149
13140
|
function ingestAttachment(args) {
|
|
13150
|
-
const destDir =
|
|
13141
|
+
const destDir = join27(UPLOADS_DIR, args.topicId);
|
|
13151
13142
|
mkdirSync17(destDir, { recursive: true });
|
|
13152
13143
|
const safeName = safeAttachmentFilename(args.filename, "upload");
|
|
13153
|
-
const destPath =
|
|
13144
|
+
const destPath = join27(destDir, `${Date.now()}-${randomUUID13().slice(0, 8)}-${safeName}`);
|
|
13154
13145
|
if (args.sourcePath !== undefined) {
|
|
13155
13146
|
copyFileSync2(args.sourcePath, destPath);
|
|
13156
13147
|
} else if (args.bytes !== undefined) {
|
|
@@ -14136,7 +14127,7 @@ var init_visual_html = __esm(() => {
|
|
|
14136
14127
|
});
|
|
14137
14128
|
|
|
14138
14129
|
// ../../packages/core/src/runtime/visuals.ts
|
|
14139
|
-
import { realpathSync as
|
|
14130
|
+
import { realpathSync as realpathSync5 } from "fs";
|
|
14140
14131
|
import { isAbsolute as isAbsolute4, resolve as resolve15 } from "path";
|
|
14141
14132
|
function activeVisualHtmlForPrompt(html) {
|
|
14142
14133
|
if (html.length <= ACTIVE_VISUAL_PROMPT_MAX_CHARS) {
|
|
@@ -14191,8 +14182,8 @@ function isPathInside(baseDir, filePath) {
|
|
|
14191
14182
|
const base = resolve15(baseDir);
|
|
14192
14183
|
const normalized = resolve15(filePath);
|
|
14193
14184
|
try {
|
|
14194
|
-
const realBase =
|
|
14195
|
-
const real =
|
|
14185
|
+
const realBase = realpathSync5(base);
|
|
14186
|
+
const real = realpathSync5(normalized);
|
|
14196
14187
|
return real === realBase || real.startsWith(`${realBase}/`);
|
|
14197
14188
|
} catch {
|
|
14198
14189
|
return false;
|
|
@@ -14257,7 +14248,7 @@ function resolveVisualMediaInput(topicId, input) {
|
|
|
14257
14248
|
}
|
|
14258
14249
|
let realCandidate;
|
|
14259
14250
|
try {
|
|
14260
|
-
realCandidate =
|
|
14251
|
+
realCandidate = realpathSync5(candidate);
|
|
14261
14252
|
} catch {
|
|
14262
14253
|
return { error: `file not found: ${rawPath}` };
|
|
14263
14254
|
}
|
|
@@ -14291,7 +14282,7 @@ var init_visuals = __esm(async () => {
|
|
|
14291
14282
|
// ../../packages/core/src/storage/token-stats.ts
|
|
14292
14283
|
import { createHash as createHash6 } from "crypto";
|
|
14293
14284
|
import { mkdirSync as mkdirSync18 } from "fs";
|
|
14294
|
-
import { join as
|
|
14285
|
+
import { join as join28 } from "path";
|
|
14295
14286
|
function emptyBucket() {
|
|
14296
14287
|
return {
|
|
14297
14288
|
inputTokens: 0,
|
|
@@ -14309,7 +14300,7 @@ function queriesPath(userId) {
|
|
|
14309
14300
|
const fileId = tokenStatsFileId(userId);
|
|
14310
14301
|
const logDir = resolveStorageLogDir();
|
|
14311
14302
|
mkdirSync18(logDir, { recursive: true });
|
|
14312
|
-
return
|
|
14303
|
+
return join28(logDir, `token-queries-${fileId}.jsonl`);
|
|
14313
14304
|
}
|
|
14314
14305
|
function loadRecords(userId) {
|
|
14315
14306
|
try {
|
|
@@ -14380,7 +14371,7 @@ var init_token_stats = __esm(async () => {
|
|
|
14380
14371
|
|
|
14381
14372
|
// ../../packages/core/src/runtime/turn-event-stream.ts
|
|
14382
14373
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
14383
|
-
import { realpathSync as
|
|
14374
|
+
import { realpathSync as realpathSync6, statSync as statSync9 } from "fs";
|
|
14384
14375
|
import { isAbsolute as isAbsolute5, resolve as resolve16 } from "path";
|
|
14385
14376
|
function sessionEventMatchesCurrentExecution(topicId, queryId, agent, model) {
|
|
14386
14377
|
if (getRoomQuery(topicId)?.queryId !== queryId)
|
|
@@ -14695,7 +14686,7 @@ async function runTurnEventStream(topicId, topicTitle, queryId, events, control,
|
|
|
14695
14686
|
}
|
|
14696
14687
|
let safePath;
|
|
14697
14688
|
try {
|
|
14698
|
-
safePath =
|
|
14689
|
+
safePath = realpathSync6(path);
|
|
14699
14690
|
if (!statSync9(safePath).isFile()) {
|
|
14700
14691
|
logger.warn({ topicId, path }, "peer output path is not a regular file");
|
|
14701
14692
|
break;
|
|
@@ -14962,10 +14953,10 @@ var init_turn_session = __esm(async () => {
|
|
|
14962
14953
|
});
|
|
14963
14954
|
|
|
14964
14955
|
// ../../packages/core/src/storage/app-settings.ts
|
|
14965
|
-
import { existsSync as
|
|
14966
|
-
import { dirname as dirname15, join as
|
|
14956
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync19, readFileSync as readFileSync18, writeFileSync as writeFileSync16 } from "fs";
|
|
14957
|
+
import { dirname as dirname15, join as join29 } from "path";
|
|
14967
14958
|
function settingsFile() {
|
|
14968
|
-
return
|
|
14959
|
+
return join29(resolveStorageDataDir(), "otium-settings.json");
|
|
14969
14960
|
}
|
|
14970
14961
|
function ensureSettingsLoaded() {
|
|
14971
14962
|
const path = settingsFile();
|
|
@@ -14974,8 +14965,8 @@ function ensureSettingsLoaded() {
|
|
|
14974
14965
|
loadedSettingsFile = path;
|
|
14975
14966
|
aiName = DEFAULT_AI_NAME;
|
|
14976
14967
|
try {
|
|
14977
|
-
if (
|
|
14978
|
-
const data = JSON.parse(
|
|
14968
|
+
if (existsSync18(path)) {
|
|
14969
|
+
const data = JSON.parse(readFileSync18(path, "utf8"));
|
|
14979
14970
|
if (typeof data.aiName === "string" && data.aiName.trim()) {
|
|
14980
14971
|
aiName = data.aiName.trim();
|
|
14981
14972
|
}
|
|
@@ -15064,8 +15055,8 @@ __export(exports_turn_runner, {
|
|
|
15064
15055
|
AGENT_DISPLAY_NAME: () => AGENT_DISPLAY_NAME
|
|
15065
15056
|
});
|
|
15066
15057
|
import { randomUUID as randomUUID16 } from "crypto";
|
|
15067
|
-
import { existsSync as
|
|
15068
|
-
import { join as
|
|
15058
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync20, readdirSync as readdirSync7, statSync as statSync10 } from "fs";
|
|
15059
|
+
import { join as join30 } from "path";
|
|
15069
15060
|
function withDefaultPlaywright(configuredMcp, isManager) {
|
|
15070
15061
|
if (isManager)
|
|
15071
15062
|
return configuredMcp;
|
|
@@ -15108,18 +15099,18 @@ function appendAskReplyMessage(topicId, text2, agentType) {
|
|
|
15108
15099
|
return message;
|
|
15109
15100
|
}
|
|
15110
15101
|
function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, matchesTitle, preferExact = true) {
|
|
15111
|
-
const preferred =
|
|
15112
|
-
if (preferExact &&
|
|
15102
|
+
const preferred = join30(directory, preferredFilename);
|
|
15103
|
+
if (preferExact && existsSync19(preferred))
|
|
15113
15104
|
return preferred;
|
|
15114
15105
|
let newestLegacyId = null;
|
|
15115
15106
|
let newestTitle = null;
|
|
15116
15107
|
try {
|
|
15117
|
-
for (const filename of
|
|
15108
|
+
for (const filename of readdirSync7(directory)) {
|
|
15118
15109
|
const titleMatch = matchesTitle(filename);
|
|
15119
15110
|
const legacyIdMatch = !titleMatch && matchesLegacyId(filename);
|
|
15120
15111
|
if (!titleMatch && !legacyIdMatch)
|
|
15121
15112
|
continue;
|
|
15122
|
-
const path =
|
|
15113
|
+
const path = join30(directory, filename);
|
|
15123
15114
|
const mtimeMs = statSync10(path).mtimeMs;
|
|
15124
15115
|
if (titleMatch) {
|
|
15125
15116
|
if (!newestTitle || mtimeMs > newestTitle.mtimeMs) {
|
|
@@ -15133,10 +15124,10 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
|
|
|
15133
15124
|
return newestTitle?.path ?? newestLegacyId?.path ?? preferred;
|
|
15134
15125
|
}
|
|
15135
15126
|
function resolveWikiMemoryMirror(wikiDir, topicId, topicTitle) {
|
|
15136
|
-
const briefFile = resolveWikiMirrorPath(
|
|
15137
|
-
const hasBriefFile =
|
|
15138
|
-
const latestSummaryCandidate = resolveWikiMirrorPath(
|
|
15139
|
-
const latestSummaryFile =
|
|
15127
|
+
const briefFile = resolveWikiMirrorPath(join30(wikiDir, "topic"), `${wikiBriefStorageKey(topicTitle, topicId)}.md`, (filename) => isTopicBriefFile(filename, topicId), (filename) => isTopicBriefFile(filename, topicId, topicTitle));
|
|
15128
|
+
const hasBriefFile = existsSync19(briefFile) && statSync10(briefFile).isFile();
|
|
15129
|
+
const latestSummaryCandidate = resolveWikiMirrorPath(join30(wikiDir, "summaries"), `__missing__-${wikiSummaryFilename("0000-00-00", topicTitle, topicId)}`, (filename) => isTopicSummaryFile(filename, topicId), (filename) => isTopicSummaryFile(filename, topicId, topicTitle), false);
|
|
15130
|
+
const latestSummaryFile = existsSync19(latestSummaryCandidate) && statSync10(latestSummaryCandidate).isFile() ? latestSummaryCandidate : null;
|
|
15140
15131
|
return { briefFile, hasBriefFile, latestSummaryFile };
|
|
15141
15132
|
}
|
|
15142
15133
|
async function streamAgentEvents(topicId, topicTitle, queryId, events, control, agentType, model, effort, userId, retryableSessionExpired = true, onSessionId, execution) {
|
|
@@ -16288,9 +16279,9 @@ __export(exports_auth_check, {
|
|
|
16288
16279
|
checkAgentAuth: () => checkAgentAuth
|
|
16289
16280
|
});
|
|
16290
16281
|
import { execFileSync as execFileSync7 } from "child_process";
|
|
16291
|
-
import { existsSync as
|
|
16282
|
+
import { existsSync as existsSync20 } from "fs";
|
|
16292
16283
|
import { homedir as homedir9, platform } from "os";
|
|
16293
|
-
import { join as
|
|
16284
|
+
import { join as join31 } from "path";
|
|
16294
16285
|
function hasMaestroCredential(host, key, userId) {
|
|
16295
16286
|
if (userId && host.getVaultValue(userId, key)?.trim())
|
|
16296
16287
|
return true;
|
|
@@ -16319,7 +16310,7 @@ function checkAgentAuth(agent, host = defaultAgentAuthHost, userId) {
|
|
|
16319
16310
|
error: "claude is not logged in (no macOS keychain entry 'Claude Code-credentials'). Run `claude` and complete login first"
|
|
16320
16311
|
};
|
|
16321
16312
|
}
|
|
16322
|
-
const path =
|
|
16313
|
+
const path = join31(host.homeDirectory(), ".claude", ".credentials.json");
|
|
16323
16314
|
if (host.exists(path))
|
|
16324
16315
|
return { ok: true };
|
|
16325
16316
|
return {
|
|
@@ -16361,7 +16352,7 @@ var init_auth_check = __esm(async () => {
|
|
|
16361
16352
|
await init_vault();
|
|
16362
16353
|
defaultAgentAuthHost = {
|
|
16363
16354
|
codexAuthFilePath,
|
|
16364
|
-
exists:
|
|
16355
|
+
exists: existsSync20,
|
|
16365
16356
|
environment: process.env,
|
|
16366
16357
|
homeDirectory: homedir9,
|
|
16367
16358
|
operatingSystem: platform,
|
|
@@ -18433,15 +18424,401 @@ await __promiseAll([
|
|
|
18433
18424
|
init_codex_registry(),
|
|
18434
18425
|
init_maestro_registry()
|
|
18435
18426
|
]);
|
|
18427
|
+
import { spawn as spawn2 } from "child_process";
|
|
18428
|
+
import { existsSync as existsSync9, readdirSync as readdirSync3 } from "fs";
|
|
18429
|
+
import { join as join11 } from "path";
|
|
18436
18430
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
18437
18431
|
import { z } from "zod";
|
|
18432
|
+
function signalProcessTree(child, signal) {
|
|
18433
|
+
try {
|
|
18434
|
+
if (child.pid && process.platform !== "win32")
|
|
18435
|
+
process.kill(-child.pid, signal);
|
|
18436
|
+
else
|
|
18437
|
+
child.kill(signal);
|
|
18438
|
+
} catch {
|
|
18439
|
+
try {
|
|
18440
|
+
child.kill(signal);
|
|
18441
|
+
} catch {}
|
|
18442
|
+
}
|
|
18443
|
+
}
|
|
18444
|
+
function spawnCapture(cmd, args, timeoutMs, signal, env) {
|
|
18445
|
+
return new Promise((resolve7, reject) => {
|
|
18446
|
+
const child = spawn2(cmd, args, {
|
|
18447
|
+
env: env ?? process.env,
|
|
18448
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
18449
|
+
detached: process.platform !== "win32"
|
|
18450
|
+
});
|
|
18451
|
+
let settled = false;
|
|
18452
|
+
let stdout = "";
|
|
18453
|
+
let stderr = "";
|
|
18454
|
+
const forceKill = () => signalProcessTree(child, "SIGKILL");
|
|
18455
|
+
let killTimer;
|
|
18456
|
+
const stop = (reason) => {
|
|
18457
|
+
if (settled)
|
|
18458
|
+
return;
|
|
18459
|
+
settled = true;
|
|
18460
|
+
signalProcessTree(child, "SIGTERM");
|
|
18461
|
+
killTimer = setTimeout(() => {
|
|
18462
|
+
forceKill();
|
|
18463
|
+
killTimer = undefined;
|
|
18464
|
+
}, 1000);
|
|
18465
|
+
killTimer.unref?.();
|
|
18466
|
+
reject(new Error(reason));
|
|
18467
|
+
};
|
|
18468
|
+
const timeout = setTimeout(() => stop("timeout"), timeoutMs);
|
|
18469
|
+
const onAbort = () => stop("aborted");
|
|
18470
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
18471
|
+
const cleanup = () => {
|
|
18472
|
+
clearTimeout(timeout);
|
|
18473
|
+
signal.removeEventListener("abort", onAbort);
|
|
18474
|
+
};
|
|
18475
|
+
child.stdout.on("data", (data) => {
|
|
18476
|
+
stdout += data.toString();
|
|
18477
|
+
});
|
|
18478
|
+
child.stderr.on("data", (data) => {
|
|
18479
|
+
stderr += data.toString();
|
|
18480
|
+
});
|
|
18481
|
+
child.on("error", (err) => {
|
|
18482
|
+
if (settled)
|
|
18483
|
+
return;
|
|
18484
|
+
settled = true;
|
|
18485
|
+
cleanup();
|
|
18486
|
+
if (killTimer)
|
|
18487
|
+
clearTimeout(killTimer);
|
|
18488
|
+
reject(err);
|
|
18489
|
+
});
|
|
18490
|
+
child.on("close", (code, exitSignal) => {
|
|
18491
|
+
cleanup();
|
|
18492
|
+
if (settled) {
|
|
18493
|
+
if (killTimer) {
|
|
18494
|
+
clearTimeout(killTimer);
|
|
18495
|
+
killTimer = undefined;
|
|
18496
|
+
}
|
|
18497
|
+
return;
|
|
18498
|
+
}
|
|
18499
|
+
settled = true;
|
|
18500
|
+
if (killTimer)
|
|
18501
|
+
clearTimeout(killTimer);
|
|
18502
|
+
if (code === 0)
|
|
18503
|
+
resolve7({ stdout, stderr });
|
|
18504
|
+
else
|
|
18505
|
+
reject(new Error(stderr.trim() || `${cmd} exited with ${code ?? exitSignal}`));
|
|
18506
|
+
});
|
|
18507
|
+
});
|
|
18508
|
+
}
|
|
18509
|
+
function resultOk(agent, model, latency, detail) {
|
|
18510
|
+
return { agent, model, ok: true, latency, detail };
|
|
18511
|
+
}
|
|
18512
|
+
function resultFail(agent, model, latency, error) {
|
|
18513
|
+
let category = "unknown";
|
|
18514
|
+
const normalized = error.toLowerCase();
|
|
18515
|
+
if (normalized.includes("auth") || normalized.includes("key") || normalized.includes("credential") || normalized.includes("unauthorized")) {
|
|
18516
|
+
category = "auth_error";
|
|
18517
|
+
} else if (normalized.includes("rate") || normalized.includes("limit") || normalized.includes("busy") || normalized.includes("overloaded")) {
|
|
18518
|
+
category = "rate_limit";
|
|
18519
|
+
} else if (normalized.includes("network") || normalized.includes("refused") || normalized.includes("dns") || normalized.includes("timeout")) {
|
|
18520
|
+
category = "network_error";
|
|
18521
|
+
}
|
|
18522
|
+
return { agent, model, ok: false, latency, error, category };
|
|
18523
|
+
}
|
|
18524
|
+
async function checkClaude(model, timeoutMs, signal) {
|
|
18525
|
+
const start = performance.now();
|
|
18526
|
+
try {
|
|
18527
|
+
const args = ["-p", "say OK", "--model", model, "--max-turns", "1", "--output-format", "text"];
|
|
18528
|
+
const { stdout, stderr } = await spawnCapture("claude", args, timeoutMs, signal);
|
|
18529
|
+
const elapsed = Math.round(performance.now() - start);
|
|
18530
|
+
const text = (stdout + stderr).trim().slice(0, 200);
|
|
18531
|
+
if (!text)
|
|
18532
|
+
return resultFail("claude", model, elapsed, "empty response");
|
|
18533
|
+
return resultOk("claude", model, elapsed, text);
|
|
18534
|
+
} catch (err) {
|
|
18535
|
+
return resultFail("claude", model, Math.round(performance.now() - start), errMsg(err));
|
|
18536
|
+
}
|
|
18537
|
+
}
|
|
18538
|
+
async function checkCodex(model, timeoutMs, signal) {
|
|
18539
|
+
const start = performance.now();
|
|
18540
|
+
try {
|
|
18541
|
+
const args = [
|
|
18542
|
+
"exec",
|
|
18543
|
+
"--model",
|
|
18544
|
+
model,
|
|
18545
|
+
"--skip-git-repo-check",
|
|
18546
|
+
"--sandbox",
|
|
18547
|
+
"danger-full-access",
|
|
18548
|
+
"say OK"
|
|
18549
|
+
];
|
|
18550
|
+
const { stdout, stderr } = await spawnCapture("codex", args, timeoutMs, signal, {
|
|
18551
|
+
...process.env,
|
|
18552
|
+
CODEX_NO_COLOR: "1"
|
|
18553
|
+
});
|
|
18554
|
+
const elapsed = Math.round(performance.now() - start);
|
|
18555
|
+
const combined = (stdout + stderr).trim();
|
|
18556
|
+
const match = combined.match(/\ncodex\s*\n(.+?)(?:\n(?:tokens|session|user|$))/);
|
|
18557
|
+
return resultOk("codex", model, elapsed, match ? match[1].trim().slice(0, 200) : "OK");
|
|
18558
|
+
} catch (err) {
|
|
18559
|
+
return resultFail("codex", model, Math.round(performance.now() - start), errMsg(err));
|
|
18560
|
+
}
|
|
18561
|
+
}
|
|
18562
|
+
async function checkMaestro(model, timeoutMs, signal) {
|
|
18563
|
+
const start = performance.now();
|
|
18564
|
+
let iterator;
|
|
18565
|
+
try {
|
|
18566
|
+
const { maestroProvider } = await import("maestro-agent-sdk");
|
|
18567
|
+
const generator = maestroProvider({
|
|
18568
|
+
model,
|
|
18569
|
+
prompt: "say OK",
|
|
18570
|
+
cwd: process.cwd(),
|
|
18571
|
+
maxTurns: 1
|
|
18572
|
+
});
|
|
18573
|
+
const deadline = Date.now() + timeoutMs;
|
|
18574
|
+
const activeIterator = generator[Symbol.asyncIterator]();
|
|
18575
|
+
iterator = activeIterator;
|
|
18576
|
+
let text = "";
|
|
18577
|
+
while (true) {
|
|
18578
|
+
const remaining = deadline - Date.now();
|
|
18579
|
+
if (remaining <= 0)
|
|
18580
|
+
throw new Error("timeout");
|
|
18581
|
+
const eventResult = await new Promise((resolve7, reject) => {
|
|
18582
|
+
const timeout = setTimeout(() => reject(new Error("timeout")), remaining);
|
|
18583
|
+
const onAbort = () => reject(new Error("aborted"));
|
|
18584
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
18585
|
+
activeIterator.next().then(resolve7, reject).finally(() => {
|
|
18586
|
+
clearTimeout(timeout);
|
|
18587
|
+
signal.removeEventListener("abort", onAbort);
|
|
18588
|
+
});
|
|
18589
|
+
});
|
|
18590
|
+
if (eventResult.done)
|
|
18591
|
+
break;
|
|
18592
|
+
const event = eventResult.value;
|
|
18593
|
+
if (event.type === "text" && event.content)
|
|
18594
|
+
text = event.content.slice(0, 200);
|
|
18595
|
+
if (event.type === "error") {
|
|
18596
|
+
return resultFail("maestro", model, Math.round(performance.now() - start), event.error || "unknown error");
|
|
18597
|
+
}
|
|
18598
|
+
}
|
|
18599
|
+
return resultOk("maestro", model, Math.round(performance.now() - start), text || "(empty response)");
|
|
18600
|
+
} catch (err) {
|
|
18601
|
+
return resultFail("maestro", model, Math.round(performance.now() - start), errMsg(err));
|
|
18602
|
+
} finally {
|
|
18603
|
+
if (iterator?.return) {
|
|
18604
|
+
try {
|
|
18605
|
+
await iterator.return();
|
|
18606
|
+
} catch {}
|
|
18607
|
+
}
|
|
18608
|
+
}
|
|
18609
|
+
}
|
|
18610
|
+
function getDefaultModel(registry) {
|
|
18611
|
+
return resolveDefaultModel(registry.kind, registry.defaultModel);
|
|
18612
|
+
}
|
|
18613
|
+
var AGENTS = [
|
|
18614
|
+
{ kind: "claude", registry: claudeRegistry, checker: checkClaude },
|
|
18615
|
+
{ kind: "codex", registry: codexRegistry, checker: checkCodex },
|
|
18616
|
+
{ kind: "maestro", registry: maestroRegistry, checker: checkMaestro }
|
|
18617
|
+
];
|
|
18618
|
+
var MAX_CONCURRENT_CHECKS = 2;
|
|
18619
|
+
var activeChecks = 0;
|
|
18620
|
+
var checkWaiters = [];
|
|
18438
18621
|
var activeCheckAllUsers = new Set;
|
|
18622
|
+
async function withCheckSlot(operation) {
|
|
18623
|
+
if (activeChecks >= MAX_CONCURRENT_CHECKS) {
|
|
18624
|
+
await new Promise((resolve7) => checkWaiters.push(resolve7));
|
|
18625
|
+
}
|
|
18626
|
+
activeChecks += 1;
|
|
18627
|
+
try {
|
|
18628
|
+
return await operation();
|
|
18629
|
+
} finally {
|
|
18630
|
+
activeChecks -= 1;
|
|
18631
|
+
checkWaiters.shift()?.();
|
|
18632
|
+
}
|
|
18633
|
+
}
|
|
18634
|
+
function createAgentHealthMcpServer(context) {
|
|
18635
|
+
const server = new McpServer({ name: "agent-health", version: "1.0.0" });
|
|
18636
|
+
const abortController = new AbortController;
|
|
18637
|
+
const originalClose = server.close.bind(server);
|
|
18638
|
+
server.close = async () => {
|
|
18639
|
+
abortController.abort();
|
|
18640
|
+
await originalClose();
|
|
18641
|
+
};
|
|
18642
|
+
server.tool("check_agent", "\uC2E4\uC81C API \uD638\uCD9C\uB85C \uD2B9\uC815 agent+model \uC870\uD569\uC774 \uC815\uC0C1 \uB3D9\uC791\uD558\uB294\uC9C0 \uCCB4\uD06C\uD569\uB2C8\uB2E4.", {
|
|
18643
|
+
agent: z.enum(["claude", "codex", "maestro"]).describe("\uCCB4\uD06C\uD560 agent"),
|
|
18644
|
+
model: z.string().optional().describe("\uCCB4\uD06C\uD560 \uBAA8\uB378 (\uC5C6\uC73C\uBA74 agent\uBCC4 default \uC0AC\uC6A9)"),
|
|
18645
|
+
timeoutMs: z.number().default(30000).describe("\uD0C0\uC784\uC544\uC6C3 (ms), \uAE30\uBCF8 30\uCD08")
|
|
18646
|
+
}, async ({ agent, model, timeoutMs }) => {
|
|
18647
|
+
const entry = AGENTS.find((candidate) => candidate.kind === agent);
|
|
18648
|
+
if (!entry)
|
|
18649
|
+
return mcpOk(`Unknown agent: ${agent}`);
|
|
18650
|
+
const resolvedModel = model || getDefaultModel(entry.registry);
|
|
18651
|
+
const result = await withCheckSlot(() => entry.checker(resolvedModel, timeoutMs, abortController.signal));
|
|
18652
|
+
if (result.ok) {
|
|
18653
|
+
return mcpOk(`OK ${result.agent} / ${result.model}
|
|
18654
|
+
latency: ${result.latency}ms
|
|
18655
|
+
detail: ${result.detail}`);
|
|
18656
|
+
}
|
|
18657
|
+
return mcpOk(`FAIL ${result.agent} / ${result.model} [${result.category}]
|
|
18658
|
+
latency: ${result.latency}ms
|
|
18659
|
+
error: ${result.error}`);
|
|
18660
|
+
});
|
|
18661
|
+
server.tool("check_all", "\uBAA8\uB4E0 agent (claude, codex, maestro)\uB97C \uAE30\uBCF8 \uBAA8\uB378\uB85C \uB3D9\uC2DC\uC5D0 \uCCB4\uD06C\uD569\uB2C8\uB2E4.", { timeoutMs: z.number().default(30000).describe("agent\uBCC4 \uD0C0\uC784\uC544\uC6C3 (ms), \uAE30\uBCF8 30\uCD08") }, async ({ timeoutMs }) => {
|
|
18662
|
+
const userKey = context.userId ?? "unscoped";
|
|
18663
|
+
if (activeCheckAllUsers.has(userKey)) {
|
|
18664
|
+
return mcpOk("FAIL check_all is already running for this user");
|
|
18665
|
+
}
|
|
18666
|
+
activeCheckAllUsers.add(userKey);
|
|
18667
|
+
try {
|
|
18668
|
+
const results = await Promise.all(AGENTS.map(async (entry) => withCheckSlot(() => entry.checker(getDefaultModel(entry.registry), timeoutMs, abortController.signal))));
|
|
18669
|
+
const lines = results.map((result) => result.ok ? `OK ${result.agent.padEnd(8)} / ${result.model.padEnd(14)} ${result.latency}ms ${result.detail}` : `FAIL ${result.agent.padEnd(8)} / ${result.model.padEnd(14)} ${result.latency}ms [${result.category}] ${result.error}`);
|
|
18670
|
+
return mcpOk(`Agent/Model Health Check
|
|
18671
|
+
${lines.join(`
|
|
18672
|
+
`)}
|
|
18673
|
+
|
|
18674
|
+
${results.every((result) => result.ok) ? "All agents healthy" : "Some agents failed"}`);
|
|
18675
|
+
} finally {
|
|
18676
|
+
activeCheckAllUsers.delete(userKey);
|
|
18677
|
+
}
|
|
18678
|
+
});
|
|
18679
|
+
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 () => {
|
|
18680
|
+
if (!context.userId)
|
|
18681
|
+
return mcpOk("\uC2E4\uD589 \uC911\uC778 \uCFFC\uB9AC \uC870\uD68C \uBD88\uAC00 (user context \uC5C6\uC74C)");
|
|
18682
|
+
const stateDir = join11(USERS_LOG_DIR, context.userId, "active-queries");
|
|
18683
|
+
if (!existsSync9(stateDir))
|
|
18684
|
+
return mcpOk("\uC2E4\uD589 \uC911\uC778 \uCFFC\uB9AC \uC5C6\uC74C");
|
|
18685
|
+
let files;
|
|
18686
|
+
try {
|
|
18687
|
+
files = readdirSync3(stateDir);
|
|
18688
|
+
} catch {
|
|
18689
|
+
return mcpOk("\uC2E4\uD589 \uC911\uC778 \uCFFC\uB9AC \uC5C6\uC74C");
|
|
18690
|
+
}
|
|
18691
|
+
const now = Date.now();
|
|
18692
|
+
const entries = files.flatMap((file) => {
|
|
18693
|
+
if (!file.endsWith(".json"))
|
|
18694
|
+
return [];
|
|
18695
|
+
const state = readJsonFile(join11(stateDir, file));
|
|
18696
|
+
if (!state)
|
|
18697
|
+
return [];
|
|
18698
|
+
const sinceMs = new Date(state.since).getTime();
|
|
18699
|
+
if (now - sinceMs > ACTIVE_QUERY_STALE_MS)
|
|
18700
|
+
return [];
|
|
18701
|
+
return [
|
|
18702
|
+
{
|
|
18703
|
+
topicName: state.topicName ?? file.slice(0, -5),
|
|
18704
|
+
elapsedSec: Math.round((now - sinceMs) / 1000),
|
|
18705
|
+
task: state.task
|
|
18706
|
+
}
|
|
18707
|
+
];
|
|
18708
|
+
});
|
|
18709
|
+
if (entries.length === 0)
|
|
18710
|
+
return mcpOk("\uC2E4\uD589 \uC911\uC778 \uCFFC\uB9AC \uC5C6\uC74C");
|
|
18711
|
+
const lines = entries.map((entry) => `\u2022 ${entry.topicName} | ${entry.elapsedSec}s \uACBD\uACFC${entry.task ? ` "${entry.task}"` : ""}`);
|
|
18712
|
+
return mcpOk(`\uC2E4\uD589 \uC911\uC778 \uCFFC\uB9AC (${entries.length}\uAC1C)
|
|
18713
|
+
${lines.join(`
|
|
18714
|
+
`)}`);
|
|
18715
|
+
});
|
|
18716
|
+
return server;
|
|
18717
|
+
}
|
|
18439
18718
|
// ../../packages/core/src/mcp/factories/compaction-log.ts
|
|
18440
18719
|
init_mcp_helpers();
|
|
18720
|
+
import { readFileSync as readFileSync8, realpathSync as realpathSync2 } from "fs";
|
|
18441
18721
|
import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
18442
18722
|
import { z as z2 } from "zod";
|
|
18723
|
+
var DEFAULT_MAX_CALLS = 12;
|
|
18443
18724
|
var DEFAULT_MAX_TOTAL_BYTES = 512 * 1024;
|
|
18444
18725
|
var DEFAULT_MAX_CHUNK_BYTES = 64 * 1024;
|
|
18726
|
+
var DEFAULT_LINE_LIMIT = 300;
|
|
18727
|
+
var MAX_LINE_LIMIT = 500;
|
|
18728
|
+
function positiveInt(value2, fallback) {
|
|
18729
|
+
return Number.isFinite(value2) && value2 && value2 > 0 ? Math.floor(value2) : fallback;
|
|
18730
|
+
}
|
|
18731
|
+
function fitUtf8(text, maxBytes) {
|
|
18732
|
+
if (Buffer.byteLength(text, "utf8") <= maxBytes)
|
|
18733
|
+
return text;
|
|
18734
|
+
const marker = `
|
|
18735
|
+
[... oversized line clipped ...]
|
|
18736
|
+
`;
|
|
18737
|
+
const markerBytes = Buffer.byteLength(marker, "utf8");
|
|
18738
|
+
const bytes = Buffer.from(text, "utf8");
|
|
18739
|
+
if (maxBytes <= markerBytes) {
|
|
18740
|
+
return bytes.subarray(0, maxBytes).toString("utf8").replace(/\uFFFD+$/u, "");
|
|
18741
|
+
}
|
|
18742
|
+
const available = Math.max(0, maxBytes - markerBytes);
|
|
18743
|
+
const headBudget = Math.ceil(available * 0.6);
|
|
18744
|
+
const tailBudget = available - headBudget;
|
|
18745
|
+
const head = bytes.subarray(0, headBudget).toString("utf8").replace(/\uFFFD+$/u, "");
|
|
18746
|
+
const tail = bytes.subarray(Math.max(0, bytes.length - tailBudget)).toString("utf8").replace(/^\uFFFD+/u, "");
|
|
18747
|
+
return `${head}${marker}${tail}`;
|
|
18748
|
+
}
|
|
18749
|
+
function createCompactionLogMcpServer(context) {
|
|
18750
|
+
if (!context.filePath)
|
|
18751
|
+
throw new Error("compaction-log MCP requires filePath");
|
|
18752
|
+
const filePath = realpathSync2(context.filePath);
|
|
18753
|
+
const lines = readFileSync8(filePath, "utf8").split(`
|
|
18754
|
+
`);
|
|
18755
|
+
const maxCalls = positiveInt(context.maxCalls, DEFAULT_MAX_CALLS);
|
|
18756
|
+
const maxTotalBytes = positiveInt(context.maxTotalBytes, DEFAULT_MAX_TOTAL_BYTES);
|
|
18757
|
+
const maxChunkBytes = positiveInt(context.maxChunkBytes, DEFAULT_MAX_CHUNK_BYTES);
|
|
18758
|
+
let calls = 0;
|
|
18759
|
+
let totalBytes = 0;
|
|
18760
|
+
const server = new McpServer2({ name: "compaction-log", version: "1.0.0" });
|
|
18761
|
+
server.tool("read_compaction_log", [
|
|
18762
|
+
`Read the immutable conversation snapshot in bounded chunks. It contains ${lines.length} lines.`,
|
|
18763
|
+
"Start at offset 1, then inspect the final chunk using total_lines from the response.",
|
|
18764
|
+
"Read intermediate chunks only when needed. Return a summary instead of calling after the budget is exhausted."
|
|
18765
|
+
].join(" "), {
|
|
18766
|
+
offset: z2.number().optional().describe("One-based line number. Defaults to 1."),
|
|
18767
|
+
limit: z2.number().optional().describe(`Number of lines. Defaults to ${DEFAULT_LINE_LIMIT}, max ${MAX_LINE_LIMIT}.`)
|
|
18768
|
+
}, async ({ offset: rawOffset, limit: rawLimit }) => {
|
|
18769
|
+
calls += 1;
|
|
18770
|
+
if (calls > maxCalls || totalBytes >= maxTotalBytes) {
|
|
18771
|
+
return mcpError(JSON.stringify({
|
|
18772
|
+
error: "compaction log read budget exhausted; produce the summary now",
|
|
18773
|
+
calls,
|
|
18774
|
+
max_calls: maxCalls,
|
|
18775
|
+
total_lines: lines.length
|
|
18776
|
+
}));
|
|
18777
|
+
}
|
|
18778
|
+
const offset = positiveInt(rawOffset, 1);
|
|
18779
|
+
const limit = Math.min(positiveInt(rawLimit, DEFAULT_LINE_LIMIT), MAX_LINE_LIMIT);
|
|
18780
|
+
const start = Math.max(0, offset - 1);
|
|
18781
|
+
if (start >= lines.length) {
|
|
18782
|
+
return mcpOk(JSON.stringify({
|
|
18783
|
+
content: "(end of compaction log)",
|
|
18784
|
+
offset,
|
|
18785
|
+
returned_lines: 0,
|
|
18786
|
+
total_lines: lines.length,
|
|
18787
|
+
calls
|
|
18788
|
+
}));
|
|
18789
|
+
}
|
|
18790
|
+
const selected = [];
|
|
18791
|
+
let returnedBytes = 0;
|
|
18792
|
+
let index = start;
|
|
18793
|
+
const callBudget = Math.min(maxChunkBytes, maxTotalBytes - totalBytes);
|
|
18794
|
+
while (index < lines.length && selected.length < limit) {
|
|
18795
|
+
const line = fitUtf8(lines[index] ?? "", Math.max(1, callBudget));
|
|
18796
|
+
const separatorBytes = selected.length > 0 ? 1 : 0;
|
|
18797
|
+
const lineBytes = Buffer.byteLength(line, "utf8");
|
|
18798
|
+
if (selected.length > 0 && returnedBytes + separatorBytes + lineBytes > callBudget)
|
|
18799
|
+
break;
|
|
18800
|
+
selected.push(line);
|
|
18801
|
+
returnedBytes += separatorBytes + lineBytes;
|
|
18802
|
+
index += 1;
|
|
18803
|
+
if (returnedBytes >= callBudget)
|
|
18804
|
+
break;
|
|
18805
|
+
}
|
|
18806
|
+
totalBytes += returnedBytes;
|
|
18807
|
+
return mcpOk(JSON.stringify({
|
|
18808
|
+
content: selected.join(`
|
|
18809
|
+
`),
|
|
18810
|
+
offset,
|
|
18811
|
+
returned_lines: selected.length,
|
|
18812
|
+
returned_bytes: returnedBytes,
|
|
18813
|
+
total_lines: lines.length,
|
|
18814
|
+
total_read_bytes: totalBytes,
|
|
18815
|
+
calls,
|
|
18816
|
+
...index < lines.length ? { next_offset: index + 1 } : {},
|
|
18817
|
+
...calls >= maxCalls || totalBytes >= maxTotalBytes ? { note: "Read budget exhausted; produce the summary now." } : {}
|
|
18818
|
+
}));
|
|
18819
|
+
});
|
|
18820
|
+
return server;
|
|
18821
|
+
}
|
|
18445
18822
|
// ../../packages/core/src/mcp/factories/session-comm.ts
|
|
18446
18823
|
import { McpServer as McpServer3 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
18447
18824
|
import { z as z5 } from "zod";
|
|
@@ -18940,7 +19317,9 @@ export {
|
|
|
18940
19317
|
createTaskMcpServer,
|
|
18941
19318
|
createSystemHealthMcpServer,
|
|
18942
19319
|
createSessionTargetCatalog,
|
|
18943
|
-
createSessionCommMcpServer
|
|
19320
|
+
createSessionCommMcpServer,
|
|
19321
|
+
createCompactionLogMcpServer,
|
|
19322
|
+
createAgentHealthMcpServer
|
|
18944
19323
|
};
|
|
18945
19324
|
|
|
18946
|
-
//# debugId=
|
|
19325
|
+
//# debugId=BC238DE297D39F6964756E2164756E21
|