negotium 0.3.14 → 0.4.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 (39) hide show
  1. package/README.md +2 -6
  2. package/dist/agent-helpers.js +333 -187
  3. package/dist/agent-helpers.js.map +9 -8
  4. package/dist/{chunk-0ynjwr50.js → chunk-zq2tcq4k.js} +12 -29
  5. package/dist/{chunk-0ynjwr50.js.map → chunk-zq2tcq4k.js.map} +4 -4
  6. package/dist/hosted-agent.js +214 -65
  7. package/dist/hosted-agent.js.map +8 -7
  8. package/dist/main.js +712 -895
  9. package/dist/main.js.map +10 -11
  10. package/dist/mcp-factories.js +305 -470
  11. package/dist/mcp-factories.js.map +9 -10
  12. package/dist/registry.js +3 -3
  13. package/dist/registry.js.map +2 -2
  14. package/dist/rollout.js +1 -1
  15. package/dist/runtime/src/agents/codex-provider.ts +40 -9
  16. package/dist/runtime/src/agents/codex-vault-hook-bridge.ts +198 -0
  17. package/dist/runtime/src/agents/codex-vault-hook.mjs +50 -0
  18. package/dist/runtime/src/agents/execution-host.ts +1 -14
  19. package/dist/runtime/src/agents/public-helpers.ts +0 -9
  20. package/dist/runtime/src/agents/vault-tool-policy.ts +9 -51
  21. package/dist/runtime/src/mcp/factories/index.ts +1 -8
  22. package/dist/runtime/src/mcp/factories/vault.ts +6 -104
  23. package/dist/runtime/src/mcp/vault-server.ts +4 -20
  24. package/dist/runtime/src/prompts/sessions/_shared-tools.md +1 -1
  25. package/dist/runtime/src/version.ts +1 -1
  26. package/dist/types/packages/core/src/agents/codex-vault-hook-bridge.d.ts +28 -0
  27. package/dist/types/packages/core/src/agents/execution-host.d.ts +0 -2
  28. package/dist/types/packages/core/src/agents/public-helpers.d.ts +0 -1
  29. package/dist/types/packages/core/src/agents/vault-tool-policy.d.ts +1 -14
  30. package/dist/types/packages/core/src/mcp/factories/index.d.ts +1 -3
  31. package/dist/types/packages/core/src/mcp/factories/vault.d.ts +4 -13
  32. package/dist/types/packages/core/src/version.d.ts +1 -1
  33. package/package.json +2 -2
  34. package/dist/runtime/src/mcp/factories/vault-host.ts +0 -8
  35. package/dist/runtime/src/mcp/vault-http.ts +0 -235
  36. package/dist/runtime/src/mcp/vault-run.ts +0 -154
  37. package/dist/types/packages/core/src/mcp/factories/vault-host.d.ts +0 -7
  38. package/dist/types/packages/core/src/mcp/vault-http.d.ts +0 -23
  39. package/dist/types/packages/core/src/mcp/vault-run.d.ts +0 -19
@@ -69,30 +69,21 @@ function shouldSubstituteVaultToolInput(toolName) {
69
69
  const leaf = leafToolName(toolName);
70
70
  return leaf.startsWith("browser_") || DIRECT_VAULT_EXECUTION_TOOLS.has(leaf);
71
71
  }
