@vtxmacro/cli 2026.9.59 → 2026.9.61

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.
@@ -0,0 +1,3125 @@
1
+ #!/usr/bin/env node
2
+
3
+ // lib/inference-host/managed-codex-wrapper.ts
4
+ import { spawn as spawn3 } from "node:child_process";
5
+ import { createInterface as createInterface2 } from "node:readline";
6
+ import { isAbsolute as isAbsolute3 } from "node:path";
7
+
8
+ // lib/inference-host/codex-app-server.ts
9
+ import { spawn as spawn2 } from "node:child_process";
10
+ import { chmod, lstat as lstat2, open as open2, readFile as readFile2, rename as rename2, rm as rm2, writeFile } from "node:fs/promises";
11
+ import { tmpdir } from "node:os";
12
+ import { dirname as dirname2, isAbsolute as isAbsolute2, join as join2, resolve as resolve2, sep } from "node:path";
13
+ import { createInterface } from "node:readline";
14
+
15
+ // lib/inference-host/config.ts
16
+ import { spawn } from "node:child_process";
17
+ import { lstat, mkdir, open, readFile, realpath, rename, rm } from "node:fs/promises";
18
+ import { dirname, isAbsolute, join, relative, resolve, win32 as windowsPath } from "node:path";
19
+ var MAX_INFERENCE_PRIVATE_FILE_BYTES = 16 * 1024 * 1024;
20
+ var WINDOWS_PRIVATE_ACL_BROKER_SCRIPT = `$ErrorActionPreference='Stop'
21
+ $ProgressPreference='SilentlyContinue'
22
+ while(($line=[Console]::In.ReadLine()) -ne $null) {
23
+ $requestId=$null
24
+ $failureStage='request_validation'
25
+ try {
26
+ if($line.Length -lt 2 -or $line.Length -gt 65536) { throw 'invalid request size' }
27
+ $request=$line | ConvertFrom-Json
28
+ $names=@($request.PSObject.Properties.Name | Sort-Object)
29
+ if(($names -join ',') -ne 'id,kind,mode,path_b64') { throw 'invalid request shape' }
30
+ if($request.id -isnot [long] -and $request.id -isnot [int]) { throw 'invalid request id' }
31
+ $requestId=[long]$request.id
32
+ if($requestId -lt 1) { throw 'invalid request id' }
33
+ $kind=[string]$request.kind
34
+ $mode=[string]$request.mode
35
+ if($kind -ne 'directory' -and $kind -ne 'file') { throw 'invalid path kind' }
36
+ if($mode -ne 'harden' -and $mode -ne 'verify' -and $mode -ne 'verify-owner') { throw 'invalid ACL mode' }
37
+ $path=[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String([string]$request.path_b64))
38
+ if([string]::IsNullOrWhiteSpace($path) -or $path.Length -gt 32767 -or $path.Contains([char]0)) { throw 'invalid path' }
39
+ $failureStage='path_lookup'
40
+ if(-not (Test-Path -LiteralPath $path)) {
41
+ [Console]::Out.WriteLine((@{id=$requestId;status='missing'} | ConvertTo-Json -Compress))
42
+ continue
43
+ }
44
+ $failureStage='principal_resolution'
45
+ $currentIdentity=[Security.Principal.WindowsIdentity]::GetCurrent()
46
+ $current=$currentIdentity.User
47
+ $system=New-Object Security.Principal.SecurityIdentifier('S-1-5-18')
48
+ $admins=New-Object Security.Principal.SecurityIdentifier('S-1-5-32-544')
49
+ $currentIsAdmin=(New-Object Security.Principal.WindowsPrincipal($currentIdentity)).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
50
+ $allowed=@($current.Value,$system.Value,$admins.Value)
51
+ if($mode -eq 'harden') {
52
+ $failureStage='acl_read'
53
+ $acl=Get-Acl -LiteralPath $path
54
+ $originalAccess=$acl.GetSecurityDescriptorSddlForm([Security.AccessControl.AccessControlSections]::Access)
55
+ $failureStage='owner_validation'
56
+ $existingOwner=(New-Object Security.Principal.NTAccount($acl.Owner)).Translate([Security.Principal.SecurityIdentifier]).Value
57
+ if($existingOwner -ne $current.Value -and ($existingOwner -ne $admins.Value -or -not $currentIsAdmin)) { throw 'private ACL owner is invalid' }
58
+ $failureStage='acl_mutation'
59
+ $acl.SetAccessRuleProtection($true,$false)
60
+ foreach($existingRule in @($acl.Access)) { [void]$acl.RemoveAccessRuleSpecific($existingRule) }
61
+ $inherit=if($kind -eq 'directory') {
62
+ [Security.AccessControl.InheritanceFlags]'ContainerInherit,ObjectInherit'
63
+ } else { [Security.AccessControl.InheritanceFlags]::None }
64
+ foreach($sid in @($current,$system,$admins)) {
65
+ $rule=New-Object Security.AccessControl.FileSystemAccessRule(
66
+ $sid,
67
+ [Security.AccessControl.FileSystemRights]::FullControl,
68
+ $inherit,
69
+ [Security.AccessControl.PropagationFlags]::None,
70
+ [Security.AccessControl.AccessControlType]::Allow
71
+ )
72
+ [void]$acl.AddAccessRule($rule)
73
+ }
74
+ $failureStage='acl_write'
75
+ if($originalAccess -ne $acl.GetSecurityDescriptorSddlForm([Security.AccessControl.AccessControlSections]::Access)) {
76
+ (Get-Item -LiteralPath $path).SetAccessControl($acl)
77
+ }
78
+ }
79
+ $failureStage='acl_readback'
80
+ $actual=Get-Acl -LiteralPath $path
81
+ $failureStage='acl_verification'
82
+ $owner=(New-Object Security.Principal.NTAccount($actual.Owner)).Translate([Security.Principal.SecurityIdentifier]).Value
83
+ if($owner -ne $current.Value -and ($owner -ne $admins.Value -or -not $currentIsAdmin)) { throw 'private ACL owner is invalid' }
84
+ if($mode -ne 'verify-owner') {
85
+ if(-not $actual.AreAccessRulesProtected) { throw 'private ACL inheritance is invalid' }
86
+ $userFull=$false
87
+ foreach($rule in $actual.Access) {
88
+ $sid=$rule.IdentityReference.Translate([Security.Principal.SecurityIdentifier]).Value
89
+ if($rule.IsInherited -or $allowed -notcontains $sid -or $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow) {
90
+ throw 'private ACL contains an unauthorized access rule'
91
+ }
92
+ if($sid -eq $current.Value -and (($rule.FileSystemRights -band [Security.AccessControl.FileSystemRights]::FullControl) -eq [Security.AccessControl.FileSystemRights]::FullControl)) { $userFull=$true }
93
+ }
94
+ if(-not $userFull) { throw 'private ACL does not grant the current user full control' }
95
+ }
96
+ [Console]::Out.WriteLine((@{id=$requestId;status='ok'} | ConvertTo-Json -Compress))
97
+ } catch {
98
+ [Console]::Out.WriteLine((@{id=$requestId;status='error';error_code=$failureStage} | ConvertTo-Json -Compress))
99
+ }
100
+ }`;
101
+ var WINDOWS_IDENTITY_COMMAND_TIMEOUT_MS = 15e3;
102
+ var WINDOWS_PRIVATE_ACL_BROKER_STARTUP_TIMEOUT_MS = 9e4;
103
+ var SMALL_IDENTITY_COMMAND_TIMEOUT_MS = 5e3;
104
+ var windowsPowerShellEnvironment = (extra = {}) => {
105
+ const sanitizedExtra = { ...extra };
106
+ delete sanitizedExtra.PSModulePath;
107
+ const windowsRoot = process.env.SystemRoot ?? process.env.WINDIR;
108
+ return {
109
+ ...sanitizedExtra,
110
+ NODE_ENV: process.env.NODE_ENV,
111
+ SystemRoot: process.env.SystemRoot,
112
+ WINDIR: process.env.WINDIR,
113
+ ComSpec: process.env.ComSpec,
114
+ PATHEXT: process.env.PATHEXT,
115
+ PSModulePath: windowsRoot ? windowsPath.join(windowsRoot, "System32", "WindowsPowerShell", "v1.0", "Modules") : void 0,
116
+ TEMP: process.env.TEMP,
117
+ TMP: process.env.TMP
118
+ };
119
+ };
120
+ var windowsPrivateAclBrokerInvocation = () => ({
121
+ args: [
122
+ "-NoLogo",
123
+ "-NoProfile",
124
+ "-NonInteractive",
125
+ "-EncodedCommand",
126
+ Buffer.from(WINDOWS_PRIVATE_ACL_BROKER_SCRIPT, "utf16le").toString("base64")
127
+ ],
128
+ env: windowsPowerShellEnvironment()
129
+ });
130
+ var WindowsPrivateAclBroker = class {
131
+ constructor(dependencies = {}) {
132
+ this.child = null;
133
+ this.requestSequence = 0;
134
+ this.queue = Promise.resolve();
135
+ this.pending = null;
136
+ this.outputBuffer = "";
137
+ this.idleTimer = null;
138
+ this.run = async (path, kind, mode) => {
139
+ const operation = this.queue.then(
140
+ () => this.dispatch(path, kind, mode),
141
+ () => this.dispatch(path, kind, mode)
142
+ );
143
+ this.queue = operation.then(() => void 0, () => void 0);
144
+ await operation;
145
+ };
146
+ this.requestTimeoutMs = dependencies.requestTimeoutMs ?? 15e3;
147
+ this.startupRequestTimeoutMs = dependencies.startupRequestTimeoutMs ?? WINDOWS_PRIVATE_ACL_BROKER_STARTUP_TIMEOUT_MS;
148
+ this.idleShutdownMs = dependencies.idleShutdownMs ?? 3e4;
149
+ this.spawnProcess = dependencies.spawnProcess ?? (() => {
150
+ const invocation = windowsPrivateAclBrokerInvocation();
151
+ return spawn("powershell.exe", [...invocation.args], {
152
+ env: invocation.env,
153
+ windowsHide: true,
154
+ stdio: ["pipe", "pipe", "pipe"]
155
+ });
156
+ });
157
+ }
158
+ scheduleIdleShutdown() {
159
+ if (this.idleTimer) clearTimeout(this.idleTimer);
160
+ this.idleTimer = setTimeout(() => {
161
+ this.idleTimer = null;
162
+ const child = this.child;
163
+ if (!child || this.pending) return;
164
+ this.child = null;
165
+ this.outputBuffer = "";
166
+ child.stdin.end();
167
+ const force = setTimeout(() => child.kill("SIGKILL"), 1e3);
168
+ force.unref();
169
+ child.once("exit", () => clearTimeout(force));
170
+ }, this.idleShutdownMs);
171
+ this.idleTimer.unref();
172
+ }
173
+ failChild(child, error) {
174
+ if (this.child !== child) return;
175
+ this.child = null;
176
+ this.outputBuffer = "";
177
+ if (this.idleTimer) {
178
+ clearTimeout(this.idleTimer);
179
+ this.idleTimer = null;
180
+ }
181
+ const pending = this.pending;
182
+ this.pending = null;
183
+ if (pending) {
184
+ clearTimeout(pending.timer);
185
+ pending.reject(error);
186
+ }
187
+ child.kill("SIGKILL");
188
+ }
189
+ acceptLine(child, line) {
190
+ const pending = this.pending;
191
+ if (!pending || !line || line.length > 4096) {
192
+ this.failChild(child, new Error("Windows private ACL broker returned malformed output."));
193
+ return;
194
+ }
195
+ let response;
196
+ try {
197
+ const parsed = JSON.parse(line);
198
+ const status = String(parsed.status);
199
+ const expectedKeys = status === "error" ? "error_code\0id\0status" : "id\0status";
200
+ if (Object.keys(parsed).sort().join("\0") !== expectedKeys || parsed.id !== pending.id || !["ok", "missing", "error"].includes(status) || status === "error" && ![
201
+ "request_validation",
202
+ "path_lookup",
203
+ "principal_resolution",
204
+ "acl_read",
205
+ "owner_validation",
206
+ "acl_mutation",
207
+ "acl_write",
208
+ "acl_readback",
209
+ "acl_verification"
210
+ ].includes(String(parsed.error_code))) throw new Error("invalid response");
211
+ response = parsed;
212
+ } catch {
213
+ this.failChild(child, new Error("Windows private ACL broker returned malformed output."));
214
+ return;
215
+ }
216
+ this.pending = null;
217
+ clearTimeout(pending.timer);
218
+ if (response.status === "ok") {
219
+ pending.resolve();
220
+ } else if (response.status === "missing") {
221
+ const error = new Error("Windows private path no longer exists.");
222
+ error.code = "ENOENT";
223
+ pending.reject(error);
224
+ } else {
225
+ pending.reject(new Error(
226
+ `Windows private ACL ${pending.mode} failed (${response.error_code}).`
227
+ ));
228
+ }
229
+ this.scheduleIdleShutdown();
230
+ }
231
+ ensureChild() {
232
+ if (this.child && this.child.exitCode === null && !this.child.killed) {
233
+ return { child: this.child, startedNow: false };
234
+ }
235
+ const child = this.spawnProcess();
236
+ this.child = child;
237
+ this.outputBuffer = "";
238
+ child.stdout.setEncoding("utf8");
239
+ child.stdout.on("data", (chunk) => {
240
+ if (this.child !== child) return;
241
+ this.outputBuffer += chunk;
242
+ if (this.outputBuffer.length > 65536) {
243
+ this.failChild(child, new Error("Windows private ACL broker exceeded its output limit."));
244
+ return;
245
+ }
246
+ while (this.child === child) {
247
+ const newline = this.outputBuffer.indexOf("\n");
248
+ if (newline < 0) break;
249
+ const line = this.outputBuffer.slice(0, newline).trim();
250
+ this.outputBuffer = this.outputBuffer.slice(newline + 1);
251
+ this.acceptLine(child, line);
252
+ }
253
+ });
254
+ child.stderr.on("data", () => void 0);
255
+ child.once("error", () => {
256
+ this.failChild(child, new Error("Windows private ACL broker failed to start."));
257
+ });
258
+ child.once("exit", () => {
259
+ this.failChild(child, new Error("Windows private ACL broker exited before confirmation."));
260
+ });
261
+ child.unref();
262
+ for (const stream of [child.stdin, child.stdout, child.stderr]) {
263
+ stream.unref?.();
264
+ }
265
+ return { child, startedNow: true };
266
+ }
267
+ async dispatch(path, kind, mode) {
268
+ if (this.idleTimer) {
269
+ clearTimeout(this.idleTimer);
270
+ this.idleTimer = null;
271
+ }
272
+ const id = ++this.requestSequence;
273
+ const request = `${JSON.stringify({
274
+ id,
275
+ kind,
276
+ mode,
277
+ path_b64: Buffer.from(path, "utf8").toString("base64")
278
+ })}
279
+ `;
280
+ if (Buffer.byteLength(request, "utf8") > 65536) {
281
+ throw new Error("Windows private ACL broker request exceeds its input limit.");
282
+ }
283
+ const { child, startedNow } = this.ensureChild();
284
+ const timeoutMs = startedNow ? this.startupRequestTimeoutMs : this.requestTimeoutMs;
285
+ await new Promise((resolvePromise, reject) => {
286
+ const timer = setTimeout(() => {
287
+ this.failChild(child, new Error("Windows private ACL broker request timed out."));
288
+ }, timeoutMs);
289
+ this.pending = { id, mode, resolve: resolvePromise, reject, timer };
290
+ child.stdin.write(request, "utf8", (error) => {
291
+ if (error) {
292
+ this.failChild(child, new Error("Windows private ACL broker request failed."));
293
+ }
294
+ });
295
+ });
296
+ }
297
+ close() {
298
+ if (this.idleTimer) clearTimeout(this.idleTimer);
299
+ this.idleTimer = null;
300
+ const child = this.child;
301
+ this.child = null;
302
+ this.outputBuffer = "";
303
+ if (child) child.stdin.end();
304
+ }
305
+ };
306
+ var defaultWindowsPrivateAclBroker = new WindowsPrivateAclBroker();
307
+ var windowsBootIdentityInvocation = () => {
308
+ const script = `$ErrorActionPreference='Stop';$s=[System.Management.ManagementObjectSearcher]::new('SELECT LastBootUpTime FROM Win32_OperatingSystem');try{$c=$s.Get();$e=$c.GetEnumerator();if(-not $e.MoveNext()){throw 'boot identity unavailable'};$raw=[string]$e.Current['LastBootUpTime'];$v=[System.Management.ManagementDateTimeConverter]::ToDateTime($raw).ToUniversalTime().ToFileTimeUtc();[Console]::Out.Write($v)}finally{if($c){$c.Dispose()};$s.Dispose()}`;
309
+ return {
310
+ args: [
311
+ "-NoLogo",
312
+ "-NoProfile",
313
+ "-NonInteractive",
314
+ "-EncodedCommand",
315
+ Buffer.from(script, "utf16le").toString("base64")
316
+ ],
317
+ env: windowsPowerShellEnvironment(),
318
+ timeoutMs: WINDOWS_IDENTITY_COMMAND_TIMEOUT_MS
319
+ };
320
+ };
321
+ var runSmallIdentityCommand = async (command, args, env, timeoutMs = SMALL_IDENTITY_COMMAND_TIMEOUT_MS) => await new Promise((resolvePromise) => {
322
+ const child = spawn(command, [...args], {
323
+ windowsHide: true,
324
+ stdio: ["ignore", "pipe", "ignore"],
325
+ env
326
+ });
327
+ const output = [];
328
+ let bytes = 0;
329
+ let settled = false;
330
+ const settle = (value) => {
331
+ if (settled) return;
332
+ settled = true;
333
+ clearTimeout(timer);
334
+ resolvePromise(value);
335
+ };
336
+ const timer = setTimeout(() => {
337
+ child.kill("SIGKILL");
338
+ settle(null);
339
+ }, timeoutMs);
340
+ child.stdout.on("data", (chunk) => {
341
+ bytes += Buffer.byteLength(chunk);
342
+ if (bytes > 4096) {
343
+ child.kill("SIGKILL");
344
+ settle(null);
345
+ return;
346
+ }
347
+ output.push(Buffer.from(chunk));
348
+ });
349
+ child.once("error", () => settle(null));
350
+ child.once("exit", (code) => settle(
351
+ code === 0 ? Buffer.concat(output).toString("utf8").trim() || null : null
352
+ ));
353
+ });
354
+ var cachedSystemBootIdentity = null;
355
+ var readInferenceSystemBootIdentity = async (platform = process.platform) => {
356
+ if (platform === process.platform && cachedSystemBootIdentity) {
357
+ return await cachedSystemBootIdentity;
358
+ }
359
+ const read = async () => {
360
+ let identity = null;
361
+ if (platform === "linux") {
362
+ try {
363
+ identity = (await readFile("/proc/sys/kernel/random/boot_id", "utf8")).trim();
364
+ } catch {
365
+ identity = null;
366
+ }
367
+ } else if (platform === "win32") {
368
+ const invocation = windowsBootIdentityInvocation();
369
+ identity = await runSmallIdentityCommand(
370
+ "powershell.exe",
371
+ invocation.args,
372
+ invocation.env,
373
+ invocation.timeoutMs
374
+ );
375
+ } else if (platform === "darwin") {
376
+ identity = await runSmallIdentityCommand("sysctl", ["-n", "kern.boottime"], void 0);
377
+ }
378
+ if (!identity || /[\r\n\0]/u.test(identity)) {
379
+ throw new Error("Inference host could not establish the current system boot identity.");
380
+ }
381
+ return `${platform}:${identity}`;
382
+ };
383
+ const pending = read();
384
+ if (platform === process.platform) cachedSystemBootIdentity = pending;
385
+ try {
386
+ return await pending;
387
+ } catch (error) {
388
+ if (platform === process.platform) cachedSystemBootIdentity = null;
389
+ throw error;
390
+ }
391
+ };
392
+
393
+ // lib/inference-host/codex-app-server.ts
394
+ var CODEX_INFERENCE_PERMISSION_PROFILE = "vtx_inference_readonly";
395
+ var CODEX_AGENT_PERMISSION_PROFILE = "vtx_inference_agent";
396
+ var CODEX_REASONING_CONTENT_MAX_UTF8_BYTES = 32768;
397
+ var CODEX_ACCOUNT_PLAN_TYPES = [
398
+ "free",
399
+ "go",
400
+ "plus",
401
+ "pro",
402
+ "prolite",
403
+ "team",
404
+ "self_serve_business_prolite",
405
+ "self_serve_business_usage_based",
406
+ "business",
407
+ "ent26",
408
+ "enterprise_cbp_automation",
409
+ "enterprise_cbp_usage_based",
410
+ "enterprise",
411
+ "edu",
412
+ "unknown"
413
+ ];
414
+ var CODEX_AGENT_DYNAMIC_TOOLS = [
415
+ "vtx_set_schedule",
416
+ "vtx_get_data",
417
+ "vtx_submit_decision",
418
+ "vtx_decision_status"
419
+ ];
420
+ var CodexAppServerError = class extends Error {
421
+ constructor(options) {
422
+ super(options.message, { cause: options.cause });
423
+ this.name = "CodexAppServerError";
424
+ this.category = options.category;
425
+ this.code = options.code;
426
+ this.retryable = options.retryable;
427
+ this.dispatchOutcome = options.dispatchOutcome ?? "not_dispatched";
428
+ this.httpStatusCode = options.httpStatusCode ?? null;
429
+ this.retryAtMs = options.retryAtMs ?? null;
430
+ this.usage = options.usage ?? null;
431
+ this.terminalEvidence = options.terminalEvidence ?? null;
432
+ this.rateLimits = options.rateLimits ?? null;
433
+ this.processExit = options.processExit ?? null;
434
+ this.grokToolValidation = options.grokToolValidation ?? null;
435
+ this.grokResponseIdentity = options.grokResponseIdentity ?? null;
436
+ }
437
+ };
438
+ var objectOrNull = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
439
+ var finiteToken = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
440
+ var tokenUsageFromBreakdown = (value) => {
441
+ const candidate = objectOrNull(value);
442
+ if (!candidate) return null;
443
+ const inputTokens = finiteToken(candidate.inputTokens ?? candidate.input_tokens);
444
+ const cachedInputTokens = finiteToken(
445
+ candidate.cachedInputTokens ?? candidate.cached_input_tokens ?? objectOrNull(candidate.input_tokens_details)?.cached_tokens
446
+ );
447
+ const outputTokens = finiteToken(candidate.outputTokens ?? candidate.output_tokens);
448
+ const reasoningOutputTokens = finiteToken(
449
+ candidate.reasoningOutputTokens ?? candidate.reasoning_output_tokens ?? objectOrNull(candidate.output_tokens_details)?.reasoning_tokens
450
+ );
451
+ const totalTokens = finiteToken(candidate.totalTokens ?? candidate.total_tokens);
452
+ if (inputTokens === null || cachedInputTokens === null || outputTokens === null || reasoningOutputTokens === null || totalTokens === null || cachedInputTokens > inputTokens || reasoningOutputTokens > outputTokens || totalTokens !== inputTokens + outputTokens) return null;
453
+ const rawCacheWrite = candidate.cacheWriteInputTokens ?? candidate.cache_write_input_tokens;
454
+ const cacheWrite = rawCacheWrite === void 0 ? null : finiteToken(rawCacheWrite);
455
+ if (rawCacheWrite !== void 0 && cacheWrite === null) return null;
456
+ return {
457
+ inputTokens,
458
+ cachedInputTokens,
459
+ outputTokens,
460
+ reasoningOutputTokens,
461
+ totalTokens,
462
+ cacheWriteInputTokens: cacheWrite,
463
+ cacheWriteSupported: rawCacheWrite !== void 0
464
+ };
465
+ };
466
+ var usageFromNotification = (method, params) => {
467
+ if (method === "thread/tokenUsage/updated") {
468
+ const tokenUsage = objectOrNull(params.tokenUsage);
469
+ return tokenUsageFromBreakdown(tokenUsage?.last) ?? tokenUsageFromBreakdown(tokenUsage?.total);
470
+ }
471
+ if (method === "rawResponse/completed") {
472
+ return tokenUsageFromBreakdown(params.usage);
473
+ }
474
+ return null;
475
+ };
476
+ var validPlanType = (value) => typeof value === "string" && CODEX_ACCOUNT_PLAN_TYPES.includes(value);
477
+ var nonnegativeSafeIntegerOrNull = (value) => Number.isSafeInteger(value) && Number(value) >= 0 ? Number(value) : null;
478
+ var nonnegativeFiniteNumberOrNull = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
479
+ var parseRateLimitWindow = (value) => {
480
+ if (value === null) return null;
481
+ const candidate = objectOrNull(value);
482
+ if (!candidate) throw new Error("invalid rate-limit window");
483
+ const usedPercent = nonnegativeFiniteNumberOrNull(candidate.usedPercent);
484
+ const windowDurationMins = candidate.windowDurationMins == null ? null : nonnegativeSafeIntegerOrNull(candidate.windowDurationMins);
485
+ const resetsAt = candidate.resetsAt == null ? null : nonnegativeSafeIntegerOrNull(candidate.resetsAt);
486
+ if (usedPercent === null || windowDurationMins === null && candidate.windowDurationMins != null || resetsAt === null && candidate.resetsAt != null) {
487
+ throw new Error("invalid rate-limit window");
488
+ }
489
+ return { usedPercent, windowDurationMins, resetsAt };
490
+ };
491
+ var RATE_LIMIT_REACHED_TYPES = [
492
+ "rate_limit_reached",
493
+ "workspace_owner_credits_depleted",
494
+ "workspace_member_credits_depleted",
495
+ "workspace_owner_usage_limit_reached",
496
+ "workspace_member_usage_limit_reached"
497
+ ];
498
+ var DEFAULT_CODEX_QUOTA_COOLDOWN_MS = 5 * 60 * 1e3;
499
+ var MAX_CODEX_QUOTA_COOLDOWN_MS = 8 * 24 * 60 * 60 * 1e3;
500
+ var CODEX_TRANSIENT_RATE_LIMIT_COOLDOWN_MS = 30 * 1e3;
501
+ var parseRateLimitSnapshot = (value) => {
502
+ const candidate = objectOrNull(value);
503
+ if (!candidate) throw new Error("invalid rate-limit snapshot");
504
+ const limitId = candidate.limitId === null || candidate.limitId === void 0 ? null : typeof candidate.limitId === "string" && candidate.limitId.trim() ? candidate.limitId.trim() : void 0;
505
+ const limitName = candidate.limitName === null || candidate.limitName === void 0 ? null : typeof candidate.limitName === "string" && candidate.limitName.trim() ? candidate.limitName.trim() : void 0;
506
+ const planType = candidate.planType === null || candidate.planType === void 0 ? null : validPlanType(candidate.planType) ? candidate.planType : void 0;
507
+ const reached = candidate.rateLimitReachedType === null || candidate.rateLimitReachedType === void 0 ? null : typeof candidate.rateLimitReachedType === "string" && RATE_LIMIT_REACHED_TYPES.includes(candidate.rateLimitReachedType) ? candidate.rateLimitReachedType : void 0;
508
+ const spendControlReached = candidate.spendControlReached === null || candidate.spendControlReached === void 0 ? null : typeof candidate.spendControlReached === "boolean" ? candidate.spendControlReached : void 0;
509
+ if (limitId === void 0 || limitName === void 0 || planType === void 0 || reached === void 0 || spendControlReached === void 0) throw new Error("invalid rate-limit snapshot");
510
+ return {
511
+ limitId,
512
+ limitName,
513
+ planType,
514
+ primary: parseRateLimitWindow(candidate.primary ?? null),
515
+ secondary: parseRateLimitWindow(candidate.secondary ?? null),
516
+ rateLimitReachedType: reached,
517
+ spendControlReached
518
+ };
519
+ };
520
+ var codexRateLimitRetryAtMs = (accountRateLimits) => {
521
+ const snapshots = [accountRateLimits.rateLimits];
522
+ const exhaustedResets = [];
523
+ const reachedResets = [];
524
+ for (const snapshot of snapshots) {
525
+ const windows = [snapshot.primary, snapshot.secondary].filter(
526
+ (window) => window !== null
527
+ );
528
+ for (const window of windows) {
529
+ if (window.resetsAt === null) continue;
530
+ const resetAtMs = window.resetsAt * 1e3;
531
+ if (!Number.isSafeInteger(resetAtMs)) continue;
532
+ if (window.usedPercent >= 100) exhaustedResets.push(resetAtMs);
533
+ if (snapshot.rateLimitReachedType !== null || snapshot.spendControlReached === true) {
534
+ reachedResets.push(resetAtMs);
535
+ }
536
+ }
537
+ }
538
+ const candidates = exhaustedResets.length > 0 ? exhaustedResets : reachedResets.length > 0 ? reachedResets : [];
539
+ return candidates.length > 0 ? Math.max(...candidates) : null;
540
+ };
541
+ var codexAccountRateLimitReached = (accountRateLimits) => [accountRateLimits.rateLimits].some((snapshot) => snapshot.rateLimitReachedType !== null || snapshot.spendControlReached === true || snapshot.primary?.usedPercent !== void 0 && snapshot.primary.usedPercent >= 100 || snapshot.secondary?.usedPercent !== void 0 && snapshot.secondary.usedPercent >= 100);
542
+ var forbiddenMethod = (method) => method.startsWith("mcpServer/") || method.startsWith("serverRequest/") || method.startsWith("item/mcpToolCall") || method.startsWith("item/commandExecution") || method.startsWith("item/fileChange") || method.startsWith("item/dynamicToolCall") || method.startsWith("item/collabAgentToolCall");
543
+ var forbiddenTerminalItem = (item) => ![
544
+ "userMessage",
545
+ "agentMessage",
546
+ "reasoning"
547
+ ].includes(String(item.type || ""));
548
+ var forbiddenAgentMethod = (method) => method.startsWith("mcpServer/") || method.startsWith("serverRequest/") || method.startsWith("item/mcpToolCall") || method.startsWith("item/commandExecution") || method.startsWith("item/fileChange") || method.startsWith("item/collabAgentToolCall");
549
+ var forbiddenAgentTerminalItem = (item) => ![
550
+ "userMessage",
551
+ "agentMessage",
552
+ "reasoning",
553
+ "dynamicToolCall",
554
+ "webSearch",
555
+ "contextCompaction"
556
+ ].includes(String(item.type || ""));
557
+ var createCodexAgentToolSpecs = (dataContract, decisionSchema) => {
558
+ if (dataContract.length === 0 || Object.keys(decisionSchema).length === 0) {
559
+ throw new CodexAppServerError({
560
+ message: "Codex Agent data contract is unavailable.",
561
+ category: "schema",
562
+ code: "invalid_agent_data_contract",
563
+ retryable: false
564
+ });
565
+ }
566
+ const dataRequestBranches = dataContract.map((descriptor) => ({
567
+ type: "object",
568
+ additionalProperties: false,
569
+ required: ["capability", "arguments"],
570
+ description: descriptor.description,
571
+ properties: {
572
+ capability: {
573
+ type: "string",
574
+ const: descriptor.id,
575
+ title: descriptor.title
576
+ },
577
+ arguments: descriptor.input_schema
578
+ }
579
+ }));
580
+ return [
581
+ {
582
+ type: "function",
583
+ name: "vtx_get_data",
584
+ description: "Request assignment-scoped VTX data using one exact canonical capability schema.",
585
+ inputSchema: {
586
+ oneOf: dataRequestBranches
587
+ }
588
+ },
589
+ {
590
+ type: "function",
591
+ name: "vtx_submit_decision",
592
+ description: "Submit one VTX structured trading decision candidate using the assignment decision schema.",
593
+ inputSchema: {
594
+ type: "object",
595
+ additionalProperties: false,
596
+ required: ["candidate"],
597
+ properties: { candidate: decisionSchema }
598
+ }
599
+ },
600
+ {
601
+ type: "function",
602
+ name: "vtx_decision_status",
603
+ description: "Resolve the durable status of a previously attempted decision operation.",
604
+ inputSchema: {
605
+ type: "object",
606
+ additionalProperties: false,
607
+ required: ["operation_id"],
608
+ properties: { operation_id: { type: "string", minLength: 1 } }
609
+ }
610
+ },
611
+ {
612
+ type: "function",
613
+ name: "vtx_set_schedule",
614
+ description: "Configure or cancel recurring market observations for this assignment. This never submits a trading decision.",
615
+ inputSchema: {
616
+ type: "object",
617
+ additionalProperties: false,
618
+ required: ["schedule"],
619
+ properties: { schedule: { anyOf: [{ type: "null" }, {
620
+ type: "object",
621
+ additionalProperties: false,
622
+ required: ["interval_seconds", "objective", "observation"],
623
+ properties: {
624
+ interval_seconds: { type: "integer", minimum: 1 },
625
+ objective: { type: "string", minLength: 1, maxLength: 4e3 },
626
+ observation: { type: "object", additionalProperties: false, required: ["capability", "arguments"], properties: {
627
+ capability: { const: "market.snapshot", type: "string" },
628
+ arguments: dataContract.find((descriptor) => descriptor.id === "market.snapshot")?.input_schema ?? { type: "object" }
629
+ } }
630
+ }
631
+ }] } }
632
+ }
633
+ }
634
+ ];
635
+ };
636
+ var classifyCodexTurnFailure = (codexErrorInfo, terminalStatus) => {
637
+ if (terminalStatus === "interrupted") {
638
+ return { code: "cancelled", category: "cancelled", retryable: false, httpStatusCode: null };
639
+ }
640
+ if (codexErrorInfo === "usageLimitExceeded") {
641
+ return { code: "quota_exceeded", category: "model", retryable: false, httpStatusCode: null };
642
+ }
643
+ if (codexErrorInfo === "unauthorized") {
644
+ return { code: "auth_expired", category: "auth", retryable: false, httpStatusCode: null };
645
+ }
646
+ const stableStringCodes = {
647
+ badRequest: "codex_bad_request",
648
+ contextWindowExceeded: "context_window_exceeded",
649
+ cyberPolicy: "codex_policy_rejected",
650
+ internalServerError: "codex_internal_error",
651
+ sandboxError: "codex_sandbox_error",
652
+ serverOverloaded: "codex_server_overloaded",
653
+ sessionBudgetExceeded: "session_budget_exceeded",
654
+ threadRollbackFailed: "codex_thread_rollback_failed"
655
+ };
656
+ if (typeof codexErrorInfo === "string" && stableStringCodes[codexErrorInfo]) {
657
+ const code = stableStringCodes[codexErrorInfo];
658
+ return {
659
+ code,
660
+ category: "adapter",
661
+ retryable: code === "codex_internal_error" || code === "codex_server_overloaded",
662
+ httpStatusCode: null
663
+ };
664
+ }
665
+ const structured = objectOrNull(codexErrorInfo);
666
+ if (structured) {
667
+ const variants = [
668
+ ["httpConnectionFailed", "codex_http_connection_failed"],
669
+ ["responseStreamConnectionFailed", "codex_response_stream_connection_failed"],
670
+ ["responseStreamDisconnected", "codex_response_stream_disconnected"],
671
+ ["responseTooManyFailedAttempts", "codex_provider_retry_exhausted"]
672
+ ];
673
+ for (const [variant, code] of variants) {
674
+ if (!(variant in structured)) continue;
675
+ const details = objectOrNull(structured[variant]);
676
+ const rawStatus = details?.httpStatusCode;
677
+ const httpStatusCode = Number.isSafeInteger(rawStatus) && Number(rawStatus) >= 100 && Number(rawStatus) <= 599 ? Number(rawStatus) : null;
678
+ if (httpStatusCode === 401) {
679
+ return {
680
+ code: "auth_expired",
681
+ category: "auth",
682
+ retryable: false,
683
+ httpStatusCode
684
+ };
685
+ }
686
+ if (httpStatusCode === 429) {
687
+ return {
688
+ code: "codex_rate_limited",
689
+ category: "adapter",
690
+ retryable: true,
691
+ httpStatusCode
692
+ };
693
+ }
694
+ if (httpStatusCode !== null && httpStatusCode >= 400 && httpStatusCode < 500 && httpStatusCode !== 408 && httpStatusCode !== 425) {
695
+ const semanticText = JSON.stringify(details || {}).toLowerCase();
696
+ if (httpStatusCode === 402 || /(quota|credit|spend|payment|subscription.*limit)/u.test(semanticText)) {
697
+ return {
698
+ code: "quota_exceeded",
699
+ category: "model",
700
+ retryable: false,
701
+ httpStatusCode
702
+ };
703
+ }
704
+ if (httpStatusCode === 403 && /(auth|account|workspace|billing|entitlement)/u.test(semanticText)) {
705
+ return {
706
+ code: "auth_expired",
707
+ category: "auth",
708
+ retryable: false,
709
+ httpStatusCode
710
+ };
711
+ }
712
+ if (httpStatusCode === 403 && /(policy|safety|cyber)/u.test(semanticText)) {
713
+ return {
714
+ code: "codex_policy_rejected",
715
+ category: "adapter",
716
+ retryable: false,
717
+ httpStatusCode
718
+ };
719
+ }
720
+ return {
721
+ code: httpStatusCode === 400 ? "codex_bad_request" : "codex_http_client_error",
722
+ category: "adapter",
723
+ retryable: false,
724
+ httpStatusCode
725
+ };
726
+ }
727
+ return {
728
+ code,
729
+ category: "adapter",
730
+ retryable: httpStatusCode === null ? true : httpStatusCode === 408 || httpStatusCode === 425 || httpStatusCode >= 500,
731
+ httpStatusCode
732
+ };
733
+ }
734
+ }
735
+ return { code: "turn_failed", category: "adapter", retryable: false, httpStatusCode: null };
736
+ };
737
+ var scrubbedCodexEnvironment = (codexHome) => {
738
+ if (process.platform === "win32") {
739
+ const systemRoot = String(process.env.SystemRoot || "C:\\Windows");
740
+ return {
741
+ CODEX_HOME: codexHome,
742
+ HOME: codexHome,
743
+ USERPROFILE: codexHome,
744
+ NODE_ENV: "production",
745
+ LANG: "C.UTF-8",
746
+ PATH: `${systemRoot}\\System32`,
747
+ SystemRoot: systemRoot,
748
+ WINDIR: String(process.env.WINDIR || systemRoot),
749
+ TEMP: tmpdir(),
750
+ TMP: tmpdir(),
751
+ TZ: "America/New_York"
752
+ };
753
+ }
754
+ return {
755
+ CODEX_HOME: codexHome,
756
+ HOME: codexHome,
757
+ NODE_ENV: "production",
758
+ LANG: "C.UTF-8",
759
+ LC_ALL: "C.UTF-8",
760
+ PATH: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
761
+ SHELL: "/bin/bash",
762
+ SSL_CERT_DIR: "/etc/ssl/certs",
763
+ TMPDIR: "/tmp",
764
+ TZ: "America/New_York",
765
+ XDG_RUNTIME_DIR: codexHome
766
+ };
767
+ };
768
+ var killWindowsProcessTree = async (pid) => {
769
+ await new Promise((resolve3, reject) => {
770
+ const child = spawn2(
771
+ "taskkill.exe",
772
+ ["/PID", String(pid), "/T", "/F"],
773
+ {
774
+ windowsHide: true,
775
+ stdio: ["ignore", "ignore", "ignore"],
776
+ env: {
777
+ NODE_ENV: "production",
778
+ SystemRoot: String(process.env.SystemRoot || "C:\\Windows"),
779
+ WINDIR: String(process.env.WINDIR || process.env.SystemRoot || "C:\\Windows"),
780
+ PATH: `${String(process.env.SystemRoot || "C:\\Windows")}\\System32`
781
+ }
782
+ }
783
+ );
784
+ const timer = setTimeout(() => {
785
+ child.kill();
786
+ reject(new Error("Windows Codex process-tree cleanup timed out."));
787
+ }, 5e3);
788
+ child.once("error", (error) => {
789
+ clearTimeout(timer);
790
+ reject(error);
791
+ });
792
+ child.once("close", (code) => {
793
+ clearTimeout(timer);
794
+ if (code === 0 || code === 128) resolve3();
795
+ else reject(new Error("Windows Codex process-tree cleanup failed."));
796
+ });
797
+ });
798
+ };
799
+ var appServerArgs = (enableAgentCodeModeHost = false) => {
800
+ const args = [
801
+ "app-server",
802
+ "--stdio",
803
+ "--strict-config",
804
+ "-c",
805
+ 'approval_policy="never"',
806
+ "-c",
807
+ 'shell_environment_policy.inherit="none"',
808
+ "-c",
809
+ 'shell_environment_policy.include_only=["PATH","LANG","LC_ALL","SHELL","TMPDIR","TZ","SSL_CERT_DIR"]'
810
+ ];
811
+ for (const feature of [
812
+ "fast_mode",
813
+ "plugins",
814
+ "unified_exec",
815
+ "apps",
816
+ "browser_use",
817
+ "in_app_browser",
818
+ "computer_use",
819
+ "memories",
820
+ "image_generation",
821
+ "multi_agent",
822
+ ...enableAgentCodeModeHost ? [] : ["code_mode_host"]
823
+ ]) args.push("--disable", feature);
824
+ if (enableAgentCodeModeHost) args.push("--enable", "code_mode_host");
825
+ return args;
826
+ };
827
+ var GUARDIAN_SCRIPT = String.raw`
828
+ import { spawn } from 'node:child_process';
829
+ import { chmod, open, readFile, rename, rm, writeFile } from 'node:fs/promises';
830
+ import { dirname } from 'node:path';
831
+ const input = JSON.parse(Buffer.from(process.argv[1], 'base64url').toString('utf8'));
832
+ // The guardian owns the process boundary for every attempt. Apply a private
833
+ // umask before writing receipts or starting Codex so a lost thread/start reply
834
+ // still leaves traversable 0700 directories and removable 0600 rollout files.
835
+ process.umask(0o077);
836
+ const replaceReceipt = async (temporary) => {
837
+ const retryableWindowsCodes = new Set(['EACCES', 'EBUSY', 'EEXIST', 'ENOTEMPTY', 'EPERM']);
838
+ for (let attempt = 0; attempt < 40; attempt += 1) {
839
+ try {
840
+ await rename(temporary, input.receiptPath);
841
+ return;
842
+ } catch (error) {
843
+ if (
844
+ process.platform !== 'win32'
845
+ || !retryableWindowsCodes.has(String(error?.code || ''))
846
+ || attempt === 39
847
+ ) throw error;
848
+ try {
849
+ await rm(input.receiptPath, { force: true });
850
+ } catch (removeError) {
851
+ if (!retryableWindowsCodes.has(String(removeError?.code || ''))) throw removeError;
852
+ }
853
+ await new Promise((resolve) => setTimeout(resolve, 25));
854
+ }
855
+ }
856
+ };
857
+ let receiptWriteSequence = 0;
858
+ let receiptWriteChain = Promise.resolve();
859
+ const writeReceipt = (state, childPid, termination = null) => {
860
+ const write = async () => {
861
+ const body = JSON.stringify({
862
+ schema_version: 'vtx_codex_guardian_v1',
863
+ process_token: input.processToken,
864
+ state,
865
+ guardian_pid: process.pid,
866
+ child_pid: childPid ?? null,
867
+ boot_identity: input.bootIdentity,
868
+ termination,
869
+ updated_at: new Date().toISOString(),
870
+ }) + '\n';
871
+ receiptWriteSequence += 1;
872
+ const temporary = input.receiptPath + '.tmp-' + process.pid + '-' + receiptWriteSequence;
873
+ try {
874
+ await writeFile(temporary, body, { mode: 0o600 });
875
+ await chmod(temporary, 0o600).catch(() => undefined);
876
+ const file = await open(temporary, 'r+');
877
+ try { await file.sync(); } finally { await file.close(); }
878
+ await replaceReceipt(temporary);
879
+ if (process.platform !== 'win32') {
880
+ const directory = await open(dirname(input.receiptPath), 'r');
881
+ try { await directory.sync(); } finally { await directory.close(); }
882
+ }
883
+ } finally {
884
+ await rm(temporary, { force: true }).catch(() => undefined);
885
+ }
886
+ };
887
+ const scheduled = receiptWriteChain.then(write, write);
888
+ receiptWriteChain = scheduled.catch(() => undefined);
889
+ return scheduled;
890
+ };
891
+ let child = null;
892
+ let shuttingDown = false;
893
+ let shutdownRequested = false;
894
+ let childStartedAt = null;
895
+ let forceTimer = null;
896
+ const stopChild = (expected) => {
897
+ if (expected) shutdownRequested = true;
898
+ if (shuttingDown) return;
899
+ shuttingDown = true;
900
+ if (!child) return;
901
+ child.stdin.end();
902
+ forceTimer = setTimeout(() => {
903
+ if (child.exitCode === null) child.kill('SIGKILL');
904
+ }, input.shutdownGraceMs);
905
+ forceTimer.unref();
906
+ };
907
+ let shutdownStarted = false;
908
+ const shutdown = async () => {
909
+ if (shutdownStarted) return;
910
+ shutdownStarted = true;
911
+ let expected = false;
912
+ try {
913
+ expected = (await readFile(input.shutdownIntentPath, 'utf8')) === input.processToken;
914
+ await rm(input.shutdownIntentPath, { force: true });
915
+ } catch {
916
+ expected = false;
917
+ }
918
+ stopChild(expected);
919
+ };
920
+ process.stdin.once('end', shutdown);
921
+ process.stdin.once('close', shutdown);
922
+ process.stdout.on('error', () => undefined);
923
+ process.stderr.on('error', () => undefined);
924
+ await writeReceipt('starting', null);
925
+ if (shuttingDown) {
926
+ await writeReceipt('terminated', null);
927
+ process.exit(0);
928
+ }
929
+ child = spawn(input.binary, input.args, {
930
+ env: process.env,
931
+ stdio: ['pipe', 'pipe', 'pipe'],
932
+ windowsHide: true,
933
+ detached: false,
934
+ });
935
+ childStartedAt = Date.now();
936
+ child.stdin.on('error', () => undefined);
937
+ process.stdin.pipe(child.stdin, { end: false });
938
+ child.stdout.pipe(process.stdout);
939
+ child.stderr.pipe(process.stderr);
940
+ child.once('spawn', async () => {
941
+ try {
942
+ await writeReceipt('running', child.pid ?? null);
943
+ } catch {
944
+ stopChild(false);
945
+ }
946
+ });
947
+ child.once('error', () => stopChild(false));
948
+ child.once('close', async (code, signal) => {
949
+ if (forceTimer) clearTimeout(forceTimer);
950
+ // A pending promise alone does not keep Node's event loop alive after the
951
+ // child and parent stdin have both closed. Hold one local handle until the
952
+ // serialized terminal tombstone is durably replaced.
953
+ const receiptKeepAlive = setInterval(() => undefined, 1_000);
954
+ try {
955
+ const normalizedSignal = typeof signal === 'string' && /^SIG[A-Z0-9]{1,28}$/.test(signal)
956
+ ? signal.toLowerCase()
957
+ : null;
958
+ const normalizedCode = normalizedSignal === null && Number.isInteger(code)
959
+ && code >= -(2 ** 31) && code <= (2 ** 31) - 1
960
+ ? code
961
+ : null;
962
+ await writeReceipt('terminated', child.pid ?? null, {
963
+ exit_code: normalizedCode,
964
+ signal: normalizedSignal,
965
+ expected: shutdownRequested,
966
+ uptime_ms: Math.min(
967
+ Math.max(0, Date.now() - (childStartedAt ?? Date.now())),
968
+ Number.MAX_SAFE_INTEGER,
969
+ ),
970
+ });
971
+ } finally {
972
+ clearInterval(receiptKeepAlive);
973
+ process.exit(0);
974
+ }
975
+ });
976
+ `;
977
+ var WINDOWS_RECEIPT_REPLACE_ERROR_CODES = /* @__PURE__ */ new Set([
978
+ "EACCES",
979
+ "EBUSY",
980
+ "EEXIST",
981
+ "ENOTEMPTY",
982
+ "EPERM"
983
+ ]);
984
+ var MAX_RETIRED_RESPONSE_IDS = 256;
985
+ var LATE_RESPONSE_SAFE_METHODS = /* @__PURE__ */ new Set([
986
+ "account/rateLimits/read",
987
+ "turn/start",
988
+ "turn/interrupt"
989
+ ]);
990
+ var replaceCodexGuardianReceiptFile = async (temporaryPath, receiptPath, options = {}) => {
991
+ const platform = options.platform ?? process.platform;
992
+ const renameFile = options.renameFile ?? rename2;
993
+ const removeFile = options.removeFile ?? ((path) => rm2(path, { force: true }));
994
+ const sleep = options.sleep ?? ((milliseconds) => new Promise((resolve3) => setTimeout(resolve3, milliseconds)));
995
+ const maxAttempts = Math.max(1, options.maxAttempts ?? 40);
996
+ const retryDelayMs = Math.max(0, options.retryDelayMs ?? 25);
997
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
998
+ try {
999
+ await renameFile(temporaryPath, receiptPath);
1000
+ return;
1001
+ } catch (error) {
1002
+ const code = String(error.code ?? "");
1003
+ if (platform !== "win32" || !WINDOWS_RECEIPT_REPLACE_ERROR_CODES.has(code) || attempt === maxAttempts - 1) {
1004
+ throw error;
1005
+ }
1006
+ try {
1007
+ await removeFile(receiptPath);
1008
+ } catch (removeError) {
1009
+ const removeCode = String(removeError.code ?? "");
1010
+ if (!WINDOWS_RECEIPT_REPLACE_ERROR_CODES.has(removeCode)) {
1011
+ throw removeError;
1012
+ }
1013
+ }
1014
+ await sleep(retryDelayMs);
1015
+ }
1016
+ }
1017
+ };
1018
+ var writeCodexGuardianSpawnIntent = async (guardian) => {
1019
+ const body = `${JSON.stringify({
1020
+ schema_version: "vtx_codex_guardian_v1",
1021
+ process_token: guardian.processToken,
1022
+ state: "spawn_intent",
1023
+ guardian_pid: null,
1024
+ child_pid: null,
1025
+ boot_identity: guardian.bootIdentity ?? null,
1026
+ termination: null,
1027
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
1028
+ })}
1029
+ `;
1030
+ const temporary = `${guardian.receiptPath}.intent-${process.pid}`;
1031
+ await writeFile(temporary, body, { mode: 384 });
1032
+ await chmod(temporary, 384).catch(() => void 0);
1033
+ const handle = await open2(temporary, "r+");
1034
+ try {
1035
+ await handle.sync();
1036
+ } finally {
1037
+ await handle.close();
1038
+ }
1039
+ await replaceCodexGuardianReceiptFile(temporary, guardian.receiptPath);
1040
+ if (process.platform !== "win32") {
1041
+ const directory = await open2(dirname2(guardian.receiptPath), "r");
1042
+ try {
1043
+ await directory.sync();
1044
+ } finally {
1045
+ await directory.close();
1046
+ }
1047
+ }
1048
+ };
1049
+ var parseGuardianReceipt = (raw) => {
1050
+ const value = JSON.parse(raw);
1051
+ const rawTermination = value.termination;
1052
+ const termination = rawTermination === null || rawTermination === void 0 ? null : objectOrNull(rawTermination);
1053
+ if (value.schema_version !== "vtx_codex_guardian_v1" || typeof value.process_token !== "string" || !/^[0-9a-f]{64}$/u.test(value.process_token) || !["spawn_intent", "starting", "running", "terminated"].includes(String(value.state)) || value.guardian_pid !== null && !Number.isSafeInteger(value.guardian_pid) || value.state === "spawn_intent" && value.guardian_pid !== null || value.state !== "spawn_intent" && !Number.isSafeInteger(value.guardian_pid) || value.child_pid !== null && !Number.isSafeInteger(value.child_pid) || value.boot_identity !== null && value.boot_identity !== void 0 && typeof value.boot_identity !== "string" || typeof value.updated_at !== "string" || !Number.isFinite(Date.parse(value.updated_at)) || rawTermination !== null && rawTermination !== void 0 && termination === null || termination !== null && (value.state !== "terminated" || termination.exit_code !== null && (!Number.isInteger(termination.exit_code) || Number(termination.exit_code) < -(2 ** 31) || Number(termination.exit_code) > 2 ** 31 - 1) || termination.signal !== null && (typeof termination.signal !== "string" || !/^sig[a-z0-9]{1,28}$/u.test(termination.signal)) || termination.signal !== null && termination.exit_code !== null || typeof termination.expected !== "boolean" || !Number.isSafeInteger(termination.uptime_ms) || Number(termination.uptime_ms) < 0)) {
1054
+ throw new Error("Codex guardian receipt is invalid.");
1055
+ }
1056
+ return {
1057
+ ...value,
1058
+ boot_identity: typeof value.boot_identity === "string" ? value.boot_identity : null,
1059
+ termination
1060
+ };
1061
+ };
1062
+ var readCodexGuardianReceipt = async (path) => {
1063
+ try {
1064
+ const state = await lstat2(path);
1065
+ if (!state.isFile() || state.isSymbolicLink() || process.platform !== "win32" && ((state.mode & 63) !== 0 || typeof process.getuid === "function" && state.uid !== process.getuid())) {
1066
+ throw new Error("Codex guardian receipt is not private.");
1067
+ }
1068
+ return parseGuardianReceipt(await readFile2(path, "utf8"));
1069
+ } catch (error) {
1070
+ if (error.code === "ENOENT") return null;
1071
+ throw error;
1072
+ }
1073
+ };
1074
+ var waitForCodexGuardianState = async (guardian, expectedState, deadlineAtMs) => {
1075
+ while (Date.now() < deadlineAtMs) {
1076
+ const receipt = await readCodexGuardianReceipt(guardian.receiptPath);
1077
+ if (receipt) {
1078
+ if (receipt.process_token !== guardian.processToken) {
1079
+ throw new Error("Codex guardian receipt crossed process scope.");
1080
+ }
1081
+ if (receipt.state === expectedState) return receipt;
1082
+ if (receipt.state === "terminated" && expectedState === "running") {
1083
+ throw new Error("Codex guardian terminated before app-server initialization.");
1084
+ }
1085
+ }
1086
+ await new Promise((resolve3) => setTimeout(resolve3, 25));
1087
+ }
1088
+ throw new Error(`Codex guardian ${expectedState} state was not confirmed.`);
1089
+ };
1090
+ var defaultSpawn = (binary, args, options) => {
1091
+ if (!options.guardian) {
1092
+ const { guardian: _guardian, ...spawnOptions } = options;
1093
+ return spawn2(binary, args, {
1094
+ ...spawnOptions,
1095
+ detached: options.detached
1096
+ });
1097
+ }
1098
+ const payload = Buffer.from(JSON.stringify({
1099
+ binary,
1100
+ args,
1101
+ processToken: options.guardian.processToken,
1102
+ receiptPath: options.guardian.receiptPath,
1103
+ shutdownIntentPath: `${options.guardian.receiptPath}.shutdown-intent`,
1104
+ shutdownGraceMs: Math.max(25, options.guardian.shutdownGraceMs ?? 2e3),
1105
+ bootIdentity: options.guardian.bootIdentity
1106
+ }), "utf8").toString("base64url");
1107
+ return spawn2(process.execPath, ["--input-type=module", "--eval", GUARDIAN_SCRIPT, payload], {
1108
+ env: options.env,
1109
+ stdio: options.stdio,
1110
+ windowsHide: options.windowsHide,
1111
+ detached: true
1112
+ });
1113
+ };
1114
+ var CodexAppServerSession = class _CodexAppServerSession {
1115
+ constructor(options) {
1116
+ this.pending = /* @__PURE__ */ new Map();
1117
+ this.retiredResponseIds = /* @__PURE__ */ new Map();
1118
+ this.notificationListeners = /* @__PURE__ */ new Set();
1119
+ this.fatalListeners = /* @__PURE__ */ new Set();
1120
+ this.agentToolHandlers = /* @__PURE__ */ new Map();
1121
+ this.accountLoginCompletions = /* @__PURE__ */ new Map();
1122
+ this.threads = /* @__PURE__ */ new Map();
1123
+ this.nextRequestId = 1;
1124
+ this.fatalError = null;
1125
+ this.closed = false;
1126
+ this.processCloseObserved = false;
1127
+ this.shutdownRequested = false;
1128
+ this.stderrBytesObserved = 0;
1129
+ this.stderrNonempty = false;
1130
+ this.stderrTruncated = false;
1131
+ this.stderrTail = "";
1132
+ this.stderrClass = "none";
1133
+ this.process = options.process;
1134
+ this.codexHome = options.codexHome;
1135
+ this.sessionGeneration = options.sessionGeneration;
1136
+ this.startedAtMs = Date.now();
1137
+ this.guardian = options.guardian;
1138
+ this.onProcessExit = options.onProcessExit;
1139
+ this.onLateResponse = options.onLateResponse;
1140
+ this.process.stderr.on("data", (chunk) => this.observeStderr(chunk));
1141
+ const lines = createInterface({ input: this.process.stdout, crlfDelay: Infinity });
1142
+ lines.on("line", (line) => this.handleLine(line));
1143
+ this.process.once("error", () => {
1144
+ });
1145
+ this.process.once("close", (code, signal) => {
1146
+ void this.handleProcessClose(code, signal);
1147
+ });
1148
+ }
1149
+ static {
1150
+ this.STDERR_OBSERVATION_CAP_BYTES = 65536;
1151
+ }
1152
+ static {
1153
+ this.STDERR_CLASSIFICATION_TAIL_CHARS = 1024;
1154
+ }
1155
+ static async start(options) {
1156
+ const spawnProcess = options.spawnProcess ?? defaultSpawn;
1157
+ const guardian = options.guardian ? {
1158
+ ...options.guardian,
1159
+ bootIdentity: options.guardian.bootIdentity ?? await readInferenceSystemBootIdentity()
1160
+ } : void 0;
1161
+ if (guardian) {
1162
+ try {
1163
+ await writeCodexGuardianSpawnIntent(guardian);
1164
+ } catch (error) {
1165
+ throw new CodexAppServerError({
1166
+ message: "Codex guardian spawn intent could not be persisted.",
1167
+ category: "transport",
1168
+ code: "codex_guardian_intent_unconfirmed",
1169
+ retryable: false,
1170
+ cause: error
1171
+ });
1172
+ }
1173
+ }
1174
+ const child = spawnProcess(options.binary.path, appServerArgs(
1175
+ options.enableAgentCodeModeHost === true
1176
+ ), {
1177
+ env: scrubbedCodexEnvironment(options.codexHome),
1178
+ stdio: ["pipe", "pipe", "pipe"],
1179
+ windowsHide: true,
1180
+ detached: true,
1181
+ guardian
1182
+ });
1183
+ if (guardian) {
1184
+ try {
1185
+ await waitForCodexGuardianState(
1186
+ guardian,
1187
+ "running",
1188
+ Math.min(options.deadlineAtMs, Date.now() + 1e4)
1189
+ );
1190
+ } catch (error) {
1191
+ child.stdin.end();
1192
+ try {
1193
+ await waitForCodexGuardianState(
1194
+ guardian,
1195
+ "terminated",
1196
+ Date.now() + 5e3
1197
+ );
1198
+ } catch (terminationError) {
1199
+ throw new CodexAppServerError({
1200
+ message: "Codex guardian startup failed and termination was not confirmed.",
1201
+ category: "transport",
1202
+ code: "codex_guardian_termination_unconfirmed",
1203
+ retryable: false,
1204
+ cause: terminationError
1205
+ });
1206
+ }
1207
+ throw new CodexAppServerError({
1208
+ message: "Codex guardian startup could not be confirmed.",
1209
+ category: "transport",
1210
+ code: "codex_guardian_start_unconfirmed",
1211
+ retryable: false,
1212
+ cause: error
1213
+ });
1214
+ }
1215
+ }
1216
+ const session = new _CodexAppServerSession({
1217
+ process: child,
1218
+ codexHome: options.codexHome,
1219
+ sessionGeneration: options.sessionGeneration ?? 1,
1220
+ guardian: guardian ?? null,
1221
+ onProcessExit: options.onProcessExit ?? null,
1222
+ onLateResponse: options.onLateResponse ?? null
1223
+ });
1224
+ try {
1225
+ const initialized = await session.request("initialize", {
1226
+ clientInfo: {
1227
+ name: "vtx_external_inference_host",
1228
+ title: "VTX External Inference Host",
1229
+ version: "external_inference.v1"
1230
+ },
1231
+ capabilities: {
1232
+ experimentalApi: true,
1233
+ optOutNotificationMethods: ["thread/started"]
1234
+ }
1235
+ }, {
1236
+ timeoutMs: Math.max(1, options.deadlineAtMs - Date.now()),
1237
+ signal: options.signal
1238
+ });
1239
+ if (String(initialized.codexHome || "") !== options.codexHome || !String(initialized.userAgent || "").trim()) {
1240
+ throw new CodexAppServerError({
1241
+ message: "Codex initialization provenance was invalid.",
1242
+ category: "adapter",
1243
+ code: "invalid_initialize_provenance",
1244
+ retryable: false
1245
+ });
1246
+ }
1247
+ session.notify("initialized", {});
1248
+ return session;
1249
+ } catch (error) {
1250
+ await session.close().catch(() => void 0);
1251
+ if (guardian) {
1252
+ try {
1253
+ await waitForCodexGuardianState(
1254
+ guardian,
1255
+ "terminated",
1256
+ Date.now() + 5e3
1257
+ );
1258
+ } catch (terminationError) {
1259
+ throw new CodexAppServerError({
1260
+ message: "Codex app-server failed and guardian termination was not confirmed.",
1261
+ category: "transport",
1262
+ code: "codex_guardian_termination_unconfirmed",
1263
+ retryable: false,
1264
+ cause: terminationError
1265
+ });
1266
+ }
1267
+ }
1268
+ throw error;
1269
+ }
1270
+ }
1271
+ handleLine(line) {
1272
+ let message;
1273
+ try {
1274
+ const parsed = JSON.parse(line);
1275
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1276
+ throw new Error("protocol message is not an object");
1277
+ }
1278
+ message = parsed;
1279
+ } catch {
1280
+ this.failTransport("invalid_protocol_json");
1281
+ return;
1282
+ }
1283
+ const id = message.id;
1284
+ if (typeof id === "number" && Number.isSafeInteger(id) && !("method" in message)) {
1285
+ const pending = this.pending.get(id);
1286
+ if (!pending) {
1287
+ const retiredMethod = this.retiredResponseIds.get(id);
1288
+ this.retiredResponseIds.delete(id);
1289
+ if (retiredMethod && LATE_RESPONSE_SAFE_METHODS.has(retiredMethod)) {
1290
+ try {
1291
+ this.onLateResponse?.(retiredMethod);
1292
+ } catch {
1293
+ }
1294
+ return;
1295
+ }
1296
+ this.failTransport("unexpected_response_id");
1297
+ return;
1298
+ }
1299
+ this.pending.delete(id);
1300
+ if (pending.timer) clearTimeout(pending.timer);
1301
+ pending.abortCleanup?.();
1302
+ const error = objectOrNull(message.error);
1303
+ if (error) {
1304
+ pending.reject(new CodexAppServerError({
1305
+ message: "Codex app-server rejected a request.",
1306
+ category: "adapter",
1307
+ code: "rpc_rejected",
1308
+ retryable: false
1309
+ }));
1310
+ return;
1311
+ }
1312
+ const result = objectOrNull(message.result);
1313
+ if (!result) {
1314
+ pending.reject(new CodexAppServerError({
1315
+ message: "Codex app-server returned an invalid result.",
1316
+ category: "adapter",
1317
+ code: "invalid_rpc_result",
1318
+ retryable: false
1319
+ }));
1320
+ return;
1321
+ }
1322
+ pending.resolve(result);
1323
+ return;
1324
+ }
1325
+ const method = typeof message.method === "string" ? message.method : "";
1326
+ const params = objectOrNull(message.params);
1327
+ if (method === "item/tool/call" && params && "id" in message) {
1328
+ const requestId = message.id;
1329
+ if (!(typeof requestId === "string" || typeof requestId === "number" && Number.isSafeInteger(requestId))) {
1330
+ this.failTransport("invalid_dynamic_tool_request_id");
1331
+ return;
1332
+ }
1333
+ void this.handleAgentToolRequest(requestId, params);
1334
+ return;
1335
+ }
1336
+ if (!method || !params || "id" in message) {
1337
+ this.failTransport("unexpected_server_request");
1338
+ return;
1339
+ }
1340
+ if (method === "account/login/completed") {
1341
+ const loginId = typeof params.loginId === "string" ? params.loginId.trim() : "";
1342
+ if (!loginId || typeof params.success !== "boolean") {
1343
+ this.failTransport("invalid_account_login_completion");
1344
+ return;
1345
+ }
1346
+ this.accountLoginCompletions.set(loginId, {
1347
+ success: params.success,
1348
+ error: typeof params.error === "string" ? params.error : null
1349
+ });
1350
+ }
1351
+ for (const listener of this.notificationListeners) listener({ method, params });
1352
+ }
1353
+ async handleAgentToolRequest(requestId, params) {
1354
+ const threadId = typeof params.threadId === "string" ? params.threadId.trim() : "";
1355
+ const requestTurnId = typeof params.turnId === "string" ? params.turnId.trim() : "";
1356
+ const callId = typeof params.callId === "string" ? params.callId.trim() : "";
1357
+ const tool = typeof params.tool === "string" ? params.tool : "";
1358
+ const args = objectOrNull(params.arguments);
1359
+ const handler = this.agentToolHandlers.get(threadId);
1360
+ if (!threadId || !requestTurnId || !callId || params.namespace !== null || !CODEX_AGENT_DYNAMIC_TOOLS.includes(tool) || !args || !handler || !handler.acceptTurnId(requestTurnId)) {
1361
+ this.failTransport("invalid_dynamic_tool_request");
1362
+ return;
1363
+ }
1364
+ try {
1365
+ const signature = JSON.stringify({ tool, arguments: args });
1366
+ const existing = handler.calls.get(callId);
1367
+ if (existing && existing.signature !== signature) {
1368
+ this.failTransport("dynamic_tool_call_identity_reused");
1369
+ return;
1370
+ }
1371
+ const promise = existing?.promise ?? handler.execute({
1372
+ callId,
1373
+ tool,
1374
+ arguments: args
1375
+ });
1376
+ if (!existing) handler.calls.set(callId, { signature, promise });
1377
+ const result = await promise;
1378
+ this.write({
1379
+ id: requestId,
1380
+ result: {
1381
+ contentItems: [{ type: "inputText", text: JSON.stringify(result.value ?? null) }],
1382
+ success: result.success
1383
+ }
1384
+ });
1385
+ } catch {
1386
+ this.write({
1387
+ id: requestId,
1388
+ result: {
1389
+ contentItems: [{
1390
+ type: "inputText",
1391
+ text: JSON.stringify({ error: "vtx_agent_tool_failed" })
1392
+ }],
1393
+ success: false
1394
+ }
1395
+ });
1396
+ }
1397
+ }
1398
+ failTransport(code, processExit = null) {
1399
+ if (this.fatalError) return;
1400
+ this.fatalError = new CodexAppServerError({
1401
+ message: "Codex app-server transport became unavailable.",
1402
+ category: "transport",
1403
+ code,
1404
+ retryable: true,
1405
+ processExit
1406
+ });
1407
+ for (const pending of this.pending.values()) {
1408
+ if (pending.timer) clearTimeout(pending.timer);
1409
+ pending.abortCleanup?.();
1410
+ pending.reject(this.fatalError);
1411
+ }
1412
+ this.pending.clear();
1413
+ for (const listener of this.fatalListeners) listener(this.fatalError);
1414
+ }
1415
+ retireResponseId(id, method) {
1416
+ this.retiredResponseIds.set(id, method);
1417
+ while (this.retiredResponseIds.size > MAX_RETIRED_RESPONSE_IDS) {
1418
+ const oldest = this.retiredResponseIds.keys().next().value;
1419
+ if (typeof oldest !== "number") break;
1420
+ this.retiredResponseIds.delete(oldest);
1421
+ }
1422
+ }
1423
+ write(message) {
1424
+ if (this.closed || this.fatalError || this.process.exitCode !== null) {
1425
+ throw this.fatalError ?? new CodexAppServerError({
1426
+ message: "Codex app-server is closed.",
1427
+ category: "transport",
1428
+ code: "transport_closed",
1429
+ retryable: true
1430
+ });
1431
+ }
1432
+ this.process.stdin.write(`${JSON.stringify(message)}
1433
+ `);
1434
+ }
1435
+ notify(method, params) {
1436
+ this.write({ method, params });
1437
+ }
1438
+ async request(method, params, options = { timeoutMs: 3e4 }) {
1439
+ if (options.signal?.aborted) {
1440
+ throw new CodexAppServerError({
1441
+ message: "Codex request was cancelled before dispatch.",
1442
+ category: "cancelled",
1443
+ code: "rpc_cancelled_before_write",
1444
+ retryable: false,
1445
+ dispatchOutcome: "not_dispatched"
1446
+ });
1447
+ }
1448
+ const id = this.nextRequestId++;
1449
+ await options.beforeWrite?.(id);
1450
+ if (options.signal?.aborted) {
1451
+ throw new CodexAppServerError({
1452
+ message: "Codex request was cancelled before dispatch.",
1453
+ category: "cancelled",
1454
+ code: "rpc_cancelled_before_write",
1455
+ retryable: false,
1456
+ dispatchOutcome: "not_dispatched"
1457
+ });
1458
+ }
1459
+ if (options.notAfterMs !== void 0 && Date.now() > options.notAfterMs) {
1460
+ throw new CodexAppServerError({
1461
+ message: "Server account context expired before provider dispatch.",
1462
+ category: "adapter",
1463
+ code: "server_account_context_expired_before_provider_dispatch",
1464
+ retryable: false,
1465
+ dispatchOutcome: "not_dispatched"
1466
+ });
1467
+ }
1468
+ return await new Promise((resolve3, reject) => {
1469
+ const pending = { resolve: resolve3, reject, timer: null, abortCleanup: null };
1470
+ pending.timer = setTimeout(() => {
1471
+ this.pending.delete(id);
1472
+ this.retireResponseId(id, method);
1473
+ pending.abortCleanup?.();
1474
+ reject(new CodexAppServerError({
1475
+ message: "Codex app-server request timed out.",
1476
+ category: "timeout",
1477
+ code: "rpc_timeout",
1478
+ retryable: true
1479
+ }));
1480
+ }, Math.max(1, options.timeoutMs));
1481
+ if (options.signal && !options.retainResponseOnAbort) {
1482
+ const onAbort = () => {
1483
+ this.pending.delete(id);
1484
+ this.retireResponseId(id, method);
1485
+ if (pending.timer) clearTimeout(pending.timer);
1486
+ pending.abortCleanup?.();
1487
+ reject(new CodexAppServerError({
1488
+ message: "Codex request was cancelled.",
1489
+ category: "cancelled",
1490
+ code: "cancelled",
1491
+ retryable: false
1492
+ }));
1493
+ };
1494
+ options.signal.addEventListener("abort", onAbort, { once: true });
1495
+ pending.abortCleanup = () => options.signal?.removeEventListener("abort", onAbort);
1496
+ }
1497
+ this.pending.set(id, pending);
1498
+ try {
1499
+ this.write(params === void 0 ? { id, method } : { id, method, params });
1500
+ options.onWritten?.(id);
1501
+ } catch (error) {
1502
+ this.pending.delete(id);
1503
+ if (pending.timer) clearTimeout(pending.timer);
1504
+ pending.abortCleanup?.();
1505
+ reject(error);
1506
+ }
1507
+ });
1508
+ }
1509
+ subscribe(listener) {
1510
+ this.notificationListeners.add(listener);
1511
+ return () => this.notificationListeners.delete(listener);
1512
+ }
1513
+ subscribeFatal(listener) {
1514
+ this.fatalListeners.add(listener);
1515
+ return () => this.fatalListeners.delete(listener);
1516
+ }
1517
+ observeStderr(chunk) {
1518
+ const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8");
1519
+ if (bytes.length === 0) return;
1520
+ this.stderrNonempty = true;
1521
+ const remaining = Math.max(
1522
+ 0,
1523
+ _CodexAppServerSession.STDERR_OBSERVATION_CAP_BYTES - this.stderrBytesObserved
1524
+ );
1525
+ if (remaining === 0) {
1526
+ this.stderrTruncated = true;
1527
+ return;
1528
+ }
1529
+ const observed = bytes.subarray(0, remaining);
1530
+ this.stderrBytesObserved += observed.length;
1531
+ if (bytes.length > remaining) this.stderrTruncated = true;
1532
+ this.stderrTail = `${this.stderrTail}${observed.toString("utf8")}`.slice(-_CodexAppServerSession.STDERR_CLASSIFICATION_TAIL_CHARS).toLowerCase();
1533
+ const classified = /heap out of memory|allocation failed|out of memory/u.test(this.stderrTail) ? "out_of_memory" : /fatal runtime error|fatal error|\bpanic(?:ked)?\b/u.test(this.stderrTail) ? "runtime_fatal" : /access violation|segmentation fault|\bsegfault\b/u.test(this.stderrTail) ? "memory_fault" : /broken pipe|econnreset|connection reset/u.test(this.stderrTail) ? "pipe_or_connection" : null;
1534
+ if (classified) this.stderrClass = classified;
1535
+ else if (this.stderrClass === "none") this.stderrClass = "unclassified";
1536
+ }
1537
+ async handleProcessClose(rawCode, rawSignal) {
1538
+ this.processCloseObserved = true;
1539
+ let termination = null;
1540
+ if (this.guardian) {
1541
+ try {
1542
+ const receipt = await readCodexGuardianReceipt(this.guardian.receiptPath);
1543
+ if (receipt?.process_token === this.guardian.processToken && receipt.state === "terminated") {
1544
+ termination = receipt.termination;
1545
+ }
1546
+ } catch {
1547
+ }
1548
+ }
1549
+ const diagnostics = this.processExitDiagnostics(rawCode, rawSignal, termination);
1550
+ if (this.guardian) {
1551
+ await rm2(`${this.guardian.receiptPath}.shutdown-intent`, { force: true }).catch(() => void 0);
1552
+ }
1553
+ try {
1554
+ this.onProcessExit?.(diagnostics);
1555
+ } catch {
1556
+ }
1557
+ this.failTransport("codex_process_closed", diagnostics);
1558
+ }
1559
+ processExitDiagnostics(rawCode, rawSignal, termination) {
1560
+ const source = termination ? "child_receipt" : this.guardian ? "guardian_process" : "direct_process";
1561
+ const reportedCode = termination?.exit_code ?? rawCode;
1562
+ const reportedSignal = termination?.signal ?? rawSignal;
1563
+ const signal = typeof reportedSignal === "string" && /^(?:SIG[A-Z0-9]{1,28}|sig[a-z0-9]{1,28})$/u.test(reportedSignal) ? reportedSignal.toLowerCase() : null;
1564
+ const exitCode = signal === null && typeof reportedCode === "number" && Number.isInteger(reportedCode) && reportedCode >= -(2 ** 31) && reportedCode <= 2 ** 31 - 1 ? reportedCode : null;
1565
+ const diagnostics = {
1566
+ schema_version: "external_inference_process_exit_v1",
1567
+ runtime: "codex_app_server",
1568
+ source,
1569
+ session_generation: this.sessionGeneration,
1570
+ expected_shutdown: termination?.expected ?? this.shutdownRequested,
1571
+ exit_class: signal !== null ? "signal" : exitCode === null ? "unknown" : exitCode === 0 ? "zero" : "nonzero",
1572
+ exit_code: exitCode,
1573
+ signal,
1574
+ uptime_ms: termination?.uptime_ms ?? Math.min(
1575
+ Math.max(0, Date.now() - this.startedAtMs),
1576
+ Number.MAX_SAFE_INTEGER
1577
+ ),
1578
+ pending_request_count: this.pending.size,
1579
+ active_thread_count: this.threads.size,
1580
+ stderr_nonempty: this.stderrNonempty,
1581
+ stderr_bytes_observed: this.stderrBytesObserved,
1582
+ stderr_truncated: this.stderrTruncated,
1583
+ stderr_class: this.stderrNonempty ? this.stderrClass : "none"
1584
+ };
1585
+ this.stderrTail = "";
1586
+ return diagnostics;
1587
+ }
1588
+ isUsable() {
1589
+ return !this.closed && this.fatalError === null && this.process.exitCode === null;
1590
+ }
1591
+ async readAccountSnapshot(deadlineAtMs, signal, refreshToken = false) {
1592
+ const result = await this.request("account/read", { refreshToken }, {
1593
+ timeoutMs: Math.max(1, deadlineAtMs - Date.now()),
1594
+ signal
1595
+ });
1596
+ const account = objectOrNull(result.account);
1597
+ if (typeof result.requiresOpenaiAuth !== "boolean") {
1598
+ throw new CodexAppServerError({
1599
+ message: "Codex returned invalid account metadata.",
1600
+ category: "auth",
1601
+ code: "invalid_account_metadata",
1602
+ retryable: false
1603
+ });
1604
+ }
1605
+ if (account?.type === "chatgpt") {
1606
+ const email = account.email === null ? null : typeof account.email === "string" && account.email.trim() ? account.email.trim() : void 0;
1607
+ if (email === void 0 || !validPlanType(account.planType)) {
1608
+ throw new CodexAppServerError({
1609
+ message: "Codex returned invalid managed ChatGPT account metadata.",
1610
+ category: "auth",
1611
+ code: "invalid_account_metadata",
1612
+ retryable: false
1613
+ });
1614
+ }
1615
+ return {
1616
+ requiresOpenaiAuth: result.requiresOpenaiAuth,
1617
+ authenticatedChatGptAccount: { email, planType: account.planType }
1618
+ };
1619
+ }
1620
+ if (account !== null && account?.type !== "apiKey" && account?.type !== "amazonBedrock") {
1621
+ throw new CodexAppServerError({
1622
+ message: "Codex returned an unsupported account type.",
1623
+ category: "auth",
1624
+ code: "invalid_account_metadata",
1625
+ retryable: false
1626
+ });
1627
+ }
1628
+ return {
1629
+ requiresOpenaiAuth: result.requiresOpenaiAuth,
1630
+ authenticatedChatGptAccount: null
1631
+ };
1632
+ }
1633
+ async hasManagedChatGptAuth(deadlineAtMs, signal, refreshToken = false) {
1634
+ const snapshot = await this.readAccountSnapshot(deadlineAtMs, signal, refreshToken);
1635
+ return snapshot.authenticatedChatGptAccount !== null && snapshot.requiresOpenaiAuth;
1636
+ }
1637
+ async readAccountRateLimits(deadlineAtMs, signal) {
1638
+ const result = await this.request("account/rateLimits/read", void 0, {
1639
+ timeoutMs: Math.max(1, deadlineAtMs - Date.now()),
1640
+ signal
1641
+ });
1642
+ try {
1643
+ const rateLimits = parseRateLimitSnapshot(result.rateLimits);
1644
+ const rawByLimitId = result.rateLimitsByLimitId;
1645
+ let rateLimitsByLimitId = null;
1646
+ if (rawByLimitId !== null && rawByLimitId !== void 0) {
1647
+ const byLimitId = objectOrNull(rawByLimitId);
1648
+ if (!byLimitId) throw new Error("invalid rate-limit bucket map");
1649
+ rateLimitsByLimitId = {};
1650
+ for (const [limitId, snapshot] of Object.entries(byLimitId)) {
1651
+ if (!limitId.trim()) throw new Error("invalid rate-limit bucket identity");
1652
+ rateLimitsByLimitId[limitId] = parseRateLimitSnapshot(snapshot);
1653
+ }
1654
+ }
1655
+ return { rateLimits, rateLimitsByLimitId };
1656
+ } catch (error) {
1657
+ throw new CodexAppServerError({
1658
+ message: "Codex returned invalid account rate-limit metadata.",
1659
+ category: "adapter",
1660
+ code: "invalid_rate_limit_metadata",
1661
+ retryable: false,
1662
+ cause: error
1663
+ });
1664
+ }
1665
+ }
1666
+ async requireManagedChatGptAuth(deadlineAtMs, signal, refreshToken = false) {
1667
+ if (!await this.hasManagedChatGptAuth(deadlineAtMs, signal, refreshToken)) {
1668
+ throw new CodexAppServerError({
1669
+ message: "Codex managed ChatGPT authentication is required.",
1670
+ category: "auth",
1671
+ code: "managed_chatgpt_auth_required",
1672
+ retryable: false
1673
+ });
1674
+ }
1675
+ }
1676
+ async startChatGptDeviceCodeLogin(deadlineAtMs, signal) {
1677
+ const result = await this.request("account/login/start", { type: "chatgptDeviceCode" }, {
1678
+ timeoutMs: Math.max(1, deadlineAtMs - Date.now()),
1679
+ signal
1680
+ });
1681
+ const loginId = typeof result.loginId === "string" ? result.loginId.trim() : "";
1682
+ const verificationUrl = typeof result.verificationUrl === "string" ? result.verificationUrl.trim() : "";
1683
+ const userCode = typeof result.userCode === "string" ? result.userCode.trim() : "";
1684
+ if (result.type !== "chatgptDeviceCode" || !loginId || !verificationUrl.startsWith("https://") || !userCode) {
1685
+ throw new CodexAppServerError({
1686
+ message: "Codex returned an invalid device-code login challenge.",
1687
+ category: "auth",
1688
+ code: "invalid_device_code_challenge",
1689
+ retryable: false
1690
+ });
1691
+ }
1692
+ return { loginId, verificationUrl, userCode };
1693
+ }
1694
+ async waitForChatGptLogin(loginId, deadlineAtMs, signal) {
1695
+ const settle = (completion, resolveCompletion, rejectCompletion) => {
1696
+ this.accountLoginCompletions.delete(loginId);
1697
+ if (completion.success) {
1698
+ resolveCompletion();
1699
+ return;
1700
+ }
1701
+ rejectCompletion(new CodexAppServerError({
1702
+ message: "Codex ChatGPT device-code login failed.",
1703
+ category: "auth",
1704
+ code: "chatgpt_login_failed",
1705
+ retryable: false
1706
+ }));
1707
+ };
1708
+ const existing = this.accountLoginCompletions.get(loginId);
1709
+ if (existing) {
1710
+ await new Promise((resolveCompletion, rejectCompletion) => {
1711
+ settle(existing, resolveCompletion, rejectCompletion);
1712
+ });
1713
+ return;
1714
+ }
1715
+ await new Promise((resolveCompletion, rejectCompletion) => {
1716
+ let timer = null;
1717
+ let abortCleanup = null;
1718
+ let unsubscribe = null;
1719
+ let unsubscribeFatal = null;
1720
+ const cleanup = () => {
1721
+ if (timer) clearTimeout(timer);
1722
+ abortCleanup?.();
1723
+ unsubscribe?.();
1724
+ unsubscribeFatal?.();
1725
+ };
1726
+ const fail = (error) => {
1727
+ cleanup();
1728
+ rejectCompletion(error);
1729
+ };
1730
+ unsubscribe = this.subscribe(({ method, params }) => {
1731
+ if (method !== "account/login/completed" || params.loginId !== loginId) return;
1732
+ const completion = this.accountLoginCompletions.get(loginId);
1733
+ if (!completion) {
1734
+ fail(new CodexAppServerError({
1735
+ message: "Codex returned an invalid device-code login completion.",
1736
+ category: "auth",
1737
+ code: "invalid_device_code_completion",
1738
+ retryable: false
1739
+ }));
1740
+ return;
1741
+ }
1742
+ cleanup();
1743
+ settle(completion, resolveCompletion, rejectCompletion);
1744
+ });
1745
+ unsubscribeFatal = this.subscribeFatal(fail);
1746
+ timer = setTimeout(() => fail(new CodexAppServerError({
1747
+ message: "Codex ChatGPT device-code login timed out.",
1748
+ category: "timeout",
1749
+ code: "chatgpt_login_timeout",
1750
+ retryable: false
1751
+ })), Math.max(1, deadlineAtMs - Date.now()));
1752
+ if (signal) {
1753
+ const onAbort = () => fail(new CodexAppServerError({
1754
+ message: "Codex ChatGPT device-code login was cancelled.",
1755
+ category: "cancelled",
1756
+ code: "cancelled",
1757
+ retryable: false
1758
+ }));
1759
+ signal.addEventListener("abort", onAbort, { once: true });
1760
+ abortCleanup = () => signal.removeEventListener("abort", onAbort);
1761
+ if (signal.aborted) onAbort();
1762
+ }
1763
+ const racedCompletion = this.accountLoginCompletions.get(loginId);
1764
+ if (racedCompletion) {
1765
+ cleanup();
1766
+ settle(racedCompletion, resolveCompletion, rejectCompletion);
1767
+ }
1768
+ });
1769
+ }
1770
+ async cancelChatGptLogin(loginId, deadlineAtMs, signal) {
1771
+ const result = await this.request("account/login/cancel", { loginId }, {
1772
+ timeoutMs: Math.max(1, deadlineAtMs - Date.now()),
1773
+ signal
1774
+ });
1775
+ if (result.status !== "canceled" && result.status !== "notFound") {
1776
+ throw new CodexAppServerError({
1777
+ message: "Codex device-code login cancellation was not confirmed.",
1778
+ category: "auth",
1779
+ code: "device_code_cancel_unconfirmed",
1780
+ retryable: false
1781
+ });
1782
+ }
1783
+ }
1784
+ async logoutManagedChatGptAuth(deadlineAtMs, signal) {
1785
+ const result = await this.request("account/logout", void 0, {
1786
+ timeoutMs: Math.max(1, deadlineAtMs - Date.now()),
1787
+ signal
1788
+ });
1789
+ if (Object.keys(result).length !== 0) {
1790
+ throw new CodexAppServerError({
1791
+ message: "Codex ChatGPT logout was not confirmed.",
1792
+ category: "auth",
1793
+ code: "chatgpt_logout_unconfirmed",
1794
+ retryable: false
1795
+ });
1796
+ }
1797
+ }
1798
+ async readModelCapabilities(deadlineAtMs, signal) {
1799
+ let cursor = null;
1800
+ const seen = /* @__PURE__ */ new Set();
1801
+ const capabilities = [];
1802
+ do {
1803
+ if (signal?.aborted) {
1804
+ throw new CodexAppServerError({
1805
+ message: "Codex model catalog request was cancelled before dispatch.",
1806
+ category: "cancelled",
1807
+ code: "cancelled",
1808
+ retryable: false
1809
+ });
1810
+ }
1811
+ if (Date.now() >= deadlineAtMs) {
1812
+ throw new CodexAppServerError({
1813
+ message: "Codex model catalog request exceeded the immutable deadline before dispatch.",
1814
+ category: "timeout",
1815
+ code: "deadline_exceeded",
1816
+ retryable: false
1817
+ });
1818
+ }
1819
+ const result = await this.request("model/list", {
1820
+ includeHidden: false,
1821
+ ...cursor ? { cursor } : {}
1822
+ }, {
1823
+ timeoutMs: Math.max(1, deadlineAtMs - Date.now()),
1824
+ signal
1825
+ });
1826
+ const data = Array.isArray(result.data) ? result.data : [];
1827
+ for (const raw of data) {
1828
+ const candidate = objectOrNull(raw);
1829
+ if (!candidate) continue;
1830
+ const id = typeof candidate.id === "string" ? candidate.id.trim() : "";
1831
+ const model = typeof candidate.model === "string" ? candidate.model.trim() : "";
1832
+ const displayName = typeof candidate.displayName === "string" ? candidate.displayName.trim() : "";
1833
+ const hidden = candidate.hidden === true;
1834
+ const supportedReasoningEfforts = Array.isArray(candidate.supportedReasoningEfforts) ? candidate.supportedReasoningEfforts.flatMap((item) => {
1835
+ const reasoningEffort = objectOrNull(item)?.reasoningEffort;
1836
+ return typeof reasoningEffort === "string" && reasoningEffort.trim() ? [reasoningEffort.trim()] : [];
1837
+ }) : [];
1838
+ const defaultReasoningEffort = typeof candidate.defaultReasoningEffort === "string" ? candidate.defaultReasoningEffort.trim() : "";
1839
+ if (!id || !model || !displayName || hidden || supportedReasoningEfforts.length === 0 || new Set(supportedReasoningEfforts).size !== supportedReasoningEfforts.length || !supportedReasoningEfforts.includes(defaultReasoningEffort)) continue;
1840
+ capabilities.push(Object.freeze({
1841
+ id,
1842
+ model,
1843
+ displayName,
1844
+ hidden,
1845
+ supportedReasoningEfforts: Object.freeze(supportedReasoningEfforts),
1846
+ defaultReasoningEffort,
1847
+ isDefault: candidate.isDefault === true
1848
+ }));
1849
+ }
1850
+ cursor = typeof result.nextCursor === "string" && result.nextCursor ? result.nextCursor : null;
1851
+ if (cursor && seen.has(cursor)) {
1852
+ throw new CodexAppServerError({
1853
+ message: "Codex model catalog repeated a cursor.",
1854
+ category: "adapter",
1855
+ code: "model_catalog_cursor_repeated",
1856
+ retryable: false
1857
+ });
1858
+ }
1859
+ if (cursor) seen.add(cursor);
1860
+ } while (cursor);
1861
+ return Object.freeze(capabilities);
1862
+ }
1863
+ requireModelCapability(capabilities, modelName, reasoningEffort) {
1864
+ const match = capabilities.find((candidate) => candidate.model === modelName || candidate.id === modelName);
1865
+ if (!match) {
1866
+ throw new CodexAppServerError({
1867
+ message: "The requested Codex model is unavailable.",
1868
+ category: "model",
1869
+ code: "model_unavailable",
1870
+ retryable: false
1871
+ });
1872
+ }
1873
+ if (!match.supportedReasoningEfforts.includes(reasoningEffort)) {
1874
+ throw new CodexAppServerError({
1875
+ message: "The requested Codex reasoning effort is unavailable.",
1876
+ category: "model",
1877
+ code: "reasoning_effort_unavailable",
1878
+ retryable: false
1879
+ });
1880
+ }
1881
+ }
1882
+ async requireModel(modelName, reasoningEffort, deadlineAtMs, signal) {
1883
+ this.requireModelCapability(
1884
+ await this.readModelCapabilities(deadlineAtMs, signal),
1885
+ modelName,
1886
+ reasoningEffort
1887
+ );
1888
+ }
1889
+ async startThread(options) {
1890
+ if (options.signal?.aborted) {
1891
+ throw new CodexAppServerError({
1892
+ message: "Codex thread request was cancelled before dispatch.",
1893
+ category: "cancelled",
1894
+ code: "cancelled",
1895
+ retryable: false
1896
+ });
1897
+ }
1898
+ if (Date.now() >= options.deadlineAtMs) {
1899
+ throw new CodexAppServerError({
1900
+ message: "Codex thread request exceeded the immutable deadline before dispatch.",
1901
+ category: "timeout",
1902
+ code: "deadline_exceeded",
1903
+ retryable: false
1904
+ });
1905
+ }
1906
+ const result = await this.request("thread/start", {
1907
+ model: options.requestedModel,
1908
+ modelProvider: "openai",
1909
+ allowProviderModelFallback: false,
1910
+ serviceTier: "default",
1911
+ cwd: options.workspacePath,
1912
+ runtimeWorkspaceRoots: [options.workspacePath],
1913
+ approvalPolicy: "never",
1914
+ permissions: CODEX_INFERENCE_PERMISSION_PROFILE,
1915
+ ephemeral: false,
1916
+ historyMode: "legacy",
1917
+ environments: [],
1918
+ dynamicTools: [],
1919
+ selectedCapabilityRoots: [],
1920
+ experimentalRawEvents: false,
1921
+ developerInstructions: options.systemPrompt,
1922
+ config: {
1923
+ model_reasoning_effort: options.requestedReasoningEffort,
1924
+ model_reasoning_summary: "none",
1925
+ show_raw_agent_reasoning: true,
1926
+ hide_agent_reasoning: false,
1927
+ web_search: "disabled",
1928
+ features: {
1929
+ apps: false,
1930
+ code_mode: false,
1931
+ code_mode_buffered_exec: false,
1932
+ code_mode_host: false,
1933
+ code_mode_only: false,
1934
+ in_app_browser: false,
1935
+ js_repl: false,
1936
+ js_repl_tools_only: false,
1937
+ multi_agent: false,
1938
+ multi_agent_v2: false,
1939
+ plugin_sharing: false,
1940
+ plugins: false,
1941
+ remote_plugin: false,
1942
+ shell_tool: false,
1943
+ skill_mcp_dependency_install: false,
1944
+ standalone_web_search: false,
1945
+ web_search_cached: false,
1946
+ web_search_request: false
1947
+ }
1948
+ }
1949
+ }, {
1950
+ timeoutMs: Math.max(1, options.deadlineAtMs - Date.now()),
1951
+ signal: options.signal,
1952
+ // Thread creation does not dispatch inference, but it can persist prompt
1953
+ // bytes. Keep its exact reply correlated after cancellation so we can
1954
+ // validate and delete the thread before reporting cleanup. The original
1955
+ // RPC deadline still bounds setup; turn/start keeps normal cancellation.
1956
+ retainResponseOnAbort: true
1957
+ });
1958
+ const thread = objectOrNull(result.thread);
1959
+ const permission = objectOrNull(result.activePermissionProfile);
1960
+ const sandbox = objectOrNull(result.sandbox);
1961
+ const threadId = String(thread?.id || "");
1962
+ const threadPath = String(thread?.path || "");
1963
+ const resolvedHome = resolve2(this.codexHome);
1964
+ const resolvedThreadPath = resolve2(threadPath);
1965
+ const resolvedSessionsRoot = join2(resolvedHome, "sessions");
1966
+ if (!threadId || !threadPath || !isAbsolute2(threadPath) || !resolvedThreadPath.startsWith(`${resolvedSessionsRoot}${sep}`) || !resolvedThreadPath.endsWith(".jsonl") || thread?.ephemeral !== false || thread?.modelProvider !== "openai" || !Array.isArray(thread?.turns) || thread.turns.length !== 0 || result.model !== options.requestedModel || result.modelProvider !== "openai" || result.serviceTier !== "default" || result.reasoningEffort !== options.requestedReasoningEffort || String(result.cwd || "") !== options.workspacePath || !Array.isArray(result.runtimeWorkspaceRoots) || result.runtimeWorkspaceRoots.length !== 0 || !Array.isArray(result.instructionSources) || result.instructionSources.length !== 0 || result.approvalPolicy !== "never" || result.approvalsReviewer !== "user" || sandbox?.type !== "readOnly" || sandbox.networkAccess !== false || permission?.id !== CODEX_INFERENCE_PERMISSION_PROFILE || permission.extends !== null) {
1967
+ throw new CodexAppServerError({
1968
+ message: "Codex thread isolation or effective settings were invalid.",
1969
+ category: "adapter",
1970
+ code: "invalid_thread_provenance",
1971
+ retryable: false
1972
+ });
1973
+ }
1974
+ this.threads.set(threadId, resolvedThreadPath);
1975
+ if (options.signal?.aborted || Date.now() >= options.deadlineAtMs) {
1976
+ await this.deleteThread(threadId);
1977
+ throw new CodexAppServerError({
1978
+ message: "Codex thread setup ended before inference dispatch.",
1979
+ category: options.signal?.aborted ? "cancelled" : "timeout",
1980
+ code: options.signal?.aborted ? "cancelled" : "deadline_exceeded",
1981
+ retryable: false
1982
+ });
1983
+ }
1984
+ return {
1985
+ threadId,
1986
+ threadPath: resolvedThreadPath,
1987
+ effectiveModel: options.requestedModel,
1988
+ effectiveReasoningEffort: options.requestedReasoningEffort
1989
+ };
1990
+ }
1991
+ async startAgentThread(options) {
1992
+ if (options.signal?.aborted || Date.now() >= options.deadlineAtMs) {
1993
+ throw new CodexAppServerError({
1994
+ message: "Codex Agent thread request was cancelled before dispatch.",
1995
+ category: options.signal?.aborted ? "cancelled" : "timeout",
1996
+ code: options.signal?.aborted ? "cancelled" : "deadline_exceeded",
1997
+ retryable: false
1998
+ });
1999
+ }
2000
+ const result = await this.request("thread/start", {
2001
+ model: options.requestedModel,
2002
+ modelProvider: "openai",
2003
+ allowProviderModelFallback: false,
2004
+ serviceTier: "default",
2005
+ cwd: options.workspacePath,
2006
+ runtimeWorkspaceRoots: [options.workspacePath],
2007
+ approvalPolicy: "never",
2008
+ permissions: CODEX_AGENT_PERMISSION_PROFILE,
2009
+ ephemeral: false,
2010
+ historyMode: "legacy",
2011
+ environments: [],
2012
+ dynamicTools: createCodexAgentToolSpecs(options.dataContract, options.decisionSchema),
2013
+ selectedCapabilityRoots: [],
2014
+ experimentalRawEvents: false,
2015
+ developerInstructions: options.systemPrompt,
2016
+ config: {
2017
+ model_reasoning_effort: options.requestedReasoningEffort,
2018
+ model_reasoning_summary: "none",
2019
+ show_raw_agent_reasoning: true,
2020
+ hide_agent_reasoning: false,
2021
+ web_search: "live",
2022
+ features: {
2023
+ apps: false,
2024
+ code_mode: true,
2025
+ code_mode_buffered_exec: false,
2026
+ code_mode_host: true,
2027
+ code_mode_only: false,
2028
+ in_app_browser: false,
2029
+ js_repl: false,
2030
+ js_repl_tools_only: false,
2031
+ multi_agent: false,
2032
+ multi_agent_v2: false,
2033
+ plugin_sharing: false,
2034
+ plugins: false,
2035
+ remote_plugin: false,
2036
+ shell_tool: false,
2037
+ skill_mcp_dependency_install: false,
2038
+ standalone_web_search: true,
2039
+ web_search_cached: false,
2040
+ web_search_request: true
2041
+ }
2042
+ }
2043
+ }, {
2044
+ timeoutMs: Math.max(1, options.deadlineAtMs - Date.now()),
2045
+ signal: options.signal
2046
+ });
2047
+ return this.validateAgentThreadReceipt(result, options, false);
2048
+ }
2049
+ async resumeAgentThread(options) {
2050
+ const expectedPath = resolve2(options.threadPath);
2051
+ const sessionsRoot = join2(resolve2(this.codexHome), "sessions");
2052
+ if (!options.threadId.trim() || !isAbsolute2(options.threadPath) || !expectedPath.startsWith(`${sessionsRoot}${sep}`) || !expectedPath.endsWith(".jsonl")) {
2053
+ throw new CodexAppServerError({
2054
+ message: "Codex Agent durable thread receipt was invalid.",
2055
+ category: "adapter",
2056
+ code: "invalid_agent_thread_receipt",
2057
+ retryable: false
2058
+ });
2059
+ }
2060
+ const result = await this.request("thread/resume", {
2061
+ threadId: options.threadId,
2062
+ model: options.requestedModel,
2063
+ modelProvider: "openai",
2064
+ serviceTier: "default",
2065
+ cwd: options.workspacePath,
2066
+ approvalPolicy: "never",
2067
+ permissions: CODEX_AGENT_PERMISSION_PROFILE,
2068
+ developerInstructions: options.systemPrompt,
2069
+ config: {
2070
+ model_reasoning_effort: options.requestedReasoningEffort,
2071
+ model_reasoning_summary: "none",
2072
+ web_search: "live"
2073
+ }
2074
+ }, {
2075
+ timeoutMs: Math.max(1, options.deadlineAtMs - Date.now()),
2076
+ signal: options.signal
2077
+ });
2078
+ const receipt = this.validateAgentThreadReceipt(result, options, true);
2079
+ if (receipt.threadId !== options.threadId || receipt.threadPath !== expectedPath) {
2080
+ throw new CodexAppServerError({
2081
+ message: "Codex Agent resumed a different durable thread.",
2082
+ category: "adapter",
2083
+ code: "agent_thread_identity_changed",
2084
+ retryable: false
2085
+ });
2086
+ }
2087
+ return receipt;
2088
+ }
2089
+ validateAgentThreadReceipt(result, options, resumed) {
2090
+ const thread = objectOrNull(result.thread);
2091
+ const permission = objectOrNull(result.activePermissionProfile);
2092
+ const sandbox = objectOrNull(result.sandbox);
2093
+ const threadId = String(thread?.id || "");
2094
+ const threadPath = String(thread?.path || "");
2095
+ const resolvedThreadPath = resolve2(threadPath);
2096
+ const sessionsRoot = join2(resolve2(this.codexHome), "sessions");
2097
+ if (!threadId || !threadPath || !isAbsolute2(threadPath) || !resolvedThreadPath.startsWith(`${sessionsRoot}${sep}`) || !resolvedThreadPath.endsWith(".jsonl") || thread?.ephemeral !== false || thread?.modelProvider !== "openai" || !Array.isArray(thread?.turns) || !resumed && thread.turns.length !== 0 || result.model !== options.requestedModel || result.modelProvider !== "openai" || result.serviceTier !== "default" || result.reasoningEffort !== options.requestedReasoningEffort || String(result.cwd || "") !== options.workspacePath || !Array.isArray(result.instructionSources) || result.instructionSources.length !== 0 || result.approvalPolicy !== "never" || result.approvalsReviewer !== "user" || sandbox?.type !== "readOnly" || sandbox.networkAccess !== false || permission?.id !== CODEX_AGENT_PERMISSION_PROFILE || permission.extends !== null) {
2098
+ throw new CodexAppServerError({
2099
+ message: "Codex Agent thread isolation or effective settings were invalid.",
2100
+ category: "adapter",
2101
+ code: "invalid_agent_thread_provenance",
2102
+ retryable: false
2103
+ });
2104
+ }
2105
+ this.threads.set(threadId, resolvedThreadPath);
2106
+ return {
2107
+ threadId,
2108
+ threadPath: resolvedThreadPath,
2109
+ effectiveModel: options.requestedModel,
2110
+ effectiveReasoningEffort: options.requestedReasoningEffort
2111
+ };
2112
+ }
2113
+ async executeTurn(request) {
2114
+ return await this.executeTurnWithPolicy(request, false);
2115
+ }
2116
+ async executeAgentTurn(request) {
2117
+ return await this.executeTurnWithPolicy(request, true);
2118
+ }
2119
+ async executeTurnWithPolicy(request, agentMode) {
2120
+ if (request.signal?.aborted || request.deadlineAtMs <= Date.now()) {
2121
+ throw new CodexAppServerError({
2122
+ message: "Codex turn was cancelled before dispatch.",
2123
+ category: request.signal?.aborted ? "cancelled" : "timeout",
2124
+ code: request.signal?.aborted ? "cancelled" : "deadline_exceeded",
2125
+ retryable: false
2126
+ });
2127
+ }
2128
+ let requestWritten = false;
2129
+ let requestId = null;
2130
+ let turnId = null;
2131
+ let rerouted = false;
2132
+ let rawResponseUsage = null;
2133
+ let threadUsage = null;
2134
+ let adapterResponseId = null;
2135
+ let firstTokenAt = null;
2136
+ let terminal = null;
2137
+ let completedReasoningObserved = false;
2138
+ let completedReasoningSequence = 0;
2139
+ const completedReasoningContent = /* @__PURE__ */ new Map();
2140
+ const agentToolCalls = [];
2141
+ const agentWebSearches = [];
2142
+ let terminalResolve;
2143
+ let terminalReject;
2144
+ const terminalPromise = new Promise((resolve3, reject) => {
2145
+ terminalResolve = resolve3;
2146
+ terminalReject = reject;
2147
+ });
2148
+ void terminalPromise.catch(() => void 0);
2149
+ const unsubscribeFatal = this.subscribeFatal((error) => {
2150
+ terminalReject(new CodexAppServerError({
2151
+ message: error.message,
2152
+ category: error.category,
2153
+ code: error.code,
2154
+ retryable: error.retryable,
2155
+ dispatchOutcome: requestWritten ? "outcome_unknown" : "not_dispatched",
2156
+ processExit: error.processExit,
2157
+ cause: error
2158
+ }));
2159
+ });
2160
+ const startedAt = Date.now();
2161
+ const unsubscribe = this.subscribe(({ method, params }) => {
2162
+ if (method === "thread/started") {
2163
+ const startedThread = objectOrNull(params.thread);
2164
+ if (!String(startedThread?.id || "")) {
2165
+ terminalReject(new CodexAppServerError({
2166
+ message: "Codex returned an invalid thread lifecycle notification.",
2167
+ category: "adapter",
2168
+ code: "invalid_thread_started_notification",
2169
+ retryable: false,
2170
+ dispatchOutcome: requestWritten ? turnId ? "confirmed_dispatched" : "outcome_unknown" : "not_dispatched"
2171
+ }));
2172
+ }
2173
+ return;
2174
+ }
2175
+ const eventThreadId = String(params.threadId || "");
2176
+ const scopedMethod = method.startsWith("thread/") || method.startsWith("turn/") || method.startsWith("item/") || method.startsWith("rawResponse") || method === "model/rerouted";
2177
+ if (eventThreadId && eventThreadId !== request.thread.threadId) {
2178
+ if (!this.threads.has(eventThreadId)) {
2179
+ terminalReject(new CodexAppServerError({
2180
+ message: "Codex notification crossed thread scope.",
2181
+ category: "adapter",
2182
+ code: "cross_thread_notification",
2183
+ retryable: false,
2184
+ dispatchOutcome: turnId ? "confirmed_dispatched" : "outcome_unknown"
2185
+ }));
2186
+ }
2187
+ return;
2188
+ }
2189
+ if (scopedMethod && !eventThreadId) {
2190
+ terminalReject(new CodexAppServerError({
2191
+ message: "Codex notification omitted its thread scope.",
2192
+ category: "adapter",
2193
+ code: "missing_thread_notification_scope",
2194
+ retryable: false,
2195
+ dispatchOutcome: requestWritten ? turnId ? "confirmed_dispatched" : "outcome_unknown" : "not_dispatched"
2196
+ }));
2197
+ return;
2198
+ }
2199
+ if (agentMode ? forbiddenAgentMethod(method) : forbiddenMethod(method)) {
2200
+ terminalReject(new CodexAppServerError({
2201
+ message: "Codex attempted to use forbidden child authority.",
2202
+ category: "adapter",
2203
+ code: "forbidden_child_authority",
2204
+ retryable: false,
2205
+ dispatchOutcome: turnId ? "confirmed_dispatched" : "outcome_unknown"
2206
+ }));
2207
+ return;
2208
+ }
2209
+ if (method === "model/rerouted") {
2210
+ rerouted = true;
2211
+ terminalReject(new CodexAppServerError({
2212
+ message: "Codex rerouted the requested model.",
2213
+ category: "model",
2214
+ code: "model_rerouted",
2215
+ retryable: false,
2216
+ dispatchOutcome: "confirmed_dispatched"
2217
+ }));
2218
+ return;
2219
+ }
2220
+ if (method === "thread/settings/updated") {
2221
+ const settings = objectOrNull(params.threadSettings);
2222
+ const permission = objectOrNull(settings?.activePermissionProfile);
2223
+ if (!settings || settings.model !== request.requestedModel || settings.modelProvider !== "openai" || settings.effort !== request.requestedReasoningEffort || settings.summary !== "none" || String(settings.cwd || "") !== request.workspacePath || settings.approvalPolicy !== "never" || permission?.id !== (agentMode ? CODEX_AGENT_PERMISSION_PROFILE : CODEX_INFERENCE_PERMISSION_PROFILE) || permission.extends !== null) {
2224
+ terminalReject(new CodexAppServerError({
2225
+ message: "Codex effective turn settings changed after dispatch.",
2226
+ category: "adapter",
2227
+ code: "effective_settings_changed",
2228
+ retryable: false,
2229
+ dispatchOutcome: turnId ? "confirmed_dispatched" : "outcome_unknown"
2230
+ }));
2231
+ return;
2232
+ }
2233
+ }
2234
+ const eventTurn = objectOrNull(params.turn);
2235
+ const eventTurnId = String(params.turnId || eventTurn?.id || "");
2236
+ if (eventTurnId && !eventThreadId) {
2237
+ terminalReject(new CodexAppServerError({
2238
+ message: "Codex turn notification omitted its thread scope.",
2239
+ category: "adapter",
2240
+ code: "missing_thread_notification_scope",
2241
+ retryable: false,
2242
+ dispatchOutcome: requestWritten ? turnId ? "confirmed_dispatched" : "outcome_unknown" : "not_dispatched"
2243
+ }));
2244
+ return;
2245
+ }
2246
+ const turnScopedMethod = method.startsWith("turn/") || method.startsWith("item/") || method.startsWith("rawResponse") || method === "model/rerouted";
2247
+ if (turnScopedMethod && !eventTurnId) {
2248
+ terminalReject(new CodexAppServerError({
2249
+ message: "Codex notification omitted its turn scope.",
2250
+ category: "adapter",
2251
+ code: "missing_turn_notification_scope",
2252
+ retryable: false,
2253
+ dispatchOutcome: requestWritten ? turnId ? "confirmed_dispatched" : "outcome_unknown" : "not_dispatched"
2254
+ }));
2255
+ return;
2256
+ }
2257
+ if (eventTurnId) {
2258
+ if (turnId && turnId !== eventTurnId) {
2259
+ terminalReject(new CodexAppServerError({
2260
+ message: "Codex notification crossed turn scope.",
2261
+ category: "adapter",
2262
+ code: "cross_turn_notification",
2263
+ retryable: false,
2264
+ dispatchOutcome: "confirmed_dispatched"
2265
+ }));
2266
+ return;
2267
+ }
2268
+ turnId = eventTurnId;
2269
+ }
2270
+ if (method === "item/agentMessage/delta" && String(params.delta || "").length > 0 && firstTokenAt === null) {
2271
+ firstTokenAt = Date.now();
2272
+ }
2273
+ if (method === "item/started" || method === "item/completed") {
2274
+ const item = objectOrNull(params.item);
2275
+ if (!item || (agentMode ? forbiddenAgentTerminalItem(item) : forbiddenTerminalItem(item))) {
2276
+ terminalReject(new CodexAppServerError({
2277
+ message: "Codex attempted forbidden tool activity.",
2278
+ category: "adapter",
2279
+ code: "forbidden_child_authority",
2280
+ retryable: false,
2281
+ dispatchOutcome: turnId ? "confirmed_dispatched" : "outcome_unknown"
2282
+ }));
2283
+ return;
2284
+ }
2285
+ if (method === "item/completed" && item.type === "reasoning") {
2286
+ completedReasoningObserved = true;
2287
+ const itemId = String(item.id || params.itemId || "").trim();
2288
+ const itemKey = itemId ? `id:${itemId}` : `sequence:${completedReasoningSequence++}`;
2289
+ completedReasoningContent.set(
2290
+ itemKey,
2291
+ Array.isArray(item.content) ? item.content : []
2292
+ );
2293
+ }
2294
+ if (agentMode && method === "item/completed" && item.type === "dynamicToolCall") {
2295
+ const tool = String(item.tool || "");
2296
+ const callArguments = objectOrNull(item.arguments);
2297
+ const callId = String(item.id || "").trim();
2298
+ if (!callId || !CODEX_AGENT_DYNAMIC_TOOLS.includes(tool) || !callArguments || typeof item.success !== "boolean") {
2299
+ terminalReject(new CodexAppServerError({
2300
+ message: "Codex Agent returned invalid dynamic-tool evidence.",
2301
+ category: "adapter",
2302
+ code: "invalid_dynamic_tool_evidence",
2303
+ retryable: false,
2304
+ dispatchOutcome: turnId ? "confirmed_dispatched" : "outcome_unknown"
2305
+ }));
2306
+ return;
2307
+ }
2308
+ agentToolCalls.push({
2309
+ callId,
2310
+ tool,
2311
+ arguments: callArguments,
2312
+ success: item.success
2313
+ });
2314
+ }
2315
+ if (agentMode && method === "item/completed" && item.type === "webSearch") {
2316
+ const query = typeof item.query === "string" ? item.query.trim() : "";
2317
+ if (!query) {
2318
+ terminalReject(new CodexAppServerError({
2319
+ message: "Codex Agent returned invalid web-search evidence.",
2320
+ category: "adapter",
2321
+ code: "invalid_web_search_evidence",
2322
+ retryable: false,
2323
+ dispatchOutcome: turnId ? "confirmed_dispatched" : "outcome_unknown"
2324
+ }));
2325
+ return;
2326
+ }
2327
+ agentWebSearches.push({ query, action: objectOrNull(item.action) });
2328
+ }
2329
+ }
2330
+ const observedUsage = usageFromNotification(method, params);
2331
+ if (method === "rawResponse/completed") {
2332
+ const responseId = String(params.responseId || "").trim();
2333
+ if (!responseId || !observedUsage || adapterResponseId !== null) {
2334
+ terminalReject(new CodexAppServerError({
2335
+ message: "Codex raw response evidence was invalid or ambiguous.",
2336
+ category: "adapter",
2337
+ code: "invalid_raw_response_evidence",
2338
+ retryable: false,
2339
+ dispatchOutcome: turnId ? "confirmed_dispatched" : "outcome_unknown"
2340
+ }));
2341
+ return;
2342
+ }
2343
+ adapterResponseId = responseId;
2344
+ rawResponseUsage = observedUsage;
2345
+ } else if (method === "thread/tokenUsage/updated" && observedUsage) {
2346
+ threadUsage = observedUsage;
2347
+ }
2348
+ if (method === "turn/completed" && eventTurn) {
2349
+ terminal = eventTurn;
2350
+ terminalResolve(eventTurn);
2351
+ }
2352
+ });
2353
+ if (agentMode) {
2354
+ if (this.agentToolHandlers.has(request.thread.threadId)) {
2355
+ unsubscribe();
2356
+ unsubscribeFatal();
2357
+ throw new CodexAppServerError({
2358
+ message: "Codex Agent thread already has an active turn.",
2359
+ category: "adapter",
2360
+ code: "agent_thread_turn_already_active",
2361
+ retryable: false
2362
+ });
2363
+ }
2364
+ this.agentToolHandlers.set(
2365
+ request.thread.threadId,
2366
+ {
2367
+ execute: request.executeTool,
2368
+ acceptTurnId: (candidate) => {
2369
+ if (turnId && turnId !== candidate) return false;
2370
+ turnId = candidate;
2371
+ return true;
2372
+ },
2373
+ calls: /* @__PURE__ */ new Map()
2374
+ }
2375
+ );
2376
+ }
2377
+ try {
2378
+ const remaining = () => Math.max(1, request.deadlineAtMs - Date.now());
2379
+ let startResult;
2380
+ try {
2381
+ startResult = await this.request("turn/start", {
2382
+ threadId: request.thread.threadId,
2383
+ input: [{ type: "text", text: request.userPrompt, text_elements: [] }],
2384
+ environments: [],
2385
+ cwd: request.workspacePath,
2386
+ runtimeWorkspaceRoots: [request.workspacePath],
2387
+ approvalPolicy: "never",
2388
+ permissions: agentMode ? CODEX_AGENT_PERMISSION_PROFILE : CODEX_INFERENCE_PERMISSION_PROFILE,
2389
+ model: request.requestedModel,
2390
+ serviceTier: "default",
2391
+ effort: request.requestedReasoningEffort,
2392
+ summary: "none",
2393
+ outputSchema: request.outputSchema
2394
+ }, {
2395
+ timeoutMs: remaining(),
2396
+ signal: request.signal,
2397
+ notAfterMs: "providerDispatchNotAfterMs" in request ? request.providerDispatchNotAfterMs : void 0,
2398
+ beforeWrite: async (id) => {
2399
+ requestId = id;
2400
+ try {
2401
+ await request.onDispatchState?.({
2402
+ requestId: String(id),
2403
+ turnId,
2404
+ dispatchOutcome: "outcome_unknown"
2405
+ });
2406
+ } catch (error) {
2407
+ throw new CodexAppServerError({
2408
+ message: "Codex pre-dispatch recovery evidence could not be persisted.",
2409
+ category: "adapter",
2410
+ code: "recovery_checkpoint_failed",
2411
+ retryable: false,
2412
+ dispatchOutcome: "not_dispatched",
2413
+ cause: error
2414
+ });
2415
+ }
2416
+ },
2417
+ onWritten: (id) => {
2418
+ requestWritten = true;
2419
+ requestId = id;
2420
+ if ("onProviderDispatch" in request) request.onProviderDispatch?.();
2421
+ }
2422
+ });
2423
+ } catch (error) {
2424
+ if (error instanceof CodexAppServerError && requestWritten) {
2425
+ throw new CodexAppServerError({
2426
+ message: error.message,
2427
+ category: error.category,
2428
+ code: error.code,
2429
+ retryable: error.retryable,
2430
+ dispatchOutcome: "outcome_unknown",
2431
+ processExit: error.processExit,
2432
+ cause: error
2433
+ });
2434
+ }
2435
+ throw error;
2436
+ }
2437
+ const startedTurn = objectOrNull(startResult.turn);
2438
+ const responseTurnId = String(startedTurn?.id || "");
2439
+ if (!responseTurnId || turnId && turnId !== responseTurnId) {
2440
+ throw new CodexAppServerError({
2441
+ message: "Codex turn start response was invalid.",
2442
+ category: "adapter",
2443
+ code: "invalid_turn_start",
2444
+ retryable: false,
2445
+ dispatchOutcome: "outcome_unknown"
2446
+ });
2447
+ }
2448
+ turnId = responseTurnId;
2449
+ try {
2450
+ await request.onDispatchState?.({
2451
+ requestId: String(requestId),
2452
+ turnId,
2453
+ dispatchOutcome: "confirmed_dispatched"
2454
+ });
2455
+ } catch (error) {
2456
+ try {
2457
+ await this.interrupt(request.thread.threadId, turnId, Math.min(5e3, remaining()));
2458
+ } catch {
2459
+ }
2460
+ throw new CodexAppServerError({
2461
+ message: "Codex confirmed-dispatch evidence could not be persisted.",
2462
+ category: "adapter",
2463
+ code: "recovery_checkpoint_failed",
2464
+ retryable: false,
2465
+ dispatchOutcome: "confirmed_dispatched",
2466
+ cause: error
2467
+ });
2468
+ }
2469
+ if (rerouted) {
2470
+ throw new CodexAppServerError({
2471
+ message: "Codex rerouted the requested model.",
2472
+ category: "model",
2473
+ code: "model_rerouted",
2474
+ retryable: false,
2475
+ dispatchOutcome: "confirmed_dispatched"
2476
+ });
2477
+ }
2478
+ let deadlineTimer = null;
2479
+ let abortHandler = null;
2480
+ const abortPromise = new Promise((_, reject) => {
2481
+ const abort = () => reject(new CodexAppServerError({
2482
+ message: "Codex turn was cancelled.",
2483
+ category: "cancelled",
2484
+ code: "cancelled",
2485
+ retryable: false,
2486
+ dispatchOutcome: "confirmed_dispatched"
2487
+ }));
2488
+ if (request.signal?.aborted) {
2489
+ abort();
2490
+ return;
2491
+ }
2492
+ abortHandler = abort;
2493
+ request.signal?.addEventListener("abort", abort, { once: true });
2494
+ });
2495
+ const deadlinePromise = new Promise((_, reject) => {
2496
+ deadlineTimer = setTimeout(() => reject(new CodexAppServerError({
2497
+ message: "Codex turn exceeded its immutable deadline.",
2498
+ category: "timeout",
2499
+ code: "deadline_exceeded",
2500
+ retryable: false,
2501
+ dispatchOutcome: "confirmed_dispatched"
2502
+ })), remaining());
2503
+ });
2504
+ try {
2505
+ try {
2506
+ terminal = terminal ?? await Promise.race([terminalPromise, abortPromise, deadlinePromise]);
2507
+ } catch (error) {
2508
+ try {
2509
+ await this.interrupt(request.thread.threadId, turnId, Math.min(5e3, remaining()));
2510
+ } catch {
2511
+ }
2512
+ throw error;
2513
+ }
2514
+ } finally {
2515
+ if (deadlineTimer) clearTimeout(deadlineTimer);
2516
+ if (request.signal && abortHandler) request.signal.removeEventListener("abort", abortHandler);
2517
+ }
2518
+ if (terminal.status !== "completed") {
2519
+ const turnError = objectOrNull(terminal.error);
2520
+ let failure = classifyCodexTurnFailure(
2521
+ turnError?.codexErrorInfo,
2522
+ String(terminal.status)
2523
+ );
2524
+ const observedUsage = threadUsage ?? rawResponseUsage;
2525
+ let retryAtMs = null;
2526
+ let observedRateLimits = null;
2527
+ if (failure.code === "quota_exceeded" || failure.httpStatusCode === 429) {
2528
+ const observedAtMs = Date.now();
2529
+ let accountLimitReached = failure.code === "quota_exceeded";
2530
+ try {
2531
+ const metadataDeadlineAtMs = Math.min(
2532
+ request.deadlineAtMs,
2533
+ observedAtMs + 5e3
2534
+ );
2535
+ if (metadataDeadlineAtMs <= observedAtMs) throw new Error("rate-limit deadline elapsed");
2536
+ observedRateLimits = await this.readAccountRateLimits(
2537
+ metadataDeadlineAtMs,
2538
+ request.signal
2539
+ );
2540
+ accountLimitReached = accountLimitReached || codexAccountRateLimitReached(observedRateLimits);
2541
+ retryAtMs = codexRateLimitRetryAtMs(observedRateLimits);
2542
+ } catch {
2543
+ }
2544
+ if (accountLimitReached) {
2545
+ failure = {
2546
+ ...failure,
2547
+ code: "quota_exceeded",
2548
+ category: "model",
2549
+ retryable: false
2550
+ };
2551
+ if (retryAtMs === null || retryAtMs <= observedAtMs) {
2552
+ retryAtMs = observedAtMs + DEFAULT_CODEX_QUOTA_COOLDOWN_MS;
2553
+ } else {
2554
+ retryAtMs = Math.min(
2555
+ retryAtMs,
2556
+ observedAtMs + MAX_CODEX_QUOTA_COOLDOWN_MS
2557
+ );
2558
+ }
2559
+ } else {
2560
+ retryAtMs = observedAtMs + CODEX_TRANSIENT_RATE_LIMIT_COOLDOWN_MS;
2561
+ }
2562
+ }
2563
+ throw new CodexAppServerError({
2564
+ message: "Codex turn did not complete successfully.",
2565
+ category: failure.category,
2566
+ code: failure.code,
2567
+ retryable: failure.retryable,
2568
+ dispatchOutcome: "confirmed_dispatched",
2569
+ httpStatusCode: failure.httpStatusCode,
2570
+ retryAtMs,
2571
+ usage: observedUsage,
2572
+ rateLimits: observedRateLimits
2573
+ });
2574
+ }
2575
+ const items = Array.isArray(terminal.items) ? terminal.items.map(objectOrNull) : [];
2576
+ if (items.some((item) => !item || (agentMode ? forbiddenAgentTerminalItem(item) : forbiddenTerminalItem(item)))) {
2577
+ throw new CodexAppServerError({
2578
+ message: "Codex terminal output contained forbidden tool activity.",
2579
+ category: "adapter",
2580
+ code: "forbidden_child_authority",
2581
+ retryable: false,
2582
+ dispatchOutcome: "confirmed_dispatched"
2583
+ });
2584
+ }
2585
+ const finalMessages = items.filter((item) => item?.type === "agentMessage" && item.phase === "final_answer");
2586
+ const fallbackMessages = items.filter((item) => item?.type === "agentMessage" && item.phase == null);
2587
+ const answerItem = finalMessages.at(-1) ?? fallbackMessages.at(-1);
2588
+ const text = typeof answerItem?.text === "string" ? answerItem.text : "";
2589
+ const reasoningContentSections = completedReasoningObserved ? [...completedReasoningContent.values()] : items.flatMap((item) => item?.type === "reasoning" && Array.isArray(item.content) ? [item.content] : []);
2590
+ const reasoningContentParts = reasoningContentSections.flatMap((content) => content.filter((part) => typeof part === "string" && part.trim().length > 0));
2591
+ const reasoningContentCandidate = reasoningContentParts.length > 0 ? reasoningContentParts.join("\n\n") : null;
2592
+ const reasoningContent = reasoningContentCandidate !== null && Buffer.byteLength(reasoningContentCandidate, "utf8") <= CODEX_REASONING_CONTENT_MAX_UTF8_BYTES ? reasoningContentCandidate : null;
2593
+ const usage = threadUsage ?? rawResponseUsage;
2594
+ const responseIdentity = adapterResponseId ?? turnId;
2595
+ if (!text || !usage || !responseIdentity) {
2596
+ throw new CodexAppServerError({
2597
+ message: !text ? "Codex returned no terminal answer." : !usage ? "Codex returned no valid token usage." : "Codex returned no response identity.",
2598
+ category: "adapter",
2599
+ code: !text ? "missing_terminal_answer" : !usage ? "missing_token_usage" : "missing_response_identity",
2600
+ retryable: false,
2601
+ dispatchOutcome: "confirmed_dispatched"
2602
+ });
2603
+ }
2604
+ const result = {
2605
+ text,
2606
+ reasoningContent,
2607
+ reasoningSummary: null,
2608
+ requestedModel: request.requestedModel,
2609
+ effectiveModel: request.thread.effectiveModel,
2610
+ requestedReasoningEffort: request.requestedReasoningEffort,
2611
+ effectiveReasoningEffort: request.thread.effectiveReasoningEffort,
2612
+ adapterRequestId: String(requestId),
2613
+ adapterResponseId: responseIdentity,
2614
+ usage,
2615
+ latencyMs: Math.max(0, Date.now() - startedAt),
2616
+ timeToFirstTokenMs: firstTokenAt === null ? null : Math.max(0, firstTokenAt - startedAt),
2617
+ terminalStatus: "completed"
2618
+ };
2619
+ return agentMode ? {
2620
+ ...result,
2621
+ toolCalls: agentToolCalls,
2622
+ webSearches: agentWebSearches
2623
+ } : result;
2624
+ } finally {
2625
+ if (agentMode) this.agentToolHandlers.delete(request.thread.threadId);
2626
+ unsubscribe();
2627
+ unsubscribeFatal();
2628
+ }
2629
+ }
2630
+ async interrupt(threadId, turnId, timeoutMs = 5e3) {
2631
+ const result = await this.request("turn/interrupt", { threadId, turnId }, { timeoutMs });
2632
+ if (Object.keys(result).length !== 0) {
2633
+ throw new CodexAppServerError({
2634
+ message: "Codex interrupt response was invalid.",
2635
+ category: "adapter",
2636
+ code: "invalid_interrupt_response",
2637
+ retryable: false,
2638
+ dispatchOutcome: "confirmed_dispatched"
2639
+ });
2640
+ }
2641
+ }
2642
+ async deleteThread(threadId) {
2643
+ const threadPath = this.threads.get(threadId);
2644
+ if (!threadPath) {
2645
+ throw new CodexAppServerError({
2646
+ message: "Codex thread cleanup identity was unavailable.",
2647
+ category: "adapter",
2648
+ code: "thread_cleanup_identity_missing",
2649
+ retryable: false
2650
+ });
2651
+ }
2652
+ const result = await this.request("thread/delete", { threadId }, { timeoutMs: 3e4 });
2653
+ if (Object.keys(result).length !== 0) {
2654
+ throw new CodexAppServerError({
2655
+ message: "Codex thread deletion was not confirmed.",
2656
+ category: "adapter",
2657
+ code: "thread_delete_unconfirmed",
2658
+ retryable: false
2659
+ });
2660
+ }
2661
+ const loaded = await this.request("thread/loaded/list", {}, { timeoutMs: 3e4 });
2662
+ const data = Array.isArray(loaded.data) ? loaded.data : null;
2663
+ if (data === null || loaded.nextCursor != null || data.some((item) => String(objectOrNull(item)?.id ?? item) === threadId)) {
2664
+ throw new CodexAppServerError({
2665
+ message: "Codex thread remained loaded after deletion.",
2666
+ category: "adapter",
2667
+ code: "thread_delete_unconfirmed",
2668
+ retryable: false
2669
+ });
2670
+ }
2671
+ try {
2672
+ await lstat2(threadPath);
2673
+ } catch (error) {
2674
+ if (error.code === "ENOENT") {
2675
+ this.threads.delete(threadId);
2676
+ return;
2677
+ }
2678
+ throw error;
2679
+ }
2680
+ throw new CodexAppServerError({
2681
+ message: "Codex persisted thread remained after deletion.",
2682
+ category: "adapter",
2683
+ code: "thread_delete_unconfirmed",
2684
+ retryable: false
2685
+ });
2686
+ }
2687
+ async close() {
2688
+ if (this.closed) return;
2689
+ this.closed = true;
2690
+ if (this.processCloseObserved || this.process.exitCode !== null) {
2691
+ if (this.guardian) {
2692
+ await rm2(`${this.guardian.receiptPath}.shutdown-intent`, { force: true }).catch(() => void 0);
2693
+ }
2694
+ return;
2695
+ }
2696
+ this.shutdownRequested = true;
2697
+ if (this.guardian) {
2698
+ await writeFile(
2699
+ `${this.guardian.receiptPath}.shutdown-intent`,
2700
+ this.guardian.processToken,
2701
+ { mode: 384 }
2702
+ ).catch(() => void 0);
2703
+ }
2704
+ this.process.stdin.end();
2705
+ const exited = await new Promise((resolve3) => {
2706
+ if (this.process.exitCode !== null) {
2707
+ resolve3(true);
2708
+ return;
2709
+ }
2710
+ const timer = setTimeout(() => resolve3(false), 5e3);
2711
+ this.process.once("close", () => {
2712
+ clearTimeout(timer);
2713
+ resolve3(true);
2714
+ });
2715
+ });
2716
+ if (exited) return;
2717
+ const pid = this.process.pid;
2718
+ try {
2719
+ if (pid && process.platform === "win32") await killWindowsProcessTree(pid);
2720
+ else if (pid) process.kill(-pid, "SIGTERM");
2721
+ else this.process.kill("SIGTERM");
2722
+ } catch {
2723
+ }
2724
+ const terminated = await new Promise((resolve3) => {
2725
+ const timer = setTimeout(() => resolve3(false), 1e3);
2726
+ this.process.once("close", () => {
2727
+ clearTimeout(timer);
2728
+ resolve3(true);
2729
+ });
2730
+ });
2731
+ if (!terminated) {
2732
+ try {
2733
+ if (pid && process.platform === "win32") await killWindowsProcessTree(pid);
2734
+ else if (pid) process.kill(-pid, "SIGKILL");
2735
+ else this.process.kill("SIGKILL");
2736
+ } catch {
2737
+ }
2738
+ await new Promise((resolve3) => {
2739
+ if (this.process.exitCode !== null) {
2740
+ resolve3();
2741
+ return;
2742
+ }
2743
+ const timer = setTimeout(resolve3, 1e3);
2744
+ this.process.once("close", () => {
2745
+ clearTimeout(timer);
2746
+ resolve3();
2747
+ });
2748
+ });
2749
+ if (this.process.exitCode === null) {
2750
+ throw new CodexAppServerError({
2751
+ message: "Codex process-tree cleanup could not be confirmed.",
2752
+ category: "adapter",
2753
+ code: "process_tree_cleanup_unconfirmed",
2754
+ retryable: false
2755
+ });
2756
+ }
2757
+ }
2758
+ }
2759
+ };
2760
+
2761
+ // lib/inference-host/managed-codex-wrapper.ts
2762
+ var object = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
2763
+ var nonnegative = (value) => Number.isSafeInteger(value) && Number(value) >= 0;
2764
+ var ManagedCodexWrapperFailure = class extends Error {
2765
+ constructor(code, dispatchOutcome) {
2766
+ super(code);
2767
+ this.dispatchOutcome = dispatchOutcome;
2768
+ }
2769
+ };
2770
+ async function runManagedCodexWrapper(binary) {
2771
+ if (!isAbsolute3(binary) || binary.includes("\0")) throw new ManagedCodexWrapperFailure("codex_binary_must_be_absolute", "not_dispatched");
2772
+ const host = createInterface2({ input: process.stdin, crlfDelay: Infinity });
2773
+ const frames = host[Symbol.asyncIterator]();
2774
+ const first = await frames.next();
2775
+ if (first.done) throw new ManagedCodexWrapperFailure("missing_turn", "not_dispatched");
2776
+ let turn;
2777
+ try {
2778
+ turn = object(JSON.parse(first.value));
2779
+ } catch {
2780
+ host.close();
2781
+ throw new ManagedCodexWrapperFailure("invalid_turn", "not_dispatched");
2782
+ }
2783
+ if (turn.schema_version !== "vtx_managed_harness_turn_v1" || turn.type !== "turn" || typeof turn.requested_model !== "string" || typeof turn.requested_reasoning_effort !== "string" || typeof turn.system_prompt !== "string" || typeof turn.user_prompt !== "string" || !Array.isArray(turn.data_contract)) {
2784
+ host.close();
2785
+ throw new ManagedCodexWrapperFailure("invalid_turn", "not_dispatched");
2786
+ }
2787
+ const deadline = Date.parse(String(turn.deadline_at));
2788
+ if (!Number.isFinite(deadline) || deadline <= Date.now()) {
2789
+ host.close();
2790
+ throw new ManagedCodexWrapperFailure("expired_turn", "not_dispatched");
2791
+ }
2792
+ const child = spawn3(binary, ["app-server", "--stdio"], {
2793
+ cwd: process.cwd(),
2794
+ env: process.env,
2795
+ shell: false,
2796
+ windowsHide: true,
2797
+ stdio: ["pipe", "pipe", "pipe"]
2798
+ });
2799
+ const nativeClosed = new Promise((resolve3) => {
2800
+ child.once("close", () => resolve3());
2801
+ });
2802
+ let nativeDispatchAttempted = false;
2803
+ let terminalError = null;
2804
+ const native = createInterface2({ input: child.stdout, crlfDelay: Infinity });
2805
+ child.stderr.on("data", () => void 0);
2806
+ const sendHost = (frame) => {
2807
+ process.stdout.write(`${JSON.stringify(frame)}
2808
+ `);
2809
+ };
2810
+ const sendNative = (frame) => {
2811
+ child.stdin.write(`${JSON.stringify(frame)}
2812
+ `);
2813
+ };
2814
+ let requestId = 0;
2815
+ const pending = /* @__PURE__ */ new Map();
2816
+ const tools = /* @__PURE__ */ new Map();
2817
+ let failed = null;
2818
+ let failTurn;
2819
+ const failure = new Promise((_resolve, reject) => {
2820
+ failTurn = reject;
2821
+ });
2822
+ void failure.catch(() => void 0);
2823
+ const fail = (code) => {
2824
+ if (failed) return;
2825
+ failed = new Error(code);
2826
+ for (const item of pending.values()) item.reject(failed);
2827
+ pending.clear();
2828
+ failTurn(failed);
2829
+ };
2830
+ const request = (method, params) => {
2831
+ if (failed) return Promise.reject(failed);
2832
+ const id = ++requestId;
2833
+ return new Promise((resolve3, reject) => {
2834
+ pending.set(id, { resolve: resolve3, reject });
2835
+ sendNative({ id, method, params });
2836
+ });
2837
+ };
2838
+ let threadId = null;
2839
+ let nativeTurnId = null;
2840
+ let nativeTurnRequestId = null;
2841
+ let nativeResponseId = null;
2842
+ let acknowledged = false;
2843
+ let finalText = "";
2844
+ let usage = null;
2845
+ let completed;
2846
+ const terminal = new Promise((resolve3) => {
2847
+ completed = resolve3;
2848
+ });
2849
+ const timer = setTimeout(() => fail("codex_deadline_exceeded"), deadline - Date.now());
2850
+ child.on("error", () => fail("codex_process_start_failed"));
2851
+ child.stdin.on("error", () => fail("codex_input_failed"));
2852
+ child.on("close", () => {
2853
+ if (!finalText) fail("codex_process_exited");
2854
+ });
2855
+ const scoped = (params) => !params.threadId || threadId === null || params.threadId === threadId;
2856
+ native.on("line", (line) => {
2857
+ try {
2858
+ const message = object(JSON.parse(line));
2859
+ if (typeof message.id === "number" && !message.method) {
2860
+ const waiter = pending.get(message.id);
2861
+ if (!waiter) {
2862
+ fail("codex_unknown_response");
2863
+ return;
2864
+ }
2865
+ pending.delete(message.id);
2866
+ if (message.error) waiter.reject(new Error("codex_request_failed"));
2867
+ else waiter.resolve(object(message.result));
2868
+ return;
2869
+ }
2870
+ const params = object(message.params);
2871
+ if (!scoped(params)) {
2872
+ fail("codex_thread_scope_changed");
2873
+ return;
2874
+ }
2875
+ if (message.method === "item/tool/call" && message.id !== void 0) {
2876
+ if (!acknowledged || !threadId || params.threadId !== threadId || typeof params.callId !== "string" || tools.has(params.callId) || !CODEX_AGENT_DYNAMIC_TOOLS.includes(params.tool) || nativeTurnId && params.turnId !== nativeTurnId || !(typeof message.id === "number" || typeof message.id === "string")) {
2877
+ fail("codex_invalid_tool_request");
2878
+ return;
2879
+ }
2880
+ tools.set(params.callId, message.id);
2881
+ sendHost({ type: "tool_call", call_id: params.callId, tool: params.tool, arguments: params.arguments });
2882
+ return;
2883
+ }
2884
+ if (message.id !== void 0) {
2885
+ fail("codex_interactive_request_required");
2886
+ return;
2887
+ }
2888
+ if (message.method === "model/rerouted") {
2889
+ fail("codex_model_rerouted");
2890
+ return;
2891
+ }
2892
+ if (message.method === "thread/settings/updated") {
2893
+ const settings = object(params.threadSettings);
2894
+ if (settings.model !== turn.requested_model || settings.effort !== turn.requested_reasoning_effort || settings.modelProvider !== "openai") {
2895
+ fail("codex_effective_selection_changed");
2896
+ return;
2897
+ }
2898
+ }
2899
+ if (message.method === "turn/started") {
2900
+ const started = object(params.turn);
2901
+ if (typeof started.id === "string") nativeTurnId = started.id;
2902
+ }
2903
+ if (message.method === "item/completed") {
2904
+ const item = object(params.item);
2905
+ if (item.type === "agentMessage" && typeof item.text === "string") finalText = item.text;
2906
+ }
2907
+ if (message.method === "thread/tokenUsage/updated") {
2908
+ const tokens = object(object(params.tokenUsage).last);
2909
+ const names = ["inputTokens", "cachedInputTokens", "outputTokens", "reasoningOutputTokens", "totalTokens"];
2910
+ if (!names.every((key) => nonnegative(tokens[key])) || Number(tokens.cachedInputTokens) > Number(tokens.inputTokens) || Number(tokens.reasoningOutputTokens) > Number(tokens.outputTokens) || Number(tokens.totalTokens) !== Number(tokens.inputTokens) + Number(tokens.outputTokens)) {
2911
+ fail("codex_usage_unavailable");
2912
+ return;
2913
+ }
2914
+ usage = Object.fromEntries(names.map((key) => [key, tokens[key]]));
2915
+ usage.cacheWriteInputTokens = null;
2916
+ usage.cacheWriteSupported = false;
2917
+ }
2918
+ if (message.method === "rawResponse/completed" && typeof params.responseId === "string") nativeResponseId = params.responseId;
2919
+ if (message.method === "turn/completed") {
2920
+ const result = object(params.turn);
2921
+ if (result.status !== "completed") {
2922
+ const info = object(result.error).codexErrorInfo;
2923
+ const categories = {
2924
+ contextWindowExceeded: "context_window_exceeded",
2925
+ sessionBudgetExceeded: "session_budget_exceeded",
2926
+ usageLimitExceeded: "usage_limit_exceeded",
2927
+ serverOverloaded: "server_overloaded",
2928
+ cyberPolicy: "policy_rejected",
2929
+ internalServerError: "internal_server_error",
2930
+ unauthorized: "unauthorized",
2931
+ badRequest: "bad_request",
2932
+ sandboxError: "sandbox_error",
2933
+ other: "other"
2934
+ };
2935
+ const category = typeof info === "string" ? categories[info] : [
2936
+ "httpConnectionFailed",
2937
+ "responseStreamConnectionFailed",
2938
+ "responseStreamDisconnected",
2939
+ "responseTooManyFailedAttempts"
2940
+ ].find((key) => key in object(info))?.replace(/[A-Z]/gu, (letter) => `_${letter.toLowerCase()}`);
2941
+ fail(`codex_turn_${category ?? "failed"}`);
2942
+ } else if (!nativeTurnId || result.id !== nativeTurnId) fail("codex_turn_identity_unverified");
2943
+ else completed();
2944
+ }
2945
+ } catch {
2946
+ fail("codex_protocol_invalid");
2947
+ }
2948
+ });
2949
+ try {
2950
+ await request("initialize", {
2951
+ clientInfo: { name: "vtx_managed_agent", version: "1" },
2952
+ capabilities: { experimentalApi: true }
2953
+ });
2954
+ sendNative({ method: "initialized", params: {} });
2955
+ let selected;
2956
+ let cursor;
2957
+ const seenCursors = /* @__PURE__ */ new Set();
2958
+ do {
2959
+ const catalog = await request("model/list", { ...cursor ? { cursor } : {} });
2960
+ selected = Array.isArray(catalog.data) ? catalog.data.map(object).find((model) => model.model === turn.requested_model || model.id === turn.requested_model) : void 0;
2961
+ cursor = typeof catalog.nextCursor === "string" && catalog.nextCursor ? catalog.nextCursor : void 0;
2962
+ if (cursor && seenCursors.has(cursor)) throw new Error("codex_catalog_cursor_repeated");
2963
+ if (cursor) seenCursors.add(cursor);
2964
+ } while (!selected && cursor);
2965
+ if (!selected || !Array.isArray(selected.supportedReasoningEfforts) || !selected.supportedReasoningEfforts.some((entry) => object(entry).reasoningEffort === turn.requested_reasoning_effort)) {
2966
+ throw new Error("codex_selection_not_available");
2967
+ }
2968
+ const threadParams = {
2969
+ model: turn.requested_model,
2970
+ modelProvider: "openai",
2971
+ allowProviderModelFallback: false,
2972
+ cwd: process.cwd(),
2973
+ developerInstructions: turn.system_prompt,
2974
+ config: { model_reasoning_effort: turn.requested_reasoning_effort }
2975
+ };
2976
+ const started = turn.resume_id ? await request("thread/resume", { ...threadParams, threadId: turn.resume_id }) : await request("thread/start", {
2977
+ ...threadParams,
2978
+ experimentalRawEvents: false,
2979
+ dynamicTools: createCodexAgentToolSpecs(turn.data_contract, object(turn.decision_schema))
2980
+ });
2981
+ const nativeThread = object(started.thread);
2982
+ if (started.model !== turn.requested_model || started.reasoningEffort !== turn.requested_reasoning_effort || started.modelProvider !== "openai" || typeof nativeThread.id !== "string" || turn.resume_id && nativeThread.id !== turn.resume_id) throw new Error("codex_thread_selection_unverified");
2983
+ threadId = nativeThread.id;
2984
+ sendHost({
2985
+ type: "thread_ready",
2986
+ resume_id: threadId,
2987
+ effective_model: started.model,
2988
+ effective_reasoning_effort: started.reasoningEffort
2989
+ });
2990
+ const ack = await Promise.race([frames.next(), failure]);
2991
+ if (ack.done) throw new Error("host_disconnected");
2992
+ const acknowledgement = object(JSON.parse(ack.value));
2993
+ if (acknowledgement.type !== "thread_ready" || acknowledgement.acknowledged !== true || acknowledgement.resume_id !== threadId) throw new Error("thread_not_checkpointed");
2994
+ acknowledged = true;
2995
+ const hostReplies = (async () => {
2996
+ while (true) {
2997
+ const next = await frames.next();
2998
+ if (next.done) return;
2999
+ const result = object(JSON.parse(next.value));
3000
+ const id = tools.get(String(result.call_id));
3001
+ if (result.type !== "tool_result" || id === void 0) {
3002
+ fail("host_tool_result_invalid");
3003
+ return;
3004
+ }
3005
+ tools.delete(String(result.call_id));
3006
+ sendNative({ id, result: {
3007
+ contentItems: [{ type: "inputText", text: JSON.stringify(result.value ?? null) }],
3008
+ success: result.success === true
3009
+ } });
3010
+ }
3011
+ })();
3012
+ void hostReplies.catch(() => fail("host_protocol_failed"));
3013
+ nativeTurnRequestId = requestId + 1;
3014
+ nativeDispatchAttempted = true;
3015
+ const begun = await request("turn/start", {
3016
+ threadId,
3017
+ input: [{ type: "text", text: turn.user_prompt, text_elements: [] }],
3018
+ model: turn.requested_model,
3019
+ effort: turn.requested_reasoning_effort,
3020
+ outputSchema: turn.output_schema
3021
+ });
3022
+ const returnedTurnId = object(begun.turn).id;
3023
+ if (typeof returnedTurnId !== "string" || nativeTurnId && returnedTurnId !== nativeTurnId) throw new Error("codex_turn_identity_unverified");
3024
+ nativeTurnId = returnedTurnId;
3025
+ await Promise.race([terminal, failure]);
3026
+ if (!usage) throw new Error("codex_usage_unavailable");
3027
+ if (!finalText) throw new Error("codex_final_text_unavailable");
3028
+ if (tools.size) throw new Error("codex_tool_outcome_unresolved");
3029
+ sendHost({
3030
+ type: "complete",
3031
+ text: finalText,
3032
+ requested_model: turn.requested_model,
3033
+ effective_model: started.model,
3034
+ requested_reasoning_effort: turn.requested_reasoning_effort,
3035
+ effective_reasoning_effort: started.reasoningEffort,
3036
+ adapter_request_id: String(nativeTurnRequestId),
3037
+ adapter_response_id: nativeResponseId ?? nativeTurnId,
3038
+ usage
3039
+ });
3040
+ } catch (error) {
3041
+ terminalError = error;
3042
+ } finally {
3043
+ clearTimeout(timer);
3044
+ host.close();
3045
+ native.close();
3046
+ child.stdin.end();
3047
+ child.kill("SIGTERM");
3048
+ const waitForClose = async () => {
3049
+ let timeout;
3050
+ try {
3051
+ return await Promise.race([
3052
+ nativeClosed.then(() => true),
3053
+ new Promise((resolve3) => {
3054
+ timeout = setTimeout(() => resolve3(false), 1e3);
3055
+ })
3056
+ ]);
3057
+ } finally {
3058
+ clearTimeout(timeout);
3059
+ }
3060
+ };
3061
+ let closed = await waitForClose();
3062
+ if (!closed) {
3063
+ child.kill("SIGKILL");
3064
+ closed = await waitForClose();
3065
+ }
3066
+ if (!closed) throw new ManagedCodexWrapperFailure("codex_teardown_unconfirmed", "outcome_unknown");
3067
+ }
3068
+ if (terminalError !== null) {
3069
+ const code = terminalError instanceof Error && /^[a-z_]{1,80}$/u.test(terminalError.message) ? terminalError.message : "native_terminal_evidence_unconfirmed";
3070
+ throw new ManagedCodexWrapperFailure(code, nativeDispatchAttempted ? "outcome_unknown" : "not_dispatched");
3071
+ }
3072
+ }
3073
+
3074
+ // bin/vtx-managed-codex.ts
3075
+ runManagedCodexWrapper(process.argv[2] ?? "").catch((error) => {
3076
+ const code = error instanceof Error && /^[a-z_]{1,80}$/u.test(error.message) ? error.message : "native_terminal_evidence_unconfirmed";
3077
+ process.stdout.write(`${JSON.stringify({
3078
+ type: "failed",
3079
+ code,
3080
+ ...error instanceof ManagedCodexWrapperFailure ? { dispatch_outcome: error.dispatchOutcome } : {}
3081
+ })}
3082
+ `);
3083
+ process.stderr.write(`VTX managed Codex turn failed: ${code}.
3084
+ `);
3085
+ process.exitCode = 1;
3086
+ });
3087
+ /*! Bundled license information:
3088
+
3089
+ smol-toml/dist/date.js:
3090
+ smol-toml/dist/error.js:
3091
+ smol-toml/dist/util.js:
3092
+ smol-toml/dist/primitive.js:
3093
+ smol-toml/dist/extract.js:
3094
+ smol-toml/dist/struct.js:
3095
+ smol-toml/dist/parse.js:
3096
+ smol-toml/dist/stringify.js:
3097
+ smol-toml/dist/index.js:
3098
+ (*!
3099
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
3100
+ * SPDX-License-Identifier: BSD-3-Clause
3101
+ *
3102
+ * Redistribution and use in source and binary forms, with or without
3103
+ * modification, are permitted provided that the following conditions are met:
3104
+ *
3105
+ * 1. Redistributions of source code must retain the above copyright notice, this
3106
+ * list of conditions and the following disclaimer.
3107
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
3108
+ * this list of conditions and the following disclaimer in the
3109
+ * documentation and/or other materials provided with the distribution.
3110
+ * 3. Neither the name of the copyright holder nor the names of its contributors
3111
+ * may be used to endorse or promote products derived from this software without
3112
+ * specific prior written permission.
3113
+ *
3114
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
3115
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3116
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3117
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3118
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3119
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3120
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
3121
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3122
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3123
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3124
+ *)
3125
+ */