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.
Files changed (55) hide show
  1. package/README.md +1 -1
  2. package/dist/agent-helpers.js +72 -78
  3. package/dist/agent-helpers.js.map +18 -17
  4. package/dist/background-bash.js +22 -10
  5. package/dist/background-bash.js.map +3 -3
  6. package/dist/browser-runtime.js +47 -72
  7. package/dist/browser-runtime.js.map +10 -9
  8. package/dist/{chunk-5rpw9d1f.js → chunk-kc5kmr95.js} +28 -11
  9. package/dist/{chunk-5rpw9d1f.js.map → chunk-kc5kmr95.js.map} +4 -4
  10. package/dist/hosted-agent.js +48 -22
  11. package/dist/hosted-agent.js.map +10 -9
  12. package/dist/main.js +576 -102
  13. package/dist/main.js.map +23 -20
  14. package/dist/mcp-factories.js +76 -82
  15. package/dist/mcp-factories.js.map +19 -18
  16. package/dist/prompts.js +22 -10
  17. package/dist/prompts.js.map +3 -3
  18. package/dist/query-runtime.js +22 -10
  19. package/dist/query-runtime.js.map +4 -4
  20. package/dist/registry.js +5 -12
  21. package/dist/registry.js.map +5 -5
  22. package/dist/rollout.js +1 -1
  23. package/dist/runtime/cron/mcp-server.ts +1 -1
  24. package/dist/runtime/src/agents/maestro-registry.ts +1 -1
  25. package/dist/runtime/src/agents/rollout/shared.ts +12 -4
  26. package/dist/runtime/src/mcp/mcp-helpers.ts +1 -1
  27. package/dist/runtime/src/mcp/wiki-server.ts +1 -1
  28. package/dist/runtime/src/migration/single-user.ts +621 -0
  29. package/dist/runtime/src/platform/config.ts +24 -11
  30. package/dist/runtime/src/platform/mcp-config.ts +4 -4
  31. package/dist/runtime/src/platform/playwright/manager.ts +10 -28
  32. package/dist/runtime/src/runtime/attachments.ts +3 -3
  33. package/dist/runtime/src/storage/browser-profiles.ts +11 -9
  34. package/dist/runtime/src/storage/conversations.ts +5 -18
  35. package/dist/runtime/src/storage/storage-host.ts +1 -1
  36. package/dist/runtime/src/storage/tasks.ts +2 -14
  37. package/dist/runtime/src/storage/vault-crypto-core.ts +65 -0
  38. package/dist/runtime/src/storage/vault-crypto.ts +8 -48
  39. package/dist/runtime/src/storage/vault.ts +3 -2
  40. package/dist/runtime/src/version.ts +1 -1
  41. package/dist/runtime-helpers.js +22 -10
  42. package/dist/runtime-helpers.js.map +5 -5
  43. package/dist/storage.js +5 -19
  44. package/dist/storage.js.map +5 -5
  45. package/dist/types/packages/core/src/mcp/mcp-helpers.d.ts +1 -1
  46. package/dist/types/packages/core/src/platform/config.d.ts +9 -1
  47. package/dist/types/packages/core/src/runtime/attachments.d.ts +1 -1
  48. package/dist/types/packages/core/src/storage/conversations.d.ts +2 -2
  49. package/dist/types/packages/core/src/storage/vault-crypto-core.d.ts +6 -0
  50. package/dist/types/packages/core/src/storage/vault-crypto.d.ts +2 -1
  51. package/dist/types/packages/core/src/version.d.ts +1 -1
  52. package/dist/vault.js +37 -16
  53. package/dist/vault.js.map +7 -6
  54. package/install-browser-rs.mjs +1 -1
  55. package/package.json +2 -2
