negotium 0.1.29 → 0.1.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-helpers.js +378 -76
- package/dist/agent-helpers.js.map +13 -12
- package/dist/background-bash.js.map +1 -1
- package/dist/{chunk-yk55n9dk.js → chunk-1p2n47qd.js} +7 -24
- package/dist/{chunk-yk55n9dk.js.map → chunk-1p2n47qd.js.map} +4 -4
- package/dist/cron.js +4992 -4537
- package/dist/cron.js.map +14 -14
- package/dist/hosted-agent.js +335 -43
- package/dist/hosted-agent.js.map +10 -9
- package/dist/main.js +7351 -6678
- package/dist/main.js.map +25 -24
- package/dist/mcp-factories.js +13 -8
- package/dist/mcp-factories.js.map +5 -5
- package/dist/prompts.js +2 -3
- package/dist/prompts.js.map +4 -4
- package/dist/registry.js +1 -1
- package/dist/rollout.js +1 -1
- package/dist/runtime/src/agents/claude-provider.ts +2 -0
- package/dist/runtime/src/agents/codex-provider.ts +192 -5
- package/dist/runtime/src/agents/rollout/codex.ts +201 -22
- package/dist/runtime/src/agents/rollout/index.ts +6 -0
- package/dist/runtime/src/agents/tool-format.ts +228 -15
- package/dist/runtime/src/bus.ts +21 -3
- package/dist/runtime/src/mcp/background-bash-server.ts +7 -4
- package/dist/runtime/src/mcp/wiki-server.ts +8 -5
- package/dist/runtime/src/platform/mcp-config.ts +9 -4
- package/dist/runtime/src/prompts/builders.ts +2 -3
- package/dist/runtime/src/runtime/turn-runner.ts +71 -17
- package/dist/runtime/src/storage/wiki-summary-names.ts +25 -5
- package/dist/runtime/src/types/api.ts +2 -0
- package/dist/runtime/src/types.ts +2 -0
- package/dist/runtime/src/version.ts +1 -1
- package/dist/runtime-helpers.js.map +1 -1
- package/dist/storage.js +17 -4
- package/dist/storage.js.map +4 -4
- package/dist/types/packages/core/src/agents/rollout/codex.d.ts +24 -0
- package/dist/types/packages/core/src/agents/rollout/index.d.ts +2 -2
- package/dist/types/packages/core/src/agents/tool-format.d.ts +16 -9
- package/dist/types/packages/core/src/bus.d.ts +2 -2
- package/dist/types/packages/core/src/prompts/builders.d.ts +1 -1
- package/dist/types/packages/core/src/storage/wiki-summary-names.d.ts +9 -0
- package/dist/types/packages/core/src/types/api.d.ts +2 -0
- package/dist/types/packages/core/src/types.d.ts +2 -0
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/dist/vault.js.map +1 -1
- package/package.json +2 -1
package/dist/agent-helpers.js
CHANGED
|
@@ -1296,9 +1296,9 @@ import { join as join10 } from "path";
|
|
|
1296
1296
|
|
|
1297
1297
|
// ../../packages/core/src/agents/rollout/codex.ts
|
|
1298
1298
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
1299
|
-
import { existsSync as existsSync5, readFileSync as readFileSync4, statSync as statSync2, unlinkSync as unlinkSync4 } from "fs";
|
|
1299
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, realpathSync, statSync as statSync2, unlinkSync as unlinkSync4 } from "fs";
|
|
1300
1300
|
import { homedir as homedir5 } from "os";
|
|
1301
|
-
import { join as join7 } from "path";
|
|
1301
|
+
import { basename, dirname as dirname4, join as join7, resolve as resolve3 } from "path";
|
|
1302
1302
|
function codexSessionsDir() {
|
|
1303
1303
|
return join7(process.env.CODEX_HOME || join7(homedir5(), ".codex"), "sessions");
|
|
1304
1304
|
}
|
|
@@ -1364,6 +1364,139 @@ function patchEnvContext(envContext, cwd, currentDate, timezone) {
|
|
|
1364
1364
|
}
|
|
1365
1365
|
}
|
|
1366
1366
|
}
|
|
1367
|
+
function canonicalFilePath(path) {
|
|
1368
|
+
const absolute = resolve3(path);
|
|
1369
|
+
try {
|
|
1370
|
+
return realpathSync(absolute);
|
|
1371
|
+
} catch {
|
|
1372
|
+
try {
|
|
1373
|
+
return join7(realpathSync(dirname4(absolute)), basename(absolute));
|
|
1374
|
+
} catch {
|
|
1375
|
+
return absolute;
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
function changedPatchLines(value) {
|
|
1380
|
+
const removed = [];
|
|
1381
|
+
const added = [];
|
|
1382
|
+
const diffPreview = [];
|
|
1383
|
+
let oldLine = 0;
|
|
1384
|
+
let newLine = 0;
|
|
1385
|
+
let sawHunk = false;
|
|
1386
|
+
for (const line of value.split(`
|
|
1387
|
+
`)) {
|
|
1388
|
+
const hunk = /^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/.exec(line);
|
|
1389
|
+
if (hunk) {
|
|
1390
|
+
if (sawHunk)
|
|
1391
|
+
diffPreview.push("\u2026");
|
|
1392
|
+
sawHunk = true;
|
|
1393
|
+
oldLine = Number.parseInt(hunk[1] ?? "0", 10);
|
|
1394
|
+
newLine = Number.parseInt(hunk[2] ?? "0", 10);
|
|
1395
|
+
continue;
|
|
1396
|
+
}
|
|
1397
|
+
if (!sawHunk && (line.startsWith("--- ") || line.startsWith("+++ ")))
|
|
1398
|
+
continue;
|
|
1399
|
+
if (line.startsWith("\\ No newline"))
|
|
1400
|
+
continue;
|
|
1401
|
+
if (line.startsWith("-")) {
|
|
1402
|
+
removed.push(line.slice(1));
|
|
1403
|
+
diffPreview.push(`${oldLine} -${line.slice(1)}`);
|
|
1404
|
+
oldLine += 1;
|
|
1405
|
+
continue;
|
|
1406
|
+
}
|
|
1407
|
+
if (line.startsWith("+")) {
|
|
1408
|
+
added.push(line.slice(1));
|
|
1409
|
+
diffPreview.push(`${newLine} +${line.slice(1)}`);
|
|
1410
|
+
newLine += 1;
|
|
1411
|
+
continue;
|
|
1412
|
+
}
|
|
1413
|
+
if (line.startsWith(" ")) {
|
|
1414
|
+
diffPreview.push(`${newLine} ${line.slice(1)}`);
|
|
1415
|
+
oldLine += 1;
|
|
1416
|
+
newLine += 1;
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
return {
|
|
1420
|
+
...removed.length > 0 ? { before: removed.join(`
|
|
1421
|
+
`) } : {},
|
|
1422
|
+
...added.length > 0 ? { after: added.join(`
|
|
1423
|
+
`) } : {},
|
|
1424
|
+
...diffPreview.length > 0 ? { diffPreview: diffPreview.join(`
|
|
1425
|
+
`) } : {}
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
function extractLatestCodexPatchPreview(jsonl, expectedPaths, consumedCallIds = new Set, expectedCallId) {
|
|
1429
|
+
const expected = expectedPaths.map(canonicalFilePath);
|
|
1430
|
+
const lines = jsonl.trimEnd().split(`
|
|
1431
|
+
`);
|
|
1432
|
+
for (let index = lines.length - 1;index >= 0; index -= 1) {
|
|
1433
|
+
try {
|
|
1434
|
+
const entry = JSON.parse(lines[index] ?? "");
|
|
1435
|
+
if (entry.type !== "event_msg" || entry.payload?.type !== "patch_apply_end")
|
|
1436
|
+
continue;
|
|
1437
|
+
const callId = entry.payload.call_id;
|
|
1438
|
+
const rawChanges = entry.payload.changes;
|
|
1439
|
+
if (!callId || consumedCallIds.has(callId) || expectedCallId !== undefined && callId !== expectedCallId || !rawChanges) {
|
|
1440
|
+
continue;
|
|
1441
|
+
}
|
|
1442
|
+
const entries = Object.entries(rawChanges);
|
|
1443
|
+
const matched = expected.map((path) => entries.find(([candidate]) => canonicalFilePath(candidate) === path));
|
|
1444
|
+
const complete = matched.filter((change) => change !== undefined);
|
|
1445
|
+
if (complete.length !== expected.length)
|
|
1446
|
+
continue;
|
|
1447
|
+
return {
|
|
1448
|
+
callId,
|
|
1449
|
+
changes: complete.map(([path, change]) => {
|
|
1450
|
+
if (typeof change.unified_diff === "string") {
|
|
1451
|
+
return { path, ...changedPatchLines(change.unified_diff) };
|
|
1452
|
+
}
|
|
1453
|
+
const content = typeof change.content === "string" ? change.content.replace(/\n$/, "") : undefined;
|
|
1454
|
+
return {
|
|
1455
|
+
path,
|
|
1456
|
+
...change.type === "delete" && content !== undefined ? { before: content } : {},
|
|
1457
|
+
...change.type === "add" && content !== undefined ? { after: content } : {}
|
|
1458
|
+
};
|
|
1459
|
+
})
|
|
1460
|
+
};
|
|
1461
|
+
} catch {}
|
|
1462
|
+
}
|
|
1463
|
+
return;
|
|
1464
|
+
}
|
|
1465
|
+
function extractCodexPatchCallIds(jsonl) {
|
|
1466
|
+
const callIds = [];
|
|
1467
|
+
for (const line of jsonl.trimEnd().split(`
|
|
1468
|
+
`)) {
|
|
1469
|
+
try {
|
|
1470
|
+
const entry = JSON.parse(line);
|
|
1471
|
+
if (entry.type === "event_msg" && entry.payload?.type === "patch_apply_end" && typeof entry.payload.call_id === "string") {
|
|
1472
|
+
callIds.push(entry.payload.call_id);
|
|
1473
|
+
}
|
|
1474
|
+
} catch {}
|
|
1475
|
+
}
|
|
1476
|
+
return callIds;
|
|
1477
|
+
}
|
|
1478
|
+
function readCodexPatchCallIds(threadId) {
|
|
1479
|
+
const path = latestCodexRolloutPath(threadId);
|
|
1480
|
+
if (!path)
|
|
1481
|
+
return [];
|
|
1482
|
+
try {
|
|
1483
|
+
return extractCodexPatchCallIds(readFileSync4(path, "utf8"));
|
|
1484
|
+
} catch (error) {
|
|
1485
|
+
logger.debug({ error, threadId }, "codex patch ids: rollout read failed");
|
|
1486
|
+
return [];
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
function readLatestCodexPatchPreview(threadId, expectedPaths, consumedCallIds = new Set, expectedCallId) {
|
|
1490
|
+
const path = latestCodexRolloutPath(threadId);
|
|
1491
|
+
if (!path)
|
|
1492
|
+
return;
|
|
1493
|
+
try {
|
|
1494
|
+
return extractLatestCodexPatchPreview(readFileSync4(path, "utf8"), expectedPaths, consumedCallIds, expectedCallId);
|
|
1495
|
+
} catch (error) {
|
|
1496
|
+
logger.debug({ error, threadId }, "codex patch preview: rollout read failed");
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1367
1500
|
function extractLatestCodexContextUsage(jsonl) {
|
|
1368
1501
|
const lines = jsonl.trimEnd().split(`
|
|
1369
1502
|
`);
|
|
@@ -1382,28 +1515,11 @@ function extractLatestCodexContextUsage(jsonl) {
|
|
|
1382
1515
|
return;
|
|
1383
1516
|
}
|
|
1384
1517
|
function readLatestCodexContextUsage(threadId) {
|
|
1385
|
-
const
|
|
1386
|
-
|
|
1387
|
-
|
|
1518
|
+
const path = latestCodexRolloutPath(threadId);
|
|
1519
|
+
if (!path)
|
|
1520
|
+
return;
|
|
1388
1521
|
try {
|
|
1389
|
-
|
|
1390
|
-
for (const bucket of buckets) {
|
|
1391
|
-
const dir = join7(sessionsDir, bucket);
|
|
1392
|
-
if (!existsSync5(dir))
|
|
1393
|
-
continue;
|
|
1394
|
-
const glob = new Bun.Glob(`rollout-*-${threadId}.jsonl`);
|
|
1395
|
-
for (const rel of glob.scanSync({ cwd: dir, onlyFiles: true })) {
|
|
1396
|
-
candidates.push(join7(dir, rel));
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
} else {
|
|
1400
|
-
const glob = new Bun.Glob(`**/rollout-*-${threadId}.jsonl`);
|
|
1401
|
-
for (const rel of glob.scanSync({ cwd: sessionsDir, onlyFiles: true })) {
|
|
1402
|
-
candidates.push(join7(sessionsDir, rel));
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
const path = candidates.sort((a, b) => statSync2(b).mtimeMs - statSync2(a).mtimeMs)[0];
|
|
1406
|
-
return path ? extractLatestCodexContextUsage(readFileSync4(path, "utf8")) : undefined;
|
|
1522
|
+
return extractLatestCodexContextUsage(readFileSync4(path, "utf8"));
|
|
1407
1523
|
} catch (error) {
|
|
1408
1524
|
logger.debug({ error, threadId }, "codex context usage: rollout read failed");
|
|
1409
1525
|
return;
|
|
@@ -1671,7 +1787,7 @@ import {
|
|
|
1671
1787
|
unlinkSync as unlinkSync5,
|
|
1672
1788
|
writeFileSync as writeFileSync4
|
|
1673
1789
|
} from "fs";
|
|
1674
|
-
import { dirname as
|
|
1790
|
+
import { dirname as dirname6, join as join9 } from "path";
|
|
1675
1791
|
|
|
1676
1792
|
// ../../packages/core/src/security/sanitize.ts
|
|
1677
1793
|
function sanitizeTopicName(name, lowercase = false) {
|
|
@@ -1688,7 +1804,7 @@ function sanitizeFileName(name) {
|
|
|
1688
1804
|
// ../../packages/core/src/storage/storage-host.ts
|
|
1689
1805
|
import { mkdirSync as mkdirSync6 } from "fs";
|
|
1690
1806
|
import { homedir as homedir6 } from "os";
|
|
1691
|
-
import { dirname as
|
|
1807
|
+
import { dirname as dirname5, join as join8, resolve as resolve4 } from "path";
|
|
1692
1808
|
var configuredHost = {};
|
|
1693
1809
|
var fallbackDatabase = null;
|
|
1694
1810
|
var fallbackDatabasePath = null;
|
|
@@ -1697,7 +1813,7 @@ var initializedSchemas = new WeakMap;
|
|
|
1697
1813
|
var initializingDatabases = new WeakSet;
|
|
1698
1814
|
function envPath(name, fallback) {
|
|
1699
1815
|
const value = process.env[name]?.trim();
|
|
1700
|
-
return
|
|
1816
|
+
return resolve4(value || fallback);
|
|
1701
1817
|
}
|
|
1702
1818
|
function defaultStateDir() {
|
|
1703
1819
|
return envPath("NEGOTIUM_STATE_DIR", join8(homedir6(), ".negotium"));
|
|
@@ -1726,7 +1842,7 @@ function defaultDatabase() {
|
|
|
1726
1842
|
return fallbackDatabase;
|
|
1727
1843
|
if (fallbackDatabase)
|
|
1728
1844
|
fallbackDatabase.close();
|
|
1729
|
-
mkdirSync6(
|
|
1845
|
+
mkdirSync6(dirname5(path), { recursive: true });
|
|
1730
1846
|
fallbackDatabase = new Database(path, { create: true });
|
|
1731
1847
|
fallbackDatabasePath = path;
|
|
1732
1848
|
initializeDatabase(fallbackDatabase);
|
|
@@ -1819,7 +1935,7 @@ function appendConversationEventStrict(userId, topicName, agent, event) {
|
|
|
1819
1935
|
agent,
|
|
1820
1936
|
event
|
|
1821
1937
|
};
|
|
1822
|
-
mkdirSync7(
|
|
1938
|
+
mkdirSync7(dirname6(path), { recursive: true });
|
|
1823
1939
|
appendJsonlLine(path, JSON.stringify(entry));
|
|
1824
1940
|
}
|
|
1825
1941
|
function readConversation(userId, topicName) {
|
|
@@ -1981,7 +2097,7 @@ function cleanupAgentFork(handle) {
|
|
|
1981
2097
|
}
|
|
1982
2098
|
// ../../packages/core/src/agents/archiver.ts
|
|
1983
2099
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
1984
|
-
import { existsSync as existsSync13, readdirSync as readdirSync2, readFileSync as
|
|
2100
|
+
import { existsSync as existsSync13, readdirSync as readdirSync2, readFileSync as readFileSync11, statSync as statSync5 } from "fs";
|
|
1985
2101
|
import { join as join15 } from "path";
|
|
1986
2102
|
|
|
1987
2103
|
// ../../packages/core/src/agents/index.ts
|
|
@@ -2014,8 +2130,8 @@ function deepMapStrings(value, fn) {
|
|
|
2014
2130
|
import { AsyncLocalStorage } from "async_hooks";
|
|
2015
2131
|
|
|
2016
2132
|
// ../../packages/core/src/security/sensitive-path.ts
|
|
2017
|
-
import { realpathSync } from "fs";
|
|
2018
|
-
import { resolve as
|
|
2133
|
+
import { realpathSync as realpathSync2 } from "fs";
|
|
2134
|
+
import { resolve as resolve5 } from "path";
|
|
2019
2135
|
var SENSITIVE_PATH_PATTERNS = [
|
|
2020
2136
|
/\/\.env(\.|$)/i,
|
|
2021
2137
|
/\/\.ssh\//i,
|
|
@@ -2032,11 +2148,11 @@ var SENSITIVE_PATH_PATTERNS = [
|
|
|
2032
2148
|
/\/sessions\.db(-wal|-shm|-journal)?$/i
|
|
2033
2149
|
];
|
|
2034
2150
|
function isSensitivePath(filePath) {
|
|
2035
|
-
const normalized =
|
|
2151
|
+
const normalized = resolve5(filePath);
|
|
2036
2152
|
if (SENSITIVE_PATH_PATTERNS.some((p) => p.test(normalized)))
|
|
2037
2153
|
return true;
|
|
2038
2154
|
try {
|
|
2039
|
-
const real =
|
|
2155
|
+
const real = realpathSync2(normalized);
|
|
2040
2156
|
if (real !== normalized)
|
|
2041
2157
|
return SENSITIVE_PATH_PATTERNS.some((p) => p.test(real));
|
|
2042
2158
|
} catch {}
|
|
@@ -2340,12 +2456,12 @@ function createBackgroundBashManager(options = {}) {
|
|
|
2340
2456
|
usedPorts.clear();
|
|
2341
2457
|
knownContexts.clear();
|
|
2342
2458
|
const deadline = now() + 3000;
|
|
2343
|
-
await Promise.all(entries.map((instance) => new Promise((
|
|
2459
|
+
await Promise.all(entries.map((instance) => new Promise((resolve6) => {
|
|
2344
2460
|
if (instance.process.exitCode !== null || instance.process.killed)
|
|
2345
|
-
return
|
|
2346
|
-
instance.process.once("exit",
|
|
2347
|
-
instance.process.once("error",
|
|
2348
|
-
const timer = setTimeout(
|
|
2461
|
+
return resolve6();
|
|
2462
|
+
instance.process.once("exit", resolve6);
|
|
2463
|
+
instance.process.once("error", resolve6);
|
|
2464
|
+
const timer = setTimeout(resolve6, Math.max(0, deadline - now()));
|
|
2349
2465
|
timer.unref?.();
|
|
2350
2466
|
})));
|
|
2351
2467
|
}
|
|
@@ -2606,11 +2722,10 @@ var MCP_CATALOG = {
|
|
|
2606
2722
|
},
|
|
2607
2723
|
"background-bash": {
|
|
2608
2724
|
...commonRuntimeMcpPolicy("background-bash"),
|
|
2609
|
-
build({ agent, bgBashPort, userId, topicId
|
|
2610
|
-
|
|
2611
|
-
if (bgBashPort === undefined || !topic)
|
|
2725
|
+
build({ agent, bgBashPort, userId, topicId }) {
|
|
2726
|
+
if (bgBashPort === undefined || !topicId)
|
|
2612
2727
|
return null;
|
|
2613
|
-
return backgroundBashTransport(agent, bgBashPort, userId,
|
|
2728
|
+
return backgroundBashTransport(agent, bgBashPort, userId, topicId);
|
|
2614
2729
|
}
|
|
2615
2730
|
},
|
|
2616
2731
|
"agent-health": {
|
|
@@ -3365,7 +3480,8 @@ async function* claudeProvider(opts) {
|
|
|
3365
3480
|
yield {
|
|
3366
3481
|
type: "tool_result",
|
|
3367
3482
|
toolUseId: trBlock.tool_use_id || "",
|
|
3368
|
-
content: trContent
|
|
3483
|
+
content: trContent,
|
|
3484
|
+
...trBlock.is_error ? { isError: true } : {}
|
|
3369
3485
|
};
|
|
3370
3486
|
}
|
|
3371
3487
|
}
|
|
@@ -3379,7 +3495,9 @@ async function* claudeProvider(opts) {
|
|
|
3379
3495
|
}
|
|
3380
3496
|
|
|
3381
3497
|
// ../../packages/core/src/agents/codex-provider.ts
|
|
3382
|
-
import {
|
|
3498
|
+
import { execFileSync as execFileSync5 } from "child_process";
|
|
3499
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8, realpathSync as realpathSync3, statSync as statSync3 } from "fs";
|
|
3500
|
+
import { isAbsolute, relative, resolve as resolve6 } from "path";
|
|
3383
3501
|
import { Codex } from "@openai/codex-sdk";
|
|
3384
3502
|
|
|
3385
3503
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
@@ -3398,10 +3516,10 @@ import {
|
|
|
3398
3516
|
} from "fs";
|
|
3399
3517
|
import { createRequire } from "module";
|
|
3400
3518
|
import { tmpdir } from "os";
|
|
3401
|
-
import { dirname as
|
|
3519
|
+
import { dirname as dirname7, join as join11 } from "path";
|
|
3402
3520
|
|
|
3403
3521
|
// ../../packages/core/src/version.ts
|
|
3404
|
-
var NEGOTIUM_VERSION = "0.1.
|
|
3522
|
+
var NEGOTIUM_VERSION = "0.1.31";
|
|
3405
3523
|
|
|
3406
3524
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
3407
3525
|
var moduleRequire = createRequire(import.meta.url);
|
|
@@ -3420,7 +3538,7 @@ var SAFE_BUNDLED_CODEX_VERSION = BUNDLED_CODEX_VERSION.replace(/[^a-zA-Z0-9._-]/
|
|
|
3420
3538
|
var NEGOTIUM_MODEL_CACHE = `negotium-models-cache-${SAFE_BUNDLED_CODEX_VERSION}.json`;
|
|
3421
3539
|
var NEGOTIUM_MODEL_CATALOG = `negotium-model-catalog-${SAFE_BUNDLED_CODEX_VERSION}.json`;
|
|
3422
3540
|
function codexCliScriptPath() {
|
|
3423
|
-
return join11(
|
|
3541
|
+
return join11(dirname7(bundledCodexPackagePath), "bin", "codex.js");
|
|
3424
3542
|
}
|
|
3425
3543
|
function parseCodexModelCache(contents, sourcePath) {
|
|
3426
3544
|
let parsed;
|
|
@@ -3461,14 +3579,14 @@ function writePrivateFileAtomic(path, contents) {
|
|
|
3461
3579
|
}
|
|
3462
3580
|
}
|
|
3463
3581
|
function bundledCodexModelCachePath(authFilePath) {
|
|
3464
|
-
return join11(
|
|
3582
|
+
return join11(dirname7(authFilePath), NEGOTIUM_MODEL_CACHE);
|
|
3465
3583
|
}
|
|
3466
3584
|
async function bootstrapCodexModelCache(codexHome, cachePath) {
|
|
3467
3585
|
const child = spawn3(process.execPath, [codexCliScriptPath(), "app-server", "--stdio"], {
|
|
3468
3586
|
env: { ...process.env, CODEX_HOME: codexHome },
|
|
3469
3587
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3470
3588
|
});
|
|
3471
|
-
await new Promise((
|
|
3589
|
+
await new Promise((resolve6, reject) => {
|
|
3472
3590
|
let settled = false;
|
|
3473
3591
|
let stdoutBuffer = "";
|
|
3474
3592
|
let stderr = "";
|
|
@@ -3487,7 +3605,7 @@ async function bootstrapCodexModelCache(codexHome, cachePath) {
|
|
|
3487
3605
|
else if (!existsSync9(cachePath))
|
|
3488
3606
|
reject(new Error("Codex did not create its model cache"));
|
|
3489
3607
|
else
|
|
3490
|
-
|
|
3608
|
+
resolve6();
|
|
3491
3609
|
};
|
|
3492
3610
|
const send = (message) => {
|
|
3493
3611
|
child.stdin.write(`${JSON.stringify(message)}
|
|
@@ -3546,7 +3664,7 @@ async function bootstrapCodexModelCache(codexHome, cachePath) {
|
|
|
3546
3664
|
});
|
|
3547
3665
|
}
|
|
3548
3666
|
async function bootstrapIsolatedCodexModelCache(authFilePath, bootstrap) {
|
|
3549
|
-
const sourceHome =
|
|
3667
|
+
const sourceHome = dirname7(authFilePath);
|
|
3550
3668
|
const isolatedHome = mkdtempSync(join11(tmpdir(), "negotium-codex-models-"));
|
|
3551
3669
|
const isolatedCachePath = join11(isolatedHome, "models_cache.json");
|
|
3552
3670
|
try {
|
|
@@ -3566,7 +3684,7 @@ async function bootstrapIsolatedCodexModelCache(authFilePath, bootstrap) {
|
|
|
3566
3684
|
}
|
|
3567
3685
|
}
|
|
3568
3686
|
async function ensureCodexModelCache(authFilePath, bootstrap = bootstrapCodexModelCache) {
|
|
3569
|
-
const codexHome =
|
|
3687
|
+
const codexHome = dirname7(authFilePath);
|
|
3570
3688
|
const configuredCachePath = process.env.NEGOTIUM_CODEX_MODELS_CACHE_FILE;
|
|
3571
3689
|
if (configuredCachePath) {
|
|
3572
3690
|
if (!existsSync9(configuredCachePath)) {
|
|
@@ -3595,7 +3713,7 @@ async function ensureCodexModelCache(authFilePath, bootstrap = bootstrapCodexMod
|
|
|
3595
3713
|
return bundledCachePath;
|
|
3596
3714
|
}
|
|
3597
3715
|
function writeCodexCatalogWithNativeMultiAgentDisabled(authFilePath, sourcePath) {
|
|
3598
|
-
const codexHome =
|
|
3716
|
+
const codexHome = dirname7(authFilePath);
|
|
3599
3717
|
const outputPath = join11(codexHome, NEGOTIUM_MODEL_CATALOG);
|
|
3600
3718
|
const parsed = readCodexModelCache(sourcePath).parsed;
|
|
3601
3719
|
const models = parsed.models.map((model, index) => {
|
|
@@ -3610,6 +3728,52 @@ function writeCodexCatalogWithNativeMultiAgentDisabled(authFilePath, sourcePath)
|
|
|
3610
3728
|
return outputPath;
|
|
3611
3729
|
}
|
|
3612
3730
|
|
|
3731
|
+
// ../../packages/core/src/agents/tool-format.ts
|
|
3732
|
+
import { diffLines as computeLineDiff } from "diff";
|
|
3733
|
+
function changedDiffLines(value) {
|
|
3734
|
+
const lines = value.split(`
|
|
3735
|
+
`);
|
|
3736
|
+
if (lines.at(-1) === "")
|
|
3737
|
+
lines.pop();
|
|
3738
|
+
return lines;
|
|
3739
|
+
}
|
|
3740
|
+
function buildNumberedDiffSummary(before, after, startLine = 1) {
|
|
3741
|
+
const removed = [];
|
|
3742
|
+
const added = [];
|
|
3743
|
+
const preview = [];
|
|
3744
|
+
let oldLine = startLine;
|
|
3745
|
+
let newLine = startLine;
|
|
3746
|
+
for (const part of computeLineDiff(before, after)) {
|
|
3747
|
+
const lines = changedDiffLines(part.value);
|
|
3748
|
+
if (part.removed) {
|
|
3749
|
+
for (const line of lines) {
|
|
3750
|
+
removed.push(line);
|
|
3751
|
+
preview.push(`${oldLine} -${line}`);
|
|
3752
|
+
oldLine += 1;
|
|
3753
|
+
}
|
|
3754
|
+
continue;
|
|
3755
|
+
}
|
|
3756
|
+
if (part.added) {
|
|
3757
|
+
for (const line of lines) {
|
|
3758
|
+
added.push(line);
|
|
3759
|
+
preview.push(`${newLine} +${line}`);
|
|
3760
|
+
newLine += 1;
|
|
3761
|
+
}
|
|
3762
|
+
continue;
|
|
3763
|
+
}
|
|
3764
|
+
oldLine += lines.length;
|
|
3765
|
+
newLine += lines.length;
|
|
3766
|
+
}
|
|
3767
|
+
return {
|
|
3768
|
+
...removed.length > 0 ? { before: removed.join(`
|
|
3769
|
+
`) } : {},
|
|
3770
|
+
...added.length > 0 ? { after: added.join(`
|
|
3771
|
+
`) } : {},
|
|
3772
|
+
...preview.length > 0 ? { diffPreview: preview.join(`
|
|
3773
|
+
`) } : {}
|
|
3774
|
+
};
|
|
3775
|
+
}
|
|
3776
|
+
|
|
3613
3777
|
// ../../packages/core/src/agents/codex-provider.ts
|
|
3614
3778
|
function mapEffort(effort) {
|
|
3615
3779
|
if (!effort)
|
|
@@ -3692,22 +3856,142 @@ function summarizeMcpToolCallResult(item) {
|
|
|
3692
3856
|
return text.slice(0, 200);
|
|
3693
3857
|
return JSON.stringify(item.result.structured_content ?? "").slice(0, 200);
|
|
3694
3858
|
}
|
|
3695
|
-
|
|
3859
|
+
var CODEX_DIFF_FILE_LIMIT = 512 * 1024;
|
|
3860
|
+
var CODEX_DIFF_BASELINE_FILE_LIMIT = 200;
|
|
3861
|
+
var CODEX_DIFF_BASELINE_BYTE_LIMIT = 16 * 1024 * 1024;
|
|
3862
|
+
function canonicalPath(path) {
|
|
3863
|
+
try {
|
|
3864
|
+
return realpathSync3(resolve6(path));
|
|
3865
|
+
} catch {
|
|
3866
|
+
return resolve6(path);
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3869
|
+
function textFile(path, maxBytes = CODEX_DIFF_FILE_LIMIT) {
|
|
3870
|
+
if (!existsSync10(path))
|
|
3871
|
+
return null;
|
|
3872
|
+
try {
|
|
3873
|
+
const byteLimit = Math.min(CODEX_DIFF_FILE_LIMIT, Math.max(0, maxBytes));
|
|
3874
|
+
if (statSync3(path).size > byteLimit)
|
|
3875
|
+
return;
|
|
3876
|
+
const content = readFileSync8(path);
|
|
3877
|
+
if (content.byteLength > byteLimit || content.includes(0))
|
|
3878
|
+
return;
|
|
3879
|
+
return content.toString("utf8");
|
|
3880
|
+
} catch {
|
|
3881
|
+
return;
|
|
3882
|
+
}
|
|
3883
|
+
}
|
|
3884
|
+
|
|
3885
|
+
class CodexFilePreviewTracker {
|
|
3886
|
+
#cwd;
|
|
3887
|
+
#root;
|
|
3888
|
+
#baseline = new Map;
|
|
3889
|
+
#baselineAvailable = false;
|
|
3890
|
+
constructor(cwd) {
|
|
3891
|
+
this.#cwd = canonicalPath(cwd);
|
|
3892
|
+
const root = this.#git(["rev-parse", "--show-toplevel"], this.#cwd)?.trim();
|
|
3893
|
+
this.#root = root ? canonicalPath(root) : null;
|
|
3894
|
+
if (!this.#root)
|
|
3895
|
+
return;
|
|
3896
|
+
const status = this.#git(["status", "--porcelain=v1", "-z", "--untracked-files=all"]);
|
|
3897
|
+
if (status === undefined)
|
|
3898
|
+
return;
|
|
3899
|
+
this.#baselineAvailable = true;
|
|
3900
|
+
let loadedFiles = 0;
|
|
3901
|
+
let loadedBytes = 0;
|
|
3902
|
+
const records = status.split("\x00");
|
|
3903
|
+
for (let index = 0;index < records.length; index += 1) {
|
|
3904
|
+
const record = records[index];
|
|
3905
|
+
if (!record || record.length < 4)
|
|
3906
|
+
continue;
|
|
3907
|
+
const code = record.slice(0, 2);
|
|
3908
|
+
const path = record.slice(3);
|
|
3909
|
+
const remainingBytes = CODEX_DIFF_BASELINE_BYTE_LIMIT - loadedBytes;
|
|
3910
|
+
const content = loadedFiles < CODEX_DIFF_BASELINE_FILE_LIMIT && remainingBytes > 0 ? textFile(resolve6(this.#root, path), remainingBytes) : undefined;
|
|
3911
|
+
this.#baseline.set(path, content);
|
|
3912
|
+
if (typeof content === "string") {
|
|
3913
|
+
loadedFiles += 1;
|
|
3914
|
+
loadedBytes += Buffer.byteLength(content);
|
|
3915
|
+
}
|
|
3916
|
+
if (/[RC]/.test(code))
|
|
3917
|
+
index += 1;
|
|
3918
|
+
}
|
|
3919
|
+
}
|
|
3920
|
+
preview(path, succeeded) {
|
|
3921
|
+
if (!this.#root || !this.#baselineAvailable || !succeeded)
|
|
3922
|
+
return {};
|
|
3923
|
+
const absolute = canonicalPath(isAbsolute(path) ? path : resolve6(this.#cwd, path));
|
|
3924
|
+
const relativePath = relative(this.#root, absolute);
|
|
3925
|
+
if (!relativePath || relativePath.startsWith("..") || isAbsolute(relativePath))
|
|
3926
|
+
return {};
|
|
3927
|
+
const before = this.#baseline.has(relativePath) ? this.#baseline.get(relativePath) : this.#headFile(relativePath);
|
|
3928
|
+
const after = textFile(absolute);
|
|
3929
|
+
this.#baseline.set(relativePath, after);
|
|
3930
|
+
if (before === undefined || after === undefined)
|
|
3931
|
+
return {};
|
|
3932
|
+
const diff = buildNumberedDiffSummary(before ?? "", after ?? "");
|
|
3933
|
+
return {
|
|
3934
|
+
...diff.before !== undefined ? { before: diff.before } : {},
|
|
3935
|
+
...diff.after !== undefined ? { after: diff.after } : {},
|
|
3936
|
+
...diff.diffPreview !== undefined ? { diff_preview: diff.diffPreview } : {}
|
|
3937
|
+
};
|
|
3938
|
+
}
|
|
3939
|
+
#headFile(path) {
|
|
3940
|
+
const content = this.#git(["show", `HEAD:${path}`]);
|
|
3941
|
+
if (content === undefined)
|
|
3942
|
+
return null;
|
|
3943
|
+
return Buffer.byteLength(content) > CODEX_DIFF_FILE_LIMIT || content.includes("\x00") ? undefined : content;
|
|
3944
|
+
}
|
|
3945
|
+
#git(args, cwd = this.#root ?? undefined) {
|
|
3946
|
+
try {
|
|
3947
|
+
return execFileSync5("git", ["-C", cwd ?? ".", ...args], {
|
|
3948
|
+
encoding: "utf8",
|
|
3949
|
+
maxBuffer: CODEX_DIFF_FILE_LIMIT * 4,
|
|
3950
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
3951
|
+
});
|
|
3952
|
+
} catch {
|
|
3953
|
+
return;
|
|
3954
|
+
}
|
|
3955
|
+
}
|
|
3956
|
+
}
|
|
3957
|
+
async function fileChangeEvents(item, previews, cwd, threadId, consumedPatchCallIds) {
|
|
3958
|
+
const expectedPaths = item.changes.map((change) => isAbsolute(change.path) ? change.path : resolve6(cwd, change.path));
|
|
3959
|
+
let nativePreview;
|
|
3960
|
+
if (threadId && item.status === "completed") {
|
|
3961
|
+
await new Promise((resolveDelay) => setTimeout(resolveDelay, 20));
|
|
3962
|
+
nativePreview = readLatestCodexPatchPreview(threadId, expectedPaths, consumedPatchCallIds);
|
|
3963
|
+
}
|
|
3964
|
+
for (const delayMs of [20, 40, 80, 120]) {
|
|
3965
|
+
if (nativePreview || !threadId || item.status !== "completed")
|
|
3966
|
+
break;
|
|
3967
|
+
await new Promise((resolveDelay) => setTimeout(resolveDelay, delayMs));
|
|
3968
|
+
nativePreview = readLatestCodexPatchPreview(threadId, expectedPaths, consumedPatchCallIds);
|
|
3969
|
+
}
|
|
3970
|
+
if (nativePreview)
|
|
3971
|
+
consumedPatchCallIds.add(nativePreview.callId);
|
|
3696
3972
|
return item.changes.flatMap((change, index) => {
|
|
3697
3973
|
const name = change.kind === "add" ? "Write" : change.kind === "delete" ? "Delete" : "Edit";
|
|
3698
3974
|
const toolUseId = `${item.id}:${index}`;
|
|
3699
3975
|
const success = item.status === "completed";
|
|
3976
|
+
const nativeChange = nativePreview?.changes[index];
|
|
3977
|
+
const fallbackPreview = previews.preview(change.path, success);
|
|
3978
|
+
const preview = success && nativeChange ? {
|
|
3979
|
+
...nativeChange.before !== undefined ? { before: nativeChange.before } : {},
|
|
3980
|
+
...nativeChange.after !== undefined ? { after: nativeChange.after } : {},
|
|
3981
|
+
...nativeChange.diffPreview !== undefined ? { diff_preview: nativeChange.diffPreview } : {}
|
|
3982
|
+
} : fallbackPreview;
|
|
3700
3983
|
return [
|
|
3701
3984
|
{
|
|
3702
3985
|
type: "tool_use",
|
|
3703
3986
|
name,
|
|
3704
|
-
input: { file_path: change.path, change_kind: change.kind },
|
|
3987
|
+
input: { file_path: change.path, change_kind: change.kind, ...preview },
|
|
3705
3988
|
toolUseId
|
|
3706
3989
|
},
|
|
3707
3990
|
{
|
|
3708
3991
|
type: "tool_result",
|
|
3709
3992
|
toolUseId,
|
|
3710
|
-
content: success ? `${change.kind} applied: ${change.path}` : `${change.kind} failed: ${change.path}
|
|
3993
|
+
content: success ? `${change.kind} applied: ${change.path}` : `${change.kind} failed: ${change.path}`,
|
|
3994
|
+
...success ? {} : { isError: true }
|
|
3711
3995
|
}
|
|
3712
3996
|
];
|
|
3713
3997
|
});
|
|
@@ -3793,6 +4077,8 @@ function prependFirstEvent(iter, firstEvent, alreadyDone) {
|
|
|
3793
4077
|
};
|
|
3794
4078
|
}
|
|
3795
4079
|
async function* codexProvider(opts) {
|
|
4080
|
+
const filePreviews = new CodexFilePreviewTracker(opts.cwd);
|
|
4081
|
+
const consumedPatchCallIds = new Set(opts.sessionId ? readCodexPatchCallIds(opts.sessionId) : []);
|
|
3796
4082
|
const codexAuthPath = hostedCodexAuthFilePath();
|
|
3797
4083
|
if (!existsSync10(codexAuthPath)) {
|
|
3798
4084
|
yield {
|
|
@@ -3927,10 +4213,11 @@ async function* codexProvider(opts) {
|
|
|
3927
4213
|
if (!item)
|
|
3928
4214
|
break;
|
|
3929
4215
|
if (item.type === "command_execution") {
|
|
4216
|
+
const command = String(item.command ?? "");
|
|
3930
4217
|
yield {
|
|
3931
4218
|
type: "tool_use",
|
|
3932
4219
|
name: "Bash",
|
|
3933
|
-
input: { command
|
|
4220
|
+
input: { command },
|
|
3934
4221
|
toolUseId: String(item.id ?? "")
|
|
3935
4222
|
};
|
|
3936
4223
|
} else if (item.type === "mcp_tool_call") {
|
|
@@ -3976,19 +4263,24 @@ async function* codexProvider(opts) {
|
|
|
3976
4263
|
if (reasoning)
|
|
3977
4264
|
yield { type: "reasoning", content: reasoning };
|
|
3978
4265
|
} else if (item.type === "mcp_tool_call") {
|
|
4266
|
+
const isError = item.status === "failed" || Boolean(item.error);
|
|
3979
4267
|
yield {
|
|
3980
4268
|
type: "tool_result",
|
|
3981
4269
|
toolUseId: String(item.id ?? ""),
|
|
3982
|
-
content: summarizeMcpToolCallResult(item)
|
|
4270
|
+
content: summarizeMcpToolCallResult(item),
|
|
4271
|
+
...isError ? { isError: true } : {}
|
|
3983
4272
|
};
|
|
3984
4273
|
} else if (item.type === "command_execution") {
|
|
4274
|
+
const isError = item.status === "failed" || typeof item.exit_code === "number" && item.exit_code !== 0;
|
|
3985
4275
|
yield {
|
|
3986
4276
|
type: "tool_result",
|
|
3987
4277
|
toolUseId: String(item.id ?? ""),
|
|
3988
|
-
content: String(item.aggregated_output ?? "").slice(0, 200)
|
|
4278
|
+
content: String(item.aggregated_output ?? "").slice(0, 200),
|
|
4279
|
+
...isError ? { isError: true } : {}
|
|
3989
4280
|
};
|
|
3990
4281
|
} else if (item.type === "file_change") {
|
|
3991
|
-
|
|
4282
|
+
const fileEvents = await fileChangeEvents(item, filePreviews, opts.cwd, currentSessionId, consumedPatchCallIds);
|
|
4283
|
+
for (const fileEvent of fileEvents) {
|
|
3992
4284
|
yield fileEvent;
|
|
3993
4285
|
}
|
|
3994
4286
|
} else if (item.type === "error") {
|
|
@@ -4184,8 +4476,8 @@ function maestroProvider(opts) {
|
|
|
4184
4476
|
}
|
|
4185
4477
|
|
|
4186
4478
|
// ../../packages/core/src/storage/tasks.ts
|
|
4187
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as
|
|
4188
|
-
import { dirname as
|
|
4479
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync9, renameSync as renameSync5, statSync as statSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
4480
|
+
import { dirname as dirname8, join as join12 } from "path";
|
|
4189
4481
|
function safeUserIdComponent2(userId) {
|
|
4190
4482
|
const str = String(userId);
|
|
4191
4483
|
if (!str || /[/\\]|\.\./.test(str)) {
|
|
@@ -4211,7 +4503,7 @@ function readTasks(userId, scopeKey) {
|
|
|
4211
4503
|
if (!existsSync11(path))
|
|
4212
4504
|
return [];
|
|
4213
4505
|
try {
|
|
4214
|
-
const parsed = JSON.parse(
|
|
4506
|
+
const parsed = JSON.parse(readFileSync9(path, "utf-8"));
|
|
4215
4507
|
return Array.isArray(parsed?.tasks) ? parsed.tasks : [];
|
|
4216
4508
|
} catch (e) {
|
|
4217
4509
|
logger.warn({ err: e, path }, "tasks: failed to read task store");
|
|
@@ -4220,7 +4512,7 @@ function readTasks(userId, scopeKey) {
|
|
|
4220
4512
|
}
|
|
4221
4513
|
function taskFileMtimeNs(userId, scopeKey) {
|
|
4222
4514
|
try {
|
|
4223
|
-
return
|
|
4515
|
+
return statSync4(getTaskFilePath(userId, scopeKey), { bigint: true }).mtimeNs;
|
|
4224
4516
|
} catch {
|
|
4225
4517
|
return null;
|
|
4226
4518
|
}
|
|
@@ -4541,9 +4833,15 @@ class SqliteRuntimeBus {
|
|
|
4541
4833
|
toolUseId: id
|
|
4542
4834
|
});
|
|
4543
4835
|
}
|
|
4544
|
-
broadcastToolOutput(topicId, queryId, toolUseId, content) {
|
|
4836
|
+
broadcastToolOutput(topicId, queryId, toolUseId, content, isError) {
|
|
4545
4837
|
const id = toolUseId.trim() || `${queryId}:tool`;
|
|
4546
|
-
this.broadcastAiStatus(topicId, {
|
|
4838
|
+
this.broadcastAiStatus(topicId, {
|
|
4839
|
+
kind: "tool_output",
|
|
4840
|
+
queryId,
|
|
4841
|
+
toolUseId: id,
|
|
4842
|
+
content,
|
|
4843
|
+
...isError ? { isError: true } : {}
|
|
4844
|
+
});
|
|
4547
4845
|
}
|
|
4548
4846
|
broadcastToolStatus(topicId, queryId, kind, content, meta) {
|
|
4549
4847
|
this.broadcastAiStatus(topicId, {
|
|
@@ -4585,8 +4883,8 @@ var WsHub = {
|
|
|
4585
4883
|
};
|
|
4586
4884
|
|
|
4587
4885
|
// ../../packages/core/src/prompts/builders.ts
|
|
4588
|
-
import { readFileSync as
|
|
4589
|
-
import { resolve as
|
|
4886
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
4887
|
+
import { resolve as resolve7 } from "path";
|
|
4590
4888
|
|
|
4591
4889
|
// ../../packages/core/src/agents/model-catalog.ts
|
|
4592
4890
|
var CODEX_PRO_20X_COST = "ChatGPT Pro 20x subscription: $200/month";
|
|
@@ -4687,10 +4985,10 @@ var SELECTABLE_MODELS = [
|
|
|
4687
4985
|
];
|
|
4688
4986
|
|
|
4689
4987
|
// ../../packages/core/src/prompts/builders.ts
|
|
4690
|
-
var PROMPTS_DIR =
|
|
4691
|
-
var SESSIONS_DIR =
|
|
4988
|
+
var PROMPTS_DIR = resolve7(PROJECT_ROOT, "src/prompts");
|
|
4989
|
+
var SESSIONS_DIR = resolve7(PROMPTS_DIR, "sessions");
|
|
4692
4990
|
function loadAgentPrompt(filename) {
|
|
4693
|
-
const raw =
|
|
4991
|
+
const raw = readFileSync10(resolve7(AGENTS_PROMPTS_DIR, filename), "utf-8");
|
|
4694
4992
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
4695
4993
|
if (!match)
|
|
4696
4994
|
throw new Error(`Agent prompt ${filename} is missing frontmatter`);
|
|
@@ -4871,7 +5169,7 @@ function setTopicBrief(topicId, fields) {
|
|
|
4871
5169
|
}
|
|
4872
5170
|
|
|
4873
5171
|
// ../../packages/core/src/storage/wiki.ts
|
|
4874
|
-
import { basename, dirname as
|
|
5172
|
+
import { basename as basename2, dirname as dirname9, join as join14 } from "path";
|
|
4875
5173
|
function getSharedWikiDir(workspaceDir = resolveStorageWorkspaceDir()) {
|
|
4876
5174
|
return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() : join14(workspaceDir, "wiki");
|
|
4877
5175
|
}
|
|
@@ -4884,7 +5182,11 @@ function isEphemeralWikiTopicId(topicId) {
|
|
|
4884
5182
|
return topicId?.startsWith("__") ?? false;
|
|
4885
5183
|
}
|
|
4886
5184
|
function wikiSummaryStorageSlug(rawTopic, topicId) {
|
|
4887
|
-
|
|
5185
|
+
const titleSlug = wikiSummarySlug(rawTopic);
|
|
5186
|
+
if (!topicId || isEphemeralWikiTopicId(topicId))
|
|
5187
|
+
return titleSlug;
|
|
5188
|
+
const idSlug = wikiSummarySlug(topicId);
|
|
5189
|
+
return titleSlug === idSlug ? idSlug : `${titleSlug}--${idSlug}`;
|
|
4888
5190
|
}
|
|
4889
5191
|
function wikiSummaryFilename(date, rawTopic, topicId) {
|
|
4890
5192
|
return `${date}-${wikiSummaryStorageSlug(rawTopic, topicId)}.md`;
|
|
@@ -5595,7 +5897,7 @@ function findSummaryFile(topicTitle, date, sinceMs, topicId) {
|
|
|
5595
5897
|
continue;
|
|
5596
5898
|
const p = join15(dir, f);
|
|
5597
5899
|
try {
|
|
5598
|
-
const m =
|
|
5900
|
+
const m = statSync5(p).mtimeMs;
|
|
5599
5901
|
if (m >= sinceMs && (!best || m > best.mtime))
|
|
5600
5902
|
best = { path: p, mtime: m };
|
|
5601
5903
|
} catch {}
|
|
@@ -5607,7 +5909,7 @@ function finalizeGeneralMemory(userId, topicTitle, messageCount, startMs, ok, to
|
|
|
5607
5909
|
const date = new Date().toISOString().slice(0, 10);
|
|
5608
5910
|
try {
|
|
5609
5911
|
const summaryPath = ok ? findSummaryFile(topicTitle, date, startMs, topicId) : null;
|
|
5610
|
-
const summaryMd = summaryPath ?
|
|
5912
|
+
const summaryMd = summaryPath ? readFileSync11(summaryPath, "utf-8") : "";
|
|
5611
5913
|
const oneLine = summaryMd && distillOneLine(summaryMd) || `${messageCount}\uAC1C \uBA54\uC2DC\uC9C0 \uC544\uCE74\uC774\uBE0C`;
|
|
5612
5914
|
const prev = getTopicBrief(generalTopicId);
|
|
5613
5915
|
const prevEntries = (prev?.briefMd ?? "").split(`
|
|
@@ -6567,4 +6869,4 @@ export {
|
|
|
6567
6869
|
MIN_MEMORY_ARCHIVE_EXCHANGES
|
|
6568
6870
|
};
|
|
6569
6871
|
|
|
6570
|
-
//# debugId=
|
|
6872
|
+
//# debugId=F639F58BC810D1BD64756E2164756E21
|