72
- function createVaultToolPolicy(host) {
73
- function isVaultBrokerTool(toolName) {
74
- return toolName.includes("vault_run") || toolName.includes("vault_http_request");
75
- }
76
- function referencesRuntimeSecretStorage(value) {
77
- if (typeof value === "string") {
78
- const lower = value.toLowerCase();
79
- if (SENSITIVE_RUNTIME_NAMES.some((name) => lower.includes(name)))
80
- return true;
81
- return value.startsWith("/") && host.isSensitivePath(value);
82
- }
83
- if (Array.isArray(value))
84
- return value.some(referencesRuntimeSecretStorage);
85
- if (value && typeof value === "object") {
86
- return Object.values(value).some(referencesRuntimeSecretStorage);
87
- }
88
- return false;
72
+ function referencesRuntimeSecretStorage(value) {
73
+ if (typeof value === "string") {
74
+ const lower = value.toLowerCase();
75
+ if (SENSITIVE_RUNTIME_NAMES.some((name) => lower.includes(name)))
76
+ return true;
77
+ return value.startsWith("/") && isSensitivePath(value);
89
78
  }
90
- function shouldRedirectVaultTool(userId, toolName, input) {
91
- return false;
79
+ if (Array.isArray(value))
80
+ return value.some(referencesRuntimeSecretStorage);
81
+ if (value && typeof value === "object") {
82
+ return Object.values(value).some(referencesRuntimeSecretStorage);
92
83
  }
93
- return { isVaultBrokerTool, referencesRuntimeSecretStorage, shouldRedirectVaultTool };
84
+ return false;
94
85
  }
95
- var SENSITIVE_RUNTIME_NAMES, DIRECT_VAULT_EXECUTION_TOOLS, VAULT_BROKER_REDIRECT_ERROR = "Vault broker redirection is disabled; use {{KEY}} directly in normal tool inputs.", defaultVaultToolPolicy, isVaultBrokerTool, referencesRuntimeSecretStorage, shouldRedirectVaultTool;
86
+ var SENSITIVE_RUNTIME_NAMES, DIRECT_VAULT_EXECUTION_TOOLS;
96
87
  var init_vault_tool_policy = __esm(() => {
97
88
  init_sensitive_path();
98
89
  SENSITIVE_RUNTIME_NAMES = [
@@ -102,13 +93,6 @@ var init_vault_tool_policy = __esm(() => {
102
93
  "sessions.db"
103
94
  ];
104
95
  DIRECT_VAULT_EXECUTION_TOOLS = new Set(["Bash", "WebFetch"]);
105
- defaultVaultToolPolicy = createVaultToolPolicy({
106
- isSensitivePath,
107
- valueReferencesVaultKey: () => false
108
- });
109
- isVaultBrokerTool = defaultVaultToolPolicy.isVaultBrokerTool;
110
- referencesRuntimeSecretStorage = defaultVaultToolPolicy.referencesRuntimeSecretStorage;
111
- shouldRedirectVaultTool = defaultVaultToolPolicy.shouldRedirectVaultTool;
112
96
  });
113
97
 
114
98
  // ../../packages/core/src/platform/config-helpers.ts
@@ -1870,7 +1854,6 @@ var init_execution_host = __esm(async () => {
1870
1854
  redactVaultSecrets,
1871
1855
  substituteVaultSecrets: (userId, value) => vaultSubstituteDetailed(userId, value).text,
1872
1856
  referencesRuntimeSecretStorage,
1873
- shouldRedirectVaultTool,
1874
1857
  claudeCodeExecutablePath: () => CLAUDE_EXECUTABLE,
1875
1858
  codexAuthFilePath
1876
1859
  };
@@ -2429,7 +2412,7 @@ var init_claude_registry = __esm(() => {
2429
2412
  });
2430
2413
 
2431
2414
  // ../../packages/core/src/version.ts
2432
- var NEGOTIUM_VERSION = "0.3.14";
2415
+ var NEGOTIUM_VERSION = "0.4.1";
2433
2416
 
2434
2417
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
2435
2418
  import { spawn as spawn2 } from "child_process";
@@ -4594,9 +4577,163 @@ var init_codex_tree_kill = __esm(() => {
4594
4577
  killOwnedCodexTreesForShutdown = manager.killOwnedTreesForShutdown;
4595
4578
  });
4596
4579
 
4580
+ // ../../packages/core/src/agents/codex-vault-hook-bridge.ts
4581
+ import { randomBytes as randomBytes5 } from "crypto";
4582
+ import { existsSync as existsSync11 } from "fs";
4583
+ import { chmod, mkdtemp, rm, writeFile } from "fs/promises";
4584
+ import { createServer } from "net";
4585
+ import { tmpdir as tmpdir2 } from "os";
4586
+ import { dirname as dirname9, join as join12, resolve as resolve7 } from "path";
4587
+ import { fileURLToPath as fileURLToPath2 } from "url";
4588
+ function evaluateCodexVaultPreToolUse(input, userId, operations) {
4589
+ if (operations.referencesSensitiveStorage(input.tool_input)) {
4590
+ return {
4591
+ hookSpecificOutput: {
4592
+ hookEventName: "PreToolUse",
4593
+ permissionDecision: "deny",
4594
+ permissionDecisionReason: SENSITIVE_STORAGE_DENIAL
4595
+ }
4596
+ };
4597
+ }
4598
+ if (!shouldSubstituteVaultToolInput(input.tool_name))
4599
+ return {};
4600
+ const updatedInput = deepMapStrings(input.tool_input, (value) => operations.substitute(userId, value));
4601
+ if (JSON.stringify(updatedInput) === JSON.stringify(input.tool_input))
4602
+ return {};
4603
+ return {
4604
+ hookSpecificOutput: {
4605
+ hookEventName: "PreToolUse",
4606
+ permissionDecision: "allow",
4607
+ updatedInput
4608
+ }
4609
+ };
4610
+ }
4611
+ function shellQuote(value) {
4612
+ return `'${value.replaceAll("'", `'"'"'`)}'`;
4613
+ }
4614
+ function hookClientPath() {
4615
+ const moduleDir = dirname9(fileURLToPath2(import.meta.url));
4616
+ const adjacent = resolve7(moduleDir, "codex-vault-hook.mjs");
4617
+ if (existsSync11(adjacent))
4618
+ return adjacent;
4619
+ const packaged = resolve7(moduleDir, "runtime/src/agents/codex-vault-hook.mjs");
4620
+ if (existsSync11(packaged))
4621
+ return packaged;
4622
+ throw new Error("Codex Vault hook client is missing from this installation");
4623
+ }
4624
+ function privateCodexWrapper(codexScript, socketPath, token) {
4625
+ return [
4626
+ "#!/bin/sh",
4627
+ `export ${HOOK_SOCKET_ENV}=${shellQuote(socketPath)}`,
4628
+ `export ${HOOK_TOKEN_ENV}=${shellQuote(token)}`,
4629
+ 'if [ "$1" = "exec" ]; then',
4630
+ " shift",
4631
+ ` exec ${shellQuote(process.execPath)} ${shellQuote(codexScript)} exec --dangerously-bypass-hook-trust "$@"`,
4632
+ "fi",
4633
+ `exec ${shellQuote(process.execPath)} ${shellQuote(codexScript)} "$@"`,
4634
+ ""
4635
+ ].join(`
4636
+ `);
4637
+ }
4638
+ async function createCodexVaultHookBridge(userId) {
4639
+ const root = await mkdtemp(join12(tmpdir2(), "negotium-codex-vault-"));
4640
+ await chmod(root, 448);
4641
+ const socketPath = join12(root, "hook.sock");
4642
+ const wrapperPath = join12(root, "codex-with-hooks");
4643
+ const token = randomBytes5(32).toString("hex");
4644
+ const connections = new Set;
4645
+ const server = createServer((socket) => {
4646
+ connections.add(socket);
4647
+ socket.once("close", () => connections.delete(socket));
4648
+ socket.setEncoding("utf8");
4649
+ let request = "";
4650
+ let handled = false;
4651
+ const handleRequest = () => {
4652
+ if (handled)
4653
+ return;
4654
+ handled = true;
4655
+ try {
4656
+ const parsed = JSON.parse(request.trimEnd());
4657
+ if (parsed.token !== token)
4658
+ throw new Error("invalid hook capability");
4659
+ if (!parsed.input || typeof parsed.input !== "object" || typeof parsed.input.tool_name !== "string") {
4660
+ throw new Error("invalid PreToolUse payload");
4661
+ }
4662
+ const output = evaluateCodexVaultPreToolUse(parsed.input, userId, {
4663
+ referencesSensitiveStorage: referencesHostedSecretStorage,
4664
+ substitute: substituteHostedSecrets
4665
+ });
4666
+ socket.end(JSON.stringify({ ok: true, output }));
4667
+ } catch (error) {
4668
+ const message = error instanceof Error ? error.message : String(error);
4669
+ socket.end(JSON.stringify({ ok: false, error: message }));
4670
+ }
4671
+ };
4672
+ socket.on("data", (chunk) => {
4673
+ request += chunk;
4674
+ if (Buffer.byteLength(request) > MAX_HOOK_REQUEST_BYTES)
4675
+ socket.destroy();
4676
+ else if (request.endsWith(`
4677
+ `))
4678
+ handleRequest();
4679
+ });
4680
+ socket.on("end", handleRequest);
4681
+ });
4682
+ try {
4683
+ await new Promise((resolveListen, reject) => {
4684
+ server.once("error", reject);
4685
+ server.listen(socketPath, () => {
4686
+ server.off("error", reject);
4687
+ resolveListen();
4688
+ });
4689
+ });
4690
+ await chmod(socketPath, 384);
4691
+ await writeFile(wrapperPath, privateCodexWrapper(codexCliScriptPath(), socketPath, token), {
4692
+ mode: 448
4693
+ });
4694
+ const command = [shellQuote(process.execPath), shellQuote(hookClientPath())].join(" ");
4695
+ return {
4696
+ codexPathOverride: wrapperPath,
4697
+ environment: { [HOOK_SOCKET_ENV]: socketPath, [HOOK_TOKEN_ENV]: token },
4698
+ hooks: {
4699
+ PreToolUse: [
4700
+ {
4701
+ matcher: "*",
4702
+ hooks: [
4703
+ {
4704
+ type: "command",
4705
+ command,
4706
+ timeout: 30,
4707
+ statusMessage: "Resolving Vault placeholders"
4708
+ }
4709
+ ]
4710
+ }
4711
+ ]
4712
+ },
4713
+ async close() {
4714
+ for (const socket of connections)
4715
+ socket.destroy();
4716
+ await new Promise((resolveClose) => server.close(() => resolveClose()));
4717
+ await rm(root, { recursive: true, force: true });
4718
+ }
4719
+ };
4720
+ } catch (error) {
4721
+ server.close();
4722
+ await rm(root, { recursive: true, force: true });
4723
+ throw error;
4724
+ }
4725
+ }
4726
+ var MAX_HOOK_REQUEST_BYTES, SENSITIVE_STORAGE_DENIAL = "Runtime secret storage access is not permitted", HOOK_SOCKET_ENV = "NEGOTIUM_CODEX_VAULT_HOOK_SOCKET", HOOK_TOKEN_ENV = "NEGOTIUM_CODEX_VAULT_HOOK_TOKEN";
4727
+ var init_codex_vault_hook_bridge = __esm(async () => {
4728
+ init_codex_native_multi_agent();
4729
+ await init_execution_host();
4730
+ init_vault_tool_policy();
4731
+ MAX_HOOK_REQUEST_BYTES = 1024 * 1024;
4732
+ });
4733
+
4597
4734
  // ../../packages/core/src/agents/tool-format.ts
4598
4735
  import { readFileSync as readFileSync10, statSync as statSync4 } from "fs";
4599
- import { isAbsolute, resolve as resolve7 } from "path";
4736
+ import { isAbsolute, resolve as resolve8 } from "path";
4600
4737
  import { diffLines as computeLineDiff } from "diff";
4601
4738
  function summarizeDisplayText(value) {
4602
4739
  const normalized = value.replace(/\s+/g, " ").trim();
@@ -4920,7 +5057,7 @@ function sourceStartLine(input, before, after, cwd) {
4920
5057
  const rawPath = input.file_path ?? input.path;
4921
5058
  if (typeof rawPath !== "string" || !rawPath.trim())
4922
5059
  return 1;
4923
- const path = isAbsolute(rawPath) ? rawPath : resolve7(cwd ?? process.cwd(), rawPath);
5060
+ const path = isAbsolute(rawPath) ? rawPath : resolve8(cwd ?? process.cwd(), rawPath);
4924
5061
  try {
4925
5062
  if (statSync4(path).size > TOOL_DIFF_SOURCE_MAX_BYTES)
4926
5063
  return 1;
@@ -5118,9 +5255,9 @@ __export(exports_codex_provider, {
5118
5255
  codexProvider: () => codexProvider
5119
5256
  });
5120
5257
  import { execFileSync as execFileSync4 } from "child_process";
5121
- import { existsSync as existsSync11, readFileSync as readFileSync11, realpathSync as realpathSync3, statSync as statSync5 } from "fs";
5258
+ import { existsSync as existsSync12, readFileSync as readFileSync11, realpathSync as realpathSync3, statSync as statSync5 } from "fs";
5122
5259
  import { homedir as homedir6 } from "os";
5123
- import { dirname as dirname9, isAbsolute as isAbsolute2, join as join12, relative, resolve as resolve8 } from "path";
5260
+ import { dirname as dirname10, isAbsolute as isAbsolute2, join as join13, relative, resolve as resolve9 } from "path";
5124
5261
  import { Codex } from "@openai/codex-sdk";
5125
5262
  function sameCodexUsage(usage, total) {
5126
5263
  return usage.input_tokens === total.inputTokens && usage.output_tokens === total.outputTokens && (usage.cached_input_tokens ?? 0) === total.cachedInputTokens && (usage.cache_write_input_tokens ?? 0) === total.cacheWriteInputTokens;
@@ -5148,8 +5285,8 @@ function codexMcpServerName(name) {
5148
5285
  return CODEX_MCP_SERVER_NAME_OVERRIDES[name] ?? name;
5149
5286
  }
5150
5287
  function globalCodexMcpServerNames(authFilePath) {
5151
- const configPath = join12(dirname9(authFilePath), "config.toml");
5152
- if (!existsSync11(configPath))
5288
+ const configPath = join13(dirname10(authFilePath), "config.toml");
5289
+ if (!existsSync12(configPath))
5153
5290
  return [];
5154
5291
  try {
5155
5292
  const names = new Set;
@@ -5244,13 +5381,13 @@ function summarizeMcpToolCallResult(item) {
5244
5381
  }
5245
5382
  function canonicalPath(path) {
5246
5383
  try {
5247
- return realpathSync3(resolve8(path));
5384
+ return realpathSync3(resolve9(path));
5248
5385
  } catch {
5249
- return resolve8(path);
5386
+ return resolve9(path);
5250
5387
  }
5251
5388
  }
5252
5389
  function textFile(path, maxBytes = CODEX_DIFF_FILE_LIMIT) {
5253
- if (!existsSync11(path))
5390
+ if (!existsSync12(path))
5254
5391
  return null;
5255
5392
  try {
5256
5393
  const byteLimit = Math.min(CODEX_DIFF_FILE_LIMIT, Math.max(0, maxBytes));
@@ -5290,7 +5427,7 @@ class CodexFilePreviewTracker {
5290
5427
  const code = record.slice(0, 2);
5291
5428
  const path = record.slice(3);
5292
5429
  const remainingBytes = CODEX_DIFF_BASELINE_BYTE_LIMIT - loadedBytes;
5293
- const content = loadedFiles < CODEX_DIFF_BASELINE_FILE_LIMIT && remainingBytes > 0 ? textFile(resolve8(this.#root, path), remainingBytes) : undefined;
5430
+ const content = loadedFiles < CODEX_DIFF_BASELINE_FILE_LIMIT && remainingBytes > 0 ? textFile(resolve9(this.#root, path), remainingBytes) : undefined;
5294
5431
  this.#baseline.set(path, content);
5295
5432
  if (typeof content === "string") {
5296
5433
  loadedFiles += 1;
@@ -5303,7 +5440,7 @@ class CodexFilePreviewTracker {
5303
5440
  preview(path, succeeded) {
5304
5441
  if (!this.#root || !this.#baselineAvailable || !succeeded)
5305
5442
  return {};
5306
- const absolute = canonicalPath(isAbsolute2(path) ? path : resolve8(this.#cwd, path));
5443
+ const absolute = canonicalPath(isAbsolute2(path) ? path : resolve9(this.#cwd, path));
5307
5444
  const relativePath = relative(this.#root, absolute);
5308
5445
  if (!relativePath || relativePath.startsWith("..") || isAbsolute2(relativePath))
5309
5446
  return {};
@@ -5338,7 +5475,7 @@ class CodexFilePreviewTracker {
5338
5475
  }
5339
5476
  }
5340
5477
  async function fileChangeEvents(item, previews, cwd, threadId, consumedPatchCallIds) {
5341
- const expectedPaths = item.changes.map((change) => isAbsolute2(change.path) ? change.path : resolve8(cwd, change.path));
5478
+ const expectedPaths = item.changes.map((change) => isAbsolute2(change.path) ? change.path : resolve9(cwd, change.path));
5342
5479
  let nativePreview;
5343
5480
  if (threadId && item.status === "completed") {
5344
5481
  await new Promise((resolveDelay) => setTimeout(resolveDelay, 20));
@@ -5462,7 +5599,7 @@ async function* codexProvider(opts) {
5462
5599
  const filePreviews = new CodexFilePreviewTracker(opts.cwd);
5463
5600
  const consumedPatchCallIds = new Set(opts.sessionId ? readCodexPatchCallIds(opts.sessionId) : []);
5464
5601
  const codexAuthPath = hostedCodexAuthFilePath();
5465
- if (!existsSync11(codexAuthPath)) {
5602
+ if (!existsSync12(codexAuthPath)) {
5466
5603
  yield {
5467
5604
  type: "error",
5468
5605
  content: `Codex auth file not found at ${codexAuthPath}. Run \`codex login\` to authenticate.`
@@ -5501,21 +5638,30 @@ async function* codexProvider(opts) {
5501
5638
  model: opts.model ?? "(sdk default)",
5502
5639
  effort: opts.effort ?? "(off)",
5503
5640
  cwd: opts.cwd,
5504
- cwdExists: existsSync11(opts.cwd),
5641
+ cwdExists: existsSync12(opts.cwd),
5505
5642
  resume: Boolean(opts.sessionId),
5506
5643
  mcpServerCount: Object.keys(codexMcpServers).length
5507
5644
  }, "codexProvider: starting turn");
5508
5645
  const hostedCodexHome = hostedCodexHomePath();
5509
- const inheritedCodexHome = process.env.CODEX_HOME || join12(homedir6(), ".codex");
5510
- const codexEnvironment = scopedBrowserCapability || resolve8(hostedCodexHome) !== resolve8(inheritedCodexHome) ? {
5646
+ const inheritedCodexHome = process.env.CODEX_HOME || join13(homedir6(), ".codex");
5647
+ const codexEnvironment = scopedBrowserCapability || resolve9(hostedCodexHome) !== resolve9(inheritedCodexHome) ? {
5511
5648
  ...Object.fromEntries(Object.entries(process.env).filter((entry) => typeof entry[1] === "string")),
5512
5649
  CODEX_HOME: hostedCodexHome,
5513
5650
  ...scopedBrowserCapability ? { [CODEX_BROWSER_CAPABILITY_ENV]: scopedBrowserCapability } : {}
5514
5651
  } : undefined;
5652
+ let vaultHook;
5653
+ try {
5654
+ vaultHook = await createCodexVaultHookBridge(opts.vaultUserId ?? opts.userId ?? "");
5655
+ } catch (err) {
5656
+ yield { type: "error", content: `Failed to initialize Codex Vault hooks: ${errMsg(err)}` };
5657
+ return;
5658
+ }
5515
5659
  const codex = new Codex({
5660
+ codexPathOverride: vaultHook.codexPathOverride,
5516
5661
  ...codexEnvironment ? { env: codexEnvironment } : {},
5517
5662
  config: {
5518
- features: { multi_agent: false, multi_agent_v2: false, enable_fanout: false },
5663
+ features: { hooks: true, multi_agent: false, multi_agent_v2: false, enable_fanout: false },
5664
+ hooks: vaultHook.hooks,
5519
5665
  model_catalog_json: codexModelCatalogPath,
5520
5666
  mcp_servers: codexMcpServers,
5521
5667
  ...opts.toolPolicy ? { sandbox_permissions: [] } : {}
@@ -5619,7 +5765,7 @@ async function* codexProvider(opts) {
5619
5765
  if (!item)
5620
5766
  break;
5621
5767
  if (item.type === "command_execution") {
5622
- const command = String(item.command ?? "");
5768
+ const command = redactHostedSecrets(opts.vaultUserId ?? opts.userId ?? "", String(item.command ?? ""));
5623
5769
  yield {
5624
5770
  type: "tool_use",
5625
5771
  name: "Bash",
@@ -5627,10 +5773,11 @@ async function* codexProvider(opts) {
5627
5773
  toolUseId: String(item.id ?? "")
5628
5774
  };
5629
5775
  } else if (item.type === "mcp_tool_call") {
5776
+ const input = item.arguments && typeof item.arguments === "object" ? item.arguments : {};
5630
5777
  yield {
5631
5778
  type: "tool_use",
5632
5779
  name: String(item.tool ?? "unknown"),
5633
- input: item.arguments && typeof item.arguments === "object" ? item.arguments : {},
5780
+ input: deepMapStrings(input, (value) => redactHostedSecrets(opts.vaultUserId ?? opts.userId ?? "", value)),
5634
5781
  toolUseId: String(item.id ?? "")
5635
5782
  };
5636
5783
  }
@@ -5673,7 +5820,7 @@ async function* codexProvider(opts) {
5673
5820
  yield {
5674
5821
  type: "tool_result",
5675
5822
  toolUseId: String(item.id ?? ""),
5676
- content: summarizeMcpToolCallResult(item),
5823
+ content: redactHostedSecrets(opts.vaultUserId ?? opts.userId ?? "", summarizeMcpToolCallResult(item)),
5677
5824
  ...isError ? { isError: true } : {}
5678
5825
  };
5679
5826
  } else if (item.type === "command_execution") {
@@ -5681,7 +5828,7 @@ async function* codexProvider(opts) {
5681
5828
  yield {
5682
5829
  type: "tool_result",
5683
5830
  toolUseId: String(item.id ?? ""),
5684
- content: String(item.aggregated_output ?? "").slice(0, 200),
5831
+ content: redactHostedSecrets(opts.vaultUserId ?? opts.userId ?? "", String(item.aggregated_output ?? "").slice(0, 200)),
5685
5832
  ...isError ? { isError: true } : {}
5686
5833
  };
5687
5834
  } else if (item.type === "file_change") {
@@ -5690,7 +5837,10 @@ async function* codexProvider(opts) {
5690
5837
  yield fileEvent;
5691
5838
  }
5692
5839
  } else if (item.type === "error") {
5693
- yield { type: "error", content: String(item.message ?? "") };
5840
+ const message = String(item.message ?? "");
5841
+ if (message !== CODEX_HOOK_TRUST_BYPASS_NOTICE) {
5842
+ yield { type: "error", content: message };
5843
+ }
5694
5844
  }
5695
5845
  break;
5696
5846
  }
@@ -5778,12 +5928,14 @@ async function* codexProvider(opts) {
5778
5928
  abortSignal?.removeEventListener("abort", onAbortKill);
5779
5929
  if (trackedPids.pids.length > 0)
5780
5930
  unregisterOwnedCodexPids(trackedPids.pids);
5931
+ await vaultHook.close();
5781
5932
  }
5782
5933
  }
5783
- var CODEX_MCP_SERVER_NAME_OVERRIDES, CODEX_DIFF_FILE_LIMIT, CODEX_DIFF_BASELINE_FILE_LIMIT = 200, CODEX_DIFF_BASELINE_BYTE_LIMIT, CODEX_STARTUP_TIMEOUT_MS = 90000;
5934
+ var CODEX_HOOK_TRUST_BYPASS_NOTICE = "`--dangerously-bypass-hook-trust` is enabled. Enabled hooks may run without review for this invocation.", CODEX_MCP_SERVER_NAME_OVERRIDES, CODEX_DIFF_FILE_LIMIT, CODEX_DIFF_BASELINE_FILE_LIMIT = 200, CODEX_DIFF_BASELINE_BYTE_LIMIT, CODEX_STARTUP_TIMEOUT_MS = 90000;
5784
5935
  var init_codex_provider = __esm(async () => {
5785
5936
  init_codex_native_multi_agent();
5786
5937
  init_codex_tree_kill();
5938
+ await init_codex_vault_hook_bridge();
5787
5939
  await init_execution_host();
5788
5940
  await init_codex();
5789
5941
  init_tool_format();
@@ -5811,7 +5963,7 @@ __export(exports_maestro_provider, {
5811
5963
  buildMaestroToolHooks: () => buildMaestroToolHooks,
5812
5964
  buildMaestroDisallowedTools: () => buildMaestroDisallowedTools
5813
5965
  });
5814
- import { resolve as resolve9 } from "path";
5966
+ import { resolve as resolve10 } from "path";
5815
5967
  import { maestroProvider as sdkMaestroProvider, setMcpResolver } from "maestro-agent-sdk";
5816
5968
  function buildMaestroDisallowedTools(callerDisallowedTools = [], toolPolicy) {
5817
5969
  return [
@@ -5945,13 +6097,13 @@ var init_maestro_provider = __esm(async () => {
5945
6097
  "ToolSearch",
5946
6098
  ...DEFAULT_MAESTRO_DISALLOWED_TOOLS
5947
6099
  ];
5948
- MAESTRO_TOOL_OUTPUT_DIR = resolve9(RUN_DIR, "maestro-tool-outputs");
6100
+ MAESTRO_TOOL_OUTPUT_DIR = resolve10(RUN_DIR, "maestro-tool-outputs");
5949
6101
  });
5950
6102
 
5951
6103
  // ../../packages/core/src/agents/index.ts
5952
- import { existsSync as existsSync12 } from "fs";
6104
+ import { existsSync as existsSync13 } from "fs";
5953
6105
  import { homedir as homedir7 } from "os";
5954
- import { join as join13 } from "path";
6106
+ import { join as join14 } from "path";
5955
6107
  async function* dispatchAgent(opts) {
5956
6108
  switch (opts.agent) {
5957
6109
  case "claude": {
@@ -5985,11 +6137,11 @@ async function resolveSessionFileMissing(agent, sessionId, cwd) {
5985
6137
  switch (agent) {
5986
6138
  case "claude": {
5987
6139
  const encodedCwd = encodeClaudeCwd(cwd);
5988
- const path = join13(homedir7(), ".claude", "projects", encodedCwd, `${sessionId}.jsonl`);
5989
- return !existsSync12(path);
6140
+ const path = join14(homedir7(), ".claude", "projects", encodedCwd, `${sessionId}.jsonl`);
6141
+ return !existsSync13(path);
5990
6142
  }
5991
6143
  case "codex": {
5992
- const sessionsDir = join13(hostedCodexHomePath(), "sessions");
6144
+ const sessionsDir = join14(hostedCodexHomePath(), "sessions");
5993
6145
  const glob = new Bun.Glob(`**/rollout-*-${sessionId}.jsonl`);
5994
6146
  for await (const _rel of glob.scan({ cwd: sessionsDir, onlyFiles: true })) {
5995
6147
  return false;
@@ -5998,7 +6150,7 @@ async function resolveSessionFileMissing(agent, sessionId, cwd) {
5998
6150
  }
5999
6151
  case "maestro": {
6000
6152
  const { hasActiveMaestroSession, maestroSessionPath: maestroSessionPath2 } = await import("maestro-agent-sdk");
6001
- return !existsSync12(maestroSessionPath2(sessionId)) && !hasActiveMaestroSession(sessionId);
6153
+ return !existsSync13(maestroSessionPath2(sessionId)) && !hasActiveMaestroSession(sessionId);
6002
6154
  }
6003
6155
  default: {
6004
6156
  const _exhaustive = agent;
@@ -6526,9 +6678,9 @@ var init_model_catalog = __esm(() => {
6526
6678
 
6527
6679
  // ../../packages/core/src/prompts/builders.ts
6528
6680
  import { readFileSync as readFileSync12 } from "fs";
6529
- import { resolve as resolve10 } from "path";
6681
+ import { resolve as resolve11 } from "path";
6530
6682
  function loadPrompt(filename, dir = SESSIONS_DIR) {
6531
- const raw = readFileSync12(resolve10(dir, filename), "utf-8");
6683
+ const raw = readFileSync12(resolve11(dir, filename), "utf-8");
6532
6684
  return raw.replace(/\{\{RESOURCES_DIR\}\}/g, RESOURCES_DIR);
6533
6685
  }
6534
6686
  function replaceVars(template, vars) {
@@ -6577,7 +6729,7 @@ function visualDesignGuide() {
6577
6729
  return _visualDesignGuide;
6578
6730
  }
6579
6731
  function loadAgentPrompt(filename) {
6580
- const raw = readFileSync12(resolve10(AGENTS_PROMPTS_DIR, filename), "utf-8");
6732
+ const raw = readFileSync12(resolve11(AGENTS_PROMPTS_DIR, filename), "utf-8");
6581
6733
  const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
6582
6734
  if (!match)
6583
6735
  throw new Error(`Agent prompt ${filename} is missing frontmatter`);
@@ -6892,8 +7044,8 @@ var init_builders = __esm(() => {
6892
7044
  init_model_catalog();
6893
7045
  init_config();
6894
7046
  init_logger();
6895
- PROMPTS_DIR = resolve10(PROJECT_ROOT, "src/prompts");
6896
- SESSIONS_DIR = resolve10(PROMPTS_DIR, "sessions");
7047
+ PROMPTS_DIR = resolve11(PROJECT_ROOT, "src/prompts");
7048
+ SESSIONS_DIR = resolve11(PROMPTS_DIR, "sessions");
6897
7049
  defaultPromptBuilders = createPromptBuilders();
6898
7050
  buildTopicSystemPrompt = defaultPromptBuilders.buildTopicSystemPrompt;
6899
7051
  buildChannelSystemPrompt = defaultPromptBuilders.buildChannelSystemPrompt;
@@ -7244,9 +7396,9 @@ var init_api_topic_brief = __esm(async () => {
7244
7396
  });
7245
7397
 
7246
7398
  // ../../packages/core/src/storage/wiki.ts
7247
- import { basename as basename2, dirname as dirname10, join as join14 } from "path";
7399
+ import { basename as basename2, dirname as dirname11, join as join15 } from "path";
7248
7400
  function getSharedWikiDir(workspaceDir = resolveStorageWorkspaceDir()) {
7249
- return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() : join14(workspaceDir, "wiki");
7401
+ return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() : join15(workspaceDir, "wiki");
7250
7402
  }
7251
7403
  var init_wiki = __esm(async () => {
7252
7404
  await init_storage_host();
@@ -8080,8 +8232,8 @@ var init_personal_general = __esm(async () => {
8080
8232
 
8081
8233
  // ../../packages/core/src/agents/archiver.ts
8082
8234
  import { randomUUID as randomUUID6 } from "crypto";
8083
- import { existsSync as existsSync13, readdirSync as readdirSync2, readFileSync as readFileSync13, statSync as statSync6 } from "fs";
8084
- import { join as join15 } from "path";
8235
+ import { existsSync as existsSync14, readdirSync as readdirSync2, readFileSync as readFileSync13, statSync as statSync6 } from "fs";
8236
+ import { join as join16 } from "path";
8085
8237
  function resolveMemoryLanguage() {
8086
8238
  const override = process.env.NEGOTIUM_MEMORY_LANG?.trim();
8087
8239
  return override && override.length > 0 ? override : resolveOutputLanguage();
@@ -8332,10 +8484,10 @@ function distillOneLine(summaryMd) {
8332
8484
  return "";
8333
8485
  }
8334
8486
  function findSummaryFile(storage, topicTitle, date, sinceMs, topicId) {
8335
- const dir = join15(storage.getWikiDir(), "summaries");
8487
+ const dir = join16(storage.getWikiDir(), "summaries");
8336
8488
  if (!storage.fileExists(dir))
8337
8489
  return null;
8338
- const predicted = join15(dir, wikiSummaryFilename(date, topicTitle, topicId));
8490
+ const predicted = join16(dir, wikiSummaryFilename(date, topicTitle, topicId));
8339
8491
  if (storage.fileExists(predicted) && storage.fileModifiedAt(predicted) >= sinceMs)
8340
8492
  return predicted;
8341
8493
  let best = null;
@@ -8343,7 +8495,7 @@ function findSummaryFile(storage, topicTitle, date, sinceMs, topicId) {
8343
8495
  if (!f.startsWith(`${date}-`) || !isTopicSummaryFile(f, topicId ?? "", topicTitle)) {
8344
8496
  continue;
8345
8497
  }
8346
- const p = join15(dir, f);
8498
+ const p = join16(dir, f);
8347
8499
  try {
8348
8500
  const m = storage.fileModifiedAt(p);
8349
8501
  if (m >= sinceMs && (!best || m > best.mtime))
@@ -8424,7 +8576,7 @@ var init_archiver = __esm(async () => {
8424
8576
  defaultArchiverRuntime = createArchiverRuntime({
8425
8577
  storage: {
8426
8578
  getWikiDir: getSharedWikiDir,
8427
- fileExists: existsSync13,
8579
+ fileExists: existsSync14,
8428
8580
  listDirectory: readdirSync2,
8429
8581
  readTextFile: (path) => readFileSync13(path, "utf-8"),
8430
8582
  fileSize: (path) => statSync6(path).size,
@@ -8469,9 +8621,9 @@ __export(exports_auth_check, {
8469
8621
  checkAgentAuth: () => checkAgentAuth
8470
8622
  });
8471
8623
  import { execFileSync as execFileSync5 } from "child_process";
8472
- import { existsSync as existsSync14 } from "fs";
8624
+ import { existsSync as existsSync15 } from "fs";
8473
8625
  import { homedir as homedir8, platform } from "os";
8474
- import { join as join16 } from "path";
8626
+ import { join as join17 } from "path";
8475
8627
  function hasMaestroCredential(host, key, userId) {
8476
8628
  if (userId && host.getVaultValue(userId, key)?.trim())
8477
8629
  return true;
@@ -8491,7 +8643,7 @@ function checkAgentAuth(agent, host = defaultAgentAuthHost, userId) {
8491
8643
  case "claude": {
8492
8644
  if (host.environment.ANTHROPIC_API_KEY)
8493
8645
  return { ok: true };
8494
- const path = join16(host.homeDirectory(), ".claude", ".credentials.json");
8646
+ const path = join17(host.homeDirectory(), ".claude", ".credentials.json");
8495
8647
  if (host.operatingSystem() === "darwin") {
8496
8648
  if (host.hasMacOsCredential("Claude Code-credentials") || host.exists(path)) {
8497
8649
  return { ok: true };
@@ -8542,7 +8694,7 @@ var init_auth_check = __esm(async () => {
8542
8694
  await init_vault();
8543
8695
  defaultAgentAuthHost = {
8544
8696
  codexAuthFilePath,
8545
- exists: existsSync14,
8697
+ exists: existsSync15,
8546
8698
  environment: process.env,
8547
8699
  homeDirectory: homedir8,
8548
8700
  operatingSystem: platform,
@@ -8559,7 +8711,7 @@ var init_auth_check = __esm(async () => {
8559
8711
  });
8560
8712
 
8561
8713
  // ../../packages/core/src/agents/fork.ts
8562
- import { existsSync as existsSync15, unlinkSync as unlinkSync8 } from "fs";
8714
+ import { existsSync as existsSync16, unlinkSync as unlinkSync8 } from "fs";
8563
8715
  function createAgentForkHelpers(host) {
8564
8716
  return {
8565
8717
  async forkAgentSession(options) {
@@ -8596,7 +8748,7 @@ var init_fork = __esm(async () => {
8596
8748
  init_logger();
8597
8749
  defaultForkHelpers = createAgentForkHelpers({
8598
8750
  forkSession: (agent, options) => getRegistryOperations(agent).forkSession(options),
8599
- exists: existsSync15,
8751
+ exists: existsSync16,
8600
8752
  unlink: unlinkSync8,
8601
8753
  warn: (details, message) => logger.warn(details, message)
8602
8754
  });
@@ -9252,13 +9404,13 @@ function formatTopicArchiveTranscriptRecord(row, topicTitle, index) {
9252
9404
 
9253
9405
  // ../../packages/core/src/storage/topic-archive.ts
9254
9406
  import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync8 } from "fs";
9255
- import { join as join17 } from "path";
9407
+ import { join as join18 } from "path";
9256
9408
  function archiveTopicMessages(topicId, topicTitle, options = {}) {
9257
9409
  const rows = options.afterRowid !== undefined ? getMessagesForTopicAfterRowid(topicId, options.afterRowid) : getAllMessagesForTopic(topicId);
9258
9410
  if (rows.length === 0)
9259
9411
  return null;
9260
9412
  const safeTopic = sanitizeTopicName(topicTitle, true);
9261
- const archiveDir = join17(getSharedWikiDir(), "archive");
9413
+ const archiveDir = join18(getSharedWikiDir(), "archive");
9262
9414
  mkdirSync10(archiveDir, { recursive: true });
9263
9415
  const date = new Date().toISOString().slice(0, 10);
9264
9416
  const reasonSuffix = options.reason && options.reason !== "delete" ? `_${options.reason}` : "";
@@ -9271,7 +9423,7 @@ function archiveTopicMessages(topicId, topicTitle, options = {}) {
9271
9423
  let path;
9272
9424
  while (true) {
9273
9425
  filename = `${safeTopic}_${date}${reasonSuffix}${counter === 1 ? "" : `_${counter}`}.jsonl`;
9274
- path = join17(archiveDir, filename);
9426
+ path = join18(archiveDir, filename);
9275
9427
  try {
9276
9428
  writeFileSync8(path, body, { flag: "wx" });
9277
9429
  break;
@@ -9316,7 +9468,7 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
9316
9468
  const entries = readRawConversation(userId, topicTitle);
9317
9469
  if (entries.length === 0)
9318
9470
  return null;
9319
- const archiveDir = join17(getSharedWikiDir(), "archive");
9471
+ const archiveDir = join18(getSharedWikiDir(), "archive");
9320
9472
  mkdirSync10(archiveDir, { recursive: true });
9321
9473
  const safeTopic = sanitizeTopicName(topicTitle, true);
9322
9474
  const date = new Date().toISOString().slice(0, 10);
@@ -9344,7 +9496,7 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
9344
9496
  let counter = 1;
9345
9497
  while (true) {
9346
9498
  const suffix = counter === 1 ? "" : `_${counter}`;
9347
- const path = join17(archiveDir, `${safeTopic}_${date}${reasonSuffix}_events${suffix}.jsonl`);
9499
+ const path = join18(archiveDir, `${safeTopic}_${date}${reasonSuffix}_events${suffix}.jsonl`);
9348
9500
  try {
9349
9501
  writeFileSync8(path, body, { flag: "wx" });
9350
9502
  logger.info({ topicId, topicTitle, archive: path, eventCount: entries.length }, "archiveConversationEvents: archived raw conversation events");
@@ -10255,8 +10407,8 @@ function createAskUserRuntime(host) {
10255
10407
  return errorResult(`Error: failed to persist ask_user_question: ${error instanceof Error ? error.message : String(error)}`);
10256
10408
  }
10257
10409
  let resolveAnswer;
10258
- const promise = new Promise((resolve11) => {
10259
- resolveAnswer = resolve11;
10410
+ const promise = new Promise((resolve12) => {
10411
+ resolveAnswer = resolve12;
10260
10412
  });
10261
10413
  pendingAsks.set(message.id, {
10262
10414
  topicId: ctx.topicId,
@@ -10510,11 +10662,11 @@ var init_manager_utils = () => {};
10510
10662
  // ../../packages/core/src/platform/playwright/browser-processes.ts
10511
10663
  import { execFileSync as execFileSync6 } from "child_process";
10512
10664
  import { readdirSync as readdirSync3, unlinkSync as unlinkSync10 } from "fs";
10513
- import { createServer } from "net";
10514
- import { resolve as resolve12, sep } from "path";
10665
+ import { createServer as createServer2 } from "net";
10666
+ import { resolve as resolve13, sep } from "path";
10515
10667
  function isPortInUse(port) {
10516
10668
  return new Promise((resolveProbe) => {
10517
- const server = createServer();
10669
+ const server = createServer2();
10518
10670
  let settled = false;
10519
10671
  const finish = (occupied) => {
10520
10672
  if (settled)
@@ -10544,8 +10696,8 @@ async function reserveAvailableLoopbackPort(minPort, maxPort, reservedPorts, pro
10544
10696
  return null;
10545
10697
  }
10546
10698
  function killBrowserProcsForUserDataDir(userDataDir) {
10547
- const target = resolve12(userDataDir);
10548
- const profileRoot = resolve12(BROWSER_PROFILES_DIR);
10699
+ const target = resolve13(userDataDir);
10700
+ const profileRoot = resolve13(BROWSER_PROFILES_DIR);
10549
10701
  if (target !== profileRoot && !target.startsWith(`${profileRoot}${sep}`))
10550
10702
  return;
10551
10703
  let pids;
@@ -10566,7 +10718,7 @@ function killBrowserProcsForUserDataDir(userDataDir) {
10566
10718
  stdio: "pipe"
10567
10719
  }).toString().trim();
10568
10720
  const argDir = extractUserDataDirArg(cmdline);
10569
- if (!argDir || resolve12(argDir) !== target)
10721
+ if (!argDir || resolve13(argDir) !== target)
10570
10722
  continue;
10571
10723
  killProcessTreeChildren(pidNum);
10572
10724
  process.kill(pidNum, "SIGKILL");
@@ -10577,13 +10729,13 @@ function killBrowserProcsForUserDataDir(userDataDir) {
10577
10729
  }
10578
10730
  }
10579
10731
  function selectOrphanBrowserPids(procs, liveUserDataDirs, profileRoot, selfPid) {
10580
- const root = resolve12(profileRoot);
10581
- const live = new Set([...liveUserDataDirs].map((d) => resolve12(d)));
10732
+ const root = resolve13(profileRoot);
10733
+ const live = new Set([...liveUserDataDirs].map((d) => resolve13(d)));
10582
10734
  const out = [];
10583
10735
  for (const { pid, userDataDir } of procs) {
10584
10736
  if (pid === selfPid || !userDataDir)
10585
10737
  continue;
10586
- const dir = resolve12(userDataDir);
10738
+ const dir = resolve13(userDataDir);
10587
10739
  if (dir !== root && !dir.startsWith(`${root}${sep}`))
10588
10740
  continue;
10589
10741
  if (live.has(dir))
@@ -10599,7 +10751,7 @@ function reapOrphanBrowsers(liveUserDataDirs) {
10599
10751
  const daemonLease = getRuntimeProcessLease("node-daemon", Date.now(), Number.POSITIVE_INFINITY);
10600
10752
  if (!isBrowserJanitorOwner(daemonLease?.pid ?? null, process.pid))
10601
10753
  return;
10602
- const profileRoot = resolve12(BROWSER_PROFILES_DIR);
10754
+ const profileRoot = resolve13(BROWSER_PROFILES_DIR);
10603
10755
  let pids;
10604
10756
  try {
10605
10757
  pids = execFileSync6("pgrep", ["-f", "--", profileRoot], { stdio: "pipe" }).toString().trim();
@@ -10638,7 +10790,7 @@ function cleanSingletonFiles(userDataDir) {
10638
10790
  for (const f of files) {
10639
10791
  if (f.startsWith("Singleton")) {
10640
10792
  try {
10641
- unlinkSync10(resolve12(userDataDir, f));
10793
+ unlinkSync10(resolve13(userDataDir, f));
10642
10794
  logger.info({ file: f, userDataDir }, "Removed stale Singleton file");
10643
10795
  } catch (e) {
10644
10796
  logger.warn({ err: e, file: f }, "Failed to remove stale Chrome Singleton file");
@@ -10678,9 +10830,9 @@ var init_browser_processes = __esm(async () => {
10678
10830
 
10679
10831
  // ../../packages/core/src/platform/playwright/headed-launch.ts
10680
10832
  import { accessSync as accessSync2, constants as constants2 } from "fs";
10681
- import { delimiter, isAbsolute as isAbsolute4, resolve as resolve13 } from "path";
10833
+ import { delimiter, isAbsolute as isAbsolute4, resolve as resolve14 } from "path";
10682
10834
  function findExecutableOnPath(command, environment = process.env) {
10683
- const candidates = isAbsolute4(command) ? [command] : (environment.PATH ?? "").split(delimiter).filter(Boolean).map((directory) => resolve13(directory, command));
10835
+ const candidates = isAbsolute4(command) ? [command] : (environment.PATH ?? "").split(delimiter).filter(Boolean).map((directory) => resolve14(directory, command));
10684
10836
  for (const candidate of candidates) {
10685
10837
  try {
10686
10838
  accessSync2(candidate, constants2.X_OK);
@@ -10778,11 +10930,11 @@ var init_vault_public = __esm(async () => {
10778
10930
  });
10779
10931
 
10780
10932
  // ../../packages/core/src/platform/playwright/vault-broker.ts
10781
- import { randomBytes as randomBytes5, timingSafeEqual as timingSafeEqual2 } from "crypto";
10933
+ import { randomBytes as randomBytes6, timingSafeEqual as timingSafeEqual2 } from "crypto";
10782
10934
  import { chmodSync as chmodSync4 } from "fs";
10783
- import { createServer as createServer2 } from "net";
10784
- import { tmpdir as tmpdir2 } from "os";
10785
- import { join as join18 } from "path";
10935
+ import { createServer as createServer3 } from "net";
10936
+ import { tmpdir as tmpdir3 } from "os";
10937
+ import { join as join19 } from "path";
10786
10938
  function deepMapStrings2(value, transform) {
10787
10939
  if (typeof value === "string")
10788
10940
  return transform(value);
@@ -10868,8 +11020,8 @@ function authorized(actual, expected) {
10868
11020
  return left.length === right.length && timingSafeEqual2(left, right);
10869
11021
  }
10870
11022
  async function createBrowserVaultBroker(userId) {
10871
- const token = randomBytes5(32).toString("hex");
10872
- const socketPath = join18(process.platform === "win32" ? tmpdir2() : "/tmp", `negotium-browser-vault-${process.pid}-${randomBytes5(8).toString("hex")}.sock`);
11023
+ const token = randomBytes6(32).toString("hex");
11024
+ const socketPath = join19(process.platform === "win32" ? tmpdir3() : "/tmp", `negotium-browser-vault-${process.pid}-${randomBytes6(8).toString("hex")}.sock`);
10873
11025
  const retainedForms = new Map;
10874
11026
  const leases = new Map;
10875
11027
  const sockets = new Set;
@@ -10908,7 +11060,7 @@ async function createBrowserVaultBroker(userId) {
10908
11060
  return result.text;
10909
11061
  });
10910
11062
  const prepared = prepareInput(request.tool, substituted);
10911
- const lease = randomBytes5(24).toString("hex");
11063
+ const lease = randomBytes6(24).toString("hex");
10912
11064
  leases.set(lease, { boundary: prepared.boundary, createdAt: Date.now() });
10913
11065
  return {
10914
11066
  id,
@@ -10940,7 +11092,7 @@ async function createBrowserVaultBroker(userId) {
10940
11092
  }
10941
11093
  return { id, ok: false, error: "unknown operation" };
10942
11094
  };
10943
- const server = createServer2((socket) => {
11095
+ const server = createServer3((socket) => {
10944
11096
  sockets.add(socket);
10945
11097
  let pending = "";
10946
11098
  socket.setEncoding("utf8");
@@ -11068,24 +11220,24 @@ var init_browser_profiles = __esm(async () => {
11068
11220
 
11069
11221
  // ../../packages/core/src/platform/playwright/manager.ts
11070
11222
  import { execFileSync as execFileSync7, spawn as spawn5 } from "child_process";
11071
- import { createHash as createHash4, randomBytes as randomBytes6, timingSafeEqual as timingSafeEqual3 } from "crypto";
11223
+ import { createHash as createHash4, randomBytes as randomBytes7, timingSafeEqual as timingSafeEqual3 } from "crypto";
11072
11224
  import {
11073
11225
  cpSync,
11074
- existsSync as existsSync17,
11226
+ existsSync as existsSync18,
11075
11227
  mkdirSync as mkdirSync11,
11076
11228
  readFileSync as readFileSync15,
11077
11229
  rmSync as rmSync3,
11078
11230
  unlinkSync as unlinkSync11,
11079
11231
  writeFileSync as writeFileSync9
11080
11232
  } from "fs";
11081
- import { dirname as dirname11, join as join19, resolve as resolve14 } from "path";
11233
+ import { dirname as dirname12, join as join20, resolve as resolve15 } from "path";
11082
11234
  function removeDefaultProfileDataDir(userDataDir) {
11083
- const root = resolve14(BROWSER_PROFILES_DIR);
11084
- const target = resolve14(userDataDir);
11085
- if (dirname11(target) !== root) {
11235
+ const root = resolve15(BROWSER_PROFILES_DIR);
11236
+ const target = resolve15(userDataDir);
11237
+ if (dirname12(target) !== root) {
11086
11238
  throw new Error(`Refusing to delete browser profile outside managed root: ${target}`);
11087
11239
  }
11088
- const existed = existsSync17(target);
11240
+ const existed = existsSync18(target);
11089
11241
  rmSync3(target, { recursive: true, force: true });
11090
11242
  return existed;
11091
11243
  }
@@ -11168,14 +11320,14 @@ function portFileName(instanceKey) {
11168
11320
  function writePortFile(instanceKey, port) {
11169
11321
  try {
11170
11322
  mkdirSync11(managerHost.portsDir, { recursive: true });
11171
- writeFileSync9(join19(managerHost.portsDir, portFileName(instanceKey)), String(port));
11323
+ writeFileSync9(join20(managerHost.portsDir, portFileName(instanceKey)), String(port));
11172
11324
  } catch (e) {
11173
11325
  logger.warn({ err: e, instanceKey, port }, "Failed to save playwright port file");
11174
11326
  }
11175
11327
  }
11176
11328
  function deletePortFile(instanceKey) {
11177
11329
  try {
11178
- unlinkSync11(join19(managerHost.portsDir, portFileName(instanceKey)));
11330
+ unlinkSync11(join20(managerHost.portsDir, portFileName(instanceKey)));
11179
11331
  } catch (e) {
11180
11332
  if (e.code === "ENOENT")
11181
11333
  return;
@@ -11299,7 +11451,7 @@ function releasePort(port) {
11299
11451
  usedPorts.delete(port);
11300
11452
  }
11301
11453
  function defaultProfileDir(_ownerId, profile) {
11302
- return resolve14(BROWSER_PROFILES_DIR, profile);
11454
+ return resolve15(BROWSER_PROFILES_DIR, profile);
11303
11455
  }
11304
11456
  function resolveUserDataDir(instanceKey) {
11305
11457
  return managerHost.resolveInstanceDataDir(instanceKey);
@@ -11391,8 +11543,8 @@ async function spawnPlaywright(instanceKey, ownerId, reservedPort, browserBin =
11391
11543
  releasePort(port);
11392
11544
  throw new Error("Browser.rs managed mode does not support authenticated egress proxies");
11393
11545
  }
11394
- const capability = randomBytes6(32).toString("hex");
11395
- const spawnNonce = randomBytes6(32).toString("hex");
11546
+ const capability = randomBytes7(32).toString("hex");
11547
+ const spawnNonce = randomBytes7(32).toString("hex");
11396
11548
  let vaultBroker;
11397
11549
  try {
11398
11550
  vaultBroker = await createBrowserVaultBroker(ownerId);
@@ -11660,14 +11812,14 @@ async function cloneProfileForChild(opts) {
11660
11812
  killInstance(dstKey);
11661
11813
  await delay(500);
11662
11814
  }
11663
- if (!existsSync17(srcDir)) {
11815
+ if (!existsSync18(srcDir)) {
11664
11816
  return { copied: false, srcDir, dstDir, reason: "src-missing" };
11665
11817
  }
11666
11818
  try {
11667
- if (existsSync17(dstDir)) {
11819
+ if (existsSync18(dstDir)) {
11668
11820
  rmSync3(dstDir, { recursive: true, force: true });
11669
11821
  }
11670
- mkdirSync11(dirname11(dstDir), { recursive: true });
11822
+ mkdirSync11(dirname12(dstDir), { recursive: true });
11671
11823
  if (process.platform === "darwin") {
11672
11824
  try {
11673
11825
  execFileSync7("cp", ["-cR", srcDir, dstDir], { stdio: "pipe" });
@@ -11685,7 +11837,7 @@ async function cloneProfileForChild(opts) {
11685
11837
  cleanSingletonFiles(dstDir);
11686
11838
  for (const f of ["DevToolsActivePort", "LOCK"]) {
11687
11839
  try {
11688
- unlinkSync11(resolve14(dstDir, f));
11840
+ unlinkSync11(resolve15(dstDir, f));
11689
11841
  } catch {}
11690
11842
  }
11691
11843
  logger.info({ srcKey, dstKey, srcDir, dstDir }, "Cloned Playwright profile for child topic");
@@ -11813,7 +11965,7 @@ RULES:
11813
11965
 
11814
11966
  // ../../packages/core/src/agents/topic-cleanup.ts
11815
11967
  import { mkdirSync as mkdirSync12, renameSync as renameSync6, unlinkSync as unlinkSync12, writeFileSync as writeFileSync10 } from "fs";
11816
- import { dirname as dirname12 } from "path";
11968
+ import { dirname as dirname13 } from "path";
11817
11969
  function collectSessionIdsByAgent(entries, extraSessions = []) {
11818
11970
  const out = new Map;
11819
11971
  for (const e of entries) {
@@ -11879,7 +12031,7 @@ function createTopicLogMaintenance(host) {
11879
12031
  const path = runtimeHost.activeConversationPath(opts.userId, opts.topicName);
11880
12032
  const tempPath = `${path}.${process.pid}.${Date.now()}.tmp`;
11881
12033
  try {
11882
- mkdirSync12(dirname12(path), { recursive: true });
12034
+ mkdirSync12(dirname13(path), { recursive: true });
11883
12035
  writeFileSync10(tempPath, retained.length > 0 ? `${retained.map((entry) => JSON.stringify(entry)).join(`
11884
12036
  `)}
11885
12037
  ` : "", { flag: "wx" });
@@ -12333,8 +12485,8 @@ var init_runtime_turn_requests = __esm(async () => {
12333
12485
  // ../../packages/core/src/topics/session.ts
12334
12486
  import { randomUUID as randomUUID11 } from "crypto";
12335
12487
  import { mkdtempSync as mkdtempSync2, rmSync as rmSync4, writeFileSync as writeFileSync11 } from "fs";
12336
- import { tmpdir as tmpdir3 } from "os";
12337
- import { join as join20 } from "path";
12488
+ import { tmpdir as tmpdir4 } from "os";
12489
+ import { join as join21 } from "path";
12338
12490
  function previousCompactedSummary(entries) {
12339
12491
  for (let index = entries.length - 2;index >= 0; index -= 1) {
12340
12492
  const request = entries[index]?.event;
@@ -12464,7 +12616,7 @@ function formatCompactElapsed(startedAt) {
12464
12616
  async function summarizeTopicContext(request) {
12465
12617
  const startedAt = Date.now();
12466
12618
  const sessionIds = [];
12467
- const compactCwd = mkdtempSync2(join20(tmpdir3(), "negotium-compact-"));
12619
+ const compactCwd = mkdtempSync2(join21(tmpdir4(), "negotium-compact-"));
12468
12620
  const abortController = new AbortController;
12469
12621
  const relayAbort = () => abortController.abort(request.signal?.reason);
12470
12622
  if (request.signal?.aborted)
@@ -12491,7 +12643,7 @@ async function summarizeTopicContext(request) {
12491
12643
  let error = "";
12492
12644
  let toolViolation = false;
12493
12645
  let compactionLogCalls = 0;
12494
- const compactionLogPath = join20(compactCwd, "conversation.log");
12646
+ const compactionLogPath = join21(compactCwd, "conversation.log");
12495
12647
  try {
12496
12648
  const compactionMcp = useCompactionLog ? {
12497
12649
  compact_log: {
@@ -13110,14 +13262,14 @@ var init_derive = __esm(async () => {
13110
13262
  });
13111
13263
 
13112
13264
  // ../../packages/core/src/query/session-inbox-path.ts
13113
- import { join as join21 } from "path";
13265
+ import { join as join22 } from "path";
13114
13266
  function sessionInboxPath(userId, topicId) {
13115
13267
  const key = Buffer.from(topicId, "utf8").toString("base64url");
13116
- return join21(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${JSONL_SUFFIX}`);
13268
+ return join22(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${JSONL_SUFFIX}`);
13117
13269
  }
13118
13270
  function scheduledSessionInboxPath(userId, topicId) {
13119
13271
  const key = Buffer.from(topicId, "utf8").toString("base64url");
13120
- return join21(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${SCHEDULE_SUFFIX}`);
13272
+ return join22(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${SCHEDULE_SUFFIX}`);
13121
13273
  }
13122
13274
  var TOPIC_ID_FILE_PREFIX = "topic-id-", JSONL_SUFFIX = ".jsonl", SCHEDULE_SUFFIX = ".schedule";
13123
13275
  var init_session_inbox_path = __esm(() => {
@@ -13126,13 +13278,13 @@ var init_session_inbox_path = __esm(() => {
13126
13278
 
13127
13279
  // ../../packages/core/src/query/session-inbox-cleanup.ts
13128
13280
  import { unlinkSync as unlinkSync14 } from "fs";
13129
- import { basename as basename3, join as join22 } from "path";
13281
+ import { basename as basename3, join as join23 } from "path";
13130
13282
  function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
13131
13283
  const live = sessionInboxPath(userId, topicId);
13132
13284
  const scheduled = scheduledSessionInboxPath(userId, topicId);
13133
13285
  const candidates = new Set([live, `${live}.processing`, scheduled, `${scheduled}.processing`]);
13134
13286
  if (legacyTopicTitle && legacyTopicTitle !== "." && legacyTopicTitle !== ".." && basename3(legacyTopicTitle) === legacyTopicTitle) {
13135
- const legacyBase = join22(SESSION_INBOX_DIR, userId, legacyTopicTitle);
13287
+ const legacyBase = join23(SESSION_INBOX_DIR, userId, legacyTopicTitle);
13136
13288
  for (const suffix of [".jsonl", ".jsonl.processing", ".schedule", ".schedule.processing"]) {
13137
13289
  candidates.add(`${legacyBase}${suffix}`);
13138
13290
  }
@@ -13158,16 +13310,16 @@ var init_session_inbox_cleanup = __esm(() => {
13158
13310
 
13159
13311
  // ../../packages/core/src/query/state.ts
13160
13312
  import { mkdirSync as mkdirSync14, renameSync as renameSync7, unlinkSync as unlinkSync15, writeFileSync as writeFileSync12 } from "fs";
13161
- import { basename as basename4, join as join23 } from "path";
13313
+ import { basename as basename4, join as join24 } from "path";
13162
13314
  function createQueryStateStore(options) {
13163
13315
  const sanitize = options.sanitizeTopicId ?? sanitizeId;
13164
- const queryStateDirPath = (userId) => join23(options.usersLogDir, String(userId), "active-queries");
13165
- const queryStateFile = (userId, topicId) => join23(queryStateDirPath(userId), `${sanitize(topicId)}.json`);
13316
+ const queryStateDirPath = (userId) => join24(options.usersLogDir, String(userId), "active-queries");
13317
+ const queryStateFile = (userId, topicId) => join24(queryStateDirPath(userId), `${sanitize(topicId)}.json`);
13166
13318
  const legacyQueryStateFile = (userId, topicName) => {
13167
13319
  if (!topicName || topicName === "." || topicName === ".." || basename4(topicName) !== topicName) {
13168
13320
  return null;
13169
13321
  }
13170
- return join23(queryStateDirPath(userId), `${topicName}.json`);
13322
+ return join24(queryStateDirPath(userId), `${topicName}.json`);
13171
13323
  };
13172
13324
  return {
13173
13325
  write(userId, topicId, topicName, task) {
@@ -13328,30 +13480,30 @@ import {
13328
13480
  unlinkSync as unlinkSync16,
13329
13481
  writeFileSync as writeFileSync13
13330
13482
  } from "fs";
13331
- import { dirname as dirname13, join as join24 } from "path";
13483
+ import { dirname as dirname14, join as join25 } from "path";
13332
13484
  function pendingAskDir(userId) {
13333
13485
  const rawUserId = String(userId);
13334
13486
  const safeUserId = /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash6("sha256").update(rawUserId).digest("hex")}`;
13335
- return join24(resolveStorageSessionAsksDir(), safeUserId);
13487
+ return join25(resolveStorageSessionAsksDir(), safeUserId);
13336
13488
  }
13337
13489
  function encodeAskKey(key) {
13338
13490
  return JSON.stringify([key.from, key.to]);
13339
13491
  }
13340
13492
  function pendingAskPath(key) {
13341
13493
  const digest = createHash6("sha256").update(encodeAskKey(key)).digest("hex");
13342
- return join24(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
13494
+ return join25(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
13343
13495
  }
13344
13496
  function v2PendingAskPath(key) {
13345
13497
  const encoded = Buffer.from(encodeAskKey(key), "utf8").toString("base64url");
13346
- return join24(pendingAskDir(key.userId), `${V2_ASK_FILENAME_PREFIX}${encoded}.pending`);
13498
+ return join25(pendingAskDir(key.userId), `${V2_ASK_FILENAME_PREFIX}${encoded}.pending`);
13347
13499
  }
13348
13500
  function legacyPendingAskPath(key) {
13349
13501
  if (key.from.includes("/") || key.from.includes("\\") || key.to.includes("/") || key.to.includes("\\") || key.from.includes("\x00") || key.to.includes("\x00")) {
13350
13502
  return null;
13351
13503
  }
13352
13504
  const dir = pendingAskDir(key.userId);
13353
- const candidate = join24(dir, `${key.from}___${key.to}.pending`);
13354
- return dirname13(candidate) === dir ? candidate : null;
13505
+ const candidate = join25(dir, `${key.from}___${key.to}.pending`);
13506
+ return dirname14(candidate) === dir ? candidate : null;
13355
13507
  }
13356
13508
  function parsePendingAskFilename(fileName) {
13357
13509
  if (!fileName.endsWith(".pending"))
@@ -13591,7 +13743,7 @@ function listPendingAsksForCaller(args) {
13591
13743
  const parsed = isV3 ? { from: args.from, to: "" } : parsePendingAskFilename(fileName);
13592
13744
  if (!parsed)
13593
13745
  continue;
13594
- const path = join24(dir, fileName);
13746
+ const path = join25(dir, fileName);
13595
13747
  const record = readPendingAskFile(path, {
13596
13748
  userId: args.userId,
13597
13749
  from: parsed.from,
@@ -13633,7 +13785,7 @@ function deletePendingAsksForTopic(args) {
13633
13785
  }
13634
13786
  let deleted = 0;
13635
13787
  for (const fileName of files) {
13636
- const path = join24(dir, fileName);
13788
+ const path = join25(dir, fileName);
13637
13789
  const parsed = parsePendingAskFilename(fileName);
13638
13790
  const record = readPendingAskFile(path, {
13639
13791
  userId: args.userId,
@@ -14033,7 +14185,7 @@ body{font-family:system-ui,-apple-system,"Segoe UI",sans-serif;background:var(--
14033
14185
  // ../../packages/core/src/storage/token-stats.ts
14034
14186
  import { createHash as createHash7 } from "crypto";
14035
14187
  import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "fs";
14036
- import { join as join25 } from "path";
14188
+ import { join as join26 } from "path";
14037
14189
  function tokenStatsFileId(userId) {
14038
14190
  const rawUserId = String(userId);
14039
14191
  return /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash7("sha256").update(rawUserId).digest("hex")}`;
@@ -14042,7 +14194,7 @@ function queriesPath(userId) {
14042
14194
  const fileId = tokenStatsFileId(userId);
14043
14195
  const logDir = resolveStorageLogDir();
14044
14196
  mkdirSync16(logDir, { recursive: true });
14045
- return join25(logDir, `token-queries-${fileId}.jsonl`);
14197
+ return join26(logDir, `token-queries-${fileId}.jsonl`);
14046
14198
  }
14047
14199
  function estimateUsageCost(agent, model, usage) {
14048
14200
  const prices = TOKEN_PRICES[`${agent}:${model}`];
@@ -14358,7 +14510,7 @@ var init_lifecycle = __esm(async () => {
14358
14510
  // ../../packages/core/src/runtime/attachments.ts
14359
14511
  import { randomUUID as randomUUID14 } from "crypto";
14360
14512
  import { copyFileSync as copyFileSync2, mkdirSync as mkdirSync17, writeFileSync as writeFileSync15 } from "fs";
14361
- import { basename as basename5, join as join26 } from "path";
14513
+ import { basename as basename5, join as join27 } from "path";
14362
14514
  function workspaceCwdFor(topicId) {
14363
14515
  return resolveTopicWorkspaceDir(topicId);
14364
14516
  }
@@ -14371,7 +14523,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
14371
14523
  if (!attachmentIds?.length)
14372
14524
  return [];
14373
14525
  const out = [];
14374
- const destDir = join26(workspaceCwdFor(topicId), "attachments", queryId);
14526
+ const destDir = join27(workspaceCwdFor(topicId), "attachments", queryId);
14375
14527
  for (const rawId of attachmentIds) {
14376
14528
  if (typeof rawId !== "string")
14377
14529
  continue;
@@ -14388,7 +14540,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
14388
14540
  mkdirSync17(destDir, { recursive: true });
14389
14541
  const index = String(out.length + 1).padStart(2, "0");
14390
14542
  const safeName = safeAttachmentFilename(attachment.filename, fileId);
14391
- const destPath = join26(destDir, `${index}-${fileId.slice(0, 8)}-${safeName}`);
14543
+ const destPath = join27(destDir, `${index}-${fileId.slice(0, 8)}-${safeName}`);
14392
14544
  copyFileSync2(sourcePath, destPath);
14393
14545
  out.push({
14394
14546
  id: attachment.id,
@@ -14418,10 +14570,10 @@ function promptWithAttachments(prompt, attachments) {
14418
14570
  return composeAttachmentPrompt(prompt, attachments.map(({ filename, path }) => attachmentPromptLine(filename, path)));
14419
14571
  }
14420
14572
  function ingestAttachment(args) {
14421
- const destDir = join26(UPLOADS_DIR, args.topicId);
14573
+ const destDir = join27(UPLOADS_DIR, args.topicId);
14422
14574
  mkdirSync17(destDir, { recursive: true });
14423
14575
  const safeName = safeAttachmentFilename(args.filename, "upload");
14424
- const destPath = join26(destDir, `${Date.now()}-${randomUUID14().slice(0, 8)}-${safeName}`);
14576
+ const destPath = join27(destDir, `${Date.now()}-${randomUUID14().slice(0, 8)}-${safeName}`);
14425
14577
  if (args.sourcePath !== undefined) {
14426
14578
  copyFileSync2(args.sourcePath, destPath);
14427
14579
  } else if (args.bytes !== undefined) {
@@ -14596,12 +14748,12 @@ var init_errors = __esm(() => {
14596
14748
 
14597
14749
  // ../../packages/core/src/runtime/event-heartbeat.ts
14598
14750
  function nextOrHeartbeat(pending, intervalMs) {
14599
- return new Promise((resolve15, reject) => {
14600
- const timer = setTimeout(() => resolve15({ kind: "heartbeat" }), intervalMs);
14751
+ return new Promise((resolve16, reject) => {
14752
+ const timer = setTimeout(() => resolve16({ kind: "heartbeat" }), intervalMs);
14601
14753
  timer.unref?.();
14602
14754
  pending.then((result) => {
14603
14755
  clearTimeout(timer);
14604
- resolve15({ kind: "event", result });
14756
+ resolve16({ kind: "event", result });
14605
14757
  }, (error) => {
14606
14758
  clearTimeout(timer);
14607
14759
  reject(error);
@@ -14922,7 +15074,7 @@ var init_visual_html = __esm(() => {
14922
15074
 
14923
15075
  // ../../packages/core/src/runtime/visuals.ts
14924
15076
  import { realpathSync as realpathSync4 } from "fs";
14925
- import { isAbsolute as isAbsolute5, resolve as resolve15 } from "path";
15077
+ import { isAbsolute as isAbsolute5, resolve as resolve16 } from "path";
14926
15078
  function activeVisualHtmlForPrompt(html) {
14927
15079
  if (html.length <= ACTIVE_VISUAL_PROMPT_MAX_CHARS) {
14928
15080
  return { html, omittedChars: 0 };
@@ -14973,8 +15125,8 @@ function topicAllowsVisualFileId(topicId, fileId) {
14973
15125
  return topicHasAttachmentFileId(topicId, fileId) || topicHasVisualFileId(topicId, fileId);
14974
15126
  }
14975
15127
  function isPathInside(baseDir, filePath) {
14976
- const base = resolve15(baseDir);
14977
- const normalized = resolve15(filePath);
15128
+ const base = resolve16(baseDir);
15129
+ const normalized = resolve16(filePath);
14978
15130
  try {
14979
15131
  const realBase = realpathSync4(base);
14980
15132
  const real = realpathSync4(normalized);
@@ -15036,7 +15188,7 @@ function resolveVisualMediaInput(topicId, input) {
15036
15188
  }
15037
15189
  const rawPath = input.file_path.trim();
15038
15190
  const cwd = workspaceCwdFor(topicId);
15039
- const candidate = isAbsolute5(rawPath) ? rawPath : resolve15(cwd, rawPath);
15191
+ const candidate = isAbsolute5(rawPath) ? rawPath : resolve16(cwd, rawPath);
15040
15192
  if (!isPathInside(cwd, candidate)) {
15041
15193
  return { error: "file_path must be inside the topic workspace" };
15042
15194
  }
@@ -15074,7 +15226,7 @@ var init_visuals = __esm(async () => {
15074
15226
  // ../../packages/core/src/runtime/turn-event-stream.ts
15075
15227
  import { randomUUID as randomUUID15 } from "crypto";
15076
15228
  import { realpathSync as realpathSync5, statSync as statSync9 } from "fs";
15077
- import { isAbsolute as isAbsolute6, resolve as resolve16 } from "path";
15229
+ import { isAbsolute as isAbsolute6, resolve as resolve17 } from "path";
15078
15230
  function sessionEventMatchesCurrentExecution(topicId, queryId, agent, model) {
15079
15231
  if (getRoomQuery(topicId)?.queryId !== queryId)
15080
15232
  return false;
@@ -15427,7 +15579,7 @@ ${JSON.stringify(event.input ?? {})}`);
15427
15579
  case "file":
15428
15580
  if (!silent && peerBridge) {
15429
15581
  const cwd = workspaceCwdFor(topicId);
15430
- const path = isAbsolute6(event.path) ? event.path : resolve16(cwd, event.path);
15582
+ const path = isAbsolute6(event.path) ? event.path : resolve17(cwd, event.path);
15431
15583
  if (!isPathInside(cwd, path)) {
15432
15584
  logger.warn({ topicId, path }, "peer output file is outside the topic workspace");
15433
15585
  break;
@@ -15709,15 +15861,15 @@ var init_turn_session = __esm(async () => {
15709
15861
  });
15710
15862
 
15711
15863
  // ../../packages/core/src/storage/app-settings.ts
15712
- import { existsSync as existsSync18, mkdirSync as mkdirSync18, readFileSync as readFileSync17, writeFileSync as writeFileSync16 } from "fs";
15713
- import { dirname as dirname14, join as join27 } from "path";
15864
+ import { existsSync as existsSync19, mkdirSync as mkdirSync18, readFileSync as readFileSync17, writeFileSync as writeFileSync16 } from "fs";
15865
+ import { dirname as dirname15, join as join28 } from "path";
15714
15866
  function settingsFile() {
15715
- return join27(resolveStorageDataDir(), "otium-settings.json");
15867
+ return join28(resolveStorageDataDir(), "otium-settings.json");
15716
15868
  }
15717
15869
  function getGlobalAiName() {
15718
15870
  const path = settingsFile();
15719
15871
  try {
15720
- if (existsSync18(path)) {
15872
+ if (existsSync19(path)) {
15721
15873
  const data = JSON.parse(readFileSync17(path, "utf8"));
15722
15874
  if (typeof data.aiName === "string" && data.aiName.trim()) {
15723
15875
  return data.aiName.trim();
@@ -15806,8 +15958,8 @@ __export(exports_turn_runner, {
15806
15958
  AGENT_DISPLAY_NAME: () => AGENT_DISPLAY_NAME
15807
15959
  });
15808
15960
  import { randomUUID as randomUUID16 } from "crypto";
15809
- import { existsSync as existsSync19, mkdirSync as mkdirSync19, readdirSync as readdirSync5, statSync as statSync10 } from "fs";
15810
- import { join as join28 } from "path";
15961
+ import { existsSync as existsSync20, mkdirSync as mkdirSync19, readdirSync as readdirSync5, statSync as statSync10 } from "fs";
15962
+ import { join as join29 } from "path";
15811
15963
  function withDefaultPlaywright(configuredMcp, isManager) {
15812
15964
  if (isManager)
15813
15965
  return configuredMcp;
@@ -15862,8 +16014,8 @@ function appendAskReplyMessage(topicId, text2, agentType) {
15862
16014
  return message;
15863
16015
  }
15864
16016
  function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, matchesTitle, preferExact = true) {
15865
- const preferred = join28(directory, preferredFilename);
15866
- if (preferExact && existsSync19(preferred))
16017
+ const preferred = join29(directory, preferredFilename);
16018
+ if (preferExact && existsSync20(preferred))
15867
16019
  return preferred;
15868
16020
  let newestLegacyId = null;
15869
16021
  let newestTitle = null;
@@ -15873,7 +16025,7 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
15873
16025
  const legacyIdMatch = !titleMatch && matchesLegacyId(filename);
15874
16026
  if (!titleMatch && !legacyIdMatch)
15875
16027
  continue;
15876
- const path = join28(directory, filename);
16028
+ const path = join29(directory, filename);
15877
16029
  const mtimeMs = statSync10(path).mtimeMs;
15878
16030
  if (titleMatch) {
15879
16031
  if (!newestTitle || mtimeMs > newestTitle.mtimeMs) {
@@ -15887,10 +16039,10 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
15887
16039
  return newestTitle?.path ?? newestLegacyId?.path ?? preferred;
15888
16040
  }
15889
16041
  function resolveWikiMemoryMirror(wikiDir, topicId, topicTitle) {
15890
- const briefFile = resolveWikiMirrorPath(join28(wikiDir, "topic"), `${wikiBriefStorageKey(topicTitle, topicId)}.md`, (filename) => isTopicBriefFile(filename, topicId), (filename) => isTopicBriefFile(filename, topicId, topicTitle));
15891
- const hasBriefFile = existsSync19(briefFile) && statSync10(briefFile).isFile();
15892
- const latestSummaryCandidate = resolveWikiMirrorPath(join28(wikiDir, "summaries"), `__missing__-${wikiSummaryFilename("0000-00-00", topicTitle, topicId)}`, (filename) => isTopicSummaryFile(filename, topicId), (filename) => isTopicSummaryFile(filename, topicId, topicTitle), false);
15893
- const latestSummaryFile = existsSync19(latestSummaryCandidate) && statSync10(latestSummaryCandidate).isFile() ? latestSummaryCandidate : null;
16042
+ const briefFile = resolveWikiMirrorPath(join29(wikiDir, "topic"), `${wikiBriefStorageKey(topicTitle, topicId)}.md`, (filename) => isTopicBriefFile(filename, topicId), (filename) => isTopicBriefFile(filename, topicId, topicTitle));
16043
+ const hasBriefFile = existsSync20(briefFile) && statSync10(briefFile).isFile();
16044
+ const latestSummaryCandidate = resolveWikiMirrorPath(join29(wikiDir, "summaries"), `__missing__-${wikiSummaryFilename("0000-00-00", topicTitle, topicId)}`, (filename) => isTopicSummaryFile(filename, topicId), (filename) => isTopicSummaryFile(filename, topicId, topicTitle), false);
16045
+ const latestSummaryFile = existsSync20(latestSummaryCandidate) && statSync10(latestSummaryCandidate).isFile() ? latestSummaryCandidate : null;
15894
16046
  return { briefFile, hasBriefFile, latestSummaryFile };
15895
16047
  }
15896
16048
  async function streamAgentEvents(topicId, topicTitle, queryId, events, control, agentType, model, effort, userId, retryableSessionExpired = true, onSessionId, execution) {
@@ -17924,8 +18076,8 @@ init_common();
17924
18076
  import { z as z2 } from "zod";
17925
18077
 
17926
18078
  // ../../packages/core/src/agents/mcp-tools/inline-assets.ts
17927
- import { existsSync as existsSync16, readFileSync as readFileSync14, statSync as statSync7 } from "fs";
17928
- import { extname, isAbsolute as isAbsolute3, resolve as resolve11 } from "path";
18079
+ import { existsSync as existsSync17, readFileSync as readFileSync14, statSync as statSync7 } from "fs";
18080
+ import { extname, isAbsolute as isAbsolute3, resolve as resolve12 } from "path";
17929
18081
  var MIME_BY_EXT = {
17930
18082
  ".apng": "image/apng",
17931
18083
  ".avif": "image/avif",
@@ -17970,10 +18122,10 @@ function inlineLocalAssets(html, options) {
17970
18122
  const relPath = stripSuffix(ref);
17971
18123
  if (!relPath)
17972
18124
  return null;
17973
- const abs = isAbsolute3(relPath) ? relPath : resolve11(baseDir, relPath);
18125
+ const abs = isAbsolute3(relPath) ? relPath : resolve12(baseDir, relPath);
17974
18126
  let bytes;
17975
18127
  try {
17976
- if (!existsSync16(abs) || !statSync7(abs).isFile()) {
18128
+ if (!existsSync17(abs) || !statSync7(abs).isFile()) {
17977
18129
  unresolved.push(ref);
17978
18130
  cache.set(ref, null);
17979
18131
  return null;
@@ -18930,7 +19082,6 @@ var otiumVisualToolDefinitions = [
18930
19082
  await init_task_events();
18931
19083
  init_tool_format();
18932
19084
  await init_topic_cleanup();
18933
- init_vault_tool_policy();
18934
19085
  export {
18935
19086
  withTaskSnapshots,
18936
19087
  withCodexSpawnSerial,
@@ -18945,23 +19096,19 @@ export {
18945
19096
  showMermaidTool,
18946
19097
  showImageTool,
18947
19098
  showHtmlTool,
18948
- shouldRedirectVaultTool,
18949
19099
  rotateTopicLogs,
18950
19100
  resolveTaskEventScope,
18951
19101
  registerOwnedCodexPids,
18952
- referencesRuntimeSecretStorage,
18953
19102
  purgeTopicLogs,
18954
19103
  otiumVisualToolDefinitions,
18955
19104
  normalizeAskUserQuestionInput,
18956
19105
  normalizeAskUserChoices,
18957
19106
  killOwnedCodexTreesForShutdown,
18958
19107
  killCodexTrees,
18959
- isVaultBrokerTool,
18960
19108
  formatToolUse,
18961
19109
  forkAgentSession,
18962
19110
  findNewCodexChildren,
18963
19111
  defaultAskUserDurabilityHost,
18964
- createVaultToolPolicy,
18965
19112
  createTopicLogMaintenance,
18966
19113
  createSubagentLifecycle,
18967
19114
  createSelfConfigToolDefinitionsForCore,
@@ -18982,9 +19129,8 @@ export {
18982
19129
  archiveActiveTopicForMemory,
18983
19130
  acquireCodexSpawnLock,
18984
19131
  VISUALS_MCP_KEY,
18985
- VAULT_BROKER_REDIRECT_ERROR,
18986
19132
  MIN_MEMORY_ARCHIVE_EXCHANGES,
18987
19133
  DEFAULT_SELF_CONFIG_PRODUCT
18988
19134
  };
18989
19135
 
18990
- //# debugId=AA945E7A95E4EEDF64756E2164756E21
19136
+ //# debugId=0CE166A02CA7806164756E2164756E21