negotium 0.2.2 → 0.2.3
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 +131 -133
- package/dist/agent-helpers.js.map +4 -4
- package/dist/{chunk-kc5kmr95.js → chunk-hsqgb2hw.js} +22 -24
- package/dist/{chunk-kc5kmr95.js.map → chunk-hsqgb2hw.js.map} +3 -3
- package/dist/hosted-agent.js +34 -36
- package/dist/hosted-agent.js.map +4 -4
- package/dist/main.js +291 -918
- package/dist/main.js.map +7 -9
- package/dist/mcp-factories.js +135 -137
- package/dist/mcp-factories.js.map +4 -4
- package/dist/registry.js +1 -1
- package/dist/rollout.js +1 -1
- package/dist/runtime/src/agents/rollout/shared.ts +3 -5
- package/dist/runtime/src/version.ts +1 -1
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/dist/runtime/src/migration/single-user.ts +0 -805
package/dist/main.js
CHANGED
|
@@ -1005,8 +1005,7 @@ function renderUserPromptBatch(prompts) {
|
|
|
1005
1005
|
|
|
1006
1006
|
// ../../packages/core/src/agents/rollout/shared.ts
|
|
1007
1007
|
import { mkdirSync as mkdirSync3 } from "fs";
|
|
1008
|
-
import {
|
|
1009
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1008
|
+
import { resolve as resolve2 } from "path";
|
|
1010
1009
|
function clone(obj) {
|
|
1011
1010
|
return structuredClone(obj);
|
|
1012
1011
|
}
|
|
@@ -1137,18 +1136,17 @@ ${toolBuffer.join(`
|
|
|
1137
1136
|
flushAssistant();
|
|
1138
1137
|
return pairs;
|
|
1139
1138
|
}
|
|
1140
|
-
var
|
|
1139
|
+
var trustedWorkspaceRoots, FIXTURES_DIR, UUID_RE;
|
|
1141
1140
|
var init_shared = __esm(() => {
|
|
1142
1141
|
init_config();
|
|
1143
1142
|
init_logger();
|
|
1144
|
-
__dirname2 = dirname2(fileURLToPath2(import.meta.url));
|
|
1145
1143
|
trustedWorkspaceRoots = [
|
|
1146
1144
|
WORKSPACE_DIR,
|
|
1147
1145
|
DM_WORKSPACE_DIR,
|
|
1148
1146
|
SESSION_WORKSPACE_DIR,
|
|
1149
1147
|
TOPIC_WORKSPACE_DIR
|
|
1150
1148
|
].map((root) => resolve2(root));
|
|
1151
|
-
FIXTURES_DIR =
|
|
1149
|
+
FIXTURES_DIR = resolve2(PROJECT_ROOT, "src", "agents", "fixtures");
|
|
1152
1150
|
UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1153
1151
|
});
|
|
1154
1152
|
|
|
@@ -1191,7 +1189,7 @@ import {
|
|
|
1191
1189
|
unlinkSync as unlinkSync2,
|
|
1192
1190
|
writeFileSync as writeFileSync2
|
|
1193
1191
|
} from "fs";
|
|
1194
|
-
import { dirname as
|
|
1192
|
+
import { dirname as dirname2 } from "path";
|
|
1195
1193
|
function readJsonlLines(filePath) {
|
|
1196
1194
|
return readFileSync2(filePath, "utf-8").trim().split(`
|
|
1197
1195
|
`).filter(Boolean);
|
|
@@ -1239,7 +1237,7 @@ function appendJsonlEntry(filePath, entry) {
|
|
|
1239
1237
|
`);
|
|
1240
1238
|
}
|
|
1241
1239
|
function appendJsonlLine(filePath, line) {
|
|
1242
|
-
mkdirSync4(
|
|
1240
|
+
mkdirSync4(dirname2(filePath), { recursive: true });
|
|
1243
1241
|
const lockPath = `${filePath}${LOCK_SUFFIX}`;
|
|
1244
1242
|
const payload = line.endsWith(`
|
|
1245
1243
|
`) ? line : `${line}
|
|
@@ -1270,7 +1268,7 @@ function appendJsonlLine(filePath, line) {
|
|
|
1270
1268
|
}
|
|
1271
1269
|
}
|
|
1272
1270
|
function writeJsonlFile(filePath, entries) {
|
|
1273
|
-
const dir =
|
|
1271
|
+
const dir = dirname2(filePath);
|
|
1274
1272
|
mkdirSync4(dir, { recursive: true });
|
|
1275
1273
|
const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
1276
1274
|
const payload = `${entries.map((e) => JSON.stringify(e)).join(`
|
|
@@ -1330,11 +1328,11 @@ var init_jsonl = __esm(() => {
|
|
|
1330
1328
|
import { randomUUID } from "crypto";
|
|
1331
1329
|
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
1332
1330
|
import { homedir as homedir3 } from "os";
|
|
1333
|
-
import { join as
|
|
1331
|
+
import { join as join4 } from "path";
|
|
1334
1332
|
function loadClaudeAttachments() {
|
|
1335
1333
|
if (_attachmentsCache)
|
|
1336
1334
|
return _attachmentsCache;
|
|
1337
|
-
const raw = readFileSync3(
|
|
1335
|
+
const raw = readFileSync3(join4(FIXTURES_DIR, "claude-attachments.jsonl"), "utf8");
|
|
1338
1336
|
const lines = parseJsonlText(raw);
|
|
1339
1337
|
if (lines.length < 2) {
|
|
1340
1338
|
throw new Error(`loadClaudeAttachments: expected >=2 entries in claude-attachments.jsonl, got ${lines.length}`);
|
|
@@ -1435,8 +1433,8 @@ function writeClaudeRollout(opts) {
|
|
|
1435
1433
|
});
|
|
1436
1434
|
lastUuid = assistantUuid;
|
|
1437
1435
|
}
|
|
1438
|
-
const projectsDir =
|
|
1439
|
-
const path =
|
|
1436
|
+
const projectsDir = join4(homedir3(), ".claude", "projects", encodeClaudeCwd(opts.cwd));
|
|
1437
|
+
const path = join4(projectsDir, `${sessionId}.jsonl`);
|
|
1440
1438
|
writeJsonlFile(path, lines);
|
|
1441
1439
|
logger.info({ sessionId, path, pairs: pairs.length }, "writeClaudeRollout: synthetic rollout placed");
|
|
1442
1440
|
return { sessionId, rolloutPath: path };
|
|
@@ -1451,7 +1449,7 @@ var init_claude = __esm(() => {
|
|
|
1451
1449
|
// ../../packages/core/src/agents/claude-registry.ts
|
|
1452
1450
|
import { existsSync as existsSync4, mkdirSync as mkdirSync5, readdirSync, renameSync as renameSync2, unlinkSync as unlinkSync3 } from "fs";
|
|
1453
1451
|
import { homedir as homedir4 } from "os";
|
|
1454
|
-
import { join as
|
|
1452
|
+
import { join as join5 } from "path";
|
|
1455
1453
|
var ALIAS_MAP, VALID_ALIASES, VALID_EFFORTS, claudeRegistry, claudeRegistryOperations;
|
|
1456
1454
|
var init_claude_registry = __esm(() => {
|
|
1457
1455
|
init_claude();
|
|
@@ -1498,11 +1496,11 @@ var init_claude_registry = __esm(() => {
|
|
|
1498
1496
|
const result = await forkSession(parentSessionId, {
|
|
1499
1497
|
...title ? { title } : {}
|
|
1500
1498
|
});
|
|
1501
|
-
const projectsRoot =
|
|
1502
|
-
const destDir =
|
|
1503
|
-
const destPath =
|
|
1499
|
+
const projectsRoot = join5(homedir4(), ".claude", "projects");
|
|
1500
|
+
const destDir = join5(projectsRoot, encodeClaudeCwd(cwd));
|
|
1501
|
+
const destPath = join5(destDir, `${result.sessionId}.jsonl`);
|
|
1504
1502
|
if (!existsSync4(destPath)) {
|
|
1505
|
-
const sourcePath = readdirSync(projectsRoot).map((d) =>
|
|
1503
|
+
const sourcePath = readdirSync(projectsRoot).map((d) => join5(projectsRoot, d, `${result.sessionId}.jsonl`)).find((p) => existsSync4(p));
|
|
1506
1504
|
if (!sourcePath) {
|
|
1507
1505
|
throw new Error(`claude forkSession: fork rollout ${result.sessionId}.jsonl not found under ${projectsRoot}`);
|
|
1508
1506
|
}
|
|
@@ -1515,10 +1513,10 @@ var init_claude_registry = __esm(() => {
|
|
|
1515
1513
|
};
|
|
1516
1514
|
},
|
|
1517
1515
|
async cleanupRollouts({ cwd, sessionIds }) {
|
|
1518
|
-
const projectsDir =
|
|
1516
|
+
const projectsDir = join5(homedir4(), ".claude", "projects", encodeClaudeCwd(cwd));
|
|
1519
1517
|
const failures = [];
|
|
1520
1518
|
for (const sid of sessionIds) {
|
|
1521
|
-
const path =
|
|
1519
|
+
const path = join5(projectsDir, `${sid}.jsonl`);
|
|
1522
1520
|
try {
|
|
1523
1521
|
unlinkSync3(path);
|
|
1524
1522
|
} catch (e) {
|
|
@@ -1539,14 +1537,14 @@ var init_claude_registry = __esm(() => {
|
|
|
1539
1537
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
1540
1538
|
import { existsSync as existsSync5, readFileSync as readFileSync4, realpathSync, statSync as statSync2, unlinkSync as unlinkSync4 } from "fs";
|
|
1541
1539
|
import { homedir as homedir5 } from "os";
|
|
1542
|
-
import { basename, dirname as
|
|
1540
|
+
import { basename, dirname as dirname3, join as join6, resolve as resolve3 } from "path";
|
|
1543
1541
|
function codexSessionsDir() {
|
|
1544
|
-
return
|
|
1542
|
+
return join6(process.env.CODEX_HOME || join6(homedir5(), ".codex"), "sessions");
|
|
1545
1543
|
}
|
|
1546
1544
|
function loadCodexShell() {
|
|
1547
1545
|
if (_shellCache)
|
|
1548
1546
|
return _shellCache;
|
|
1549
|
-
const raw = readFileSync4(
|
|
1547
|
+
const raw = readFileSync4(join6(FIXTURES_DIR, "codex-shell.jsonl"), "utf8");
|
|
1550
1548
|
const lines = parseJsonlText(raw);
|
|
1551
1549
|
if (lines.length < 5) {
|
|
1552
1550
|
throw new Error(`loadCodexShell: expected >=5 entries in codex-shell.jsonl, got ${lines.length}`);
|
|
@@ -1610,7 +1608,7 @@ function canonicalFilePath(path) {
|
|
|
1610
1608
|
return realpathSync(absolute);
|
|
1611
1609
|
} catch {
|
|
1612
1610
|
try {
|
|
1613
|
-
return
|
|
1611
|
+
return join6(realpathSync(dirname3(absolute)), basename(absolute));
|
|
1614
1612
|
} catch {
|
|
1615
1613
|
return absolute;
|
|
1616
1614
|
}
|
|
@@ -1799,19 +1797,19 @@ function latestCodexRolloutPath(threadId) {
|
|
|
1799
1797
|
try {
|
|
1800
1798
|
if (buckets) {
|
|
1801
1799
|
for (const bucket of buckets) {
|
|
1802
|
-
const dir =
|
|
1800
|
+
const dir = join6(sessionsDir, bucket);
|
|
1803
1801
|
if (!existsSync5(dir))
|
|
1804
1802
|
continue;
|
|
1805
1803
|
const glob = new Bun.Glob(`rollout-*-${threadId}.jsonl`);
|
|
1806
1804
|
for (const rel of glob.scanSync({ cwd: dir, onlyFiles: true })) {
|
|
1807
|
-
candidates.push(
|
|
1805
|
+
candidates.push(join6(dir, rel));
|
|
1808
1806
|
}
|
|
1809
1807
|
}
|
|
1810
1808
|
}
|
|
1811
1809
|
if (candidates.length === 0) {
|
|
1812
1810
|
const glob = new Bun.Glob(`**/rollout-*-${threadId}.jsonl`);
|
|
1813
1811
|
for (const rel of glob.scanSync({ cwd: sessionsDir, onlyFiles: true })) {
|
|
1814
|
-
candidates.push(
|
|
1812
|
+
candidates.push(join6(sessionsDir, rel));
|
|
1815
1813
|
}
|
|
1816
1814
|
}
|
|
1817
1815
|
return candidates.sort((a, b) => statSync2(b).mtimeMs - statSync2(a).mtimeMs)[0];
|
|
@@ -1920,8 +1918,8 @@ function writeCodexRollout(opts) {
|
|
|
1920
1918
|
const mm = String(now.getUTCMonth() + 1).padStart(2, "0");
|
|
1921
1919
|
const dd = String(now.getUTCDate()).padStart(2, "0");
|
|
1922
1920
|
const tsStr = tsIso.replace(/[:.]/g, "-").slice(0, 19);
|
|
1923
|
-
const dir =
|
|
1924
|
-
const path =
|
|
1921
|
+
const dir = join6(codexSessionsDir(), String(yyyy), mm, dd);
|
|
1922
|
+
const path = join6(dir, `rollout-${tsStr}-${threadId}.jsonl`);
|
|
1925
1923
|
if (opts.threadId) {
|
|
1926
1924
|
sweepPriorRolloutsForThread(opts.threadId);
|
|
1927
1925
|
}
|
|
@@ -1937,13 +1935,13 @@ function sweepPriorRolloutsForThread(threadId) {
|
|
|
1937
1935
|
return;
|
|
1938
1936
|
}
|
|
1939
1937
|
for (const bucket of buckets) {
|
|
1940
|
-
const dir =
|
|
1938
|
+
const dir = join6(sessionsDir, bucket);
|
|
1941
1939
|
if (!existsSync5(dir))
|
|
1942
1940
|
continue;
|
|
1943
1941
|
try {
|
|
1944
1942
|
const glob = new Bun.Glob(`rollout-*-${threadId}.jsonl`);
|
|
1945
1943
|
for (const rel of glob.scanSync({ cwd: dir, onlyFiles: true })) {
|
|
1946
|
-
const fullPath =
|
|
1944
|
+
const fullPath = join6(dir, rel);
|
|
1947
1945
|
try {
|
|
1948
1946
|
unlinkSync4(fullPath);
|
|
1949
1947
|
} catch (e) {
|
|
@@ -1961,7 +1959,7 @@ function sweepPriorRolloutsFullTree(threadId, sessionsDir) {
|
|
|
1961
1959
|
try {
|
|
1962
1960
|
const glob = new Bun.Glob(`**/rollout-*-${threadId}.jsonl`);
|
|
1963
1961
|
for (const rel of glob.scanSync({ cwd: sessionsDir, onlyFiles: true })) {
|
|
1964
|
-
const fullPath =
|
|
1962
|
+
const fullPath = join6(sessionsDir, rel);
|
|
1965
1963
|
try {
|
|
1966
1964
|
unlinkSync4(fullPath);
|
|
1967
1965
|
} catch (e) {
|
|
@@ -2039,29 +2037,29 @@ function sanitizeId(id) {
|
|
|
2039
2037
|
// ../../packages/core/src/storage/storage-host.ts
|
|
2040
2038
|
import { mkdirSync as mkdirSync6 } from "fs";
|
|
2041
2039
|
import { homedir as homedir6 } from "os";
|
|
2042
|
-
import { dirname as
|
|
2040
|
+
import { dirname as dirname4, join as join7, resolve as resolve4 } from "path";
|
|
2043
2041
|
function envPath(name, fallback) {
|
|
2044
2042
|
const value = process.env[name]?.trim();
|
|
2045
2043
|
return resolve4(value || fallback);
|
|
2046
2044
|
}
|
|
2047
2045
|
function defaultStateDir() {
|
|
2048
|
-
return envPath("NEGOTIUM_STATE_DIR",
|
|
2046
|
+
return envPath("NEGOTIUM_STATE_DIR", join7(homedir6(), ".negotium"));
|
|
2049
2047
|
}
|
|
2050
2048
|
function defaultDataDir() {
|
|
2051
|
-
return envPath("NEGOTIUM_DATA_DIR",
|
|
2049
|
+
return envPath("NEGOTIUM_DATA_DIR", join7(defaultStateDir(), "data"));
|
|
2052
2050
|
}
|
|
2053
2051
|
function defaultLogDir() {
|
|
2054
|
-
return envPath("NEGOTIUM_LOG_DIR",
|
|
2052
|
+
return envPath("NEGOTIUM_LOG_DIR", join7(defaultStateDir(), "logs"));
|
|
2055
2053
|
}
|
|
2056
2054
|
function defaultWorkspaceDir() {
|
|
2057
|
-
return envPath("NEGOTIUM_WORKSPACE_DIR",
|
|
2055
|
+
return envPath("NEGOTIUM_WORKSPACE_DIR", join7(defaultStateDir(), "workspace"));
|
|
2058
2056
|
}
|
|
2059
2057
|
function defaultSessionAsksDir() {
|
|
2060
|
-
const runDir = envPath("NEGOTIUM_RUN_DIR",
|
|
2061
|
-
return
|
|
2058
|
+
const runDir = envPath("NEGOTIUM_RUN_DIR", join7(defaultStateDir(), "runtime"));
|
|
2059
|
+
return join7(runDir, "session-asks");
|
|
2062
2060
|
}
|
|
2063
2061
|
function defaultSessionsDatabasePath() {
|
|
2064
|
-
return envPath("SESSIONS_DB_PATH",
|
|
2062
|
+
return envPath("SESSIONS_DB_PATH", join7(resolveStorageDataDir(), "sessions.db"));
|
|
2065
2063
|
}
|
|
2066
2064
|
function initializeDatabase(database) {
|
|
2067
2065
|
database.exec("PRAGMA busy_timeout = 5000");
|
|
@@ -2078,7 +2076,7 @@ function defaultDatabase() {
|
|
|
2078
2076
|
return fallbackDatabase;
|
|
2079
2077
|
if (fallbackDatabase)
|
|
2080
2078
|
fallbackDatabase.close();
|
|
2081
|
-
mkdirSync6(
|
|
2079
|
+
mkdirSync6(dirname4(path), { recursive: true });
|
|
2082
2080
|
fallbackDatabase = new Database(path, { create: true });
|
|
2083
2081
|
fallbackDatabasePath = path;
|
|
2084
2082
|
initializeDatabase(fallbackDatabase);
|
|
@@ -2100,10 +2098,10 @@ function resolveStorageWorkspaceDir() {
|
|
|
2100
2098
|
return configuredHost.workspaceDir ?? defaultWorkspaceDir();
|
|
2101
2099
|
}
|
|
2102
2100
|
function resolveStorageSharedWikiDir() {
|
|
2103
|
-
return configuredHost.sharedWikiDir ??
|
|
2101
|
+
return configuredHost.sharedWikiDir ?? join7(resolveStorageWorkspaceDir(), "wiki");
|
|
2104
2102
|
}
|
|
2105
2103
|
function resolveStorageUsersLogDir() {
|
|
2106
|
-
return configuredHost.usersLogDir ??
|
|
2104
|
+
return configuredHost.usersLogDir ?? join7(resolveStorageDataDir(), "users");
|
|
2107
2105
|
}
|
|
2108
2106
|
function normalizeStorageHostPatch(options) {
|
|
2109
2107
|
const patch = {};
|
|
@@ -2237,16 +2235,16 @@ import {
|
|
|
2237
2235
|
unlinkSync as unlinkSync5,
|
|
2238
2236
|
writeFileSync as writeFileSync4
|
|
2239
2237
|
} from "fs";
|
|
2240
|
-
import { dirname as
|
|
2238
|
+
import { dirname as dirname5, join as join8 } from "path";
|
|
2241
2239
|
function conversationDir(_userId) {
|
|
2242
|
-
return
|
|
2240
|
+
return join8(resolveStorageDataDir(), "conversations");
|
|
2243
2241
|
}
|
|
2244
2242
|
function topicFilename(topicName) {
|
|
2245
2243
|
const t = sanitizeTopicName(topicName, true);
|
|
2246
2244
|
return `${t}.jsonl`;
|
|
2247
2245
|
}
|
|
2248
2246
|
function getConversationPath(userId, topicName) {
|
|
2249
|
-
return
|
|
2247
|
+
return join8(conversationDir(userId), topicFilename(topicName));
|
|
2250
2248
|
}
|
|
2251
2249
|
function getActiveConversationPath(userId, topicName) {
|
|
2252
2250
|
const rawPath = getConversationPath(userId, topicName);
|
|
@@ -2272,7 +2270,7 @@ function appendConversationEventStrict(userId, topicName, agent, event) {
|
|
|
2272
2270
|
event
|
|
2273
2271
|
};
|
|
2274
2272
|
const line = JSON.stringify(entry);
|
|
2275
|
-
mkdirSync7(
|
|
2273
|
+
mkdirSync7(dirname5(path), { recursive: true });
|
|
2276
2274
|
appendJsonlLine(path, line);
|
|
2277
2275
|
const activePath = getActiveConversationPath(userId, topicName);
|
|
2278
2276
|
if (existsSync6(activePath)) {
|
|
@@ -2290,7 +2288,7 @@ function appendRawConversationEventStrict(userId, topicName, agent, event) {
|
|
|
2290
2288
|
agent,
|
|
2291
2289
|
event
|
|
2292
2290
|
};
|
|
2293
|
-
mkdirSync7(
|
|
2291
|
+
mkdirSync7(dirname5(path), { recursive: true });
|
|
2294
2292
|
appendJsonlLine(path, JSON.stringify(entry));
|
|
2295
2293
|
}
|
|
2296
2294
|
function readConversationPath(path) {
|
|
@@ -2331,7 +2329,7 @@ function replaceRawConversationStrict(userId, topicName, entries) {
|
|
|
2331
2329
|
}
|
|
2332
2330
|
function replaceConversationPathStrict(path, entries) {
|
|
2333
2331
|
const tempPath = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
2334
|
-
mkdirSync7(
|
|
2332
|
+
mkdirSync7(dirname5(path), { recursive: true });
|
|
2335
2333
|
try {
|
|
2336
2334
|
writeFileSync4(tempPath, entries.length > 0 ? `${entries.map((entry) => JSON.stringify(entry)).join(`
|
|
2337
2335
|
`)}
|
|
@@ -2358,7 +2356,7 @@ function cloneConversationLog(opts) {
|
|
|
2358
2356
|
const body = `${entries.map((e) => JSON.stringify(e)).join(`
|
|
2359
2357
|
`)}
|
|
2360
2358
|
`;
|
|
2361
|
-
mkdirSync7(
|
|
2359
|
+
mkdirSync7(dirname5(dstPath), { recursive: true });
|
|
2362
2360
|
writeFileSync4(dstPath, body);
|
|
2363
2361
|
const srcActivePath = getActiveConversationPath(userId, srcTopic);
|
|
2364
2362
|
if (existsSync6(srcActivePath)) {
|
|
@@ -2400,7 +2398,7 @@ var init_conversations = __esm(async () => {
|
|
|
2400
2398
|
// ../../packages/core/src/agents/codex-registry.ts
|
|
2401
2399
|
import { existsSync as existsSync7, unlinkSync as unlinkSync6 } from "fs";
|
|
2402
2400
|
import { homedir as homedir7 } from "os";
|
|
2403
|
-
import { join as
|
|
2401
|
+
import { join as join9 } from "path";
|
|
2404
2402
|
var VALID_EFFORTS2, codexRegistry, codexRegistryOperations;
|
|
2405
2403
|
var init_codex_registry = __esm(async () => {
|
|
2406
2404
|
init_codex();
|
|
@@ -2449,7 +2447,7 @@ var init_codex_registry = __esm(async () => {
|
|
|
2449
2447
|
async cleanupRollouts({ sessionIds }) {
|
|
2450
2448
|
if (sessionIds.length === 0)
|
|
2451
2449
|
return;
|
|
2452
|
-
const sessionsDir =
|
|
2450
|
+
const sessionsDir = join9(process.env.CODEX_HOME || join9(homedir7(), ".codex"), "sessions");
|
|
2453
2451
|
if (!existsSync7(sessionsDir))
|
|
2454
2452
|
return;
|
|
2455
2453
|
const failures = [];
|
|
@@ -2457,7 +2455,7 @@ var init_codex_registry = __esm(async () => {
|
|
|
2457
2455
|
try {
|
|
2458
2456
|
const glob = new Bun.Glob(`**/rollout-*-${tid}.jsonl`);
|
|
2459
2457
|
for await (const rel of glob.scan({ cwd: sessionsDir, onlyFiles: true })) {
|
|
2460
|
-
const path =
|
|
2458
|
+
const path = join9(sessionsDir, rel);
|
|
2461
2459
|
try {
|
|
2462
2460
|
unlinkSync6(path);
|
|
2463
2461
|
} catch (e) {
|
|
@@ -2483,15 +2481,15 @@ var init_codex_registry = __esm(async () => {
|
|
|
2483
2481
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2484
2482
|
import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
2485
2483
|
import { homedir as homedir8 } from "os";
|
|
2486
|
-
import { join as
|
|
2484
|
+
import { join as join10, resolve as resolve5 } from "path";
|
|
2487
2485
|
function maestroSessionsDir() {
|
|
2488
|
-
return
|
|
2486
|
+
return join10(process.env.MAESTRO_DATA_DIR ? resolve5(process.env.MAESTRO_DATA_DIR) : join10(homedir8(), ".maestro"), "sessions");
|
|
2489
2487
|
}
|
|
2490
2488
|
function maestroSessionPath(sessionId) {
|
|
2491
|
-
return
|
|
2489
|
+
return join10(maestroSessionsDir(), `${sessionId}.jsonl`);
|
|
2492
2490
|
}
|
|
2493
2491
|
function maestroActiveSessionPath(sessionId) {
|
|
2494
|
-
return
|
|
2492
|
+
return join10(maestroSessionsDir(), `${sessionId}.active.jsonl`);
|
|
2495
2493
|
}
|
|
2496
2494
|
function existingCreatedAt(path) {
|
|
2497
2495
|
if (!existsSync8(path))
|
|
@@ -2697,7 +2695,7 @@ __export(exports_tasks, {
|
|
|
2697
2695
|
TASK_STATUS_VALUES: () => TASK_STATUS_VALUES
|
|
2698
2696
|
});
|
|
2699
2697
|
import { existsSync as existsSync10, mkdirSync as mkdirSync9, readFileSync as readFileSync7, renameSync as renameSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
2700
|
-
import { dirname as
|
|
2698
|
+
import { dirname as dirname6, join as join11 } from "path";
|
|
2701
2699
|
function safeTaskScopeKey(scopeKey) {
|
|
2702
2700
|
const safe = sanitizeFileName(scopeKey);
|
|
2703
2701
|
if (!safe || safe === "." || safe === "..") {
|
|
@@ -2709,7 +2707,7 @@ function taskScopeKey(opts) {
|
|
|
2709
2707
|
return opts.topicId?.trim() || opts.session || "default";
|
|
2710
2708
|
}
|
|
2711
2709
|
function getTaskFilePath(userId, scopeKey) {
|
|
2712
|
-
return
|
|
2710
|
+
return join11(resolveStorageDataDir(), "tasks", `${safeTaskScopeKey(scopeKey)}.json`);
|
|
2713
2711
|
}
|
|
2714
2712
|
function readTasks(userId, scopeKey) {
|
|
2715
2713
|
const path = getTaskFilePath(userId, scopeKey);
|
|
@@ -2725,7 +2723,7 @@ function readTasks(userId, scopeKey) {
|
|
|
2725
2723
|
}
|
|
2726
2724
|
function writeTasks(userId, scopeKey, tasks) {
|
|
2727
2725
|
const path = getTaskFilePath(userId, scopeKey);
|
|
2728
|
-
mkdirSync9(
|
|
2726
|
+
mkdirSync9(dirname6(path), { recursive: true });
|
|
2729
2727
|
const payload = { version: 1, tasks };
|
|
2730
2728
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
2731
2729
|
writeFileSync6(tmp, JSON.stringify(payload, null, 2), "utf-8");
|
|
@@ -4594,7 +4592,7 @@ var exports_version = {};
|
|
|
4594
4592
|
__export(exports_version, {
|
|
4595
4593
|
NEGOTIUM_VERSION: () => NEGOTIUM_VERSION
|
|
4596
4594
|
});
|
|
4597
|
-
var NEGOTIUM_VERSION = "0.2.
|
|
4595
|
+
var NEGOTIUM_VERSION = "0.2.3";
|
|
4598
4596
|
|
|
4599
4597
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
4600
4598
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -4612,7 +4610,7 @@ import {
|
|
|
4612
4610
|
} from "fs";
|
|
4613
4611
|
import { createRequire as createRequire2 } from "module";
|
|
4614
4612
|
import { tmpdir } from "os";
|
|
4615
|
-
import { dirname as
|
|
4613
|
+
import { dirname as dirname7, join as join12 } from "path";
|
|
4616
4614
|
function readPackageVersion(packageJsonPath) {
|
|
4617
4615
|
const parsed = JSON.parse(readFileSync9(packageJsonPath, "utf8"));
|
|
4618
4616
|
if (typeof parsed.version !== "string" || !parsed.version.trim()) {
|
|
@@ -4621,7 +4619,7 @@ function readPackageVersion(packageJsonPath) {
|
|
|
4621
4619
|
return parsed.version;
|
|
4622
4620
|
}
|
|
4623
4621
|
function codexCliScriptPath() {
|
|
4624
|
-
return
|
|
4622
|
+
return join12(dirname7(bundledCodexPackagePath), "bin", "codex.js");
|
|
4625
4623
|
}
|
|
4626
4624
|
function parseCodexModelCache(contents, sourcePath) {
|
|
4627
4625
|
let parsed;
|
|
@@ -4662,7 +4660,7 @@ function writePrivateFileAtomic(path, contents) {
|
|
|
4662
4660
|
}
|
|
4663
4661
|
}
|
|
4664
4662
|
function bundledCodexModelCachePath(authFilePath) {
|
|
4665
|
-
return
|
|
4663
|
+
return join12(dirname7(authFilePath), NEGOTIUM_MODEL_CACHE);
|
|
4666
4664
|
}
|
|
4667
4665
|
async function bootstrapCodexModelCache(codexHome, cachePath) {
|
|
4668
4666
|
const child = spawn3(process.execPath, [codexCliScriptPath(), "app-server", "--stdio"], {
|
|
@@ -4747,16 +4745,16 @@ async function bootstrapCodexModelCache(codexHome, cachePath) {
|
|
|
4747
4745
|
});
|
|
4748
4746
|
}
|
|
4749
4747
|
async function bootstrapIsolatedCodexModelCache(authFilePath, bootstrap) {
|
|
4750
|
-
const sourceHome =
|
|
4751
|
-
const isolatedHome = mkdtempSync(
|
|
4752
|
-
const isolatedCachePath =
|
|
4748
|
+
const sourceHome = dirname7(authFilePath);
|
|
4749
|
+
const isolatedHome = mkdtempSync(join12(tmpdir(), "negotium-codex-models-"));
|
|
4750
|
+
const isolatedCachePath = join12(isolatedHome, "models_cache.json");
|
|
4753
4751
|
try {
|
|
4754
|
-
const isolatedAuthPath =
|
|
4752
|
+
const isolatedAuthPath = join12(isolatedHome, "auth.json");
|
|
4755
4753
|
copyFileSync(authFilePath, isolatedAuthPath);
|
|
4756
4754
|
chmodSync3(isolatedAuthPath, 384);
|
|
4757
|
-
const sourceConfigPath =
|
|
4755
|
+
const sourceConfigPath = join12(sourceHome, "config.toml");
|
|
4758
4756
|
if (existsSync12(sourceConfigPath)) {
|
|
4759
|
-
const isolatedConfigPath =
|
|
4757
|
+
const isolatedConfigPath = join12(isolatedHome, "config.toml");
|
|
4760
4758
|
copyFileSync(sourceConfigPath, isolatedConfigPath);
|
|
4761
4759
|
chmodSync3(isolatedConfigPath, 384);
|
|
4762
4760
|
}
|
|
@@ -4767,7 +4765,7 @@ async function bootstrapIsolatedCodexModelCache(authFilePath, bootstrap) {
|
|
|
4767
4765
|
}
|
|
4768
4766
|
}
|
|
4769
4767
|
async function ensureCodexModelCache(authFilePath, bootstrap = bootstrapCodexModelCache) {
|
|
4770
|
-
const codexHome =
|
|
4768
|
+
const codexHome = dirname7(authFilePath);
|
|
4771
4769
|
const configuredCachePath = process.env.NEGOTIUM_CODEX_MODELS_CACHE_FILE;
|
|
4772
4770
|
if (configuredCachePath) {
|
|
4773
4771
|
if (!existsSync12(configuredCachePath)) {
|
|
@@ -4777,7 +4775,7 @@ async function ensureCodexModelCache(authFilePath, bootstrap = bootstrapCodexMod
|
|
|
4777
4775
|
return configuredCachePath;
|
|
4778
4776
|
}
|
|
4779
4777
|
const bundledCachePath = bundledCodexModelCachePath(authFilePath);
|
|
4780
|
-
const sharedCachePath =
|
|
4778
|
+
const sharedCachePath = join12(codexHome, "models_cache.json");
|
|
4781
4779
|
if (existsSync12(sharedCachePath)) {
|
|
4782
4780
|
try {
|
|
4783
4781
|
const shared = readCompatibleCodexModelCache(sharedCachePath);
|
|
@@ -4796,8 +4794,8 @@ async function ensureCodexModelCache(authFilePath, bootstrap = bootstrapCodexMod
|
|
|
4796
4794
|
return bundledCachePath;
|
|
4797
4795
|
}
|
|
4798
4796
|
function writeCodexCatalogWithNativeMultiAgentDisabled(authFilePath, sourcePath) {
|
|
4799
|
-
const codexHome =
|
|
4800
|
-
const outputPath =
|
|
4797
|
+
const codexHome = dirname7(authFilePath);
|
|
4798
|
+
const outputPath = join12(codexHome, NEGOTIUM_MODEL_CATALOG);
|
|
4801
4799
|
const parsed = readCodexModelCache(sourcePath).parsed;
|
|
4802
4800
|
const models = parsed.models.map((model, index) => {
|
|
4803
4801
|
if (!model || typeof model !== "object" || Array.isArray(model)) {
|
|
@@ -5346,7 +5344,7 @@ __export(exports_codex_provider, {
|
|
|
5346
5344
|
});
|
|
5347
5345
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
5348
5346
|
import { existsSync as existsSync13, readFileSync as readFileSync11, realpathSync as realpathSync3, statSync as statSync5 } from "fs";
|
|
5349
|
-
import { dirname as
|
|
5347
|
+
import { dirname as dirname8, isAbsolute as isAbsolute2, join as join13, relative, resolve as resolve8 } from "path";
|
|
5350
5348
|
import { Codex } from "@openai/codex-sdk";
|
|
5351
5349
|
function mapEffort(effort) {
|
|
5352
5350
|
if (!effort)
|
|
@@ -5360,7 +5358,7 @@ function codexMcpServerName(name) {
|
|
|
5360
5358
|
return CODEX_MCP_SERVER_NAME_OVERRIDES[name] ?? name;
|
|
5361
5359
|
}
|
|
5362
5360
|
function globalCodexMcpServerNames(authFilePath) {
|
|
5363
|
-
const configPath =
|
|
5361
|
+
const configPath = join13(dirname8(authFilePath), "config.toml");
|
|
5364
5362
|
if (!existsSync13(configPath))
|
|
5365
5363
|
return [];
|
|
5366
5364
|
try {
|
|
@@ -6151,7 +6149,7 @@ var init_maestro_provider = __esm(async () => {
|
|
|
6151
6149
|
// ../../packages/core/src/agents/index.ts
|
|
6152
6150
|
import { existsSync as existsSync14 } from "fs";
|
|
6153
6151
|
import { homedir as homedir9 } from "os";
|
|
6154
|
-
import { join as
|
|
6152
|
+
import { join as join14 } from "path";
|
|
6155
6153
|
async function* dispatchAgent(opts) {
|
|
6156
6154
|
switch (opts.agent) {
|
|
6157
6155
|
case "claude": {
|
|
@@ -6185,11 +6183,11 @@ async function resolveSessionFileMissing(agent, sessionId, cwd) {
|
|
|
6185
6183
|
switch (agent) {
|
|
6186
6184
|
case "claude": {
|
|
6187
6185
|
const encodedCwd = encodeClaudeCwd(cwd);
|
|
6188
|
-
const path =
|
|
6186
|
+
const path = join14(homedir9(), ".claude", "projects", encodedCwd, `${sessionId}.jsonl`);
|
|
6189
6187
|
return !existsSync14(path);
|
|
6190
6188
|
}
|
|
6191
6189
|
case "codex": {
|
|
6192
|
-
const sessionsDir =
|
|
6190
|
+
const sessionsDir = join14(process.env.CODEX_HOME || join14(homedir9(), ".codex"), "sessions");
|
|
6193
6191
|
const glob = new Bun.Glob(`**/rollout-*-${sessionId}.jsonl`);
|
|
6194
6192
|
for await (const _rel of glob.scan({ cwd: sessionsDir, onlyFiles: true })) {
|
|
6195
6193
|
return false;
|
|
@@ -9497,7 +9495,7 @@ import { randomBytes as randomBytes5, timingSafeEqual as timingSafeEqual2 } from
|
|
|
9497
9495
|
import { chmodSync as chmodSync4 } from "fs";
|
|
9498
9496
|
import { createServer as createServer2 } from "net";
|
|
9499
9497
|
import { tmpdir as tmpdir2 } from "os";
|
|
9500
|
-
import { join as
|
|
9498
|
+
import { join as join15 } from "path";
|
|
9501
9499
|
function deepMapStrings2(value, transform) {
|
|
9502
9500
|
if (typeof value === "string")
|
|
9503
9501
|
return transform(value);
|
|
@@ -9584,7 +9582,7 @@ function authorized(actual, expected) {
|
|
|
9584
9582
|
}
|
|
9585
9583
|
async function createBrowserVaultBroker(userId) {
|
|
9586
9584
|
const token = randomBytes5(32).toString("hex");
|
|
9587
|
-
const socketPath =
|
|
9585
|
+
const socketPath = join15(process.platform === "win32" ? tmpdir2() : "/tmp", `negotium-browser-vault-${process.pid}-${randomBytes5(8).toString("hex")}.sock`);
|
|
9588
9586
|
const retainedForms = new Map;
|
|
9589
9587
|
const leases = new Map;
|
|
9590
9588
|
const sockets = new Set;
|
|
@@ -9815,7 +9813,7 @@ import {
|
|
|
9815
9813
|
unlinkSync as unlinkSync11,
|
|
9816
9814
|
writeFileSync as writeFileSync8
|
|
9817
9815
|
} from "fs";
|
|
9818
|
-
import { dirname as
|
|
9816
|
+
import { dirname as dirname9, join as join16, resolve as resolve12 } from "path";
|
|
9819
9817
|
function makeInstanceKey(userId, topic) {
|
|
9820
9818
|
return resolvePlaywrightTopicBinding(userId, topic).instanceKey;
|
|
9821
9819
|
}
|
|
@@ -9895,14 +9893,14 @@ function portFileName(instanceKey) {
|
|
|
9895
9893
|
function writePortFile(instanceKey, port) {
|
|
9896
9894
|
try {
|
|
9897
9895
|
mkdirSync10(managerHost.portsDir, { recursive: true });
|
|
9898
|
-
writeFileSync8(
|
|
9896
|
+
writeFileSync8(join16(managerHost.portsDir, portFileName(instanceKey)), String(port));
|
|
9899
9897
|
} catch (e) {
|
|
9900
9898
|
logger.warn({ err: e, instanceKey, port }, "Failed to save playwright port file");
|
|
9901
9899
|
}
|
|
9902
9900
|
}
|
|
9903
9901
|
function deletePortFile(instanceKey) {
|
|
9904
9902
|
try {
|
|
9905
|
-
unlinkSync11(
|
|
9903
|
+
unlinkSync11(join16(managerHost.portsDir, portFileName(instanceKey)));
|
|
9906
9904
|
} catch (e) {
|
|
9907
9905
|
logger.warn({ err: e, instanceKey }, "Failed to delete playwright port file");
|
|
9908
9906
|
}
|
|
@@ -10392,7 +10390,7 @@ async function cloneProfileForChild(opts) {
|
|
|
10392
10390
|
if (existsSync15(dstDir)) {
|
|
10393
10391
|
rmSync2(dstDir, { recursive: true, force: true });
|
|
10394
10392
|
}
|
|
10395
|
-
mkdirSync10(
|
|
10393
|
+
mkdirSync10(dirname9(dstDir), { recursive: true });
|
|
10396
10394
|
if (process.platform === "darwin") {
|
|
10397
10395
|
try {
|
|
10398
10396
|
execFileSync7("cp", ["-cR", srcDir, dstDir], { stdio: "pipe" });
|
|
@@ -11483,32 +11481,32 @@ __export(exports_wiki, {
|
|
|
11483
11481
|
getSharedWikiDir: () => getSharedWikiDir
|
|
11484
11482
|
});
|
|
11485
11483
|
import { existsSync as existsSync16, readdirSync as readdirSync3, statSync as statSync6 } from "fs";
|
|
11486
|
-
import { basename as basename2, dirname as
|
|
11484
|
+
import { basename as basename2, dirname as dirname10, join as join17 } from "path";
|
|
11487
11485
|
function getWikiDir(_userId, workspaceDir = resolveStorageWorkspaceDir()) {
|
|
11488
|
-
return
|
|
11486
|
+
return join17(workspaceDir, "wiki");
|
|
11489
11487
|
}
|
|
11490
11488
|
function getSharedWikiDir(workspaceDir = resolveStorageWorkspaceDir()) {
|
|
11491
|
-
return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() :
|
|
11489
|
+
return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() : join17(workspaceDir, "wiki");
|
|
11492
11490
|
}
|
|
11493
11491
|
function findLatestSummaryFile(wikiDir, safeTopic) {
|
|
11494
|
-
const summariesDir =
|
|
11492
|
+
const summariesDir = join17(wikiDir, "summaries");
|
|
11495
11493
|
if (!existsSync16(summariesDir))
|
|
11496
11494
|
return null;
|
|
11497
11495
|
const files = readdirSync3(summariesDir).filter((f) => f.endsWith(".md") && f.match(new RegExp(`^\\d{4}-\\d{2}-\\d{2}-${safeTopic}(\\.md|~\\d+\\.md)$`)) && !f.endsWith("-sent-files.md")).sort((left, right) => {
|
|
11498
|
-
const mtimeDelta = statSync6(
|
|
11496
|
+
const mtimeDelta = statSync6(join17(summariesDir, right)).mtimeMs - statSync6(join17(summariesDir, left)).mtimeMs;
|
|
11499
11497
|
return mtimeDelta || right.localeCompare(left, undefined, { numeric: true });
|
|
11500
11498
|
});
|
|
11501
|
-
return files.length > 0 ?
|
|
11499
|
+
return files.length > 0 ? join17(summariesDir, files[0]) : null;
|
|
11502
11500
|
}
|
|
11503
11501
|
function getTopicMemoryFilePaths(_userId, topicName, forkOrigin, workspaceDir = resolveStorageWorkspaceDir()) {
|
|
11504
11502
|
const wikiDir = getSharedWikiDir(workspaceDir);
|
|
11505
11503
|
const resolveBrief = (name) => {
|
|
11506
11504
|
const safe = sanitizeTopicName(name, true);
|
|
11507
|
-
const brief =
|
|
11505
|
+
const brief = join17(wikiDir, "topic", `${safe}.md`);
|
|
11508
11506
|
const latestSummary = findLatestSummaryFile(wikiDir, safe);
|
|
11509
11507
|
return { brief, latestSummary };
|
|
11510
11508
|
};
|
|
11511
|
-
const archiveDir =
|
|
11509
|
+
const archiveDir = join17(wikiDir, "archive");
|
|
11512
11510
|
const archiveExistsFor = (name) => {
|
|
11513
11511
|
const safe = sanitizeTopicName(name);
|
|
11514
11512
|
return existsSync16(archiveDir) && readdirSync3(archiveDir).some((f) => f.endsWith(".jsonl") && f.startsWith(`${safe}_`));
|
|
@@ -11518,14 +11516,14 @@ function getTopicMemoryFilePaths(_userId, topicName, forkOrigin, workspaceDir =
|
|
|
11518
11516
|
const target = resolveBrief(sourceTopic);
|
|
11519
11517
|
if (existsSync16(target.brief)) {
|
|
11520
11518
|
return {
|
|
11521
|
-
memoryDir:
|
|
11519
|
+
memoryDir: dirname10(target.brief),
|
|
11522
11520
|
memoryFiles: [basename2(target.brief)],
|
|
11523
11521
|
...target.latestSummary ? { latestSummaryFile: target.latestSummary } : {},
|
|
11524
11522
|
...hasArchive ? { hasArchive: true } : {}
|
|
11525
11523
|
};
|
|
11526
11524
|
}
|
|
11527
11525
|
return {
|
|
11528
|
-
memoryDir:
|
|
11526
|
+
memoryDir: join17(wikiDir, "topic"),
|
|
11529
11527
|
memoryFiles: [],
|
|
11530
11528
|
...target.latestSummary ? { latestSummaryFile: target.latestSummary } : {},
|
|
11531
11529
|
...hasArchive ? { hasArchive: true } : {}
|
|
@@ -11538,7 +11536,7 @@ var init_wiki = __esm(async () => {
|
|
|
11538
11536
|
// ../../packages/core/src/agents/archiver.ts
|
|
11539
11537
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
11540
11538
|
import { existsSync as existsSync17, readdirSync as readdirSync4, readFileSync as readFileSync14, statSync as statSync7 } from "fs";
|
|
11541
|
-
import { join as
|
|
11539
|
+
import { join as join18 } from "path";
|
|
11542
11540
|
function resolveMemoryLanguage() {
|
|
11543
11541
|
const override = process.env.NEGOTIUM_MEMORY_LANG?.trim();
|
|
11544
11542
|
return override && override.length > 0 ? override : resolveOutputLanguage();
|
|
@@ -11789,10 +11787,10 @@ function distillOneLine(summaryMd) {
|
|
|
11789
11787
|
return "";
|
|
11790
11788
|
}
|
|
11791
11789
|
function findSummaryFile(storage, topicTitle, date, sinceMs, topicId) {
|
|
11792
|
-
const dir =
|
|
11790
|
+
const dir = join18(storage.getWikiDir(), "summaries");
|
|
11793
11791
|
if (!storage.fileExists(dir))
|
|
11794
11792
|
return null;
|
|
11795
|
-
const predicted =
|
|
11793
|
+
const predicted = join18(dir, wikiSummaryFilename(date, topicTitle, topicId));
|
|
11796
11794
|
if (storage.fileExists(predicted) && storage.fileModifiedAt(predicted) >= sinceMs)
|
|
11797
11795
|
return predicted;
|
|
11798
11796
|
let best = null;
|
|
@@ -11800,7 +11798,7 @@ function findSummaryFile(storage, topicTitle, date, sinceMs, topicId) {
|
|
|
11800
11798
|
if (!f.startsWith(`${date}-`) || !isTopicSummaryFile(f, topicId ?? "", topicTitle)) {
|
|
11801
11799
|
continue;
|
|
11802
11800
|
}
|
|
11803
|
-
const p =
|
|
11801
|
+
const p = join18(dir, f);
|
|
11804
11802
|
try {
|
|
11805
11803
|
const m = storage.fileModifiedAt(p);
|
|
11806
11804
|
if (m >= sinceMs && (!best || m > best.mtime))
|
|
@@ -12010,13 +12008,13 @@ __export(exports_topic_archive, {
|
|
|
12010
12008
|
archiveConversationEvents: () => archiveConversationEvents
|
|
12011
12009
|
});
|
|
12012
12010
|
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync9 } from "fs";
|
|
12013
|
-
import { join as
|
|
12011
|
+
import { join as join19 } from "path";
|
|
12014
12012
|
function archiveTopicMessages(topicId, topicTitle, options = {}) {
|
|
12015
12013
|
const rows = options.afterRowid !== undefined ? getMessagesForTopicAfterRowid(topicId, options.afterRowid) : getAllMessagesForTopic(topicId);
|
|
12016
12014
|
if (rows.length === 0)
|
|
12017
12015
|
return null;
|
|
12018
12016
|
const safeTopic = sanitizeTopicName(topicTitle, true);
|
|
12019
|
-
const archiveDir =
|
|
12017
|
+
const archiveDir = join19(getSharedWikiDir(), "archive");
|
|
12020
12018
|
mkdirSync11(archiveDir, { recursive: true });
|
|
12021
12019
|
const date = new Date().toISOString().slice(0, 10);
|
|
12022
12020
|
const reasonSuffix = options.reason && options.reason !== "delete" ? `_${options.reason}` : "";
|
|
@@ -12029,7 +12027,7 @@ function archiveTopicMessages(topicId, topicTitle, options = {}) {
|
|
|
12029
12027
|
let path;
|
|
12030
12028
|
while (true) {
|
|
12031
12029
|
filename = `${safeTopic}_${date}${reasonSuffix}${counter === 1 ? "" : `_${counter}`}.jsonl`;
|
|
12032
|
-
path =
|
|
12030
|
+
path = join19(archiveDir, filename);
|
|
12033
12031
|
try {
|
|
12034
12032
|
writeFileSync9(path, body, { flag: "wx" });
|
|
12035
12033
|
break;
|
|
@@ -12074,7 +12072,7 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
|
|
|
12074
12072
|
const entries = readRawConversation(userId, topicTitle);
|
|
12075
12073
|
if (entries.length === 0)
|
|
12076
12074
|
return null;
|
|
12077
|
-
const archiveDir =
|
|
12075
|
+
const archiveDir = join19(getSharedWikiDir(), "archive");
|
|
12078
12076
|
mkdirSync11(archiveDir, { recursive: true });
|
|
12079
12077
|
const safeTopic = sanitizeTopicName(topicTitle, true);
|
|
12080
12078
|
const date = new Date().toISOString().slice(0, 10);
|
|
@@ -12102,7 +12100,7 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
|
|
|
12102
12100
|
let counter = 1;
|
|
12103
12101
|
while (true) {
|
|
12104
12102
|
const suffix = counter === 1 ? "" : `_${counter}`;
|
|
12105
|
-
const path =
|
|
12103
|
+
const path = join19(archiveDir, `${safeTopic}_${date}${reasonSuffix}_events${suffix}.jsonl`);
|
|
12106
12104
|
try {
|
|
12107
12105
|
writeFileSync9(path, body, { flag: "wx" });
|
|
12108
12106
|
logger.info({ topicId, topicTitle, archive: path, eventCount: entries.length }, "archiveConversationEvents: archived raw conversation events");
|
|
@@ -12434,7 +12432,7 @@ var init_idle_archiver = __esm(async () => {
|
|
|
12434
12432
|
|
|
12435
12433
|
// ../../packages/core/src/agents/topic-cleanup.ts
|
|
12436
12434
|
import { mkdirSync as mkdirSync12, renameSync as renameSync6, unlinkSync as unlinkSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
12437
|
-
import { dirname as
|
|
12435
|
+
import { dirname as dirname11 } from "path";
|
|
12438
12436
|
function collectSessionIdsByAgent(entries, extraSessions = []) {
|
|
12439
12437
|
const out = new Map;
|
|
12440
12438
|
for (const e of entries) {
|
|
@@ -12500,7 +12498,7 @@ function createTopicLogMaintenance(host) {
|
|
|
12500
12498
|
const path = runtimeHost.activeConversationPath(opts.userId, opts.topicName);
|
|
12501
12499
|
const tempPath = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
12502
12500
|
try {
|
|
12503
|
-
mkdirSync12(
|
|
12501
|
+
mkdirSync12(dirname11(path), { recursive: true });
|
|
12504
12502
|
writeFileSync10(tempPath, retained.length > 0 ? `${retained.map((entry) => JSON.stringify(entry)).join(`
|
|
12505
12503
|
`)}
|
|
12506
12504
|
` : "", { flag: "wx" });
|
|
@@ -13114,7 +13112,7 @@ var init_runtime_turn_requests = __esm(async () => {
|
|
|
13114
13112
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
13115
13113
|
import { mkdtempSync as mkdtempSync2, rmSync as rmSync4, writeFileSync as writeFileSync11 } from "fs";
|
|
13116
13114
|
import { tmpdir as tmpdir3 } from "os";
|
|
13117
|
-
import { join as
|
|
13115
|
+
import { join as join20 } from "path";
|
|
13118
13116
|
async function waitForMemoryArchive(settled, timeoutMs) {
|
|
13119
13117
|
let timer;
|
|
13120
13118
|
try {
|
|
@@ -13367,7 +13365,7 @@ function formatCompactElapsed(startedAt) {
|
|
|
13367
13365
|
async function summarizeTopicContext(request) {
|
|
13368
13366
|
const startedAt = Date.now();
|
|
13369
13367
|
const sessionIds = [];
|
|
13370
|
-
const compactCwd = mkdtempSync2(
|
|
13368
|
+
const compactCwd = mkdtempSync2(join20(tmpdir3(), "negotium-compact-"));
|
|
13371
13369
|
const abortController = new AbortController;
|
|
13372
13370
|
const relayAbort = () => abortController.abort(request.signal?.reason);
|
|
13373
13371
|
if (request.signal?.aborted)
|
|
@@ -13394,7 +13392,7 @@ async function summarizeTopicContext(request) {
|
|
|
13394
13392
|
let error = "";
|
|
13395
13393
|
let toolViolation = false;
|
|
13396
13394
|
let compactionLogCalls = 0;
|
|
13397
|
-
const compactionLogPath =
|
|
13395
|
+
const compactionLogPath = join20(compactCwd, "conversation.log");
|
|
13398
13396
|
try {
|
|
13399
13397
|
const compactionMcp = useCompactionLog ? {
|
|
13400
13398
|
compact_log: {
|
|
@@ -14694,14 +14692,14 @@ var init_self_config = __esm(async () => {
|
|
|
14694
14692
|
});
|
|
14695
14693
|
|
|
14696
14694
|
// ../../packages/core/src/query/session-inbox-path.ts
|
|
14697
|
-
import { join as
|
|
14695
|
+
import { join as join21 } from "path";
|
|
14698
14696
|
function sessionInboxPath(userId, topicId) {
|
|
14699
14697
|
const key = Buffer.from(topicId, "utf8").toString("base64url");
|
|
14700
|
-
return
|
|
14698
|
+
return join21(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${JSONL_SUFFIX}`);
|
|
14701
14699
|
}
|
|
14702
14700
|
function scheduledSessionInboxPath(userId, topicId) {
|
|
14703
14701
|
const key = Buffer.from(topicId, "utf8").toString("base64url");
|
|
14704
|
-
return
|
|
14702
|
+
return join21(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${SCHEDULE_SUFFIX}`);
|
|
14705
14703
|
}
|
|
14706
14704
|
function decodeTopicIdFileName(fileName, suffix) {
|
|
14707
14705
|
if (!fileName.startsWith(TOPIC_ID_FILE_PREFIX) || !fileName.endsWith(suffix))
|
|
@@ -14729,13 +14727,13 @@ var init_session_inbox_path = __esm(() => {
|
|
|
14729
14727
|
|
|
14730
14728
|
// ../../packages/core/src/query/session-inbox-cleanup.ts
|
|
14731
14729
|
import { unlinkSync as unlinkSync14 } from "fs";
|
|
14732
|
-
import { basename as basename3, join as
|
|
14730
|
+
import { basename as basename3, join as join22 } from "path";
|
|
14733
14731
|
function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
|
|
14734
14732
|
const live = sessionInboxPath(userId, topicId);
|
|
14735
14733
|
const scheduled = scheduledSessionInboxPath(userId, topicId);
|
|
14736
14734
|
const candidates = new Set([live, `${live}.processing`, scheduled, `${scheduled}.processing`]);
|
|
14737
14735
|
if (legacyTopicTitle && legacyTopicTitle !== "." && legacyTopicTitle !== ".." && basename3(legacyTopicTitle) === legacyTopicTitle) {
|
|
14738
|
-
const legacyBase =
|
|
14736
|
+
const legacyBase = join22(SESSION_INBOX_DIR, userId, legacyTopicTitle);
|
|
14739
14737
|
for (const suffix of [".jsonl", ".jsonl.processing", ".schedule", ".schedule.processing"]) {
|
|
14740
14738
|
candidates.add(`${legacyBase}${suffix}`);
|
|
14741
14739
|
}
|
|
@@ -14761,16 +14759,16 @@ var init_session_inbox_cleanup = __esm(() => {
|
|
|
14761
14759
|
|
|
14762
14760
|
// ../../packages/core/src/query/state.ts
|
|
14763
14761
|
import { mkdirSync as mkdirSync14, renameSync as renameSync7, unlinkSync as unlinkSync15, writeFileSync as writeFileSync12 } from "fs";
|
|
14764
|
-
import { basename as basename4, join as
|
|
14762
|
+
import { basename as basename4, join as join23 } from "path";
|
|
14765
14763
|
function createQueryStateStore(options) {
|
|
14766
14764
|
const sanitize = options.sanitizeTopicId ?? sanitizeId;
|
|
14767
|
-
const queryStateDirPath = (userId) =>
|
|
14768
|
-
const queryStateFile = (userId, topicId) =>
|
|
14765
|
+
const queryStateDirPath = (userId) => join23(options.usersLogDir, String(userId), "active-queries");
|
|
14766
|
+
const queryStateFile = (userId, topicId) => join23(queryStateDirPath(userId), `${sanitize(topicId)}.json`);
|
|
14769
14767
|
const legacyQueryStateFile = (userId, topicName) => {
|
|
14770
14768
|
if (!topicName || topicName === "." || topicName === ".." || basename4(topicName) !== topicName) {
|
|
14771
14769
|
return null;
|
|
14772
14770
|
}
|
|
14773
|
-
return
|
|
14771
|
+
return join23(queryStateDirPath(userId), `${topicName}.json`);
|
|
14774
14772
|
};
|
|
14775
14773
|
return {
|
|
14776
14774
|
write(userId, topicId, topicName, task) {
|
|
@@ -14930,30 +14928,30 @@ import {
|
|
|
14930
14928
|
unlinkSync as unlinkSync16,
|
|
14931
14929
|
writeFileSync as writeFileSync13
|
|
14932
14930
|
} from "fs";
|
|
14933
|
-
import { dirname as
|
|
14931
|
+
import { dirname as dirname12, join as join24 } from "path";
|
|
14934
14932
|
function pendingAskDir(userId) {
|
|
14935
14933
|
const rawUserId = String(userId);
|
|
14936
14934
|
const safeUserId = /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash5("sha256").update(rawUserId).digest("hex")}`;
|
|
14937
|
-
return
|
|
14935
|
+
return join24(resolveStorageSessionAsksDir(), safeUserId);
|
|
14938
14936
|
}
|
|
14939
14937
|
function encodeAskKey(key) {
|
|
14940
14938
|
return JSON.stringify([key.from, key.to]);
|
|
14941
14939
|
}
|
|
14942
14940
|
function pendingAskPath(key) {
|
|
14943
14941
|
const digest = createHash5("sha256").update(encodeAskKey(key)).digest("hex");
|
|
14944
|
-
return
|
|
14942
|
+
return join24(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
|
|
14945
14943
|
}
|
|
14946
14944
|
function v2PendingAskPath(key) {
|
|
14947
14945
|
const encoded = Buffer.from(encodeAskKey(key), "utf8").toString("base64url");
|
|
14948
|
-
return
|
|
14946
|
+
return join24(pendingAskDir(key.userId), `${V2_ASK_FILENAME_PREFIX}${encoded}.pending`);
|
|
14949
14947
|
}
|
|
14950
14948
|
function legacyPendingAskPath(key) {
|
|
14951
14949
|
if (key.from.includes("/") || key.from.includes("\\") || key.to.includes("/") || key.to.includes("\\") || key.from.includes("\x00") || key.to.includes("\x00")) {
|
|
14952
14950
|
return null;
|
|
14953
14951
|
}
|
|
14954
14952
|
const dir = pendingAskDir(key.userId);
|
|
14955
|
-
const candidate =
|
|
14956
|
-
return
|
|
14953
|
+
const candidate = join24(dir, `${key.from}___${key.to}.pending`);
|
|
14954
|
+
return dirname12(candidate) === dir ? candidate : null;
|
|
14957
14955
|
}
|
|
14958
14956
|
function parsePendingAskFilename(fileName) {
|
|
14959
14957
|
if (!fileName.endsWith(".pending"))
|
|
@@ -15193,7 +15191,7 @@ function listPendingAsksForCaller(args) {
|
|
|
15193
15191
|
const parsed = isV3 ? { from: args.from, to: "" } : parsePendingAskFilename(fileName);
|
|
15194
15192
|
if (!parsed)
|
|
15195
15193
|
continue;
|
|
15196
|
-
const path =
|
|
15194
|
+
const path = join24(dir, fileName);
|
|
15197
15195
|
const record = readPendingAskFile(path, {
|
|
15198
15196
|
userId: args.userId,
|
|
15199
15197
|
from: parsed.from,
|
|
@@ -15235,7 +15233,7 @@ function deletePendingAsksForTopic(args) {
|
|
|
15235
15233
|
}
|
|
15236
15234
|
let deleted = 0;
|
|
15237
15235
|
for (const fileName of files) {
|
|
15238
|
-
const path =
|
|
15236
|
+
const path = join24(dir, fileName);
|
|
15239
15237
|
const parsed = parsePendingAskFilename(fileName);
|
|
15240
15238
|
const record = readPendingAskFile(path, {
|
|
15241
15239
|
userId: args.userId,
|
|
@@ -15876,7 +15874,7 @@ var init_lifecycle = __esm(async () => {
|
|
|
15876
15874
|
// ../../packages/core/src/runtime/attachments.ts
|
|
15877
15875
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
15878
15876
|
import { copyFileSync as copyFileSync2, mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "fs";
|
|
15879
|
-
import { basename as basename5, join as
|
|
15877
|
+
import { basename as basename5, join as join25 } from "path";
|
|
15880
15878
|
function workspaceCwdFor(topicId) {
|
|
15881
15879
|
return resolveTopicWorkspaceDir(topicId);
|
|
15882
15880
|
}
|
|
@@ -15889,7 +15887,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
|
|
|
15889
15887
|
if (!attachmentIds?.length)
|
|
15890
15888
|
return [];
|
|
15891
15889
|
const out = [];
|
|
15892
|
-
const destDir =
|
|
15890
|
+
const destDir = join25(workspaceCwdFor(topicId), "attachments", queryId);
|
|
15893
15891
|
for (const rawId of attachmentIds) {
|
|
15894
15892
|
if (typeof rawId !== "string")
|
|
15895
15893
|
continue;
|
|
@@ -15906,7 +15904,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
|
|
|
15906
15904
|
mkdirSync16(destDir, { recursive: true });
|
|
15907
15905
|
const index = String(out.length + 1).padStart(2, "0");
|
|
15908
15906
|
const safeName = safeAttachmentFilename(attachment.filename, fileId);
|
|
15909
|
-
const destPath =
|
|
15907
|
+
const destPath = join25(destDir, `${index}-${fileId.slice(0, 8)}-${safeName}`);
|
|
15910
15908
|
copyFileSync2(sourcePath, destPath);
|
|
15911
15909
|
out.push({
|
|
15912
15910
|
id: attachment.id,
|
|
@@ -15936,10 +15934,10 @@ function promptWithAttachments(prompt, attachments) {
|
|
|
15936
15934
|
return composeAttachmentPrompt(prompt, attachments.map(({ filename, path }) => attachmentPromptLine(filename, path)));
|
|
15937
15935
|
}
|
|
15938
15936
|
function ingestAttachment(args) {
|
|
15939
|
-
const destDir =
|
|
15937
|
+
const destDir = join25(UPLOADS_DIR, args.topicId);
|
|
15940
15938
|
mkdirSync16(destDir, { recursive: true });
|
|
15941
15939
|
const safeName = safeAttachmentFilename(args.filename, "upload");
|
|
15942
|
-
const destPath =
|
|
15940
|
+
const destPath = join25(destDir, `${Date.now()}-${randomUUID15().slice(0, 8)}-${safeName}`);
|
|
15943
15941
|
if (args.sourcePath !== undefined) {
|
|
15944
15942
|
copyFileSync2(args.sourcePath, destPath);
|
|
15945
15943
|
} else if (args.bytes !== undefined) {
|
|
@@ -16553,7 +16551,7 @@ __export(exports_token_stats, {
|
|
|
16553
16551
|
});
|
|
16554
16552
|
import { createHash as createHash6 } from "crypto";
|
|
16555
16553
|
import { mkdirSync as mkdirSync17 } from "fs";
|
|
16556
|
-
import { join as
|
|
16554
|
+
import { join as join26 } from "path";
|
|
16557
16555
|
function emptyBucket() {
|
|
16558
16556
|
return {
|
|
16559
16557
|
inputTokens: 0,
|
|
@@ -16571,7 +16569,7 @@ function queriesPath(userId) {
|
|
|
16571
16569
|
const fileId = tokenStatsFileId(userId);
|
|
16572
16570
|
const logDir = resolveStorageLogDir();
|
|
16573
16571
|
mkdirSync17(logDir, { recursive: true });
|
|
16574
|
-
return
|
|
16572
|
+
return join26(logDir, `token-queries-${fileId}.jsonl`);
|
|
16575
16573
|
}
|
|
16576
16574
|
function loadRecords(userId) {
|
|
16577
16575
|
try {
|
|
@@ -17231,9 +17229,9 @@ __export(exports_app_settings, {
|
|
|
17231
17229
|
DEFAULT_AI_NAME: () => DEFAULT_AI_NAME
|
|
17232
17230
|
});
|
|
17233
17231
|
import { existsSync as existsSync18, mkdirSync as mkdirSync18, readFileSync as readFileSync16, writeFileSync as writeFileSync15 } from "fs";
|
|
17234
|
-
import { dirname as
|
|
17232
|
+
import { dirname as dirname13, join as join27 } from "path";
|
|
17235
17233
|
function settingsFile() {
|
|
17236
|
-
return
|
|
17234
|
+
return join27(resolveStorageDataDir(), "otium-settings.json");
|
|
17237
17235
|
}
|
|
17238
17236
|
function ensureSettingsLoaded() {
|
|
17239
17237
|
const path = settingsFile();
|
|
@@ -17259,7 +17257,7 @@ function setGlobalAiName(name) {
|
|
|
17259
17257
|
const path = ensureSettingsLoaded();
|
|
17260
17258
|
aiName = name.trim() || DEFAULT_AI_NAME;
|
|
17261
17259
|
try {
|
|
17262
|
-
mkdirSync18(
|
|
17260
|
+
mkdirSync18(dirname13(path), { recursive: true });
|
|
17263
17261
|
writeFileSync15(path, JSON.stringify({ aiName }, null, 2));
|
|
17264
17262
|
} catch {}
|
|
17265
17263
|
return aiName;
|
|
@@ -17342,7 +17340,7 @@ __export(exports_turn_runner, {
|
|
|
17342
17340
|
});
|
|
17343
17341
|
import { randomUUID as randomUUID17 } from "crypto";
|
|
17344
17342
|
import { existsSync as existsSync19, mkdirSync as mkdirSync19, readdirSync as readdirSync6, statSync as statSync10 } from "fs";
|
|
17345
|
-
import { join as
|
|
17343
|
+
import { join as join28 } from "path";
|
|
17346
17344
|
function withDefaultPlaywright(configuredMcp, isManager) {
|
|
17347
17345
|
if (isManager)
|
|
17348
17346
|
return configuredMcp;
|
|
@@ -17385,7 +17383,7 @@ function appendAskReplyMessage(topicId, text2, agentType) {
|
|
|
17385
17383
|
return message;
|
|
17386
17384
|
}
|
|
17387
17385
|
function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, matchesTitle, preferExact = true) {
|
|
17388
|
-
const preferred =
|
|
17386
|
+
const preferred = join28(directory, preferredFilename);
|
|
17389
17387
|
if (preferExact && existsSync19(preferred))
|
|
17390
17388
|
return preferred;
|
|
17391
17389
|
let newestLegacyId = null;
|
|
@@ -17396,7 +17394,7 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
|
|
|
17396
17394
|
const legacyIdMatch = !titleMatch && matchesLegacyId(filename);
|
|
17397
17395
|
if (!titleMatch && !legacyIdMatch)
|
|
17398
17396
|
continue;
|
|
17399
|
-
const path =
|
|
17397
|
+
const path = join28(directory, filename);
|
|
17400
17398
|
const mtimeMs = statSync10(path).mtimeMs;
|
|
17401
17399
|
if (titleMatch) {
|
|
17402
17400
|
if (!newestTitle || mtimeMs > newestTitle.mtimeMs) {
|
|
@@ -17410,9 +17408,9 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
|
|
|
17410
17408
|
return newestTitle?.path ?? newestLegacyId?.path ?? preferred;
|
|
17411
17409
|
}
|
|
17412
17410
|
function resolveWikiMemoryMirror(wikiDir, topicId, topicTitle) {
|
|
17413
|
-
const briefFile = resolveWikiMirrorPath(
|
|
17411
|
+
const briefFile = resolveWikiMirrorPath(join28(wikiDir, "topic"), `${wikiBriefStorageKey(topicTitle, topicId)}.md`, (filename) => isTopicBriefFile(filename, topicId), (filename) => isTopicBriefFile(filename, topicId, topicTitle));
|
|
17414
17412
|
const hasBriefFile = existsSync19(briefFile) && statSync10(briefFile).isFile();
|
|
17415
|
-
const latestSummaryCandidate = resolveWikiMirrorPath(
|
|
17413
|
+
const latestSummaryCandidate = resolveWikiMirrorPath(join28(wikiDir, "summaries"), `__missing__-${wikiSummaryFilename("0000-00-00", topicTitle, topicId)}`, (filename) => isTopicSummaryFile(filename, topicId), (filename) => isTopicSummaryFile(filename, topicId, topicTitle), false);
|
|
17416
17414
|
const latestSummaryFile = existsSync19(latestSummaryCandidate) && statSync10(latestSummaryCandidate).isFile() ? latestSummaryCandidate : null;
|
|
17417
17415
|
return { briefFile, hasBriefFile, latestSummaryFile };
|
|
17418
17416
|
}
|
|
@@ -20092,7 +20090,7 @@ var init_vault_command = __esm(async () => {
|
|
|
20092
20090
|
import { execFile } from "child_process";
|
|
20093
20091
|
import { existsSync as existsSync20, mkdirSync as mkdirSync21, readFileSync as readFileSync17, rmSync as rmSync7 } from "fs";
|
|
20094
20092
|
import { readFile } from "fs/promises";
|
|
20095
|
-
import { extname, join as
|
|
20093
|
+
import { extname, join as join29 } from "path";
|
|
20096
20094
|
import { promisify } from "util";
|
|
20097
20095
|
async function extractText(filePath) {
|
|
20098
20096
|
const ext = extname(filePath).toLowerCase();
|
|
@@ -20209,7 +20207,7 @@ async function extractFromAudio(filePath, opts = {}) {
|
|
|
20209
20207
|
const tmpDir = `${filePath}_whisper_tmp`;
|
|
20210
20208
|
try {
|
|
20211
20209
|
mkdirSync21(tmpDir, { recursive: true });
|
|
20212
|
-
const mp3Path =
|
|
20210
|
+
const mp3Path = join29(tmpDir, "audio.mp3");
|
|
20213
20211
|
await execFileAsync(opts.ffmpegBin ?? FFMPEG_BIN2, [
|
|
20214
20212
|
"-y",
|
|
20215
20213
|
"-i",
|
|
@@ -20236,7 +20234,7 @@ async function extractFromAudio(filePath, opts = {}) {
|
|
|
20236
20234
|
"--output-format",
|
|
20237
20235
|
"txt"
|
|
20238
20236
|
], { timeout: 120000 });
|
|
20239
|
-
const txtPath =
|
|
20237
|
+
const txtPath = join29(tmpDir, "audio.txt");
|
|
20240
20238
|
const text2 = existsSync20(txtPath) ? readFileSync17(txtPath, "utf-8").trim() : null;
|
|
20241
20239
|
if (!text2) {
|
|
20242
20240
|
return { text: null, method: "whisper", error: "Whisper produced no text" };
|
|
@@ -20759,7 +20757,7 @@ var init_utils = __esm(() => {
|
|
|
20759
20757
|
// ../../packages/core/src/runtime/inbox.ts
|
|
20760
20758
|
import { createHash as createHash7, randomUUID as randomUUID21 } from "crypto";
|
|
20761
20759
|
import { readdirSync as readdirSync7, statSync as statSync11, writeFileSync as writeFileSync16 } from "fs";
|
|
20762
|
-
import { join as
|
|
20760
|
+
import { join as join30 } from "path";
|
|
20763
20761
|
async function createAskForkPlan(options) {
|
|
20764
20762
|
const snapshot = structuredClone(options.entries);
|
|
20765
20763
|
const prepareSession = async () => options.synthesize(structuredClone(snapshot));
|
|
@@ -20884,7 +20882,7 @@ async function flushSessionInbox() {
|
|
|
20884
20882
|
return;
|
|
20885
20883
|
}
|
|
20886
20884
|
for (const uid of userDirs) {
|
|
20887
|
-
const userInboxDir =
|
|
20885
|
+
const userInboxDir = join30(SESSION_INBOX_DIR, uid);
|
|
20888
20886
|
let entries;
|
|
20889
20887
|
try {
|
|
20890
20888
|
entries = readdirSync7(userInboxDir);
|
|
@@ -20892,7 +20890,7 @@ async function flushSessionInbox() {
|
|
|
20892
20890
|
continue;
|
|
20893
20891
|
}
|
|
20894
20892
|
for (const entry of entries) {
|
|
20895
|
-
const entryPath =
|
|
20893
|
+
const entryPath = join30(userInboxDir, entry);
|
|
20896
20894
|
let isDir = false;
|
|
20897
20895
|
try {
|
|
20898
20896
|
isDir = statSync11(entryPath).isDirectory();
|
|
@@ -20982,7 +20980,7 @@ function sweepScheduledSessionInbox(nowMs = Date.now()) {
|
|
|
20982
20980
|
return;
|
|
20983
20981
|
}
|
|
20984
20982
|
for (const userId of userDirs) {
|
|
20985
|
-
const userInboxDir =
|
|
20983
|
+
const userInboxDir = join30(SESSION_INBOX_DIR, userId);
|
|
20986
20984
|
let files;
|
|
20987
20985
|
try {
|
|
20988
20986
|
files = readdirSync7(userInboxDir);
|
|
@@ -20994,7 +20992,7 @@ function sweepScheduledSessionInbox(nowMs = Date.now()) {
|
|
|
20994
20992
|
const topicId = topicIdFromScheduledSessionInboxFileName(file);
|
|
20995
20993
|
if (!topicId)
|
|
20996
20994
|
continue;
|
|
20997
|
-
const schedulePath =
|
|
20995
|
+
const schedulePath = join30(userInboxDir, file);
|
|
20998
20996
|
const hasProcessingClaim = files.includes(`${file}.processing`);
|
|
20999
20997
|
if (!hasProcessingClaim && !scheduledFileNeedsClaim(schedulePath, nowMs))
|
|
21000
20998
|
continue;
|
|
@@ -21718,7 +21716,7 @@ var init_src = __esm(async () => {
|
|
|
21718
21716
|
|
|
21719
21717
|
// ../../packages/core/src/storage/conversation-migration.ts
|
|
21720
21718
|
import { copyFileSync as copyFileSync3, existsSync as existsSync22, mkdirSync as mkdirSync23, readFileSync as readFileSync19 } from "fs";
|
|
21721
|
-
import { dirname as
|
|
21719
|
+
import { dirname as dirname14, join as join31 } from "path";
|
|
21722
21720
|
function readEntries(path) {
|
|
21723
21721
|
const entries = [];
|
|
21724
21722
|
for (const [index, line] of readFileSync19(path, "utf8").split(`
|
|
@@ -21785,7 +21783,7 @@ function migrateLegacyCompactedConversations() {
|
|
|
21785
21783
|
result.skipped++;
|
|
21786
21784
|
continue;
|
|
21787
21785
|
}
|
|
21788
|
-
const backupPath =
|
|
21786
|
+
const backupPath = join31(resolveStorageDataDir(), "conversation-migration-backups", MIGRATION_NAME, userId, `${sanitizeTopicName(topic.title, true)}.jsonl`);
|
|
21789
21787
|
const sourcePath = existsSync22(backupPath) ? backupPath : rawPath;
|
|
21790
21788
|
const legacyEntries = readEntries(sourcePath);
|
|
21791
21789
|
const compactIndex = compactionEntryIndex(legacyEntries);
|
|
@@ -21794,7 +21792,7 @@ function migrateLegacyCompactedConversations() {
|
|
|
21794
21792
|
continue;
|
|
21795
21793
|
}
|
|
21796
21794
|
if (!existsSync22(backupPath)) {
|
|
21797
|
-
mkdirSync23(
|
|
21795
|
+
mkdirSync23(dirname14(backupPath), { recursive: true });
|
|
21798
21796
|
copyFileSync3(rawPath, backupPath);
|
|
21799
21797
|
}
|
|
21800
21798
|
const compactedAt = legacyEntries[compactIndex]?.ts;
|
|
@@ -22520,7 +22518,7 @@ __export(exports_agent_health, {
|
|
|
22520
22518
|
});
|
|
22521
22519
|
import { spawn as spawn5 } from "child_process";
|
|
22522
22520
|
import { existsSync as existsSync23, readdirSync as readdirSync8 } from "fs";
|
|
22523
|
-
import { join as
|
|
22521
|
+
import { join as join32 } from "path";
|
|
22524
22522
|
import { McpServer as McpServer4 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
22525
22523
|
import { z as z8 } from "zod";
|
|
22526
22524
|
function signalProcessTree2(child, signal) {
|
|
@@ -22764,7 +22762,7 @@ ${results.every((result) => result.ok) ? "All agents healthy" : "Some agents fai
|
|
|
22764
22762
|
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 () => {
|
|
22765
22763
|
if (!context.userId)
|
|
22766
22764
|
return mcpOk("\uC2E4\uD589 \uC911\uC778 \uCFFC\uB9AC \uC870\uD68C \uBD88\uAC00 (user context \uC5C6\uC74C)");
|
|
22767
|
-
const stateDir =
|
|
22765
|
+
const stateDir = join32(USERS_LOG_DIR, context.userId, "active-queries");
|
|
22768
22766
|
if (!existsSync23(stateDir))
|
|
22769
22767
|
return mcpOk("\uC2E4\uD589 \uC911\uC778 \uCFFC\uB9AC \uC5C6\uC74C");
|
|
22770
22768
|
let files;
|
|
@@ -22777,7 +22775,7 @@ ${results.every((result) => result.ok) ? "All agents healthy" : "Some agents fai
|
|
|
22777
22775
|
const entries = files.flatMap((file) => {
|
|
22778
22776
|
if (!file.endsWith(".json"))
|
|
22779
22777
|
return [];
|
|
22780
|
-
const state = readJsonFile(
|
|
22778
|
+
const state = readJsonFile(join32(stateDir, file));
|
|
22781
22779
|
if (!state)
|
|
22782
22780
|
return [];
|
|
22783
22781
|
const sinceMs = new Date(state.since).getTime();
|
|
@@ -22986,7 +22984,7 @@ var exports_default_host = {};
|
|
|
22986
22984
|
__export(exports_default_host, {
|
|
22987
22985
|
createDefaultSessionCommMcpHost: () => createDefaultSessionCommMcpHost
|
|
22988
22986
|
});
|
|
22989
|
-
import { basename as basename6, join as
|
|
22987
|
+
import { basename as basename6, join as join33 } from "path";
|
|
22990
22988
|
function ok2(text2) {
|
|
22991
22989
|
return { content: [{ type: "text", text: text2 }] };
|
|
22992
22990
|
}
|
|
@@ -23028,10 +23026,10 @@ function remoteTarget(context, to) {
|
|
|
23028
23026
|
return { node: to.slice(0, slash), topic: to.slice(slash + 1) };
|
|
23029
23027
|
}
|
|
23030
23028
|
function activeQuery(context, topicId, title) {
|
|
23031
|
-
const dir =
|
|
23032
|
-
const candidates = [
|
|
23029
|
+
const dir = join33(USERS_LOG_DIR, context.userId, "active-queries");
|
|
23030
|
+
const candidates = [join33(dir, `${sanitizeId(topicId)}.json`)];
|
|
23033
23031
|
if (title && basename6(title) === title && title !== "." && title !== "..") {
|
|
23034
|
-
candidates.push(
|
|
23032
|
+
candidates.push(join33(dir, `${title}.json`));
|
|
23035
23033
|
}
|
|
23036
23034
|
for (const path of candidates) {
|
|
23037
23035
|
const state = readJsonFile(path);
|
|
@@ -23676,7 +23674,7 @@ import {
|
|
|
23676
23674
|
unlinkSync as unlinkSync18,
|
|
23677
23675
|
writeFileSync as writeFileSync17
|
|
23678
23676
|
} from "fs";
|
|
23679
|
-
import { basename as basename7, dirname as
|
|
23677
|
+
import { basename as basename7, dirname as dirname15, join as join34, resolve as resolve16 } from "path";
|
|
23680
23678
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
23681
23679
|
import { StdioServerTransport as StdioServerTransport2 } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
23682
23680
|
import {
|
|
@@ -23825,13 +23823,13 @@ function wikiQuery(args) {
|
|
|
23825
23823
|
try {
|
|
23826
23824
|
for (const entry of readdirSync9(dir, { withFileTypes: true })) {
|
|
23827
23825
|
if (entry.isDirectory()) {
|
|
23828
|
-
const sub =
|
|
23826
|
+
const sub = join34(dir, entry.name);
|
|
23829
23827
|
if (label === "articles" || label === "skills") {
|
|
23830
23828
|
try {
|
|
23831
23829
|
for (const f of readdirSync9(sub, { withFileTypes: true })) {
|
|
23832
23830
|
if (!f.isFile() || !f.name.endsWith(".md"))
|
|
23833
23831
|
continue;
|
|
23834
|
-
const fp =
|
|
23832
|
+
const fp = join34(sub, f.name);
|
|
23835
23833
|
try {
|
|
23836
23834
|
const text2 = readFileSync20(fp, "utf-8");
|
|
23837
23835
|
scored.push({
|
|
@@ -23844,7 +23842,7 @@ function wikiQuery(args) {
|
|
|
23844
23842
|
} catch {}
|
|
23845
23843
|
}
|
|
23846
23844
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
23847
|
-
const fp =
|
|
23845
|
+
const fp = join34(dir, entry.name);
|
|
23848
23846
|
try {
|
|
23849
23847
|
const text2 = readFileSync20(fp, "utf-8");
|
|
23850
23848
|
scored.push({
|
|
@@ -24193,7 +24191,7 @@ function saveTopicBrief(args) {
|
|
|
24193
24191
|
const topicId = runtime().topicId;
|
|
24194
24192
|
const fileSlug = wikiBriefStorageKey(rawTopic, topicId);
|
|
24195
24193
|
const briefPath = resolve16(runtime().topicsDir, `${fileSlug}.md`);
|
|
24196
|
-
ensureDir(
|
|
24194
|
+
ensureDir(dirname15(briefPath));
|
|
24197
24195
|
const existed = existsSync24(briefPath);
|
|
24198
24196
|
writeFileSync17(briefPath, content, "utf-8");
|
|
24199
24197
|
const setTopicBrief2 = runtime().host.setTopicBrief;
|
|
@@ -24231,7 +24229,7 @@ function indexUpsert(args) {
|
|
|
24231
24229
|
return resolve16(runtime().wikiDir, "skill-index.md");
|
|
24232
24230
|
return resolve16(runtime().wikiDir, "article-index.md");
|
|
24233
24231
|
})();
|
|
24234
|
-
ensureDir(
|
|
24232
|
+
ensureDir(dirname15(indexPath));
|
|
24235
24233
|
const releaseLock = acquireFileLock(indexPath);
|
|
24236
24234
|
try {
|
|
24237
24235
|
let index;
|
|
@@ -24529,7 +24527,7 @@ import {
|
|
|
24529
24527
|
unlinkSync as unlinkSync19,
|
|
24530
24528
|
writeFileSync as writeFileSync18
|
|
24531
24529
|
} from "fs";
|
|
24532
|
-
import { basename as basename8, join as
|
|
24530
|
+
import { basename as basename8, join as join35 } from "path";
|
|
24533
24531
|
function startLogRotation() {
|
|
24534
24532
|
if (rotationTimer)
|
|
24535
24533
|
return;
|
|
@@ -24543,7 +24541,7 @@ function writeLog(entry) {
|
|
|
24543
24541
|
mkdirSync25(logDir, { recursive: true });
|
|
24544
24542
|
const safeSession = sanitizeTopicName(entry.session);
|
|
24545
24543
|
const sidShort = entry.sessionId ? entry.sessionId.slice(0, 8) : "new";
|
|
24546
|
-
const file =
|
|
24544
|
+
const file = join35(logDir, `${entry.userId}_${safeSession}_${sidShort}.jsonl`);
|
|
24547
24545
|
try {
|
|
24548
24546
|
const stat = statSync13(file);
|
|
24549
24547
|
if (stat.size >= MAX_FILE_SIZE) {
|
|
@@ -24563,7 +24561,7 @@ function rotateOldLogs() {
|
|
|
24563
24561
|
try {
|
|
24564
24562
|
const files = readdirSync10(logDir).filter((f) => f.endsWith(".jsonl")).map((f) => {
|
|
24565
24563
|
try {
|
|
24566
|
-
const stat = statSync13(
|
|
24564
|
+
const stat = statSync13(join35(logDir, f));
|
|
24567
24565
|
return { name: f, size: stat.size, mtimeMs: stat.mtimeMs };
|
|
24568
24566
|
} catch {
|
|
24569
24567
|
return null;
|
|
@@ -24579,7 +24577,7 @@ function rotateOldLogs() {
|
|
|
24579
24577
|
if (freed >= toFree)
|
|
24580
24578
|
break;
|
|
24581
24579
|
try {
|
|
24582
|
-
unlinkSync19(
|
|
24580
|
+
unlinkSync19(join35(logDir, file.name));
|
|
24583
24581
|
freed += file.size;
|
|
24584
24582
|
logger.info({ file: file.name, sizeKB: (file.size / 1024).toFixed(0) }, "Rotated out old log");
|
|
24585
24583
|
} catch (e) {
|
|
@@ -24591,9 +24589,9 @@ function rotateOldLogs() {
|
|
|
24591
24589
|
}
|
|
24592
24590
|
}
|
|
24593
24591
|
function writeSentFileLog(entry) {
|
|
24594
|
-
const dir =
|
|
24592
|
+
const dir = join35(resolveStorageUsersLogDir(), String(entry.userId));
|
|
24595
24593
|
mkdirSync25(dir, { recursive: true });
|
|
24596
|
-
const file =
|
|
24594
|
+
const file = join35(dir, "sent-files.jsonl");
|
|
24597
24595
|
try {
|
|
24598
24596
|
appendJsonlEntry(file, { ...entry, fileName: basename8(entry.filePath) });
|
|
24599
24597
|
} catch (e) {
|
|
@@ -24604,7 +24602,7 @@ function entryMatchesTopic(e, topicName) {
|
|
|
24604
24602
|
return e.topicName === topicName;
|
|
24605
24603
|
}
|
|
24606
24604
|
function readSentFilesForTopic(userId, topicName) {
|
|
24607
|
-
const file =
|
|
24605
|
+
const file = join35(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
|
|
24608
24606
|
if (!existsSync25(file))
|
|
24609
24607
|
return [];
|
|
24610
24608
|
try {
|
|
@@ -24615,7 +24613,7 @@ function readSentFilesForTopic(userId, topicName) {
|
|
|
24615
24613
|
}
|
|
24616
24614
|
}
|
|
24617
24615
|
function removeSentFilesForTopic(userId, topicName) {
|
|
24618
|
-
const file =
|
|
24616
|
+
const file = join35(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
|
|
24619
24617
|
if (!existsSync25(file))
|
|
24620
24618
|
return;
|
|
24621
24619
|
try {
|
|
@@ -26137,7 +26135,7 @@ var init_spec = __esm(() => {
|
|
|
26137
26135
|
|
|
26138
26136
|
// ../../packages/mcp-host/src/manifest.ts
|
|
26139
26137
|
import { existsSync as existsSync26, mkdirSync as mkdirSync26, readFileSync as readFileSync21, renameSync as renameSync11, writeFileSync as writeFileSync19 } from "fs";
|
|
26140
|
-
import { dirname as
|
|
26138
|
+
import { dirname as dirname16 } from "path";
|
|
26141
26139
|
import { z as z13 } from "zod";
|
|
26142
26140
|
|
|
26143
26141
|
class McpManifest {
|
|
@@ -26197,7 +26195,7 @@ class McpManifest {
|
|
|
26197
26195
|
}
|
|
26198
26196
|
}
|
|
26199
26197
|
save() {
|
|
26200
|
-
mkdirSync26(
|
|
26198
|
+
mkdirSync26(dirname16(this.file), { recursive: true });
|
|
26201
26199
|
const payload = {
|
|
26202
26200
|
version: 1,
|
|
26203
26201
|
servers: [...this.entries.values()]
|
|
@@ -26241,7 +26239,7 @@ import {
|
|
|
26241
26239
|
writeFileSync as writeFileSync20
|
|
26242
26240
|
} from "fs";
|
|
26243
26241
|
import { connect, createServer as createServer3 } from "net";
|
|
26244
|
-
import { join as
|
|
26242
|
+
import { join as join36 } from "path";
|
|
26245
26243
|
function regKey(key, instanceKey) {
|
|
26246
26244
|
return `${key}\x00${instanceKey}`;
|
|
26247
26245
|
}
|
|
@@ -26543,7 +26541,7 @@ class McpHost {
|
|
|
26543
26541
|
if (file.includes(".tmp-"))
|
|
26544
26542
|
continue;
|
|
26545
26543
|
try {
|
|
26546
|
-
const port = Number.parseInt(readFileSync22(
|
|
26544
|
+
const port = Number.parseInt(readFileSync22(join36(this.portsDir, file), "utf8").trim(), 10);
|
|
26547
26545
|
if (!Number.isNaN(port))
|
|
26548
26546
|
claims.set(file, port);
|
|
26549
26547
|
} catch {}
|
|
@@ -26553,7 +26551,7 @@ class McpHost {
|
|
|
26553
26551
|
writePortFile(fileName, port) {
|
|
26554
26552
|
try {
|
|
26555
26553
|
mkdirSync27(this.portsDir, { recursive: true });
|
|
26556
|
-
const file =
|
|
26554
|
+
const file = join36(this.portsDir, fileName);
|
|
26557
26555
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
26558
26556
|
writeFileSync20(tmp, String(port));
|
|
26559
26557
|
renameSync12(tmp, file);
|
|
@@ -26563,7 +26561,7 @@ class McpHost {
|
|
|
26563
26561
|
}
|
|
26564
26562
|
deletePortFile(fileName) {
|
|
26565
26563
|
try {
|
|
26566
|
-
unlinkSync20(
|
|
26564
|
+
unlinkSync20(join36(this.portsDir, fileName));
|
|
26567
26565
|
} catch {}
|
|
26568
26566
|
}
|
|
26569
26567
|
cleanupRunning(rkey, inst) {
|
|
@@ -26675,7 +26673,7 @@ import {
|
|
|
26675
26673
|
statSync as statSync15,
|
|
26676
26674
|
writeFileSync as writeFileSync21
|
|
26677
26675
|
} from "fs";
|
|
26678
|
-
import { basename as basename10, extname as extname3, join as
|
|
26676
|
+
import { basename as basename10, extname as extname3, join as join37 } from "path";
|
|
26679
26677
|
function safeExtension(filename) {
|
|
26680
26678
|
const extension = extname3(basename10(filename));
|
|
26681
26679
|
return /^\.[A-Za-z0-9]{1,16}$/.test(extension) ? extension.toLowerCase() : "";
|
|
@@ -26693,14 +26691,14 @@ function contentDisposition(filename) {
|
|
|
26693
26691
|
|
|
26694
26692
|
class NodeFileStore {
|
|
26695
26693
|
uploadDir;
|
|
26696
|
-
constructor(uploadDir =
|
|
26694
|
+
constructor(uploadDir = join37(DATA_DIR, "uploads")) {
|
|
26697
26695
|
this.uploadDir = uploadDir;
|
|
26698
26696
|
}
|
|
26699
26697
|
#ensureDir() {
|
|
26700
26698
|
mkdirSync28(this.uploadDir, { recursive: true });
|
|
26701
26699
|
}
|
|
26702
26700
|
#metadataPath(fileId) {
|
|
26703
|
-
return
|
|
26701
|
+
return join37(this.uploadDir, `${fileId}.meta.json`);
|
|
26704
26702
|
}
|
|
26705
26703
|
#metadata(fileId) {
|
|
26706
26704
|
if (!FILE_ID_RE.test(fileId))
|
|
@@ -26729,7 +26727,7 @@ class NodeFileStore {
|
|
|
26729
26727
|
hooks = {
|
|
26730
26728
|
resolveAttachmentByFileId: (fileId) => {
|
|
26731
26729
|
const metadata = this.#metadata(fileId);
|
|
26732
|
-
if (!metadata || !existsSync27(
|
|
26730
|
+
if (!metadata || !existsSync27(join37(this.uploadDir, metadata.savedName)))
|
|
26733
26731
|
return null;
|
|
26734
26732
|
return this.#attachment(fileId, metadata);
|
|
26735
26733
|
},
|
|
@@ -26737,7 +26735,7 @@ class NodeFileStore {
|
|
|
26737
26735
|
const metadata = this.#metadata(fileId);
|
|
26738
26736
|
if (!metadata)
|
|
26739
26737
|
return null;
|
|
26740
|
-
const path =
|
|
26738
|
+
const path = join37(this.uploadDir, metadata.savedName);
|
|
26741
26739
|
return existsSync27(path) ? path : null;
|
|
26742
26740
|
},
|
|
26743
26741
|
storeLocalFileAsUpload: (absPath, access = {}) => this.store(absPath, access),
|
|
@@ -26748,7 +26746,7 @@ class NodeFileStore {
|
|
|
26748
26746
|
const fileId = randomUUID25();
|
|
26749
26747
|
const extension = safeExtension(absPath);
|
|
26750
26748
|
const savedName = `${fileId}${extension}`;
|
|
26751
|
-
const savedPath =
|
|
26749
|
+
const savedPath = join37(this.uploadDir, savedName);
|
|
26752
26750
|
try {
|
|
26753
26751
|
const stats = statSync15(absPath);
|
|
26754
26752
|
if (!stats.isFile() || stats.size > MAX_UPLOAD_BYTES)
|
|
@@ -26780,7 +26778,7 @@ class NodeFileStore {
|
|
|
26780
26778
|
const allowed = metadata.visibility === "workspace" || metadata.ownerUserId === userId || Boolean(topic && isParticipant(topic, userId));
|
|
26781
26779
|
if (!allowed)
|
|
26782
26780
|
return null;
|
|
26783
|
-
const path =
|
|
26781
|
+
const path = join37(this.uploadDir, metadata.savedName);
|
|
26784
26782
|
if (!existsSync27(path))
|
|
26785
26783
|
return null;
|
|
26786
26784
|
return new Response(Bun.file(path), {
|
|
@@ -26799,7 +26797,7 @@ class NodeFileStore {
|
|
|
26799
26797
|
const metadata = this.#metadata(fileId);
|
|
26800
26798
|
if (metadata?.topicId !== topicId)
|
|
26801
26799
|
continue;
|
|
26802
|
-
rmSync8(
|
|
26800
|
+
rmSync8(join37(this.uploadDir, metadata.savedName), { force: true });
|
|
26803
26801
|
rmSync8(this.#metadataPath(fileId), { force: true });
|
|
26804
26802
|
}
|
|
26805
26803
|
}
|
|
@@ -26958,7 +26956,7 @@ import {
|
|
|
26958
26956
|
unlinkSync as unlinkSync21,
|
|
26959
26957
|
writeFileSync as writeFileSync22
|
|
26960
26958
|
} from "fs";
|
|
26961
|
-
import { dirname as
|
|
26959
|
+
import { dirname as dirname17, resolve as resolve20 } from "path";
|
|
26962
26960
|
function jsonError(status, error2) {
|
|
26963
26961
|
return Response.json({ ok: false, error: error2 }, { status });
|
|
26964
26962
|
}
|
|
@@ -27444,7 +27442,7 @@ function writeNodeDaemonInfo(port, startedAt) {
|
|
|
27444
27442
|
stateDir: STATE_DIR,
|
|
27445
27443
|
startedAt
|
|
27446
27444
|
};
|
|
27447
|
-
mkdirSync29(
|
|
27445
|
+
mkdirSync29(dirname17(NODE_DAEMON_INFO_PATH), { recursive: true });
|
|
27448
27446
|
const temporary = `${NODE_DAEMON_INFO_PATH}.${process.pid}.${randomUUID26()}.tmp`;
|
|
27449
27447
|
writeFileSync22(temporary, `${JSON.stringify(info, null, 2)}
|
|
27450
27448
|
`, { mode: 384 });
|
|
@@ -29002,7 +29000,7 @@ var init_scheduler = __esm(async () => {
|
|
|
29002
29000
|
|
|
29003
29001
|
// ../../packages/module-cron/src/module.ts
|
|
29004
29002
|
import { existsSync as existsSync30 } from "fs";
|
|
29005
|
-
import { fileURLToPath as
|
|
29003
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
29006
29004
|
function envMs(name, fallback) {
|
|
29007
29005
|
const parsed = Number.parseInt(process.env[name] ?? "", 10);
|
|
29008
29006
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
@@ -29127,8 +29125,8 @@ var init_module = __esm(async () => {
|
|
|
29127
29125
|
init_scripts(),
|
|
29128
29126
|
init_store()
|
|
29129
29127
|
]);
|
|
29130
|
-
SOURCE_MCP_SERVER_FILE =
|
|
29131
|
-
PACKAGED_MCP_SERVER_FILE =
|
|
29128
|
+
SOURCE_MCP_SERVER_FILE = fileURLToPath2(new URL("./mcp-server.ts", import.meta.url));
|
|
29129
|
+
PACKAGED_MCP_SERVER_FILE = fileURLToPath2(new URL("./runtime/cron/mcp-server.ts", import.meta.url));
|
|
29132
29130
|
});
|
|
29133
29131
|
|
|
29134
29132
|
// ../../packages/module-cron/src/summarize.ts
|
|
@@ -29708,7 +29706,7 @@ var init_commands = __esm(() => {
|
|
|
29708
29706
|
import { execFile as execFile3 } from "child_process";
|
|
29709
29707
|
import { existsSync as existsSync31, readdirSync as readdirSync13, statSync as statSync16 } from "fs";
|
|
29710
29708
|
import { homedir as homedir11 } from "os";
|
|
29711
|
-
import { basename as basename11, dirname as
|
|
29709
|
+
import { basename as basename11, dirname as dirname18, join as join38, sep as sep3 } from "path";
|
|
29712
29710
|
import { promisify as promisify3 } from "util";
|
|
29713
29711
|
function indexRecursivePaths(files) {
|
|
29714
29712
|
const paths = [];
|
|
@@ -29809,15 +29807,15 @@ function resolveFragment(frag) {
|
|
|
29809
29807
|
else if (frag === "~/")
|
|
29810
29808
|
path = home;
|
|
29811
29809
|
else if (frag.startsWith("~/"))
|
|
29812
|
-
path =
|
|
29810
|
+
path = join38(home, frag.slice(2));
|
|
29813
29811
|
else if (frag.startsWith("/"))
|
|
29814
29812
|
path = frag;
|
|
29815
29813
|
else
|
|
29816
|
-
path =
|
|
29814
|
+
path = join38(home, frag);
|
|
29817
29815
|
if (frag.endsWith("/") || frag === "" || frag === "~") {
|
|
29818
29816
|
return { dir: path, prefix: "" };
|
|
29819
29817
|
}
|
|
29820
|
-
return { dir:
|
|
29818
|
+
return { dir: dirname18(path), prefix: basename11(path) };
|
|
29821
29819
|
}
|
|
29822
29820
|
function toToken(fullPath, isDir) {
|
|
29823
29821
|
const home = homedir11();
|
|
@@ -29842,7 +29840,7 @@ function rankAndSlice(dir, candidates) {
|
|
|
29842
29840
|
});
|
|
29843
29841
|
return candidates.slice(0, MAX_SUGGESTIONS).map(({ relPath, isDir }) => ({
|
|
29844
29842
|
label: `${relPath}${isDir ? "/" : ""}`,
|
|
29845
|
-
value: toToken(
|
|
29843
|
+
value: toToken(join38(dir, relPath), isDir),
|
|
29846
29844
|
isDir
|
|
29847
29845
|
}));
|
|
29848
29846
|
}
|
|
@@ -29921,7 +29919,7 @@ function pathSuggestions(lineText, col) {
|
|
|
29921
29919
|
let isDir = entry.isDirectory();
|
|
29922
29920
|
if (!isDir && entry.isSymbolicLink()) {
|
|
29923
29921
|
try {
|
|
29924
|
-
isDir = statSync16(
|
|
29922
|
+
isDir = statSync16(join38(dir, entry.name)).isDirectory();
|
|
29925
29923
|
} catch {}
|
|
29926
29924
|
}
|
|
29927
29925
|
return {
|
|
@@ -29948,10 +29946,10 @@ function fragmentToAbsolutePath(frag) {
|
|
|
29948
29946
|
if (frag === "~" || frag === "~/")
|
|
29949
29947
|
return home;
|
|
29950
29948
|
if (frag.startsWith("~/"))
|
|
29951
|
-
return
|
|
29949
|
+
return join38(home, frag.slice(2));
|
|
29952
29950
|
if (frag.startsWith("/"))
|
|
29953
29951
|
return frag;
|
|
29954
|
-
return
|
|
29952
|
+
return join38(home, frag);
|
|
29955
29953
|
}
|
|
29956
29954
|
function fragmentResolves(frag) {
|
|
29957
29955
|
try {
|
|
@@ -36825,7 +36823,7 @@ var init_commands2 = __esm(async () => {
|
|
|
36825
36823
|
// ../../adapters/telegram/src/mapping-store.ts
|
|
36826
36824
|
import { Database as Database2 } from "bun:sqlite";
|
|
36827
36825
|
import { mkdirSync as mkdirSync31 } from "fs";
|
|
36828
|
-
import { dirname as
|
|
36826
|
+
import { dirname as dirname19, join as join39 } from "path";
|
|
36829
36827
|
function outboxRowToEntry(row) {
|
|
36830
36828
|
return {
|
|
36831
36829
|
id: row.id,
|
|
@@ -36891,9 +36889,9 @@ function migrateOutboxSchema(db4) {
|
|
|
36891
36889
|
db4.run("CREATE INDEX IF NOT EXISTS idx_telegram_outbox_runtime_message ON outbox(runtime_message_id)");
|
|
36892
36890
|
}
|
|
36893
36891
|
function openMappingStore(path) {
|
|
36894
|
-
const dbPath = path ??
|
|
36892
|
+
const dbPath = path ?? join39(DATA_DIR, "adapter-telegram.db");
|
|
36895
36893
|
if (dbPath !== ":memory:")
|
|
36896
|
-
mkdirSync31(
|
|
36894
|
+
mkdirSync31(dirname19(dbPath), { recursive: true });
|
|
36897
36895
|
const db4 = new Database2(dbPath);
|
|
36898
36896
|
migrateLegacySchema(db4);
|
|
36899
36897
|
createTables(db4);
|
|
@@ -38754,8 +38752,8 @@ __export(exports_central, {
|
|
|
38754
38752
|
listPeerNodes: () => listPeerNodes,
|
|
38755
38753
|
configureOtiumCentral: () => configureOtiumCentral
|
|
38756
38754
|
});
|
|
38757
|
-
function configureOtiumCentral(
|
|
38758
|
-
joinConfig =
|
|
38755
|
+
function configureOtiumCentral(join40) {
|
|
38756
|
+
joinConfig = join40;
|
|
38759
38757
|
resetPeerCentralCaches();
|
|
38760
38758
|
}
|
|
38761
38759
|
function otiumCentralConfig() {
|
|
@@ -38925,7 +38923,7 @@ import {
|
|
|
38925
38923
|
unlinkSync as unlinkSync22,
|
|
38926
38924
|
writeFileSync as writeFileSync23
|
|
38927
38925
|
} from "fs";
|
|
38928
|
-
import { dirname as
|
|
38926
|
+
import { dirname as dirname20, resolve as resolve22 } from "path";
|
|
38929
38927
|
function joinFilePath() {
|
|
38930
38928
|
return resolve22(DATA_DIR, "otium-join.json");
|
|
38931
38929
|
}
|
|
@@ -38998,7 +38996,7 @@ function withJoinCredentialLock(operation) {
|
|
|
38998
38996
|
const lockPath = joinLockPath();
|
|
38999
38997
|
const ownerPath = resolve22(lockPath, "owner.json");
|
|
39000
38998
|
const owner = { pid: process.pid, token: randomUUID28() };
|
|
39001
|
-
mkdirSync32(
|
|
38999
|
+
mkdirSync32(dirname20(lockPath), { recursive: true });
|
|
39002
39000
|
for (let attempt = 0;; attempt += 1) {
|
|
39003
39001
|
let created = false;
|
|
39004
39002
|
try {
|
|
@@ -39062,17 +39060,17 @@ function withJoinCredentialLock(operation) {
|
|
|
39062
39060
|
function joinsEqual(left, right) {
|
|
39063
39061
|
return left.central === right.central && left.relay === right.relay && left.cellId === right.cellId && left.secret === right.secret;
|
|
39064
39062
|
}
|
|
39065
|
-
function normalizedJoin(
|
|
39063
|
+
function normalizedJoin(join40) {
|
|
39066
39064
|
return normalizeJoin({
|
|
39067
|
-
v:
|
|
39068
|
-
central:
|
|
39069
|
-
relay:
|
|
39070
|
-
cellId:
|
|
39071
|
-
secret:
|
|
39065
|
+
v: join40.v,
|
|
39066
|
+
central: join40.central,
|
|
39067
|
+
relay: join40.relay,
|
|
39068
|
+
cellId: join40.cellId,
|
|
39069
|
+
secret: join40.secret
|
|
39072
39070
|
});
|
|
39073
39071
|
}
|
|
39074
|
-
function joinCredentialDigest(
|
|
39075
|
-
return createHash9("sha256").update(JSON.stringify(normalizedJoin(
|
|
39072
|
+
function joinCredentialDigest(join40) {
|
|
39073
|
+
return createHash9("sha256").update(JSON.stringify(normalizedJoin(join40))).digest("base64url");
|
|
39076
39074
|
}
|
|
39077
39075
|
function readPersistedJoin(path = joinFilePath()) {
|
|
39078
39076
|
if (!existsSync33(path))
|
|
@@ -39083,18 +39081,18 @@ function readPersistedJoin(path = joinFilePath()) {
|
|
|
39083
39081
|
}
|
|
39084
39082
|
return normalizeJoin(parsed);
|
|
39085
39083
|
}
|
|
39086
|
-
function isJoinPersisted(
|
|
39084
|
+
function isJoinPersisted(join40) {
|
|
39087
39085
|
try {
|
|
39088
39086
|
const persisted = readPersistedJoin();
|
|
39089
|
-
return persisted !== null && joinsEqual(persisted, normalizedJoin(
|
|
39087
|
+
return persisted !== null && joinsEqual(persisted, normalizedJoin(join40));
|
|
39090
39088
|
} catch {
|
|
39091
39089
|
return false;
|
|
39092
39090
|
}
|
|
39093
39091
|
}
|
|
39094
|
-
function saveJoinWhileLocked(
|
|
39092
|
+
function saveJoinWhileLocked(join40, options = {}) {
|
|
39095
39093
|
const path = joinFilePath();
|
|
39096
|
-
const directory =
|
|
39097
|
-
const normalized = normalizedJoin(
|
|
39094
|
+
const directory = dirname20(path);
|
|
39095
|
+
const normalized = normalizedJoin(join40);
|
|
39098
39096
|
mkdirSync32(directory, { recursive: true });
|
|
39099
39097
|
if (existsSync33(path)) {
|
|
39100
39098
|
if (lstatSync(path).isSymbolicLink()) {
|
|
@@ -39159,8 +39157,8 @@ function saveJoinWhileLocked(join41, options = {}) {
|
|
|
39159
39157
|
}
|
|
39160
39158
|
return path;
|
|
39161
39159
|
}
|
|
39162
|
-
function saveJoin(
|
|
39163
|
-
return withJoinCredentialLock(() => saveJoinWhileLocked(
|
|
39160
|
+
function saveJoin(join40, options = {}) {
|
|
39161
|
+
return withJoinCredentialLock(() => saveJoinWhileLocked(join40, options));
|
|
39164
39162
|
}
|
|
39165
39163
|
function removeJoin() {
|
|
39166
39164
|
return withJoinCredentialLock(() => {
|
|
@@ -39171,7 +39169,7 @@ function removeJoin() {
|
|
|
39171
39169
|
throw new Error(`refusing to remove symlinked Otium join file at ${path}`);
|
|
39172
39170
|
}
|
|
39173
39171
|
unlinkSync22(path);
|
|
39174
|
-
const directoryFd = openSync4(
|
|
39172
|
+
const directoryFd = openSync4(dirname20(path), "r");
|
|
39175
39173
|
try {
|
|
39176
39174
|
fsyncSync2(directoryFd);
|
|
39177
39175
|
} finally {
|
|
@@ -40178,7 +40176,7 @@ var init_event_backflow = __esm(async () => {
|
|
|
40178
40176
|
// ../../adapters/otium/src/peer-files.ts
|
|
40179
40177
|
import { randomUUID as randomUUID30 } from "crypto";
|
|
40180
40178
|
import { copyFileSync as copyFileSync5, mkdirSync as mkdirSync33, rmSync as rmSync10, statSync as statSync18 } from "fs";
|
|
40181
|
-
import { basename as basename13, extname as extname5, join as
|
|
40179
|
+
import { basename as basename13, extname as extname5, join as join40 } from "path";
|
|
40182
40180
|
function fileType(mimeType) {
|
|
40183
40181
|
if (mimeType.startsWith("image/"))
|
|
40184
40182
|
return "image";
|
|
@@ -40248,7 +40246,7 @@ function recordFile(args) {
|
|
|
40248
40246
|
function insertLocalFile(args) {
|
|
40249
40247
|
const id = randomUUID30();
|
|
40250
40248
|
mkdirSync33(PEER_FILES_DIR, { recursive: true });
|
|
40251
|
-
const path =
|
|
40249
|
+
const path = join40(PEER_FILES_DIR, `${id}-${safeFilename(args.filename)}`);
|
|
40252
40250
|
copyFileSync5(args.sourcePath, path);
|
|
40253
40251
|
return recordFile({ id, path, sizeBytes: statSync18(path).size, ...args });
|
|
40254
40252
|
}
|
|
@@ -40262,7 +40260,7 @@ async function storePeerInputFile(file, access) {
|
|
|
40262
40260
|
const id = randomUUID30();
|
|
40263
40261
|
mkdirSync33(PEER_FILES_DIR, { recursive: true });
|
|
40264
40262
|
const filename = file.name || "upload";
|
|
40265
|
-
const path =
|
|
40263
|
+
const path = join40(PEER_FILES_DIR, `${id}-${safeFilename(filename)}`);
|
|
40266
40264
|
const sizeBytes = await Bun.write(path, file);
|
|
40267
40265
|
return recordFile({
|
|
40268
40266
|
id,
|
|
@@ -40309,7 +40307,7 @@ function installPeerFileHooks() {
|
|
|
40309
40307
|
var PEER_FILES_DIR;
|
|
40310
40308
|
var init_peer_files = __esm(async () => {
|
|
40311
40309
|
await init_src();
|
|
40312
|
-
PEER_FILES_DIR =
|
|
40310
|
+
PEER_FILES_DIR = join40(DATA_DIR, "otium-peer-files");
|
|
40313
40311
|
db.exec(`
|
|
40314
40312
|
CREATE TABLE IF NOT EXISTS otium_peer_files (
|
|
40315
40313
|
id TEXT PRIMARY KEY,
|
|
@@ -41013,7 +41011,7 @@ function messageEnvelope(message) {
|
|
|
41013
41011
|
...message.kind ? { kind: message.kind } : {}
|
|
41014
41012
|
};
|
|
41015
41013
|
}
|
|
41016
|
-
async function publishTopic(
|
|
41014
|
+
async function publishTopic(join41, topicId, node) {
|
|
41017
41015
|
const topic = getTopic(topicId);
|
|
41018
41016
|
if (!topic || topic.kind !== "agent" || !topic.agent || !isTopicShared(topic) || !topic.visibility || topic.visibility === "hidden" || isMirrorTopic(topicId))
|
|
41019
41017
|
return;
|
|
@@ -41061,10 +41059,10 @@ async function publishTopic(join42, topicId, node) {
|
|
|
41061
41059
|
}
|
|
41062
41060
|
} catch (error2) {
|
|
41063
41061
|
logger.warn({ error: error2, topicId }, "otium: shared topic publish deferred");
|
|
41064
|
-
setTimeout(() => void reconcileTopic(
|
|
41062
|
+
setTimeout(() => void reconcileTopic(join41, topicId), RETRY_MS).unref?.();
|
|
41065
41063
|
}
|
|
41066
41064
|
}
|
|
41067
|
-
async function unpublishTopic(
|
|
41065
|
+
async function unpublishTopic(join41, topicId, node) {
|
|
41068
41066
|
const state2 = getSharedTopicState(topicId);
|
|
41069
41067
|
if (!state2)
|
|
41070
41068
|
return;
|
|
@@ -41080,26 +41078,26 @@ async function unpublishTopic(join42, topicId, node) {
|
|
|
41080
41078
|
deleteSharedTopicState(topicId);
|
|
41081
41079
|
} catch (error2) {
|
|
41082
41080
|
logger.warn({ error: error2, topicId }, "otium: shared topic unpublish deferred");
|
|
41083
|
-
setTimeout(() => void reconcileTopic(
|
|
41081
|
+
setTimeout(() => void reconcileTopic(join41, topicId), RETRY_MS).unref?.();
|
|
41084
41082
|
}
|
|
41085
41083
|
}
|
|
41086
|
-
async function reconcileTopic(
|
|
41084
|
+
async function reconcileTopic(join41, topicId, explicit = false) {
|
|
41087
41085
|
if (!otiumCentralConfig())
|
|
41088
41086
|
return;
|
|
41089
|
-
if (!explicit && isPeerDetached(
|
|
41087
|
+
if (!explicit && isPeerDetached(join41.cellId))
|
|
41090
41088
|
return;
|
|
41091
41089
|
const target = (await listPeerNodes()).find((node) => node.isPrimary) ?? null;
|
|
41092
41090
|
if (!target)
|
|
41093
41091
|
return;
|
|
41094
41092
|
const topic = getTopic(topicId);
|
|
41095
41093
|
if (topic?.kind === "agent" && topic.agent && isTopicShared(topic) && topic.visibility !== "hidden" && !isMirrorTopic(topicId))
|
|
41096
|
-
return publishTopic(
|
|
41097
|
-
return unpublishTopic(
|
|
41094
|
+
return publishTopic(join41, topicId, target);
|
|
41095
|
+
return unpublishTopic(join41, topicId, target);
|
|
41098
41096
|
}
|
|
41099
|
-
function disconnectSharedTopics(
|
|
41097
|
+
function disconnectSharedTopics(join41) {
|
|
41100
41098
|
const states = listSharedTopicStates();
|
|
41101
41099
|
const hubPromise = listPeerNodes({ fresh: true }).then((nodes) => nodes.find((node) => node.isPrimary) ?? null, () => null);
|
|
41102
|
-
const updated = downgradeSharedTopicsLocally(
|
|
41100
|
+
const updated = downgradeSharedTopicsLocally(join41.cellId);
|
|
41103
41101
|
for (const topicId of updated)
|
|
41104
41102
|
WsHub.get().broadcastTopicUpdated(topicId);
|
|
41105
41103
|
const deletions = states.map(async (state2) => {
|
|
@@ -41122,16 +41120,16 @@ function downgradeSharedTopicsForHub(hubNodeId) {
|
|
|
41122
41120
|
WsHub.get().broadcastTopicUpdated(topicId);
|
|
41123
41121
|
return updated.length;
|
|
41124
41122
|
}
|
|
41125
|
-
async function checkPeerAttachment(
|
|
41123
|
+
async function checkPeerAttachment(join41) {
|
|
41126
41124
|
const nodes = await listPeerNodes({ fresh: true });
|
|
41127
|
-
if (nodes.some((node) => node.cellId ===
|
|
41125
|
+
if (nodes.some((node) => node.cellId === join41.cellId))
|
|
41128
41126
|
return true;
|
|
41129
|
-
downgradeSharedTopicsForHub(
|
|
41127
|
+
downgradeSharedTopicsForHub(join41.cellId);
|
|
41130
41128
|
return false;
|
|
41131
41129
|
}
|
|
41132
|
-
function startSharedTopicSync(
|
|
41130
|
+
function startSharedTopicSync(join41) {
|
|
41133
41131
|
let stopped = false;
|
|
41134
|
-
let detached = isPeerDetached(
|
|
41132
|
+
let detached = isPeerDetached(join41.cellId);
|
|
41135
41133
|
const queue = new Set;
|
|
41136
41134
|
const schedule = (topicId, explicit = false) => {
|
|
41137
41135
|
if (stopped || queue.has(topicId))
|
|
@@ -41140,7 +41138,7 @@ function startSharedTopicSync(join42) {
|
|
|
41140
41138
|
queueMicrotask(async () => {
|
|
41141
41139
|
queue.delete(topicId);
|
|
41142
41140
|
try {
|
|
41143
|
-
await reconcileTopic(
|
|
41141
|
+
await reconcileTopic(join41, topicId, explicit);
|
|
41144
41142
|
} catch (error2) {
|
|
41145
41143
|
logger.warn({ error: error2, topicId }, "otium: shared topic reconciliation failed");
|
|
41146
41144
|
}
|
|
@@ -41154,7 +41152,7 @@ function startSharedTopicSync(join42) {
|
|
|
41154
41152
|
if (stopped || detached)
|
|
41155
41153
|
return;
|
|
41156
41154
|
try {
|
|
41157
|
-
if (!await checkPeerAttachment(
|
|
41155
|
+
if (!await checkPeerAttachment(join41))
|
|
41158
41156
|
detached = true;
|
|
41159
41157
|
} catch {}
|
|
41160
41158
|
}, 30000);
|
|
@@ -41166,7 +41164,7 @@ function startSharedTopicSync(join42) {
|
|
|
41166
41164
|
const message = event.payload;
|
|
41167
41165
|
if (!message.sourceNode) {
|
|
41168
41166
|
schedule(event.topicId);
|
|
41169
|
-
forwardSharedTopicMessage(
|
|
41167
|
+
forwardSharedTopicMessage(join41, message).catch((error2) => logger.warn({ error: error2, topicId: event.topicId }, "otium: shared message deferred"));
|
|
41170
41168
|
}
|
|
41171
41169
|
}
|
|
41172
41170
|
});
|
|
@@ -41928,7 +41926,7 @@ import {
|
|
|
41928
41926
|
unlinkSync as unlinkSync23,
|
|
41929
41927
|
writeFileSync as writeFileSync24
|
|
41930
41928
|
} from "fs";
|
|
41931
|
-
import { dirname as
|
|
41929
|
+
import { dirname as dirname21, resolve as resolve24 } from "path";
|
|
41932
41930
|
function parseEnrollmentInvite(code) {
|
|
41933
41931
|
let parsed;
|
|
41934
41932
|
try {
|
|
@@ -41978,8 +41976,8 @@ function loadOrCreatePending(invite, nodeName) {
|
|
|
41978
41976
|
publicKey: pair.publicKey.export({ format: "der", type: "spki" }).toString("base64url"),
|
|
41979
41977
|
...nodeName ? { nodeName } : {}
|
|
41980
41978
|
};
|
|
41981
|
-
mkdirSync34(
|
|
41982
|
-
const temporaryPath = resolve24(
|
|
41979
|
+
mkdirSync34(dirname21(path), { recursive: true });
|
|
41980
|
+
const temporaryPath = resolve24(dirname21(path), `.otium-enrollment-pending.json.${process.pid}.${randomUUID32()}.tmp`);
|
|
41983
41981
|
let fd;
|
|
41984
41982
|
try {
|
|
41985
41983
|
fd = openSync5(temporaryPath, "wx", 384);
|
|
@@ -41991,7 +41989,7 @@ function loadOrCreatePending(invite, nodeName) {
|
|
|
41991
41989
|
linkSync2(temporaryPath, path);
|
|
41992
41990
|
unlinkSync23(temporaryPath);
|
|
41993
41991
|
chmodSync7(path, 384);
|
|
41994
|
-
const directoryFd = openSync5(
|
|
41992
|
+
const directoryFd = openSync5(dirname21(path), "r");
|
|
41995
41993
|
try {
|
|
41996
41994
|
fsyncSync3(directoryFd);
|
|
41997
41995
|
} finally {
|
|
@@ -42013,7 +42011,7 @@ function loadOrCreatePending(invite, nodeName) {
|
|
|
42013
42011
|
}
|
|
42014
42012
|
function replacePendingEnrollment(pending2) {
|
|
42015
42013
|
const path = pendingEnrollmentPath();
|
|
42016
|
-
const directory =
|
|
42014
|
+
const directory = dirname21(path);
|
|
42017
42015
|
const temporaryPath = resolve24(directory, `.otium-enrollment-pending.json.${process.pid}.${randomUUID32()}.tmp`);
|
|
42018
42016
|
let fd;
|
|
42019
42017
|
try {
|
|
@@ -42038,13 +42036,13 @@ function replacePendingEnrollment(pending2) {
|
|
|
42038
42036
|
throw error2;
|
|
42039
42037
|
}
|
|
42040
42038
|
}
|
|
42041
|
-
function recordClaimedCredential(pending2,
|
|
42039
|
+
function recordClaimedCredential(pending2, join41) {
|
|
42042
42040
|
withJoinCredentialLock(() => {
|
|
42043
42041
|
const current3 = JSON.parse(readFileSync26(pendingEnrollmentPath(), "utf8"));
|
|
42044
42042
|
if (current3.central !== pending2.central || current3.token !== pending2.token || current3.idempotencyKey !== pending2.idempotencyKey || current3.publicKey !== pending2.publicKey) {
|
|
42045
42043
|
throw new Error("pending Otium enrollment changed while its claim was in flight");
|
|
42046
42044
|
}
|
|
42047
|
-
const claimed = { digest: joinCredentialDigest(
|
|
42045
|
+
const claimed = { digest: joinCredentialDigest(join41), cellId: join41.cellId };
|
|
42048
42046
|
if (current3.claimed && (current3.claimed.digest !== claimed.digest || current3.claimed.cellId !== claimed.cellId)) {
|
|
42049
42047
|
throw new Error("central returned different credentials for an idempotent enrollment claim");
|
|
42050
42048
|
}
|
|
@@ -42102,36 +42100,36 @@ async function claimEnrollment(invite, nodeName) {
|
|
|
42102
42100
|
const secret = openCredential(credential, pending2.privateKey);
|
|
42103
42101
|
if (!secret.startsWith("rcs_"))
|
|
42104
42102
|
throw new Error("central returned an invalid runtime credential");
|
|
42105
|
-
const
|
|
42103
|
+
const join41 = {
|
|
42106
42104
|
v: 2,
|
|
42107
42105
|
central: invite.central,
|
|
42108
42106
|
relay: String(response.relayUrl),
|
|
42109
42107
|
cellId: String(response.cell?.id),
|
|
42110
42108
|
secret
|
|
42111
42109
|
};
|
|
42112
|
-
if (!
|
|
42110
|
+
if (!join41.relay || !join41.cellId || join41.cellId === "undefined") {
|
|
42113
42111
|
throw new Error("central returned an incomplete enrollment response");
|
|
42114
42112
|
}
|
|
42115
|
-
assertSecureRelayUrl(
|
|
42116
|
-
recordClaimedCredential(pending2,
|
|
42117
|
-
return
|
|
42113
|
+
assertSecureRelayUrl(join41.relay);
|
|
42114
|
+
recordClaimedCredential(pending2, join41);
|
|
42115
|
+
return join41;
|
|
42118
42116
|
}
|
|
42119
|
-
function commitEnrollment(
|
|
42117
|
+
function commitEnrollment(join41, options = {}) {
|
|
42120
42118
|
return withJoinCredentialLock(() => {
|
|
42121
42119
|
const pendingPath = pendingEnrollmentPath();
|
|
42122
42120
|
const pending2 = existsSync35(pendingPath) ? JSON.parse(readFileSync26(pendingPath, "utf8")) : null;
|
|
42123
|
-
const digest = joinCredentialDigest(
|
|
42124
|
-
if (pending2 && (!pending2.claimed || pending2.claimed.digest !== digest || pending2.claimed.cellId !==
|
|
42121
|
+
const digest = joinCredentialDigest(join41);
|
|
42122
|
+
if (pending2 && (!pending2.claimed || pending2.claimed.digest !== digest || pending2.claimed.cellId !== join41.cellId)) {
|
|
42125
42123
|
throw new Error(`pending Otium enrollment at ${pendingPath} does not match these credentials`);
|
|
42126
42124
|
}
|
|
42127
|
-
const path = saveJoinWhileLocked(
|
|
42128
|
-
if (!isJoinPersisted(
|
|
42125
|
+
const path = saveJoinWhileLocked(join41, options);
|
|
42126
|
+
if (!isJoinPersisted(join41)) {
|
|
42129
42127
|
throw new Error("Otium join credentials were not durably persisted");
|
|
42130
42128
|
}
|
|
42131
42129
|
if (!pending2)
|
|
42132
42130
|
return path;
|
|
42133
42131
|
unlinkSync23(pendingPath);
|
|
42134
|
-
const directoryFd = openSync5(
|
|
42132
|
+
const directoryFd = openSync5(dirname21(pendingPath), "r");
|
|
42135
42133
|
try {
|
|
42136
42134
|
fsyncSync3(directoryFd);
|
|
42137
42135
|
} finally {
|
|
@@ -43016,14 +43014,14 @@ var init_peer_server = __esm(async () => {
|
|
|
43016
43014
|
|
|
43017
43015
|
// ../../adapters/otium/src/index.ts
|
|
43018
43016
|
function startOtiumNodeRuntime(options) {
|
|
43019
|
-
const { join:
|
|
43020
|
-
configureOtiumCentral(
|
|
43017
|
+
const { join: join41 } = options;
|
|
43018
|
+
configureOtiumCentral(join41);
|
|
43021
43019
|
const failed = failInterruptedPeerTurnRequestsOnStartup();
|
|
43022
43020
|
if (failed > 0) {
|
|
43023
43021
|
logger.warn({ failed }, "otium: failed interrupted peer turns from previous process");
|
|
43024
43022
|
}
|
|
43025
43023
|
const stopBackflow = startEventBackflow();
|
|
43026
|
-
const stopSharedTopicSync = startSharedTopicSync(
|
|
43024
|
+
const stopSharedTopicSync = startSharedTopicSync(join41);
|
|
43027
43025
|
const unregisterRuntimeBridge = registerPeerRuntimeBridge(otiumPeerRuntimeBridge);
|
|
43028
43026
|
const unregisterSessionBridge = registerPeerSessionBridge(otiumPeerSessionBridge);
|
|
43029
43027
|
const sessionBridgeIpc = startPeerSessionBridgeIpc(otiumPeerSessionBridge);
|
|
@@ -43044,7 +43042,7 @@ function startOtiumNodeRuntime(options) {
|
|
|
43044
43042
|
}
|
|
43045
43043
|
});
|
|
43046
43044
|
let stopped = false;
|
|
43047
|
-
logger.info({ central:
|
|
43045
|
+
logger.info({ central: join41.central, cellId: join41.cellId }, "otium: worker mode enabled");
|
|
43048
43046
|
selfPeerNode().then((self) => {
|
|
43049
43047
|
if (self) {
|
|
43050
43048
|
logger.info({ nodeName: self.nodeName, baseUrl: self.baseUrl }, "otium: attached to workspace");
|
|
@@ -43054,7 +43052,7 @@ function startOtiumNodeRuntime(options) {
|
|
|
43054
43052
|
});
|
|
43055
43053
|
return {
|
|
43056
43054
|
name: "otium",
|
|
43057
|
-
join:
|
|
43055
|
+
join: join41,
|
|
43058
43056
|
stop: () => {
|
|
43059
43057
|
if (stopped)
|
|
43060
43058
|
return;
|
|
@@ -43176,10 +43174,10 @@ async function handleOtiumAdapterControlRequest(req) {
|
|
|
43176
43174
|
return await handleOtiumPeerRequest(new Request(peerUrl.toString(), { method: req.method, headers, body, signal: req.signal })) ?? Response.json({ ok: false, error: "Otium route not found" }, { status: 404 });
|
|
43177
43175
|
}
|
|
43178
43176
|
function mountConfiguredOtiumNodeRuntime() {
|
|
43179
|
-
const
|
|
43180
|
-
if (!
|
|
43177
|
+
const join41 = loadJoin();
|
|
43178
|
+
if (!join41)
|
|
43181
43179
|
return null;
|
|
43182
|
-
const runtime2 = startOtiumNodeRuntime({ join:
|
|
43180
|
+
const runtime2 = startOtiumNodeRuntime({ join: join41 });
|
|
43183
43181
|
registerNodeRequestHandler("otium-adapter-control", handleOtiumAdapterControlRequest);
|
|
43184
43182
|
let stopped = false;
|
|
43185
43183
|
return {
|
|
@@ -43230,11 +43228,11 @@ async function joinCommand(args) {
|
|
|
43230
43228
|
process.exitCode = 1;
|
|
43231
43229
|
return;
|
|
43232
43230
|
}
|
|
43233
|
-
let
|
|
43231
|
+
let join41;
|
|
43234
43232
|
let productionEnrollment = false;
|
|
43235
43233
|
if (args.includes("--legacy")) {
|
|
43236
43234
|
try {
|
|
43237
|
-
|
|
43235
|
+
join41 = parseInviteCode(code);
|
|
43238
43236
|
} catch (err2) {
|
|
43239
43237
|
console.error(`invalid legacy invite code: ${err2 instanceof Error ? err2.message : err2}`);
|
|
43240
43238
|
process.exitCode = 1;
|
|
@@ -43261,7 +43259,7 @@ async function joinCommand(args) {
|
|
|
43261
43259
|
return;
|
|
43262
43260
|
}
|
|
43263
43261
|
}
|
|
43264
|
-
|
|
43262
|
+
join41 = await claimEnrollment(invite, nodeName);
|
|
43265
43263
|
productionEnrollment = true;
|
|
43266
43264
|
} catch (err2) {
|
|
43267
43265
|
console.error(`enrollment failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
@@ -43272,16 +43270,16 @@ async function joinCommand(args) {
|
|
|
43272
43270
|
let path;
|
|
43273
43271
|
try {
|
|
43274
43272
|
const saveOptions = { replaceExisting: args.includes("--replace") };
|
|
43275
|
-
path = productionEnrollment ? commitEnrollment(
|
|
43273
|
+
path = productionEnrollment ? commitEnrollment(join41, saveOptions) : saveJoin(join41, saveOptions);
|
|
43276
43274
|
} catch (err2) {
|
|
43277
43275
|
console.error(`could not save join credentials: ${err2 instanceof Error ? err2.message : err2}`);
|
|
43278
43276
|
process.exitCode = 1;
|
|
43279
43277
|
return;
|
|
43280
43278
|
}
|
|
43281
43279
|
console.log(`otium join credentials saved to ${path}`);
|
|
43282
|
-
console.log(` central: ${
|
|
43283
|
-
console.log(` cellId: ${
|
|
43284
|
-
configureOtiumCentral(
|
|
43280
|
+
console.log(` central: ${join41.central}`);
|
|
43281
|
+
console.log(` cellId: ${join41.cellId}`);
|
|
43282
|
+
configureOtiumCentral(join41);
|
|
43285
43283
|
try {
|
|
43286
43284
|
const self = await selfPeerNode();
|
|
43287
43285
|
if (self) {
|
|
@@ -43336,8 +43334,8 @@ async function proxyOtiumPeerRequest(req, dependencies = {}) {
|
|
|
43336
43334
|
}
|
|
43337
43335
|
}
|
|
43338
43336
|
async function runOtiumSidecar(options) {
|
|
43339
|
-
const
|
|
43340
|
-
if (!
|
|
43337
|
+
const join41 = loadJoin();
|
|
43338
|
+
if (!join41) {
|
|
43341
43339
|
throw new Error("not joined to an Otium workspace \u2014 run `negotium otium join <code>` first");
|
|
43342
43340
|
}
|
|
43343
43341
|
const initialNode = await inspectNodeDaemon();
|
|
@@ -43369,10 +43367,10 @@ async function runOtiumSidecar(options) {
|
|
|
43369
43367
|
lease.stop();
|
|
43370
43368
|
throw error2;
|
|
43371
43369
|
}
|
|
43372
|
-
const selectedRelay = options.relayUrl?.trim() ||
|
|
43370
|
+
const selectedRelay = options.relayUrl?.trim() || join41.relay || process.env.OTIUM_RELAY_URL?.trim();
|
|
43373
43371
|
const tunnel = selectedRelay ? new TunnelClient({
|
|
43374
43372
|
relayUrl: selectedRelay,
|
|
43375
|
-
token:
|
|
43373
|
+
token: join41.secret,
|
|
43376
43374
|
targetOrigin: `http://127.0.0.1:${server.port}`,
|
|
43377
43375
|
nodeVersion: `negotium@${NEGOTIUM_VERSION}`,
|
|
43378
43376
|
logger
|
|
@@ -43463,10 +43461,10 @@ async function resolveHostNodeId(explicit) {
|
|
|
43463
43461
|
init_central().then(() => exports_central),
|
|
43464
43462
|
init_join().then(() => exports_join)
|
|
43465
43463
|
]);
|
|
43466
|
-
const
|
|
43467
|
-
if (!
|
|
43464
|
+
const join41 = loadJoin2();
|
|
43465
|
+
if (!join41)
|
|
43468
43466
|
throw new Error("not joined to an Otium workspace; pass --host-node or join first");
|
|
43469
|
-
configureOtiumCentral2(
|
|
43467
|
+
configureOtiumCentral2(join41);
|
|
43470
43468
|
try {
|
|
43471
43469
|
const nodes = await listPeerNodes2({ fresh: true });
|
|
43472
43470
|
const primary = nodes.find((node) => node.isPrimary && !node.self) ?? nodes.find((node) => node.isPrimary);
|
|
@@ -43535,12 +43533,12 @@ async function runOtiumCli(args = process.argv.slice(2)) {
|
|
|
43535
43533
|
const { configureOtiumCentral: configureOtiumCentral2 } = await init_central().then(() => exports_central);
|
|
43536
43534
|
const { loadJoin: loadJoin2, removeJoin: removeJoin2 } = await init_join().then(() => exports_join);
|
|
43537
43535
|
const { disconnectSharedTopics: disconnectSharedTopics2 } = await init_shared_topic_sync().then(() => exports_shared_topic_sync);
|
|
43538
|
-
const
|
|
43539
|
-
if (!
|
|
43536
|
+
const join41 = loadJoin2();
|
|
43537
|
+
if (!join41)
|
|
43540
43538
|
throw new Error("not joined to an Otium workspace");
|
|
43541
|
-
configureOtiumCentral2(
|
|
43539
|
+
configureOtiumCentral2(join41);
|
|
43542
43540
|
try {
|
|
43543
|
-
await disconnectSharedTopics2(
|
|
43541
|
+
await disconnectSharedTopics2(join41);
|
|
43544
43542
|
removeJoin2();
|
|
43545
43543
|
} finally {
|
|
43546
43544
|
configureOtiumCentral2(null);
|
|
@@ -43650,620 +43648,6 @@ var init_init = __esm(async () => {
|
|
|
43650
43648
|
await init_src();
|
|
43651
43649
|
});
|
|
43652
43650
|
|
|
43653
|
-
// ../../packages/core/src/migration/single-user.ts
|
|
43654
|
-
import { createHash as createHash11, randomUUID as randomUUID34 } from "crypto";
|
|
43655
|
-
import {
|
|
43656
|
-
chmodSync as chmodSync8,
|
|
43657
|
-
copyFileSync as copyFileSync6,
|
|
43658
|
-
existsSync as existsSync36,
|
|
43659
|
-
mkdirSync as mkdirSync35,
|
|
43660
|
-
readdirSync as readdirSync14,
|
|
43661
|
-
readFileSync as readFileSync27,
|
|
43662
|
-
renameSync as renameSync16,
|
|
43663
|
-
rmSync as rmSync11,
|
|
43664
|
-
statSync as statSync19,
|
|
43665
|
-
writeFileSync as writeFileSync25
|
|
43666
|
-
} from "fs";
|
|
43667
|
-
import { homedir as homedir12 } from "os";
|
|
43668
|
-
import { basename as basename14, dirname as dirname23, join as join42, resolve as resolve25 } from "path";
|
|
43669
|
-
function entries(path) {
|
|
43670
|
-
return existsSync36(path) && statSync19(path).isDirectory() ? readdirSync14(path) : [];
|
|
43671
|
-
}
|
|
43672
|
-
function processIsAlive2(pid) {
|
|
43673
|
-
if (!Number.isInteger(pid) || pid <= 0)
|
|
43674
|
-
return false;
|
|
43675
|
-
try {
|
|
43676
|
-
process.kill(pid, 0);
|
|
43677
|
-
return true;
|
|
43678
|
-
} catch (error2) {
|
|
43679
|
-
return error2.code === "EPERM";
|
|
43680
|
-
}
|
|
43681
|
-
}
|
|
43682
|
-
function assertNoActiveNode(stateDir2) {
|
|
43683
|
-
for (const runtimeName of ["run", "runtime"]) {
|
|
43684
|
-
const infoPath = join42(stateDir2, runtimeName, "node-daemon.json");
|
|
43685
|
-
if (!existsSync36(infoPath))
|
|
43686
|
-
continue;
|
|
43687
|
-
try {
|
|
43688
|
-
const value = JSON.parse(readFileSync27(infoPath, "utf8"));
|
|
43689
|
-
if (typeof value.pid === "number" && processIsAlive2(value.pid)) {
|
|
43690
|
-
throw new Error(`Refusing migration while Negotium pid ${value.pid} is active.`);
|
|
43691
|
-
}
|
|
43692
|
-
} catch (error2) {
|
|
43693
|
-
if (error2 instanceof SyntaxError) {
|
|
43694
|
-
throw new Error(`Refusing migration: unreadable process metadata at ${infoPath}.`);
|
|
43695
|
-
}
|
|
43696
|
-
throw error2;
|
|
43697
|
-
}
|
|
43698
|
-
}
|
|
43699
|
-
const dbPath = join42(stateDir2, "data", "sessions.db");
|
|
43700
|
-
if (!existsSync36(dbPath))
|
|
43701
|
-
return;
|
|
43702
|
-
const database = new Database(dbPath, { readonly: true });
|
|
43703
|
-
try {
|
|
43704
|
-
const hasLeases = database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='runtime_process_leases'").get();
|
|
43705
|
-
if (!hasLeases)
|
|
43706
|
-
return;
|
|
43707
|
-
const leases = database.query("SELECT role, pid FROM runtime_process_leases").all();
|
|
43708
|
-
const active2 = leases.find((lease) => processIsAlive2(lease.pid));
|
|
43709
|
-
if (active2)
|
|
43710
|
-
throw new Error(`Refusing migration while ${active2.role} pid ${active2.pid} is active.`);
|
|
43711
|
-
} finally {
|
|
43712
|
-
database.close();
|
|
43713
|
-
}
|
|
43714
|
-
}
|
|
43715
|
-
function oldOwnerDirectory(ownerId) {
|
|
43716
|
-
const digest = createHash11("sha256").update(ownerId).digest("hex").slice(0, 16);
|
|
43717
|
-
return `${sanitizeTopicName(ownerId).slice(0, 24)}_${digest}`;
|
|
43718
|
-
}
|
|
43719
|
-
function addDirectoryContents(operations, sourceDir, destinationDir, stagingDir) {
|
|
43720
|
-
for (const name of entries(sourceDir)) {
|
|
43721
|
-
operations.push({
|
|
43722
|
-
source: join42(sourceDir, name),
|
|
43723
|
-
staged: join42(stagingDir, randomUUID34()),
|
|
43724
|
-
...destinationDir ? { destination: join42(destinationDir, name) } : {},
|
|
43725
|
-
state: "pending"
|
|
43726
|
-
});
|
|
43727
|
-
}
|
|
43728
|
-
}
|
|
43729
|
-
function pathWithin(path, root) {
|
|
43730
|
-
return path === root || path.startsWith(`${root}/`);
|
|
43731
|
-
}
|
|
43732
|
-
function collisionPolicy(operation, stateDir2) {
|
|
43733
|
-
const destination = operation.destination;
|
|
43734
|
-
if (!destination || !existsSync36(destination))
|
|
43735
|
-
return;
|
|
43736
|
-
if (pathWithin(destination, join42(stateDir2, "runtime")))
|
|
43737
|
-
return "keep-destination";
|
|
43738
|
-
if (pathWithin(destination, join42(stateDir2, "binaries")))
|
|
43739
|
-
return "keep-destination";
|
|
43740
|
-
if (pathWithin(destination, join42(stateDir2, "secrets")))
|
|
43741
|
-
return "replace-destination";
|
|
43742
|
-
if (destination === join42(stateDir2, "data", "vault", "vault.db")) {
|
|
43743
|
-
return "replace-destination";
|
|
43744
|
-
}
|
|
43745
|
-
if (pathWithin(destination, join42(stateDir2, "browser", "profiles"))) {
|
|
43746
|
-
return "replace-destination";
|
|
43747
|
-
}
|
|
43748
|
-
if (pathWithin(destination, join42(stateDir2, "data", "conversations")) && destination.endsWith(".jsonl")) {
|
|
43749
|
-
return "merge-jsonl";
|
|
43750
|
-
}
|
|
43751
|
-
if (pathWithin(destination, join42(stateDir2, "data", "tasks")) && destination.endsWith(".json")) {
|
|
43752
|
-
return "merge-tasks";
|
|
43753
|
-
}
|
|
43754
|
-
if (statSync19(operation.source).isFile() && statSync19(destination).isFile() && readFileSync27(operation.source).equals(readFileSync27(destination))) {
|
|
43755
|
-
return "keep-destination";
|
|
43756
|
-
}
|
|
43757
|
-
throw new Error(`Migration collision at ${destination}.`);
|
|
43758
|
-
}
|
|
43759
|
-
function configureCollisions(operations, stateDir2, stagingRoot) {
|
|
43760
|
-
const destinations = new Set;
|
|
43761
|
-
for (const operation of operations) {
|
|
43762
|
-
if (!operation.destination)
|
|
43763
|
-
continue;
|
|
43764
|
-
if (destinations.has(operation.destination)) {
|
|
43765
|
-
throw new Error(`Multiple legacy paths target ${operation.destination}.`);
|
|
43766
|
-
}
|
|
43767
|
-
destinations.add(operation.destination);
|
|
43768
|
-
operation.collision = collisionPolicy(operation, stateDir2);
|
|
43769
|
-
if (operation.collision && operation.collision !== "keep-destination") {
|
|
43770
|
-
operation.destinationStaged = join42(stagingRoot, randomUUID34());
|
|
43771
|
-
}
|
|
43772
|
-
}
|
|
43773
|
-
}
|
|
43774
|
-
function writeJournal(path, journal) {
|
|
43775
|
-
writeFileSync25(path, `${JSON.stringify(journal, null, 2)}
|
|
43776
|
-
`, { mode: 384 });
|
|
43777
|
-
}
|
|
43778
|
-
function rollbackFilesystem(journal, journalPath) {
|
|
43779
|
-
for (const operation of [...journal.operations].reverse()) {
|
|
43780
|
-
if (operation.state === "placed") {
|
|
43781
|
-
if (operation.collision === "keep-destination" || !operation.destination) {
|
|
43782
|
-
if (existsSync36(operation.staged) && !existsSync36(operation.source)) {
|
|
43783
|
-
mkdirSync35(dirname23(operation.source), { recursive: true });
|
|
43784
|
-
renameSync16(operation.staged, operation.source);
|
|
43785
|
-
}
|
|
43786
|
-
} else if (operation.destination && existsSync36(operation.destination)) {
|
|
43787
|
-
if (operation.collision === "merge-jsonl" || operation.collision === "merge-tasks") {
|
|
43788
|
-
rmSync11(operation.destination, { recursive: true, force: true });
|
|
43789
|
-
if (existsSync36(operation.staged) && !existsSync36(operation.source)) {
|
|
43790
|
-
mkdirSync35(dirname23(operation.source), { recursive: true });
|
|
43791
|
-
renameSync16(operation.staged, operation.source);
|
|
43792
|
-
}
|
|
43793
|
-
} else if (!existsSync36(operation.source)) {
|
|
43794
|
-
mkdirSync35(dirname23(operation.source), { recursive: true });
|
|
43795
|
-
renameSync16(operation.destination, operation.source);
|
|
43796
|
-
}
|
|
43797
|
-
}
|
|
43798
|
-
} else if (existsSync36(operation.staged) && !existsSync36(operation.source)) {
|
|
43799
|
-
mkdirSync35(dirname23(operation.source), { recursive: true });
|
|
43800
|
-
renameSync16(operation.staged, operation.source);
|
|
43801
|
-
}
|
|
43802
|
-
if (operation.destination && operation.destinationStaged && existsSync36(operation.destinationStaged) && !existsSync36(operation.destination)) {
|
|
43803
|
-
mkdirSync35(dirname23(operation.destination), { recursive: true });
|
|
43804
|
-
renameSync16(operation.destinationStaged, operation.destination);
|
|
43805
|
-
}
|
|
43806
|
-
operation.state = "pending";
|
|
43807
|
-
}
|
|
43808
|
-
journal.phase = "filesystem";
|
|
43809
|
-
writeJournal(journalPath, journal);
|
|
43810
|
-
}
|
|
43811
|
-
function mergedJsonl(source, destination) {
|
|
43812
|
-
const lines = new Set;
|
|
43813
|
-
for (const path of [source, destination]) {
|
|
43814
|
-
for (const line2 of readFileSync27(path, "utf8").split(/\r?\n/)) {
|
|
43815
|
-
if (line2)
|
|
43816
|
-
lines.add(line2);
|
|
43817
|
-
}
|
|
43818
|
-
}
|
|
43819
|
-
return lines.size > 0 ? `${[...lines].join(`
|
|
43820
|
-
`)}
|
|
43821
|
-
` : "";
|
|
43822
|
-
}
|
|
43823
|
-
function readTaskFile(path) {
|
|
43824
|
-
const parsed = JSON.parse(readFileSync27(path, "utf8"));
|
|
43825
|
-
if (parsed.version !== 1 || !Array.isArray(parsed.tasks)) {
|
|
43826
|
-
throw new Error(`Invalid task file during migration: ${path}`);
|
|
43827
|
-
}
|
|
43828
|
-
return parsed;
|
|
43829
|
-
}
|
|
43830
|
-
function mergedTasks(source, destination) {
|
|
43831
|
-
const legacy = readTaskFile(source).tasks;
|
|
43832
|
-
const current3 = readTaskFile(destination).tasks;
|
|
43833
|
-
const merged = legacy.map((task) => ({ ...task }));
|
|
43834
|
-
const usedIds = new Set(merged.map((task) => String(task.id)));
|
|
43835
|
-
let nextId = Math.max(0, ...[...usedIds].map(Number).filter(Number.isInteger)) + 1;
|
|
43836
|
-
const remapped = new Map;
|
|
43837
|
-
for (const task of current3) {
|
|
43838
|
-
const originalId = String(task.id);
|
|
43839
|
-
const exact = merged.find((candidate) => candidate.id === originalId && JSON.stringify(candidate) === JSON.stringify(task));
|
|
43840
|
-
if (exact) {
|
|
43841
|
-
remapped.set(originalId, originalId);
|
|
43842
|
-
continue;
|
|
43843
|
-
}
|
|
43844
|
-
const id = usedIds.has(originalId) ? String(nextId++) : originalId;
|
|
43845
|
-
usedIds.add(id);
|
|
43846
|
-
remapped.set(originalId, id);
|
|
43847
|
-
merged.push({ ...task, id });
|
|
43848
|
-
}
|
|
43849
|
-
for (const task of merged.slice(legacy.length)) {
|
|
43850
|
-
if (task.blockedBy)
|
|
43851
|
-
task.blockedBy = task.blockedBy.map((id) => remapped.get(id) ?? id);
|
|
43852
|
-
}
|
|
43853
|
-
return `${JSON.stringify({ version: 1, tasks: merged }, null, 2)}
|
|
43854
|
-
`;
|
|
43855
|
-
}
|
|
43856
|
-
function placeOperation(operation) {
|
|
43857
|
-
if (!operation.destination || operation.collision === "keep-destination")
|
|
43858
|
-
return;
|
|
43859
|
-
mkdirSync35(dirname23(operation.destination), { recursive: true });
|
|
43860
|
-
if (operation.collision === "merge-jsonl") {
|
|
43861
|
-
writeFileSync25(operation.destination, mergedJsonl(operation.staged, operation.destinationStaged));
|
|
43862
|
-
return;
|
|
43863
|
-
}
|
|
43864
|
-
if (operation.collision === "merge-tasks") {
|
|
43865
|
-
writeFileSync25(operation.destination, mergedTasks(operation.staged, operation.destinationStaged));
|
|
43866
|
-
return;
|
|
43867
|
-
}
|
|
43868
|
-
renameSync16(operation.staged, operation.destination);
|
|
43869
|
-
}
|
|
43870
|
-
function tablesWithColumn(database, columnName) {
|
|
43871
|
-
const tables = database.query("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'").all();
|
|
43872
|
-
return tables.map((row) => row.name).filter((table) => database.query(`PRAGMA table_info("${table.replaceAll('"', '""')}")`).all().some((column) => column.name === columnName));
|
|
43873
|
-
}
|
|
43874
|
-
function selectedTopicIds(dbPath, source) {
|
|
43875
|
-
if (!existsSync36(dbPath))
|
|
43876
|
-
return null;
|
|
43877
|
-
const database = new Database(dbPath, { readonly: true });
|
|
43878
|
-
try {
|
|
43879
|
-
const hasMemberships = database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='topic_members'").get();
|
|
43880
|
-
if (!hasMemberships)
|
|
43881
|
-
return null;
|
|
43882
|
-
return new Set(database.query("SELECT topic_id FROM topic_members WHERE user_id = ?").all(source).map((row) => row.topic_id));
|
|
43883
|
-
} finally {
|
|
43884
|
-
database.close();
|
|
43885
|
-
}
|
|
43886
|
-
}
|
|
43887
|
-
function migrateDatabase(dbPath, source, masterKey, legacyTopicProfiles = []) {
|
|
43888
|
-
if (!existsSync36(dbPath))
|
|
43889
|
-
return [];
|
|
43890
|
-
const database = new Database(dbPath);
|
|
43891
|
-
const userTables = tablesWithColumn(database, "user_id");
|
|
43892
|
-
const ownerUserTables = tablesWithColumn(database, "owner_user_id");
|
|
43893
|
-
const migratedTables = [...new Set([...userTables, ...ownerUserTables])];
|
|
43894
|
-
const retainedTopicIds = selectedTopicIds(dbPath, source);
|
|
43895
|
-
const quote = (name) => `"${name.replaceAll('"', '""')}"`;
|
|
43896
|
-
try {
|
|
43897
|
-
if (source !== CANONICAL_LOCAL_USER_ID) {
|
|
43898
|
-
for (const [column, tables] of [
|
|
43899
|
-
["user_id", userTables],
|
|
43900
|
-
["owner_user_id", ownerUserTables]
|
|
43901
|
-
]) {
|
|
43902
|
-
for (const table of tables) {
|
|
43903
|
-
const collision = database.query(`SELECT COUNT(*) AS count FROM ${quote(table)} WHERE ${column} = ?`).get(CANONICAL_LOCAL_USER_ID)?.count;
|
|
43904
|
-
if (collision)
|
|
43905
|
-
throw new Error(`Database collision: ${table}.${column} already contains local rows.`);
|
|
43906
|
-
}
|
|
43907
|
-
}
|
|
43908
|
-
const hasUsers = database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='users'").get();
|
|
43909
|
-
if (hasUsers) {
|
|
43910
|
-
const localUser = database.query("SELECT 1 FROM users WHERE id = ?").get(CANONICAL_LOCAL_USER_ID);
|
|
43911
|
-
if (localUser)
|
|
43912
|
-
throw new Error("Database collision: users already contains canonical local.");
|
|
43913
|
-
}
|
|
43914
|
-
}
|
|
43915
|
-
database.exec("PRAGMA foreign_keys = OFF");
|
|
43916
|
-
database.exec("BEGIN IMMEDIATE");
|
|
43917
|
-
for (const table of userTables) {
|
|
43918
|
-
database.query(`DELETE FROM ${quote(table)} WHERE user_id <> ?`).run(source);
|
|
43919
|
-
if (table === "vault" && source !== CANONICAL_LOCAL_USER_ID) {
|
|
43920
|
-
if (!masterKey)
|
|
43921
|
-
throw new Error("Cannot migrate encrypted vault rows without vault-master-key.");
|
|
43922
|
-
const rows = database.query("SELECT key, value FROM vault WHERE user_id = ?").all(source);
|
|
43923
|
-
for (const row of rows) {
|
|
43924
|
-
const plaintext = decryptVaultValueWithKey(source, row.key, row.value, masterKey).value;
|
|
43925
|
-
database.query("UPDATE vault SET value = ? WHERE user_id = ? AND key = ?").run(encryptVaultValueWithKey(CANONICAL_LOCAL_USER_ID, row.key, plaintext, masterKey), source, row.key);
|
|
43926
|
-
}
|
|
43927
|
-
}
|
|
43928
|
-
database.query(`UPDATE ${quote(table)} SET user_id = ? WHERE user_id = ?`).run(CANONICAL_LOCAL_USER_ID, source);
|
|
43929
|
-
}
|
|
43930
|
-
for (const table of ownerUserTables) {
|
|
43931
|
-
database.query(`DELETE FROM ${quote(table)} WHERE owner_user_id <> ?`).run(source);
|
|
43932
|
-
database.query(`UPDATE ${quote(table)} SET owner_user_id = ? WHERE owner_user_id = ?`).run(CANONICAL_LOCAL_USER_ID, source);
|
|
43933
|
-
}
|
|
43934
|
-
if (retainedTopicIds) {
|
|
43935
|
-
database.exec("CREATE TEMP TABLE migration_selected_topics (id TEXT PRIMARY KEY)");
|
|
43936
|
-
for (const topicId of retainedTopicIds) {
|
|
43937
|
-
database.query("INSERT INTO migration_selected_topics (id) VALUES (?)").run(topicId);
|
|
43938
|
-
}
|
|
43939
|
-
const topicTables = database.query("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'").all().map((row) => row.name).filter((table) => database.query(`PRAGMA table_info(${quote(table)})`).all().some((column) => column.name === "topic_id"));
|
|
43940
|
-
for (const table of topicTables) {
|
|
43941
|
-
database.query(`DELETE FROM ${quote(table)} WHERE topic_id NOT IN (SELECT id FROM migration_selected_topics)`).run();
|
|
43942
|
-
}
|
|
43943
|
-
if (database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='api_topics'").get()) {
|
|
43944
|
-
database.query("DELETE FROM api_topics WHERE id NOT IN (SELECT id FROM migration_selected_topics)").run();
|
|
43945
|
-
}
|
|
43946
|
-
}
|
|
43947
|
-
if (database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='browser_profiles'").get()) {
|
|
43948
|
-
database.query("DELETE FROM browser_profiles WHERE owner_id <> ?").run(source);
|
|
43949
|
-
database.query("UPDATE browser_profiles SET owner_id = ? WHERE owner_id = ?").run(CANONICAL_LOCAL_USER_ID, source);
|
|
43950
|
-
}
|
|
43951
|
-
if (database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='api_topics'").get() && database.query("PRAGMA table_info(api_topics)").all().some((column) => column.name === "browser_profile_owner")) {
|
|
43952
|
-
database.query("UPDATE api_topics SET browser_profile_owner = ? WHERE browser_profile_owner = ?").run(CANONICAL_LOCAL_USER_ID, source);
|
|
43953
|
-
if (retainedTopicIds) {
|
|
43954
|
-
database.query("UPDATE api_topics SET browser_profile_owner = ? WHERE browser_profile_owner IS NOT NULL").run(CANONICAL_LOCAL_USER_ID);
|
|
43955
|
-
} else {
|
|
43956
|
-
database.query("DELETE FROM api_topics WHERE browser_profile_owner IS NOT NULL AND browser_profile_owner <> ?").run(CANONICAL_LOCAL_USER_ID);
|
|
43957
|
-
}
|
|
43958
|
-
for (const binding of legacyTopicProfiles) {
|
|
43959
|
-
database.query("UPDATE api_topics SET browser_profile = ?, browser_profile_owner = ? WHERE id = ?").run(binding.profile, CANONICAL_LOCAL_USER_ID, binding.topicId);
|
|
43960
|
-
}
|
|
43961
|
-
}
|
|
43962
|
-
if (database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='users'").get()) {
|
|
43963
|
-
database.query("DELETE FROM users WHERE id <> ?").run(source);
|
|
43964
|
-
database.query("UPDATE users SET id = ? WHERE id = ?").run(CANONICAL_LOCAL_USER_ID, source);
|
|
43965
|
-
}
|
|
43966
|
-
database.exec("COMMIT");
|
|
43967
|
-
database.exec("PRAGMA foreign_keys = ON");
|
|
43968
|
-
const fkErrors = database.query("PRAGMA foreign_key_check").all();
|
|
43969
|
-
if (fkErrors.length > 0)
|
|
43970
|
-
throw new Error("Database migration left foreign-key violations.");
|
|
43971
|
-
return migratedTables;
|
|
43972
|
-
} catch (error2) {
|
|
43973
|
-
try {
|
|
43974
|
-
database.exec("ROLLBACK");
|
|
43975
|
-
} catch {}
|
|
43976
|
-
throw error2;
|
|
43977
|
-
} finally {
|
|
43978
|
-
database.close();
|
|
43979
|
-
}
|
|
43980
|
-
}
|
|
43981
|
-
function migrateSingleUserState(options) {
|
|
43982
|
-
const stateDir2 = resolve25(options.stateDir ?? process.env.NEGOTIUM_STATE_DIR ?? join42(homedir12(), ".negotium"));
|
|
43983
|
-
const source = options.sourcePrincipal?.trim() || CANONICAL_LOCAL_USER_ID;
|
|
43984
|
-
if (!source || /[/\\]|\.\./.test(source))
|
|
43985
|
-
throw new Error("Invalid source principal.");
|
|
43986
|
-
if (!options.deleteOtherUsers || !options.confirmed) {
|
|
43987
|
-
throw new Error("Migration requires --delete-other-users and --yes; other principals are permanently deleted.");
|
|
43988
|
-
}
|
|
43989
|
-
const markerPath = join42(stateDir2, ".migration-0.2.0-single-user.json");
|
|
43990
|
-
if (existsSync36(markerPath)) {
|
|
43991
|
-
const marker = JSON.parse(readFileSync27(markerPath, "utf8"));
|
|
43992
|
-
if (marker.id !== SINGLE_USER_MIGRATION_ID)
|
|
43993
|
-
throw new Error(`Unexpected migration marker at ${markerPath}.`);
|
|
43994
|
-
return {
|
|
43995
|
-
status: "already-completed",
|
|
43996
|
-
markerPath,
|
|
43997
|
-
sourcePrincipal: marker.sourcePrincipal ?? source,
|
|
43998
|
-
movedPaths: marker.movedPaths ?? 0,
|
|
43999
|
-
deletedPaths: marker.deletedPaths ?? 0,
|
|
44000
|
-
migratedTables: marker.migratedTables ?? []
|
|
44001
|
-
};
|
|
44002
|
-
}
|
|
44003
|
-
assertNoActiveNode(stateDir2);
|
|
44004
|
-
mkdirSync35(stateDir2, { recursive: true });
|
|
44005
|
-
const stagingRoot = join42(stateDir2, ".migration-0.2.0-staging");
|
|
44006
|
-
const journalPath = join42(stagingRoot, "journal.json");
|
|
44007
|
-
mkdirSync35(stagingRoot, { recursive: true, mode: 448 });
|
|
44008
|
-
let journal;
|
|
44009
|
-
if (existsSync36(journalPath)) {
|
|
44010
|
-
journal = JSON.parse(readFileSync27(journalPath, "utf8"));
|
|
44011
|
-
if (journal.sourcePrincipal !== source)
|
|
44012
|
-
throw new Error("Interrupted migration used a different source principal.");
|
|
44013
|
-
} else {
|
|
44014
|
-
const operations = [];
|
|
44015
|
-
const retainedTopicIds = selectedTopicIds(join42(stateDir2, "data", "sessions.db"), source);
|
|
44016
|
-
addDirectoryContents(operations, join42(stateDir2, "run"), join42(stateDir2, "runtime"), stagingRoot);
|
|
44017
|
-
addDirectoryContents(operations, join42(stateDir2, "bin"), join42(stateDir2, "binaries"), stagingRoot);
|
|
44018
|
-
for (const secret of ["node-control-token", "runtime-mcp-secret", "vault-master-key"]) {
|
|
44019
|
-
const sourcePath = join42(stateDir2, secret);
|
|
44020
|
-
if (existsSync36(sourcePath))
|
|
44021
|
-
operations.push({
|
|
44022
|
-
source: sourcePath,
|
|
44023
|
-
staged: join42(stagingRoot, randomUUID34()),
|
|
44024
|
-
destination: join42(stateDir2, "secrets", secret),
|
|
44025
|
-
state: "pending"
|
|
44026
|
-
});
|
|
44027
|
-
}
|
|
44028
|
-
const legacyVaultDb = join42(stateDir2, "data", "vault.db");
|
|
44029
|
-
if (existsSync36(legacyVaultDb)) {
|
|
44030
|
-
operations.push({
|
|
44031
|
-
source: legacyVaultDb,
|
|
44032
|
-
staged: join42(stagingRoot, randomUUID34()),
|
|
44033
|
-
destination: join42(stateDir2, "data", "vault", "vault.db"),
|
|
44034
|
-
state: "pending"
|
|
44035
|
-
});
|
|
44036
|
-
}
|
|
44037
|
-
for (const store of ["conversations", "tasks", "users"]) {
|
|
44038
|
-
const root = join42(stateDir2, "data", store);
|
|
44039
|
-
addDirectoryContents(operations, join42(root, source), root, stagingRoot);
|
|
44040
|
-
for (const owner of entries(root)) {
|
|
44041
|
-
const ownerPath = join42(root, owner);
|
|
44042
|
-
if (owner !== source && statSync19(ownerPath).isDirectory()) {
|
|
44043
|
-
operations.push({
|
|
44044
|
-
source: ownerPath,
|
|
44045
|
-
staged: join42(stagingRoot, randomUUID34()),
|
|
44046
|
-
state: "pending"
|
|
44047
|
-
});
|
|
44048
|
-
}
|
|
44049
|
-
}
|
|
44050
|
-
}
|
|
44051
|
-
for (const legacyWorkspaceDir of ["contexts", "dm", "sessions"]) {
|
|
44052
|
-
addDirectoryContents(operations, join42(stateDir2, "workspace", legacyWorkspaceDir), join42(stateDir2, "data", legacyWorkspaceDir), stagingRoot);
|
|
44053
|
-
}
|
|
44054
|
-
for (const topicId of entries(join42(stateDir2, "workspace", "topics"))) {
|
|
44055
|
-
const topicPath = join42(stateDir2, "workspace", "topics", topicId);
|
|
44056
|
-
if (retainedTopicIds && !retainedTopicIds.has(topicId)) {
|
|
44057
|
-
operations.push({
|
|
44058
|
-
source: topicPath,
|
|
44059
|
-
staged: join42(stagingRoot, randomUUID34()),
|
|
44060
|
-
state: "pending"
|
|
44061
|
-
});
|
|
44062
|
-
} else {
|
|
44063
|
-
addDirectoryContents(operations, join42(topicPath, "uploads"), join42(stateDir2, "data", "uploads", topicId), stagingRoot);
|
|
44064
|
-
}
|
|
44065
|
-
}
|
|
44066
|
-
if (retainedTopicIds) {
|
|
44067
|
-
for (const topicId of entries(join42(stateDir2, "workspace", "wiki"))) {
|
|
44068
|
-
if (retainedTopicIds.has(topicId))
|
|
44069
|
-
continue;
|
|
44070
|
-
operations.push({
|
|
44071
|
-
source: join42(stateDir2, "workspace", "wiki", topicId),
|
|
44072
|
-
staged: join42(stagingRoot, randomUUID34()),
|
|
44073
|
-
state: "pending"
|
|
44074
|
-
});
|
|
44075
|
-
}
|
|
44076
|
-
}
|
|
44077
|
-
const legacyBrowserRoot = join42(stateDir2, "workspace", "browser-profiles");
|
|
44078
|
-
const selectedProfiles = join42(legacyBrowserRoot, "profiles", oldOwnerDirectory(source));
|
|
44079
|
-
addDirectoryContents(operations, selectedProfiles, join42(stateDir2, "browser", "profiles"), stagingRoot);
|
|
44080
|
-
for (const owner of entries(join42(legacyBrowserRoot, "profiles"))) {
|
|
44081
|
-
const ownerPath = join42(legacyBrowserRoot, "profiles", owner);
|
|
44082
|
-
if (ownerPath !== selectedProfiles) {
|
|
44083
|
-
operations.push({
|
|
44084
|
-
source: ownerPath,
|
|
44085
|
-
staged: join42(stagingRoot, randomUUID34()),
|
|
44086
|
-
state: "pending"
|
|
44087
|
-
});
|
|
44088
|
-
}
|
|
44089
|
-
}
|
|
44090
|
-
for (const topicId of entries(legacyBrowserRoot).filter((name) => name !== "profiles")) {
|
|
44091
|
-
if (retainedTopicIds && !retainedTopicIds.has(topicId)) {
|
|
44092
|
-
operations.push({
|
|
44093
|
-
source: join42(legacyBrowserRoot, topicId),
|
|
44094
|
-
staged: join42(stagingRoot, randomUUID34()),
|
|
44095
|
-
state: "pending"
|
|
44096
|
-
});
|
|
44097
|
-
continue;
|
|
44098
|
-
}
|
|
44099
|
-
const profile = `legacy_${createHash11("sha256").update(topicId).digest("hex").slice(0, 12)}`;
|
|
44100
|
-
operations.push({
|
|
44101
|
-
source: join42(legacyBrowserRoot, topicId),
|
|
44102
|
-
staged: join42(stagingRoot, randomUUID34()),
|
|
44103
|
-
destination: join42(stateDir2, "browser", "profiles", profile),
|
|
44104
|
-
state: "pending"
|
|
44105
|
-
});
|
|
44106
|
-
}
|
|
44107
|
-
configureCollisions(operations, stateDir2, stagingRoot);
|
|
44108
|
-
journal = {
|
|
44109
|
-
id: SINGLE_USER_MIGRATION_ID,
|
|
44110
|
-
sourcePrincipal: source,
|
|
44111
|
-
createdAt: new Date().toISOString(),
|
|
44112
|
-
phase: "filesystem",
|
|
44113
|
-
operations
|
|
44114
|
-
};
|
|
44115
|
-
writeJournal(journalPath, journal);
|
|
44116
|
-
}
|
|
44117
|
-
const dbPath = join42(stateDir2, "data", "sessions.db");
|
|
44118
|
-
const dbBackup = join42(stagingRoot, "sessions.db.rollback");
|
|
44119
|
-
const vaultDbPath = join42(stateDir2, "data", "vault", "vault.db");
|
|
44120
|
-
const vaultDbBackup = join42(stagingRoot, "vault.db.rollback");
|
|
44121
|
-
try {
|
|
44122
|
-
for (const operation of journal.operations) {
|
|
44123
|
-
if (operation.state === "staged")
|
|
44124
|
-
operation.state = "source-staged";
|
|
44125
|
-
if (operation.state === "pending" && !existsSync36(operation.source)) {
|
|
44126
|
-
if (existsSync36(operation.staged))
|
|
44127
|
-
operation.state = "source-staged";
|
|
44128
|
-
else if (operation.destination && existsSync36(operation.destination)) {
|
|
44129
|
-
operation.state = "placed";
|
|
44130
|
-
}
|
|
44131
|
-
}
|
|
44132
|
-
if (operation.state === "pending") {
|
|
44133
|
-
mkdirSync35(dirname23(operation.staged), { recursive: true });
|
|
44134
|
-
renameSync16(operation.source, operation.staged);
|
|
44135
|
-
operation.state = "source-staged";
|
|
44136
|
-
writeJournal(journalPath, journal);
|
|
44137
|
-
}
|
|
44138
|
-
if (operation.state === "source-staged" && operation.collision === "replace-destination" && operation.destination && operation.destinationStaged && !existsSync36(operation.staged) && existsSync36(operation.destination) && existsSync36(operation.destinationStaged)) {
|
|
44139
|
-
operation.state = "placed";
|
|
44140
|
-
writeJournal(journalPath, journal);
|
|
44141
|
-
}
|
|
44142
|
-
if (operation.state === "destination-staged" && operation.collision !== "merge-jsonl" && operation.collision !== "merge-tasks" && operation.collision !== "keep-destination" && operation.destination && !existsSync36(operation.staged) && existsSync36(operation.destination)) {
|
|
44143
|
-
operation.state = "placed";
|
|
44144
|
-
writeJournal(journalPath, journal);
|
|
44145
|
-
}
|
|
44146
|
-
if (operation.state === "source-staged") {
|
|
44147
|
-
if (operation.destination && operation.destinationStaged) {
|
|
44148
|
-
if (existsSync36(operation.destination) && !existsSync36(operation.destinationStaged)) {
|
|
44149
|
-
renameSync16(operation.destination, operation.destinationStaged);
|
|
44150
|
-
}
|
|
44151
|
-
if (!existsSync36(operation.destinationStaged)) {
|
|
44152
|
-
throw new Error(`Missing collision backup for ${operation.destination}.`);
|
|
44153
|
-
}
|
|
44154
|
-
}
|
|
44155
|
-
operation.state = "destination-staged";
|
|
44156
|
-
writeJournal(journalPath, journal);
|
|
44157
|
-
}
|
|
44158
|
-
if (operation.state === "destination-staged") {
|
|
44159
|
-
placeOperation(operation);
|
|
44160
|
-
operation.state = "placed";
|
|
44161
|
-
writeJournal(journalPath, journal);
|
|
44162
|
-
}
|
|
44163
|
-
}
|
|
44164
|
-
journal.phase = "database";
|
|
44165
|
-
writeJournal(journalPath, journal);
|
|
44166
|
-
if (existsSync36(dbPath) && !existsSync36(dbBackup))
|
|
44167
|
-
copyFileSync6(dbPath, dbBackup);
|
|
44168
|
-
if (existsSync36(vaultDbPath) && !existsSync36(vaultDbBackup))
|
|
44169
|
-
copyFileSync6(vaultDbPath, vaultDbBackup);
|
|
44170
|
-
const masterKeyPath = join42(stateDir2, "secrets", "vault-master-key");
|
|
44171
|
-
const masterKey = existsSync36(masterKeyPath) ? readFileSync27(masterKeyPath, "utf8").trim() : undefined;
|
|
44172
|
-
const legacyBrowserRoot = join42(stateDir2, "workspace", "browser-profiles");
|
|
44173
|
-
const legacyTopicProfiles = journal.operations.filter((operation) => dirname23(operation.source) === legacyBrowserRoot && operation.destination).map((operation) => ({
|
|
44174
|
-
topicId: basename14(operation.source),
|
|
44175
|
-
profile: basename14(operation.destination)
|
|
44176
|
-
}));
|
|
44177
|
-
const migratedTables = migrateDatabase(dbPath, source, masterKey, legacyTopicProfiles);
|
|
44178
|
-
const migratedVaultTables = migrateDatabase(vaultDbPath, source, masterKey);
|
|
44179
|
-
for (const table of migratedVaultTables)
|
|
44180
|
-
if (!migratedTables.includes(table))
|
|
44181
|
-
migratedTables.push(table);
|
|
44182
|
-
mkdirSync35(join42(stateDir2, "secrets"), { recursive: true, mode: 448 });
|
|
44183
|
-
chmodSync8(join42(stateDir2, "secrets"), 448);
|
|
44184
|
-
for (const secret of ["node-control-token", "runtime-mcp-secret", "vault-master-key"]) {
|
|
44185
|
-
const path = join42(stateDir2, "secrets", secret);
|
|
44186
|
-
if (existsSync36(path))
|
|
44187
|
-
chmodSync8(path, 384);
|
|
44188
|
-
}
|
|
44189
|
-
const deletedPaths = journal.operations.filter((operation) => !operation.destination).length;
|
|
44190
|
-
const movedPaths = journal.operations.length - deletedPaths;
|
|
44191
|
-
const marker = {
|
|
44192
|
-
id: SINGLE_USER_MIGRATION_ID,
|
|
44193
|
-
version: "0.2.0",
|
|
44194
|
-
completedAt: new Date().toISOString(),
|
|
44195
|
-
sourcePrincipal: source,
|
|
44196
|
-
canonicalPrincipal: CANONICAL_LOCAL_USER_ID,
|
|
44197
|
-
movedPaths,
|
|
44198
|
-
deletedPaths,
|
|
44199
|
-
migratedTables
|
|
44200
|
-
};
|
|
44201
|
-
for (const store of ["conversations", "tasks", "users"]) {
|
|
44202
|
-
rmSync11(join42(stateDir2, "data", store, source), {
|
|
44203
|
-
recursive: true,
|
|
44204
|
-
force: true
|
|
44205
|
-
});
|
|
44206
|
-
}
|
|
44207
|
-
rmSync11(join42(stateDir2, "run"), { recursive: true, force: true });
|
|
44208
|
-
rmSync11(join42(stateDir2, "bin"), { recursive: true, force: true });
|
|
44209
|
-
rmSync11(join42(stateDir2, "workspace", "browser-profiles"), {
|
|
44210
|
-
recursive: true,
|
|
44211
|
-
force: true
|
|
44212
|
-
});
|
|
44213
|
-
writeFileSync25(markerPath, `${JSON.stringify(marker, null, 2)}
|
|
44214
|
-
`, {
|
|
44215
|
-
mode: 384,
|
|
44216
|
-
flag: "wx"
|
|
44217
|
-
});
|
|
44218
|
-
journal.phase = "complete";
|
|
44219
|
-
rmSync11(stagingRoot, { recursive: true, force: true });
|
|
44220
|
-
return {
|
|
44221
|
-
status: "completed",
|
|
44222
|
-
markerPath,
|
|
44223
|
-
sourcePrincipal: source,
|
|
44224
|
-
movedPaths,
|
|
44225
|
-
deletedPaths,
|
|
44226
|
-
migratedTables
|
|
44227
|
-
};
|
|
44228
|
-
} catch (error2) {
|
|
44229
|
-
if (existsSync36(dbBackup))
|
|
44230
|
-
copyFileSync6(dbBackup, dbPath);
|
|
44231
|
-
if (existsSync36(vaultDbBackup))
|
|
44232
|
-
copyFileSync6(vaultDbBackup, vaultDbPath);
|
|
44233
|
-
rollbackFilesystem(journal, journalPath);
|
|
44234
|
-
throw error2;
|
|
44235
|
-
}
|
|
44236
|
-
}
|
|
44237
|
-
var CANONICAL_LOCAL_USER_ID = "local", SINGLE_USER_MIGRATION_ID = "negotium-0.2.0-single-user";
|
|
44238
|
-
var init_single_user = __esm(async () => {
|
|
44239
|
-
init_vault_crypto_core();
|
|
44240
|
-
await init_sqlite();
|
|
44241
|
-
});
|
|
44242
|
-
|
|
44243
|
-
// ../cli/src/commands/migrate.ts
|
|
44244
|
-
var exports_migrate = {};
|
|
44245
|
-
__export(exports_migrate, {
|
|
44246
|
-
migrateCommand: () => migrateCommand
|
|
44247
|
-
});
|
|
44248
|
-
function option3(args, name) {
|
|
44249
|
-
const prefix = `--${name}=`;
|
|
44250
|
-
return args.find((arg) => arg.startsWith(prefix))?.slice(prefix.length);
|
|
44251
|
-
}
|
|
44252
|
-
function migrateCommand(args) {
|
|
44253
|
-
if (args[0] !== "single-user") {
|
|
44254
|
-
throw new Error("usage: negotium migrate single-user [--source=local] --delete-other-users --yes");
|
|
44255
|
-
}
|
|
44256
|
-
const result = migrateSingleUserState({
|
|
44257
|
-
sourcePrincipal: option3(args, "source"),
|
|
44258
|
-
deleteOtherUsers: args.includes("--delete-other-users"),
|
|
44259
|
-
confirmed: args.includes("--yes")
|
|
44260
|
-
});
|
|
44261
|
-
console.log(`${result.status}: ${result.markerPath}`);
|
|
44262
|
-
}
|
|
44263
|
-
var init_migrate = __esm(async () => {
|
|
44264
|
-
await init_single_user();
|
|
44265
|
-
});
|
|
44266
|
-
|
|
44267
43651
|
// ../cli/src/commands/topics.ts
|
|
44268
43652
|
var exports_topics = {};
|
|
44269
43653
|
__export(exports_topics, {
|
|
@@ -44365,12 +43749,12 @@ function vaultCommand(args) {
|
|
|
44365
43749
|
switch (sub) {
|
|
44366
43750
|
case undefined:
|
|
44367
43751
|
case "list": {
|
|
44368
|
-
const
|
|
44369
|
-
if (
|
|
43752
|
+
const entries = vaultListWithValues(DEFAULT_USER);
|
|
43753
|
+
if (entries.length === 0) {
|
|
44370
43754
|
console.log("vault is empty \u2014 `negotium vault set MY_KEY <value> [description]`");
|
|
44371
43755
|
return;
|
|
44372
43756
|
}
|
|
44373
|
-
for (const entry of
|
|
43757
|
+
for (const entry of entries) {
|
|
44374
43758
|
console.log(`${entry.key} ${entry.description || ""}`.trimEnd());
|
|
44375
43759
|
}
|
|
44376
43760
|
return;
|
|
@@ -44694,12 +44078,6 @@ var CLI_COMMANDS = [
|
|
|
44694
44078
|
description: "bootstrap ~/.negotium and check agent auth",
|
|
44695
44079
|
group: "Setup"
|
|
44696
44080
|
},
|
|
44697
|
-
{
|
|
44698
|
-
name: "migrate",
|
|
44699
|
-
usage: "migrate single-user [--source=local] --delete-other-users --yes",
|
|
44700
|
-
description: "explicitly migrate a 0.1 state tree to the 0.2 single-user layout",
|
|
44701
|
-
group: "Setup"
|
|
44702
|
-
},
|
|
44703
44081
|
{
|
|
44704
44082
|
name: "serve",
|
|
44705
44083
|
usage: "serve [otium]",
|
|
@@ -44806,7 +44184,7 @@ async function runCanonicalNode(port) {
|
|
|
44806
44184
|
});
|
|
44807
44185
|
console.log(`negotium node listening on 127.0.0.1:${node.port} (ctrl-c to stop)`);
|
|
44808
44186
|
await node.completed;
|
|
44809
|
-
await new Promise((
|
|
44187
|
+
await new Promise((resolve25) => setImmediate(resolve25));
|
|
44810
44188
|
process.exit(0);
|
|
44811
44189
|
}
|
|
44812
44190
|
async function stopAdapter(name) {
|
|
@@ -44829,11 +44207,6 @@ switch (command) {
|
|
|
44829
44207
|
initCommand2();
|
|
44830
44208
|
break;
|
|
44831
44209
|
}
|
|
44832
|
-
case "migrate": {
|
|
44833
|
-
const { migrateCommand: migrateCommand2 } = await init_migrate().then(() => exports_migrate);
|
|
44834
|
-
migrateCommand2(args);
|
|
44835
|
-
break;
|
|
44836
|
-
}
|
|
44837
44210
|
case "-v":
|
|
44838
44211
|
case "--version": {
|
|
44839
44212
|
const { NEGOTIUM_VERSION: NEGOTIUM_VERSION2 } = await Promise.resolve().then(() => exports_version);
|
|
@@ -44942,4 +44315,4 @@ switch (command) {
|
|
|
44942
44315
|
}
|
|
44943
44316
|
}
|
|
44944
44317
|
|
|
44945
|
-
//# debugId=
|
|
44318
|
+
//# debugId=C9823B7F89627C9D64756E2164756E21
|