negotium 0.1.12 → 0.1.13

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 (137) hide show
  1. package/dist/canonical-mcp-bridge.js +2 -3
  2. package/dist/canonical-mcp-bridge.js.map +1 -1
  3. package/dist/chunk-a9y2rwxf.js.map +1 -1
  4. package/dist/{chunk-j0kjscb7.js → chunk-s2gez3wg.js} +20 -2
  5. package/dist/{chunk-j0kjscb7.js.map → chunk-s2gez3wg.js.map} +2 -2
  6. package/dist/cron.js +49 -25
  7. package/dist/cron.js.map +15 -14
  8. package/dist/hosted-agent.js +3012 -17
  9. package/dist/hosted-agent.js.map +30 -3
  10. package/dist/main.js +31323 -36
  11. package/dist/main.js.map +198 -3
  12. package/dist/prompts.js +11 -8
  13. package/dist/prompts.js.map +4 -4
  14. package/dist/runtime/src/application/submit-user-message.ts +3 -0
  15. package/dist/runtime/src/index.ts +7 -0
  16. package/dist/runtime/src/mcp/runtime-spec.ts +3 -0
  17. package/dist/runtime/src/mcp/session-comm/server.ts +1 -1
  18. package/dist/runtime/src/platform/mcp-config.ts +13 -0
  19. package/dist/runtime/src/prompts/builders.ts +20 -6
  20. package/dist/runtime/src/query/active-rooms.ts +2 -0
  21. package/dist/runtime/src/runtime/delivery-ack.ts +112 -0
  22. package/dist/runtime/src/runtime/errors.ts +12 -12
  23. package/dist/runtime/src/runtime/turn-runner.ts +12 -0
  24. package/dist/runtime/src/storage/runtime-turn-requests.ts +1 -0
  25. package/dist/runtime/src/types/api.ts +2 -0
  26. package/dist/runtime/src/types.ts +2 -0
  27. package/dist/runtime/src/version.ts +1 -1
  28. package/dist/runtime-helpers.js.map +1 -1
  29. package/dist/storage.js.map +1 -1
  30. package/dist/types/packages/core/src/mcp/runtime-spec.d.ts +2 -0
  31. package/dist/types/packages/core/src/platform/mcp-config.d.ts +4 -0
  32. package/dist/types/packages/core/src/prompts/builders.d.ts +2 -0
  33. package/dist/types/packages/core/src/types/api.d.ts +2 -0
  34. package/dist/types/packages/core/src/types.d.ts +2 -0
  35. package/dist/types/packages/core/src/version.d.ts +1 -1
  36. package/dist/vault.js.map +1 -1
  37. package/package.json +1 -1
  38. package/dist/chunk-00q25k7p.js +0 -2387
  39. package/dist/chunk-00q25k7p.js.map +0 -26
  40. package/dist/chunk-03kv7mvj.js +0 -2152
  41. package/dist/chunk-03kv7mvj.js.map +0 -15
  42. package/dist/chunk-05pm51dh.js +0 -589
  43. package/dist/chunk-05pm51dh.js.map +0 -11
  44. package/dist/chunk-0eh16bk1.js +0 -2936
  45. package/dist/chunk-0eh16bk1.js.map +0 -20
  46. package/dist/chunk-0yfqyv88.js +0 -108
  47. package/dist/chunk-0yfqyv88.js.map +0 -10
  48. package/dist/chunk-1k7t7bnx.js +0 -97
  49. package/dist/chunk-1k7t7bnx.js.map +0 -10
  50. package/dist/chunk-3gkfr9vb.js +0 -431
  51. package/dist/chunk-3gkfr9vb.js.map +0 -11
  52. package/dist/chunk-5akd1gbj.js +0 -281
  53. package/dist/chunk-5akd1gbj.js.map +0 -10
  54. package/dist/chunk-7k19pcg8.js +0 -577
  55. package/dist/chunk-7k19pcg8.js.map +0 -14
  56. package/dist/chunk-81tbfbmt.js +0 -10
  57. package/dist/chunk-81tbfbmt.js.map +0 -10
  58. package/dist/chunk-82qhv1mq.js +0 -512
  59. package/dist/chunk-82qhv1mq.js.map +0 -13
  60. package/dist/chunk-8dy7e2a9.js +0 -103
  61. package/dist/chunk-8dy7e2a9.js.map +0 -10
  62. package/dist/chunk-8f2sqmrj.js +0 -1712
  63. package/dist/chunk-8f2sqmrj.js.map +0 -18
  64. package/dist/chunk-9hjeemfz.js +0 -372
  65. package/dist/chunk-9hjeemfz.js.map +0 -10
  66. package/dist/chunk-a4aa2ccv.js +0 -141
  67. package/dist/chunk-a4aa2ccv.js.map +0 -10
  68. package/dist/chunk-bsg215q3.js +0 -3536
  69. package/dist/chunk-bsg215q3.js.map +0 -20
  70. package/dist/chunk-bxnfsc7w.js +0 -58
  71. package/dist/chunk-bxnfsc7w.js.map +0 -10
  72. package/dist/chunk-c500xe9z.js +0 -33
  73. package/dist/chunk-c500xe9z.js.map +0 -10
  74. package/dist/chunk-cngrf7ab.js +0 -149
  75. package/dist/chunk-cngrf7ab.js.map +0 -10
  76. package/dist/chunk-d7tprf06.js +0 -53
  77. package/dist/chunk-d7tprf06.js.map +0 -10
  78. package/dist/chunk-ddnrmkrv.js +0 -61
  79. package/dist/chunk-ddnrmkrv.js.map +0 -10
  80. package/dist/chunk-edb07sjp.js +0 -567
  81. package/dist/chunk-edb07sjp.js.map +0 -14
  82. package/dist/chunk-ejcm6zx8.js +0 -591
  83. package/dist/chunk-ejcm6zx8.js.map +0 -11
  84. package/dist/chunk-ezs352qs.js +0 -237
  85. package/dist/chunk-ezs352qs.js.map +0 -11
  86. package/dist/chunk-f5xgprg1.js +0 -59
  87. package/dist/chunk-f5xgprg1.js.map +0 -10
  88. package/dist/chunk-fbtb3v0s.js +0 -1339
  89. package/dist/chunk-fbtb3v0s.js.map +0 -16
  90. package/dist/chunk-ffefbd3r.js +0 -17
  91. package/dist/chunk-ffefbd3r.js.map +0 -10
  92. package/dist/chunk-gaknyw04.js +0 -708
  93. package/dist/chunk-gaknyw04.js.map +0 -14
  94. package/dist/chunk-gxmny6tq.js +0 -1637
  95. package/dist/chunk-gxmny6tq.js.map +0 -15
  96. package/dist/chunk-h7bj5zwb.js +0 -3069
  97. package/dist/chunk-h7bj5zwb.js.map +0 -32
  98. package/dist/chunk-hp4g7wx7.js +0 -46
  99. package/dist/chunk-hp4g7wx7.js.map +0 -10
  100. package/dist/chunk-hwy3n31w.js +0 -21
  101. package/dist/chunk-hwy3n31w.js.map +0 -9
  102. package/dist/chunk-jzz91jwh.js +0 -70
  103. package/dist/chunk-jzz91jwh.js.map +0 -10
  104. package/dist/chunk-k778y16p.js +0 -153
  105. package/dist/chunk-k778y16p.js.map +0 -11
  106. package/dist/chunk-mh5mexsf.js +0 -147
  107. package/dist/chunk-mh5mexsf.js.map +0 -11
  108. package/dist/chunk-mnwaext5.js +0 -318
  109. package/dist/chunk-mnwaext5.js.map +0 -10
  110. package/dist/chunk-nkgs40ch.js +0 -23
  111. package/dist/chunk-nkgs40ch.js.map +0 -10
  112. package/dist/chunk-pz57vwsm.js +0 -250
  113. package/dist/chunk-pz57vwsm.js.map +0 -11
  114. package/dist/chunk-r6kdp7gn.js +0 -252
  115. package/dist/chunk-r6kdp7gn.js.map +0 -10
  116. package/dist/chunk-rkvrkcgx.js +0 -117
  117. package/dist/chunk-rkvrkcgx.js.map +0 -10
  118. package/dist/chunk-s74rdyqe.js +0 -117
  119. package/dist/chunk-s74rdyqe.js.map +0 -12
  120. package/dist/chunk-sa874j5c.js +0 -9
  121. package/dist/chunk-sa874j5c.js.map +0 -10
  122. package/dist/chunk-sffqdkvq.js +0 -122
  123. package/dist/chunk-sffqdkvq.js.map +0 -10
  124. package/dist/chunk-tcs9qjps.js +0 -64
  125. package/dist/chunk-tcs9qjps.js.map +0 -10
  126. package/dist/chunk-wx83ep8e.js +0 -131
  127. package/dist/chunk-wx83ep8e.js.map +0 -10
  128. package/dist/chunk-xag86ng3.js +0 -122
  129. package/dist/chunk-xag86ng3.js.map +0 -10
  130. package/dist/chunk-xfdkep71.js +0 -371
  131. package/dist/chunk-xfdkep71.js.map +0 -11
  132. package/dist/chunk-xhm1rfpt.js +0 -2907
  133. package/dist/chunk-xhm1rfpt.js.map +0 -24
  134. package/dist/chunk-xpcps28p.js +0 -2138
  135. package/dist/chunk-xpcps28p.js.map +0 -29
  136. package/dist/chunk-yb4rbev9.js +0 -214
  137. package/dist/chunk-yb4rbev9.js.map +0 -10
@@ -1,22 +1,3017 @@
1
1
  // @bun
