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
@@ -99,10 +99,14 @@ function parsePortEnv(envValue, fallback) {
99
99
  var WORKSPACE_DIR = resolveLocalStateDir("NEGOTIUM_WORKSPACE_DIR", "workspace");
100
100
  var TOPIC_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "topics");
101
101
  var SHARED_WIKI_DIR = resolve(WORKSPACE_DIR, "wiki");
102
- var CONTEXTS_DIR = resolve(WORKSPACE_DIR, "contexts");
103
- var BROWSER_PROFILES_DIR = resolve(WORKSPACE_DIR, "browser-profiles");
104
- var DM_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "dm");
105
- var SESSION_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "sessions");
102
+ var CRON_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "cron");
103
+ var BROWSER_DIR = resolveLocalStateDir("NEGOTIUM_BROWSER_DIR", "browser");
104
+ var BROWSER_PROFILES_DIR = resolve(BROWSER_DIR, "profiles");
105
+ var BINARIES_DIR = resolve(STATE_DIR, "binaries");
106
+ var SECRETS_DIR = resolve(STATE_DIR, "secrets");
107
+ var CONTEXTS_DIR = resolve(STATE_DIR, "data", "contexts");
108
+ var DM_WORKSPACE_DIR = resolve(STATE_DIR, "data", "dm");
109
+ var SESSION_WORKSPACE_DIR = resolve(STATE_DIR, "data", "sessions");
106
110
  var CLAUDE_EXECUTABLE_ENV = envText("NEGOTIUM_CLAUDE_EXECUTABLE");
107
111
  var CLAUDE_EXECUTABLE = CLAUDE_EXECUTABLE_ENV ? resolve(CLAUDE_EXECUTABLE_ENV) : undefined;
108
112
  var BROWSER_RS_VERSION = "v0.1.16";