package/README.md CHANGED
@@ -296,7 +296,7 @@ const restoreStorageHost = configureStorageHost({
296
296
  database,
297
297
  dataDir: "/srv/otium/state/data",
298
298
  logDir: "/srv/otium/logs",
299
- sessionAsksDir: "/srv/otium/state/run/session-asks",
299
+ sessionAsksDir: "/srv/otium/state/runtime/session-asks",
300
300
  workspaceDir: "/srv/otium/state/workspace",
301
301
  sharedWikiDir: "/srv/otium/state/workspace/wiki",
302
302
  usersLogDir: "/srv/otium/state/data/users",
@@ -162,7 +162,7 @@ function resolveBrowserRsBin(envValue) {
162
162
  if (!override && !versionAtLeast(BROWSER_RS_VERSION.replace(/^v/, ""), BROWSER_RS_MIN_SECURE_VERSION)) {
163
163
  return;
164
164
  }
165
- const candidate = override ? resolve(override) : resolve(STATE_DIR, "bin", "browser-rs", BROWSER_RS_VERSION, "browser-rs");
165
+ const candidate = override ? resolve(override) : resolve(BINARIES_DIR, "browser-rs", BROWSER_RS_VERSION, "browser-rs");
166
166
  try {
167
167
  accessSync(candidate, constants.X_OK);
168
168
  return browserRsMeetsMinimumVersion(candidate) ? candidate : undefined;
@@ -174,7 +174,7 @@ function resolveBrowserMcpBin(envValue) {
174
174
  const override = envValue?.trim();
175
175
  if (override)
176
176
  return resolve(override);
177
- return BROWSER_RS_BIN ?? resolve(STATE_DIR, "bin", "browser-rs", BROWSER_RS_VERSION, "browser-rs");
177
+ return BROWSER_RS_BIN ?? resolve(BINARIES_DIR, "browser-rs", BROWSER_RS_VERSION, "browser-rs");
178
178
  }
179
179
  function resolveBrowserProxy() {
180
180
  const raw = envText("BROWSER_PROXY_URL");
@@ -206,7 +206,7 @@ function resolveTopicWorkspaceDir(topicId) {
206
206
  }
207
207
  function loadOrCreateLocalSecret(envKey, filename, options = {}) {
208
208
  const envValue = envText(envKey);
209
- const secretFile = resolve(STATE_DIR, filename);
209
+ const secretFile = resolve(SECRETS_DIR, filename);
210
210
  mkdirSync(dirname(secretFile), { recursive: true });
211
211
  if (envValue) {
212
212
  if (options.persistEnvValue) {
@@ -247,7 +247,7 @@ function resolveDefaultModel(agent, registryDefaultModel) {
247
247
  function codexAuthFilePath() {
248
248
  return process.env.NEGOTIUM_CODEX_AUTH_FILE || join(homedir(), ".codex", "auth.json");
249
249
  }
250
- var HOME, PROJECT_ROOT, STATE_DIR_ENV, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR, CONTEXTS_DIR, BROWSER_PROFILES_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, 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;
250
+ 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;
251
251
  var init_config = __esm(() => {
252
252
  init_config_helpers();
253
253
  init_logger();
@@ -259,10 +259,14 @@ var init_config = __esm(() => {
259
259
  WORKSPACE_DIR = resolveLocalStateDir("NEGOTIUM_WORKSPACE_DIR", "workspace");
260
260
  TOPIC_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "topics");
261
261
  SHARED_WIKI_DIR = resolve(WORKSPACE_DIR, "wiki");
262
- CONTEXTS_DIR = resolve(WORKSPACE_DIR, "contexts");
263
- BROWSER_PROFILES_DIR = resolve(WORKSPACE_DIR, "browser-profiles");
264
- DM_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "dm");
265
- SESSION_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "sessions");
262
+ CRON_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "cron");
263
+ BROWSER_DIR = resolveLocalStateDir("NEGOTIUM_BROWSER_DIR", "browser");
264
+ BROWSER_PROFILES_DIR = resolve(BROWSER_DIR, "profiles");
265
+ BINARIES_DIR = resolve(STATE_DIR, "binaries");
266
+ SECRETS_DIR = resolve(STATE_DIR, "secrets");
267
+ CONTEXTS_DIR = resolve(STATE_DIR, "data", "contexts");
268
+ DM_WORKSPACE_DIR = resolve(STATE_DIR, "data", "dm");
269
+ SESSION_WORKSPACE_DIR = resolve(STATE_DIR, "data", "sessions");
266
270
  CLAUDE_EXECUTABLE_ENV = envText("NEGOTIUM_CLAUDE_EXECUTABLE");
267
271
  CLAUDE_EXECUTABLE = CLAUDE_EXECUTABLE_ENV ? resolve(CLAUDE_EXECUTABLE_ENV) : undefined;
268
272
  BROWSER_RS_BIN = resolveBrowserRsBin(envText("NEGOTIUM_BROWSER_RS_BIN"));
@@ -291,10 +295,12 @@ var init_config = __esm(() => {
291
295
  hostname = process.env.HOSTNAME || "127.0.0.1";
292
296
  DATA_DIR = resolveLocalStateDir("NEGOTIUM_DATA_DIR", "data");
293
297
  LOG_DIR = resolveLocalStateDir("NEGOTIUM_LOG_DIR", "logs");
298
+ UPLOADS_DIR = resolve(DATA_DIR, "uploads");
299
+ VAULT_DIR = resolve(DATA_DIR, "vault");
294
300
  SESSIONS_DB = process.env.SESSIONS_DB_PATH ? resolve(process.env.SESSIONS_DB_PATH) : resolve(DATA_DIR, "sessions.db");
295
301
  DEBUG_FILE = resolve(DATA_DIR, "debug-users.json");
296
302
  USERS_LOG_DIR = resolve(DATA_DIR, "users");
297
- RUN_DIR = resolveLocalStateDir("NEGOTIUM_RUN_DIR", "run");
303
+ RUN_DIR = resolveLocalStateDir("NEGOTIUM_RUN_DIR", "runtime");
298
304
  PROGRESS_DIR = resolve(RUN_DIR, "progress");
299
305
  DM_CMD_DIR = resolve(RUN_DIR, "dm-commands");
300
306
  DM_RESP_DIR = resolve(RUN_DIR, "dm-responses");
@@ -305,6 +311,8 @@ var init_config = __esm(() => {
305
311
  PLAYWRIGHT_PORTS_DIR = resolve(RUN_DIR, "playwright-ports");
306
312
  mkdirSync(STATE_DIR, { recursive: true });
307
313
  mkdirSync(DATA_DIR, { recursive: true });
314
+ mkdirSync(UPLOADS_DIR, { recursive: true });
315
+ mkdirSync(VAULT_DIR, { recursive: true, mode: 448 });
308
316
  mkdirSync(LOG_DIR, { recursive: true });
309
317
  mkdirSync(PROGRESS_DIR, { recursive: true });
310
318
  mkdirSync(DM_CMD_DIR, { recursive: true });
@@ -315,10 +323,14 @@ var init_config = __esm(() => {
315
323
  mkdirSync(WORKSPACE_DIR, { recursive: true });
316
324
  mkdirSync(TOPIC_WORKSPACE_DIR, { recursive: true });
317
325
  mkdirSync(SHARED_WIKI_DIR, { recursive: true });
326
+ mkdirSync(CRON_WORKSPACE_DIR, { recursive: true });
318
327
  mkdirSync(CONTEXTS_DIR, { recursive: true });
319
- mkdirSync(BROWSER_PROFILES_DIR, { recursive: true });
320
328
  mkdirSync(DM_WORKSPACE_DIR, { recursive: true });
321
329
  mkdirSync(SESSION_WORKSPACE_DIR, { recursive: true });
330
+ mkdirSync(BROWSER_DIR, { recursive: true });
331
+ mkdirSync(BROWSER_PROFILES_DIR, { recursive: true });
332
+ mkdirSync(BINARIES_DIR, { recursive: true });
333
+ mkdirSync(SECRETS_DIR, { recursive: true, mode: 448 });
322
334
  ACTIVE_QUERY_STALE_MS = 10 * 60 * 1000;
323
335
  AGENTS_PROMPTS_DIR = resolve(PROJECT_ROOT, "src/prompts/agents");
324
336
  RESOURCES_DIR = resolve(PROJECT_ROOT, "src/resources");
@@ -498,7 +510,12 @@ var init_shared = __esm(() => {
498
510
  init_config();
499
511
  init_logger();
500
512
  __dirname2 = dirname2(fileURLToPath2(import.meta.url));
501
- trustedWorkspaceRoots = [WORKSPACE_DIR, DM_WORKSPACE_DIR, TOPIC_WORKSPACE_DIR].map((root) => resolve2(root));
513
+ trustedWorkspaceRoots = [
514
+ WORKSPACE_DIR,
515
+ DM_WORKSPACE_DIR,
516
+ SESSION_WORKSPACE_DIR,
517
+ TOPIC_WORKSPACE_DIR
518
+ ].map((root) => resolve2(root));
502
519
  FIXTURES_DIR = join2(__dirname2, "..", "fixtures");
503
520
  UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
504
521
  });
@@ -1450,7 +1467,7 @@ function defaultWorkspaceDir() {
1450
1467
  return envPath("NEGOTIUM_WORKSPACE_DIR", join6(defaultStateDir(), "workspace"));
1451
1468
  }
1452
1469
  function defaultSessionAsksDir() {
1453
- const runDir = envPath("NEGOTIUM_RUN_DIR", join6(defaultStateDir(), "run"));
1470
+ const runDir = envPath("NEGOTIUM_RUN_DIR", join6(defaultStateDir(), "runtime"));
1454
1471
  return join6(runDir, "session-asks");
1455
1472
  }
1456
1473
  function defaultSessionsDatabasePath() {
@@ -1556,15 +1573,8 @@ import {
1556
1573
  writeFileSync as writeFileSync4
1557
1574
  } from "fs";
1558
1575
  import { dirname as dirname6, join as join7 } from "path";
1559
- function safeUserIdComponent(userId) {
1560
- const str = String(userId);
1561
- if (!str || /[/\\]|\.\./.test(str)) {
1562
- throw new Error(`conversations: refusing unsafe userId path component: ${str}`);
1563
- }
1564
- return str;
1565
- }
1566
- function conversationDir(userId) {
1567
- return join7(resolveStorageDataDir(), "conversations", safeUserIdComponent(userId));
1576
+ function conversationDir(_userId) {
1577
+ return join7(resolveStorageDataDir(), "conversations");
1568
1578
  }
1569
1579
  function topicFilename(topicName) {
1570
1580
  const t = sanitizeTopicName(topicName, true);
@@ -1813,7 +1823,7 @@ function writeRollout(options) {
1813
1823
  version: 1,
1814
1824
  cwd: options.cwd,
1815
1825
  createdAt: existingCreatedAt(path) ?? new Date().toISOString(),
1816
- sdkVersion: "0.1.53"
1826
+ sdkVersion: "0.1.54"
1817
1827
  }
1818
1828
  },
1819
1829
  ...messages
@@ -1929,13 +1939,6 @@ var init_registry = __esm(async () => {
1929
1939
  // ../../packages/core/src/storage/tasks.ts
1930
1940
  import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync7, renameSync as renameSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
1931
1941
  import { dirname as dirname7, join as join10 } from "path";
1932
- function safeUserIdComponent2(userId) {
1933
- const str = String(userId);
1934
- if (!str || /[/\\]|\.\./.test(str)) {
1935
- throw new Error(`tasks: refusing unsafe userId path component: ${str}`);
1936
- }
1937
- return str;
1938
- }
1939
1942
  function safeTaskScopeKey(scopeKey) {
1940
1943
  const safe = sanitizeFileName(scopeKey);
1941
1944
  if (!safe || safe === "." || safe === "..") {
@@ -1947,7 +1950,7 @@ function taskScopeKey(opts) {
1947
1950
  return opts.topicId?.trim() || opts.session || "default";
1948
1951
  }
1949
1952
  function getTaskFilePath(userId, scopeKey) {
1950
- return join10(resolveStorageDataDir(), "tasks", safeUserIdComponent2(userId), `${safeTaskScopeKey(scopeKey)}.json`);
1953
+ return join10(resolveStorageDataDir(), "tasks", `${safeTaskScopeKey(scopeKey)}.json`);
1951
1954
  }
1952
1955
  function readTasks(userId, scopeKey) {
1953
1956
  const path = getTaskFilePath(userId, scopeKey);
@@ -2709,7 +2712,7 @@ function getMcpServersForQuery(opts) {
2709
2712
  if (!opts.topicId)
2710
2713
  throw new Error("getMcpServersForQuery: cron sessionType requires topicId");
2711
2714
  return getCronMcpServers({
2712
- userId: opts.userId || "default",
2715
+ userId: opts.userId || "local",
2713
2716
  session: opts.session || "cron",
2714
2717
  topicId: opts.topicId,
2715
2718
  queryId: opts.queryId,
@@ -2726,7 +2729,7 @@ function getMcpServersForQuery(opts) {
2726
2729
  }
2727
2730
  if (opts.sessionType === "dm" || opts.sessionType === "ephemeral") {
2728
2731
  return getDmMcpServers({
2729
- userId: opts.userId || "default",
2732
+ userId: opts.userId || "local",
2730
2733
  agent: opts.agent,
2731
2734
  playwrightPort: opts.playwrightPort,
2732
2735
  playwrightCapability: opts.playwrightCapability
@@ -2734,7 +2737,7 @@ function getMcpServersForQuery(opts) {
2734
2737
  }
2735
2738
  if (opts.sessionType === "manager") {
2736
2739
  return getManagerMcpServers({
2737
- userId: opts.userId || "default",
2740
+ userId: opts.userId || "local",
2738
2741
  session: opts.session,
2739
2742
  topicId: opts.topicId,
2740
2743
  queryId: opts.queryId,
@@ -2751,7 +2754,7 @@ function getMcpServersForQuery(opts) {
2751
2754
  });
2752
2755
  }
2753
2756
  return getForumMcpServers({
2754
- userId: opts.userId || "default",
2757
+ userId: opts.userId || "local",
2755
2758
  session: opts.session || "default",
2756
2759
  topicId: opts.topicId,
2757
2760
  subagentParentTopicId: opts.subagentParentTopicId,
@@ -2969,9 +2972,9 @@ var init_mcp_config = __esm(() => {
2969
2972
  nodeMcpEntries = [];
2970
2973
  });
2971
2974
 
2972
- // ../../packages/core/src/storage/vault-crypto.ts
2975
+ // ../../packages/core/src/storage/vault-crypto-core.ts
2973
2976
  import { createCipheriv, createDecipheriv, createHash, randomBytes as randomBytes4 } from "crypto";
2974
- function encryptionKey(masterKey = VAULT_MASTER_KEY) {
2977
+ function encryptionKey(masterKey) {
2975
2978
  return createHash("sha256").update("otium-vault-value-v1\x00", "utf8").update(masterKey, "utf8").digest().subarray(0, KEY_BYTES);
2976
2979
  }
2977
2980
  function aad(userId, key) {
@@ -2980,7 +2983,7 @@ function aad(userId, key) {
2980
2983
  function isEncryptedVaultValue(value) {
2981
2984
  return value.startsWith(ENVELOPE_PREFIX);
2982
2985
  }
2983
- function encryptVaultValue(userId, key, value, masterKey = VAULT_MASTER_KEY) {
2986
+ function encryptVaultValueWithKey(userId, key, value, masterKey) {
2984
2987
  const iv = randomBytes4(IV_BYTES);
2985
2988
  const cipher = createCipheriv("aes-256-gcm", encryptionKey(masterKey), iv);
2986
2989
  cipher.setAAD(aad(userId, key));
@@ -2988,7 +2991,7 @@ function encryptVaultValue(userId, key, value, masterKey = VAULT_MASTER_KEY) {
2988
2991
  const tag = cipher.getAuthTag();
2989
2992
  return `${ENVELOPE_PREFIX}${iv.toString("base64url")}.${ciphertext.toString("base64url")}.${tag.toString("base64url")}`;
2990
2993
  }
2991
- function decryptVaultValue(userId, key, storedValue, masterKey = VAULT_MASTER_KEY) {
2994
+ function decryptVaultValueWithKey(userId, key, storedValue, masterKey) {
2992
2995
  if (!isEncryptedVaultValue(storedValue)) {
2993
2996
  return { value: storedValue, legacyPlaintext: true };
2994
2997
  }
@@ -3010,8 +3013,18 @@ function decryptVaultValue(userId, key, storedValue, masterKey = VAULT_MASTER_KE
3010
3013
  return { value: plaintext.toString("utf8"), legacyPlaintext: false };
3011
3014
  }
3012
3015
  var ENVELOPE_PREFIX = "otium-vault:v1:", IV_BYTES = 12, KEY_BYTES = 32;
3016
+ var init_vault_crypto_core = () => {};
3017
+
3018
+ // ../../packages/core/src/storage/vault-crypto.ts
3019
+ function encryptVaultValue(userId, key, value, masterKey = VAULT_MASTER_KEY) {
3020
+ return encryptVaultValueWithKey(userId, key, value, masterKey);
3021
+ }
3022
+ function decryptVaultValue(userId, key, storedValue, masterKey = VAULT_MASTER_KEY) {
3023
+ return decryptVaultValueWithKey(userId, key, storedValue, masterKey);
3024
+ }
3013
3025
  var init_vault_crypto = __esm(() => {
3014
3026
  init_config();
3027
+ init_vault_crypto_core();
3015
3028
  });
3016
3029
 
3017
3030
  // ../../packages/core/src/storage/vault.ts
@@ -3051,8 +3064,9 @@ function initializeVaultDatabase(database) {
3051
3064
  }
3052
3065
  }
3053
3066
  function openVaultDatabase(dataDir) {
3054
- const path = join11(dataDir, "vault.db");
3055
- mkdirSync9(dataDir, { recursive: true });
3067
+ const vaultDir = join11(dataDir, "vault");
3068
+ const path = join11(vaultDir, "vault.db");
3069
+ mkdirSync9(vaultDir, { recursive: true, mode: 448 });
3056
3070
  const database = new Database(path, { create: true });
3057
3071
  chmodSync2(path, 384);
3058
3072
  initializeVaultDatabase(database);
@@ -3771,7 +3785,7 @@ var init_claude_provider = __esm(async () => {
3771
3785
  });
3772
3786
 
3773
3787
  // ../../packages/core/src/version.ts
3774
- var NEGOTIUM_VERSION = "0.1.49";
3788
+ var NEGOTIUM_VERSION = "0.2.1";
3775
3789
 
3776
3790
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
3777
3791
  import { spawn as spawn3 } from "child_process";
@@ -10522,7 +10536,7 @@ function createBrowserProfile(ownerId, rawName) {
10522
10536
  const name = normalizeBrowserProfileName(rawName);
10523
10537
  if (name === DEFAULT_BROWSER_PROFILE)
10524
10538
  return name;
10525
- db.query("INSERT OR IGNORE INTO browser_profiles (owner_id, name, created_at) VALUES (?, ?, ?)").run(ownerId, name, new Date().toISOString());
10539
+ db.query("INSERT OR IGNORE INTO browser_profiles (owner_id, name, created_at) VALUES (?, ?, ?)").run("local", name, new Date().toISOString());
10526
10540
  return name;
10527
10541
  }
10528
10542
  function assignTopicBrowserProfile(opts) {
@@ -10562,7 +10576,6 @@ import {
10562
10576
  existsSync as existsSync16,
10563
10577
  mkdirSync as mkdirSync11,
10564
10578
  readFileSync as readFileSync14,
10565
- renameSync as renameSync6,
10566
10579
  rmSync as rmSync3,
10567
10580
  unlinkSync as unlinkSync11,
10568
10581
  writeFileSync as writeFileSync9
@@ -10578,7 +10591,7 @@ function defaultTopicBinding(userId, topic) {
10578
10591
  if (!topic)
10579
10592
  return managerHost.resolveNamedBinding(userId, "default");
10580
10593
  const ownerId = getBrowserProfileOwner(topic, userId);
10581
- const profile = migrateLegacyTopicProfile(ownerId, topic);
10594
+ const profile = getTopicBrowserProfile(topic);
10582
10595
  return managerHost.resolveNamedBinding(ownerId, profile);
10583
10596
  }
10584
10597
  function resolvePlaywrightProfileBinding(ownerId, rawProfile) {
@@ -10590,34 +10603,15 @@ function validateProfileBinding(binding) {
10590
10603
  }
10591
10604
  return Object.freeze({ ...binding });
10592
10605
  }
10593
- function defaultNamedBinding(ownerId, rawProfile) {
10606
+ function defaultNamedBinding(_ownerId, rawProfile) {
10594
10607
  const profile = normalizeBrowserProfileName(rawProfile);
10595
- const instanceKey = `profile:${encodeURIComponent(ownerId)}:${profile}`;
10608
+ const instanceKey = `profile:${profile}`;
10596
10609
  return {
10597
10610
  instanceKey,
10598
- ownerId,
10611
+ ownerId: "local",
10599
10612
  profile
10600
10613
  };
10601
10614
  }
10602
- function legacyBrowserProfileName(topic) {
10603
- return `legacy_${createHash3("sha256").update(topic).digest("hex").slice(0, 12)}`;
10604
- }
10605
- function migrateLegacyTopicProfile(ownerId, topic) {
10606
- const current2 = getTopicBrowserProfile(topic);
10607
- if (current2 !== "default" || !hasBrowserProfileTopic(topic))
10608
- return current2;
10609
- const legacyDir = resolve13(BROWSER_PROFILES_DIR, sanitizeTopicName(topic));
10610
- if (!existsSync16(legacyDir))
10611
- return current2;
10612
- const profile = legacyBrowserProfileName(topic);
10613
- const profileDir = defaultProfileDir(ownerId, profile);
10614
- mkdirSync11(dirname11(profileDir), { recursive: true });
10615
- if (!existsSync16(profileDir))
10616
- renameSync6(legacyDir, profileDir);
10617
- assignTopicBrowserProfile({ topicId: topic, actorUserId: ownerId, profile });
10618
- logger.info({ ownerId, topic, profile }, "Adopted legacy topic browser profile");
10619
- return profile;
10620
- }
10621
10615
  function defaultChildEnvironment(context) {
10622
10616
  const childEnvironment = {};
10623
10617
  for (const key of [
@@ -10648,6 +10642,10 @@ function defaultChildEnvironment(context) {
10648
10642
  return childEnvironment;
10649
10643
  }
10650
10644
  function parseInstanceKey(instanceKey) {
10645
+ const shared = /^profile:(.+)$/.exec(instanceKey);
10646
+ if (shared && !shared[1].includes(":")) {
10647
+ return { ownerId: "local", profile: normalizeBrowserProfileName(shared[1]) };
10648
+ }
10651
10649
  const match = /^profile:([^:]+):(.+)$/.exec(instanceKey);
10652
10650
  if (!match)
10653
10651
  return { ownerId: "legacy", profile: sanitizeTopicName(instanceKey) };
@@ -10790,12 +10788,8 @@ async function allocatePort() {
10790
10788
  function releasePort(port) {
10791
10789
  usedPorts.delete(port);
10792
10790
  }
10793
- function ownerDirectory(ownerId) {
10794
- const digest = createHash3("sha256").update(ownerId).digest("hex").slice(0, 16);
10795
- return `${sanitizeTopicName(ownerId).slice(0, 24)}_${digest}`;
10796
- }
10797
- function defaultProfileDir(ownerId, profile) {
10798
- return resolve13(BROWSER_PROFILES_DIR, "profiles", ownerDirectory(ownerId), profile);
10791
+ function defaultProfileDir(_ownerId, profile) {
10792
+ return resolve13(BROWSER_PROFILES_DIR, profile);
10799
10793
  }
10800
10794
  function resolveUserDataDir(instanceKey) {
10801
10795
  return managerHost.resolveInstanceDataDir(instanceKey);
@@ -11309,7 +11303,7 @@ RULES:
11309
11303
  - Keep the entire summary under 1500 words.`, CHARS_PER_TEXT_TOKEN = 3.5, CHARS_PER_CJK_TOKEN = 0.9;
11310
11304
 
11311
11305
  // ../../packages/core/src/agents/topic-cleanup.ts
11312
- import { mkdirSync as mkdirSync12, renameSync as renameSync7, unlinkSync as unlinkSync12, writeFileSync as writeFileSync10 } from "fs";
11306
+ import { mkdirSync as mkdirSync12, renameSync as renameSync6, unlinkSync as unlinkSync12, writeFileSync as writeFileSync10 } from "fs";
11313
11307
  import { dirname as dirname12 } from "path";
11314
11308
  function collectSessionIdsByAgent(entries, extraSessions = []) {
11315
11309
  const out = new Map;
@@ -11380,7 +11374,7 @@ function createTopicLogMaintenance(host) {
11380
11374
  writeFileSync10(tempPath, retained.length > 0 ? `${retained.map((entry) => JSON.stringify(entry)).join(`
11381
11375
  `)}
11382
11376
  ` : "", { flag: "wx" });
11383
- renameSync7(tempPath, path);
11377
+ renameSync6(tempPath, path);
11384
11378
  } catch (e) {
11385
11379
  try {
11386
11380
  unlinkSync12(tempPath);
@@ -12609,7 +12603,7 @@ var init_session_inbox_cleanup = __esm(() => {
12609
12603
  });
12610
12604
 
12611
12605
  // ../../packages/core/src/query/state.ts
12612
- import { mkdirSync as mkdirSync14, renameSync as renameSync8, unlinkSync as unlinkSync15, writeFileSync as writeFileSync12 } from "fs";
12606
+ import { mkdirSync as mkdirSync14, renameSync as renameSync7, unlinkSync as unlinkSync15, writeFileSync as writeFileSync12 } from "fs";
12613
12607
  import { basename as basename4, join as join24 } from "path";
12614
12608
  function createQueryStateStore(options) {
12615
12609
  const sanitize = options.sanitizeTopicId ?? sanitizeId;
@@ -12631,7 +12625,7 @@ function createQueryStateStore(options) {
12631
12625
  const target = queryStateFile(userId, topicId);
12632
12626
  const tmp = `${target}.${process.pid}.${Date.now()}.tmp`;
12633
12627
  writeFileSync12(tmp, JSON.stringify(state));
12634
- renameSync8(tmp, target);
12628
+ renameSync7(tmp, target);
12635
12629
  },
12636
12630
  clear(userId, topicId, legacyTopicName) {
12637
12631
  const paths = [
@@ -13776,7 +13770,7 @@ function promptWithAttachments(prompt, attachments) {
13776
13770
  return composeAttachmentPrompt(prompt, attachments.map(({ filename, path }) => attachmentPromptLine(filename, path)));
13777
13771
  }
13778
13772
  function ingestAttachment(args) {
13779
- const destDir = join26(workspaceCwdFor(args.topicId), "uploads");
13773
+ const destDir = join26(UPLOADS_DIR, args.topicId);
13780
13774
  mkdirSync16(destDir, { recursive: true });
13781
13775
  const safeName = safeAttachmentFilename(args.filename, "upload");
13782
13776
  const destPath = join26(destDir, `${Date.now()}-${randomUUID14().slice(0, 8)}-${safeName}`);
@@ -17983,4 +17977,4 @@ export {
17983
17977
  DEFAULT_SELF_CONFIG_PRODUCT
17984
17978
  };
17985
17979
 
17986
- //# debugId=752753A08D9FFBDE64756E2164756E21
17980
+ //# debugId=FCF6570ACBE724C664756E2164756E21