negotium 0.1.49 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/agent-helpers.js +72 -78
- package/dist/agent-helpers.js.map +18 -17
- package/dist/background-bash.js +22 -10
- package/dist/background-bash.js.map +3 -3
- package/dist/browser-runtime.js +47 -72
- package/dist/browser-runtime.js.map +10 -9
- package/dist/{chunk-5rpw9d1f.js → chunk-kc5kmr95.js} +28 -11
- package/dist/{chunk-5rpw9d1f.js.map → chunk-kc5kmr95.js.map} +4 -4
- package/dist/hosted-agent.js +48 -22
- package/dist/hosted-agent.js.map +10 -9
- package/dist/main.js +576 -102
- package/dist/main.js.map +23 -20
- package/dist/mcp-factories.js +76 -82
- package/dist/mcp-factories.js.map +19 -18
- package/dist/prompts.js +22 -10
- package/dist/prompts.js.map +3 -3
- package/dist/query-runtime.js +22 -10
- package/dist/query-runtime.js.map +4 -4
- package/dist/registry.js +5 -12
- package/dist/registry.js.map +5 -5
- package/dist/rollout.js +1 -1
- package/dist/runtime/cron/mcp-server.ts +1 -1
- package/dist/runtime/src/agents/maestro-registry.ts +1 -1
- package/dist/runtime/src/agents/rollout/shared.ts +12 -4
- package/dist/runtime/src/mcp/mcp-helpers.ts +1 -1
- package/dist/runtime/src/mcp/wiki-server.ts +1 -1
- package/dist/runtime/src/migration/single-user.ts +621 -0
- package/dist/runtime/src/platform/config.ts +24 -11
- package/dist/runtime/src/platform/mcp-config.ts +4 -4
- package/dist/runtime/src/platform/playwright/manager.ts +10 -28
- package/dist/runtime/src/runtime/attachments.ts +3 -3
- package/dist/runtime/src/storage/browser-profiles.ts +11 -9
- package/dist/runtime/src/storage/conversations.ts +5 -18
- package/dist/runtime/src/storage/storage-host.ts +1 -1
- package/dist/runtime/src/storage/tasks.ts +2 -14
- package/dist/runtime/src/storage/vault-crypto-core.ts +65 -0
- package/dist/runtime/src/storage/vault-crypto.ts +8 -48
- package/dist/runtime/src/storage/vault.ts +3 -2
- package/dist/runtime/src/version.ts +1 -1
- package/dist/runtime-helpers.js +22 -10
- package/dist/runtime-helpers.js.map +5 -5
- package/dist/storage.js +5 -19
- package/dist/storage.js.map +5 -5
- package/dist/types/packages/core/src/mcp/mcp-helpers.d.ts +1 -1
- package/dist/types/packages/core/src/platform/config.d.ts +9 -1
- package/dist/types/packages/core/src/runtime/attachments.d.ts +1 -1
- package/dist/types/packages/core/src/storage/conversations.d.ts +2 -2
- package/dist/types/packages/core/src/storage/vault-crypto-core.d.ts +6 -0
- package/dist/types/packages/core/src/storage/vault-crypto.d.ts +2 -1
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/dist/vault.js +37 -16
- package/dist/vault.js.map +7 -6
- package/install-browser-rs.mjs +1 -1
- package/package.json +2 -2
package/dist/main.js
CHANGED
|
@@ -168,7 +168,7 @@ function resolveBrowserRsBin(envValue) {
|
|
|
168
168
|
if (!override && !versionAtLeast(BROWSER_RS_VERSION.replace(/^v/, ""), BROWSER_RS_MIN_SECURE_VERSION)) {
|
|
169
169
|
return;
|
|
170
170
|
}
|
|
171
|
-
const candidate = override ? resolve(override) : resolve(
|
|
171
|
+
const candidate = override ? resolve(override) : resolve(BINARIES_DIR, "browser-rs", BROWSER_RS_VERSION, "browser-rs");
|
|
172
172
|
try {
|
|
173
173
|
accessSync(candidate, constants.X_OK);
|
|
174
174
|
return browserRsMeetsMinimumVersion(candidate) ? candidate : undefined;
|
|
@@ -180,7 +180,7 @@ function resolveBrowserMcpBin(envValue) {
|
|
|
180
180
|
const override = envValue?.trim();
|
|
181
181
|
if (override)
|
|
182
182
|
return resolve(override);
|
|
183
|
-
return BROWSER_RS_BIN ?? resolve(
|
|
183
|
+
return BROWSER_RS_BIN ?? resolve(BINARIES_DIR, "browser-rs", BROWSER_RS_VERSION, "browser-rs");
|
|
184
184
|
}
|
|
185
185
|
function resolveBrowserProxy() {
|
|
186
186
|
const raw = envText("BROWSER_PROXY_URL");
|
|
@@ -212,7 +212,7 @@ function resolveTopicWorkspaceDir(topicId) {
|
|
|
212
212
|
}
|
|
213
213
|
function loadOrCreateLocalSecret(envKey, filename, options = {}) {
|
|
214
214
|
const envValue = envText(envKey);
|
|
215
|
-
const secretFile = resolve(
|
|
215
|
+
const secretFile = resolve(SECRETS_DIR, filename);
|
|
216
216
|
mkdirSync(dirname(secretFile), { recursive: true });
|
|
217
217
|
if (envValue) {
|
|
218
218
|
if (options.persistEnvValue) {
|
|
@@ -253,7 +253,7 @@ function resolveDefaultModel(agent, registryDefaultModel) {
|
|
|
253
253
|
function codexAuthFilePath() {
|
|
254
254
|
return process.env.NEGOTIUM_CODEX_AUTH_FILE || join(homedir(), ".codex", "auth.json");
|
|
255
255
|
}
|
|
256
|
-
var HOME, PROJECT_ROOT, STATE_DIR_ENV, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR,
|
|
256
|
+
var HOME, PROJECT_ROOT, STATE_DIR_ENV, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR, CRON_WORKSPACE_DIR, BROWSER_DIR, BROWSER_PROFILES_DIR, BINARIES_DIR, SECRETS_DIR, CONTEXTS_DIR, DM_WORKSPACE_DIR, SESSION_WORKSPACE_DIR, CLAUDE_EXECUTABLE_ENV, CLAUDE_EXECUTABLE, DEFAULT_OUTPUT_LANGUAGE = "English", BROWSER_RS_VERSION = "v0.1.16", BROWSER_RS_MIN_SECURE_VERSION = "0.1.15", BROWSER_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, BROWSER_MCP_SSE_PROXY_SERVER, CANONICAL_MCP_PROXY_SERVER, WIKI_SERVER, TOKEN_STATS_SERVER, COMPACTION_LOG_SERVER, SYSTEM_HEALTH_SERVER, AGENT_HEALTH_SERVER, BACKGROUND_BASH_SERVER, VAULT_SERVER, BG_BASH_BASE_PORT, BG_BASH_MAX_PORT, RUNTIME_MCP_SECRET, NODE_CONTROL_TOKEN, VAULT_MASTER_KEY, NEGOTIUM_PORT, hostname, DATA_DIR, LOG_DIR, UPLOADS_DIR, VAULT_DIR, SESSIONS_DB, DEBUG_FILE, USERS_LOG_DIR, RUN_DIR, PROGRESS_DIR, DM_CMD_DIR, DM_RESP_DIR, SESSION_INBOX_DIR, SESSION_ASKS_DIR, PLAYWRIGHT_BASE_PORT, PLAYWRIGHT_MAX_PORT, PLAYWRIGHT_PORTS_DIR, ACTIVE_QUERY_STALE_MS, AGENTS_PROMPTS_DIR, RESOURCES_DIR, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5", MODEL_FABLE = "claude-fable-5", FALLBACK_AGENT, SESSION_AGENT, GATEWAY_AGENT, FALLBACK_MODEL, SESSION_MODEL, GATEWAY_MODEL, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, _envMaxTellDepth, MAX_TELL_DEPTH;
|
|
257
257
|
var init_config = __esm(() => {
|
|
258
258
|
init_config_helpers();
|
|
259
259
|
init_logger();
|
|
@@ -265,10 +265,14 @@ var init_config = __esm(() => {
|
|
|
265
265
|
WORKSPACE_DIR = resolveLocalStateDir("NEGOTIUM_WORKSPACE_DIR", "workspace");
|
|
266
266
|
TOPIC_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "topics");
|
|
267
267
|
SHARED_WIKI_DIR = resolve(WORKSPACE_DIR, "wiki");
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
268
|
+
CRON_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "cron");
|
|
269
|
+
BROWSER_DIR = resolveLocalStateDir("NEGOTIUM_BROWSER_DIR", "browser");
|
|
270
|
+
BROWSER_PROFILES_DIR = resolve(BROWSER_DIR, "profiles");
|
|
271
|
+
BINARIES_DIR = resolve(STATE_DIR, "binaries");
|
|
272
|
+
SECRETS_DIR = resolve(STATE_DIR, "secrets");
|
|
273
|
+
CONTEXTS_DIR = resolve(STATE_DIR, "data", "contexts");
|
|
274
|
+
DM_WORKSPACE_DIR = resolve(STATE_DIR, "data", "dm");
|
|
275
|
+
SESSION_WORKSPACE_DIR = resolve(STATE_DIR, "data", "sessions");
|
|
272
276
|
CLAUDE_EXECUTABLE_ENV = envText("NEGOTIUM_CLAUDE_EXECUTABLE");
|
|
273
277
|
CLAUDE_EXECUTABLE = CLAUDE_EXECUTABLE_ENV ? resolve(CLAUDE_EXECUTABLE_ENV) : undefined;
|
|
274
278
|
BROWSER_RS_BIN = resolveBrowserRsBin(envText("NEGOTIUM_BROWSER_RS_BIN"));
|
|
@@ -297,10 +301,12 @@ var init_config = __esm(() => {
|
|
|
297
301
|
hostname = process.env.HOSTNAME || "127.0.0.1";
|
|
298
302
|
DATA_DIR = resolveLocalStateDir("NEGOTIUM_DATA_DIR", "data");
|
|
299
303
|
LOG_DIR = resolveLocalStateDir("NEGOTIUM_LOG_DIR", "logs");
|
|
304
|
+
UPLOADS_DIR = resolve(DATA_DIR, "uploads");
|
|
305
|
+
VAULT_DIR = resolve(DATA_DIR, "vault");
|
|
300
306
|
SESSIONS_DB = process.env.SESSIONS_DB_PATH ? resolve(process.env.SESSIONS_DB_PATH) : resolve(DATA_DIR, "sessions.db");
|
|
301
307
|
DEBUG_FILE = resolve(DATA_DIR, "debug-users.json");
|
|
302
308
|
USERS_LOG_DIR = resolve(DATA_DIR, "users");
|
|
303
|
-
RUN_DIR = resolveLocalStateDir("NEGOTIUM_RUN_DIR", "
|
|
309
|
+
RUN_DIR = resolveLocalStateDir("NEGOTIUM_RUN_DIR", "runtime");
|
|
304
310
|
PROGRESS_DIR = resolve(RUN_DIR, "progress");
|
|
305
311
|
DM_CMD_DIR = resolve(RUN_DIR, "dm-commands");
|
|
306
312
|
DM_RESP_DIR = resolve(RUN_DIR, "dm-responses");
|
|
@@ -311,6 +317,8 @@ var init_config = __esm(() => {
|
|
|
311
317
|
PLAYWRIGHT_PORTS_DIR = resolve(RUN_DIR, "playwright-ports");
|
|
312
318
|
mkdirSync(STATE_DIR, { recursive: true });
|
|
313
319
|
mkdirSync(DATA_DIR, { recursive: true });
|
|
320
|
+
mkdirSync(UPLOADS_DIR, { recursive: true });
|
|
321
|
+
mkdirSync(VAULT_DIR, { recursive: true, mode: 448 });
|
|
314
322
|
mkdirSync(LOG_DIR, { recursive: true });
|
|
315
323
|
mkdirSync(PROGRESS_DIR, { recursive: true });
|
|
316
324
|
mkdirSync(DM_CMD_DIR, { recursive: true });
|
|
@@ -321,10 +329,14 @@ var init_config = __esm(() => {
|
|
|
321
329
|
mkdirSync(WORKSPACE_DIR, { recursive: true });
|
|
322
330
|
mkdirSync(TOPIC_WORKSPACE_DIR, { recursive: true });
|
|
323
331
|
mkdirSync(SHARED_WIKI_DIR, { recursive: true });
|
|
332
|
+
mkdirSync(CRON_WORKSPACE_DIR, { recursive: true });
|
|
324
333
|
mkdirSync(CONTEXTS_DIR, { recursive: true });
|
|
325
|
-
mkdirSync(BROWSER_PROFILES_DIR, { recursive: true });
|
|
326
334
|
mkdirSync(DM_WORKSPACE_DIR, { recursive: true });
|
|
327
335
|
mkdirSync(SESSION_WORKSPACE_DIR, { recursive: true });
|
|
336
|
+
mkdirSync(BROWSER_DIR, { recursive: true });
|
|
337
|
+
mkdirSync(BROWSER_PROFILES_DIR, { recursive: true });
|
|
338
|
+
mkdirSync(BINARIES_DIR, { recursive: true });
|
|
339
|
+
mkdirSync(SECRETS_DIR, { recursive: true, mode: 448 });
|
|
328
340
|
ACTIVE_QUERY_STALE_MS = 10 * 60 * 1000;
|
|
329
341
|
AGENTS_PROMPTS_DIR = resolve(PROJECT_ROOT, "src/prompts/agents");
|
|
330
342
|
RESOURCES_DIR = resolve(PROJECT_ROOT, "src/resources");
|
|
@@ -399,9 +411,9 @@ var init_sqlite = __esm(async () => {
|
|
|
399
411
|
}
|
|
400
412
|
});
|
|
401
413
|
|
|
402
|
-
// ../../packages/core/src/storage/vault-crypto.ts
|
|
414
|
+
// ../../packages/core/src/storage/vault-crypto-core.ts
|
|
403
415
|
import { createCipheriv, createDecipheriv, createHash, randomBytes as randomBytes2 } from "crypto";
|
|
404
|
-
function encryptionKey(masterKey
|
|
416
|
+
function encryptionKey(masterKey) {
|
|
405
417
|
return createHash("sha256").update("otium-vault-value-v1\x00", "utf8").update(masterKey, "utf8").digest().subarray(0, KEY_BYTES);
|
|
406
418
|
}
|
|
407
419
|
function aad(userId, key) {
|
|
@@ -410,7 +422,7 @@ function aad(userId, key) {
|
|
|
410
422
|
function isEncryptedVaultValue(value) {
|
|
411
423
|
return value.startsWith(ENVELOPE_PREFIX);
|
|
412
424
|
}
|
|
413
|
-
function
|
|
425
|
+
function encryptVaultValueWithKey(userId, key, value, masterKey) {
|
|
414
426
|
const iv = randomBytes2(IV_BYTES);
|
|
415
427
|
const cipher = createCipheriv("aes-256-gcm", encryptionKey(masterKey), iv);
|
|
416
428
|
cipher.setAAD(aad(userId, key));
|
|
@@ -418,7 +430,7 @@ function encryptVaultValue(userId, key, value, masterKey = VAULT_MASTER_KEY) {
|
|
|
418
430
|
const tag = cipher.getAuthTag();
|
|
419
431
|
return `${ENVELOPE_PREFIX}${iv.toString("base64url")}.${ciphertext.toString("base64url")}.${tag.toString("base64url")}`;
|
|
420
432
|
}
|
|
421
|
-
function
|
|
433
|
+
function decryptVaultValueWithKey(userId, key, storedValue, masterKey) {
|
|
422
434
|
if (!isEncryptedVaultValue(storedValue)) {
|
|
423
435
|
return { value: storedValue, legacyPlaintext: true };
|
|
424
436
|
}
|
|
@@ -440,8 +452,18 @@ function decryptVaultValue(userId, key, storedValue, masterKey = VAULT_MASTER_KE
|
|
|
440
452
|
return { value: plaintext.toString("utf8"), legacyPlaintext: false };
|
|
441
453
|
}
|
|
442
454
|
var ENVELOPE_PREFIX = "otium-vault:v1:", IV_BYTES = 12, KEY_BYTES = 32;
|
|
455
|
+
var init_vault_crypto_core = () => {};
|
|
456
|
+
|
|
457
|
+
// ../../packages/core/src/storage/vault-crypto.ts
|
|
458
|
+
function encryptVaultValue(userId, key, value, masterKey = VAULT_MASTER_KEY) {
|
|
459
|
+
return encryptVaultValueWithKey(userId, key, value, masterKey);
|
|
460
|
+
}
|
|
461
|
+
function decryptVaultValue(userId, key, storedValue, masterKey = VAULT_MASTER_KEY) {
|
|
462
|
+
return decryptVaultValueWithKey(userId, key, storedValue, masterKey);
|
|
463
|
+
}
|
|
443
464
|
var init_vault_crypto = __esm(() => {
|
|
444
465
|
init_config();
|
|
466
|
+
init_vault_crypto_core();
|
|
445
467
|
});
|
|
446
468
|
|
|
447
469
|
// ../../packages/core/src/storage/vault.ts
|
|
@@ -481,8 +503,9 @@ function initializeVaultDatabase(database) {
|
|
|
481
503
|
}
|
|
482
504
|
}
|
|
483
505
|
function openVaultDatabase(dataDir) {
|
|
484
|
-
const
|
|
485
|
-
|
|
506
|
+
const vaultDir = join2(dataDir, "vault");
|
|
507
|
+
const path = join2(vaultDir, "vault.db");
|
|
508
|
+
mkdirSync2(vaultDir, { recursive: true, mode: 448 });
|
|
486
509
|
const database = new Database(path, { create: true });
|
|
487
510
|
chmodSync2(path, 384);
|
|
488
511
|
initializeVaultDatabase(database);
|
|
@@ -1119,7 +1142,12 @@ var init_shared = __esm(() => {
|
|
|
1119
1142
|
init_config();
|
|
1120
1143
|
init_logger();
|
|
1121
1144
|
__dirname2 = dirname2(fileURLToPath2(import.meta.url));
|
|
1122
|
-
trustedWorkspaceRoots = [
|
|
1145
|
+
trustedWorkspaceRoots = [
|
|
1146
|
+
WORKSPACE_DIR,
|
|
1147
|
+
DM_WORKSPACE_DIR,
|
|
1148
|
+
SESSION_WORKSPACE_DIR,
|
|
1149
|
+
TOPIC_WORKSPACE_DIR
|
|
1150
|
+
].map((root) => resolve2(root));
|
|
1123
1151
|
FIXTURES_DIR = join4(__dirname2, "..", "fixtures");
|
|
1124
1152
|
UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1125
1153
|
});
|
|
@@ -2029,7 +2057,7 @@ function defaultWorkspaceDir() {
|
|
|
2029
2057
|
return envPath("NEGOTIUM_WORKSPACE_DIR", join8(defaultStateDir(), "workspace"));
|
|
2030
2058
|
}
|
|
2031
2059
|
function defaultSessionAsksDir() {
|
|
2032
|
-
const runDir = envPath("NEGOTIUM_RUN_DIR", join8(defaultStateDir(), "
|
|
2060
|
+
const runDir = envPath("NEGOTIUM_RUN_DIR", join8(defaultStateDir(), "runtime"));
|
|
2033
2061
|
return join8(runDir, "session-asks");
|
|
2034
2062
|
}
|
|
2035
2063
|
function defaultSessionsDatabasePath() {
|
|
@@ -2210,15 +2238,8 @@ import {
|
|
|
2210
2238
|
writeFileSync as writeFileSync4
|
|
2211
2239
|
} from "fs";
|
|
2212
2240
|
import { dirname as dirname6, join as join9 } from "path";
|
|
2213
|
-
function
|
|
2214
|
-
|
|
2215
|
-
if (!str || /[/\\]|\.\./.test(str)) {
|
|
2216
|
-
throw new Error(`conversations: refusing unsafe userId path component: ${str}`);
|
|
2217
|
-
}
|
|
2218
|
-
return str;
|
|
2219
|
-
}
|
|
2220
|
-
function conversationDir(userId) {
|
|
2221
|
-
return join9(resolveStorageDataDir(), "conversations", safeUserIdComponent(userId));
|
|
2241
|
+
function conversationDir(_userId) {
|
|
2242
|
+
return join9(resolveStorageDataDir(), "conversations");
|
|
2222
2243
|
}
|
|
2223
2244
|
function topicFilename(topicName) {
|
|
2224
2245
|
const t = sanitizeTopicName(topicName, true);
|
|
@@ -2500,7 +2521,7 @@ function writeRollout(options) {
|
|
|
2500
2521
|
version: 1,
|
|
2501
2522
|
cwd: options.cwd,
|
|
2502
2523
|
createdAt: existingCreatedAt(path) ?? new Date().toISOString(),
|
|
2503
|
-
sdkVersion: "0.1.
|
|
2524
|
+
sdkVersion: "0.1.54"
|
|
2504
2525
|
}
|
|
2505
2526
|
},
|
|
2506
2527
|
...messages
|
|
@@ -2677,13 +2698,6 @@ __export(exports_tasks, {
|
|
|
2677
2698
|
});
|
|
2678
2699
|
import { existsSync as existsSync10, mkdirSync as mkdirSync9, readFileSync as readFileSync7, renameSync as renameSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
2679
2700
|
import { dirname as dirname7, join as join12 } from "path";
|
|
2680
|
-
function safeUserIdComponent2(userId) {
|
|
2681
|
-
const str = String(userId);
|
|
2682
|
-
if (!str || /[/\\]|\.\./.test(str)) {
|
|
2683
|
-
throw new Error(`tasks: refusing unsafe userId path component: ${str}`);
|
|
2684
|
-
}
|
|
2685
|
-
return str;
|
|
2686
|
-
}
|
|
2687
2701
|
function safeTaskScopeKey(scopeKey) {
|
|
2688
2702
|
const safe = sanitizeFileName(scopeKey);
|
|
2689
2703
|
if (!safe || safe === "." || safe === "..") {
|
|
@@ -2695,7 +2709,7 @@ function taskScopeKey(opts) {
|
|
|
2695
2709
|
return opts.topicId?.trim() || opts.session || "default";
|
|
2696
2710
|
}
|
|
2697
2711
|
function getTaskFilePath(userId, scopeKey) {
|
|
2698
|
-
return join12(resolveStorageDataDir(), "tasks",
|
|
2712
|
+
return join12(resolveStorageDataDir(), "tasks", `${safeTaskScopeKey(scopeKey)}.json`);
|
|
2699
2713
|
}
|
|
2700
2714
|
function readTasks(userId, scopeKey) {
|
|
2701
2715
|
const path = getTaskFilePath(userId, scopeKey);
|
|
@@ -3680,7 +3694,7 @@ function getMcpServersForQuery(opts) {
|
|
|
3680
3694
|
if (!opts.topicId)
|
|
3681
3695
|
throw new Error("getMcpServersForQuery: cron sessionType requires topicId");
|
|
3682
3696
|
return getCronMcpServers({
|
|
3683
|
-
userId: opts.userId || "
|
|
3697
|
+
userId: opts.userId || "local",
|
|
3684
3698
|
session: opts.session || "cron",
|
|
3685
3699
|
topicId: opts.topicId,
|
|
3686
3700
|
queryId: opts.queryId,
|
|
@@ -3697,7 +3711,7 @@ function getMcpServersForQuery(opts) {
|
|
|
3697
3711
|
}
|
|
3698
3712
|
if (opts.sessionType === "dm" || opts.sessionType === "ephemeral") {
|
|
3699
3713
|
return getDmMcpServers({
|
|
3700
|
-
userId: opts.userId || "
|
|
3714
|
+
userId: opts.userId || "local",
|
|
3701
3715
|
agent: opts.agent,
|
|
3702
3716
|
playwrightPort: opts.playwrightPort,
|
|
3703
3717
|
playwrightCapability: opts.playwrightCapability
|
|
@@ -3705,7 +3719,7 @@ function getMcpServersForQuery(opts) {
|
|
|
3705
3719
|
}
|
|
3706
3720
|
if (opts.sessionType === "manager") {
|
|
3707
3721
|
return getManagerMcpServers({
|
|
3708
|
-
userId: opts.userId || "
|
|
3722
|
+
userId: opts.userId || "local",
|
|
3709
3723
|
session: opts.session,
|
|
3710
3724
|
topicId: opts.topicId,
|
|
3711
3725
|
queryId: opts.queryId,
|
|
@@ -3722,7 +3736,7 @@ function getMcpServersForQuery(opts) {
|
|
|
3722
3736
|
});
|
|
3723
3737
|
}
|
|
3724
3738
|
return getForumMcpServers({
|
|
3725
|
-
userId: opts.userId || "
|
|
3739
|
+
userId: opts.userId || "local",
|
|
3726
3740
|
session: opts.session || "default",
|
|
3727
3741
|
topicId: opts.topicId,
|
|
3728
3742
|
subagentParentTopicId: opts.subagentParentTopicId,
|
|
@@ -4580,7 +4594,7 @@ var exports_version = {};
|
|
|
4580
4594
|
__export(exports_version, {
|
|
4581
4595
|
NEGOTIUM_VERSION: () => NEGOTIUM_VERSION
|
|
4582
4596
|
});
|
|
4583
|
-
var NEGOTIUM_VERSION = "0.1
|
|
4597
|
+
var NEGOTIUM_VERSION = "0.2.1";
|
|
4584
4598
|
|
|
4585
4599
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
4586
4600
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -9730,7 +9744,7 @@ function createBrowserProfile(ownerId, rawName) {
|
|
|
9730
9744
|
const name = normalizeBrowserProfileName(rawName);
|
|
9731
9745
|
if (name === DEFAULT_BROWSER_PROFILE)
|
|
9732
9746
|
return name;
|
|
9733
|
-
db.query("INSERT OR IGNORE INTO browser_profiles (owner_id, name, created_at) VALUES (?, ?, ?)").run(
|
|
9747
|
+
db.query("INSERT OR IGNORE INTO browser_profiles (owner_id, name, created_at) VALUES (?, ?, ?)").run("local", name, new Date().toISOString());
|
|
9734
9748
|
return name;
|
|
9735
9749
|
}
|
|
9736
9750
|
function assignTopicBrowserProfile(opts) {
|
|
@@ -9750,10 +9764,9 @@ function assignTopicBrowserProfile(opts) {
|
|
|
9750
9764
|
return { previous, profile };
|
|
9751
9765
|
}
|
|
9752
9766
|
function listBrowserProfiles(ownerId) {
|
|
9753
|
-
const records = db.query("SELECT name, created_at FROM browser_profiles WHERE owner_id = ? ORDER BY name").all(
|
|
9767
|
+
const records = db.query("SELECT name, created_at FROM browser_profiles WHERE owner_id = ? ORDER BY name").all("local");
|
|
9754
9768
|
const topics = db.query(`SELECT t.id, t.title, t.browser_profile FROM api_topics t
|
|
9755
|
-
|
|
9756
|
-
ORDER BY t.title`).all(ownerId);
|
|
9769
|
+
ORDER BY t.title`).all();
|
|
9757
9770
|
const byName = new Map;
|
|
9758
9771
|
byName.set(DEFAULT_BROWSER_PROFILE, {
|
|
9759
9772
|
name: DEFAULT_BROWSER_PROFILE,
|
|
@@ -9798,7 +9811,6 @@ import {
|
|
|
9798
9811
|
existsSync as existsSync15,
|
|
9799
9812
|
mkdirSync as mkdirSync10,
|
|
9800
9813
|
readFileSync as readFileSync12,
|
|
9801
|
-
renameSync as renameSync6,
|
|
9802
9814
|
rmSync as rmSync2,
|
|
9803
9815
|
unlinkSync as unlinkSync11,
|
|
9804
9816
|
writeFileSync as writeFileSync8
|
|
@@ -9814,7 +9826,7 @@ function defaultTopicBinding(userId, topic) {
|
|
|
9814
9826
|
if (!topic)
|
|
9815
9827
|
return managerHost.resolveNamedBinding(userId, "default");
|
|
9816
9828
|
const ownerId = getBrowserProfileOwner(topic, userId);
|
|
9817
|
-
const profile =
|
|
9829
|
+
const profile = getTopicBrowserProfile(topic);
|
|
9818
9830
|
return managerHost.resolveNamedBinding(ownerId, profile);
|
|
9819
9831
|
}
|
|
9820
9832
|
function resolvePlaywrightProfileBinding(ownerId, rawProfile) {
|
|
@@ -9826,34 +9838,15 @@ function validateProfileBinding(binding) {
|
|
|
9826
9838
|
}
|
|
9827
9839
|
return Object.freeze({ ...binding });
|
|
9828
9840
|
}
|
|
9829
|
-
function defaultNamedBinding(
|
|
9841
|
+
function defaultNamedBinding(_ownerId, rawProfile) {
|
|
9830
9842
|
const profile = normalizeBrowserProfileName(rawProfile);
|
|
9831
|
-
const instanceKey = `profile:${
|
|
9843
|
+
const instanceKey = `profile:${profile}`;
|
|
9832
9844
|
return {
|
|
9833
9845
|
instanceKey,
|
|
9834
|
-
ownerId,
|
|
9846
|
+
ownerId: "local",
|
|
9835
9847
|
profile
|
|
9836
9848
|
};
|
|
9837
9849
|
}
|
|
9838
|
-
function legacyBrowserProfileName(topic) {
|
|
9839
|
-
return `legacy_${createHash3("sha256").update(topic).digest("hex").slice(0, 12)}`;
|
|
9840
|
-
}
|
|
9841
|
-
function migrateLegacyTopicProfile(ownerId, topic) {
|
|
9842
|
-
const current2 = getTopicBrowserProfile(topic);
|
|
9843
|
-
if (current2 !== "default" || !hasBrowserProfileTopic(topic))
|
|
9844
|
-
return current2;
|
|
9845
|
-
const legacyDir = resolve12(BROWSER_PROFILES_DIR, sanitizeTopicName(topic));
|
|
9846
|
-
if (!existsSync15(legacyDir))
|
|
9847
|
-
return current2;
|
|
9848
|
-
const profile = legacyBrowserProfileName(topic);
|
|
9849
|
-
const profileDir = defaultProfileDir(ownerId, profile);
|
|
9850
|
-
mkdirSync10(dirname10(profileDir), { recursive: true });
|
|
9851
|
-
if (!existsSync15(profileDir))
|
|
9852
|
-
renameSync6(legacyDir, profileDir);
|
|
9853
|
-
assignTopicBrowserProfile({ topicId: topic, actorUserId: ownerId, profile });
|
|
9854
|
-
logger.info({ ownerId, topic, profile }, "Adopted legacy topic browser profile");
|
|
9855
|
-
return profile;
|
|
9856
|
-
}
|
|
9857
9850
|
function defaultChildEnvironment(context) {
|
|
9858
9851
|
const childEnvironment = {};
|
|
9859
9852
|
for (const key of [
|
|
@@ -9884,6 +9877,10 @@ function defaultChildEnvironment(context) {
|
|
|
9884
9877
|
return childEnvironment;
|
|
9885
9878
|
}
|
|
9886
9879
|
function parseInstanceKey(instanceKey) {
|
|
9880
|
+
const shared = /^profile:(.+)$/.exec(instanceKey);
|
|
9881
|
+
if (shared && !shared[1].includes(":")) {
|
|
9882
|
+
return { ownerId: "local", profile: normalizeBrowserProfileName(shared[1]) };
|
|
9883
|
+
}
|
|
9887
9884
|
const match = /^profile:([^:]+):(.+)$/.exec(instanceKey);
|
|
9888
9885
|
if (!match)
|
|
9889
9886
|
return { ownerId: "legacy", profile: sanitizeTopicName(instanceKey) };
|
|
@@ -10026,12 +10023,8 @@ async function allocatePort() {
|
|
|
10026
10023
|
function releasePort(port) {
|
|
10027
10024
|
usedPorts.delete(port);
|
|
10028
10025
|
}
|
|
10029
|
-
function
|
|
10030
|
-
|
|
10031
|
-
return `${sanitizeTopicName(ownerId).slice(0, 24)}_${digest}`;
|
|
10032
|
-
}
|
|
10033
|
-
function defaultProfileDir(ownerId, profile) {
|
|
10034
|
-
return resolve12(BROWSER_PROFILES_DIR, "profiles", ownerDirectory(ownerId), profile);
|
|
10026
|
+
function defaultProfileDir(_ownerId, profile) {
|
|
10027
|
+
return resolve12(BROWSER_PROFILES_DIR, profile);
|
|
10035
10028
|
}
|
|
10036
10029
|
function resolveUserDataDir(instanceKey) {
|
|
10037
10030
|
return managerHost.resolveInstanceDataDir(instanceKey);
|
|
@@ -12440,7 +12433,7 @@ var init_idle_archiver = __esm(async () => {
|
|
|
12440
12433
|
});
|
|
12441
12434
|
|
|
12442
12435
|
// ../../packages/core/src/agents/topic-cleanup.ts
|
|
12443
|
-
import { mkdirSync as mkdirSync12, renameSync as
|
|
12436
|
+
import { mkdirSync as mkdirSync12, renameSync as renameSync6, unlinkSync as unlinkSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
12444
12437
|
import { dirname as dirname12 } from "path";
|
|
12445
12438
|
function collectSessionIdsByAgent(entries, extraSessions = []) {
|
|
12446
12439
|
const out = new Map;
|
|
@@ -12511,7 +12504,7 @@ function createTopicLogMaintenance(host) {
|
|
|
12511
12504
|
writeFileSync10(tempPath, retained.length > 0 ? `${retained.map((entry) => JSON.stringify(entry)).join(`
|
|
12512
12505
|
`)}
|
|
12513
12506
|
` : "", { flag: "wx" });
|
|
12514
|
-
|
|
12507
|
+
renameSync6(tempPath, path);
|
|
12515
12508
|
} catch (e) {
|
|
12516
12509
|
try {
|
|
12517
12510
|
unlinkSync12(tempPath);
|
|
@@ -14767,7 +14760,7 @@ var init_session_inbox_cleanup = __esm(() => {
|
|
|
14767
14760
|
});
|
|
14768
14761
|
|
|
14769
14762
|
// ../../packages/core/src/query/state.ts
|
|
14770
|
-
import { mkdirSync as mkdirSync14, renameSync as
|
|
14763
|
+
import { mkdirSync as mkdirSync14, renameSync as renameSync7, unlinkSync as unlinkSync15, writeFileSync as writeFileSync12 } from "fs";
|
|
14771
14764
|
import { basename as basename4, join as join24 } from "path";
|
|
14772
14765
|
function createQueryStateStore(options) {
|
|
14773
14766
|
const sanitize = options.sanitizeTopicId ?? sanitizeId;
|
|
@@ -14789,7 +14782,7 @@ function createQueryStateStore(options) {
|
|
|
14789
14782
|
const target = queryStateFile(userId, topicId);
|
|
14790
14783
|
const tmp = `${target}.${process.pid}.${Date.now()}.tmp`;
|
|
14791
14784
|
writeFileSync12(tmp, JSON.stringify(state));
|
|
14792
|
-
|
|
14785
|
+
renameSync7(tmp, target);
|
|
14793
14786
|
},
|
|
14794
14787
|
clear(userId, topicId, legacyTopicName) {
|
|
14795
14788
|
const paths = [
|
|
@@ -15943,7 +15936,7 @@ function promptWithAttachments(prompt, attachments) {
|
|
|
15943
15936
|
return composeAttachmentPrompt(prompt, attachments.map(({ filename, path }) => attachmentPromptLine(filename, path)));
|
|
15944
15937
|
}
|
|
15945
15938
|
function ingestAttachment(args) {
|
|
15946
|
-
const destDir = join26(
|
|
15939
|
+
const destDir = join26(UPLOADS_DIR, args.topicId);
|
|
15947
15940
|
mkdirSync16(destDir, { recursive: true });
|
|
15948
15941
|
const safeName = safeAttachmentFilename(args.filename, "upload");
|
|
15949
15942
|
const destPath = join26(destDir, `${Date.now()}-${randomUUID15().slice(0, 8)}-${safeName}`);
|
|
@@ -20616,7 +20609,7 @@ function renderTurnFooter(msg) {
|
|
|
20616
20609
|
|
|
20617
20610
|
// ../../packages/core/src/outbox/file-ops.ts
|
|
20618
20611
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
20619
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync21, readFileSync as readFileSync18, renameSync as
|
|
20612
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync21, readFileSync as readFileSync18, renameSync as renameSync8, unlinkSync as unlinkSync17 } from "fs";
|
|
20620
20613
|
function host() {
|
|
20621
20614
|
return hostContext.getStore() ?? defaultHost2;
|
|
20622
20615
|
}
|
|
@@ -20657,7 +20650,7 @@ function drainOutboxFile(filePath, label) {
|
|
|
20657
20650
|
if (!existsSync21(filePath))
|
|
20658
20651
|
return null;
|
|
20659
20652
|
try {
|
|
20660
|
-
|
|
20653
|
+
renameSync8(filePath, processingPath);
|
|
20661
20654
|
} catch (e) {
|
|
20662
20655
|
host().logger.warn({ err: e, filePath }, `${label}: failed to rename for processing`);
|
|
20663
20656
|
return null;
|
|
@@ -23678,7 +23671,7 @@ import {
|
|
|
23678
23671
|
openSync as openSync3,
|
|
23679
23672
|
readdirSync as readdirSync9,
|
|
23680
23673
|
readFileSync as readFileSync20,
|
|
23681
|
-
renameSync as
|
|
23674
|
+
renameSync as renameSync9,
|
|
23682
23675
|
statSync as statSync12,
|
|
23683
23676
|
unlinkSync as unlinkSync18,
|
|
23684
23677
|
writeFileSync as writeFileSync17
|
|
@@ -23798,7 +23791,7 @@ function atomicWriteFile(path, content) {
|
|
|
23798
23791
|
const temporaryPath = `${path}.tmp.${process.pid}.${Date.now()}`;
|
|
23799
23792
|
writeFileSync17(temporaryPath, content, "utf-8");
|
|
23800
23793
|
try {
|
|
23801
|
-
|
|
23794
|
+
renameSync9(temporaryPath, path);
|
|
23802
23795
|
} catch (error2) {
|
|
23803
23796
|
try {
|
|
23804
23797
|
unlinkSync18(temporaryPath);
|
|
@@ -24531,7 +24524,7 @@ import {
|
|
|
24531
24524
|
existsSync as existsSync25,
|
|
24532
24525
|
mkdirSync as mkdirSync25,
|
|
24533
24526
|
readdirSync as readdirSync10,
|
|
24534
|
-
renameSync as
|
|
24527
|
+
renameSync as renameSync10,
|
|
24535
24528
|
statSync as statSync13,
|
|
24536
24529
|
unlinkSync as unlinkSync19,
|
|
24537
24530
|
writeFileSync as writeFileSync18
|
|
@@ -24555,7 +24548,7 @@ function writeLog(entry) {
|
|
|
24555
24548
|
const stat = statSync13(file);
|
|
24556
24549
|
if (stat.size >= MAX_FILE_SIZE) {
|
|
24557
24550
|
const rotated = file.replace(/\.jsonl$/, `.${Date.now()}.jsonl`);
|
|
24558
|
-
|
|
24551
|
+
renameSync10(file, rotated);
|
|
24559
24552
|
}
|
|
24560
24553
|
} catch {}
|
|
24561
24554
|
try {
|
|
@@ -26143,7 +26136,7 @@ var init_spec = __esm(() => {
|
|
|
26143
26136
|
});
|
|
26144
26137
|
|
|
26145
26138
|
// ../../packages/mcp-host/src/manifest.ts
|
|
26146
|
-
import { existsSync as existsSync26, mkdirSync as mkdirSync26, readFileSync as readFileSync21, renameSync as
|
|
26139
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync26, readFileSync as readFileSync21, renameSync as renameSync11, writeFileSync as writeFileSync19 } from "fs";
|
|
26147
26140
|
import { dirname as dirname17 } from "path";
|
|
26148
26141
|
import { z as z13 } from "zod";
|
|
26149
26142
|
|
|
@@ -26212,7 +26205,7 @@ class McpManifest {
|
|
|
26212
26205
|
const tmp = `${this.file}.tmp-${process.pid}`;
|
|
26213
26206
|
writeFileSync19(tmp, `${JSON.stringify(payload, null, 2)}
|
|
26214
26207
|
`);
|
|
26215
|
-
|
|
26208
|
+
renameSync11(tmp, this.file);
|
|
26216
26209
|
}
|
|
26217
26210
|
}
|
|
26218
26211
|
var manifestEntrySchema, manifestFileSchema;
|
|
@@ -26243,7 +26236,7 @@ import {
|
|
|
26243
26236
|
mkdirSync as mkdirSync27,
|
|
26244
26237
|
readdirSync as readdirSync11,
|
|
26245
26238
|
readFileSync as readFileSync22,
|
|
26246
|
-
renameSync as
|
|
26239
|
+
renameSync as renameSync12,
|
|
26247
26240
|
unlinkSync as unlinkSync20,
|
|
26248
26241
|
writeFileSync as writeFileSync20
|
|
26249
26242
|
} from "fs";
|
|
@@ -26563,7 +26556,7 @@ class McpHost {
|
|
|
26563
26556
|
const file = join37(this.portsDir, fileName);
|
|
26564
26557
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
26565
26558
|
writeFileSync20(tmp, String(port));
|
|
26566
|
-
|
|
26559
|
+
renameSync12(tmp, file);
|
|
26567
26560
|
} catch (e) {
|
|
26568
26561
|
this.log("warn", "Failed to write MCP port file", { fileName, port, err: String(e) });
|
|
26569
26562
|
}
|
|
@@ -26961,7 +26954,7 @@ import {
|
|
|
26961
26954
|
existsSync as existsSync28,
|
|
26962
26955
|
mkdirSync as mkdirSync29,
|
|
26963
26956
|
readFileSync as readFileSync24,
|
|
26964
|
-
renameSync as
|
|
26957
|
+
renameSync as renameSync13,
|
|
26965
26958
|
unlinkSync as unlinkSync21,
|
|
26966
26959
|
writeFileSync as writeFileSync22
|
|
26967
26960
|
} from "fs";
|
|
@@ -27456,7 +27449,7 @@ function writeNodeDaemonInfo(port, startedAt) {
|
|
|
27456
27449
|
writeFileSync22(temporary, `${JSON.stringify(info, null, 2)}
|
|
27457
27450
|
`, { mode: 384 });
|
|
27458
27451
|
chmodSync5(temporary, 384);
|
|
27459
|
-
|
|
27452
|
+
renameSync13(temporary, NODE_DAEMON_INFO_PATH);
|
|
27460
27453
|
chmodSync5(NODE_DAEMON_INFO_PATH, 384);
|
|
27461
27454
|
return info;
|
|
27462
27455
|
}
|
|
@@ -38926,7 +38919,7 @@ import {
|
|
|
38926
38919
|
mkdirSync as mkdirSync32,
|
|
38927
38920
|
openSync as openSync4,
|
|
38928
38921
|
readFileSync as readFileSync25,
|
|
38929
|
-
renameSync as
|
|
38922
|
+
renameSync as renameSync14,
|
|
38930
38923
|
rmSync as rmSync9,
|
|
38931
38924
|
statSync as statSync17,
|
|
38932
38925
|
unlinkSync as unlinkSync22,
|
|
@@ -39047,7 +39040,7 @@ function withJoinCredentialLock(operation) {
|
|
|
39047
39040
|
}
|
|
39048
39041
|
const stalePath = `${lockPath}.stale.${process.pid}.${randomUUID28()}`;
|
|
39049
39042
|
try {
|
|
39050
|
-
|
|
39043
|
+
renameSync14(lockPath, stalePath);
|
|
39051
39044
|
rmSync9(stalePath, { recursive: true, force: true });
|
|
39052
39045
|
} catch (staleError) {
|
|
39053
39046
|
if (staleError.code !== "ENOENT")
|
|
@@ -39145,7 +39138,7 @@ function saveJoinWhileLocked(join41, options = {}) {
|
|
|
39145
39138
|
closeSync4(fd);
|
|
39146
39139
|
fd = undefined;
|
|
39147
39140
|
if (options.replaceExisting) {
|
|
39148
|
-
|
|
39141
|
+
renameSync14(temporaryPath, path);
|
|
39149
39142
|
} else {
|
|
39150
39143
|
linkSync(temporaryPath, path);
|
|
39151
39144
|
unlinkSync22(temporaryPath);
|
|
@@ -41931,7 +41924,7 @@ import {
|
|
|
41931
41924
|
mkdirSync as mkdirSync34,
|
|
41932
41925
|
openSync as openSync5,
|
|
41933
41926
|
readFileSync as readFileSync26,
|
|
41934
|
-
renameSync as
|
|
41927
|
+
renameSync as renameSync15,
|
|
41935
41928
|
unlinkSync as unlinkSync23,
|
|
41936
41929
|
writeFileSync as writeFileSync24
|
|
41937
41930
|
} from "fs";
|
|
@@ -42030,7 +42023,7 @@ function replacePendingEnrollment(pending2) {
|
|
|
42030
42023
|
fsyncSync3(fd);
|
|
42031
42024
|
closeSync5(fd);
|
|
42032
42025
|
fd = undefined;
|
|
42033
|
-
|
|
42026
|
+
renameSync15(temporaryPath, path);
|
|
42034
42027
|
const directoryFd = openSync5(directory, "r");
|
|
42035
42028
|
try {
|
|
42036
42029
|
fsyncSync3(directoryFd);
|
|
@@ -43657,6 +43650,476 @@ var init_init = __esm(async () => {
|
|
|
43657
43650
|
await init_src();
|
|
43658
43651
|
});
|
|
43659
43652
|
|
|
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 assertNoCollisions(operations) {
|
|
43730
|
+
const destinations = new Set;
|
|
43731
|
+
for (const operation of operations) {
|
|
43732
|
+
if (!operation.destination)
|
|
43733
|
+
continue;
|
|
43734
|
+
if (existsSync36(operation.destination)) {
|
|
43735
|
+
throw new Error(`Migration collision at ${operation.destination}.`);
|
|
43736
|
+
}
|
|
43737
|
+
if (destinations.has(operation.destination)) {
|
|
43738
|
+
throw new Error(`Multiple legacy paths target ${operation.destination}.`);
|
|
43739
|
+
}
|
|
43740
|
+
destinations.add(operation.destination);
|
|
43741
|
+
}
|
|
43742
|
+
}
|
|
43743
|
+
function writeJournal(path, journal) {
|
|
43744
|
+
writeFileSync25(path, `${JSON.stringify(journal, null, 2)}
|
|
43745
|
+
`, { mode: 384 });
|
|
43746
|
+
}
|
|
43747
|
+
function rollbackFilesystem(journal, journalPath) {
|
|
43748
|
+
for (const operation of [...journal.operations].reverse()) {
|
|
43749
|
+
const current3 = operation.state === "placed" ? operation.destination : operation.staged;
|
|
43750
|
+
if (!current3 || !existsSync36(current3) || existsSync36(operation.source))
|
|
43751
|
+
continue;
|
|
43752
|
+
mkdirSync35(dirname23(operation.source), { recursive: true });
|
|
43753
|
+
renameSync16(current3, operation.source);
|
|
43754
|
+
operation.state = "pending";
|
|
43755
|
+
}
|
|
43756
|
+
journal.phase = "filesystem";
|
|
43757
|
+
writeJournal(journalPath, journal);
|
|
43758
|
+
}
|
|
43759
|
+
function tablesWithColumn(database, columnName) {
|
|
43760
|
+
const tables = database.query("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'").all();
|
|
43761
|
+
return tables.map((row) => row.name).filter((table) => database.query(`PRAGMA table_info("${table.replaceAll('"', '""')}")`).all().some((column) => column.name === columnName));
|
|
43762
|
+
}
|
|
43763
|
+
function selectedTopicIds(dbPath, source) {
|
|
43764
|
+
if (!existsSync36(dbPath))
|
|
43765
|
+
return null;
|
|
43766
|
+
const database = new Database(dbPath, { readonly: true });
|
|
43767
|
+
try {
|
|
43768
|
+
const hasMemberships = database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='topic_members'").get();
|
|
43769
|
+
if (!hasMemberships)
|
|
43770
|
+
return null;
|
|
43771
|
+
return new Set(database.query("SELECT topic_id FROM topic_members WHERE user_id = ?").all(source).map((row) => row.topic_id));
|
|
43772
|
+
} finally {
|
|
43773
|
+
database.close();
|
|
43774
|
+
}
|
|
43775
|
+
}
|
|
43776
|
+
function migrateDatabase(dbPath, source, masterKey, legacyTopicProfiles = []) {
|
|
43777
|
+
if (!existsSync36(dbPath))
|
|
43778
|
+
return [];
|
|
43779
|
+
const database = new Database(dbPath);
|
|
43780
|
+
const userTables = tablesWithColumn(database, "user_id");
|
|
43781
|
+
const ownerUserTables = tablesWithColumn(database, "owner_user_id");
|
|
43782
|
+
const migratedTables = [...new Set([...userTables, ...ownerUserTables])];
|
|
43783
|
+
const retainedTopicIds = selectedTopicIds(dbPath, source);
|
|
43784
|
+
const quote = (name) => `"${name.replaceAll('"', '""')}"`;
|
|
43785
|
+
try {
|
|
43786
|
+
if (source !== CANONICAL_LOCAL_USER_ID) {
|
|
43787
|
+
for (const [column, tables] of [
|
|
43788
|
+
["user_id", userTables],
|
|
43789
|
+
["owner_user_id", ownerUserTables]
|
|
43790
|
+
]) {
|
|
43791
|
+
for (const table of tables) {
|
|
43792
|
+
const collision = database.query(`SELECT COUNT(*) AS count FROM ${quote(table)} WHERE ${column} = ?`).get(CANONICAL_LOCAL_USER_ID)?.count;
|
|
43793
|
+
if (collision)
|
|
43794
|
+
throw new Error(`Database collision: ${table}.${column} already contains local rows.`);
|
|
43795
|
+
}
|
|
43796
|
+
}
|
|
43797
|
+
const hasUsers = database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='users'").get();
|
|
43798
|
+
if (hasUsers) {
|
|
43799
|
+
const localUser = database.query("SELECT 1 FROM users WHERE id = ?").get(CANONICAL_LOCAL_USER_ID);
|
|
43800
|
+
if (localUser)
|
|
43801
|
+
throw new Error("Database collision: users already contains canonical local.");
|
|
43802
|
+
}
|
|
43803
|
+
}
|
|
43804
|
+
database.exec("PRAGMA foreign_keys = OFF");
|
|
43805
|
+
database.exec("BEGIN IMMEDIATE");
|
|
43806
|
+
for (const table of userTables) {
|
|
43807
|
+
database.query(`DELETE FROM ${quote(table)} WHERE user_id <> ?`).run(source);
|
|
43808
|
+
if (table === "vault" && source !== CANONICAL_LOCAL_USER_ID) {
|
|
43809
|
+
if (!masterKey)
|
|
43810
|
+
throw new Error("Cannot migrate encrypted vault rows without vault-master-key.");
|
|
43811
|
+
const rows = database.query("SELECT key, value FROM vault WHERE user_id = ?").all(source);
|
|
43812
|
+
for (const row of rows) {
|
|
43813
|
+
const plaintext = decryptVaultValueWithKey(source, row.key, row.value, masterKey).value;
|
|
43814
|
+
database.query("UPDATE vault SET value = ? WHERE user_id = ? AND key = ?").run(encryptVaultValueWithKey(CANONICAL_LOCAL_USER_ID, row.key, plaintext, masterKey), source, row.key);
|
|
43815
|
+
}
|
|
43816
|
+
}
|
|
43817
|
+
database.query(`UPDATE ${quote(table)} SET user_id = ? WHERE user_id = ?`).run(CANONICAL_LOCAL_USER_ID, source);
|
|
43818
|
+
}
|
|
43819
|
+
for (const table of ownerUserTables) {
|
|
43820
|
+
database.query(`DELETE FROM ${quote(table)} WHERE owner_user_id <> ?`).run(source);
|
|
43821
|
+
database.query(`UPDATE ${quote(table)} SET owner_user_id = ? WHERE owner_user_id = ?`).run(CANONICAL_LOCAL_USER_ID, source);
|
|
43822
|
+
}
|
|
43823
|
+
if (retainedTopicIds) {
|
|
43824
|
+
database.exec("CREATE TEMP TABLE migration_selected_topics (id TEXT PRIMARY KEY)");
|
|
43825
|
+
for (const topicId of retainedTopicIds) {
|
|
43826
|
+
database.query("INSERT INTO migration_selected_topics (id) VALUES (?)").run(topicId);
|
|
43827
|
+
}
|
|
43828
|
+
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"));
|
|
43829
|
+
for (const table of topicTables) {
|
|
43830
|
+
database.query(`DELETE FROM ${quote(table)} WHERE topic_id NOT IN (SELECT id FROM migration_selected_topics)`).run();
|
|
43831
|
+
}
|
|
43832
|
+
if (database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='api_topics'").get()) {
|
|
43833
|
+
database.query("DELETE FROM api_topics WHERE id NOT IN (SELECT id FROM migration_selected_topics)").run();
|
|
43834
|
+
}
|
|
43835
|
+
}
|
|
43836
|
+
if (database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='browser_profiles'").get()) {
|
|
43837
|
+
database.query("DELETE FROM browser_profiles WHERE owner_id <> ?").run(source);
|
|
43838
|
+
database.query("UPDATE browser_profiles SET owner_id = ? WHERE owner_id = ?").run(CANONICAL_LOCAL_USER_ID, source);
|
|
43839
|
+
}
|
|
43840
|
+
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")) {
|
|
43841
|
+
database.query("UPDATE api_topics SET browser_profile_owner = ? WHERE browser_profile_owner = ?").run(CANONICAL_LOCAL_USER_ID, source);
|
|
43842
|
+
if (retainedTopicIds) {
|
|
43843
|
+
database.query("UPDATE api_topics SET browser_profile_owner = ? WHERE browser_profile_owner IS NOT NULL").run(CANONICAL_LOCAL_USER_ID);
|
|
43844
|
+
} else {
|
|
43845
|
+
database.query("DELETE FROM api_topics WHERE browser_profile_owner IS NOT NULL AND browser_profile_owner <> ?").run(CANONICAL_LOCAL_USER_ID);
|
|
43846
|
+
}
|
|
43847
|
+
for (const binding of legacyTopicProfiles) {
|
|
43848
|
+
database.query("UPDATE api_topics SET browser_profile = ?, browser_profile_owner = ? WHERE id = ?").run(binding.profile, CANONICAL_LOCAL_USER_ID, binding.topicId);
|
|
43849
|
+
}
|
|
43850
|
+
}
|
|
43851
|
+
if (database.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='users'").get()) {
|
|
43852
|
+
database.query("DELETE FROM users WHERE id <> ?").run(source);
|
|
43853
|
+
database.query("UPDATE users SET id = ? WHERE id = ?").run(CANONICAL_LOCAL_USER_ID, source);
|
|
43854
|
+
}
|
|
43855
|
+
database.exec("COMMIT");
|
|
43856
|
+
database.exec("PRAGMA foreign_keys = ON");
|
|
43857
|
+
const fkErrors = database.query("PRAGMA foreign_key_check").all();
|
|
43858
|
+
if (fkErrors.length > 0)
|
|
43859
|
+
throw new Error("Database migration left foreign-key violations.");
|
|
43860
|
+
return migratedTables;
|
|
43861
|
+
} catch (error2) {
|
|
43862
|
+
try {
|
|
43863
|
+
database.exec("ROLLBACK");
|
|
43864
|
+
} catch {}
|
|
43865
|
+
throw error2;
|
|
43866
|
+
} finally {
|
|
43867
|
+
database.close();
|
|
43868
|
+
}
|
|
43869
|
+
}
|
|
43870
|
+
function migrateSingleUserState(options) {
|
|
43871
|
+
const stateDir2 = resolve25(options.stateDir ?? process.env.NEGOTIUM_STATE_DIR ?? join42(homedir12(), ".negotium"));
|
|
43872
|
+
const source = options.sourcePrincipal?.trim() || CANONICAL_LOCAL_USER_ID;
|
|
43873
|
+
if (!source || /[/\\]|\.\./.test(source))
|
|
43874
|
+
throw new Error("Invalid source principal.");
|
|
43875
|
+
if (!options.deleteOtherUsers || !options.confirmed) {
|
|
43876
|
+
throw new Error("Migration requires --delete-other-users and --yes; other principals are permanently deleted.");
|
|
43877
|
+
}
|
|
43878
|
+
const markerPath = join42(stateDir2, ".migration-0.2.0-single-user.json");
|
|
43879
|
+
if (existsSync36(markerPath)) {
|
|
43880
|
+
const marker = JSON.parse(readFileSync27(markerPath, "utf8"));
|
|
43881
|
+
if (marker.id !== SINGLE_USER_MIGRATION_ID)
|
|
43882
|
+
throw new Error(`Unexpected migration marker at ${markerPath}.`);
|
|
43883
|
+
return {
|
|
43884
|
+
status: "already-completed",
|
|
43885
|
+
markerPath,
|
|
43886
|
+
sourcePrincipal: marker.sourcePrincipal ?? source,
|
|
43887
|
+
movedPaths: marker.movedPaths ?? 0,
|
|
43888
|
+
deletedPaths: marker.deletedPaths ?? 0,
|
|
43889
|
+
migratedTables: marker.migratedTables ?? []
|
|
43890
|
+
};
|
|
43891
|
+
}
|
|
43892
|
+
assertNoActiveNode(stateDir2);
|
|
43893
|
+
mkdirSync35(stateDir2, { recursive: true });
|
|
43894
|
+
const stagingRoot = join42(stateDir2, ".migration-0.2.0-staging");
|
|
43895
|
+
const journalPath = join42(stagingRoot, "journal.json");
|
|
43896
|
+
mkdirSync35(stagingRoot, { recursive: true, mode: 448 });
|
|
43897
|
+
let journal;
|
|
43898
|
+
if (existsSync36(journalPath)) {
|
|
43899
|
+
journal = JSON.parse(readFileSync27(journalPath, "utf8"));
|
|
43900
|
+
if (journal.sourcePrincipal !== source)
|
|
43901
|
+
throw new Error("Interrupted migration used a different source principal.");
|
|
43902
|
+
} else {
|
|
43903
|
+
const operations = [];
|
|
43904
|
+
const retainedTopicIds = selectedTopicIds(join42(stateDir2, "data", "sessions.db"), source);
|
|
43905
|
+
addDirectoryContents(operations, join42(stateDir2, "run"), join42(stateDir2, "runtime"), stagingRoot);
|
|
43906
|
+
addDirectoryContents(operations, join42(stateDir2, "bin"), join42(stateDir2, "binaries"), stagingRoot);
|
|
43907
|
+
for (const secret of ["node-control-token", "runtime-mcp-secret", "vault-master-key"]) {
|
|
43908
|
+
const sourcePath = join42(stateDir2, secret);
|
|
43909
|
+
if (existsSync36(sourcePath))
|
|
43910
|
+
operations.push({
|
|
43911
|
+
source: sourcePath,
|
|
43912
|
+
staged: join42(stagingRoot, randomUUID34()),
|
|
43913
|
+
destination: join42(stateDir2, "secrets", secret),
|
|
43914
|
+
state: "pending"
|
|
43915
|
+
});
|
|
43916
|
+
}
|
|
43917
|
+
const legacyVaultDb = join42(stateDir2, "data", "vault.db");
|
|
43918
|
+
if (existsSync36(legacyVaultDb)) {
|
|
43919
|
+
operations.push({
|
|
43920
|
+
source: legacyVaultDb,
|
|
43921
|
+
staged: join42(stagingRoot, randomUUID34()),
|
|
43922
|
+
destination: join42(stateDir2, "data", "vault", "vault.db"),
|
|
43923
|
+
state: "pending"
|
|
43924
|
+
});
|
|
43925
|
+
}
|
|
43926
|
+
for (const store of ["conversations", "tasks", "users"]) {
|
|
43927
|
+
const root = join42(stateDir2, "data", store);
|
|
43928
|
+
addDirectoryContents(operations, join42(root, source), root, stagingRoot);
|
|
43929
|
+
for (const owner of entries(root)) {
|
|
43930
|
+
const ownerPath = join42(root, owner);
|
|
43931
|
+
if (owner !== source && statSync19(ownerPath).isDirectory()) {
|
|
43932
|
+
operations.push({
|
|
43933
|
+
source: ownerPath,
|
|
43934
|
+
staged: join42(stagingRoot, randomUUID34()),
|
|
43935
|
+
state: "pending"
|
|
43936
|
+
});
|
|
43937
|
+
}
|
|
43938
|
+
}
|
|
43939
|
+
}
|
|
43940
|
+
for (const legacyWorkspaceDir of ["contexts", "dm", "sessions"]) {
|
|
43941
|
+
addDirectoryContents(operations, join42(stateDir2, "workspace", legacyWorkspaceDir), join42(stateDir2, "data", legacyWorkspaceDir), stagingRoot);
|
|
43942
|
+
}
|
|
43943
|
+
for (const topicId of entries(join42(stateDir2, "workspace", "topics"))) {
|
|
43944
|
+
const topicPath = join42(stateDir2, "workspace", "topics", topicId);
|
|
43945
|
+
if (retainedTopicIds && !retainedTopicIds.has(topicId)) {
|
|
43946
|
+
operations.push({
|
|
43947
|
+
source: topicPath,
|
|
43948
|
+
staged: join42(stagingRoot, randomUUID34()),
|
|
43949
|
+
state: "pending"
|
|
43950
|
+
});
|
|
43951
|
+
} else {
|
|
43952
|
+
addDirectoryContents(operations, join42(topicPath, "uploads"), join42(stateDir2, "data", "uploads", topicId), stagingRoot);
|
|
43953
|
+
}
|
|
43954
|
+
}
|
|
43955
|
+
if (retainedTopicIds) {
|
|
43956
|
+
for (const topicId of entries(join42(stateDir2, "workspace", "wiki"))) {
|
|
43957
|
+
if (retainedTopicIds.has(topicId))
|
|
43958
|
+
continue;
|
|
43959
|
+
operations.push({
|
|
43960
|
+
source: join42(stateDir2, "workspace", "wiki", topicId),
|
|
43961
|
+
staged: join42(stagingRoot, randomUUID34()),
|
|
43962
|
+
state: "pending"
|
|
43963
|
+
});
|
|
43964
|
+
}
|
|
43965
|
+
}
|
|
43966
|
+
const legacyBrowserRoot = join42(stateDir2, "workspace", "browser-profiles");
|
|
43967
|
+
const selectedProfiles = join42(legacyBrowserRoot, "profiles", oldOwnerDirectory(source));
|
|
43968
|
+
addDirectoryContents(operations, selectedProfiles, join42(stateDir2, "browser", "profiles"), stagingRoot);
|
|
43969
|
+
for (const owner of entries(join42(legacyBrowserRoot, "profiles"))) {
|
|
43970
|
+
const ownerPath = join42(legacyBrowserRoot, "profiles", owner);
|
|
43971
|
+
if (ownerPath !== selectedProfiles) {
|
|
43972
|
+
operations.push({
|
|
43973
|
+
source: ownerPath,
|
|
43974
|
+
staged: join42(stagingRoot, randomUUID34()),
|
|
43975
|
+
state: "pending"
|
|
43976
|
+
});
|
|
43977
|
+
}
|
|
43978
|
+
}
|
|
43979
|
+
for (const topicId of entries(legacyBrowserRoot).filter((name) => name !== "profiles")) {
|
|
43980
|
+
if (retainedTopicIds && !retainedTopicIds.has(topicId)) {
|
|
43981
|
+
operations.push({
|
|
43982
|
+
source: join42(legacyBrowserRoot, topicId),
|
|
43983
|
+
staged: join42(stagingRoot, randomUUID34()),
|
|
43984
|
+
state: "pending"
|
|
43985
|
+
});
|
|
43986
|
+
continue;
|
|
43987
|
+
}
|
|
43988
|
+
const profile = `legacy_${createHash11("sha256").update(topicId).digest("hex").slice(0, 12)}`;
|
|
43989
|
+
operations.push({
|
|
43990
|
+
source: join42(legacyBrowserRoot, topicId),
|
|
43991
|
+
staged: join42(stagingRoot, randomUUID34()),
|
|
43992
|
+
destination: join42(stateDir2, "browser", "profiles", profile),
|
|
43993
|
+
state: "pending"
|
|
43994
|
+
});
|
|
43995
|
+
}
|
|
43996
|
+
assertNoCollisions(operations);
|
|
43997
|
+
journal = {
|
|
43998
|
+
id: SINGLE_USER_MIGRATION_ID,
|
|
43999
|
+
sourcePrincipal: source,
|
|
44000
|
+
createdAt: new Date().toISOString(),
|
|
44001
|
+
phase: "filesystem",
|
|
44002
|
+
operations
|
|
44003
|
+
};
|
|
44004
|
+
writeJournal(journalPath, journal);
|
|
44005
|
+
}
|
|
44006
|
+
const dbPath = join42(stateDir2, "data", "sessions.db");
|
|
44007
|
+
const dbBackup = join42(stagingRoot, "sessions.db.rollback");
|
|
44008
|
+
const vaultDbPath = join42(stateDir2, "data", "vault", "vault.db");
|
|
44009
|
+
const vaultDbBackup = join42(stagingRoot, "vault.db.rollback");
|
|
44010
|
+
try {
|
|
44011
|
+
for (const operation of journal.operations) {
|
|
44012
|
+
if (operation.state === "pending" && !existsSync36(operation.source) && existsSync36(operation.staged)) {
|
|
44013
|
+
operation.state = "staged";
|
|
44014
|
+
}
|
|
44015
|
+
if (operation.state === "staged" && operation.destination && !existsSync36(operation.staged) && existsSync36(operation.destination)) {
|
|
44016
|
+
operation.state = "placed";
|
|
44017
|
+
}
|
|
44018
|
+
if (operation.state === "pending") {
|
|
44019
|
+
mkdirSync35(dirname23(operation.staged), { recursive: true });
|
|
44020
|
+
renameSync16(operation.source, operation.staged);
|
|
44021
|
+
operation.state = "staged";
|
|
44022
|
+
writeJournal(journalPath, journal);
|
|
44023
|
+
}
|
|
44024
|
+
if (operation.state === "staged" && operation.destination) {
|
|
44025
|
+
mkdirSync35(dirname23(operation.destination), { recursive: true });
|
|
44026
|
+
renameSync16(operation.staged, operation.destination);
|
|
44027
|
+
operation.state = "placed";
|
|
44028
|
+
writeJournal(journalPath, journal);
|
|
44029
|
+
}
|
|
44030
|
+
}
|
|
44031
|
+
journal.phase = "database";
|
|
44032
|
+
writeJournal(journalPath, journal);
|
|
44033
|
+
if (existsSync36(dbPath) && !existsSync36(dbBackup))
|
|
44034
|
+
copyFileSync6(dbPath, dbBackup);
|
|
44035
|
+
if (existsSync36(vaultDbPath) && !existsSync36(vaultDbBackup))
|
|
44036
|
+
copyFileSync6(vaultDbPath, vaultDbBackup);
|
|
44037
|
+
const masterKeyPath = join42(stateDir2, "secrets", "vault-master-key");
|
|
44038
|
+
const masterKey = existsSync36(masterKeyPath) ? readFileSync27(masterKeyPath, "utf8").trim() : undefined;
|
|
44039
|
+
const legacyBrowserRoot = join42(stateDir2, "workspace", "browser-profiles");
|
|
44040
|
+
const legacyTopicProfiles = journal.operations.filter((operation) => dirname23(operation.source) === legacyBrowserRoot && operation.destination).map((operation) => ({
|
|
44041
|
+
topicId: basename14(operation.source),
|
|
44042
|
+
profile: basename14(operation.destination)
|
|
44043
|
+
}));
|
|
44044
|
+
const migratedTables = migrateDatabase(dbPath, source, masterKey, legacyTopicProfiles);
|
|
44045
|
+
const migratedVaultTables = migrateDatabase(vaultDbPath, source, masterKey);
|
|
44046
|
+
for (const table of migratedVaultTables)
|
|
44047
|
+
if (!migratedTables.includes(table))
|
|
44048
|
+
migratedTables.push(table);
|
|
44049
|
+
mkdirSync35(join42(stateDir2, "secrets"), { recursive: true, mode: 448 });
|
|
44050
|
+
chmodSync8(join42(stateDir2, "secrets"), 448);
|
|
44051
|
+
for (const secret of ["node-control-token", "runtime-mcp-secret", "vault-master-key"]) {
|
|
44052
|
+
const path = join42(stateDir2, "secrets", secret);
|
|
44053
|
+
if (existsSync36(path))
|
|
44054
|
+
chmodSync8(path, 384);
|
|
44055
|
+
}
|
|
44056
|
+
const deletedPaths = journal.operations.filter((operation) => !operation.destination).length;
|
|
44057
|
+
const movedPaths = journal.operations.length - deletedPaths;
|
|
44058
|
+
const marker = {
|
|
44059
|
+
id: SINGLE_USER_MIGRATION_ID,
|
|
44060
|
+
version: "0.2.0",
|
|
44061
|
+
completedAt: new Date().toISOString(),
|
|
44062
|
+
sourcePrincipal: source,
|
|
44063
|
+
canonicalPrincipal: CANONICAL_LOCAL_USER_ID,
|
|
44064
|
+
movedPaths,
|
|
44065
|
+
deletedPaths,
|
|
44066
|
+
migratedTables
|
|
44067
|
+
};
|
|
44068
|
+
for (const store of ["conversations", "tasks", "users"]) {
|
|
44069
|
+
rmSync11(join42(stateDir2, "data", store, source), { recursive: true, force: true });
|
|
44070
|
+
}
|
|
44071
|
+
rmSync11(join42(stateDir2, "workspace", "browser-profiles"), { recursive: true, force: true });
|
|
44072
|
+
writeFileSync25(markerPath, `${JSON.stringify(marker, null, 2)}
|
|
44073
|
+
`, { mode: 384, flag: "wx" });
|
|
44074
|
+
journal.phase = "complete";
|
|
44075
|
+
rmSync11(stagingRoot, { recursive: true, force: true });
|
|
44076
|
+
return {
|
|
44077
|
+
status: "completed",
|
|
44078
|
+
markerPath,
|
|
44079
|
+
sourcePrincipal: source,
|
|
44080
|
+
movedPaths,
|
|
44081
|
+
deletedPaths,
|
|
44082
|
+
migratedTables
|
|
44083
|
+
};
|
|
44084
|
+
} catch (error2) {
|
|
44085
|
+
if (existsSync36(dbBackup))
|
|
44086
|
+
copyFileSync6(dbBackup, dbPath);
|
|
44087
|
+
if (existsSync36(vaultDbBackup))
|
|
44088
|
+
copyFileSync6(vaultDbBackup, vaultDbPath);
|
|
44089
|
+
rollbackFilesystem(journal, journalPath);
|
|
44090
|
+
throw error2;
|
|
44091
|
+
}
|
|
44092
|
+
}
|
|
44093
|
+
var CANONICAL_LOCAL_USER_ID = "local", SINGLE_USER_MIGRATION_ID = "negotium-0.2.0-single-user";
|
|
44094
|
+
var init_single_user = __esm(async () => {
|
|
44095
|
+
init_vault_crypto_core();
|
|
44096
|
+
await init_sqlite();
|
|
44097
|
+
});
|
|
44098
|
+
|
|
44099
|
+
// ../cli/src/commands/migrate.ts
|
|
44100
|
+
var exports_migrate = {};
|
|
44101
|
+
__export(exports_migrate, {
|
|
44102
|
+
migrateCommand: () => migrateCommand
|
|
44103
|
+
});
|
|
44104
|
+
function option3(args, name) {
|
|
44105
|
+
const prefix = `--${name}=`;
|
|
44106
|
+
return args.find((arg) => arg.startsWith(prefix))?.slice(prefix.length);
|
|
44107
|
+
}
|
|
44108
|
+
function migrateCommand(args) {
|
|
44109
|
+
if (args[0] !== "single-user") {
|
|
44110
|
+
throw new Error("usage: negotium migrate single-user [--source=local] --delete-other-users --yes");
|
|
44111
|
+
}
|
|
44112
|
+
const result = migrateSingleUserState({
|
|
44113
|
+
sourcePrincipal: option3(args, "source"),
|
|
44114
|
+
deleteOtherUsers: args.includes("--delete-other-users"),
|
|
44115
|
+
confirmed: args.includes("--yes")
|
|
44116
|
+
});
|
|
44117
|
+
console.log(`${result.status}: ${result.markerPath}`);
|
|
44118
|
+
}
|
|
44119
|
+
var init_migrate = __esm(async () => {
|
|
44120
|
+
await init_single_user();
|
|
44121
|
+
});
|
|
44122
|
+
|
|
43660
44123
|
// ../cli/src/commands/topics.ts
|
|
43661
44124
|
var exports_topics = {};
|
|
43662
44125
|
__export(exports_topics, {
|
|
@@ -43758,12 +44221,12 @@ function vaultCommand(args) {
|
|
|
43758
44221
|
switch (sub) {
|
|
43759
44222
|
case undefined:
|
|
43760
44223
|
case "list": {
|
|
43761
|
-
const
|
|
43762
|
-
if (
|
|
44224
|
+
const entries2 = vaultListWithValues(DEFAULT_USER);
|
|
44225
|
+
if (entries2.length === 0) {
|
|
43763
44226
|
console.log("vault is empty \u2014 `negotium vault set MY_KEY <value> [description]`");
|
|
43764
44227
|
return;
|
|
43765
44228
|
}
|
|
43766
|
-
for (const entry of
|
|
44229
|
+
for (const entry of entries2) {
|
|
43767
44230
|
console.log(`${entry.key} ${entry.description || ""}`.trimEnd());
|
|
43768
44231
|
}
|
|
43769
44232
|
return;
|
|
@@ -44087,6 +44550,12 @@ var CLI_COMMANDS = [
|
|
|
44087
44550
|
description: "bootstrap ~/.negotium and check agent auth",
|
|
44088
44551
|
group: "Setup"
|
|
44089
44552
|
},
|
|
44553
|
+
{
|
|
44554
|
+
name: "migrate",
|
|
44555
|
+
usage: "migrate single-user [--source=local] --delete-other-users --yes",
|
|
44556
|
+
description: "explicitly migrate a 0.1 state tree to the 0.2 single-user layout",
|
|
44557
|
+
group: "Setup"
|
|
44558
|
+
},
|
|
44090
44559
|
{
|
|
44091
44560
|
name: "serve",
|
|
44092
44561
|
usage: "serve [otium]",
|
|
@@ -44193,7 +44662,7 @@ async function runCanonicalNode(port) {
|
|
|
44193
44662
|
});
|
|
44194
44663
|
console.log(`negotium node listening on 127.0.0.1:${node.port} (ctrl-c to stop)`);
|
|
44195
44664
|
await node.completed;
|
|
44196
|
-
await new Promise((
|
|
44665
|
+
await new Promise((resolve26) => setImmediate(resolve26));
|
|
44197
44666
|
process.exit(0);
|
|
44198
44667
|
}
|
|
44199
44668
|
async function stopAdapter(name) {
|
|
@@ -44216,6 +44685,11 @@ switch (command) {
|
|
|
44216
44685
|
initCommand2();
|
|
44217
44686
|
break;
|
|
44218
44687
|
}
|
|
44688
|
+
case "migrate": {
|
|
44689
|
+
const { migrateCommand: migrateCommand2 } = await init_migrate().then(() => exports_migrate);
|
|
44690
|
+
migrateCommand2(args);
|
|
44691
|
+
break;
|
|
44692
|
+
}
|
|
44219
44693
|
case "-v":
|
|
44220
44694
|
case "--version": {
|
|
44221
44695
|
const { NEGOTIUM_VERSION: NEGOTIUM_VERSION2 } = await Promise.resolve().then(() => exports_version);
|
|
@@ -44324,4 +44798,4 @@ switch (command) {
|
|
|
44324
44798
|
}
|
|
44325
44799
|
}
|
|
44326
44800
|
|
|
44327
|
-
//# debugId=
|
|
44801
|
+
//# debugId=9371DDB5367979FC64756E2164756E21
|