@@ -140,7 +144,7 @@ function resolveBrowserRsBin(envValue) {
140
144
  if (!override && !versionAtLeast(BROWSER_RS_VERSION.replace(/^v/, ""), BROWSER_RS_MIN_SECURE_VERSION)) {
141
145
  return;
142
146
  }
143
- const candidate = override ? resolve(override) : resolve(STATE_DIR, "bin", "browser-rs", BROWSER_RS_VERSION, "browser-rs");
147
+ const candidate = override ? resolve(override) : resolve(BINARIES_DIR, "browser-rs", BROWSER_RS_VERSION, "browser-rs");
144
148
  try {
145
149
  accessSync(candidate, constants.X_OK);
146
150
  return browserRsMeetsMinimumVersion(candidate) ? candidate : undefined;
@@ -153,7 +157,7 @@ function resolveBrowserMcpBin(envValue) {
153
157
  const override = envValue?.trim();
154
158
  if (override)
155
159
  return resolve(override);
156
- return BROWSER_RS_BIN ?? resolve(STATE_DIR, "bin", "browser-rs", BROWSER_RS_VERSION, "browser-rs");
160
+ return BROWSER_RS_BIN ?? resolve(BINARIES_DIR, "browser-rs", BROWSER_RS_VERSION, "browser-rs");
157
161
  }
158
162
  var PLAYWRIGHT_MCP_BIN = resolveBrowserMcpBin(envText("NEGOTIUM_BROWSER_MCP_BIN"));
159
163
  var TSX_BIN = resolveDependencyBin("tsx");
@@ -174,7 +178,7 @@ var BG_BASH_BASE_PORT = parsePortEnv(process.env.BG_BASH_BASE_PORT, 9700);
174
178
  var BG_BASH_MAX_PORT = parsePortEnv(process.env.BG_BASH_MAX_PORT, 9799);
175
179
  function loadOrCreateLocalSecret(envKey, filename, options = {}) {
176
180
  const envValue = envText(envKey);
177
- const secretFile = resolve(STATE_DIR, filename);
181
+ const secretFile = resolve(SECRETS_DIR, filename);
178
182
  mkdirSync(dirname(secretFile), { recursive: true });
179
183
  if (envValue) {
180
184
  if (options.persistEnvValue) {
@@ -214,10 +218,12 @@ var NEGOTIUM_PORT = parseInt(process.env.NEGOTIUM_PORT || "7777", 10);
214
218
  var hostname = process.env.HOSTNAME || "127.0.0.1";
215
219
  var DATA_DIR = resolveLocalStateDir("NEGOTIUM_DATA_DIR", "data");
216
220
  var LOG_DIR = resolveLocalStateDir("NEGOTIUM_LOG_DIR", "logs");
221
+ var UPLOADS_DIR = resolve(DATA_DIR, "uploads");
222
+ var VAULT_DIR = resolve(DATA_DIR, "vault");
217
223
  var SESSIONS_DB = process.env.SESSIONS_DB_PATH ? resolve(process.env.SESSIONS_DB_PATH) : resolve(DATA_DIR, "sessions.db");
218
224
  var DEBUG_FILE = resolve(DATA_DIR, "debug-users.json");
219
225
  var USERS_LOG_DIR = resolve(DATA_DIR, "users");
220
- var RUN_DIR = resolveLocalStateDir("NEGOTIUM_RUN_DIR", "run");
226
+ var RUN_DIR = resolveLocalStateDir("NEGOTIUM_RUN_DIR", "runtime");
221
227
  var PROGRESS_DIR = resolve(RUN_DIR, "progress");
222
228
  var DM_CMD_DIR = resolve(RUN_DIR, "dm-commands");
223
229
  var DM_RESP_DIR = resolve(RUN_DIR, "dm-responses");
@@ -228,6 +234,8 @@ var PLAYWRIGHT_MAX_PORT = parsePortEnv(process.env.PLAYWRIGHT_MAX_PORT, 9499);
228
234
  var PLAYWRIGHT_PORTS_DIR = resolve(RUN_DIR, "playwright-ports");
229
235
  mkdirSync(STATE_DIR, { recursive: true });
230
236
  mkdirSync(DATA_DIR, { recursive: true });
237
+ mkdirSync(UPLOADS_DIR, { recursive: true });
238
+ mkdirSync(VAULT_DIR, { recursive: true, mode: 448 });
231
239
  mkdirSync(LOG_DIR, { recursive: true });
232
240
  mkdirSync(PROGRESS_DIR, { recursive: true });
233
241
  mkdirSync(DM_CMD_DIR, { recursive: true });
@@ -238,10 +246,14 @@ mkdirSync(PLAYWRIGHT_PORTS_DIR, { recursive: true });
238
246
  mkdirSync(WORKSPACE_DIR, { recursive: true });
239
247
  mkdirSync(TOPIC_WORKSPACE_DIR, { recursive: true });
240
248
  mkdirSync(SHARED_WIKI_DIR, { recursive: true });
249
+ mkdirSync(CRON_WORKSPACE_DIR, { recursive: true });
241
250
  mkdirSync(CONTEXTS_DIR, { recursive: true });
242
- mkdirSync(BROWSER_PROFILES_DIR, { recursive: true });
243
251
  mkdirSync(DM_WORKSPACE_DIR, { recursive: true });
244
252
  mkdirSync(SESSION_WORKSPACE_DIR, { recursive: true });
253
+ mkdirSync(BROWSER_DIR, { recursive: true });
254
+ mkdirSync(BROWSER_PROFILES_DIR, { recursive: true });
255
+ mkdirSync(BINARIES_DIR, { recursive: true });
256
+ mkdirSync(SECRETS_DIR, { recursive: true, mode: 448 });
245
257
  var ACTIVE_QUERY_STALE_MS = 10 * 60 * 1000;
246
258
  var AGENTS_PROMPTS_DIR = resolve(PROJECT_ROOT, "src/prompts/agents");
247
259
  var RESOURCES_DIR = resolve(PROJECT_ROOT, "src/resources");
@@ -463,4 +475,4 @@ export {
463
475
  bgBashContextCapability
464
476
  };
465
477
 
466
- //# debugId=450027B0CC69815A64756E2164756E21
478
+ //# debugId=C4E26CE8FA80E8DB64756E2164756E21
@@ -3,14 +3,14 @@
3
3
  "sources": ["../../../packages/core/src/platform/background-bash/manager.ts", "../../../packages/core/src/platform/config.ts", "../../../packages/core/src/platform/config-helpers.ts", "../../../packages/core/src/platform/logger.ts", "../../../packages/core/src/types.ts", "../../../packages/core/src/platform/delay.ts", "../../../packages/core/src/platform/background-bash/context.ts"],
4
4
  "sourcesContent": [
5
5
  "import { type ChildProcess, execFileSync, spawn } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport { BACKGROUND_BASH_SERVER, BG_BASH_BASE_PORT, BG_BASH_MAX_PORT } from \"#platform/config\";\nimport { delay } from \"#platform/delay\";\nimport { logger } from \"#platform/logger\";\nimport { deriveBgBashContextCapability } from \"./context\";\n\nexport function makeBgBashKey(_userId: string, _topic: string): string {\n return \"runtime\";\n}\n\ninterface BgBashInstance {\n process: ChildProcess;\n port: number;\n startedAt: number;\n lastUsedAt: number;\n}\n\nexport interface BackgroundBashManager {\n contextCapability(userId: string, topic: string): string;\n ensure(userId: string, topic: string): Promise<number>;\n clear(userId: string, topic: string): void;\n clearUser(userId: string): void;\n killAll(): Promise<void>;\n}\n\nexport interface BackgroundBashManagerOptions {\n serverFile?: string;\n basePort?: number;\n maxPort?: number;\n capability?: string;\n serverId?: string;\n env?: NodeJS.ProcessEnv;\n fetch?: typeof globalThis.fetch;\n now?: () => number;\n delay?: (milliseconds: number) => Promise<void>;\n portPids?: (port: number) => readonly number[];\n spawn?: (\n command: string,\n args: readonly string[],\n options: Parameters<typeof spawn>[2],\n ) => ChildProcess;\n}\n\nfunction defaultPortPids(port: number): number[] {\n try {\n return execFileSync(\"lsof\", [\"-i\", `:${port}`, \"-t\"], { stdio: \"pipe\" })\n .toString()\n .trim()\n .split(\"\\n\")\n .map((pid) => Number.parseInt(pid, 10))\n .filter((pid) => !Number.isNaN(pid));\n } catch {\n return [];\n }\n}\n\n/** Create a fully isolated manager. All mutable process/port/context state belongs to the caller. */\nexport function createBackgroundBashManager(\n options: BackgroundBashManagerOptions = {},\n): BackgroundBashManager {\n const instances = new Map<string, BgBashInstance>();\n const usedPorts = new Set<number>();\n const spawning = new Map<string, Promise<number>>();\n const knownContexts = new Map<string, { userId: string; topic: string }>();\n const runtimeCapability = options.capability ?? randomBytes(32).toString(\"hex\");\n const runtimeServerId = options.serverId ?? randomBytes(16).toString(\"hex\");\n const serverFile = options.serverFile ?? BACKGROUND_BASH_SERVER;\n const basePort = options.basePort ?? BG_BASH_BASE_PORT;\n const maxPort = options.maxPort ?? BG_BASH_MAX_PORT;\n const fetchImpl = options.fetch ?? globalThis.fetch;\n const now = options.now ?? Date.now;\n const wait = options.delay ?? delay;\n const portPids = options.portPids ?? defaultPortPids;\n const spawnImpl =\n options.spawn ?? ((command, args, spawnOptions) => spawn(command, [...args], spawnOptions));\n\n function contextKey(userId: string, topic: string): string {\n return `${userId}\\0${topic}`;\n }\n\n function contextCapability(userId: string, topic: string): string {\n return deriveBgBashContextCapability(runtimeCapability, userId, topic);\n }\n\n async function allocatePort(excludedPorts: ReadonlySet<number> = new Set()): Promise<number> {\n for (let port = basePort; port <= maxPort; port++) {\n if (usedPorts.has(port) || excludedPorts.has(port)) continue;\n usedPorts.add(port);\n if (portPids(port).length > 0) {\n usedPorts.delete(port);\n continue;\n }\n return port;\n }\n throw new Error(\n `No available ports for background-bash (range ${basePort}-${maxPort}, ${instances.size} active)`,\n );\n }\n\n async function isHealthy(port: number): Promise<boolean> {\n try {\n const response = await fetchImpl(`http://127.0.0.1:${port}/health`, {\n signal: AbortSignal.timeout(2000),\n });\n return response.ok && (await response.text()) === runtimeServerId;\n } catch {\n return false;\n }\n }\n\n function killRuntime(): void {\n const key = \"runtime\";\n const instance = instances.get(key);\n if (!instance) return;\n try {\n instance.process.kill(\"SIGTERM\");\n } catch {}\n usedPorts.delete(instance.port);\n instances.delete(key);\n logger.info({ key, port: instance.port }, \"background-bash server killed\");\n }\n\n async function spawnServer(\n key: string,\n reservedPort?: number,\n excludedPorts: ReadonlySet<number> = new Set(),\n ): Promise<number> {\n const port = reservedPort ?? (await allocatePort(excludedPorts));\n const process = spawnImpl(\"bun\", [\"run\", serverFile, `--port=${port}`], {\n stdio: \"ignore\",\n detached: false,\n env: {\n ...(options.env ?? globalThis.process.env),\n NEGOTIUM_BG_BASH_CAPABILITY: runtimeCapability,\n NEGOTIUM_BG_BASH_SERVER_ID: runtimeServerId,\n },\n });\n\n process.once(\"error\", (error) => {\n logger.error({ err: error, key }, \"background-bash server error\");\n if (instances.get(key)?.process === process) {\n usedPorts.delete(port);\n instances.delete(key);\n }\n });\n process.once(\"exit\", (code) => {\n logger.info({ key, code }, \"background-bash server exited\");\n if (instances.get(key)?.process === process) {\n usedPorts.delete(port);\n instances.delete(key);\n }\n });\n\n const timestamp = now();\n instances.set(key, { process, port, startedAt: timestamp, lastUsedAt: timestamp });\n const started = now();\n while (now() - started < 8_000) {\n if (process.exitCode !== null) {\n const nextExcluded = new Set(excludedPorts);\n nextExcluded.add(port);\n return spawnServer(key, undefined, nextExcluded);\n }\n if (await isHealthy(port)) return port;\n await wait(200);\n }\n killRuntime();\n throw new Error(`background-bash server failed health check after spawn on port ${port}`);\n }\n\n async function ensure(userId: string, topic: string): Promise<number> {\n const key = makeBgBashKey(userId, topic);\n knownContexts.set(contextKey(userId, topic), { userId, topic });\n const inProgress = spawning.get(key);\n if (inProgress) return inProgress;\n\n const promise = (async () => {\n const existing = instances.get(key);\n if (existing && !existing.process.killed && existing.process.exitCode === null) {\n if (await isHealthy(existing.port)) {\n existing.lastUsedAt = now();\n return existing.port;\n }\n killRuntime();\n } else if (existing) {\n usedPorts.delete(existing.port);\n instances.delete(key);\n }\n return spawnServer(key);\n })().finally(() => spawning.delete(key));\n spawning.set(key, promise);\n return promise;\n }\n\n function clear(userId: string, topic: string): void {\n knownContexts.delete(contextKey(userId, topic));\n const instance = instances.get(\"runtime\");\n if (!instance) return;\n const query = new URLSearchParams({\n user: userId,\n topic,\n capability: contextCapability(userId, topic),\n });\n void fetchImpl(`http://127.0.0.1:${instance.port}/contexts?${query}`, {\n method: \"DELETE\",\n }).catch(() => {});\n }\n\n function clearUser(userId: string): void {\n for (const context of [...knownContexts.values()]) {\n if (context.userId === userId) clear(context.userId, context.topic);\n }\n }\n\n async function killAll(): Promise<void> {\n const entries = [...instances.values()];\n for (const instance of entries) {\n try {\n instance.process.kill(\"SIGTERM\");\n } catch {}\n }\n instances.clear();\n usedPorts.clear();\n knownContexts.clear();\n const deadline = now() + 3000;\n await Promise.all(\n entries.map(\n (instance) =>\n new Promise<void>((resolve) => {\n if (instance.process.exitCode !== null || instance.process.killed) return resolve();\n instance.process.once(\"exit\", resolve);\n instance.process.once(\"error\", resolve);\n const timer = setTimeout(resolve, Math.max(0, deadline - now()));\n timer.unref?.();\n }),\n ),\n );\n }\n\n return { contextCapability, ensure, clear, clearUser, killAll };\n}\n\nconst defaultManager = createBackgroundBashManager();\n\nexport const bgBashContextCapability = defaultManager.contextCapability;\nexport const ensureBgBash = defaultManager.ensure;\nexport const killBgBash = defaultManager.clear;\nexport const killBgBashForUser = defaultManager.clearUser;\nexport const killAllBgBash = defaultManager.killAll;\n",
6
- "import { execFileSync } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport {\n accessSync,\n chmodSync,\n constants,\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n} from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parseRuntimePort, readEnvText, safeRuntimePathSegment } from \"#platform/config-helpers\";\nimport { logger } from \"#platform/logger\";\nimport { type AgentKind, isAgentKind } from \"#types\";\n\nexport function envText(envKey: string): string | undefined {\n return readEnvText(process.env, envKey);\n}\n\nfunction resolveAgentEnv(envKey: string, fallback: AgentKind, legacyEnvKey?: string): AgentKind {\n const value = envText(envKey) ?? (legacyEnvKey ? envText(legacyEnvKey) : undefined);\n return isAgentKind(value) ? value : fallback;\n}\n\nconst HOME = homedir();\n\n// new URL(\"../..\", import.meta.url) causes webpack to treat \"../..\" as a module import.\n// Split into fileURLToPath → dirname → resolve to avoid that.\nfunction resolveProjectRoot(): string {\n const moduleDir = dirname(fileURLToPath(import.meta.url));\n const packagedRuntime = resolve(moduleDir, \"runtime\");\n if (existsSync(resolve(packagedRuntime, \"src\"))) return packagedRuntime;\n return resolve(moduleDir, \"../..\");\n}\n\nexport const PROJECT_ROOT = resolveProjectRoot();\n\n/** Resolve a dependency executable from either a package-local or hoisted install. */\nfunction resolveDependencyBin(name: string): string {\n let dir = PROJECT_ROOT;\n while (true) {\n const candidate = resolve(dir, \"node_modules\", \".bin\", name);\n if (existsSync(candidate)) return candidate;\n const parent = dirname(dir);\n if (parent === dir) return candidate;\n dir = parent;\n }\n}\n\n// Each machine is one negotium node; all node state lives in one dotdir.\n// NEGOTIUM_STATE_DIR overrides (useful for tests and multi-node-on-one-box).\nconst STATE_DIR_ENV = envText(\"NEGOTIUM_STATE_DIR\");\nexport const STATE_DIR = STATE_DIR_ENV ? resolve(STATE_DIR_ENV) : resolve(HOME, \".negotium\");\n\nfunction resolveLocalStateDir(envKey: string, stateName: string): string {\n const envValue = envText(envKey);\n if (envValue) return resolve(envValue);\n return resolve(STATE_DIR, stateName);\n}\n\nfunction parsePortEnv(envValue: string | undefined, fallback: number): number {\n return parseRuntimePort(envValue, fallback);\n}\n\nexport const WORKSPACE_DIR = resolveLocalStateDir(\"NEGOTIUM_WORKSPACE_DIR\", \"workspace\");\nexport const TOPIC_WORKSPACE_DIR = resolve(WORKSPACE_DIR, \"topics\");\nexport const SHARED_WIKI_DIR = resolve(WORKSPACE_DIR, \"wiki\");\nexport const CONTEXTS_DIR = resolve(WORKSPACE_DIR, \"contexts\");\nexport const BROWSER_PROFILES_DIR = resolve(WORKSPACE_DIR, \"browser-profiles\");\nexport const DM_WORKSPACE_DIR = resolve(WORKSPACE_DIR, \"dm\");\nexport const SESSION_WORKSPACE_DIR = resolve(WORKSPACE_DIR, \"sessions\");\n// The Claude Agent SDK ships a platform-matched Claude Code binary. Keep that\n// SDK/CLI pair together by default; only use an external executable when an\n// operator explicitly opts in. This avoids silently pairing an older SDK with\n// a newer globally installed Claude Code release.\nconst CLAUDE_EXECUTABLE_ENV = envText(\"NEGOTIUM_CLAUDE_EXECUTABLE\");\nexport const CLAUDE_EXECUTABLE = CLAUDE_EXECUTABLE_ENV ? resolve(CLAUDE_EXECUTABLE_ENV) : undefined;\n\n// Fallback output language for model-generated prose (topic/channel/manager\n// replies and the archiver's summaries, briefs, articles, completion reply).\n// Defaults to English; set `NEGOTIUM_LANG` to the user's mother tongue (e.g.\n// `Korean`, `ko`). The assistant still mirrors whatever language the user\n// writes in; `NEGOTIUM_MEMORY_LANG` can narrow just the archiver. Fixed system\n// chrome / degraded-path strings emitted by code stay English (can't translate\n// an arbitrary value at runtime).\nexport const DEFAULT_OUTPUT_LANGUAGE = \"English\";\n\nexport function resolveOutputLanguage(): string {\n const raw = envText(\"NEGOTIUM_LANG\")?.trim();\n return raw && raw.length > 0 ? raw : DEFAULT_OUTPUT_LANGUAGE;\n}\n\n/** Browser.rs release tested with this Negotium version. */\nexport const BROWSER_RS_VERSION = \"v0.1.16\";\n/** Require the authenticated listener and the current Browser.rs tool contract. */\nexport const BROWSER_RS_MIN_SECURE_VERSION = \"0.1.15\";\n\nfunction versionAtLeast(actualVersion: string, minimumVersion: string): boolean {\n const actual = actualVersion.split(\".\").map(Number);\n const minimum = minimumVersion.split(\".\").map(Number);\n if (actual.some(Number.isNaN) || minimum.some(Number.isNaN)) return false;\n for (let index = 0; index < minimum.length; index += 1) {\n if ((actual[index] ?? 0) > (minimum[index] ?? 0)) return true;\n if ((actual[index] ?? 0) < (minimum[index] ?? 0)) return false;\n }\n return true;\n}\n\nfunction browserRsMeetsMinimumVersion(candidate: string): boolean {\n try {\n const output = execFileSync(candidate, [\"--version\"], {\n encoding: \"utf8\",\n timeout: 2_000,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n const match = output.match(/^browser-rs (\\d+)\\.(\\d+)\\.(\\d+)$/);\n if (!match) return false;\n return versionAtLeast(match.slice(1).join(\".\"), BROWSER_RS_MIN_SECURE_VERSION);\n } catch {\n return false;\n }\n}\n\n/**\n * Resolve the preferred Browser.rs engine without consulting PATH. The\n * versioned private location keeps different Negotium releases reproducible\n * and avoids changing a user's global browser-rs installation.\n */\nexport function resolveBrowserRsBin(envValue?: string): string | undefined {\n const override = envValue?.trim();\n if (\n !override &&\n !versionAtLeast(BROWSER_RS_VERSION.replace(/^v/, \"\"), BROWSER_RS_MIN_SECURE_VERSION)\n ) {\n return undefined;\n }\n const candidate = override\n ? resolve(override)\n : resolve(STATE_DIR, \"bin\", \"browser-rs\", BROWSER_RS_VERSION, \"browser-rs\");\n try {\n accessSync(candidate, constants.X_OK);\n return browserRsMeetsMinimumVersion(candidate) ? candidate : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport const BROWSER_RS_BIN = resolveBrowserRsBin(envText(\"NEGOTIUM_BROWSER_RS_BIN\"));\n\n// Managed Browser.rs terminates MCP transports and security policy itself.\nexport function resolveBrowserMcpBin(envValue?: string): string {\n const override = envValue?.trim();\n if (override) return resolve(override);\n return (\n BROWSER_RS_BIN ?? resolve(STATE_DIR, \"bin\", \"browser-rs\", BROWSER_RS_VERSION, \"browser-rs\")\n );\n}\n\nexport const PLAYWRIGHT_MCP_BIN = resolveBrowserMcpBin(envText(\"NEGOTIUM_BROWSER_MCP_BIN\"));\n\n// --- Browser egress proxy ---\n//\n// On a datacenter host (AWS) the browser's egress IP is a known cloud range,\n// so anti-bot services (Cloudflare, DataDome, reCAPTCHA) challenge or block it\n// far more than a residential IP would. Routing the automation browser through\n// a residential/ISP proxy moves the egress IP out of the datacenter range.\n//\n// Operators set BROWSER_PROXY_URL, e.g. http://user:pass@proxy.host:8080 or\n// socks5://proxy.host:1080. Credentials in the URL are split out because\n// Playwright takes them as separate fields. BROWSER_PROXY_BYPASS is an optional\n// comma-separated no-proxy list (e.g. \"localhost,127.0.0.1,*.internal\").\n//\n// NOTE: Chromium does not support authentication for SOCKS proxies — put\n// credentials only on http/https proxy URLs.\nexport type BrowserProxyConfig = {\n server: string;\n username?: string;\n password?: string;\n bypass?: string;\n};\n\nexport function resolveBrowserProxy(): BrowserProxyConfig | null {\n const raw = envText(\"BROWSER_PROXY_URL\");\n if (!raw) return null;\n let url: URL;\n try {\n url = new URL(raw);\n } catch {\n logger.warn({ raw }, \"Ignoring malformed BROWSER_PROXY_URL\");\n return null;\n }\n // Playwright wants the server without embedded credentials.\n const server = `${url.protocol}//${url.host}`;\n const proxy: BrowserProxyConfig = { server };\n if (url.username) proxy.username = decodeURIComponent(url.username);\n if (url.password) proxy.password = decodeURIComponent(url.password);\n const bypass = envText(\"BROWSER_PROXY_BYPASS\");\n if (bypass) proxy.bypass = bypass;\n return proxy;\n}\n\n// --- Node/tsx runtime for the `codex` agent's MCP servers ---\n//\n// codex 0.135's rmcp stdio MCP client cannot reliably complete the initialize\n// handshake with servers spawned via `bun` (the JSON-RPC initialize is\n// dropped/raced and no tools ever reach the model). Pure-node servers connect\n// reliably, so codex turns launch the SAME .ts servers via node + tsx instead\n// of `bun run`. claude/maestro keep using `bun run` (fast, native, unaffected).\n//\n// tsx transpiles .ts on the fly and resolves the `@/*` tsconfig path aliases,\n// but only when it can find the tsconfig — and MCP servers run with cwd set to\n// the user's workspace dir, not PROJECT_ROOT — so we pass TSX_TSCONFIG_PATH\n// explicitly via env. Requires package.json `\"type\": \"module\"` so the servers'\n// top-level `await` loads as ESM under node.\nexport const TSX_BIN = resolveDependencyBin(\"tsx\");\n/** In-process tsx loader used by Node MCP entrypoints (avoids the tsx CLI child process). */\nexport const TSX_LOADER = createRequire(import.meta.url).resolve(\"tsx\");\nexport const TSCONFIG_PATH = resolve(PROJECT_ROOT, \"tsconfig.json\");\n\nexport const SESSION_COMM_SERVER = resolve(PROJECT_ROOT, \"src/mcp/session-comm/server.ts\");\n\nexport const TASK_SERVER = resolve(PROJECT_ROOT, \"src/mcp/task-server.ts\");\nexport const BROWSER_MCP_SSE_PROXY_SERVER = resolve(\n PROJECT_ROOT,\n \"src/mcp/browser-sse-proxy-server.ts\",\n);\nexport const CANONICAL_MCP_PROXY_SERVER = resolve(\n PROJECT_ROOT,\n \"src/mcp/canonical-proxy-server.ts\",\n);\n\nexport const WIKI_SERVER = resolve(PROJECT_ROOT, \"src/mcp/wiki-server.ts\");\n\nexport const TOKEN_STATS_SERVER = resolve(PROJECT_ROOT, \"src/mcp/token-stats-server.ts\");\n\nexport const COMPACTION_LOG_SERVER = resolve(PROJECT_ROOT, \"src/mcp/compaction-log-server.ts\");\n\nexport const SYSTEM_HEALTH_SERVER = resolve(PROJECT_ROOT, \"src/mcp/system-health-server.ts\");\n\nexport const AGENT_HEALTH_SERVER = resolve(PROJECT_ROOT, \"src/mcp/agent-health-server.ts\");\n\nexport const BACKGROUND_BASH_SERVER = resolve(PROJECT_ROOT, \"src/mcp/background-bash-server.ts\");\n\nexport const VAULT_SERVER = resolve(PROJECT_ROOT, \"src/mcp/vault-server.ts\");\n\nexport const BG_BASH_BASE_PORT = parsePortEnv(process.env.BG_BASH_BASE_PORT, 9700);\nexport const BG_BASH_MAX_PORT = parsePortEnv(process.env.BG_BASH_MAX_PORT, 9799);\n\nfunction safeWorkspaceSegment(value: string, fallback: string): string {\n return safeRuntimePathSegment(value, fallback);\n}\n\n/** Resolve the shared filesystem workspace for an API topic. */\nexport function resolveTopicWorkspaceDir(topicId: string): string {\n return join(TOPIC_WORKSPACE_DIR, safeWorkspaceSegment(topicId, \"topic\"));\n}\n\nexport function isProductionEnv(): boolean {\n return process.env.NODE_ENV === \"production\";\n}\n\nfunction loadOrCreateLocalSecret(\n envKey: string,\n filename: string,\n options: { persistEnvValue?: boolean } = {},\n): string {\n const envValue = envText(envKey);\n const secretFile = resolve(STATE_DIR, filename);\n mkdirSync(dirname(secretFile), { recursive: true });\n if (envValue) {\n if (options.persistEnvValue) {\n writeFileSync(secretFile, `${envValue}\\n`, { mode: 0o600 });\n chmodSync(secretFile, 0o600);\n }\n return envValue;\n }\n\n if (existsSync(secretFile)) {\n const stored = readFileSync(secretFile, \"utf-8\").trim();\n if (stored) {\n chmodSync(secretFile, 0o600);\n return stored;\n }\n }\n\n const secret = randomBytes(32).toString(\"base64url\");\n try {\n writeFileSync(secretFile, `${secret}\\n`, { mode: 0o600, flag: \"wx\" });\n return secret;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n const stored = readFileSync(secretFile, \"utf-8\").trim();\n if (!stored) throw new Error(`Secret file exists but is empty: ${secretFile}`);\n chmodSync(secretFile, 0o600);\n return stored;\n }\n}\n\nexport const RUNTIME_MCP_SECRET = loadOrCreateLocalSecret(\n \"RUNTIME_MCP_SECRET\",\n \"runtime-mcp-secret\",\n);\n/** Local bearer token for the loopback node-control API. */\nexport const NODE_CONTROL_TOKEN = loadOrCreateLocalSecret(\n \"NEGOTIUM_CONTROL_TOKEN\",\n \"node-control-token\",\n);\nexport const VAULT_MASTER_KEY = loadOrCreateLocalSecret(\n \"NEGOTIUM_VAULT_MASTER_KEY\",\n \"vault-master-key\",\n { persistEnvValue: true },\n);\n// Agent/tool subprocesses inherit process.env. Keep the loaded key in this\n// process only so `env`/`ps` inside an agent workspace cannot reveal it.\ndelete process.env.NEGOTIUM_VAULT_MASTER_KEY;\n\n/** The node's single open port: runtime MCP endpoint + node API. */\nexport const NEGOTIUM_PORT = parseInt(process.env.NEGOTIUM_PORT || \"7777\", 10);\nexport const hostname = process.env.HOSTNAME || \"127.0.0.1\";\n\n// Persistent state (survives restarts, long-lived)\nexport const DATA_DIR = resolveLocalStateDir(\"NEGOTIUM_DATA_DIR\", \"data\");\nexport const LOG_DIR = resolveLocalStateDir(\"NEGOTIUM_LOG_DIR\", \"logs\");\n// SESSIONS_DB_PATH env override lets tests point the DB singleton at a temp file.\nexport const SESSIONS_DB = process.env.SESSIONS_DB_PATH\n ? resolve(process.env.SESSIONS_DB_PATH)\n : resolve(DATA_DIR, \"sessions.db\");\nexport const DEBUG_FILE = resolve(DATA_DIR, \"debug-users.json\");\nexport const USERS_LOG_DIR = resolve(DATA_DIR, \"users\");\n\n// Runtime IPC queues (transient, safe to clear on restart)\nexport const RUN_DIR = resolveLocalStateDir(\"NEGOTIUM_RUN_DIR\", \"run\");\nexport const PROGRESS_DIR = resolve(RUN_DIR, \"progress\");\nexport const DM_CMD_DIR = resolve(RUN_DIR, \"dm-commands\");\nexport const DM_RESP_DIR = resolve(RUN_DIR, \"dm-responses\");\nexport const SESSION_INBOX_DIR = resolve(RUN_DIR, \"session-inbox\");\nexport const SESSION_ASKS_DIR = resolve(RUN_DIR, \"session-asks\");\nexport const PLAYWRIGHT_BASE_PORT = parsePortEnv(process.env.PLAYWRIGHT_BASE_PORT, 9100);\nexport const PLAYWRIGHT_MAX_PORT = parsePortEnv(process.env.PLAYWRIGHT_MAX_PORT, 9499);\nexport const PLAYWRIGHT_PORTS_DIR = resolve(RUN_DIR, \"playwright-ports\");\nmkdirSync(STATE_DIR, { recursive: true });\nmkdirSync(DATA_DIR, { recursive: true });\nmkdirSync(LOG_DIR, { recursive: true });\nmkdirSync(PROGRESS_DIR, { recursive: true });\nmkdirSync(DM_CMD_DIR, { recursive: true });\nmkdirSync(DM_RESP_DIR, { recursive: true });\nmkdirSync(SESSION_INBOX_DIR, { recursive: true });\nmkdirSync(SESSION_ASKS_DIR, { recursive: true });\nmkdirSync(PLAYWRIGHT_PORTS_DIR, { recursive: true });\nmkdirSync(WORKSPACE_DIR, { recursive: true });\nmkdirSync(TOPIC_WORKSPACE_DIR, { recursive: true });\nmkdirSync(SHARED_WIKI_DIR, { recursive: true });\nmkdirSync(CONTEXTS_DIR, { recursive: true });\nmkdirSync(BROWSER_PROFILES_DIR, { recursive: true });\nmkdirSync(DM_WORKSPACE_DIR, { recursive: true });\nmkdirSync(SESSION_WORKSPACE_DIR, { recursive: true });\n\n/** Stale threshold for active-query state files (crash recovery) */\nexport const ACTIVE_QUERY_STALE_MS = 10 * 60 * 1000; // 10 minutes\n\nexport const AGENTS_PROMPTS_DIR = resolve(PROJECT_ROOT, \"src/prompts/agents\");\nexport const RESOURCES_DIR = resolve(PROJECT_ROOT, \"src/resources\");\n\n/** Returns process.env without CLAUDECODE, to prevent nested claude-code detection in subprocesses. */\nexport function getCleanEnv(): NodeJS.ProcessEnv {\n const env = { ...process.env };\n delete env.CLAUDECODE;\n return env;\n}\n\nexport const FILE_EXTENSIONS_REGEX =\n /(?:\\/[^\\s\"'<>|*?[\\]]+\\.(?:png|jpg|jpeg|gif|webp|svg|pdf|csv|xlsx|xls|json|txt|md|html|zip|py|js|ts|tsx|jsx|css|xml|yaml|yml|docx|pptx))/gi;\n\nexport const FILE_TAG_REGEX = /\\[FILE:(\\/[^\\]]+)\\]/gi;\n\n// Canonical Claude model IDs — update here when Anthropic releases new versions\nexport const MODEL_SONNET = \"claude-sonnet-5\";\nexport const MODEL_OPUS = \"claude-opus-5\";\nexport const MODEL_HAIKU = \"claude-haiku-4-5-20251001\";\nexport const MODEL_FABLE = \"claude-fable-5\"; // Mythos-class, announced 2026-06-09\n\n// DeepSeek V4 (released 2026-04-24). API is OpenAI-compatible at\n// https://api.deepseek.com/v1/chat/completions; thinking mode is enabled via\n// `extra_body.thinking.type` + `reasoning_effort`. Legacy `deepseek-chat` /\n// `deepseek-reasoner` are deprecated 2026-07-24.\nexport const MODEL_DEEPSEEK_V4_PRO = \"deepseek-v4-pro\";\nexport const MODEL_DEEPSEEK_V4_FLASH = \"deepseek-v4-flash\";\n\n// Agent + model defaults split by session role. FALLBACK_* is the shared base;\n// SESSION_* overrides topic + ephemeral; GATEWAY_* overrides dm + manager.\n// DEFAULT_* is accepted as a legacy alias during the env migration window.\nexport const FALLBACK_AGENT: AgentKind = resolveAgentEnv(\n \"FALLBACK_AGENT\",\n \"maestro\",\n \"DEFAULT_AGENT\",\n);\nexport const SESSION_AGENT: AgentKind = resolveAgentEnv(\"SESSION_AGENT\", FALLBACK_AGENT);\nexport const GATEWAY_AGENT: AgentKind = resolveAgentEnv(\"GATEWAY_AGENT\", FALLBACK_AGENT);\n\nexport const FALLBACK_MODEL = envText(\"FALLBACK_MODEL\") ?? envText(\"DEFAULT_MODEL\");\n\nfunction resolveModelEnv(envKey: string, agentConst: AgentKind): string | undefined {\n return envText(envKey) ?? (agentConst === FALLBACK_AGENT ? FALLBACK_MODEL : undefined);\n}\n\nexport const SESSION_MODEL = resolveModelEnv(\"SESSION_MODEL\", SESSION_AGENT);\nexport const GATEWAY_MODEL = resolveModelEnv(\"GATEWAY_MODEL\", GATEWAY_AGENT);\n\n/** Resolve the effective display/default model for a topic (session context).\n * Applies the session model override only when that role owns the agent;\n * otherwise each registry's native default stays authoritative. */\nexport function resolveDefaultModel(agent: string, registryDefaultModel: string): string {\n return agent === SESSION_AGENT && SESSION_MODEL ? SESSION_MODEL : registryDefaultModel;\n}\n\n// ── External tool binaries + media pipeline env ───────────────────\n// (src/media/* 에서 사용. 미설정 시 fallback 의미는 기존 그대로:\n// FFMPEG_BIN은 text-extractor에서 필수(undefined면 spawn 시점 실패),\n// video.ts에서는 PATH의 ffmpeg/ffprobe로 fallback.)\nexport const FFMPEG_BIN = envText(\"FFMPEG_BIN\");\nexport const FFPROBE_BIN = envText(\"FFPROBE_BIN\");\nexport const PYTHON_BIN = envText(\"PYTHON_BIN\") ?? \"python3\";\nexport const FASTER_WHISPER_WRAPPER =\n envText(\"FASTER_WHISPER_WRAPPER\") ?? resolve(PROJECT_ROOT, \"scripts/faster-whisper-wrapper.py\");\nexport const WHISPER_MODEL = envText(\"WHISPER_MODEL_FILE\") ?? \"turbo\";\nexport const TESSERACT_BIN = envText(\"TESSERACT_BIN\") ?? \"tesseract\";\nexport const PDFTOTEXT_BIN = envText(\"PDFTOTEXT_BIN\") ?? \"pdftotext\";\n\n// Max tell_session relay depth from origin user. ask_session forks reset to\n// depth=0, so this only caps tell_session chains. Override via MAX_TELL_DEPTH\n// (positive int); defaults to 20 when unset or invalid.\nconst _envMaxTellDepth = Number.parseInt(process.env.MAX_TELL_DEPTH ?? \"\", 10);\nexport const MAX_TELL_DEPTH =\n Number.isInteger(_envMaxTellDepth) && _envMaxTellDepth > 0 ? _envMaxTellDepth : 20;\n\n/** Codex CLI auth file. 호출 시점에 env를 읽는다 — 테스트가 런타임에\n * NEGOTIUM_CODEX_AUTH_FILE을 바꾸므로 모듈 로드 상수로 만들면 안 된다. */\nexport function codexAuthFilePath(): string {\n return process.env.NEGOTIUM_CODEX_AUTH_FILE || join(homedir(), \".codex\", \"auth.json\");\n}\n\n// System defaults moved to per-agent registries\n// (`src/agents/{claude,codex}-registry.ts`). Read via\n// `getRegistry(agent).defaultModel` / `.defaultEffort`.\n\n// MCP server builders -> src/platform/mcp-config.ts\n",
6
+ "import { execFileSync } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport {\n accessSync,\n chmodSync,\n constants,\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n} from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parseRuntimePort, readEnvText, safeRuntimePathSegment } from \"#platform/config-helpers\";\nimport { logger } from \"#platform/logger\";\nimport { type AgentKind, isAgentKind } from \"#types\";\n\nexport function envText(envKey: string): string | undefined {\n return readEnvText(process.env, envKey);\n}\n\nfunction resolveAgentEnv(envKey: string, fallback: AgentKind, legacyEnvKey?: string): AgentKind {\n const value = envText(envKey) ?? (legacyEnvKey ? envText(legacyEnvKey) : undefined);\n return isAgentKind(value) ? value : fallback;\n}\n\nconst HOME = homedir();\n\n// new URL(\"../..\", import.meta.url) causes webpack to treat \"../..\" as a module import.\n// Split into fileURLToPath → dirname → resolve to avoid that.\nfunction resolveProjectRoot(): string {\n const moduleDir = dirname(fileURLToPath(import.meta.url));\n const packagedRuntime = resolve(moduleDir, \"runtime\");\n if (existsSync(resolve(packagedRuntime, \"src\"))) return packagedRuntime;\n return resolve(moduleDir, \"../..\");\n}\n\nexport const PROJECT_ROOT = resolveProjectRoot();\n\n/** Resolve a dependency executable from either a package-local or hoisted install. */\nfunction resolveDependencyBin(name: string): string {\n let dir = PROJECT_ROOT;\n while (true) {\n const candidate = resolve(dir, \"node_modules\", \".bin\", name);\n if (existsSync(candidate)) return candidate;\n const parent = dirname(dir);\n if (parent === dir) return candidate;\n dir = parent;\n }\n}\n\n// Each machine is one negotium node; all node state lives in one dotdir.\n// NEGOTIUM_STATE_DIR overrides (useful for tests and multi-node-on-one-box).\nconst STATE_DIR_ENV = envText(\"NEGOTIUM_STATE_DIR\");\nexport const STATE_DIR = STATE_DIR_ENV ? resolve(STATE_DIR_ENV) : resolve(HOME, \".negotium\");\n\nfunction resolveLocalStateDir(envKey: string, stateName: string): string {\n const envValue = envText(envKey);\n if (envValue) return resolve(envValue);\n return resolve(STATE_DIR, stateName);\n}\n\nfunction parsePortEnv(envValue: string | undefined, fallback: number): number {\n return parseRuntimePort(envValue, fallback);\n}\n\nexport const WORKSPACE_DIR = resolveLocalStateDir(\"NEGOTIUM_WORKSPACE_DIR\", \"workspace\");\nexport const TOPIC_WORKSPACE_DIR = resolve(WORKSPACE_DIR, \"topics\");\nexport const SHARED_WIKI_DIR = resolve(WORKSPACE_DIR, \"wiki\");\nexport const CRON_WORKSPACE_DIR = resolve(WORKSPACE_DIR, \"cron\");\nexport const BROWSER_DIR = resolveLocalStateDir(\"NEGOTIUM_BROWSER_DIR\", \"browser\");\nexport const BROWSER_PROFILES_DIR = resolve(BROWSER_DIR, \"profiles\");\nexport const BINARIES_DIR = resolve(STATE_DIR, \"binaries\");\nexport const SECRETS_DIR = resolve(STATE_DIR, \"secrets\");\n// Legacy names remain public, but their durable contents now live under data.\nexport const CONTEXTS_DIR = resolve(STATE_DIR, \"data\", \"contexts\");\nexport const DM_WORKSPACE_DIR = resolve(STATE_DIR, \"data\", \"dm\");\nexport const SESSION_WORKSPACE_DIR = resolve(STATE_DIR, \"data\", \"sessions\");\n// The Claude Agent SDK ships a platform-matched Claude Code binary. Keep that\n// SDK/CLI pair together by default; only use an external executable when an\n// operator explicitly opts in. This avoids silently pairing an older SDK with\n// a newer globally installed Claude Code release.\nconst CLAUDE_EXECUTABLE_ENV = envText(\"NEGOTIUM_CLAUDE_EXECUTABLE\");\nexport const CLAUDE_EXECUTABLE = CLAUDE_EXECUTABLE_ENV ? resolve(CLAUDE_EXECUTABLE_ENV) : undefined;\n\n// Fallback output language for model-generated prose (topic/channel/manager\n// replies and the archiver's summaries, briefs, articles, completion reply).\n// Defaults to English; set `NEGOTIUM_LANG` to the user's mother tongue (e.g.\n// `Korean`, `ko`). The assistant still mirrors whatever language the user\n// writes in; `NEGOTIUM_MEMORY_LANG` can narrow just the archiver. Fixed system\n// chrome / degraded-path strings emitted by code stay English (can't translate\n// an arbitrary value at runtime).\nexport const DEFAULT_OUTPUT_LANGUAGE = \"English\";\n\nexport function resolveOutputLanguage(): string {\n const raw = envText(\"NEGOTIUM_LANG\")?.trim();\n return raw && raw.length > 0 ? raw : DEFAULT_OUTPUT_LANGUAGE;\n}\n\n/** Browser.rs release tested with this Negotium version. */\nexport const BROWSER_RS_VERSION = \"v0.1.16\";\n/** Require the authenticated listener and the current Browser.rs tool contract. */\nexport const BROWSER_RS_MIN_SECURE_VERSION = \"0.1.15\";\n\nfunction versionAtLeast(actualVersion: string, minimumVersion: string): boolean {\n const actual = actualVersion.split(\".\").map(Number);\n const minimum = minimumVersion.split(\".\").map(Number);\n if (actual.some(Number.isNaN) || minimum.some(Number.isNaN)) return false;\n for (let index = 0; index < minimum.length; index += 1) {\n if ((actual[index] ?? 0) > (minimum[index] ?? 0)) return true;\n if ((actual[index] ?? 0) < (minimum[index] ?? 0)) return false;\n }\n return true;\n}\n\nfunction browserRsMeetsMinimumVersion(candidate: string): boolean {\n try {\n const output = execFileSync(candidate, [\"--version\"], {\n encoding: \"utf8\",\n timeout: 2_000,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n const match = output.match(/^browser-rs (\\d+)\\.(\\d+)\\.(\\d+)$/);\n if (!match) return false;\n return versionAtLeast(match.slice(1).join(\".\"), BROWSER_RS_MIN_SECURE_VERSION);\n } catch {\n return false;\n }\n}\n\n/**\n * Resolve the preferred Browser.rs engine without consulting PATH. The\n * versioned private location keeps different Negotium releases reproducible\n * and avoids changing a user's global browser-rs installation.\n */\nexport function resolveBrowserRsBin(envValue?: string): string | undefined {\n const override = envValue?.trim();\n if (\n !override &&\n !versionAtLeast(BROWSER_RS_VERSION.replace(/^v/, \"\"), BROWSER_RS_MIN_SECURE_VERSION)\n ) {\n return undefined;\n }\n const candidate = override\n ? resolve(override)\n : resolve(BINARIES_DIR, \"browser-rs\", BROWSER_RS_VERSION, \"browser-rs\");\n try {\n accessSync(candidate, constants.X_OK);\n return browserRsMeetsMinimumVersion(candidate) ? candidate : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport const BROWSER_RS_BIN = resolveBrowserRsBin(envText(\"NEGOTIUM_BROWSER_RS_BIN\"));\n\n// Managed Browser.rs terminates MCP transports and security policy itself.\nexport function resolveBrowserMcpBin(envValue?: string): string {\n const override = envValue?.trim();\n if (override) return resolve(override);\n return BROWSER_RS_BIN ?? resolve(BINARIES_DIR, \"browser-rs\", BROWSER_RS_VERSION, \"browser-rs\");\n}\n\nexport const PLAYWRIGHT_MCP_BIN = resolveBrowserMcpBin(envText(\"NEGOTIUM_BROWSER_MCP_BIN\"));\n\n// --- Browser egress proxy ---\n//\n// On a datacenter host (AWS) the browser's egress IP is a known cloud range,\n// so anti-bot services (Cloudflare, DataDome, reCAPTCHA) challenge or block it\n// far more than a residential IP would. Routing the automation browser through\n// a residential/ISP proxy moves the egress IP out of the datacenter range.\n//\n// Operators set BROWSER_PROXY_URL, e.g. http://user:pass@proxy.host:8080 or\n// socks5://proxy.host:1080. Credentials in the URL are split out because\n// Playwright takes them as separate fields. BROWSER_PROXY_BYPASS is an optional\n// comma-separated no-proxy list (e.g. \"localhost,127.0.0.1,*.internal\").\n//\n// NOTE: Chromium does not support authentication for SOCKS proxies — put\n// credentials only on http/https proxy URLs.\nexport type BrowserProxyConfig = {\n server: string;\n username?: string;\n password?: string;\n bypass?: string;\n};\n\nexport function resolveBrowserProxy(): BrowserProxyConfig | null {\n const raw = envText(\"BROWSER_PROXY_URL\");\n if (!raw) return null;\n let url: URL;\n try {\n url = new URL(raw);\n } catch {\n logger.warn({ raw }, \"Ignoring malformed BROWSER_PROXY_URL\");\n return null;\n }\n // Playwright wants the server without embedded credentials.\n const server = `${url.protocol}//${url.host}`;\n const proxy: BrowserProxyConfig = { server };\n if (url.username) proxy.username = decodeURIComponent(url.username);\n if (url.password) proxy.password = decodeURIComponent(url.password);\n const bypass = envText(\"BROWSER_PROXY_BYPASS\");\n if (bypass) proxy.bypass = bypass;\n return proxy;\n}\n\n// --- Node/tsx runtime for the `codex` agent's MCP servers ---\n//\n// codex 0.135's rmcp stdio MCP client cannot reliably complete the initialize\n// handshake with servers spawned via `bun` (the JSON-RPC initialize is\n// dropped/raced and no tools ever reach the model). Pure-node servers connect\n// reliably, so codex turns launch the SAME .ts servers via node + tsx instead\n// of `bun run`. claude/maestro keep using `bun run` (fast, native, unaffected).\n//\n// tsx transpiles .ts on the fly and resolves the `@/*` tsconfig path aliases,\n// but only when it can find the tsconfig — and MCP servers run with cwd set to\n// the user's workspace dir, not PROJECT_ROOT — so we pass TSX_TSCONFIG_PATH\n// explicitly via env. Requires package.json `\"type\": \"module\"` so the servers'\n// top-level `await` loads as ESM under node.\nexport const TSX_BIN = resolveDependencyBin(\"tsx\");\n/** In-process tsx loader used by Node MCP entrypoints (avoids the tsx CLI child process). */\nexport const TSX_LOADER = createRequire(import.meta.url).resolve(\"tsx\");\nexport const TSCONFIG_PATH = resolve(PROJECT_ROOT, \"tsconfig.json\");\n\nexport const SESSION_COMM_SERVER = resolve(PROJECT_ROOT, \"src/mcp/session-comm/server.ts\");\n\nexport const TASK_SERVER = resolve(PROJECT_ROOT, \"src/mcp/task-server.ts\");\nexport const BROWSER_MCP_SSE_PROXY_SERVER = resolve(\n PROJECT_ROOT,\n \"src/mcp/browser-sse-proxy-server.ts\",\n);\nexport const CANONICAL_MCP_PROXY_SERVER = resolve(\n PROJECT_ROOT,\n \"src/mcp/canonical-proxy-server.ts\",\n);\n\nexport const WIKI_SERVER = resolve(PROJECT_ROOT, \"src/mcp/wiki-server.ts\");\n\nexport const TOKEN_STATS_SERVER = resolve(PROJECT_ROOT, \"src/mcp/token-stats-server.ts\");\n\nexport const COMPACTION_LOG_SERVER = resolve(PROJECT_ROOT, \"src/mcp/compaction-log-server.ts\");\n\nexport const SYSTEM_HEALTH_SERVER = resolve(PROJECT_ROOT, \"src/mcp/system-health-server.ts\");\n\nexport const AGENT_HEALTH_SERVER = resolve(PROJECT_ROOT, \"src/mcp/agent-health-server.ts\");\n\nexport const BACKGROUND_BASH_SERVER = resolve(PROJECT_ROOT, \"src/mcp/background-bash-server.ts\");\n\nexport const VAULT_SERVER = resolve(PROJECT_ROOT, \"src/mcp/vault-server.ts\");\n\nexport const BG_BASH_BASE_PORT = parsePortEnv(process.env.BG_BASH_BASE_PORT, 9700);\nexport const BG_BASH_MAX_PORT = parsePortEnv(process.env.BG_BASH_MAX_PORT, 9799);\n\nfunction safeWorkspaceSegment(value: string, fallback: string): string {\n return safeRuntimePathSegment(value, fallback);\n}\n\n/** Resolve the shared filesystem workspace for an API topic. */\nexport function resolveTopicWorkspaceDir(topicId: string): string {\n return join(TOPIC_WORKSPACE_DIR, safeWorkspaceSegment(topicId, \"topic\"));\n}\n\nexport function isProductionEnv(): boolean {\n return process.env.NODE_ENV === \"production\";\n}\n\nfunction loadOrCreateLocalSecret(\n envKey: string,\n filename: string,\n options: { persistEnvValue?: boolean } = {},\n): string {\n const envValue = envText(envKey);\n const secretFile = resolve(SECRETS_DIR, filename);\n mkdirSync(dirname(secretFile), { recursive: true });\n if (envValue) {\n if (options.persistEnvValue) {\n writeFileSync(secretFile, `${envValue}\\n`, { mode: 0o600 });\n chmodSync(secretFile, 0o600);\n }\n return envValue;\n }\n\n if (existsSync(secretFile)) {\n const stored = readFileSync(secretFile, \"utf-8\").trim();\n if (stored) {\n chmodSync(secretFile, 0o600);\n return stored;\n }\n }\n\n const secret = randomBytes(32).toString(\"base64url\");\n try {\n writeFileSync(secretFile, `${secret}\\n`, { mode: 0o600, flag: \"wx\" });\n return secret;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n const stored = readFileSync(secretFile, \"utf-8\").trim();\n if (!stored) throw new Error(`Secret file exists but is empty: ${secretFile}`);\n chmodSync(secretFile, 0o600);\n return stored;\n }\n}\n\nexport const RUNTIME_MCP_SECRET = loadOrCreateLocalSecret(\n \"RUNTIME_MCP_SECRET\",\n \"runtime-mcp-secret\",\n);\n/** Local bearer token for the loopback node-control API. */\nexport const NODE_CONTROL_TOKEN = loadOrCreateLocalSecret(\n \"NEGOTIUM_CONTROL_TOKEN\",\n \"node-control-token\",\n);\nexport const VAULT_MASTER_KEY = loadOrCreateLocalSecret(\n \"NEGOTIUM_VAULT_MASTER_KEY\",\n \"vault-master-key\",\n { persistEnvValue: true },\n);\n// Agent/tool subprocesses inherit process.env. Keep the loaded key in this\n// process only so `env`/`ps` inside an agent workspace cannot reveal it.\ndelete process.env.NEGOTIUM_VAULT_MASTER_KEY;\n\n/** The node's single open port: runtime MCP endpoint + node API. */\nexport const NEGOTIUM_PORT = parseInt(process.env.NEGOTIUM_PORT || \"7777\", 10);\nexport const hostname = process.env.HOSTNAME || \"127.0.0.1\";\n\n// Persistent state (survives restarts, long-lived)\nexport const DATA_DIR = resolveLocalStateDir(\"NEGOTIUM_DATA_DIR\", \"data\");\nexport const LOG_DIR = resolveLocalStateDir(\"NEGOTIUM_LOG_DIR\", \"logs\");\nexport const UPLOADS_DIR = resolve(DATA_DIR, \"uploads\");\nexport const VAULT_DIR = resolve(DATA_DIR, \"vault\");\n// SESSIONS_DB_PATH env override lets tests point the DB singleton at a temp file.\nexport const SESSIONS_DB = process.env.SESSIONS_DB_PATH\n ? resolve(process.env.SESSIONS_DB_PATH)\n : resolve(DATA_DIR, \"sessions.db\");\nexport const DEBUG_FILE = resolve(DATA_DIR, \"debug-users.json\");\nexport const USERS_LOG_DIR = resolve(DATA_DIR, \"users\");\n\n// Runtime IPC queues (transient, safe to clear on restart)\n/** @deprecated Use the runtime layout name; NEGOTIUM_RUN_DIR remains a compatibility override. */\nexport const RUN_DIR = resolveLocalStateDir(\"NEGOTIUM_RUN_DIR\", \"runtime\");\nexport const RUNTIME_DIR = RUN_DIR;\nexport const PROGRESS_DIR = resolve(RUN_DIR, \"progress\");\nexport const DM_CMD_DIR = resolve(RUN_DIR, \"dm-commands\");\nexport const DM_RESP_DIR = resolve(RUN_DIR, \"dm-responses\");\nexport const SESSION_INBOX_DIR = resolve(RUN_DIR, \"session-inbox\");\nexport const SESSION_ASKS_DIR = resolve(RUN_DIR, \"session-asks\");\nexport const PLAYWRIGHT_BASE_PORT = parsePortEnv(process.env.PLAYWRIGHT_BASE_PORT, 9100);\nexport const PLAYWRIGHT_MAX_PORT = parsePortEnv(process.env.PLAYWRIGHT_MAX_PORT, 9499);\nexport const PLAYWRIGHT_PORTS_DIR = resolve(RUN_DIR, \"playwright-ports\");\nmkdirSync(STATE_DIR, { recursive: true });\nmkdirSync(DATA_DIR, { recursive: true });\nmkdirSync(UPLOADS_DIR, { recursive: true });\nmkdirSync(VAULT_DIR, { recursive: true, mode: 0o700 });\nmkdirSync(LOG_DIR, { recursive: true });\nmkdirSync(PROGRESS_DIR, { recursive: true });\nmkdirSync(DM_CMD_DIR, { recursive: true });\nmkdirSync(DM_RESP_DIR, { recursive: true });\nmkdirSync(SESSION_INBOX_DIR, { recursive: true });\nmkdirSync(SESSION_ASKS_DIR, { recursive: true });\nmkdirSync(PLAYWRIGHT_PORTS_DIR, { recursive: true });\nmkdirSync(WORKSPACE_DIR, { recursive: true });\nmkdirSync(TOPIC_WORKSPACE_DIR, { recursive: true });\nmkdirSync(SHARED_WIKI_DIR, { recursive: true });\nmkdirSync(CRON_WORKSPACE_DIR, { recursive: true });\nmkdirSync(CONTEXTS_DIR, { recursive: true });\nmkdirSync(DM_WORKSPACE_DIR, { recursive: true });\nmkdirSync(SESSION_WORKSPACE_DIR, { recursive: true });\nmkdirSync(BROWSER_DIR, { recursive: true });\nmkdirSync(BROWSER_PROFILES_DIR, { recursive: true });\nmkdirSync(BINARIES_DIR, { recursive: true });\nmkdirSync(SECRETS_DIR, { recursive: true, mode: 0o700 });\n\n/** Stale threshold for active-query state files (crash recovery) */\nexport const ACTIVE_QUERY_STALE_MS = 10 * 60 * 1000; // 10 minutes\n\nexport const AGENTS_PROMPTS_DIR = resolve(PROJECT_ROOT, \"src/prompts/agents\");\nexport const RESOURCES_DIR = resolve(PROJECT_ROOT, \"src/resources\");\n\n/** Returns process.env without CLAUDECODE, to prevent nested claude-code detection in subprocesses. */\nexport function getCleanEnv(): NodeJS.ProcessEnv {\n const env = { ...process.env };\n delete env.CLAUDECODE;\n return env;\n}\n\nexport const FILE_EXTENSIONS_REGEX =\n /(?:\\/[^\\s\"'<>|*?[\\]]+\\.(?:png|jpg|jpeg|gif|webp|svg|pdf|csv|xlsx|xls|json|txt|md|html|zip|py|js|ts|tsx|jsx|css|xml|yaml|yml|docx|pptx))/gi;\n\nexport const FILE_TAG_REGEX = /\\[FILE:(\\/[^\\]]+)\\]/gi;\n\n// Canonical Claude model IDs — update here when Anthropic releases new versions\nexport const MODEL_SONNET = \"claude-sonnet-5\";\nexport const MODEL_OPUS = \"claude-opus-5\";\nexport const MODEL_HAIKU = \"claude-haiku-4-5-20251001\";\nexport const MODEL_FABLE = \"claude-fable-5\"; // Mythos-class, announced 2026-06-09\n\n// DeepSeek V4 (released 2026-04-24). API is OpenAI-compatible at\n// https://api.deepseek.com/v1/chat/completions; thinking mode is enabled via\n// `extra_body.thinking.type` + `reasoning_effort`. Legacy `deepseek-chat` /\n// `deepseek-reasoner` are deprecated 2026-07-24.\nexport const MODEL_DEEPSEEK_V4_PRO = \"deepseek-v4-pro\";\nexport const MODEL_DEEPSEEK_V4_FLASH = \"deepseek-v4-flash\";\n\n// Agent + model defaults split by session role. FALLBACK_* is the shared base;\n// SESSION_* overrides topic + ephemeral; GATEWAY_* overrides dm + manager.\n// DEFAULT_* is accepted as a legacy alias during the env migration window.\nexport const FALLBACK_AGENT: AgentKind = resolveAgentEnv(\n \"FALLBACK_AGENT\",\n \"maestro\",\n \"DEFAULT_AGENT\",\n);\nexport const SESSION_AGENT: AgentKind = resolveAgentEnv(\"SESSION_AGENT\", FALLBACK_AGENT);\nexport const GATEWAY_AGENT: AgentKind = resolveAgentEnv(\"GATEWAY_AGENT\", FALLBACK_AGENT);\n\nexport const FALLBACK_MODEL = envText(\"FALLBACK_MODEL\") ?? envText(\"DEFAULT_MODEL\");\n\nfunction resolveModelEnv(envKey: string, agentConst: AgentKind): string | undefined {\n return envText(envKey) ?? (agentConst === FALLBACK_AGENT ? FALLBACK_MODEL : undefined);\n}\n\nexport const SESSION_MODEL = resolveModelEnv(\"SESSION_MODEL\", SESSION_AGENT);\nexport const GATEWAY_MODEL = resolveModelEnv(\"GATEWAY_MODEL\", GATEWAY_AGENT);\n\n/** Resolve the effective display/default model for a topic (session context).\n * Applies the session model override only when that role owns the agent;\n * otherwise each registry's native default stays authoritative. */\nexport function resolveDefaultModel(agent: string, registryDefaultModel: string): string {\n return agent === SESSION_AGENT && SESSION_MODEL ? SESSION_MODEL : registryDefaultModel;\n}\n\n// ── External tool binaries + media pipeline env ───────────────────\n// (src/media/* 에서 사용. 미설정 시 fallback 의미는 기존 그대로:\n// FFMPEG_BIN은 text-extractor에서 필수(undefined면 spawn 시점 실패),\n// video.ts에서는 PATH의 ffmpeg/ffprobe로 fallback.)\nexport const FFMPEG_BIN = envText(\"FFMPEG_BIN\");\nexport const FFPROBE_BIN = envText(\"FFPROBE_BIN\");\nexport const PYTHON_BIN = envText(\"PYTHON_BIN\") ?? \"python3\";\nexport const FASTER_WHISPER_WRAPPER =\n envText(\"FASTER_WHISPER_WRAPPER\") ?? resolve(PROJECT_ROOT, \"scripts/faster-whisper-wrapper.py\");\nexport const WHISPER_MODEL = envText(\"WHISPER_MODEL_FILE\") ?? \"turbo\";\nexport const TESSERACT_BIN = envText(\"TESSERACT_BIN\") ?? \"tesseract\";\nexport const PDFTOTEXT_BIN = envText(\"PDFTOTEXT_BIN\") ?? \"pdftotext\";\n\n// Max tell_session relay depth from origin user. ask_session forks reset to\n// depth=0, so this only caps tell_session chains. Override via MAX_TELL_DEPTH\n// (positive int); defaults to 20 when unset or invalid.\nconst _envMaxTellDepth = Number.parseInt(process.env.MAX_TELL_DEPTH ?? \"\", 10);\nexport const MAX_TELL_DEPTH =\n Number.isInteger(_envMaxTellDepth) && _envMaxTellDepth > 0 ? _envMaxTellDepth : 20;\n\n/** Codex CLI auth file. 호출 시점에 env를 읽는다 — 테스트가 런타임에\n * NEGOTIUM_CODEX_AUTH_FILE을 바꾸므로 모듈 로드 상수로 만들면 안 된다. */\nexport function codexAuthFilePath(): string {\n return process.env.NEGOTIUM_CODEX_AUTH_FILE || join(homedir(), \".codex\", \"auth.json\");\n}\n\n// System defaults moved to per-agent registries\n// (`src/agents/{claude,codex}-registry.ts`). Read via\n// `getRegistry(agent).defaultModel` / `.defaultEffort`.\n\n// MCP server builders -> src/platform/mcp-config.ts\n",
7
7
  "import { resolve } from \"node:path\";\n\nexport type RuntimeEnvironment = Readonly<Record<string, string | undefined>>;\n\nexport function readEnvText(env: RuntimeEnvironment, key: string): string | undefined {\n const value = env[key]?.trim();\n return value || undefined;\n}\n\nexport function parseRuntimePort(value: string | undefined, fallback: number): number {\n if (!value) return fallback;\n const port = Number.parseInt(value, 10);\n return Number.isInteger(port) && port > 0 && port <= 65_535 ? port : fallback;\n}\n\nexport function resolveRuntimeStateDir(options: {\n env: RuntimeEnvironment;\n envKey: string;\n fallbackRoot: string;\n fallbackName: string;\n}): string {\n const configured = readEnvText(options.env, options.envKey);\n return configured ? resolve(configured) : resolve(options.fallbackRoot, options.fallbackName);\n}\n\nexport function safeRuntimePathSegment(value: string, fallback: string, maxLength = 160): string {\n const cleaned = value\n .trim()\n .replace(/[^A-Za-z0-9._-]/g, \"_\")\n .replace(/^_+|_+$/g, \"\")\n .slice(0, maxLength);\n return cleaned || fallback;\n}\n",
8
8
  "import pino from \"pino\";\n\nexport interface StdioLoggerOptions {\n level?: string;\n development?: boolean;\n}\n\n/**\n * Always write logs to stderr (fd 2), never stdout.\n *\n * MCP servers under `src/mcp/**` run as stdio subprocesses where stdout is the\n * JSON-RPC transport channel. A single log line on stdout corrupts the next\n * message and the MCP client closes the transport (\"Transport closed\"). The\n * main bot process is also fine with stderr — pm2 captures both streams.\n *\n * In dev mode pino spawns a `pino-pretty` worker that owns its own sink, so we\n * pass `destination: 2` through transport.options. In prod (no transport) the\n * second arg to `pino()` sets the destination directly.\n */\nexport function createStdioLogger(options: StdioLoggerOptions = {}) {\n const development = options.development ?? process.env.NODE_ENV === \"development\";\n return pino(\n {\n level: options.level ?? process.env.LOG_LEVEL ?? \"info\",\n transport: development\n ? {\n target: \"pino-pretty\",\n options: {\n colorize: true,\n translateTime: \"SYS:yyyy-mm-dd HH:MM:ss\",\n destination: 2,\n },\n }\n : undefined,\n },\n pino.destination(2),\n );\n}\n\nexport type StdioLogger = ReturnType<typeof createStdioLogger>;\n\nexport const logger = createStdioLogger();\n",
9
9
  "/**\n * Common context carried through the attachment/prompt-build pipeline.\n * Used by buildPromptFromMessage and related helpers.\n */\nexport interface SessionContext {\n userId: number;\n topicName?: string;\n userDir?: string;\n sessionType?: \"dm\" | \"forum\" | \"ephemeral\" | \"manager\" | \"cron\";\n}\n\nexport interface TokenUsage {\n /** Aggregate billable input across every model call made during this turn. */\n inputTokens: number;\n outputTokens: number;\n cacheCreationInputTokens?: number;\n cacheReadInputTokens?: number;\n /** Provider-reported query cost when available. */\n costUsd?: number;\n /** Tokens occupied by the latest model call, not aggregate turn spend. */\n contextTokens?: number;\n /** Provider-reported context window for the latest model call. */\n contextWindow?: number;\n}\n\n/** Agent identifier — one of the supported AI provider backends. */\nexport type AgentKind = \"maestro\" | \"claude\" | \"codex\";\n\nexport const SUPPORTED_AGENTS: readonly AgentKind[] = [\"maestro\", \"claude\", \"codex\"] as const;\n\nexport function isAgentKind(value: unknown): value is AgentKind {\n return typeof value === \"string\" && (SUPPORTED_AGENTS as readonly string[]).includes(value);\n}\n\n/**\n * Per-agent supported reasoning efforts. Single source of truth for both the\n * `EffortLevel` type and each registry's `validEfforts` runtime list — the\n * registries import these directly so adding a value in one place\n * propagates to validation, footer rendering, and zod enums.\n *\n * Claude SDK rejects 'minimal'; Codex SDK rejects 'max'. The two sets\n * intersect on low/medium/high/xhigh. Maestro (TS port) currently piggybacks\n * on the Anthropic provider, so its efforts mirror the Claude set; this can\n * narrow per-provider once Phase 5 lands.\n *\n * 'minimal' removed from codex: Codex API rejects it when default tools\n * (image_gen, web_search) are active, making agent sessions unusable.\n */\nexport const CLAUDE_EFFORT_VALUES = [\"low\", \"medium\", \"high\", \"xhigh\", \"max\"] as const;\nexport const CODEX_EFFORT_VALUES = [\"low\", \"medium\", \"high\", \"xhigh\", \"max\"] as const;\nexport const MAESTRO_EFFORT_VALUES = [\"low\", \"medium\", \"high\", \"xhigh\", \"max\"] as const;\n\nexport type EffortLevel =\n | (typeof CLAUDE_EFFORT_VALUES)[number]\n | (typeof CODEX_EFFORT_VALUES)[number]\n | (typeof MAESTRO_EFFORT_VALUES)[number];\n\n/**\n * Runtime iteration list (used by zod enums and any callers that need to\n * loop over every accepted value). Manually ordered for readability; the\n * `satisfies` check fails the build if an entry here isn't covered by the\n * per-agent unions above.\n */\nexport const EFFORT_VALUES = [\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\",\n \"max\",\n] as const satisfies readonly EffortLevel[];\n\n/**\n * Normalized events yielded by any agent provider (claudeProvider, codexProvider).\n * The handler/event-processor consumes these without caring which backend produced them.\n *\n * `user_message` is the lone \"into-the-log\" variant — no provider yields it.\n * The query handler writes it directly to the conversation log right before\n * `runAgent()` starts, so cross-agent rollout reconstruction can pair every\n * assistant turn with the user prompt that triggered it. Consumers that only\n * react to provider output (e.g. processAgentEvent) can safely ignore it.\n */\n/**\n * Wire-safe projection of one task, carried by the `tasks` UnifiedEvent.\n *\n * This is also the on-disk shape of Otium's shared task store, so claude,\n * codex, and maestro render the same live panel from the same source of truth.\n */\nexport interface TaskSnapshot {\n id: string;\n subject: string;\n status: \"pending\" | \"in_progress\" | \"completed\";\n /** Task ids this one is blocked by; omitted when empty. */\n blockedBy?: string[];\n /** Present-continuous label for spinners, when set. */\n activeForm?: string;\n /** Owner / agent name for multi-agent runs, when set. */\n owner?: string;\n}\n\nexport type UnifiedEvent =\n | {\n type: \"user_message\";\n content: string;\n synthetic?: \"compaction\";\n /** Total ordered user submissions represented by one preempting provider turn. */\n consecutiveBatchSize?: number;\n /** Zero-based position within the ordered preemption batch. */\n consecutiveBatchIndex?: number;\n }\n | { type: \"session\"; sessionId: string }\n | {\n type: \"tool_use\";\n name: string;\n input: Record<string, unknown>;\n /** Provider-assigned id so the client can match tool_use→tool_result pairs. */\n toolUseId?: string;\n }\n | { type: \"tool_progress\"; toolName: string; elapsed: number }\n | { type: \"tool_use_summary\"; summary: string }\n // Provider reasoning/thinking summary text (Codex `reasoning` items; Claude\n // extended-thinking). Surfaced so background runs (cron/archiver) show the\n // agent's thought process, not just tool calls.\n | { type: \"reasoning\"; content: string }\n // Full task-list snapshot (replace, not delta) from Otium's shared task\n // store. Provider-native task/todo stores are not authoritative.\n | { type: \"tasks\"; tasks: TaskSnapshot[] }\n | {\n type: \"tool_result\";\n toolUseId: string;\n content: string;\n /** True when the tool call failed; absent/false means success. */\n isError?: boolean;\n metadata?: {\n truncatedForModel: boolean;\n originalBytes: number;\n returnedBytes: number;\n omittedBytes?: number;\n outputPath?: string;\n };\n }\n | { type: \"text_delta\"; content: string }\n | { type: \"text\"; content: string }\n | { type: \"result\"; content: string; stopReason: string; usage?: TokenUsage }\n | { type: \"file\"; path: string; source: string; origin: \"tag\" | \"extension\" }\n | {\n type: \"error\";\n content: string;\n usage?: TokenUsage;\n code?: \"budget_exceeded\";\n }\n | { type: \"status\"; content: string };\n\nexport interface AgentInputAttachment {\n id: string;\n type: \"image\" | \"file\" | \"audio\";\n filename: string;\n mimeType: string;\n sizeBytes: number;\n path: string;\n}\n\n/** Worker-side runtime tools proxy user-facing state back to the canonical\n * hub topic identified here. */\nexport interface PeerRuntimeBridgeContext {\n hubCellId: string;\n hostTopicId: string;\n hostQueryId: string;\n canSpawnSubagents: boolean;\n}\n\nexport interface AgentQueryOptions {\n agent: AgentKind;\n prompt: string;\n attachments?: AgentInputAttachment[];\n sessionId?: string | null;\n cwd: string;\n systemPrompt: string;\n userId?: string;\n session?: string;\n playwrightPort?: number;\n playwrightCapability?: string;\n bgBashPort?: number;\n sessionType?: \"dm\" | \"forum\" | \"ephemeral\" | \"manager\" | \"cron\";\n /** API topic id (REST/WS world). Carries per-query topic context for MCP servers. */\n topicId?: string;\n /** Direct parent topic id when this query runs inside a subagent room. */\n subagentParentTopicId?: string;\n /** API query id for the currently running turn. Used by runtime MCP tools. */\n queryId?: string;\n /** Optional wiki-memory topic id. Derived topics use their root origin here\n * while other per-topic MCP servers keep `topicId` bound to the live room. */\n wikiTopicId?: string;\n /** Whether self-config MCP may enqueue an automatic continue turn after set_* changes. */\n autoContinue?: boolean;\n /** Expose Otium-only visual panel tools for this turn. Default-deny. */\n visualTools?: boolean;\n /** Expose adapter-backed file-delivery tools for this turn. Default-deny. */\n fileDeliveryTools?: boolean;\n abortController?: AbortController;\n model?: string;\n /** Provider-side hard budget when the selected SDK supports one. */\n maxBudgetUsd?: number;\n depth?: number;\n agents?: Record<\n string,\n {\n description: string;\n prompt: string;\n model?: string;\n tools?: string[];\n maxTurns?: number;\n effort?: EffortLevel | number;\n }\n >;\n effort?: EffortLevel;\n /**\n * Per-API-call `max_tokens` ceiling on the assistant's output. Wired\n * through to the underlying provider request body for every agent\n * (claude/codex/maestro). Omit to inherit each provider SDK's per-model\n * default — for maestro that's the v0.1.21+ `getNativeMaxOutputTokens`\n * catalog (deepseek-pro=64K, kimi-k3=64K, kimi-k2.7-code=32K).\n *\n * Pass an explicit number when a specific topic / surface needs a tighter\n * latency cap or a higher ceiling for long-form generation (legal\n * report writing, multi-K Write/Edit file bodies). Pre-0.1.21 maestro\n * builds silently clamped at 4096 and truncated outputs mid-string;\n * setting this field is now the supported way to lift that ceiling.\n */\n maxTokens?: number;\n /**\n * v0.1.22+: Claude-Code-style deferred tool catalog + `ToolSearch` built-in.\n *\n * Wired straight through to `maestro-agent-sdk`'s\n * `AgentQueryOptions.enableToolSearch`. When `true`, the maestro provider\n * registers every MCP tool as deferred — schemas stay off the wire until\n * the model promotes them via `ToolSearch(\"select:Name1,Name2\")` or\n * `ToolSearch(\"keyword\")`. Active set persists across resume.\n *\n * Otium's maestro provider supplies `true` when the caller leaves this\n * option unset, because most forum turns carry enough MCP surface for the\n * reminder-token savings to outweigh the first-use `ToolSearch` round-trip.\n * Callers can still pass `false` per call when a narrow surface or\n * latency-sensitive workflow is better served by eager MCP schemas.\n *\n * No-op for claude / codex agents — they have their own deferred-tool\n * machinery owned by their respective SDKs.\n */\n enableToolSearch?: boolean;\n /**\n * Bounded tool results with the full output kept on disk.\n *\n * Wired to `maestro-agent-sdk`'s `AgentQueryOptions.toolResultTruncation`.\n * The SDK caps a string tool result, writes the untruncated bytes to a file,\n * and splices an opaque `maestro://tool-output/<id>` reference into the text\n * that the `ReadToolOutput` tool can page back through.\n *\n * The maestro provider enables it by default. Left unset, every tool result\n * — a whole-file `Read`, a wide `Grep`, a `WebFetch` of a large page —\n * entered the context at full size, and the `\"ReadToolOutput\"` entry in the\n * provider's builtin list was dead, because the SDK only registers that tool\n * when truncation is on with `saveFullOutput`.\n *\n * Pass an explicit object to tune the budget, or `{ enabled: false }` for a\n * call whose tool results must arrive whole.\n *\n * No-op for claude / codex agents — their SDKs do their own truncation.\n */\n toolResultTruncation?: {\n enabled?: boolean;\n maxBytes?: number;\n headBytes?: number;\n tailBytes?: number;\n saveFullOutput?: boolean;\n outputDir?: string;\n retentionDays?: number;\n ignoreTools?: string[];\n };\n /**\n * Claude-Code-compatible exact tool denylist. Maestro v0.1.42+ hides these\n * tools from provider schemas / ToolSearch and blocks dispatch if a stale\n * call still arrives. Claude maps this to its SDK option. Codex does not\n * support this name-based list; its provider-native multi-agent tool family\n * is disabled separately through the Codex feature config.\n */\n disallowedTools?: readonly string[];\n /**\n * Hard provider tool policy for auxiliary model calls.\n *\n * `\"none\"` removes MCP and provider-native tools before the request is\n * dispatched. `\"compaction-log\"` keeps provider-native tools disabled and\n * exposes only the host-scoped immutable log reader. Use these for untrusted\n * transcript transforms; reacting to tool events after dispatch is not a\n * security boundary.\n */\n toolPolicy?: \"none\" | \"compaction-log\";\n mcpEnabled?: string[] | null;\n peerBridge?: PeerRuntimeBridgeContext;\n mcpExtra?: Record<string, unknown>;\n /**\n * true for silent fork runs generating ask_session replies — restricts session-comm\n * outbound tools (ask/tell/abort) so the forked session can only produce text\n */\n silent?: boolean;\n}\n\n/** State file written to data/users/{userId}/active-queries/{topicId}.json while a query is running. */\nexport interface QueryState {\n topicId?: string;\n topicName?: string;\n task?: string; // first 100 chars of prompt, newlines normalized\n since: string; // ISO timestamp\n}\n",
10
10
  "export const delay = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));\n",
11
11
  "import { createHmac } from \"node:crypto\";\n\nexport function deriveBgBashContextCapability(\n runtimeCapability: string,\n userId: string,\n topic: string,\n): string {\n return createHmac(\"sha256\", runtimeCapability).update(`${userId}\\0${topic}`).digest(\"hex\");\n}\n"
12
12
  ],
13
- "mappings": "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",
14
- "debugId": "450027B0CC69815A64756E2164756E21",
13
+ "mappings": "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",
14
+ "debugId": "C4E26CE8FA80E8DB64756E2164756E21",
15
15
  "names": []
16
16
  }
@@ -103,10 +103,14 @@ function parsePortEnv(envValue, fallback) {
103
103
  var WORKSPACE_DIR = resolveLocalStateDir("NEGOTIUM_WORKSPACE_DIR", "workspace");
104
104
  var TOPIC_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "topics");
105
105
  var SHARED_WIKI_DIR = resolve(WORKSPACE_DIR, "wiki");
106
- var CONTEXTS_DIR = resolve(WORKSPACE_DIR, "contexts");
107
- var BROWSER_PROFILES_DIR = resolve(WORKSPACE_DIR, "browser-profiles");
108
- var DM_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "dm");
109
- var SESSION_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "sessions");
106
+ var CRON_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "cron");
107
+ var BROWSER_DIR = resolveLocalStateDir("NEGOTIUM_BROWSER_DIR", "browser");
108
+ var BROWSER_PROFILES_DIR = resolve(BROWSER_DIR, "profiles");
109
+ var BINARIES_DIR = resolve(STATE_DIR, "binaries");
110
+ var SECRETS_DIR = resolve(STATE_DIR, "secrets");
111
+ var CONTEXTS_DIR = resolve(STATE_DIR, "data", "contexts");
112
+ var DM_WORKSPACE_DIR = resolve(STATE_DIR, "data", "dm");
113
+ var SESSION_WORKSPACE_DIR = resolve(STATE_DIR, "data", "sessions");
110
114
  var CLAUDE_EXECUTABLE_ENV = envText("NEGOTIUM_CLAUDE_EXECUTABLE");
111
115
  var CLAUDE_EXECUTABLE = CLAUDE_EXECUTABLE_ENV ? resolve(CLAUDE_EXECUTABLE_ENV) : undefined;
112
116
  var BROWSER_RS_VERSION = "v0.1.16";
@@ -144,7 +148,7 @@ function resolveBrowserRsBin(envValue) {
144
148
  if (!override && !versionAtLeast(BROWSER_RS_VERSION.replace(/^v/, ""), BROWSER_RS_MIN_SECURE_VERSION)) {
145
149
  return;
146
150
  }
147
- const candidate = override ? resolve(override) : resolve(STATE_DIR, "bin", "browser-rs", BROWSER_RS_VERSION, "browser-rs");
151
+ const candidate = override ? resolve(override) : resolve(BINARIES_DIR, "browser-rs", BROWSER_RS_VERSION, "browser-rs");
148
152
  try {
149
153
  accessSync(candidate, constants.X_OK);
150
154
  return browserRsMeetsMinimumVersion(candidate) ? candidate : undefined;
@@ -157,7 +161,7 @@ function resolveBrowserMcpBin(envValue) {
157
161
  const override = envValue?.trim();
158
162
  if (override)
159
163
  return resolve(override);
160
- return BROWSER_RS_BIN ?? resolve(STATE_DIR, "bin", "browser-rs", BROWSER_RS_VERSION, "browser-rs");
164
+ return BROWSER_RS_BIN ?? resolve(BINARIES_DIR, "browser-rs", BROWSER_RS_VERSION, "browser-rs");
161
165
  }
162
166
  var PLAYWRIGHT_MCP_BIN = resolveBrowserMcpBin(envText("NEGOTIUM_BROWSER_MCP_BIN"));
163
167
  function resolveBrowserProxy() {
@@ -200,7 +204,7 @@ var BG_BASH_BASE_PORT = parsePortEnv(process.env.BG_BASH_BASE_PORT, 9700);
200
204
  var BG_BASH_MAX_PORT = parsePortEnv(process.env.BG_BASH_MAX_PORT, 9799);
201
205
  function loadOrCreateLocalSecret(envKey, filename, options = {}) {
202
206
  const envValue = envText(envKey);
203
- const secretFile = resolve(STATE_DIR, filename);
207
+ const secretFile = resolve(SECRETS_DIR, filename);
204
208
  mkdirSync(dirname(secretFile), { recursive: true });
205
209
  if (envValue) {
206
210
  if (options.persistEnvValue) {
@@ -240,10 +244,12 @@ var NEGOTIUM_PORT = parseInt(process.env.NEGOTIUM_PORT || "7777", 10);
240
244
  var hostname = process.env.HOSTNAME || "127.0.0.1";
241
245
  var DATA_DIR = resolveLocalStateDir("NEGOTIUM_DATA_DIR", "data");
242
246
  var LOG_DIR = resolveLocalStateDir("NEGOTIUM_LOG_DIR", "logs");
247
+ var UPLOADS_DIR = resolve(DATA_DIR, "uploads");
248
+ var VAULT_DIR = resolve(DATA_DIR, "vault");
243
249
  var SESSIONS_DB = process.env.SESSIONS_DB_PATH ? resolve(process.env.SESSIONS_DB_PATH) : resolve(DATA_DIR, "sessions.db");
244
250
  var DEBUG_FILE = resolve(DATA_DIR, "debug-users.json");
245
251
  var USERS_LOG_DIR = resolve(DATA_DIR, "users");
246
- var RUN_DIR = resolveLocalStateDir("NEGOTIUM_RUN_DIR", "run");
252
+ var RUN_DIR = resolveLocalStateDir("NEGOTIUM_RUN_DIR", "runtime");
247
253
  var PROGRESS_DIR = resolve(RUN_DIR, "progress");
248
254
  var DM_CMD_DIR = resolve(RUN_DIR, "dm-commands");
249
255
  var DM_RESP_DIR = resolve(RUN_DIR, "dm-responses");
@@ -254,6 +260,8 @@ var PLAYWRIGHT_MAX_PORT = parsePortEnv(process.env.PLAYWRIGHT_MAX_PORT, 9499);
254
260
  var PLAYWRIGHT_PORTS_DIR = resolve(RUN_DIR, "playwright-ports");
255
261
  mkdirSync(STATE_DIR, { recursive: true });
256
262
  mkdirSync(DATA_DIR, { recursive: true });
263
+ mkdirSync(UPLOADS_DIR, { recursive: true });
264
+ mkdirSync(VAULT_DIR, { recursive: true, mode: 448 });
257
265
  mkdirSync(LOG_DIR, { recursive: true });
258
266
  mkdirSync(PROGRESS_DIR, { recursive: true });
259
267
  mkdirSync(DM_CMD_DIR, { recursive: true });
@@ -264,10 +272,14 @@ mkdirSync(PLAYWRIGHT_PORTS_DIR, { recursive: true });
264
272
  mkdirSync(WORKSPACE_DIR, { recursive: true });
265
273
  mkdirSync(TOPIC_WORKSPACE_DIR, { recursive: true });
266
274
  mkdirSync(SHARED_WIKI_DIR, { recursive: true });
275
+ mkdirSync(CRON_WORKSPACE_DIR, { recursive: true });
267
276
  mkdirSync(CONTEXTS_DIR, { recursive: true });
268
- mkdirSync(BROWSER_PROFILES_DIR, { recursive: true });
269
277
  mkdirSync(DM_WORKSPACE_DIR, { recursive: true });
270
278
  mkdirSync(SESSION_WORKSPACE_DIR, { recursive: true });
279
+ mkdirSync(BROWSER_DIR, { recursive: true });
280
+ mkdirSync(BROWSER_PROFILES_DIR, { recursive: true });
281
+ mkdirSync(BINARIES_DIR, { recursive: true });
282
+ mkdirSync(SECRETS_DIR, { recursive: true, mode: 448 });
271
283
  var ACTIVE_QUERY_STALE_MS = 10 * 60 * 1000;
272
284
  var AGENTS_PROMPTS_DIR = resolve(PROJECT_ROOT, "src/prompts/agents");
273
285
  var RESOURCES_DIR = resolve(PROJECT_ROOT, "src/resources");
@@ -741,7 +753,6 @@ import {
741
753
  existsSync as existsSync2,
742
754
  mkdirSync as mkdirSync4,
743
755
  readFileSync as readFileSync2,
744
- renameSync,
745
756
  rmSync,
746
757
  unlinkSync as unlinkSync2,
747
758
  writeFileSync as writeFileSync2
@@ -862,12 +873,12 @@ import { join as join4 } from "path";
862
873
  import { chmodSync as chmodSync2, mkdirSync as mkdirSync3 } from "fs";
863
874
  import { join as join3 } from "path";
864
875
 
865
- // ../../packages/core/src/storage/vault-crypto.ts
876
+ // ../../packages/core/src/storage/vault-crypto-core.ts
866
877
  import { createCipheriv, createDecipheriv, createHash, randomBytes as randomBytes2 } from "crypto";
867
878
  var ENVELOPE_PREFIX = "otium-vault:v1:";
868
879
  var IV_BYTES = 12;
869
880
  var KEY_BYTES = 32;
870
- function encryptionKey(masterKey = VAULT_MASTER_KEY) {
881
+ function encryptionKey(masterKey) {
871
882
  return createHash("sha256").update("otium-vault-value-v1\x00", "utf8").update(masterKey, "utf8").digest().subarray(0, KEY_BYTES);
872
883
  }
873
884
  function aad(userId, key) {
@@ -876,7 +887,7 @@ function aad(userId, key) {
876
887
  function isEncryptedVaultValue(value) {
877
888
  return value.startsWith(ENVELOPE_PREFIX);
878
889
  }
879
- function encryptVaultValue(userId, key, value, masterKey = VAULT_MASTER_KEY) {
890
+ function encryptVaultValueWithKey(userId, key, value, masterKey) {
880
891
  const iv = randomBytes2(IV_BYTES);
881
892
  const cipher = createCipheriv("aes-256-gcm", encryptionKey(masterKey), iv);
882
893
  cipher.setAAD(aad(userId, key));
@@ -884,7 +895,7 @@ function encryptVaultValue(userId, key, value, masterKey = VAULT_MASTER_KEY) {
884
895
  const tag = cipher.getAuthTag();
885
896
  return `${ENVELOPE_PREFIX}${iv.toString("base64url")}.${ciphertext.toString("base64url")}.${tag.toString("base64url")}`;
886
897
  }
887
- function decryptVaultValue(userId, key, storedValue, masterKey = VAULT_MASTER_KEY) {
898
+ function decryptVaultValueWithKey(userId, key, storedValue, masterKey) {
888
899
  if (!isEncryptedVaultValue(storedValue)) {
889
900
  return { value: storedValue, legacyPlaintext: true };
890
901
  }
@@ -906,6 +917,14 @@ function decryptVaultValue(userId, key, storedValue, masterKey = VAULT_MASTER_KE
906
917
  return { value: plaintext.toString("utf8"), legacyPlaintext: false };
907
918
  }
908
919
 
920
+ // ../../packages/core/src/storage/vault-crypto.ts
921
+ function encryptVaultValue(userId, key, value, masterKey = VAULT_MASTER_KEY) {
922
+ return encryptVaultValueWithKey(userId, key, value, masterKey);
923
+ }
924
+ function decryptVaultValue(userId, key, storedValue, masterKey = VAULT_MASTER_KEY) {
925
+ return decryptVaultValueWithKey(userId, key, storedValue, masterKey);
926
+ }
927
+
909
928
  // ../../packages/core/src/storage/vault.ts
910
929
  var vaultDb;
911
930
  var vaultMasterKey = VAULT_MASTER_KEY;
@@ -943,8 +962,9 @@ function initializeVaultDatabase(database) {
943
962
  }
944
963
  }
945
964
  function openVaultDatabase(dataDir) {
946
- const path = join3(dataDir, "vault.db");
947
- mkdirSync3(dataDir, { recursive: true });
965
+ const vaultDir = join3(dataDir, "vault");
966
+ const path = join3(vaultDir, "vault.db");
967
+ mkdirSync3(vaultDir, { recursive: true, mode: 448 });
948
968
  const database = new Database(path, { create: true });
949
969
  chmodSync2(path, 384);
950
970
  initializeVaultDatabase(database);
@@ -1263,32 +1283,6 @@ function getTopicBrowserProfile(topicId) {
1263
1283
  const value = db.query("SELECT browser_profile FROM api_topics WHERE id = ?").get(topicId)?.browser_profile;
1264
1284
  return value || DEFAULT_BROWSER_PROFILE;
1265
1285
  }
1266
- function hasBrowserProfileTopic(topicId) {
1267
- return Boolean(db.query("SELECT id FROM api_topics WHERE id = ?").get(topicId));
1268
- }
1269
- function createBrowserProfile(ownerId, rawName) {
1270
- const name = normalizeBrowserProfileName(rawName);
1271
- if (name === DEFAULT_BROWSER_PROFILE)
1272
- return name;
1273
- db.query("INSERT OR IGNORE INTO browser_profiles (owner_id, name, created_at) VALUES (?, ?, ?)").run(ownerId, name, new Date().toISOString());
1274
- return name;
1275
- }
1276
- function assignTopicBrowserProfile(opts) {
1277
- const actualOwner = getBrowserProfileOwner(opts.topicId, "");
1278
- if (!actualOwner)
1279
- throw new Error(`Topic "${opts.topicId}" not found or has no owner.`);
1280
- if (actualOwner !== opts.actorUserId) {
1281
- throw new Error(`Only the topic owner can change its browser profile.`);
1282
- }
1283
- const profile = normalizeBrowserProfileName(opts.profile);
1284
- if (profile !== DEFAULT_BROWSER_PROFILE)
1285
- createBrowserProfile(actualOwner, profile);
1286
- const previous = getTopicBrowserProfile(opts.topicId);
1287
- const result = db.query("UPDATE api_topics SET browser_profile = ? WHERE id = ?").run(profile, opts.topicId);
1288
- if (Number(result.changes ?? 0) !== 1)
1289
- throw new Error(`Topic "${opts.topicId}" not found.`);
1290
- return { previous, profile };
1291
- }
1292
1286
  // ../../packages/core/src/platform/playwright/manager.ts
1293
1287
  function makeInstanceKey(userId, topic) {
1294
1288
  return resolvePlaywrightTopicBinding(userId, topic).instanceKey;
@@ -1300,7 +1294,7 @@ function defaultTopicBinding(userId, topic) {
1300
1294
  if (!topic)
1301
1295
  return managerHost.resolveNamedBinding(userId, "default");
1302
1296
  const ownerId = getBrowserProfileOwner(topic, userId);
1303
- const profile = migrateLegacyTopicProfile(ownerId, topic);
1297
+ const profile = getTopicBrowserProfile(topic);
1304
1298
  return managerHost.resolveNamedBinding(ownerId, profile);
1305
1299
  }
1306
1300
  function makeBrowserProfileInstanceKey(ownerId, rawProfile) {
@@ -1315,34 +1309,15 @@ function validateProfileBinding(binding) {
1315
1309
  }
1316
1310
  return Object.freeze({ ...binding });
1317
1311
  }
1318
- function defaultNamedBinding(ownerId, rawProfile) {
1312
+ function defaultNamedBinding(_ownerId, rawProfile) {
1319
1313
  const profile = normalizeBrowserProfileName(rawProfile);
1320
- const instanceKey = `profile:${encodeURIComponent(ownerId)}:${profile}`;
1314
+ const instanceKey = `profile:${profile}`;
1321
1315
  return {
1322
1316
  instanceKey,
1323
- ownerId,
1317
+ ownerId: "local",
1324
1318
  profile
1325
1319
  };
1326
1320
  }
1327
- function legacyBrowserProfileName(topic) {
1328
- return `legacy_${createHash2("sha256").update(topic).digest("hex").slice(0, 12)}`;
1329
- }
1330
- function migrateLegacyTopicProfile(ownerId, topic) {
1331
- const current = getTopicBrowserProfile(topic);
1332
- if (current !== "default" || !hasBrowserProfileTopic(topic))
1333
- return current;
1334
- const legacyDir = resolve6(BROWSER_PROFILES_DIR, sanitizeTopicName(topic));
1335
- if (!existsSync2(legacyDir))
1336
- return current;
1337
- const profile = legacyBrowserProfileName(topic);
1338
- const profileDir = defaultProfileDir(ownerId, profile);
1339
- mkdirSync4(dirname3(profileDir), { recursive: true });
1340
- if (!existsSync2(profileDir))
1341
- renameSync(legacyDir, profileDir);
1342
- assignTopicBrowserProfile({ topicId: topic, actorUserId: ownerId, profile });
1343
- logger.info({ ownerId, topic, profile }, "Adopted legacy topic browser profile");
1344
- return profile;
1345
- }
1346
1321
  function defaultChildEnvironment(context) {
1347
1322
  const childEnvironment = {};
1348
1323
  for (const key of [
@@ -1417,6 +1392,10 @@ function resetPlaywrightManagerHost() {
1417
1392
  configurePlaywrightManagerHost(defaultManagerHost);
1418
1393
  }
1419
1394
  function parseInstanceKey(instanceKey) {
1395
+ const shared = /^profile:(.+)$/.exec(instanceKey);
1396
+ if (shared && !shared[1].includes(":")) {
1397
+ return { ownerId: "local", profile: normalizeBrowserProfileName(shared[1]) };
1398
+ }
1420
1399
  const match = /^profile:([^:]+):(.+)$/.exec(instanceKey);
1421
1400
  if (!match)
1422
1401
  return { ownerId: "legacy", profile: sanitizeTopicName(instanceKey) };
@@ -1598,12 +1577,8 @@ async function allocatePort() {
1598
1577
  function releasePort(port) {
1599
1578
  usedPorts.delete(port);
1600
1579
  }
1601
- function ownerDirectory(ownerId) {
1602
- const digest = createHash2("sha256").update(ownerId).digest("hex").slice(0, 16);
1603
- return `${sanitizeTopicName(ownerId).slice(0, 24)}_${digest}`;
1604
- }
1605
- function defaultProfileDir(ownerId, profile) {
1606
- return resolve6(BROWSER_PROFILES_DIR, "profiles", ownerDirectory(ownerId), profile);
1580
+ function defaultProfileDir(_ownerId, profile) {
1581
+ return resolve6(BROWSER_PROFILES_DIR, profile);
1607
1582
  }
1608
1583
  function resolveUserDataDir(instanceKey) {
1609
1584
  return managerHost.resolveInstanceDataDir(instanceKey);
@@ -2041,4 +2016,4 @@ export {
2041
2016
  browserProcessMatchesExpectedProfile
2042
2017
  };
2043
2018
 
2044
- //# debugId=2CF8E30F8AE6C02A64756E2164756E21
2019
+ //# debugId=E1E4675036B694DF64756E2164756E21