2
2
  import {
3
- claudeProvider,
4
- codexProvider,
5
- configureAgentExecutionHost,
6
- maestroProvider,
7
- resolveAgentExecutionHost,
8
- transformHostedQueryOptions,
9
- withAgentExecutionHost
10
- } from "./chunk-00q25k7p.js";
11
- import"./chunk-gaknyw04.js";
12
- import"./chunk-mh5mexsf.js";
13
- import"./chunk-ezs352qs.js";
14
- import {
3
+ __require,
4
+ __toESM,
5
+ canonicalMcpBridgeEnv,
15
6
  revokeCanonicalMcpBridgeTurn
16
- } from "./chunk-j0kjscb7.js";
17
- import"./chunk-ffefbd3r.js";
18
- import"./chunk-f5xgprg1.js";
19
- import"./chunk-hwy3n31w.js";
7
+ } from "./chunk-s2gez3wg.js";
8
+
9
+ // ../../packages/core/src/agents/claude-provider.ts
10
+ import { spawn } from "child_process";
11
+ import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
12
+ import { query } from "@anthropic-ai/claude-agent-sdk";
13
+
14
+ // ../../packages/core/src/agents/claude-registry.ts
15
+ import { existsSync as existsSync3, mkdirSync as mkdirSync4, readdirSync, renameSync as renameSync2, unlinkSync as unlinkSync2 } from "fs";
16
+ import { homedir as homedir3 } from "os";
17
+ import { join as join4 } from "path";
18
+
19
+ // ../../packages/core/src/agents/rollout/claude.ts
20
+ import { randomUUID } from "crypto";
21
+ import { existsSync as existsSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
22
+ import { homedir as homedir2 } from "os";
23
+ import { join as join3 } from "path";
24
+
25
+ // ../../packages/core/src/agents/rollout/shared.ts
26
+ import { mkdirSync as mkdirSync2 } from "fs";
27
+ import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
28
+ import { fileURLToPath as fileURLToPath2 } from "url";
29
+
30
+ // ../../packages/core/src/platform/config.ts
31
+ import { randomBytes } from "crypto";
32
+ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
33
+ import { homedir } from "os";
34
+ import { dirname, join, resolve } from "path";
35
+ import { fileURLToPath } from "url";
36
+
37
+ // ../../packages/core/src/platform/logger.ts
38
+ import pino from "pino";
39
+ var logger = pino({
40
+ level: process.env.LOG_LEVEL || "info",
41
+ transport: {
42
+ target: "pino-pretty",
43
+ options: {
44
+ colorize: true,
45
+ translateTime: "SYS:yyyy-mm-dd HH:MM:ss",
46
+ destination: 2
47
+ }
48
+ }
49
+ }, pino.destination(2));
50
+
51
+ // ../../packages/core/src/types.ts
52
+ var SUPPORTED_AGENTS = ["maestro", "claude", "codex"];
53
+ function isAgentKind(value) {
54
+ return typeof value === "string" && SUPPORTED_AGENTS.includes(value);
55
+ }
56
+ var CLAUDE_EFFORT_VALUES = ["low", "medium", "high", "xhigh", "max"];
57
+
58
+ // ../../packages/core/src/platform/config.ts
59
+ function envText(envKey) {
60
+ const value = process.env[envKey]?.trim();
61
+ return value ? value : undefined;
62
+ }
63
+ function resolveAgentEnv(envKey, fallback, legacyEnvKey) {
64
+ const value = envText(envKey) ?? (legacyEnvKey ? envText(legacyEnvKey) : undefined);
65
+ return isAgentKind(value) ? value : fallback;
66
+ }
67
+ var HOME = homedir();
68
+ function resolveProjectRoot() {
69
+ const moduleDir = dirname(fileURLToPath(import.meta.url));
70
+ const packagedRuntime = resolve(moduleDir, "runtime");
71
+ if (existsSync(resolve(packagedRuntime, "src")))
72
+ return packagedRuntime;
73
+ return resolve(moduleDir, "../..");
74
+ }
75
+ var PROJECT_ROOT = resolveProjectRoot();
76
+ function resolveDependencyBin(name) {
77
+ let dir = PROJECT_ROOT;
78
+ while (true) {
79
+ const candidate = resolve(dir, "node_modules", ".bin", name);
80
+ if (existsSync(candidate))
81
+ return candidate;
82
+ const parent = dirname(dir);
83
+ if (parent === dir)
84
+ return candidate;
85
+ dir = parent;
86
+ }
87
+ }
88
+ var STATE_DIR_ENV = envText("NEGOTIUM_STATE_DIR");
89
+ var STATE_DIR = STATE_DIR_ENV ? resolve(STATE_DIR_ENV) : resolve(HOME, ".negotium");
90
+ function resolveLocalStateDir(envKey, stateName) {
91
+ const envValue = envText(envKey);
92
+ if (envValue)
93
+ return resolve(envValue);
94
+ return resolve(STATE_DIR, stateName);
95
+ }
96
+ function parsePortEnv(envValue, fallback) {
97
+ if (!envValue)
98
+ return fallback;
99
+ const port = Number.parseInt(envValue, 10);
100
+ return Number.isInteger(port) && port > 0 ? port : fallback;
101
+ }
102
+ var WORKSPACE_DIR = resolveLocalStateDir("NEGOTIUM_WORKSPACE_DIR", "workspace");
103
+ var TOPIC_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "topics");
104
+ var SHARED_WIKI_DIR = resolve(WORKSPACE_DIR, "wiki");
105
+ var CONTEXTS_DIR = resolve(WORKSPACE_DIR, "contexts");
106
+ var BROWSER_PROFILES_DIR = resolve(WORKSPACE_DIR, "browser-profiles");
107
+ var DM_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "dm");
108
+ var SESSION_WORKSPACE_DIR = resolve(WORKSPACE_DIR, "sessions");
109
+ var CLAUDE_EXECUTABLE = resolve(HOME, ".local/bin/claude");
110
+ function resolveBrowserMcpBin(envValue) {
111
+ const override = envValue?.trim();
112
+ if (override) {
113
+ if (!/(^|\/)(mcp-patchright|mcp-patchright-http\.mjs)$/.test(override)) {
114
+ throw new Error("NEGOTIUM_BROWSER_MCP_BIN must point to the authenticated mcp-patchright wrapper.");
115
+ }
116
+ return override;
117
+ }
118
+ return PATCHRIGHT_MCP_BIN;
119
+ }
120
+ var PATCHRIGHT_MCP_BIN = resolve(PROJECT_ROOT, "scripts/mcp-patchright-http.mjs");
121
+ var PLAYWRIGHT_MCP_BIN = resolveBrowserMcpBin(envText("NEGOTIUM_BROWSER_MCP_BIN"));
122
+ var TSX_BIN = resolveDependencyBin("tsx");
123
+ var TSCONFIG_PATH = resolve(PROJECT_ROOT, "tsconfig.json");
124
+ var SESSION_COMM_SERVER = resolve(PROJECT_ROOT, "src/mcp/session-comm/server.ts");
125
+ var TASK_SERVER = resolve(PROJECT_ROOT, "src/mcp/task-server.ts");
126
+ var CANONICAL_MCP_PROXY_SERVER = resolve(PROJECT_ROOT, "src/mcp/canonical-proxy-server.ts");
127
+ var WIKI_SERVER = resolve(PROJECT_ROOT, "src/mcp/wiki-server.ts");
128
+ var PADDLEOCR_SERVER = resolve(PROJECT_ROOT, "src/mcp/paddleocr-server.ts");
129
+ var TOKEN_STATS_SERVER = resolve(PROJECT_ROOT, "src/mcp/token-stats-server.ts");
130
+ var SYSTEM_HEALTH_SERVER = resolve(PROJECT_ROOT, "src/mcp/system-health-server.ts");
131
+ var AGENT_HEALTH_SERVER = resolve(PROJECT_ROOT, "src/mcp/agent-health-server.ts");
132
+ var BACKGROUND_BASH_SERVER = resolve(PROJECT_ROOT, "src/mcp/background-bash-server.ts");
133
+ var VAULT_SERVER = resolve(PROJECT_ROOT, "src/mcp/vault-server.ts");
134
+ var BG_BASH_BASE_PORT = parsePortEnv(process.env.BG_BASH_BASE_PORT, 9700);
135
+ var BG_BASH_MAX_PORT = parsePortEnv(process.env.BG_BASH_MAX_PORT, 9799);
136
+ function safeWorkspaceSegment(value, fallback) {
137
+ const cleaned = value.trim().replace(/[^A-Za-z0-9._-]/g, "_").replace(/^_+|_+$/g, "").slice(0, 160);
138
+ return cleaned || fallback;
139
+ }
140
+ function resolveTopicWorkspaceDir(topicId) {
141
+ return join(TOPIC_WORKSPACE_DIR, safeWorkspaceSegment(topicId, "topic"));
142
+ }
143
+ function loadOrCreateLocalSecret(envKey, filename, options = {}) {
144
+ const envValue = envText(envKey);
145
+ const secretFile = resolve(STATE_DIR, filename);
146
+ mkdirSync(dirname(secretFile), { recursive: true });
147
+ if (envValue) {
148
+ if (options.persistEnvValue) {
149
+ writeFileSync(secretFile, `${envValue}
150
+ `, { mode: 384 });
151
+ chmodSync(secretFile, 384);
152
+ }
153
+ return envValue;
154
+ }
155
+ if (existsSync(secretFile)) {
156
+ const stored = readFileSync(secretFile, "utf-8").trim();
157
+ if (stored) {
158
+ chmodSync(secretFile, 384);
159
+ return stored;
160
+ }
161
+ }
162
+ const secret = randomBytes(32).toString("base64url");
163
+ try {
164
+ writeFileSync(secretFile, `${secret}
165
+ `, { mode: 384, flag: "wx" });
166
+ return secret;
167
+ } catch (error) {
168
+ if (error.code !== "EEXIST")
169
+ throw error;
170
+ const stored = readFileSync(secretFile, "utf-8").trim();
171
+ if (!stored)
172
+ throw new Error(`Secret file exists but is empty: ${secretFile}`);
173
+ chmodSync(secretFile, 384);
174
+ return stored;
175
+ }
176
+ }
177
+ var RUNTIME_MCP_SECRET = loadOrCreateLocalSecret("RUNTIME_MCP_SECRET", "runtime-mcp-secret");
178
+ var NODE_CONTROL_TOKEN = loadOrCreateLocalSecret("NEGOTIUM_CONTROL_TOKEN", "node-control-token");
179
+ var VAULT_MASTER_KEY = loadOrCreateLocalSecret("NEGOTIUM_VAULT_MASTER_KEY", "vault-master-key", { persistEnvValue: true });
180
+ delete process.env.NEGOTIUM_VAULT_MASTER_KEY;
181
+ var NEGOTIUM_PORT = parseInt(process.env.NEGOTIUM_PORT || "7777", 10);
182
+ var hostname = process.env.HOSTNAME || "127.0.0.1";
183
+ var DATA_DIR = resolveLocalStateDir("NEGOTIUM_DATA_DIR", "data");
184
+ var LOG_DIR = resolveLocalStateDir("NEGOTIUM_LOG_DIR", "logs");
185
+ var SESSIONS_DB = process.env.SESSIONS_DB_PATH ? resolve(process.env.SESSIONS_DB_PATH) : resolve(DATA_DIR, "sessions.db");
186
+ var DEBUG_FILE = resolve(DATA_DIR, "debug-users.json");
187
+ var USERS_LOG_DIR = resolve(DATA_DIR, "users");
188
+ var RUN_DIR = resolveLocalStateDir("NEGOTIUM_RUN_DIR", "run");
189
+ var PROGRESS_DIR = resolve(RUN_DIR, "progress");
190
+ var DM_CMD_DIR = resolve(RUN_DIR, "dm-commands");
191
+ var DM_RESP_DIR = resolve(RUN_DIR, "dm-responses");
192
+ var SESSION_INBOX_DIR = resolve(RUN_DIR, "session-inbox");
193
+ var SESSION_ASKS_DIR = resolve(RUN_DIR, "session-asks");
194
+ var PLAYWRIGHT_BASE_PORT = parsePortEnv(process.env.PLAYWRIGHT_BASE_PORT, 9100);
195
+ var PLAYWRIGHT_MAX_PORT = parsePortEnv(process.env.PLAYWRIGHT_MAX_PORT, 9499);
196
+ var PLAYWRIGHT_PORTS_DIR = resolve(RUN_DIR, "playwright-ports");
197
+ mkdirSync(STATE_DIR, { recursive: true });
198
+ mkdirSync(DATA_DIR, { recursive: true });
199
+ mkdirSync(LOG_DIR, { recursive: true });
200
+ mkdirSync(PROGRESS_DIR, { recursive: true });
201
+ mkdirSync(DM_CMD_DIR, { recursive: true });
202
+ mkdirSync(DM_RESP_DIR, { recursive: true });
203
+ mkdirSync(SESSION_INBOX_DIR, { recursive: true });
204
+ mkdirSync(SESSION_ASKS_DIR, { recursive: true });
205
+ mkdirSync(PLAYWRIGHT_PORTS_DIR, { recursive: true });
206
+ mkdirSync(WORKSPACE_DIR, { recursive: true });
207
+ mkdirSync(TOPIC_WORKSPACE_DIR, { recursive: true });
208
+ mkdirSync(SHARED_WIKI_DIR, { recursive: true });
209
+ mkdirSync(CONTEXTS_DIR, { recursive: true });
210
+ mkdirSync(BROWSER_PROFILES_DIR, { recursive: true });
211
+ mkdirSync(DM_WORKSPACE_DIR, { recursive: true });
212
+ mkdirSync(SESSION_WORKSPACE_DIR, { recursive: true });
213
+ var ACTIVE_QUERY_STALE_MS = 10 * 60 * 1000;
214
+ var AGENTS_PROMPTS_DIR = resolve(PROJECT_ROOT, "src/prompts/agents");
215
+ var RESOURCES_DIR = resolve(PROJECT_ROOT, "src/resources");
216
+ var FILE_TAG_REGEX = /\[FILE:(\/[^\]]+)\]/gi;
217
+ var MODEL_SONNET = "claude-sonnet-5";
218
+ var MODEL_OPUS = "claude-opus-4-8";
219
+ var MODEL_FABLE = "claude-fable-5";
220
+ var FALLBACK_AGENT = resolveAgentEnv("FALLBACK_AGENT", "maestro", "DEFAULT_AGENT");
221
+ var SESSION_AGENT = resolveAgentEnv("SESSION_AGENT", FALLBACK_AGENT);
222
+ var GATEWAY_AGENT = resolveAgentEnv("GATEWAY_AGENT", FALLBACK_AGENT);
223
+ var FALLBACK_MODEL = envText("FALLBACK_MODEL") ?? envText("DEFAULT_MODEL");
224
+ function resolveModelEnv(envKey, agentConst) {
225
+ return envText(envKey) ?? (agentConst === FALLBACK_AGENT ? FALLBACK_MODEL : undefined);
226
+ }
227
+ var SESSION_MODEL = resolveModelEnv("SESSION_MODEL", SESSION_AGENT);
228
+ var GATEWAY_MODEL = resolveModelEnv("GATEWAY_MODEL", GATEWAY_AGENT);
229
+ var FFMPEG_BIN = envText("FFMPEG_BIN");
230
+ var FFPROBE_BIN = envText("FFPROBE_BIN");
231
+ var PYTHON_BIN = envText("PYTHON_BIN") ?? "python3";
232
+ var FASTER_WHISPER_WRAPPER = envText("FASTER_WHISPER_WRAPPER") ?? resolve(PROJECT_ROOT, "scripts/faster-whisper-wrapper.py");
233
+ var WHISPER_MODEL = envText("WHISPER_MODEL_FILE") ?? "turbo";
234
+ var TESSERACT_BIN = envText("TESSERACT_BIN") ?? "tesseract";
235
+ var PDFTOTEXT_BIN = envText("PDFTOTEXT_BIN") ?? "pdftotext";
236
+ var _envMaxTellDepth = Number.parseInt(process.env.MAX_TELL_DEPTH ?? "", 10);
237
+ var MAX_TELL_DEPTH = Number.isInteger(_envMaxTellDepth) && _envMaxTellDepth > 0 ? _envMaxTellDepth : 20;
238
+ function codexAuthFilePath() {
239
+ return process.env.NEGOTIUM_CODEX_AUTH_FILE || join(homedir(), ".codex", "auth.json");
240
+ }
241
+
242
+ // ../../packages/core/src/agents/rollout/shared.ts
243
+ var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
244
+ var trustedWorkspaceRoots = [WORKSPACE_DIR, DM_WORKSPACE_DIR, TOPIC_WORKSPACE_DIR].map((root) => resolve2(root));
245
+ var FIXTURES_DIR = join2(__dirname2, "..", "fixtures");
246
+ function clone(obj) {
247
+ return structuredClone(obj);
248
+ }
249
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
250
+ function assertUuidLike(label, value) {
251
+ if (!UUID_RE.test(value)) {
252
+ throw new Error(`rollout: ${label} is not a UUID-shaped string: ${value}`);
253
+ }
254
+ }
255
+ function assertCwdInWorkspace(cwd) {
256
+ const abs = resolve2(cwd);
257
+ const ok = trustedWorkspaceRoots.some((root) => abs === root || abs.startsWith(`${root}/`));
258
+ if (!ok) {
259
+ throw new Error(`rollout: cwd outside trusted workspace roots: ${cwd} (resolved=${abs})`);
260
+ }
261
+ }
262
+ function ensureCwdExists(cwd) {
263
+ assertCwdInWorkspace(cwd);
264
+ try {
265
+ mkdirSync2(cwd, { recursive: true });
266
+ } catch (err) {
267
+ logger.warn({ err, cwd }, "rollout: ensureCwdExists failed \u2014 caller should pre-create cwd");
268
+ }
269
+ }
270
+ function truncate(text, n) {
271
+ const cps = Array.from(text);
272
+ return cps.length > n ? `${cps.slice(0, n).join("")}\u2026` : text;
273
+ }
274
+ function extractChatPairs(entries, opts = { includeToolAnnotations: true }) {
275
+ const pairs = [];
276
+ let pendingUser = null;
277
+ let pendingAssistantParts = [];
278
+ let toolBuffer = [];
279
+ const flushAssistant = () => {
280
+ if (pendingUser === null)
281
+ return;
282
+ const tools = opts.includeToolAnnotations && toolBuffer.length > 0 ? `
283
+
284
+ ${toolBuffer.join(`
285
+ `)}` : "";
286
+ const assistantText = pendingAssistantParts.join("").trim() + tools;
287
+ if (assistantText.trim()) {
288
+ pairs.push({ userText: pendingUser, assistantText });
289
+ }
290
+ pendingUser = null;
291
+ pendingAssistantParts = [];
292
+ toolBuffer = [];
293
+ };
294
+ for (const entry of entries) {
295
+ const ev = entry.event;
296
+ switch (ev.type) {
297
+ case "user_message": {
298
+ flushAssistant();
299
+ pendingUser = ev.content;
300
+ break;
301
+ }
302
+ case "session":
303
+ if (pendingAssistantParts.length > 0 || toolBuffer.length > 0) {
304
+ flushAssistant();
305
+ }
306
+ break;
307
+ case "text": {
308
+ if (pendingUser === null) {
309
+ pendingUser = "(continued)";
310
+ }
311
+ pendingAssistantParts.push(ev.content);
312
+ break;
313
+ }
314
+ case "result": {
315
+ if (pendingUser === null) {
316
+ pendingUser = "(continued)";
317
+ }
318
+ pendingAssistantParts = [ev.content];
319
+ flushAssistant();
320
+ break;
321
+ }
322
+ case "text_delta":
323
+ break;
324
+ case "tool_use": {
325
+ const u = ev;
326
+ toolBuffer.push(`<!-- Tool: ${u.name} ${truncate(JSON.stringify(u.input), 200)} -->`);
327
+ break;
328
+ }
329
+ case "tool_result": {
330
+ const u = ev;
331
+ toolBuffer.push(`<!-- Tool result: ${truncate(u.content, 200)} -->`);
332
+ break;
333
+ }
334
+ case "error": {
335
+ const u = ev;
336
+ toolBuffer.push(`[Error: ${truncate(u.content, 200)}]`);
337
+ break;
338
+ }
339
+ case "tool_progress":
340
+ case "tool_use_summary":
341
+ case "file":
342
+ case "status":
343
+ break;
344
+ }
345
+ }
346
+ flushAssistant();
347
+ return pairs;
348
+ }
349
+
350
+ // ../../packages/core/src/platform/jsonl.ts
351
+ import {
352
+ appendFileSync,
353
+ closeSync,
354
+ fsyncSync,
355
+ mkdirSync as mkdirSync3,
356
+ openSync,
357
+ readFileSync as readFileSync2,
358
+ renameSync,
359
+ statSync,
360
+ unlinkSync,
361
+ writeFileSync as writeFileSync2
362
+ } from "fs";
363
+ import { dirname as dirname3 } from "path";
364
+ function parseJsonlText(raw) {
365
+ return raw.trim().split(`
366
+ `).filter(Boolean).map((line) => JSON.parse(line));
367
+ }
368
+ var LOCK_SLEEP = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
369
+ function writeJsonlFile(filePath, entries) {
370
+ const dir = dirname3(filePath);
371
+ mkdirSync3(dir, { recursive: true });
372
+ const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
373
+ const payload = `${entries.map((e) => JSON.stringify(e)).join(`
374
+ `)}
375
+ `;
376
+ let fd = null;
377
+ try {
378
+ fd = openSync(tmpPath, "w");
379
+ writeFileSync2(fd, payload);
380
+ fsyncSync(fd);
381
+ closeSync(fd);
382
+ fd = null;
383
+ renameSync(tmpPath, filePath);
384
+ fsyncDirectoryBestEffort(dir);
385
+ } catch (err) {
386
+ if (fd !== null) {
387
+ try {
388
+ closeSync(fd);
389
+ } catch {}
390
+ }
391
+ try {
392
+ unlinkSync(tmpPath);
393
+ } catch {}
394
+ throw err;
395
+ }
396
+ }
397
+ function fsyncDirectoryBestEffort(dir) {
398
+ let fd = null;
399
+ try {
400
+ fd = openSync(dir, "r");
401
+ fsyncSync(fd);
402
+ } catch {} finally {
403
+ if (fd !== null) {
404
+ try {
405
+ closeSync(fd);
406
+ } catch {}
407
+ }
408
+ }
409
+ }
410
+
411
+ // ../../packages/core/src/agents/rollout/claude.ts
412
+ var _attachmentsCache = null;
413
+ function loadClaudeAttachments() {
414
+ if (_attachmentsCache)
415
+ return _attachmentsCache;
416
+ const raw = readFileSync3(join3(FIXTURES_DIR, "claude-attachments.jsonl"), "utf8");
417
+ const lines = parseJsonlText(raw);
418
+ if (lines.length < 2) {
419
+ throw new Error(`loadClaudeAttachments: expected >=2 entries in claude-attachments.jsonl, got ${lines.length}`);
420
+ }
421
+ _attachmentsCache = {
422
+ deferredToolsDelta: lines[0],
423
+ skillListing: lines[1]
424
+ };
425
+ return _attachmentsCache;
426
+ }
427
+ var CLAUDE_SDK_VERSION = "2.1.126";
428
+ var CLAUDE_DEFAULT_MODEL = "claude-sonnet-5";
429
+ var CLAUDE_DEFAULT_GIT_BRANCH = "HEAD";
430
+ function encodeClaudeCwd(cwd) {
431
+ const realCwd = cwd.startsWith("/tmp/") ? cwd.replace(/^\/tmp\//, "/private/tmp/") : cwd;
432
+ return `-${realCwd.replaceAll(/[^a-zA-Z0-9]/g, "-").replace(/^-/, "")}`;
433
+ }
434
+ function writeClaudeRollout(opts) {
435
+ const sessionId = opts.sessionId ?? randomUUID();
436
+ assertUuidLike("sessionId", sessionId);
437
+ ensureCwdExists(opts.cwd);
438
+ const pairs = opts.pairs ?? extractChatPairs(opts.entries ?? []);
439
+ const cwdReal = opts.cwd.startsWith("/tmp/") ? opts.cwd.replace(/^\/tmp\//, "/private/tmp/") : opts.cwd;
440
+ const lines = [];
441
+ const ts = () => new Date().toISOString();
442
+ let lastUuid = null;
443
+ lines.push({ type: "queue-operation", operation: "enqueue", timestamp: ts(), sessionId });
444
+ lines.push({ type: "queue-operation", operation: "dequeue", timestamp: ts(), sessionId });
445
+ const attachments = loadClaudeAttachments();
446
+ for (const pair of pairs) {
447
+ const userUuid = randomUUID();
448
+ lines.push({
449
+ parentUuid: lastUuid,
450
+ isSidechain: false,
451
+ promptId: randomUUID(),
452
+ type: "user",
453
+ message: { role: "user", content: [{ type: "text", text: pair.userText }] },
454
+ uuid: userUuid,
455
+ timestamp: ts(),
456
+ permissionMode: "bypassPermissions",
457
+ userType: "external",
458
+ entrypoint: "sdk-ts",
459
+ cwd: cwdReal,
460
+ sessionId,
461
+ version: CLAUDE_SDK_VERSION,
462
+ gitBranch: CLAUDE_DEFAULT_GIT_BRANCH
463
+ });
464
+ const att1Uuid = randomUUID();
465
+ const att1 = clone(attachments.deferredToolsDelta);
466
+ att1.parentUuid = userUuid;
467
+ att1.uuid = att1Uuid;
468
+ att1.timestamp = ts();
469
+ att1.sessionId = sessionId;
470
+ att1.cwd = cwdReal;
471
+ lines.push(att1);
472
+ const att2Uuid = randomUUID();
473
+ const att2 = clone(attachments.skillListing);
474
+ att2.parentUuid = att1Uuid;
475
+ att2.uuid = att2Uuid;
476
+ att2.timestamp = ts();
477
+ att2.sessionId = sessionId;
478
+ att2.cwd = cwdReal;
479
+ lines.push(att2);
480
+ const assistantUuid = randomUUID();
481
+ lines.push({
482
+ parentUuid: att2Uuid,
483
+ isSidechain: false,
484
+ message: {
485
+ model: opts.model ?? CLAUDE_DEFAULT_MODEL,
486
+ id: `msg_${randomUUID().replace(/-/g, "").slice(0, 24)}`,
487
+ type: "message",
488
+ role: "assistant",
489
+ content: [{ type: "text", text: pair.assistantText }],
490
+ stop_reason: "end_turn",
491
+ stop_sequence: null,
492
+ stop_details: null,
493
+ usage: {
494
+ input_tokens: 0,
495
+ cache_creation_input_tokens: 0,
496
+ cache_read_input_tokens: 0,
497
+ output_tokens: 0,
498
+ server_tool_use: { web_search_requests: 0, web_fetch_requests: 0 },
499
+ service_tier: "standard",
500
+ cache_creation: { ephemeral_1h_input_tokens: 0, ephemeral_5m_input_tokens: 0 },
501
+ inference_geo: "",
502
+ iterations: [],
503
+ speed: "standard"
504
+ },
505
+ diagnostics: null
506
+ },
507
+ requestId: `req_${randomUUID().replace(/-/g, "").slice(0, 22)}`,
508
+ type: "assistant",
509
+ uuid: assistantUuid,
510
+ timestamp: ts(),
511
+ userType: "external",
512
+ entrypoint: "sdk-ts",
513
+ cwd: cwdReal,
514
+ sessionId,
515
+ version: CLAUDE_SDK_VERSION,
516
+ gitBranch: CLAUDE_DEFAULT_GIT_BRANCH
517
+ });
518
+ lastUuid = assistantUuid;
519
+ }
520
+ const projectsDir = join3(homedir2(), ".claude", "projects", encodeClaudeCwd(opts.cwd));
521
+ const path = join3(projectsDir, `${sessionId}.jsonl`);
522
+ writeJsonlFile(path, lines);
523
+ logger.info({ sessionId, path, pairs: pairs.length }, "writeClaudeRollout: synthetic rollout placed");
524
+ return { sessionId, rolloutPath: path };
525
+ }
526
+
527
+ // ../../packages/core/src/agents/claude-registry.ts
528
+ var ALIAS_MAP = {
529
+ sonnet: MODEL_SONNET,
530
+ opus: MODEL_OPUS,
531
+ fable: MODEL_FABLE
532
+ };
533
+ var VALID_ALIASES = new Set(Object.keys(ALIAS_MAP));
534
+ var VALID_EFFORTS = new Set(CLAUDE_EFFORT_VALUES);
535
+ var claudeRegistry = {
536
+ kind: "claude",
537
+ defaultModel: "sonnet",
538
+ defaultEffort: "high",
539
+ expandModelAlias(s) {
540
+ return ALIAS_MAP[s] ?? s;
541
+ },
542
+ validateModel(s) {
543
+ return VALID_ALIASES.has(s);
544
+ },
545
+ validEfforts: CLAUDE_EFFORT_VALUES,
546
+ validateEffort(s) {
547
+ return VALID_EFFORTS.has(s);
548
+ },
549
+ footerLabel(model, effort) {
550
+ return effort ? `${model} \xB7 ${effort}` : model;
551
+ },
552
+ writeRollout(opts) {
553
+ const { sessionId, rolloutPath } = writeClaudeRollout({
554
+ cwd: opts.cwd,
555
+ entries: opts.entries,
556
+ model: claudeRegistry.expandModelAlias(opts.model ?? claudeRegistry.defaultModel),
557
+ ...opts.reuseSessionId ? { sessionId: opts.reuseSessionId } : {}
558
+ });
559
+ return { sessionId, rolloutPath };
560
+ },
561
+ async forkSession({ parentSessionId, cwd, title }) {
562
+ const { forkSession } = await import("@anthropic-ai/claude-agent-sdk");
563
+ const result = await forkSession(parentSessionId, {
564
+ ...title ? { title } : {}
565
+ });
566
+ const projectsRoot = join4(homedir3(), ".claude", "projects");
567
+ const destDir = join4(projectsRoot, encodeClaudeCwd(cwd));
568
+ const destPath = join4(destDir, `${result.sessionId}.jsonl`);
569
+ if (!existsSync3(destPath)) {
570
+ const sourcePath = readdirSync(projectsRoot).map((d) => join4(projectsRoot, d, `${result.sessionId}.jsonl`)).find((p) => existsSync3(p));
571
+ if (!sourcePath) {
572
+ throw new Error(`claude forkSession: fork rollout ${result.sessionId}.jsonl not found under ${projectsRoot}`);
573
+ }
574
+ mkdirSync4(destDir, { recursive: true });
575
+ renameSync2(sourcePath, destPath);
576
+ }
577
+ return {
578
+ forkId: result.sessionId,
579
+ rolloutPath: destPath
580
+ };
581
+ },
582
+ async cleanupRollouts({ cwd, sessionIds }) {
583
+ const projectsDir = join4(homedir3(), ".claude", "projects", encodeClaudeCwd(cwd));
584
+ const failures = [];
585
+ for (const sid of sessionIds) {
586
+ const path = join4(projectsDir, `${sid}.jsonl`);
587
+ try {
588
+ unlinkSync2(path);
589
+ } catch (e) {
590
+ if (e?.code !== "ENOENT") {
591
+ logger.warn({ err: e, path }, "claude cleanupRollouts: unlink failed");
592
+ failures.push(e);
593
+ }
594
+ }
595
+ }
596
+ if (failures.length > 0) {
597
+ throw new AggregateError(failures, "claude cleanupRollouts failed");
598
+ }
599
+ }
600
+ };
601
+
602
+ // ../../packages/core/src/agents/deep-map.ts
603
+ function deepMapStrings(value, fn) {
604
+ if (typeof value === "string")
605
+ return fn(value);
606
+ if (Array.isArray(value))
607
+ return value.map((v) => deepMapStrings(v, fn));
608
+ if (value && typeof value === "object") {
609
+ const out = {};
610
+ for (const [k, v] of Object.entries(value)) {
611
+ out[k] = deepMapStrings(v, fn);
612
+ }
613
+ return out;
614
+ }
615
+ return value;
616
+ }
617
+
618
+ // ../../packages/core/src/agents/execution-host.ts
619
+ import { AsyncLocalStorage } from "async_hooks";
620
+
621
+ // ../../packages/core/src/security/sensitive-path.ts
622
+ import { realpathSync } from "fs";
623
+ import { resolve as resolve3 } from "path";
624
+ var SENSITIVE_PATH_PATTERNS = [
625
+ /\/\.env(\.|$)/i,
626
+ /\/\.ssh\//i,
627
+ /\/\.aws\//i,
628
+ /\/\.gnupg\//i,
629
+ /\/\.netrc$/i,
630
+ /\/\.npmrc$/i,
631
+ /\/(id_rsa|id_ed25519|id_ecdsa|id_dsa)(\.pub)?$/i,
632
+ /\.(pem|key|p12|pfx|cer|crt)$/i,
633
+ /\/Library\/Keychains\//i,
634
+ /\/vault\.db(-wal|-shm|-journal)?$/i,
635
+ /\/vault-master-key$/i,
636
+ /\/runtime-mcp-secret$/i,
637
+ /\/sessions\.db(-wal|-shm|-journal)?$/i
638
+ ];
639
+ function isSensitivePath(filePath) {
640
+ const normalized = resolve3(filePath);
641
+ if (SENSITIVE_PATH_PATTERNS.some((p) => p.test(normalized)))
642
+ return true;
643
+ try {
644
+ const real = realpathSync(normalized);
645
+ if (real !== normalized)
646
+ return SENSITIVE_PATH_PATTERNS.some((p) => p.test(real));
647
+ } catch {}
648
+ return false;
649
+ }
650
+
651
+ // ../../packages/core/src/storage/vault.ts
652
+ import { chmodSync as chmodSync2, mkdirSync as mkdirSync5 } from "fs";
653
+ import { join as join5 } from "path";
654
+
655
+ // ../../packages/core/src/storage/sqlite.ts
656
+ var isBun = typeof process.versions.bun === "string";
657
+ var Database;
658
+ if (isBun) {
659
+ ({ Database } = await import("bun:sqlite"));
660
+ } else {
661
+ const nodeSqliteSpecifier = ["node", "sqlite"].join(":");
662
+ const { DatabaseSync } = await import(nodeSqliteSpecifier);
663
+
664
+ class NodeDatabase {
665
+ #db;
666
+ constructor(path, options = {}) {
667
+ this.#db = options.readonly ? new DatabaseSync(path, { readOnly: true }) : new DatabaseSync(path);
668
+ }
669
+ query(sql) {
670
+ return this.#db.prepare(sql);
671
+ }
672
+ prepare(sql) {
673
+ return this.#db.prepare(sql);
674
+ }
675
+ exec(sql) {
676
+ this.#db.exec(sql);
677
+ }
678
+ run(sql, ...params) {
679
+ return this.#db.prepare(sql).run(...params);
680
+ }
681
+ transaction(fn) {
682
+ const run = (begin) => (...args) => {
683
+ this.#db.exec(begin);
684
+ try {
685
+ const result = fn(...args);
686
+ this.#db.exec("COMMIT");
687
+ return result;
688
+ } catch (err) {
689
+ this.#db.exec("ROLLBACK");
690
+ throw err;
691
+ }
692
+ };
693
+ const tx = run("BEGIN");
694
+ tx.deferred = run("BEGIN DEFERRED");
695
+ tx.immediate = run("BEGIN IMMEDIATE");
696
+ tx.exclusive = run("BEGIN EXCLUSIVE");
697
+ return tx;
698
+ }
699
+ close() {
700
+ this.#db.close();
701
+ }
702
+ }
703
+ Database = NodeDatabase;
704
+ }
705
+
706
+ // ../../packages/core/src/storage/vault-crypto.ts
707
+ import { createCipheriv, createDecipheriv, createHash, randomBytes as randomBytes2 } from "crypto";
708
+ var ENVELOPE_PREFIX = "otium-vault:v1:";
709
+ var IV_BYTES = 12;
710
+ var KEY_BYTES = 32;
711
+ function encryptionKey(masterKey = VAULT_MASTER_KEY) {
712
+ return createHash("sha256").update("otium-vault-value-v1\x00", "utf8").update(masterKey, "utf8").digest().subarray(0, KEY_BYTES);
713
+ }
714
+ function aad(userId, key) {
715
+ return Buffer.from(`${userId}\x00${key.toUpperCase()}`, "utf8");
716
+ }
717
+ function isEncryptedVaultValue(value) {
718
+ return value.startsWith(ENVELOPE_PREFIX);
719
+ }
720
+ function encryptVaultValue(userId, key, value, masterKey = VAULT_MASTER_KEY) {
721
+ const iv = randomBytes2(IV_BYTES);
722
+ const cipher = createCipheriv("aes-256-gcm", encryptionKey(masterKey), iv);
723
+ cipher.setAAD(aad(userId, key));
724
+ const ciphertext = Buffer.concat([cipher.update(value, "utf8"), cipher.final()]);
725
+ const tag = cipher.getAuthTag();
726
+ return `${ENVELOPE_PREFIX}${iv.toString("base64url")}.${ciphertext.toString("base64url")}.${tag.toString("base64url")}`;
727
+ }
728
+ function decryptVaultValue(userId, key, storedValue, masterKey = VAULT_MASTER_KEY) {
729
+ if (!isEncryptedVaultValue(storedValue)) {
730
+ return { value: storedValue, legacyPlaintext: true };
731
+ }
732
+ const encoded = storedValue.slice(ENVELOPE_PREFIX.length);
733
+ const [ivPart, ciphertextPart, tagPart, ...extra] = encoded.split(".");
734
+ if (!ivPart || ciphertextPart === undefined || !tagPart || extra.length > 0) {
735
+ throw new Error("Invalid encrypted vault value");
736
+ }
737
+ const iv = Buffer.from(ivPart, "base64url");
738
+ const ciphertext = Buffer.from(ciphertextPart, "base64url");
739
+ const tag = Buffer.from(tagPart, "base64url");
740
+ if (iv.length !== IV_BYTES || tag.length !== 16) {
741
+ throw new Error("Invalid encrypted vault value");
742
+ }
743
+ const decipher = createDecipheriv("aes-256-gcm", encryptionKey(masterKey), iv);
744
+ decipher.setAAD(aad(userId, key));
745
+ decipher.setAuthTag(tag);
746
+ const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
747
+ return { value: plaintext.toString("utf8"), legacyPlaintext: false };
748
+ }
749
+
750
+ // ../../packages/core/src/storage/vault.ts
751
+ var vaultDb;
752
+ var vaultMasterKey = VAULT_MASTER_KEY;
753
+ function initializeVaultDatabase(database) {
754
+ database.exec("PRAGMA journal_mode = WAL");
755
+ database.exec("PRAGMA busy_timeout = 5000");
756
+ database.exec(`
757
+ CREATE TABLE IF NOT EXISTS vault (
758
+ user_id TEXT NOT NULL,
759
+ key TEXT NOT NULL,
760
+ value TEXT NOT NULL,
761
+ description TEXT NOT NULL DEFAULT '',
762
+ PRIMARY KEY (user_id, key)
763
+ )
764
+ `);
765
+ {
766
+ const cols = database.prepare("PRAGMA table_info(vault)").all();
767
+ const uid = cols.find((c) => c.name === "user_id");
768
+ if (uid && uid.type.toUpperCase() === "INTEGER") {
769
+ database.exec("BEGIN");
770
+ database.exec(`
771
+ CREATE TABLE vault_migrated (
772
+ user_id TEXT NOT NULL,
773
+ key TEXT NOT NULL,
774
+ value TEXT NOT NULL,
775
+ description TEXT NOT NULL DEFAULT '',
776
+ PRIMARY KEY (user_id, key)
777
+ )
778
+ `);
779
+ database.exec("INSERT INTO vault_migrated SELECT CAST(user_id AS TEXT), key, value, description FROM vault");
780
+ database.exec("DROP TABLE vault");
781
+ database.exec("ALTER TABLE vault_migrated RENAME TO vault");
782
+ database.exec("COMMIT");
783
+ }
784
+ }
785
+ }
786
+ function openVaultDatabase(dataDir) {
787
+ const path = join5(dataDir, "vault.db");
788
+ mkdirSync5(dataDir, { recursive: true });
789
+ const database = new Database(path, { create: true });
790
+ chmodSync2(path, 384);
791
+ initializeVaultDatabase(database);
792
+ return database;
793
+ }
794
+ function activeVaultDatabase() {
795
+ if (!vaultDb)
796
+ vaultDb = openVaultDatabase(DATA_DIR);
797
+ return vaultDb;
798
+ }
799
+ var VAULT_VALUE_MAX_BYTES = 64 * 1024;
800
+ function normalizeVaultKey(key) {
801
+ return key.trim().toUpperCase();
802
+ }
803
+ function decryptRow(userId, key, storedValue) {
804
+ const database = activeVaultDatabase();
805
+ const decoded = decryptVaultValue(userId, key, storedValue, vaultMasterKey);
806
+ if (decoded.legacyPlaintext) {
807
+ database.prepare("UPDATE vault SET value = ? WHERE user_id = ? AND key = ? AND value = ?").run(encryptVaultValue(userId, key, decoded.value, vaultMasterKey), userId, key, storedValue);
808
+ }
809
+ return decoded.value;
810
+ }
811
+ function vaultListWithValues(userId) {
812
+ const rows = activeVaultDatabase().prepare("SELECT key, description, value FROM vault WHERE user_id = ? ORDER BY key").all(userId);
813
+ return rows.map((row) => ({
814
+ key: row.key,
815
+ description: row.description,
816
+ value: decryptRow(userId, row.key, row.value)
817
+ }));
818
+ }
819
+ function vaultList(userId) {
820
+ return activeVaultDatabase().prepare("SELECT key, description FROM vault WHERE user_id = ? ORDER BY key").all(userId);
821
+ }
822
+ function valueReferencesVaultKey(userId, value) {
823
+ const keys = new Set(vaultList(userId).map((entry) => entry.key));
824
+ const visit = (candidate) => {
825
+ if (typeof candidate === "string") {
826
+ for (const match of candidate.matchAll(/\{\{([^}]+)\}\}/g)) {
827
+ if (keys.has(normalizeVaultKey(match[1] ?? "")))
828
+ return true;
829
+ }
830
+ return false;
831
+ }
832
+ if (Array.isArray(candidate))
833
+ return candidate.some(visit);
834
+ if (candidate && typeof candidate === "object") {
835
+ return Object.values(candidate).some(visit);
836
+ }
837
+ return false;
838
+ };
839
+ return visit(value);
840
+ }
841
+ function encodedSecretForms(value) {
842
+ const forms = new Set([
843
+ value,
844
+ encodeURIComponent(value),
845
+ Buffer.from(value, "utf8").toString("base64"),
846
+ Buffer.from(value, "utf8").toString("base64url"),
847
+ Buffer.from(value, "utf8").toString("hex")
848
+ ]);
849
+ forms.delete("");
850
+ return [...forms].sort((a, b) => b.length - a.length);
851
+ }
852
+ function redactVaultSecrets(userId, text) {
853
+ const candidates = vaultListWithValues(userId).flatMap((entry) => encodedSecretForms(entry.value).map((form) => ({ form, key: entry.key }))).sort((a, b) => b.form.length - a.form.length || a.key.localeCompare(b.key));
854
+ if (candidates.length === 0)
855
+ return text;
856
+ const candidatesByFirstCharacter = new Map;
857
+ for (const candidate of candidates) {
858
+ const first = candidate.form[0];
859
+ if (!first)
860
+ continue;
861
+ const bucket = candidatesByFirstCharacter.get(first) ?? [];
862
+ bucket.push(candidate);
863
+ candidatesByFirstCharacter.set(first, bucket);
864
+ }
865
+ let redacted = "";
866
+ let offset = 0;
867
+ while (offset < text.length) {
868
+ const match = candidatesByFirstCharacter.get(text[offset] ?? "")?.find((candidate) => text.startsWith(candidate.form, offset));
869
+ if (!match) {
870
+ redacted += text[offset];
871
+ offset += 1;
872
+ continue;
873
+ }
874
+ redacted += `[REDACTED:${match.key}]`;
875
+ offset += match.form.length;
876
+ }
877
+ return redacted;
878
+ }
879
+
880
+ // ../../packages/core/src/agents/vault-tool-policy.ts
881
+ var SENSITIVE_RUNTIME_NAMES = [
882
+ "vault.db",
883
+ "vault-master-key",
884
+ "runtime-mcp-secret",
885
+ "sessions.db"
886
+ ];
887
+ var VAULT_BROKER_REDIRECT_ERROR = "Vault placeholders must be executed through mcp__vault__vault_run (shell/CLI) or mcp__vault__vault_http_request (HTTP) so secret values cannot enter the model transcript.";
888
+ function isVaultBrokerTool(toolName) {
889
+ return toolName.includes("vault_run") || toolName.includes("vault_http_request");
890
+ }
891
+ function referencesRuntimeSecretStorage(value) {
892
+ if (typeof value === "string") {
893
+ const lower = value.toLowerCase();
894
+ if (SENSITIVE_RUNTIME_NAMES.some((name) => lower.includes(name)))
895
+ return true;
896
+ return value.startsWith("/") && isSensitivePath(value);
897
+ }
898
+ if (Array.isArray(value))
899
+ return value.some(referencesRuntimeSecretStorage);
900
+ if (value && typeof value === "object") {
901
+ return Object.values(value).some(referencesRuntimeSecretStorage);
902
+ }
903
+ return false;
904
+ }
905
+ function shouldRedirectVaultTool(userId, toolName, input) {
906
+ return !isVaultBrokerTool(toolName) && valueReferencesVaultKey(userId, input);
907
+ }
908
+
909
+ // ../../packages/core/src/platform/mcp-config.ts
910
+ import { createHmac as createHmac2 } from "crypto";
911
+
912
+ // ../../packages/core/src/mcp/runtime-spec.ts
913
+ import { createHmac, timingSafeEqual } from "crypto";
914
+ var RUNTIME_MCP_KEY = "runtime";
915
+ var RUNTIME_MCP_BASE_PATH = "/mcp/runtime";
916
+ var TOKEN_TTL_MS = 4 * 60 * 60 * 1000;
917
+ var CLAUDE_MCP_TOOL_TIMEOUT_MS = 600000;
918
+ var runtimePort = NEGOTIUM_PORT;
919
+ function encodeTokenPart(value) {
920
+ return Buffer.from(JSON.stringify(value), "utf-8").toString("base64url");
921
+ }
922
+ function signTokenPayload(payloadPart) {
923
+ return createHmac("sha256", RUNTIME_MCP_SECRET).update(payloadPart).digest("base64url");
924
+ }
925
+ function issueRuntimeMcpToken(ctx) {
926
+ const payloadPart = encodeTokenPart({
927
+ v: 1,
928
+ exp: Date.now() + TOKEN_TTL_MS,
929
+ ctx
930
+ });
931
+ return `${payloadPart}.${signTokenPayload(payloadPart)}`;
932
+ }
933
+ function buildRuntimeMcpSpec(agent, ctx) {
934
+ const token = issueRuntimeMcpToken(ctx);
935
+ const base = `http://127.0.0.1:${runtimePort}${RUNTIME_MCP_BASE_PATH}`;
936
+ const query = `token=${encodeURIComponent(token)}`;
937
+ if (agent === "codex")
938
+ return { url: `${base}/mcp?${query}` };
939
+ return {
940
+ type: "sse",
941
+ url: `${base}/sse?${query}`,
942
+ timeout: CLAUDE_MCP_TOOL_TIMEOUT_MS
943
+ };
944
+ }
945
+
946
+ // ../../packages/core/src/mcp/session-comm/bridge-ipc-config.ts
947
+ var registrations = [];
948
+ function peerSessionBridgeIpcEnv() {
949
+ const active = registrations.at(-1)?.config;
950
+ if (!active)
951
+ return;
952
+ return {
953
+ NEGOTIUM_PEER_SESSION_BRIDGE_URL: active.url,
954
+ NEGOTIUM_PEER_SESSION_BRIDGE_TOKEN: active.token
955
+ };
956
+ }
957
+
958
+ // ../../packages/core/src/platform/mcp-config.ts
959
+ function buildStdioMcpServer(agent, serverFile, serverArgs, env) {
960
+ if (agent === "codex") {
961
+ return {
962
+ command: "node",
963
+ args: [TSX_BIN, serverFile, ...serverArgs],
964
+ env: { TSX_TSCONFIG_PATH: TSCONFIG_PATH, ...env }
965
+ };
966
+ }
967
+ return {
968
+ command: "bun",
969
+ args: ["run", serverFile, ...serverArgs],
970
+ ...env ? { env } : {}
971
+ };
972
+ }
973
+ var _playwrightUnavailableNotifier;
974
+ var _playwrightUnavailableLastNotifiedAt = new Map;
975
+ var _PLAYWRIGHT_UNAVAILABLE_COOLDOWN_MS = 5 * 60000;
976
+ var _playwrightUnavailableThisTurn = new Set;
977
+ function _playwrightUnavailableKey(userId, topic) {
978
+ return `${userId}:${topic ?? ""}`;
979
+ }
980
+ function _markPlaywrightUnavailable(ctx) {
981
+ _playwrightUnavailableThisTurn.add(_playwrightUnavailableKey(ctx.userId, ctx.topic));
982
+ if (!_playwrightUnavailableNotifier)
983
+ return;
984
+ const key = _playwrightUnavailableKey(ctx.userId, ctx.topic);
985
+ const now = Date.now();
986
+ const last = _playwrightUnavailableLastNotifiedAt.get(key) ?? 0;
987
+ if (now - last < _PLAYWRIGHT_UNAVAILABLE_COOLDOWN_MS)
988
+ return;
989
+ _playwrightUnavailableLastNotifiedAt.set(key, now);
990
+ try {
991
+ _playwrightUnavailableNotifier(ctx);
992
+ } catch (err) {
993
+ logger.warn({ err }, "playwright unavailable notifier threw");
994
+ }
995
+ }
996
+ var CODEX_BROWSER_CAPABILITY_ENV = "NEGOTIUM_BROWSER_CAPABILITY";
997
+ function browserOwnerCapability(capability, owner) {
998
+ return createHmac2("sha256", capability).update(owner).digest("hex");
999
+ }
1000
+ function browserOwnerForContext(ctx) {
1001
+ if (ctx.topicId)
1002
+ return `topic:${ctx.topicId}`;
1003
+ if (ctx.userId && ctx.session)
1004
+ return `user:${ctx.userId}:${ctx.session}`;
1005
+ return;
1006
+ }
1007
+ function playwrightTransport(port, owner, capability, agent) {
1008
+ const ownerCapability = browserOwnerCapability(capability, owner);
1009
+ if (agent === "codex") {
1010
+ return {
1011
+ url: `http://127.0.0.1:${port}/mcp`,
1012
+ http_headers: { "X-Browser-Owner": owner },
1013
+ env_http_headers: { "X-Browser-Capability": CODEX_BROWSER_CAPABILITY_ENV }
1014
+ };
1015
+ }
1016
+ if (agent === "maestro") {
1017
+ const query = new URLSearchParams({ owner, capability: ownerCapability });
1018
+ return {
1019
+ type: "sse",
1020
+ url: `http://127.0.0.1:${port}/sse?${query}`
1021
+ };
1022
+ }
1023
+ return {
1024
+ type: "sse",
1025
+ url: `http://127.0.0.1:${port}/sse`,
1026
+ headers: { "X-Browser-Owner": owner, "X-Browser-Capability": ownerCapability }
1027
+ };
1028
+ }
1029
+ function longLivedHttpMcp(agent, port) {
1030
+ return agent === "codex" ? { url: `http://127.0.0.1:${port}/mcp` } : { type: "sse", url: `http://127.0.0.1:${port}/sse` };
1031
+ }
1032
+ var MCP_CATALOG = {
1033
+ playwright: {
1034
+ scopes: ["dm", "forum", "fork", "cron"],
1035
+ build({ userId, session, topicId, playwrightPort, playwrightCapability, agent }) {
1036
+ if (playwrightPort && playwrightCapability) {
1037
+ const owner = browserOwnerForContext({ userId, session, topicId });
1038
+ if (!owner)
1039
+ return null;
1040
+ return playwrightTransport(playwrightPort, owner, playwrightCapability, agent);
1041
+ }
1042
+ _markPlaywrightUnavailable({
1043
+ userId,
1044
+ topic: session,
1045
+ agent
1046
+ });
1047
+ return null;
1048
+ }
1049
+ },
1050
+ [RUNTIME_MCP_KEY]: {
1051
+ scopes: ["forum", "manager", "fork", "cron"],
1052
+ forumRequired: true,
1053
+ build({
1054
+ userId,
1055
+ session,
1056
+ topicId,
1057
+ queryId,
1058
+ agent,
1059
+ cwd,
1060
+ model,
1061
+ currentUserPrompt,
1062
+ autoContinue,
1063
+ visualTools,
1064
+ fileDeliveryTools,
1065
+ peerBridge
1066
+ }) {
1067
+ if (!topicId || !agent)
1068
+ return null;
1069
+ return buildRuntimeMcpSpec(agent, {
1070
+ userId,
1071
+ topicId,
1072
+ topicTitle: session,
1073
+ queryId,
1074
+ cwd: cwd ?? resolveTopicWorkspaceDir(topicId),
1075
+ agent,
1076
+ model,
1077
+ currentUserPrompt,
1078
+ autoContinue,
1079
+ visualTools,
1080
+ fileDeliveryTools,
1081
+ peerBridge
1082
+ });
1083
+ }
1084
+ },
1085
+ paddleocr: {
1086
+ scopes: ["dm", "forum", "fork", "cron"],
1087
+ build({ agent }) {
1088
+ return buildStdioMcpServer(agent, PADDLEOCR_SERVER, []);
1089
+ }
1090
+ },
1091
+ "token-stats": {
1092
+ scopes: ["dm", "forum", "manager", "cron"],
1093
+ forumRequired: true,
1094
+ build({ userId, agent }) {
1095
+ return buildStdioMcpServer(agent, TOKEN_STATS_SERVER, [`--user-id=${userId}`]);
1096
+ }
1097
+ },
1098
+ task: {
1099
+ scopes: ["dm", "forum", "manager", "cron"],
1100
+ forumRequired: true,
1101
+ build({ userId, session, topicId, queryId, agent, peerBridge }) {
1102
+ if (peerBridge) {
1103
+ if (!topicId || !queryId)
1104
+ return null;
1105
+ const env = canonicalMcpBridgeEnv({
1106
+ surface: "task",
1107
+ userId,
1108
+ topicId,
1109
+ queryId,
1110
+ peerBridge
1111
+ });
1112
+ return env ? buildStdioMcpServer(agent, CANONICAL_MCP_PROXY_SERVER, ["--surface=task"], env) : null;
1113
+ }
1114
+ const args = [`--user-id=${userId}`, `--topic=${session}`];
1115
+ if (topicId)
1116
+ args.push(`--topic-id=${topicId}`);
1117
+ return buildStdioMcpServer(agent, TASK_SERVER, args);
1118
+ }
1119
+ },
1120
+ "session-comm": {
1121
+ scopes: ["forum", "fork", "manager"],
1122
+ forumRequired: true,
1123
+ build({ userId, session, topicId, agent, depth = 0, silent, peerBridge }) {
1124
+ const effectiveAgent = agent ?? FALLBACK_AGENT;
1125
+ const args = [
1126
+ `--user-id=${userId}`,
1127
+ `--topic=${session}`,
1128
+ ...topicId ? [`--topic-id=${topicId}`] : [],
1129
+ `--depth=${depth}`,
1130
+ `--agent=${effectiveAgent}`,
1131
+ ...silent ? ["--reply-only=true"] : [],
1132
+ ...peerBridge ? [`--peer-host-query-id=${peerBridge.hostQueryId}`] : []
1133
+ ];
1134
+ return buildStdioMcpServer(effectiveAgent, SESSION_COMM_SERVER, args, peerBridge ? peerSessionBridgeIpcEnv() : undefined);
1135
+ }
1136
+ },
1137
+ wiki: {
1138
+ scopes: ["dm", "forum", "manager", "cron"],
1139
+ forumRequired: true,
1140
+ build({ userId, session, topicId, queryId, wikiTopicId, agent, peerBridge }) {
1141
+ if (peerBridge) {
1142
+ if (!topicId || !queryId)
1143
+ return null;
1144
+ const env = canonicalMcpBridgeEnv({
1145
+ surface: "wiki",
1146
+ userId,
1147
+ topicId,
1148
+ queryId,
1149
+ peerBridge
1150
+ });
1151
+ return env ? buildStdioMcpServer(agent, CANONICAL_MCP_PROXY_SERVER, ["--surface=wiki"], env) : null;
1152
+ }
1153
+ const args = [`--user-id=${userId}`];
1154
+ const resolvedWikiTopicId = wikiTopicId ?? topicId ?? (session !== "dm" ? session : undefined);
1155
+ if (resolvedWikiTopicId)
1156
+ args.push(`--topic-id=${resolvedWikiTopicId}`);
1157
+ args.push("--surface=wiki");
1158
+ return buildStdioMcpServer(agent, WIKI_SERVER, args);
1159
+ }
1160
+ },
1161
+ skills: {
1162
+ scopes: ["dm", "forum", "manager", "cron"],
1163
+ forumRequired: true,
1164
+ build({ userId, topicId, agent }) {
1165
+ const args = [`--user-id=${userId}`, "--surface=skills"];
1166
+ if (topicId)
1167
+ args.push(`--topic-id=${topicId}`);
1168
+ return buildStdioMcpServer(agent, WIKI_SERVER, args);
1169
+ }
1170
+ },
1171
+ "system-health": {
1172
+ scopes: ["dm", "forum", "manager", "cron"],
1173
+ forumRequired: true,
1174
+ build({ agent }) {
1175
+ return buildStdioMcpServer(agent, SYSTEM_HEALTH_SERVER, []);
1176
+ }
1177
+ },
1178
+ "background-bash": {
1179
+ scopes: ["forum"],
1180
+ build({ agent, bgBashPort }) {
1181
+ if (bgBashPort === undefined)
1182
+ return null;
1183
+ return longLivedHttpMcp(agent, bgBashPort);
1184
+ }
1185
+ },
1186
+ "agent-health": {
1187
+ scopes: ["forum", "manager", "cron"],
1188
+ forumRequired: true,
1189
+ build({ userId, agent }) {
1190
+ const args = [`--user-id=${userId}`];
1191
+ return buildStdioMcpServer(agent, AGENT_HEALTH_SERVER, args);
1192
+ }
1193
+ },
1194
+ vault: {
1195
+ scopes: ["dm", "forum", "manager", "cron"],
1196
+ forumRequired: true,
1197
+ build({ userId, agent }) {
1198
+ const args = [`--user-id=${userId}`];
1199
+ if (agent === "codex")
1200
+ args.push("--http-only=true");
1201
+ return buildStdioMcpServer(agent, VAULT_SERVER, args);
1202
+ }
1203
+ }
1204
+ };
1205
+ function namesInScope(scope) {
1206
+ return Object.entries(MCP_CATALOG).filter(([, e]) => e.scopes.includes(scope)).map(([name]) => name);
1207
+ }
1208
+ var allForumMcpServerNames = [];
1209
+ var requiredForumMcpServers = [];
1210
+ var REQUIRED_FORUM_MCP_SERVERS = requiredForumMcpServers;
1211
+ var optionalForumMcpServers = [];
1212
+ function refreshForumCatalogViews() {
1213
+ const all = namesInScope("forum");
1214
+ const required = Object.entries(MCP_CATALOG).filter(([, entry]) => entry.scopes.includes("forum") && entry.forumRequired).map(([name]) => name);
1215
+ allForumMcpServerNames.splice(0, allForumMcpServerNames.length, ...all);
1216
+ requiredForumMcpServers.splice(0, requiredForumMcpServers.length, ...required);
1217
+ optionalForumMcpServers.splice(0, optionalForumMcpServers.length, ...all.filter((name) => !required.includes(name)));
1218
+ }
1219
+ refreshForumCatalogViews();
1220
+ var nodeMcpEntries = [];
1221
+ function buildNodeMcpSpecs(agent, filter) {
1222
+ const out = {};
1223
+ for (const entry of nodeMcpEntries) {
1224
+ if (!filter(entry.key))
1225
+ continue;
1226
+ out[entry.key] = entry.kind === "http" ? longLivedHttpMcp(agent, entry.port) : {
1227
+ command: entry.command,
1228
+ args: entry.args ?? [],
1229
+ ...entry.env ? { env: entry.env } : {}
1230
+ };
1231
+ }
1232
+ return out;
1233
+ }
1234
+ function buildScope(scope, ctx, filter = () => true) {
1235
+ const out = {};
1236
+ for (const [name, entry] of Object.entries(MCP_CATALOG)) {
1237
+ if (!entry.scopes.includes(scope))
1238
+ continue;
1239
+ if (!filter(name))
1240
+ continue;
1241
+ const spec = entry.build(ctx);
1242
+ if (spec === null)
1243
+ continue;
1244
+ out[name] = spec;
1245
+ }
1246
+ if (scope !== "cron") {
1247
+ Object.assign(out, buildNodeMcpSpecs(ctx.agent, filter));
1248
+ }
1249
+ return out;
1250
+ }
1251
+ function getDmMcpServers(opts) {
1252
+ return buildScope("dm", {
1253
+ userId: opts.userId,
1254
+ session: "dm",
1255
+ agent: opts.agent,
1256
+ playwrightPort: opts.playwrightPort,
1257
+ playwrightCapability: opts.playwrightCapability
1258
+ });
1259
+ }
1260
+ function getManagerMcpServers(opts) {
1261
+ if (!opts.topicId) {
1262
+ throw new Error("getManagerMcpServers: private General topicId is required");
1263
+ }
1264
+ const topicId = opts.topicId;
1265
+ return buildScope("manager", {
1266
+ userId: opts.userId,
1267
+ session: opts.session ?? "General",
1268
+ topicId,
1269
+ queryId: opts.queryId,
1270
+ wikiTopicId: opts.wikiTopicId ?? topicId,
1271
+ agent: opts.agent,
1272
+ cwd: opts.cwd,
1273
+ model: opts.model,
1274
+ currentUserPrompt: opts.currentUserPrompt,
1275
+ playwrightPort: opts.playwrightPort,
1276
+ playwrightCapability: opts.playwrightCapability,
1277
+ autoContinue: opts.autoContinue,
1278
+ visualTools: opts.visualTools,
1279
+ fileDeliveryTools: opts.fileDeliveryTools
1280
+ });
1281
+ }
1282
+ function getForumMcpServers(opts) {
1283
+ const {
1284
+ userId,
1285
+ session,
1286
+ topicId,
1287
+ queryId,
1288
+ wikiTopicId,
1289
+ agent,
1290
+ cwd,
1291
+ model,
1292
+ currentUserPrompt,
1293
+ playwrightPort,
1294
+ playwrightCapability,
1295
+ depth = 0,
1296
+ enabled = null,
1297
+ extra = {},
1298
+ silent = false,
1299
+ bgBashPort,
1300
+ autoContinue,
1301
+ visualTools,
1302
+ fileDeliveryTools,
1303
+ peerBridge
1304
+ } = opts;
1305
+ const filter = (name) => {
1306
+ if (silent && name === "task")
1307
+ return false;
1308
+ if (enabled === null)
1309
+ return true;
1310
+ return enabled.includes(name) || REQUIRED_FORUM_MCP_SERVERS.includes(name);
1311
+ };
1312
+ const base = buildScope("forum", {
1313
+ userId,
1314
+ session,
1315
+ topicId,
1316
+ queryId,
1317
+ wikiTopicId,
1318
+ agent,
1319
+ cwd,
1320
+ model,
1321
+ currentUserPrompt,
1322
+ depth,
1323
+ playwrightPort,
1324
+ playwrightCapability,
1325
+ bgBashPort,
1326
+ autoContinue,
1327
+ visualTools,
1328
+ fileDeliveryTools,
1329
+ silent,
1330
+ peerBridge
1331
+ }, filter);
1332
+ return { ...base, ...extra };
1333
+ }
1334
+ function getCronMcpServers(opts) {
1335
+ return buildScope("cron", {
1336
+ userId: opts.userId,
1337
+ session: opts.session,
1338
+ topicId: opts.topicId,
1339
+ queryId: opts.queryId,
1340
+ wikiTopicId: opts.wikiTopicId ?? opts.topicId,
1341
+ agent: opts.agent,
1342
+ cwd: opts.cwd,
1343
+ model: opts.model,
1344
+ currentUserPrompt: opts.currentUserPrompt,
1345
+ playwrightPort: opts.playwrightPort,
1346
+ playwrightCapability: opts.playwrightCapability,
1347
+ autoContinue: false,
1348
+ visualTools: opts.visualTools,
1349
+ fileDeliveryTools: opts.fileDeliveryTools
1350
+ });
1351
+ }
1352
+ function getMcpServersForQuery(opts) {
1353
+ if (opts.sessionType === "cron") {
1354
+ if (!opts.topicId)
1355
+ throw new Error("getMcpServersForQuery: cron sessionType requires topicId");
1356
+ return getCronMcpServers({
1357
+ userId: opts.userId || "default",
1358
+ session: opts.session || "cron",
1359
+ topicId: opts.topicId,
1360
+ queryId: opts.queryId,
1361
+ wikiTopicId: opts.wikiTopicId,
1362
+ agent: opts.agent,
1363
+ cwd: opts.cwd,
1364
+ model: opts.model,
1365
+ currentUserPrompt: opts.prompt,
1366
+ playwrightPort: opts.playwrightPort,
1367
+ playwrightCapability: opts.playwrightCapability,
1368
+ visualTools: opts.visualTools,
1369
+ fileDeliveryTools: opts.fileDeliveryTools
1370
+ });
1371
+ }
1372
+ if (opts.sessionType === "dm" || opts.sessionType === "ephemeral") {
1373
+ return getDmMcpServers({
1374
+ userId: opts.userId || "default",
1375
+ agent: opts.agent,
1376
+ playwrightPort: opts.playwrightPort,
1377
+ playwrightCapability: opts.playwrightCapability
1378
+ });
1379
+ }
1380
+ if (opts.sessionType === "manager") {
1381
+ return getManagerMcpServers({
1382
+ userId: opts.userId || "default",
1383
+ session: opts.session,
1384
+ topicId: opts.topicId,
1385
+ queryId: opts.queryId,
1386
+ wikiTopicId: opts.wikiTopicId,
1387
+ agent: opts.agent,
1388
+ cwd: opts.cwd,
1389
+ model: opts.model,
1390
+ currentUserPrompt: opts.prompt,
1391
+ playwrightPort: opts.playwrightPort,
1392
+ playwrightCapability: opts.playwrightCapability,
1393
+ autoContinue: opts.autoContinue,
1394
+ visualTools: opts.visualTools,
1395
+ fileDeliveryTools: opts.fileDeliveryTools
1396
+ });
1397
+ }
1398
+ return getForumMcpServers({
1399
+ userId: opts.userId || "default",
1400
+ session: opts.session || "default",
1401
+ topicId: opts.topicId,
1402
+ queryId: opts.queryId,
1403
+ wikiTopicId: opts.wikiTopicId,
1404
+ agent: opts.agent,
1405
+ cwd: opts.cwd,
1406
+ model: opts.model,
1407
+ currentUserPrompt: opts.prompt,
1408
+ playwrightPort: opts.playwrightPort,
1409
+ playwrightCapability: opts.playwrightCapability,
1410
+ bgBashPort: opts.bgBashPort,
1411
+ autoContinue: opts.autoContinue,
1412
+ visualTools: opts.visualTools,
1413
+ fileDeliveryTools: opts.fileDeliveryTools,
1414
+ depth: opts.depth,
1415
+ enabled: opts.mcpEnabled,
1416
+ extra: opts.mcpExtra,
1417
+ silent: opts.silent,
1418
+ peerBridge: opts.peerBridge
1419
+ });
1420
+ }
1421
+
1422
+ // ../../packages/core/src/agents/execution-host.ts
1423
+ var defaultHost = {
1424
+ getMcpServersForQuery,
1425
+ redactVaultSecrets,
1426
+ referencesRuntimeSecretStorage,
1427
+ shouldRedirectVaultTool,
1428
+ claudeCodeExecutablePath: () => CLAUDE_EXECUTABLE,
1429
+ codexAuthFilePath
1430
+ };
1431
+ var hostRegistrations = [];
1432
+ var scopedHost = new AsyncLocalStorage;
1433
+ function activeHost() {
1434
+ const scoped = scopedHost.getStore();
1435
+ if (scoped)
1436
+ return scoped;
1437
+ const host = { ...defaultHost };
1438
+ for (const registration of hostRegistrations)
1439
+ Object.assign(host, registration.overrides);
1440
+ return host;
1441
+ }
1442
+ function resolveAgentExecutionHost(overrides = {}) {
1443
+ return { ...activeHost(), ...overrides };
1444
+ }
1445
+ function withAgentExecutionHost(host, operation) {
1446
+ return scopedHost.run(host, operation);
1447
+ }
1448
+ function configureAgentExecutionHost(overrides) {
1449
+ const registration = { id: Symbol("agent-execution-host"), overrides };
1450
+ hostRegistrations.push(registration);
1451
+ let disposed = false;
1452
+ return () => {
1453
+ if (disposed)
1454
+ return;
1455
+ disposed = true;
1456
+ const index = hostRegistrations.findIndex((entry) => entry.id === registration.id);
1457
+ if (index >= 0)
1458
+ hostRegistrations.splice(index, 1);
1459
+ };
1460
+ }
1461
+ function hostedMcpServers(opts) {
1462
+ return activeHost().getMcpServersForQuery(opts);
1463
+ }
1464
+ function redactHostedSecrets(userId, value) {
1465
+ return activeHost().redactVaultSecrets(userId, value);
1466
+ }
1467
+ function referencesHostedSecretStorage(value) {
1468
+ return activeHost().referencesRuntimeSecretStorage(value);
1469
+ }
1470
+ function shouldRedirectHostedVaultTool(userId, toolName, input) {
1471
+ return activeHost().shouldRedirectVaultTool(userId, toolName, input);
1472
+ }
1473
+ function transformHostedQueryOptions(opts) {
1474
+ return activeHost().transformQueryOptions?.(opts) ?? opts;
1475
+ }
1476
+ function hostedClaudeCodeExecutablePath() {
1477
+ return activeHost().claudeCodeExecutablePath();
1478
+ }
1479
+ function hostedCodexAuthFilePath() {
1480
+ return activeHost().codexAuthFilePath();
1481
+ }
1482
+
1483
+ // ../../packages/core/src/media/file-events.ts
1484
+ function* extractFileEvents(text, source) {
1485
+ const tagRegex = new RegExp(FILE_TAG_REGEX.source, "gi");
1486
+ let match = tagRegex.exec(text);
1487
+ while (match !== null) {
1488
+ yield { type: "file", path: match[1], source, origin: "tag" };
1489
+ match = tagRegex.exec(text);
1490
+ }
1491
+ }
1492
+
1493
+ // ../../packages/core/src/platform/error.ts
1494
+ function errMsg(e, fallback) {
1495
+ if (e instanceof Error)
1496
+ return e.message;
1497
+ return fallback ?? String(e);
1498
+ }
1499
+
1500
+ // ../../packages/core/src/agents/claude-provider.ts
1501
+ var CLAUDE_DEFAULT_DISALLOWED_TOOLS = [
1502
+ "AskUserQuestion",
1503
+ "Workflow",
1504
+ "TodoWrite",
1505
+ "TaskCreate",
1506
+ "TaskUpdate",
1507
+ "TaskList",
1508
+ "TaskGet",
1509
+ "Task",
1510
+ "Agent",
1511
+ "TaskOutput",
1512
+ "TaskStop"
1513
+ ];
1514
+ function buildClaudeDisallowedTools(extra = undefined) {
1515
+ return [...new Set([...CLAUDE_DEFAULT_DISALLOWED_TOOLS, ...extra ?? []])];
1516
+ }
1517
+ function toClaudeEffort(e) {
1518
+ if (!e || !claudeRegistry.validateEffort(e))
1519
+ return;
1520
+ return e;
1521
+ }
1522
+ var CLAUDE_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
1523
+ var CLAUDE_IMAGE_MIME_TYPES = new Set([
1524
+ "image/jpeg",
1525
+ "image/png",
1526
+ "image/gif",
1527
+ "image/webp"
1528
+ ]);
1529
+ function isClaudeImageAttachment(attachment) {
1530
+ return attachment.type === "image" && CLAUDE_IMAGE_MIME_TYPES.has(attachment.mimeType);
1531
+ }
1532
+ async function* singleUserMessage(message) {
1533
+ yield message;
1534
+ }
1535
+ function buildClaudePrompt(opts) {
1536
+ const attachments = opts.attachments ?? [];
1537
+ if (attachments.length === 0)
1538
+ return opts.prompt;
1539
+ const imageBlocks = [];
1540
+ for (const attachment of attachments) {
1541
+ if (!isClaudeImageAttachment(attachment))
1542
+ continue;
1543
+ if (attachment.sizeBytes > CLAUDE_IMAGE_MAX_BYTES) {
1544
+ logger.info({
1545
+ path: attachment.path,
1546
+ mimeType: attachment.mimeType,
1547
+ sizeBytes: attachment.sizeBytes,
1548
+ maxBytes: CLAUDE_IMAGE_MAX_BYTES
1549
+ }, "claudeProvider: skipping oversized image attachment content block");
1550
+ continue;
1551
+ }
1552
+ try {
1553
+ imageBlocks.push({
1554
+ type: "image",
1555
+ source: {
1556
+ type: "base64",
1557
+ media_type: attachment.mimeType,
1558
+ data: readFileSync4(attachment.path).toString("base64")
1559
+ }
1560
+ });
1561
+ } catch (err) {
1562
+ logger.warn({
1563
+ path: attachment.path,
1564
+ mimeType: attachment.mimeType,
1565
+ err
1566
+ }, "claudeProvider: failed to read image attachment for content block");
1567
+ }
1568
+ }
1569
+ if (imageBlocks.length === 0)
1570
+ return opts.prompt;
1571
+ const content = [{ type: "text", text: opts.prompt }, ...imageBlocks];
1572
+ return singleUserMessage({
1573
+ type: "user",
1574
+ message: {
1575
+ role: "user",
1576
+ content
1577
+ },
1578
+ parent_tool_use_id: null
1579
+ });
1580
+ }
1581
+ var CLAUDE_ABORT_SIGKILL_DELAY_MS = 2500;
1582
+ function signalProcessTree(pid, signal) {
1583
+ try {
1584
+ process.kill(-pid, signal);
1585
+ return true;
1586
+ } catch (groupErr) {
1587
+ try {
1588
+ process.kill(pid, signal);
1589
+ return true;
1590
+ } catch (pidErr) {
1591
+ logger.debug({ groupErr, pidErr, pid, signal }, "Failed to signal Claude process tree");
1592
+ return false;
1593
+ }
1594
+ }
1595
+ }
1596
+ function spawnClaudeCodeProcessWithTreeKill(options) {
1597
+ const child = spawn(options.command, options.args, {
1598
+ cwd: options.cwd,
1599
+ detached: true,
1600
+ env: options.env,
1601
+ stdio: ["pipe", "pipe", "inherit"]
1602
+ });
1603
+ if (!child.stdin || !child.stdout) {
1604
+ child.kill("SIGKILL");
1605
+ throw new Error("Failed to spawn Claude Code process with piped stdin/stdout");
1606
+ }
1607
+ let exited = false;
1608
+ let killTimer;
1609
+ const clearKillTimer = () => {
1610
+ if (killTimer)
1611
+ clearTimeout(killTimer);
1612
+ killTimer = undefined;
1613
+ };
1614
+ const kill = (signal) => {
1615
+ if (!child.pid)
1616
+ return child.kill(signal);
1617
+ const ok = signalProcessTree(child.pid, signal);
1618
+ if (signal !== "SIGKILL") {
1619
+ clearKillTimer();
1620
+ killTimer = setTimeout(() => {
1621
+ if (!exited && child.pid) {
1622
+ logger.warn({ pid: child.pid }, "Claude process tree still alive after SIGTERM; SIGKILL");
1623
+ signalProcessTree(child.pid, "SIGKILL");
1624
+ }
1625
+ }, CLAUDE_ABORT_SIGKILL_DELAY_MS);
1626
+ killTimer.unref?.();
1627
+ }
1628
+ return ok;
1629
+ };
1630
+ const onAbort = () => {
1631
+ logger.warn({ pid: child.pid, command: options.command }, "Aborting Claude Code process tree");
1632
+ kill("SIGTERM");
1633
+ };
1634
+ if (options.signal.aborted)
1635
+ onAbort();
1636
+ else
1637
+ options.signal.addEventListener("abort", onAbort, { once: true });
1638
+ child.once("exit", (code, signal) => {
1639
+ exited = true;
1640
+ clearKillTimer();
1641
+ options.signal.removeEventListener("abort", onAbort);
1642
+ logger.debug({ pid: child.pid, code, signal }, "Claude Code process exited");
1643
+ });
1644
+ child.once("error", (err) => {
1645
+ exited = true;
1646
+ clearKillTimer();
1647
+ options.signal.removeEventListener("abort", onAbort);
1648
+ logger.error({
1649
+ pid: child.pid,
1650
+ command: options.command,
1651
+ err: err instanceof Error ? err.message : String(err)
1652
+ }, "Claude Code process error event");
1653
+ });
1654
+ return {
1655
+ stdin: child.stdin,
1656
+ stdout: child.stdout,
1657
+ get killed() {
1658
+ return child.killed || exited;
1659
+ },
1660
+ get exitCode() {
1661
+ return child.exitCode;
1662
+ },
1663
+ kill,
1664
+ on(event, listener) {
1665
+ child.on(event, listener);
1666
+ },
1667
+ once(event, listener) {
1668
+ child.once(event, listener);
1669
+ },
1670
+ off(event, listener) {
1671
+ child.off(event, listener);
1672
+ }
1673
+ };
1674
+ }
1675
+ function isAbortError(err) {
1676
+ if (!err || typeof err !== "object")
1677
+ return false;
1678
+ const e = err;
1679
+ if (e.name === "AbortError")
1680
+ return true;
1681
+ if (e.code === 20 || e.code === "ABORT_ERR")
1682
+ return true;
1683
+ return false;
1684
+ }
1685
+ async function* claudeProvider(opts) {
1686
+ const claudeExecutable = hostedClaudeCodeExecutablePath();
1687
+ if (claudeExecutable && !existsSync4(claudeExecutable)) {
1688
+ yield {
1689
+ type: "error",
1690
+ content: `Claude CLI not found at ${claudeExecutable}. Install Claude Code or configure the executable path.`
1691
+ };
1692
+ return;
1693
+ }
1694
+ const cleanEnv = { ...process.env };
1695
+ delete cleanEnv.NEGOTIUM_PEER_SESSION_BRIDGE_URL;
1696
+ delete cleanEnv.NEGOTIUM_PEER_SESSION_BRIDGE_TOKEN;
1697
+ delete cleanEnv.CLAUDECODE;
1698
+ cleanEnv.CLAUDE_CODE_STREAM_CLOSE_TIMEOUT ??= process.env.PADDLEOCR_TIMEOUT_MS ?? "300000";
1699
+ cleanEnv.CLAUDE_CODE_DISABLE_WORKFLOWS = "1";
1700
+ const queryOptions = {
1701
+ ...claudeExecutable ? { pathToClaudeCodeExecutable: claudeExecutable } : {},
1702
+ spawnClaudeCodeProcess: spawnClaudeCodeProcessWithTreeKill,
1703
+ cwd: opts.cwd,
1704
+ permissionMode: "bypassPermissions",
1705
+ allowDangerouslySkipPermissions: true,
1706
+ includePartialMessages: true,
1707
+ env: cleanEnv,
1708
+ mcpServers: hostedMcpServers(opts),
1709
+ abortController: opts.abortController,
1710
+ disallowedTools: buildClaudeDisallowedTools(opts.disallowedTools),
1711
+ ...opts.model ? { model: opts.model } : {},
1712
+ ...opts.maxBudgetUsd ? { maxBudgetUsd: opts.maxBudgetUsd } : {},
1713
+ ...opts.agents ? {
1714
+ agents: Object.fromEntries(Object.entries(opts.agents).map(([name, def]) => {
1715
+ const { effort, ...rest } = def;
1716
+ const narrowed = typeof effort === "string" ? toClaudeEffort(effort) : effort;
1717
+ return [name, narrowed !== undefined ? { ...rest, effort: narrowed } : rest];
1718
+ }))
1719
+ } : {},
1720
+ ...toClaudeEffort(opts.effort) ? { effort: toClaudeEffort(opts.effort) } : {},
1721
+ hooks: {
1722
+ PreToolUse: [
1723
+ {
1724
+ hooks: [
1725
+ async (input) => {
1726
+ const { tool_name, tool_input } = input;
1727
+ if (referencesHostedSecretStorage(tool_input)) {
1728
+ return {
1729
+ hookSpecificOutput: {
1730
+ hookEventName: "PreToolUse",
1731
+ permissionDecision: "deny",
1732
+ permissionDecisionReason: "Runtime secret storage access is not permitted"
1733
+ }
1734
+ };
1735
+ }
1736
+ if (tool_name === "Bash" && tool_input?.run_in_background === true) {
1737
+ return {
1738
+ hookSpecificOutput: {
1739
+ hookEventName: "PreToolUse",
1740
+ permissionDecision: "deny",
1741
+ permissionDecisionReason: "run_in_background is not supported in headless mode \u2014 the bash process dies when the agent turn ends. Use mcp__background-bash__background_bash_run instead: it survives across turns and automatically injects the result into the session when done."
1742
+ }
1743
+ };
1744
+ }
1745
+ const userId = opts.userId ?? "";
1746
+ if (!shouldRedirectHostedVaultTool(userId, tool_name, tool_input)) {
1747
+ return { continue: true };
1748
+ }
1749
+ return {
1750
+ hookSpecificOutput: {
1751
+ hookEventName: "PreToolUse",
1752
+ permissionDecision: "deny",
1753
+ permissionDecisionReason: VAULT_BROKER_REDIRECT_ERROR
1754
+ }
1755
+ };
1756
+ }
1757
+ ]
1758
+ }
1759
+ ],
1760
+ PostToolUse: [
1761
+ {
1762
+ hooks: [
1763
+ async (input) => {
1764
+ const { tool_response } = input;
1765
+ const userId = opts.userId ?? "";
1766
+ const redacted = deepMapStrings(tool_response, (value) => redactHostedSecrets(userId, value));
1767
+ if (JSON.stringify(redacted) === JSON.stringify(tool_response)) {
1768
+ return { continue: true };
1769
+ }
1770
+ return {
1771
+ hookSpecificOutput: {
1772
+ hookEventName: "PostToolUse",
1773
+ updatedToolOutput: redacted
1774
+ }
1775
+ };
1776
+ }
1777
+ ]
1778
+ }
1779
+ ]
1780
+ },
1781
+ settingSources: ["project"],
1782
+ settings: {
1783
+ disableWorkflows: true,
1784
+ workflowKeywordTriggerEnabled: false
1785
+ },
1786
+ systemPrompt: opts.systemPrompt
1787
+ };
1788
+ if (opts.sessionId) {
1789
+ queryOptions.resume = opts.sessionId;
1790
+ }
1791
+ const THINKING_BEAT_MS = 5000;
1792
+ let thinkingStart = null;
1793
+ let lastThinkingBeat = 0;
1794
+ let lastContextTokens;
1795
+ let lastContextModel;
1796
+ const thinkingBeat = () => {
1797
+ const now = Date.now();
1798
+ if (thinkingStart === null) {
1799
+ thinkingStart = now;
1800
+ lastThinkingBeat = now;
1801
+ return { type: "tool_progress", toolName: "thinking", elapsed: 0 };
1802
+ }
1803
+ if (now - lastThinkingBeat < THINKING_BEAT_MS)
1804
+ return null;
1805
+ lastThinkingBeat = now;
1806
+ return { type: "tool_progress", toolName: "thinking", elapsed: (now - thinkingStart) / 1000 };
1807
+ };
1808
+ try {
1809
+ const prompt = buildClaudePrompt(opts);
1810
+ for await (const message of query({
1811
+ prompt,
1812
+ options: queryOptions
1813
+ })) {
1814
+ if (message.type === "system" && message.subtype === "thinking_tokens") {
1815
+ const beat = thinkingBeat();
1816
+ if (beat)
1817
+ yield beat;
1818
+ continue;
1819
+ }
1820
+ if (message.type === "stream_event") {
1821
+ const streamMsg = message;
1822
+ const evt = streamMsg.event;
1823
+ if (!evt)
1824
+ continue;
1825
+ if (evt.type === "content_block_delta") {
1826
+ const delta = evt;
1827
+ if (delta.delta.type === "thinking_delta") {
1828
+ const beat = thinkingBeat();
1829
+ if (beat)
1830
+ yield beat;
1831
+ } else if (delta.delta.type === "text_delta" && delta.delta.text) {
1832
+ thinkingStart = null;
1833
+ } else {
1834
+ thinkingStart = null;
1835
+ }
1836
+ }
1837
+ continue;
1838
+ }
1839
+ thinkingStart = null;
1840
+ if (message.type === "tool_progress") {
1841
+ const m = message;
1842
+ yield {
1843
+ type: "tool_progress",
1844
+ toolName: m.tool_name,
1845
+ elapsed: m.elapsed_time_seconds
1846
+ };
1847
+ continue;
1848
+ }
1849
+ if (message.type === "tool_use_summary") {
1850
+ const m = message;
1851
+ yield { type: "tool_use_summary", summary: m.summary };
1852
+ continue;
1853
+ }
1854
+ if (message.type === "system") {
1855
+ const m = message;
1856
+ if (m.subtype === "init") {
1857
+ yield { type: "session", sessionId: m.session_id };
1858
+ } else if (m.subtype === "task_started") {
1859
+ const t = m;
1860
+ if (t.subagent_type && !t.skip_transcript) {
1861
+ const desc = t.description ? ` ${t.description.slice(0, 60)}` : "";
1862
+ yield { type: "status", content: `\u25B6 [${t.subagent_type}]${desc}` };
1863
+ }
1864
+ } else {
1865
+ logger.debug({ subtype: m.subtype, msg: m }, "claudeProvider: system message (unhandled subtype)");
1866
+ }
1867
+ continue;
1868
+ }
1869
+ if (message.type === "result") {
1870
+ const m = message;
1871
+ if (m.subtype === "success") {
1872
+ const contextWindow = (lastContextModel ? m.modelUsage?.[lastContextModel]?.contextWindow : undefined) ?? Object.values(m.modelUsage ?? {})[0]?.contextWindow;
1873
+ yield {
1874
+ type: "result",
1875
+ content: m.result,
1876
+ stopReason: m.stop_reason ?? "end_turn",
1877
+ usage: m.usage ? {
1878
+ inputTokens: m.usage.input_tokens,
1879
+ outputTokens: m.usage.output_tokens,
1880
+ cacheCreationInputTokens: m.usage.cache_creation_input_tokens ?? undefined,
1881
+ cacheReadInputTokens: m.usage.cache_read_input_tokens ?? undefined,
1882
+ costUsd: m.total_cost_usd,
1883
+ ...lastContextTokens !== undefined && contextWindow ? { contextTokens: lastContextTokens, contextWindow } : {}
1884
+ } : undefined
1885
+ };
1886
+ yield* extractFileEvents(m.result, "result");
1887
+ return;
1888
+ }
1889
+ const budgetExceeded = m.subtype === "error_max_budget_usd";
1890
+ const errorMsg = budgetExceeded ? "The job reached its cost limit" : m.errors?.join("; ") || "Unknown error";
1891
+ yield {
1892
+ type: "error",
1893
+ content: errorMsg,
1894
+ ...budgetExceeded ? { code: "budget_exceeded" } : {},
1895
+ ...m.usage ? {
1896
+ usage: {
1897
+ inputTokens: m.usage.input_tokens,
1898
+ outputTokens: m.usage.output_tokens,
1899
+ cacheCreationInputTokens: m.usage.cache_creation_input_tokens ?? undefined,
1900
+ cacheReadInputTokens: m.usage.cache_read_input_tokens ?? undefined,
1901
+ costUsd: m.total_cost_usd
1902
+ }
1903
+ } : {}
1904
+ };
1905
+ return;
1906
+ }
1907
+ if (message.type === "assistant") {
1908
+ const m = message;
1909
+ const content = m.message?.content ?? [];
1910
+ const usage = m.message?.usage;
1911
+ if (usage) {
1912
+ lastContextTokens = (usage.input_tokens ?? 0) + (usage.cache_creation_input_tokens ?? 0) + (usage.cache_read_input_tokens ?? 0) + (usage.output_tokens ?? 0);
1913
+ lastContextModel = m.message.model;
1914
+ }
1915
+ for (const block of content) {
1916
+ if (block.type === "text") {
1917
+ const textBlock = block;
1918
+ yield { type: "text", content: textBlock.text };
1919
+ yield* extractFileEvents(textBlock.text, "text");
1920
+ } else if (block.type === "tool_use") {
1921
+ const tb = block;
1922
+ yield {
1923
+ type: "tool_use",
1924
+ name: tb.name,
1925
+ input: tb.input || {},
1926
+ toolUseId: tb.id
1927
+ };
1928
+ }
1929
+ }
1930
+ continue;
1931
+ }
1932
+ if (message.type === "user") {
1933
+ const um = message;
1934
+ if ("isReplay" in um && um.isReplay)
1935
+ continue;
1936
+ const content = um.message?.content;
1937
+ if (!Array.isArray(content))
1938
+ continue;
1939
+ for (const block of content) {
1940
+ if (block.type !== "tool_result")
1941
+ continue;
1942
+ const trBlock = block;
1943
+ const trContent = typeof trBlock.content === "string" ? trBlock.content.slice(0, 200) : "";
1944
+ yield {
1945
+ type: "tool_result",
1946
+ toolUseId: trBlock.tool_use_id || "",
1947
+ content: trContent
1948
+ };
1949
+ }
1950
+ }
1951
+ }
1952
+ } catch (e) {
1953
+ if (isAbortError(e) || opts.abortController?.signal.aborted)
1954
+ return;
1955
+ logger.error({ err: e }, "claudeProvider: SDK iteration failed");
1956
+ yield { type: "error", content: errMsg(e) };
1957
+ }
1958
+ }
1959
+
1960
+ // ../../packages/core/src/agents/codex-provider.ts
1961
+ import { existsSync as existsSync7 } from "fs";
1962
+ import { Codex } from "@openai/codex-sdk";
1963
+
1964
+ // ../../packages/core/src/agents/codex-native-multi-agent.ts
1965
+ import { spawn as spawn2 } from "child_process";
1966
+ import {
1967
+ chmodSync as chmodSync3,
1968
+ existsSync as existsSync5,
1969
+ readFileSync as readFileSync5,
1970
+ renameSync as renameSync3,
1971
+ unlinkSync as unlinkSync3,
1972
+ writeFileSync as writeFileSync4
1973
+ } from "fs";
1974
+ import { createRequire } from "module";
1975
+ import { dirname as dirname4, join as join6 } from "path";
1976
+
1977
+ // ../../packages/core/src/version.ts
1978
+ var NEGOTIUM_VERSION = "0.1.13";
1979
+
1980
+ // ../../packages/core/src/agents/codex-native-multi-agent.ts
1981
+ var NEGOTIUM_MODEL_CATALOG = "negotium-model-catalog.json";
1982
+ var moduleRequire = createRequire(import.meta.url);
1983
+ function codexCliScriptPath() {
1984
+ const sdkPackagePath = moduleRequire.resolve("@openai/codex-sdk/package.json");
1985
+ const sdkRequire = createRequire(sdkPackagePath);
1986
+ return join6(dirname4(sdkRequire.resolve("@openai/codex/package.json")), "bin", "codex.js");
1987
+ }
1988
+ async function bootstrapCodexModelCache(codexHome, cachePath) {
1989
+ const child = spawn2(process.execPath, [codexCliScriptPath(), "app-server", "--stdio"], {
1990
+ env: { ...process.env, CODEX_HOME: codexHome },
1991
+ stdio: ["pipe", "pipe", "pipe"]
1992
+ });
1993
+ await new Promise((resolve4, reject) => {
1994
+ let settled = false;
1995
+ let stdoutBuffer = "";
1996
+ let stderr = "";
1997
+ const timer = setTimeout(() => finish(new Error("timed out while refreshing the Codex model catalog")), 15000);
1998
+ const finish = (error) => {
1999
+ if (settled)
2000
+ return;
2001
+ settled = true;
2002
+ clearTimeout(timer);
2003
+ try {
2004
+ child.stdin.end();
2005
+ child.kill();
2006
+ } catch {}
2007
+ if (error)
2008
+ reject(error);
2009
+ else if (!existsSync5(cachePath))
2010
+ reject(new Error("Codex did not create its model cache"));
2011
+ else
2012
+ resolve4();
2013
+ };
2014
+ const send = (message) => {
2015
+ child.stdin.write(`${JSON.stringify(message)}
2016
+ `);
2017
+ };
2018
+ child.stderr.on("data", (chunk) => {
2019
+ if (stderr.length < 4096)
2020
+ stderr += String(chunk);
2021
+ });
2022
+ child.on("error", (error) => finish(error));
2023
+ child.on("exit", (code, signal) => {
2024
+ if (!settled) {
2025
+ finish(new Error(`Codex model catalog refresh exited with ${signal ? `signal ${signal}` : `code ${code ?? 1}`}${stderr.trim() ? `: ${stderr.trim()}` : ""}`));
2026
+ }
2027
+ });
2028
+ child.stdout.on("data", (chunk) => {
2029
+ stdoutBuffer += String(chunk);
2030
+ for (;; ) {
2031
+ const newline = stdoutBuffer.indexOf(`
2032
+ `);
2033
+ if (newline < 0)
2034
+ break;
2035
+ const line = stdoutBuffer.slice(0, newline);
2036
+ stdoutBuffer = stdoutBuffer.slice(newline + 1);
2037
+ let message;
2038
+ try {
2039
+ message = JSON.parse(line);
2040
+ } catch {
2041
+ continue;
2042
+ }
2043
+ if (message.id === 1) {
2044
+ if (message.error) {
2045
+ finish(new Error(message.error.message || "Codex initialization failed"));
2046
+ return;
2047
+ }
2048
+ send({ method: "initialized" });
2049
+ send({ id: 2, method: "model/list", params: { includeHidden: true } });
2050
+ } else if (message.id === 2) {
2051
+ if (message.error) {
2052
+ finish(new Error(message.error.message || "Codex model listing failed"));
2053
+ } else {
2054
+ finish();
2055
+ }
2056
+ return;
2057
+ }
2058
+ }
2059
+ });
2060
+ send({
2061
+ id: 1,
2062
+ method: "initialize",
2063
+ params: {
2064
+ clientInfo: { name: "negotium", version: NEGOTIUM_VERSION },
2065
+ capabilities: { experimentalApi: true }
2066
+ }
2067
+ });
2068
+ });
2069
+ }
2070
+ async function ensureCodexModelCache(authFilePath, bootstrap = bootstrapCodexModelCache) {
2071
+ const codexHome = dirname4(authFilePath);
2072
+ const cachePath = process.env.NEGOTIUM_CODEX_MODELS_CACHE_FILE ?? join6(codexHome, "models_cache.json");
2073
+ const hardenedCatalogPath = join6(codexHome, NEGOTIUM_MODEL_CATALOG);
2074
+ if (existsSync5(cachePath) || existsSync5(hardenedCatalogPath))
2075
+ return;
2076
+ if (process.env.NEGOTIUM_CODEX_MODELS_CACHE_FILE) {
2077
+ throw new Error(`Configured Codex model cache does not exist: ${cachePath}`);
2078
+ }
2079
+ await bootstrap(codexHome, cachePath);
2080
+ }
2081
+ function writeCodexCatalogWithNativeMultiAgentDisabled(authFilePath) {
2082
+ const codexHome = dirname4(authFilePath);
2083
+ const sourcePath = process.env.NEGOTIUM_CODEX_MODELS_CACHE_FILE ?? (existsSync5(join6(codexHome, "models_cache.json")) ? join6(codexHome, "models_cache.json") : join6(codexHome, NEGOTIUM_MODEL_CATALOG));
2084
+ const outputPath = join6(codexHome, NEGOTIUM_MODEL_CATALOG);
2085
+ const parsed = JSON.parse(readFileSync5(sourcePath, "utf8"));
2086
+ if (!Array.isArray(parsed.models) || parsed.models.length === 0) {
2087
+ throw new Error(`Codex model cache has no models: ${sourcePath}`);
2088
+ }
2089
+ const models = parsed.models.map((model, index) => {
2090
+ if (!model || typeof model !== "object" || Array.isArray(model)) {
2091
+ throw new Error(`Codex model cache entry ${index} is invalid: ${sourcePath}`);
2092
+ }
2093
+ return { ...model, multi_agent_version: "disabled" };
2094
+ });
2095
+ const contents = `${JSON.stringify({ models }, null, 2)}
2096
+ `;
2097
+ if (existsSync5(outputPath) && readFileSync5(outputPath, "utf8") === contents) {
2098
+ return outputPath;
2099
+ }
2100
+ const tempPath = `${outputPath}.${process.pid}.${Date.now()}.tmp`;
2101
+ try {
2102
+ writeFileSync4(tempPath, contents, { encoding: "utf8", mode: 384 });
2103
+ renameSync3(tempPath, outputPath);
2104
+ chmodSync3(outputPath, 384);
2105
+ } finally {
2106
+ try {
2107
+ unlinkSync3(tempPath);
2108
+ } catch {}
2109
+ }
2110
+ return outputPath;
2111
+ }
2112
+
2113
+ // ../../packages/core/src/agents/codex-tree-kill.ts
2114
+ import { execFileSync } from "child_process";
2115
+ var SIGKILL_DELAY_MS = 5000;
2116
+ var CODEX_PROC_NAME_MATCH = /codex/i;
2117
+ var TREE_DEPTH_CAP = 16;
2118
+ function getDirectChildren(parentPid) {
2119
+ try {
2120
+ const out = execFileSync("pgrep", ["-P", String(parentPid)], {
2121
+ encoding: "utf8",
2122
+ stdio: ["ignore", "pipe", "ignore"]
2123
+ }).trim();
2124
+ if (!out)
2125
+ return [];
2126
+ return out.split(`
2127
+ `).map((s) => Number(s)).filter((n) => Number.isFinite(n) && n > 0);
2128
+ } catch {
2129
+ return [];
2130
+ }
2131
+ }
2132
+ function getProcName(pid) {
2133
+ try {
2134
+ return execFileSync("ps", ["-p", String(pid), "-o", "comm="], {
2135
+ encoding: "utf8",
2136
+ stdio: ["ignore", "pipe", "ignore"]
2137
+ }).trim();
2138
+ } catch {
2139
+ return "";
2140
+ }
2141
+ }
2142
+ function getProcLstart(pid) {
2143
+ try {
2144
+ return execFileSync("ps", ["-p", String(pid), "-o", "lstart="], {
2145
+ encoding: "utf8",
2146
+ stdio: ["ignore", "pipe", "ignore"]
2147
+ }).trim();
2148
+ } catch {
2149
+ return "";
2150
+ }
2151
+ }
2152
+ function collectTree(rootPid, out = new Set, depth = 0) {
2153
+ if (out.has(rootPid))
2154
+ return out;
2155
+ out.add(rootPid);
2156
+ if (depth >= TREE_DEPTH_CAP) {
2157
+ logger.warn({ rootPid, depth, cap: TREE_DEPTH_CAP }, "codex-tree-kill: tree depth cap reached, descendants beyond this point not collected");
2158
+ return out;
2159
+ }
2160
+ for (const child of getDirectChildren(rootPid)) {
2161
+ collectTree(child, out, depth + 1);
2162
+ }
2163
+ return out;
2164
+ }
2165
+ function snapshotCodexChildren() {
2166
+ const out = new Map;
2167
+ for (const pid of getDirectChildren(process.pid)) {
2168
+ const name = getProcName(pid);
2169
+ if (!name || !CODEX_PROC_NAME_MATCH.test(name))
2170
+ continue;
2171
+ const lstart = getProcLstart(pid);
2172
+ out.set(pid, lstart);
2173
+ }
2174
+ return out;
2175
+ }
2176
+ var globalOwnedCodexPids = new Set;
2177
+ function registerOwnedCodexPids(pids) {
2178
+ for (const p of pids)
2179
+ globalOwnedCodexPids.add(p);
2180
+ }
2181
+ function unregisterOwnedCodexPids(pids) {
2182
+ for (const p of pids)
2183
+ globalOwnedCodexPids.delete(p);
2184
+ }
2185
+ function findNewCodexChildren(baseline) {
2186
+ const current = snapshotCodexChildren();
2187
+ const novel = [];
2188
+ for (const [pid, lstart] of current) {
2189
+ const baselineLstart = baseline.get(pid);
2190
+ if (baselineLstart !== undefined && baselineLstart === lstart)
2191
+ continue;
2192
+ if (globalOwnedCodexPids.has(pid))
2193
+ continue;
2194
+ novel.push(pid);
2195
+ }
2196
+ return novel;
2197
+ }
2198
+ var codexSpawnChain = Promise.resolve();
2199
+ async function acquireCodexSpawnLock() {
2200
+ const prev = codexSpawnChain;
2201
+ let release;
2202
+ let released = false;
2203
+ codexSpawnChain = new Promise((r) => {
2204
+ release = () => {
2205
+ if (released)
2206
+ return;
2207
+ released = true;
2208
+ r();
2209
+ };
2210
+ });
2211
+ await prev;
2212
+ return release;
2213
+ }
2214
+ function isAlive(pid) {
2215
+ try {
2216
+ process.kill(pid, 0);
2217
+ return true;
2218
+ } catch {
2219
+ return false;
2220
+ }
2221
+ }
2222
+ function isSameProcess(pid, lstart) {
2223
+ return lstart !== "" && isAlive(pid) && getProcLstart(pid) === lstart;
2224
+ }
2225
+ function signalCodexTrees(rootPids) {
2226
+ if (rootPids.length === 0)
2227
+ return null;
2228
+ const targets = new Map;
2229
+ for (const root of rootPids) {
2230
+ for (const pid of collectTree(root)) {
2231
+ if (!targets.has(pid))
2232
+ targets.set(pid, getProcLstart(pid));
2233
+ }
2234
+ }
2235
+ logger.warn({ rootPids, totalPids: targets.size }, "codex-tree-kill: SIGTERM process tree");
2236
+ for (const pid of targets.keys()) {
2237
+ try {
2238
+ process.kill(pid, "SIGTERM");
2239
+ } catch {}
2240
+ }
2241
+ return { rootPids, targets };
2242
+ }
2243
+ function killCodexStragglers({ rootPids, targets }) {
2244
+ const aliveTargets = [];
2245
+ let droppedAsPossibleReuse = 0;
2246
+ for (const [pid, lstart] of targets) {
2247
+ if (isSameProcess(pid, lstart)) {
2248
+ aliveTargets.push(pid);
2249
+ } else if (isAlive(pid)) {
2250
+ droppedAsPossibleReuse++;
2251
+ }
2252
+ }
2253
+ if (aliveTargets.length === 0)
2254
+ return;
2255
+ const reachable = new Set(aliveTargets);
2256
+ for (const root of rootPids) {
2257
+ const rootLstart = targets.get(root);
2258
+ if (rootLstart && isSameProcess(root, rootLstart)) {
2259
+ for (const pid of collectTree(root))
2260
+ reachable.add(pid);
2261
+ }
2262
+ }
2263
+ const stragglers = [];
2264
+ for (const pid of reachable) {
2265
+ const lstart = targets.get(pid);
2266
+ if (lstart && isSameProcess(pid, lstart))
2267
+ stragglers.push(pid);
2268
+ else if (isAlive(pid))
2269
+ droppedAsPossibleReuse++;
2270
+ }
2271
+ logger.warn({
2272
+ aliveRoots: rootPids.filter((pid) => {
2273
+ const lstart = targets.get(pid);
2274
+ return lstart ? isSameProcess(pid, lstart) : false;
2275
+ }),
2276
+ totalStragglers: stragglers.length,
2277
+ droppedAsPossibleReuse
2278
+ }, "codex-tree-kill: SIGKILL fallback after SIGTERM timeout");
2279
+ for (const pid of stragglers) {
2280
+ try {
2281
+ process.kill(pid, "SIGKILL");
2282
+ } catch {}
2283
+ }
2284
+ }
2285
+ function killCodexTrees(rootPids) {
2286
+ const plan = signalCodexTrees(rootPids);
2287
+ if (!plan)
2288
+ return;
2289
+ const killTimer = setTimeout(() => {
2290
+ killCodexStragglers(plan);
2291
+ }, SIGKILL_DELAY_MS);
2292
+ killTimer.unref?.();
2293
+ }
2294
+
2295
+ // ../../packages/core/src/agents/rollout/codex.ts
2296
+ import { existsSync as existsSync6, readFileSync as readFileSync6, statSync as statSync2, unlinkSync as unlinkSync4 } from "fs";
2297
+ import { homedir as homedir4 } from "os";
2298
+ import { join as join7 } from "path";
2299
+ function codexSessionsDir() {
2300
+ return join7(process.env.CODEX_HOME || join7(homedir4(), ".codex"), "sessions");
2301
+ }
2302
+ function extractLatestCodexContextUsage(jsonl) {
2303
+ const lines = jsonl.trimEnd().split(`
2304
+ `);
2305
+ for (let index = lines.length - 1;index >= 0; index -= 1) {
2306
+ try {
2307
+ const entry = JSON.parse(lines[index] ?? "");
2308
+ if (entry.type !== "event_msg" || entry.payload?.type !== "token_count")
2309
+ continue;
2310
+ const contextTokens = entry.payload.info?.last_token_usage?.total_tokens;
2311
+ const contextWindow = entry.payload.info?.model_context_window;
2312
+ if (typeof contextTokens === "number" && Number.isFinite(contextTokens) && contextTokens >= 0 && typeof contextWindow === "number" && Number.isFinite(contextWindow) && contextWindow > 0) {
2313
+ return { contextTokens, contextWindow };
2314
+ }
2315
+ } catch {}
2316
+ }
2317
+ return;
2318
+ }
2319
+ function readLatestCodexContextUsage(threadId) {
2320
+ const sessionsDir = codexSessionsDir();
2321
+ const candidates = [];
2322
+ const buckets = candidateDateBuckets(threadId);
2323
+ try {
2324
+ if (buckets) {
2325
+ for (const bucket of buckets) {
2326
+ const dir = join7(sessionsDir, bucket);
2327
+ if (!existsSync6(dir))
2328
+ continue;
2329
+ const glob = new Bun.Glob(`rollout-*-${threadId}.jsonl`);
2330
+ for (const rel of glob.scanSync({ cwd: dir, onlyFiles: true })) {
2331
+ candidates.push(join7(dir, rel));
2332
+ }
2333
+ }
2334
+ } else {
2335
+ const glob = new Bun.Glob(`**/rollout-*-${threadId}.jsonl`);
2336
+ for (const rel of glob.scanSync({ cwd: sessionsDir, onlyFiles: true })) {
2337
+ candidates.push(join7(sessionsDir, rel));
2338
+ }
2339
+ }
2340
+ const path = candidates.sort((a, b) => statSync2(b).mtimeMs - statSync2(a).mtimeMs)[0];
2341
+ return path ? extractLatestCodexContextUsage(readFileSync6(path, "utf8")) : undefined;
2342
+ } catch (error) {
2343
+ logger.debug({ error, threadId }, "codex context usage: rollout read failed");
2344
+ return;
2345
+ }
2346
+ }
2347
+ function migrateCodexRolloutNativeMultiAgentMetadata(threadId) {
2348
+ const path = latestCodexRolloutPath(threadId);
2349
+ if (!path)
2350
+ return false;
2351
+ try {
2352
+ const entries = parseJsonlText(readFileSync6(path, "utf8"));
2353
+ let changed = false;
2354
+ for (const entry of entries) {
2355
+ if (entry.type !== "session_meta" && entry.type !== "turn_context")
2356
+ continue;
2357
+ if (!entry.payload)
2358
+ entry.payload = {};
2359
+ if (entry.payload.multi_agent_version !== "disabled") {
2360
+ entry.payload.multi_agent_version = "disabled";
2361
+ changed = true;
2362
+ }
2363
+ }
2364
+ if (changed) {
2365
+ writeJsonlFile(path, entries);
2366
+ logger.info({ threadId, path }, "codex rollout native multi-agent metadata disabled");
2367
+ }
2368
+ return changed;
2369
+ } catch (error) {
2370
+ logger.error({ error, threadId, path }, "codex rollout native multi-agent migration failed");
2371
+ throw new Error(`Failed to migrate Codex rollout '${threadId}'`, { cause: error });
2372
+ }
2373
+ }
2374
+ function latestCodexRolloutPath(threadId) {
2375
+ const sessionsDir = codexSessionsDir();
2376
+ const candidates = [];
2377
+ const buckets = candidateDateBuckets(threadId);
2378
+ try {
2379
+ if (buckets) {
2380
+ for (const bucket of buckets) {
2381
+ const dir = join7(sessionsDir, bucket);
2382
+ if (!existsSync6(dir))
2383
+ continue;
2384
+ const glob = new Bun.Glob(`rollout-*-${threadId}.jsonl`);
2385
+ for (const rel of glob.scanSync({ cwd: dir, onlyFiles: true })) {
2386
+ candidates.push(join7(dir, rel));
2387
+ }
2388
+ }
2389
+ }
2390
+ if (candidates.length === 0) {
2391
+ const glob = new Bun.Glob(`**/rollout-*-${threadId}.jsonl`);
2392
+ for (const rel of glob.scanSync({ cwd: sessionsDir, onlyFiles: true })) {
2393
+ candidates.push(join7(sessionsDir, rel));
2394
+ }
2395
+ }
2396
+ return candidates.sort((a, b) => statSync2(b).mtimeMs - statSync2(a).mtimeMs)[0];
2397
+ } catch (error) {
2398
+ logger.debug({ error, threadId }, "codex rollout lookup failed");
2399
+ return;
2400
+ }
2401
+ }
2402
+ var MAX_DAY_SPAN = 30;
2403
+ var DAY_MS = 86400000;
2404
+ var LOCAL_DATE_SKEW_DAYS = 1;
2405
+ function candidateDateBuckets(threadId) {
2406
+ const tidMs = decodeUuidV7Timestamp(threadId);
2407
+ if (tidMs === null)
2408
+ return null;
2409
+ const nowMs = Date.now();
2410
+ const tidDay = Math.floor(tidMs / DAY_MS);
2411
+ const todayDay = Math.floor(nowMs / DAY_MS);
2412
+ const minDay = Math.min(tidDay, todayDay);
2413
+ const maxDay = Math.max(tidDay, todayDay);
2414
+ const span = maxDay - minDay;
2415
+ if (span > MAX_DAY_SPAN)
2416
+ return null;
2417
+ const buckets = new Set;
2418
+ for (let d = minDay - LOCAL_DATE_SKEW_DAYS;d <= maxDay + LOCAL_DATE_SKEW_DAYS; d++) {
2419
+ buckets.add(formatDateBucket(new Date(d * DAY_MS)));
2420
+ }
2421
+ return buckets;
2422
+ }
2423
+ function decodeUuidV7Timestamp(threadId) {
2424
+ if (typeof threadId !== "string")
2425
+ return null;
2426
+ const m = /^([0-9a-fA-F]{8})-([0-9a-fA-F]{4})-7[0-9a-fA-F]{3}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.exec(threadId);
2427
+ if (!m)
2428
+ return null;
2429
+ const hex = `${m[1]}${m[2]}`;
2430
+ const ms = Number.parseInt(hex, 16);
2431
+ if (!Number.isFinite(ms))
2432
+ return null;
2433
+ const MIN = 1577836800000;
2434
+ const MAX = 4102444800000;
2435
+ if (ms < MIN || ms > MAX)
2436
+ return null;
2437
+ return ms;
2438
+ }
2439
+ function formatDateBucket(d) {
2440
+ const yyyy = d.getUTCFullYear();
2441
+ const mm = String(d.getUTCMonth() + 1).padStart(2, "0");
2442
+ const dd = String(d.getUTCDate()).padStart(2, "0");
2443
+ return `${yyyy}/${mm}/${dd}`;
2444
+ }
2445
+
2446
+ // ../../packages/core/src/agents/codex-provider.ts
2447
+ function mapEffort(effort) {
2448
+ if (!effort)
2449
+ return;
2450
+ if (effort === "max" || effort === "minimal") {
2451
+ throw new Error(`codexProvider received effort='${effort}', which codex does not support \u2014 storage validation was bypassed`);
2452
+ }
2453
+ return effort;
2454
+ }
2455
+ var CODEX_MCP_SERVER_NAME_OVERRIDES = {
2456
+ playwright: "otium_playwright"
2457
+ };
2458
+ function codexMcpServerName(name) {
2459
+ return CODEX_MCP_SERVER_NAME_OVERRIDES[name] ?? name;
2460
+ }
2461
+ function parsePositiveInt(value, fallback) {
2462
+ if (!value)
2463
+ return fallback;
2464
+ const parsed = Number.parseInt(value, 10);
2465
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
2466
+ }
2467
+ function withCodexMcpServerOverrides(name, server) {
2468
+ if (name === "paddleocr") {
2469
+ return {
2470
+ ...server,
2471
+ startup_timeout_sec: parsePositiveInt(process.env.PADDLEOCR_MCP_STARTUP_TIMEOUT_SEC, 30),
2472
+ tool_timeout_sec: parsePositiveInt(process.env.PADDLEOCR_MCP_TOOL_TIMEOUT_SEC, 300)
2473
+ };
2474
+ }
2475
+ return {
2476
+ startup_timeout_sec: parsePositiveInt(process.env.CODEX_MCP_STARTUP_TIMEOUT_SEC, 30),
2477
+ ...server
2478
+ };
2479
+ }
2480
+ function toCodexMcpServers(claudeShape) {
2481
+ const disabledBrowserStdio = () => ({
2482
+ command: process.execPath,
2483
+ args: ["-e", "process.exit(0)"],
2484
+ enabled: false
2485
+ });
2486
+ const out = {
2487
+ playwright: disabledBrowserStdio(),
2488
+ "browser-rs": disabledBrowserStdio(),
2489
+ patchright: disabledBrowserStdio()
2490
+ };
2491
+ for (const [name, srv] of Object.entries(claudeShape)) {
2492
+ if (!srv || typeof srv !== "object")
2493
+ continue;
2494
+ const s = srv;
2495
+ const codexName = codexMcpServerName(name);
2496
+ if (typeof s.command === "string") {
2497
+ out[codexName] = withCodexMcpServerOverrides(name, {
2498
+ command: s.command,
2499
+ ...Array.isArray(s.args) ? { args: s.args } : {},
2500
+ ...s.env && typeof s.env === "object" ? { env: s.env } : {}
2501
+ });
2502
+ continue;
2503
+ }
2504
+ if (typeof s.url === "string" && s.type !== "sse") {
2505
+ out[codexName] = withCodexMcpServerOverrides(name, {
2506
+ url: s.url,
2507
+ ...s.http_headers && typeof s.http_headers === "object" ? { http_headers: s.http_headers } : {},
2508
+ ...s.env_http_headers && typeof s.env_http_headers === "object" ? { env_http_headers: s.env_http_headers } : {}
2509
+ });
2510
+ }
2511
+ }
2512
+ return out;
2513
+ }
2514
+ function isMissingCodexRolloutError(err) {
2515
+ const msg = errMsg(err);
2516
+ return /no rollout found|thread\/resume failed/i.test(msg);
2517
+ }
2518
+ function summarizeMcpToolCallResult(item) {
2519
+ if (item.error)
2520
+ return item.error.message.slice(0, 200);
2521
+ if (!item.result)
2522
+ return "";
2523
+ const blocks = Array.isArray(item.result.content) ? item.result.content : [];
2524
+ const text = blocks.map((b) => {
2525
+ if (b && typeof b === "object" && "type" in b && b.type === "text" && "text" in b) {
2526
+ return String(b.text ?? "");
2527
+ }
2528
+ return "";
2529
+ }).filter(Boolean).join(`
2530
+ `);
2531
+ if (text)
2532
+ return text.slice(0, 200);
2533
+ return JSON.stringify(item.result.structured_content ?? "").slice(0, 200);
2534
+ }
2535
+ function fileChangeEvents(item) {
2536
+ return item.changes.flatMap((change, index) => {
2537
+ const name = change.kind === "add" ? "Write" : change.kind === "delete" ? "Delete" : "Edit";
2538
+ const toolUseId = `${item.id}:${index}`;
2539
+ const success = item.status === "completed";
2540
+ return [
2541
+ {
2542
+ type: "tool_use",
2543
+ name,
2544
+ input: { file_path: change.path, change_kind: change.kind },
2545
+ toolUseId
2546
+ },
2547
+ {
2548
+ type: "tool_result",
2549
+ toolUseId,
2550
+ content: success ? `${change.kind} applied: ${change.path}` : `${change.kind} failed: ${change.path}`
2551
+ }
2552
+ ];
2553
+ });
2554
+ }
2555
+ function promptForThread(opts, includeSystemPrompt) {
2556
+ return includeSystemPrompt && opts.systemPrompt ? `[System Instructions]
2557
+ ${opts.systemPrompt}
2558
+
2559
+ ${opts.prompt}` : opts.prompt;
2560
+ }
2561
+ async function closeIterator(iter) {
2562
+ try {
2563
+ await iter.return?.();
2564
+ } catch (err) {
2565
+ logger.warn({ err }, "codexProvider: failed to close codex event iterator");
2566
+ }
2567
+ }
2568
+ var CODEX_STARTUP_TIMEOUT_MS = 90000;
2569
+ async function startStreamedWithTracking(thread, prompt, abortSignal, trackedPids) {
2570
+ const release = await acquireCodexSpawnLock();
2571
+ try {
2572
+ const baseline = snapshotCodexChildren();
2573
+ const runResult = await thread.runStreamed(prompt, {
2574
+ ...abortSignal ? { signal: abortSignal } : {}
2575
+ });
2576
+ const iter = runResult.events[Symbol.asyncIterator]();
2577
+ let first;
2578
+ let startupTimer;
2579
+ try {
2580
+ const startupTimeout = new Promise((_, reject) => {
2581
+ startupTimer = setTimeout(() => reject(new Error(`Codex\uAC00 ${CODEX_STARTUP_TIMEOUT_MS / 1000}\uCD08 \uB0B4 \uC751\uB2F5\uC744 \uC2DC\uC791\uD558\uC9C0 \uC54A\uC544 \uC911\uB2E8\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.`)), CODEX_STARTUP_TIMEOUT_MS);
2582
+ });
2583
+ const nextP = iter.next();
2584
+ nextP.catch(() => {});
2585
+ first = await Promise.race([nextP, startupTimeout]);
2586
+ } catch (err) {
2587
+ const novel2 = findNewCodexChildren(baseline);
2588
+ if (novel2.length > 0) {
2589
+ killCodexTrees(novel2);
2590
+ }
2591
+ await closeIterator(iter);
2592
+ throw err;
2593
+ } finally {
2594
+ if (startupTimer)
2595
+ clearTimeout(startupTimer);
2596
+ }
2597
+ const novel = findNewCodexChildren(baseline);
2598
+ trackedPids.pids = novel;
2599
+ registerOwnedCodexPids(novel);
2600
+ return { iter, firstEvent: first.value, done: !!first.done };
2601
+ } finally {
2602
+ release();
2603
+ }
2604
+ }
2605
+ function prependFirstEvent(iter, firstEvent, alreadyDone) {
2606
+ return {
2607
+ [Symbol.asyncIterator]() {
2608
+ let emittedFirst = false;
2609
+ let exhausted = alreadyDone;
2610
+ return {
2611
+ async next() {
2612
+ if (!emittedFirst) {
2613
+ emittedFirst = true;
2614
+ if (alreadyDone)
2615
+ return { value: undefined, done: true };
2616
+ return { value: firstEvent, done: false };
2617
+ }
2618
+ if (exhausted)
2619
+ return { value: undefined, done: true };
2620
+ const r = await iter.next();
2621
+ if (r.done)
2622
+ exhausted = true;
2623
+ return r;
2624
+ },
2625
+ async return(value) {
2626
+ exhausted = true;
2627
+ if (iter.return)
2628
+ return iter.return(value);
2629
+ return { value, done: true };
2630
+ }
2631
+ };
2632
+ }
2633
+ };
2634
+ }
2635
+ async function* codexProvider(opts) {
2636
+ const codexAuthPath = hostedCodexAuthFilePath();
2637
+ if (!existsSync7(codexAuthPath)) {
2638
+ yield {
2639
+ type: "error",
2640
+ content: `Codex auth file not found at ${codexAuthPath}. Run \`codex login\` to authenticate.`
2641
+ };
2642
+ return;
2643
+ }
2644
+ let codexModelCatalogPath;
2645
+ try {
2646
+ await ensureCodexModelCache(codexAuthPath);
2647
+ codexModelCatalogPath = writeCodexCatalogWithNativeMultiAgentDisabled(codexAuthPath);
2648
+ if (opts.sessionId)
2649
+ migrateCodexRolloutNativeMultiAgentMetadata(opts.sessionId);
2650
+ } catch (err) {
2651
+ yield {
2652
+ type: "error",
2653
+ content: `Failed to enforce the Codex native multi-agent policy: ${errMsg(err)}`
2654
+ };
2655
+ return;
2656
+ }
2657
+ const codexMcpServers = toCodexMcpServers(hostedMcpServers(opts));
2658
+ const browserOwner = browserOwnerForContext(opts);
2659
+ const scopedBrowserCapability = opts.playwrightCapability && browserOwner ? browserOwnerCapability(opts.playwrightCapability, browserOwner) : undefined;
2660
+ logger.info({
2661
+ model: opts.model ?? "(sdk default)",
2662
+ effort: opts.effort ?? "(off)",
2663
+ cwd: opts.cwd,
2664
+ cwdExists: existsSync7(opts.cwd),
2665
+ resume: Boolean(opts.sessionId),
2666
+ mcpServerCount: Object.keys(codexMcpServers).length
2667
+ }, "codexProvider: starting turn");
2668
+ const codex = new Codex({
2669
+ ...scopedBrowserCapability ? {
2670
+ env: {
2671
+ ...Object.fromEntries(Object.entries(process.env).filter((entry) => typeof entry[1] === "string")),
2672
+ [CODEX_BROWSER_CAPABILITY_ENV]: scopedBrowserCapability
2673
+ }
2674
+ } : {},
2675
+ config: {
2676
+ features: { multi_agent: false, multi_agent_v2: false, enable_fanout: false },
2677
+ model_catalog_json: codexModelCatalogPath,
2678
+ mcp_servers: codexMcpServers
2679
+ }
2680
+ });
2681
+ const threadOptions = {
2682
+ workingDirectory: opts.cwd,
2683
+ skipGitRepoCheck: true,
2684
+ sandboxMode: "danger-full-access",
2685
+ approvalPolicy: "never",
2686
+ ...opts.model ? { model: opts.model } : {},
2687
+ ...opts.effort ? { modelReasoningEffort: mapEffort(opts.effort) } : {}
2688
+ };
2689
+ let currentSessionId = opts.sessionId;
2690
+ let thread = currentSessionId ? codex.resumeThread(currentSessionId, threadOptions) : codex.startThread(threadOptions);
2691
+ let prompt = promptForThread(opts, true);
2692
+ let agentTextSoFar = "";
2693
+ let currentAgentMessageId;
2694
+ let finalText = "";
2695
+ let stopReason = "end_turn";
2696
+ const trackedPids = { pids: [] };
2697
+ const abortSignal = opts.abortController?.signal;
2698
+ const onAbortKill = () => {
2699
+ if (trackedPids.pids.length > 0) {
2700
+ killCodexTrees(trackedPids.pids);
2701
+ }
2702
+ };
2703
+ abortSignal?.addEventListener("abort", onAbortKill, { once: true });
2704
+ let heartbeatMs = 8 * 60 * 1000;
2705
+ let heartbeatAttempts = 0;
2706
+ const HEARTBEAT_MAX_MS = 16 * 60 * 1000;
2707
+ const HEARTBEAT_MAX_ATTEMPTS = 2;
2708
+ const HEARTBEAT_CONTINUATION = "\uACC4\uC18D \uC9C4\uD589\uD574\uC918.";
2709
+ try {
2710
+ while (true) {
2711
+ if (abortSignal?.aborted)
2712
+ return;
2713
+ const attemptAbort = new AbortController;
2714
+ const propagateOuter = () => attemptAbort.abort();
2715
+ abortSignal?.addEventListener("abort", propagateOuter, { once: true });
2716
+ trackedPids.pids = [];
2717
+ let heartbeatTriggered = false;
2718
+ let attemptCompleted = false;
2719
+ let heartbeatTimer = null;
2720
+ const scheduleHeartbeat = () => {
2721
+ if (heartbeatTimer !== null)
2722
+ clearTimeout(heartbeatTimer);
2723
+ if (abortSignal?.aborted || attemptAbort.signal.aborted)
2724
+ return;
2725
+ heartbeatTimer = setTimeout(() => {
2726
+ heartbeatTriggered = true;
2727
+ if (trackedPids.pids.length > 0)
2728
+ killCodexTrees(trackedPids.pids);
2729
+ attemptAbort.abort();
2730
+ }, heartbeatMs);
2731
+ };
2732
+ try {
2733
+ scheduleHeartbeat();
2734
+ let startResult;
2735
+ try {
2736
+ startResult = await startStreamedWithTracking(thread, prompt, attemptAbort.signal, trackedPids);
2737
+ } catch (err) {
2738
+ if (err instanceof Error && err.name === "AbortError")
2739
+ throw err;
2740
+ if (!currentSessionId || !isMissingCodexRolloutError(err))
2741
+ throw err;
2742
+ logger.warn({ staleSessionId: currentSessionId, err: errMsg(err) }, "codexProvider: stale/missing rollout, restarting fresh thread");
2743
+ thread = codex.startThread(threadOptions);
2744
+ prompt = promptForThread(opts, true);
2745
+ currentSessionId = undefined;
2746
+ startResult = await startStreamedWithTracking(thread, prompt, attemptAbort.signal, trackedPids);
2747
+ }
2748
+ if (attemptAbort.signal.aborted) {
2749
+ killCodexTrees(trackedPids.pids);
2750
+ await closeIterator(startResult.iter);
2751
+ throw Object.assign(new Error("heartbeat abort"), { name: "AbortError" });
2752
+ }
2753
+ const eventStream = prependFirstEvent(startResult.iter, startResult.firstEvent, startResult.done);
2754
+ for await (const rawEvent of eventStream) {
2755
+ scheduleHeartbeat();
2756
+ const event = rawEvent;
2757
+ switch (event.type) {
2758
+ case "thread.started": {
2759
+ if (event.thread_id) {
2760
+ currentSessionId = event.thread_id;
2761
+ yield { type: "session", sessionId: event.thread_id };
2762
+ }
2763
+ break;
2764
+ }
2765
+ case "item.started": {
2766
+ const item = event.item;
2767
+ if (!item)
2768
+ break;
2769
+ if (item.type === "command_execution") {
2770
+ yield {
2771
+ type: "tool_use",
2772
+ name: "Bash",
2773
+ input: { command: String(item.command ?? "") },
2774
+ toolUseId: String(item.id ?? "")
2775
+ };
2776
+ } else if (item.type === "mcp_tool_call") {
2777
+ yield {
2778
+ type: "tool_use",
2779
+ name: String(item.tool ?? "unknown"),
2780
+ input: item.arguments && typeof item.arguments === "object" ? item.arguments : {},
2781
+ toolUseId: String(item.id ?? "")
2782
+ };
2783
+ }
2784
+ break;
2785
+ }
2786
+ case "item.updated": {
2787
+ const item = event.item;
2788
+ if (!item)
2789
+ break;
2790
+ if (item.type === "agent_message") {
2791
+ const messageId = item.id != null ? String(item.id) : undefined;
2792
+ if (messageId !== currentAgentMessageId) {
2793
+ currentAgentMessageId = messageId;
2794
+ agentTextSoFar = "";
2795
+ }
2796
+ const text = String(item.text ?? "");
2797
+ const newChars = text.slice(agentTextSoFar.length);
2798
+ if (newChars) {
2799
+ yield { type: "text_delta", content: newChars };
2800
+ agentTextSoFar = text;
2801
+ }
2802
+ }
2803
+ break;
2804
+ }
2805
+ case "item.completed": {
2806
+ const item = event.item;
2807
+ if (!item)
2808
+ break;
2809
+ if (item.type === "agent_message") {
2810
+ finalText = String(item.text ?? "");
2811
+ agentTextSoFar = finalText;
2812
+ yield { type: "text", content: finalText };
2813
+ yield* extractFileEvents(finalText, "text");
2814
+ } else if (item.type === "reasoning") {
2815
+ const reasoning = String(item.text ?? "").trim();
2816
+ if (reasoning)
2817
+ yield { type: "reasoning", content: reasoning };
2818
+ } else if (item.type === "mcp_tool_call") {
2819
+ yield {
2820
+ type: "tool_result",
2821
+ toolUseId: String(item.id ?? ""),
2822
+ content: summarizeMcpToolCallResult(item)
2823
+ };
2824
+ } else if (item.type === "command_execution") {
2825
+ yield {
2826
+ type: "tool_result",
2827
+ toolUseId: String(item.id ?? ""),
2828
+ content: String(item.aggregated_output ?? "").slice(0, 200)
2829
+ };
2830
+ } else if (item.type === "file_change") {
2831
+ for (const fileEvent of fileChangeEvents(item)) {
2832
+ yield fileEvent;
2833
+ }
2834
+ } else if (item.type === "error") {
2835
+ yield { type: "error", content: String(item.message ?? "") };
2836
+ }
2837
+ break;
2838
+ }
2839
+ case "turn.completed": {
2840
+ const usage = event.usage;
2841
+ if (!usage)
2842
+ break;
2843
+ attemptCompleted = true;
2844
+ const contextUsage = currentSessionId ? readLatestCodexContextUsage(currentSessionId) : undefined;
2845
+ yield {
2846
+ type: "result",
2847
+ content: finalText,
2848
+ stopReason,
2849
+ usage: {
2850
+ inputTokens: usage.input_tokens,
2851
+ outputTokens: usage.output_tokens,
2852
+ cacheReadInputTokens: usage.cached_input_tokens,
2853
+ ...contextUsage
2854
+ }
2855
+ };
2856
+ if (finalText)
2857
+ yield* extractFileEvents(finalText, "result");
2858
+ break;
2859
+ }
2860
+ case "turn.failed": {
2861
+ stopReason = "error";
2862
+ yield {
2863
+ type: "error",
2864
+ content: event.error?.message || "Codex turn failed"
2865
+ };
2866
+ break;
2867
+ }
2868
+ default:
2869
+ break;
2870
+ }
2871
+ }
2872
+ } catch (err) {
2873
+ if (abortSignal?.aborted)
2874
+ return;
2875
+ if (err instanceof Error && err.name === "AbortError") {
2876
+ if (!heartbeatTriggered)
2877
+ return;
2878
+ } else {
2879
+ logger.error({ err }, "codexProvider: attempt failed");
2880
+ yield { type: "error", content: errMsg(err) };
2881
+ break;
2882
+ }
2883
+ } finally {
2884
+ if (heartbeatTimer !== null)
2885
+ clearTimeout(heartbeatTimer);
2886
+ abortSignal?.removeEventListener("abort", propagateOuter);
2887
+ if (trackedPids.pids.length > 0)
2888
+ unregisterOwnedCodexPids(trackedPids.pids);
2889
+ }
2890
+ if (attemptCompleted || abortSignal?.aborted)
2891
+ break;
2892
+ if (!heartbeatTriggered)
2893
+ break;
2894
+ heartbeatAttempts++;
2895
+ if (heartbeatAttempts > HEARTBEAT_MAX_ATTEMPTS) {
2896
+ logger.warn({ attempts: heartbeatAttempts }, "codexProvider: max heartbeat attempts reached");
2897
+ yield {
2898
+ type: "error",
2899
+ content: `Codex\uAC00 ${HEARTBEAT_MAX_ATTEMPTS}\uD68C \uC7AC\uC2DC\uB3C4 \uD6C4\uC5D0\uB3C4 \uC751\uB2F5\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`
2900
+ };
2901
+ break;
2902
+ }
2903
+ heartbeatMs = Math.min(heartbeatMs * 2, HEARTBEAT_MAX_MS);
2904
+ logger.info({ attempt: heartbeatAttempts, nextIntervalMs: heartbeatMs }, "codexProvider: heartbeat fired, resuming thread with continuation prompt");
2905
+ agentTextSoFar = "";
2906
+ finalText = "";
2907
+ thread = currentSessionId ? codex.resumeThread(currentSessionId, threadOptions) : codex.startThread(threadOptions);
2908
+ prompt = currentSessionId ? HEARTBEAT_CONTINUATION : promptForThread(opts, true);
2909
+ }
2910
+ } catch (err) {
2911
+ if (err instanceof Error && err.name === "AbortError")
2912
+ return;
2913
+ if (abortSignal?.aborted)
2914
+ return;
2915
+ logger.error({ err }, "codexProvider: setup failed");
2916
+ yield { type: "error", content: errMsg(err) };
2917
+ } finally {
2918
+ abortSignal?.removeEventListener("abort", onAbortKill);
2919
+ if (trackedPids.pids.length > 0)
2920
+ unregisterOwnedCodexPids(trackedPids.pids);
2921
+ }
2922
+ }
2923
+
2924
+ // ../../packages/core/src/platform/maestro-bootstrap-env.ts
2925
+ process.env.MAESTRO_SDK_SILENT_BOOTSTRAP ??= "1";
2926
+
2927
+ // ../../packages/core/src/agents/maestro-provider.ts
2928
+ import { maestroProvider as sdkMaestroProvider, setMcpResolver } from "maestro-agent-sdk";
2929
+ var MAESTRO_DEFAULT_MAX_TOKENS = 32768;
2930
+ var PROVIDER_ASK_USER_TOOL = "AskUserQuestion";
2931
+ var PROVIDER_SUBAGENT_TOOL = "Agent";
2932
+ var MAESTRO_NATIVE_TASK_TOOLS = [
2933
+ "TaskCreate",
2934
+ "TaskUpdate",
2935
+ "TaskList",
2936
+ "TaskGet",
2937
+ "TaskOutput",
2938
+ "TaskStop"
2939
+ ];
2940
+ var MAESTRO_PROVIDER_OWNED_TOOL_SET = new Set([
2941
+ PROVIDER_ASK_USER_TOOL,
2942
+ PROVIDER_SUBAGENT_TOOL,
2943
+ ...MAESTRO_NATIVE_TASK_TOOLS
2944
+ ]);
2945
+ var DEFAULT_MAESTRO_DISALLOWED_TOOLS = [
2946
+ PROVIDER_ASK_USER_TOOL,
2947
+ PROVIDER_SUBAGENT_TOOL,
2948
+ ...MAESTRO_NATIVE_TASK_TOOLS
2949
+ ];
2950
+ function buildMaestroDisallowedTools(callerDisallowedTools = []) {
2951
+ return [...new Set([...DEFAULT_MAESTRO_DISALLOWED_TOOLS, ...callerDisallowedTools])];
2952
+ }
2953
+ function buildVaultHook(userId) {
2954
+ return {
2955
+ name: "vault-guard",
2956
+ pre({ toolName, input }) {
2957
+ if (referencesHostedSecretStorage(input)) {
2958
+ return { decision: "block", error: "Runtime secret storage access is not permitted" };
2959
+ }
2960
+ if (shouldRedirectHostedVaultTool(userId, toolName, input)) {
2961
+ return { decision: "block", error: VAULT_BROKER_REDIRECT_ERROR };
2962
+ }
2963
+ return { decision: "allow" };
2964
+ },
2965
+ post({ output }) {
2966
+ const redacted = redactHostedSecrets(userId, output);
2967
+ return redacted === output ? {} : { output: redacted };
2968
+ }
2969
+ };
2970
+ }
2971
+ function buildMaestroToolHooks(userId) {
2972
+ return [buildVaultHook(userId), buildProviderOwnedToolBlockHook()];
2973
+ }
2974
+ function providerOwnedToolRedirect(toolName) {
2975
+ if (toolName === PROVIDER_ASK_USER_TOOL) {
2976
+ return "Use the runtime ask_user_question MCP tool instead.";
2977
+ }
2978
+ if (toolName === PROVIDER_SUBAGENT_TOOL) {
2979
+ return "Use the runtime spawn_subagent MCP tool instead.";
2980
+ }
2981
+ return "Use the shared task MCP tools instead " + "(mcp__task__task_create / task_update / task_list / task_get / task_delete).";
2982
+ }
2983
+ function buildProviderOwnedToolBlockHook() {
2984
+ return {
2985
+ name: "provider-owned-tool-redirect",
2986
+ pre({ toolName }) {
2987
+ if (!MAESTRO_PROVIDER_OWNED_TOOL_SET.has(toolName))
2988
+ return { decision: "allow" };
2989
+ return {
2990
+ decision: "block",
2991
+ error: `${toolName} is disabled in this environment. ${providerOwnedToolRedirect(toolName)}`
2992
+ };
2993
+ }
2994
+ };
2995
+ }
2996
+ function maestroProvider(opts) {
2997
+ if (opts.agent !== undefined && opts.agent !== "maestro") {
2998
+ throw new Error(`maestroProvider: unexpected agent "${opts.agent}", expected "maestro"`);
2999
+ }
3000
+ const userId = opts.userId ?? "";
3001
+ setMcpResolver(hostedMcpServers);
3002
+ const callerDisallowedTools = opts.disallowedTools ?? [];
3003
+ const callerToolHooks = opts.toolHooks ?? [];
3004
+ const sdkOpts = {
3005
+ enableBackgroundBash: false,
3006
+ maxTokens: MAESTRO_DEFAULT_MAX_TOKENS,
3007
+ enableToolSearch: true,
3008
+ ...opts,
3009
+ agent: "maestro",
3010
+ disallowedTools: buildMaestroDisallowedTools(callerDisallowedTools),
3011
+ toolHooks: [...buildMaestroToolHooks(userId), ...callerToolHooks]
3012
+ };
3013
+ return sdkMaestroProvider(sdkOpts);
3014
+ }
20
3015
 
21
3016
  // ../../packages/core/src/agents/hosted-agent.ts
22
3017
  async function* runHostedAgent(input, host) {
@@ -61,4 +3056,4 @@ export {
61
3056
  configureAgentExecutionHost
62
3057
  };
63
3058
 
64
- //# debugId=D187F007DFA0700264756E2164756E21
3059
+ //# debugId=F7C9A771B460541764756E2164756E21