@titan-design/agent 0.3.0 → 0.4.0
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.
- package/README.md +49 -3
- package/dist/index.d.ts +139 -122
- package/dist/index.js +293 -98
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/run.ts
|
|
2
2
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
3
|
-
import { toJSONSchema } from "zod";
|
|
3
|
+
import { toJSONSchema as toJSONSchema2 } from "zod";
|
|
4
4
|
|
|
5
5
|
// src/env.ts
|
|
6
6
|
var ANTI_NESTING_VARS = ["CLAUDECODE", "CLAUDE_CODE_SSE_PORT", "CLAUDE_CODE_ENTRYPOINT"];
|
|
@@ -64,7 +64,7 @@ function assertAuthEnvOk(env, options = {}) {
|
|
|
64
64
|
"pass the env through prepareEnv, or set allowApiKeyBilling to bill the API account on purpose"
|
|
65
65
|
);
|
|
66
66
|
}
|
|
67
|
-
if (!env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
67
|
+
if (options.requireOAuthToken !== false && !env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
68
68
|
throw new AuthMisconfiguredError(
|
|
69
69
|
"CLAUDE_CODE_OAUTH_TOKEN is not set; subscription auth will fail",
|
|
70
70
|
"run `claude setup-token` once and export the printed token"
|
|
@@ -84,6 +84,86 @@ function assertApiKeySourceAllowed(observed) {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
// src/claude-print.ts
|
|
88
|
+
import { spawn as spawn2 } from "child_process";
|
|
89
|
+
import { accessSync, constants, statSync } from "fs";
|
|
90
|
+
import { delimiter, join as join2 } from "path";
|
|
91
|
+
import { toJSONSchema } from "zod";
|
|
92
|
+
|
|
93
|
+
// src/codex-process.ts
|
|
94
|
+
import { execFile, spawn } from "child_process";
|
|
95
|
+
import { mkdtemp, rm, writeFile } from "fs/promises";
|
|
96
|
+
import { tmpdir } from "os";
|
|
97
|
+
import { join } from "path";
|
|
98
|
+
import { createInterface } from "readline";
|
|
99
|
+
async function inspectCodexVersion(executablePath, env, options) {
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
execFile(
|
|
102
|
+
executablePath,
|
|
103
|
+
["--version"],
|
|
104
|
+
{
|
|
105
|
+
env,
|
|
106
|
+
encoding: "utf8",
|
|
107
|
+
signal: options.signal,
|
|
108
|
+
timeout: Math.max(1, Math.ceil(options.timeoutMs)),
|
|
109
|
+
killSignal: "SIGKILL"
|
|
110
|
+
},
|
|
111
|
+
(error, stdout) => {
|
|
112
|
+
if (error) reject(error);
|
|
113
|
+
else resolve(stdout);
|
|
114
|
+
}
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
function startCodexProcess(input) {
|
|
119
|
+
const child = spawn(input.executablePath, input.args, {
|
|
120
|
+
cwd: input.cwd,
|
|
121
|
+
env: input.env,
|
|
122
|
+
detached: process.platform !== "win32",
|
|
123
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
124
|
+
});
|
|
125
|
+
return {
|
|
126
|
+
stdout: lines(child.stdout),
|
|
127
|
+
stderr: lines(child.stderr),
|
|
128
|
+
completed: completionOf(child),
|
|
129
|
+
terminate: (signal) => terminateProcessGroup(child, signal)
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
async function createCodexSchemaFile(schema) {
|
|
133
|
+
const directory = await mkdtemp(join(tmpdir(), "titan-codex-schema-"));
|
|
134
|
+
const path = join(directory, "output-schema.json");
|
|
135
|
+
try {
|
|
136
|
+
await writeFile(path, JSON.stringify(schema), { encoding: "utf8", mode: 384 });
|
|
137
|
+
return { path, dispose: () => rm(directory, { recursive: true, force: true }) };
|
|
138
|
+
} catch (error) {
|
|
139
|
+
await rm(directory, { recursive: true, force: true });
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async function* lines(stream) {
|
|
144
|
+
const reader = createInterface({ input: stream });
|
|
145
|
+
for await (const line of reader) yield line;
|
|
146
|
+
}
|
|
147
|
+
function completionOf(child) {
|
|
148
|
+
return new Promise((resolve, reject) => {
|
|
149
|
+
child.once("error", reject);
|
|
150
|
+
child.once("close", (exitCode, signal) => resolve({ exitCode, signal }));
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
function terminateProcessGroup(child, signal) {
|
|
154
|
+
if (child.pid && process.platform !== "win32") {
|
|
155
|
+
try {
|
|
156
|
+
process.kill(-child.pid, signal);
|
|
157
|
+
return;
|
|
158
|
+
} catch {
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
child.kill(signal);
|
|
163
|
+
} catch {
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
87
167
|
// src/failures.ts
|
|
88
168
|
var RATE_LIMIT_PATTERNS = [
|
|
89
169
|
/you'?ve hit your (session|weekly|opus|sonnet) limit/i,
|
|
@@ -146,18 +226,220 @@ function sumModelCost(modelUsage) {
|
|
|
146
226
|
return Object.values(modelUsage).reduce((total, m) => total + (m.costUSD ?? 0), 0);
|
|
147
227
|
}
|
|
148
228
|
|
|
229
|
+
// src/harness-contracts.ts
|
|
230
|
+
var CLAUDE_PRINT_UNSUPPORTED_OPTIONS = [
|
|
231
|
+
"allowedTools",
|
|
232
|
+
"disallowedTools",
|
|
233
|
+
"permissionMode",
|
|
234
|
+
"resumeSessionId",
|
|
235
|
+
"agents",
|
|
236
|
+
"mcpServers",
|
|
237
|
+
"hooks"
|
|
238
|
+
];
|
|
239
|
+
var CODEX_SANDBOXES = ["read-only", "workspace-write", "danger-full-access"];
|
|
240
|
+
var CODEX_APPROVAL_POLICIES = ["untrusted", "on-failure", "on-request", "never"];
|
|
241
|
+
var EXECUTION_CAPABILITIES = [
|
|
242
|
+
"fresh_run",
|
|
243
|
+
"resume",
|
|
244
|
+
"fork",
|
|
245
|
+
"structured_output",
|
|
246
|
+
"interactive_approvals",
|
|
247
|
+
"external_cancellation",
|
|
248
|
+
"semantic_interrupt",
|
|
249
|
+
"active_turn_steering",
|
|
250
|
+
"idle_turn_submission",
|
|
251
|
+
"persisted_transcript",
|
|
252
|
+
"process_reattachment",
|
|
253
|
+
"token_reporting"
|
|
254
|
+
];
|
|
255
|
+
|
|
256
|
+
// src/claude-print.ts
|
|
257
|
+
var CLAUDE_PRINT_KILL_GRACE_MS = 5e3;
|
|
258
|
+
var DEFAULT_TIMEOUT_MS = 6e5;
|
|
259
|
+
var EMPTY_MCP_CONFIG = '{"mcpServers":{}}';
|
|
260
|
+
var LOGIN_FAILURE = /not logged in|please run \/login|invalid api key/i;
|
|
261
|
+
function claudePrintCapabilities() {
|
|
262
|
+
const capabilities = Object.fromEntries(EXECUTION_CAPABILITIES.map((capability) => [capability, {
|
|
263
|
+
status: "unsupported",
|
|
264
|
+
reason: "claude -p runs one turn with no tools, hooks, MCP or resume"
|
|
265
|
+
}]));
|
|
266
|
+
capabilities.fresh_run = { status: "supported", evidence: "spawns claude -p --max-turns 1 per call" };
|
|
267
|
+
capabilities.structured_output = { status: "supported", evidence: "--json-schema, then a local zod parse" };
|
|
268
|
+
capabilities.external_cancellation = { status: "supported", evidence: "abort kills the child process group" };
|
|
269
|
+
capabilities.token_reporting = { status: "supported", evidence: "usage and modelUsage from the JSON result" };
|
|
270
|
+
return {
|
|
271
|
+
harness: "claude-print",
|
|
272
|
+
adapter: { name: "claude-print", version: "1" },
|
|
273
|
+
capabilities,
|
|
274
|
+
limits: [{ unit: "milliseconds", scope: "execution", enforcement: "hard", assessment: {
|
|
275
|
+
status: "supported",
|
|
276
|
+
evidence: "inactivityTimeoutMs is a wall deadline that kills the child process group"
|
|
277
|
+
} }]
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function assertClaudePrintConfig(config) {
|
|
281
|
+
const field = CLAUDE_PRINT_UNSUPPORTED_OPTIONS.find((name) => config[name] !== void 0) ?? (config.tools?.length ? "tools" : void 0) ?? (config.settingSources?.length ? "settingSources" : void 0);
|
|
282
|
+
if (field) throw new TypeError(`${field} is not supported by the claude-print harness (one turn, no tools, hooks or MCP)`);
|
|
283
|
+
}
|
|
284
|
+
function resolveClaudeBin(env) {
|
|
285
|
+
if (env.CLAUDE_BIN) return env.CLAUDE_BIN;
|
|
286
|
+
for (const dir of (env.PATH ?? "").split(delimiter)) {
|
|
287
|
+
if (dir && isExecutableFile(join2(dir, "claude"))) return join2(dir, "claude");
|
|
288
|
+
}
|
|
289
|
+
return void 0;
|
|
290
|
+
}
|
|
291
|
+
function isExecutableFile(path) {
|
|
292
|
+
try {
|
|
293
|
+
accessSync(path, constants.X_OK);
|
|
294
|
+
return statSync(path).isFile();
|
|
295
|
+
} catch {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
function buildClaudePrintArgs(config) {
|
|
300
|
+
const args = [
|
|
301
|
+
"-p",
|
|
302
|
+
"--output-format",
|
|
303
|
+
"json",
|
|
304
|
+
"--tools",
|
|
305
|
+
"",
|
|
306
|
+
"--strict-mcp-config",
|
|
307
|
+
"--mcp-config",
|
|
308
|
+
EMPTY_MCP_CONFIG,
|
|
309
|
+
"--setting-sources",
|
|
310
|
+
"",
|
|
311
|
+
"--max-turns",
|
|
312
|
+
"1",
|
|
313
|
+
"--max-budget-usd",
|
|
314
|
+
String(config.maxBudgetUsd)
|
|
315
|
+
];
|
|
316
|
+
if (config.model) args.push("--model", config.model);
|
|
317
|
+
if (config.systemPrompt !== void 0) args.push("--system-prompt", config.systemPrompt);
|
|
318
|
+
if (config.outputSchema) args.push("--json-schema", cliJsonSchema(config.outputSchema));
|
|
319
|
+
return args;
|
|
320
|
+
}
|
|
321
|
+
function cliJsonSchema(schema) {
|
|
322
|
+
const body = { ...toJSONSchema(schema) };
|
|
323
|
+
delete body.$schema;
|
|
324
|
+
return JSON.stringify(body);
|
|
325
|
+
}
|
|
326
|
+
async function runClaudePrint(config, env, clock) {
|
|
327
|
+
if (config.signal?.aborted) return { ok: false, failure: aborted(config.signal) };
|
|
328
|
+
const bin = resolveClaudeBin(env);
|
|
329
|
+
if (!bin) return { ok: false, failure: { kind: "runtime_error", reason: "claude binary not found on PATH; set CLAUDE_BIN" } };
|
|
330
|
+
const child = spawn2(bin, buildClaudePrintArgs(config), {
|
|
331
|
+
cwd: config.cwd,
|
|
332
|
+
env,
|
|
333
|
+
detached: process.platform !== "win32",
|
|
334
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
335
|
+
});
|
|
336
|
+
const outcome = await supervise(child, config);
|
|
337
|
+
return settle(outcome, config, clock.now() - clock.startedAt);
|
|
338
|
+
}
|
|
339
|
+
function supervise(child, config) {
|
|
340
|
+
const timeoutMs = config.inactivityTimeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
341
|
+
const output = collectOutput(child);
|
|
342
|
+
let ended;
|
|
343
|
+
const stop = (failure) => {
|
|
344
|
+
ended ??= failure;
|
|
345
|
+
terminateProcessGroup(child, "SIGTERM");
|
|
346
|
+
setTimeout(() => terminateProcessGroup(child, "SIGKILL"), CLAUDE_PRINT_KILL_GRACE_MS).unref();
|
|
347
|
+
};
|
|
348
|
+
const timer = setTimeout(() => stop({ kind: "inactivity_timeout", reason: `claude -p ran past ${timeoutMs}ms`, timeoutMs }), timeoutMs);
|
|
349
|
+
const onAbort = () => stop(aborted(config.signal));
|
|
350
|
+
config.signal?.addEventListener("abort", onAbort, { once: true });
|
|
351
|
+
child.stdin?.on("error", () => {
|
|
352
|
+
});
|
|
353
|
+
child.stdin?.end(config.prompt);
|
|
354
|
+
return new Promise((resolve) => {
|
|
355
|
+
const finish = (code, signal, spawnError) => {
|
|
356
|
+
clearTimeout(timer);
|
|
357
|
+
config.signal?.removeEventListener("abort", onAbort);
|
|
358
|
+
resolve({ code, signal, ...output(), ...spawnError ? { spawnError } : {}, ...ended ? { ended } : {} });
|
|
359
|
+
};
|
|
360
|
+
child.once("error", (error) => finish(null, null, error));
|
|
361
|
+
child.once("close", (code, signal) => finish(code, signal));
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
function collectOutput(child) {
|
|
365
|
+
const stdout = [];
|
|
366
|
+
const stderr = [];
|
|
367
|
+
child.stdout?.on("data", (chunk) => stdout.push(chunk));
|
|
368
|
+
child.stderr?.on("data", (chunk) => stderr.push(chunk));
|
|
369
|
+
return () => ({ stdout: Buffer.concat(stdout).toString("utf8"), stderr: Buffer.concat(stderr).toString("utf8") });
|
|
370
|
+
}
|
|
371
|
+
function settle(outcome, config, durationMs) {
|
|
372
|
+
if (outcome.ended) return { ok: false, failure: outcome.ended };
|
|
373
|
+
if (outcome.spawnError) return { ok: false, failure: { kind: "runtime_error", reason: `claude -p failed to start: ${outcome.spawnError.message}`, raw: outcome.spawnError } };
|
|
374
|
+
const result = parseResult(outcome.stdout);
|
|
375
|
+
if (!result) return { ok: false, failure: exitFailure(outcome, "printed no JSON result") };
|
|
376
|
+
config.onMessage?.(result);
|
|
377
|
+
const usage = usageFromResult(result, durationMs);
|
|
378
|
+
const failure = loginFailure(result) ?? classifyResult(result) ?? (outcome.code === 0 ? void 0 : exitFailure(outcome, "reported success"));
|
|
379
|
+
const sessionId = typeof result.session_id === "string" ? result.session_id : void 0;
|
|
380
|
+
if (failure) return { ok: false, failure, ...sessionId ? { sessionId } : {}, usage };
|
|
381
|
+
if (!sessionId) return { ok: false, failure: { kind: "runtime_error", reason: "the JSON result carried no session_id", raw: result }, usage };
|
|
382
|
+
const output = readOutput(result, config);
|
|
383
|
+
if ("failure" in output) return { ok: false, failure: output.failure, sessionId, usage };
|
|
384
|
+
return { ok: true, output: output.value, sessionId, usage, init: initFrom(result) };
|
|
385
|
+
}
|
|
386
|
+
function parseResult(stdout) {
|
|
387
|
+
try {
|
|
388
|
+
const parsed = JSON.parse(stdout);
|
|
389
|
+
const isResult = typeof parsed === "object" && parsed !== null && parsed.type === "result";
|
|
390
|
+
return isResult ? parsed : void 0;
|
|
391
|
+
} catch {
|
|
392
|
+
return void 0;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
function exitFailure(outcome, what) {
|
|
396
|
+
const exit = outcome.signal ? `signal ${outcome.signal}` : `code ${String(outcome.code)}`;
|
|
397
|
+
const stderr = outcome.stderr.trim();
|
|
398
|
+
return { kind: "runtime_error", reason: `claude -p exited with ${exit} and ${what}${stderr ? `: ${stderr}` : ""}`, raw: outcome };
|
|
399
|
+
}
|
|
400
|
+
function loginFailure(result) {
|
|
401
|
+
const text = result.subtype === "success" ? result.result : (result.errors ?? []).join("\n");
|
|
402
|
+
if (!result.is_error || !LOGIN_FAILURE.test(text)) return void 0;
|
|
403
|
+
return { kind: "auth_misconfigured", reason: text, hint: "run `claude` once interactively and /login", raw: result };
|
|
404
|
+
}
|
|
405
|
+
function readOutput(result, config) {
|
|
406
|
+
const text = result.subtype === "success" ? result.result : "";
|
|
407
|
+
if (!config.outputSchema) return { value: text };
|
|
408
|
+
const raw = (result.subtype === "success" ? result.structured_output : void 0) ?? parseJson(text);
|
|
409
|
+
const parsed = config.outputSchema.safeParse(raw);
|
|
410
|
+
if (parsed.success) return { value: parsed.data };
|
|
411
|
+
return { failure: { kind: "schema_invalid", reason: "structured output did not match the supplied schema", error: parsed.error, raw } };
|
|
412
|
+
}
|
|
413
|
+
function parseJson(text) {
|
|
414
|
+
try {
|
|
415
|
+
return JSON.parse(text);
|
|
416
|
+
} catch {
|
|
417
|
+
return void 0;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
function initFrom(result) {
|
|
421
|
+
const models = Object.keys(result.modelUsage ?? {});
|
|
422
|
+
return { apiKeySource: void 0, model: models.length === 1 ? models[0] : void 0, tools: [], permissionMode: void 0, claudeCodeVersion: void 0 };
|
|
423
|
+
}
|
|
424
|
+
function aborted(signal) {
|
|
425
|
+
return { kind: "aborted", reason: String(signal?.reason ?? "aborted by caller") };
|
|
426
|
+
}
|
|
427
|
+
|
|
149
428
|
// src/run.ts
|
|
150
429
|
var DEFAULT_INACTIVITY_MS = 6e5;
|
|
151
430
|
async function runAgent(config, deps = {}) {
|
|
152
431
|
assertBudgets(config);
|
|
432
|
+
if (config.harness === "claude-print") assertClaudePrintConfig(config);
|
|
153
433
|
const now = deps.now ?? Date.now;
|
|
154
434
|
const startedAt = now();
|
|
435
|
+
const print = config.harness === "claude-print";
|
|
155
436
|
const env = prepareEnv(deps.env ?? process.env, { allowApiKeyBilling: config.allowApiKeyBilling });
|
|
156
437
|
try {
|
|
157
|
-
assertAuthEnvOk(env, { allowApiKeyBilling: config.allowApiKeyBilling });
|
|
438
|
+
assertAuthEnvOk(env, { allowApiKeyBilling: config.allowApiKeyBilling, requireOAuthToken: !print });
|
|
158
439
|
} catch (error) {
|
|
159
440
|
return { ok: false, failure: authFailure(error) };
|
|
160
441
|
}
|
|
442
|
+
if (print) return runClaudePrint(config, env, { now, startedAt });
|
|
161
443
|
const session = new Session(config, env, deps);
|
|
162
444
|
try {
|
|
163
445
|
return await session.run(startedAt);
|
|
@@ -251,7 +533,7 @@ var Session = class {
|
|
|
251
533
|
if (c.mcpServers) options.mcpServers = c.mcpServers;
|
|
252
534
|
if (c.hooks) options.hooks = c.hooks;
|
|
253
535
|
if (c.outputSchema) {
|
|
254
|
-
options.outputFormat = { type: "json_schema", schema:
|
|
536
|
+
options.outputFormat = { type: "json_schema", schema: toJSONSchema2(c.outputSchema) };
|
|
255
537
|
}
|
|
256
538
|
return options;
|
|
257
539
|
}
|
|
@@ -348,24 +630,6 @@ function describeEnd(reason) {
|
|
|
348
630
|
return reason.kind === "aborted" ? reason.reason : `no message for ${reason.timeoutMs}ms`;
|
|
349
631
|
}
|
|
350
632
|
|
|
351
|
-
// src/harness-contracts.ts
|
|
352
|
-
var CODEX_SANDBOXES = ["read-only", "workspace-write", "danger-full-access"];
|
|
353
|
-
var CODEX_APPROVAL_POLICIES = ["untrusted", "on-failure", "on-request", "never"];
|
|
354
|
-
var EXECUTION_CAPABILITIES = [
|
|
355
|
-
"fresh_run",
|
|
356
|
-
"resume",
|
|
357
|
-
"fork",
|
|
358
|
-
"structured_output",
|
|
359
|
-
"interactive_approvals",
|
|
360
|
-
"external_cancellation",
|
|
361
|
-
"semantic_interrupt",
|
|
362
|
-
"active_turn_steering",
|
|
363
|
-
"idle_turn_submission",
|
|
364
|
-
"persisted_transcript",
|
|
365
|
-
"process_reattachment",
|
|
366
|
-
"token_reporting"
|
|
367
|
-
];
|
|
368
|
-
|
|
369
633
|
// src/preflight.ts
|
|
370
634
|
import { conversationRef } from "@titan-design/agent-protocol";
|
|
371
635
|
function preflightHarnessRun(request, descriptor) {
|
|
@@ -660,7 +924,7 @@ var CodexExecSession = class {
|
|
|
660
924
|
if (this.stopReason === "timeout") return this.failure(timeoutFailure(this.request.wallTimeMs));
|
|
661
925
|
if (this.stopReason === "abort") return this.failure(abortFailure(this.request.signal));
|
|
662
926
|
if (this.streamError) return this.failure(this.streamError);
|
|
663
|
-
if (exit.exitCode !== 0) return this.failure(
|
|
927
|
+
if (exit.exitCode !== 0) return this.failure(exitFailure2(exit, this.stderr));
|
|
664
928
|
return this.success();
|
|
665
929
|
}
|
|
666
930
|
success() {
|
|
@@ -811,7 +1075,7 @@ function cancelledUnknown(cause, request, exit) {
|
|
|
811
1075
|
native: { cause, requested, processExit: exit }
|
|
812
1076
|
};
|
|
813
1077
|
}
|
|
814
|
-
function
|
|
1078
|
+
function exitFailure2(exit, stderr) {
|
|
815
1079
|
return {
|
|
816
1080
|
kind: "runtime_error",
|
|
817
1081
|
reason: stderr.trim() || `Codex exited with status ${String(exit.exitCode)}`,
|
|
@@ -830,80 +1094,6 @@ function messageOf3(error) {
|
|
|
830
1094
|
return error instanceof Error ? error.message : String(error);
|
|
831
1095
|
}
|
|
832
1096
|
|
|
833
|
-
// src/codex-process.ts
|
|
834
|
-
import { execFile, spawn } from "child_process";
|
|
835
|
-
import { mkdtemp, rm, writeFile } from "fs/promises";
|
|
836
|
-
import { tmpdir } from "os";
|
|
837
|
-
import { join } from "path";
|
|
838
|
-
import { createInterface } from "readline";
|
|
839
|
-
async function inspectCodexVersion(executablePath, env, options) {
|
|
840
|
-
return new Promise((resolve, reject) => {
|
|
841
|
-
execFile(
|
|
842
|
-
executablePath,
|
|
843
|
-
["--version"],
|
|
844
|
-
{
|
|
845
|
-
env,
|
|
846
|
-
encoding: "utf8",
|
|
847
|
-
signal: options.signal,
|
|
848
|
-
timeout: Math.max(1, Math.ceil(options.timeoutMs)),
|
|
849
|
-
killSignal: "SIGKILL"
|
|
850
|
-
},
|
|
851
|
-
(error, stdout) => {
|
|
852
|
-
if (error) reject(error);
|
|
853
|
-
else resolve(stdout);
|
|
854
|
-
}
|
|
855
|
-
);
|
|
856
|
-
});
|
|
857
|
-
}
|
|
858
|
-
function startCodexProcess(input) {
|
|
859
|
-
const child = spawn(input.executablePath, input.args, {
|
|
860
|
-
cwd: input.cwd,
|
|
861
|
-
env: input.env,
|
|
862
|
-
detached: process.platform !== "win32",
|
|
863
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
864
|
-
});
|
|
865
|
-
return {
|
|
866
|
-
stdout: lines(child.stdout),
|
|
867
|
-
stderr: lines(child.stderr),
|
|
868
|
-
completed: completionOf(child),
|
|
869
|
-
terminate: (signal) => terminateProcessGroup(child, signal)
|
|
870
|
-
};
|
|
871
|
-
}
|
|
872
|
-
async function createCodexSchemaFile(schema) {
|
|
873
|
-
const directory = await mkdtemp(join(tmpdir(), "titan-codex-schema-"));
|
|
874
|
-
const path = join(directory, "output-schema.json");
|
|
875
|
-
try {
|
|
876
|
-
await writeFile(path, JSON.stringify(schema), { encoding: "utf8", mode: 384 });
|
|
877
|
-
return { path, dispose: () => rm(directory, { recursive: true, force: true }) };
|
|
878
|
-
} catch (error) {
|
|
879
|
-
await rm(directory, { recursive: true, force: true });
|
|
880
|
-
throw error;
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
async function* lines(stream) {
|
|
884
|
-
const reader = createInterface({ input: stream });
|
|
885
|
-
for await (const line of reader) yield line;
|
|
886
|
-
}
|
|
887
|
-
function completionOf(child) {
|
|
888
|
-
return new Promise((resolve, reject) => {
|
|
889
|
-
child.once("error", reject);
|
|
890
|
-
child.once("close", (exitCode, signal) => resolve({ exitCode, signal }));
|
|
891
|
-
});
|
|
892
|
-
}
|
|
893
|
-
function terminateProcessGroup(child, signal) {
|
|
894
|
-
if (child.pid && process.platform !== "win32") {
|
|
895
|
-
try {
|
|
896
|
-
process.kill(-child.pid, signal);
|
|
897
|
-
return;
|
|
898
|
-
} catch {
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
try {
|
|
902
|
-
child.kill(signal);
|
|
903
|
-
} catch {
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
|
|
907
1097
|
// src/codex-exec.ts
|
|
908
1098
|
var DEFAULT_CODEX_EXECUTABLE = "/Applications/ChatGPT.app/Contents/Resources/codex";
|
|
909
1099
|
var SUPPORTED_CODEX_EXEC_VERSION = "0.154.0-alpha.6.1";
|
|
@@ -1792,6 +1982,8 @@ export {
|
|
|
1792
1982
|
ANTI_NESTING_VARS,
|
|
1793
1983
|
AuthMisconfiguredError,
|
|
1794
1984
|
CLAUDE_CODE_PASSTHROUGH_VARS,
|
|
1985
|
+
CLAUDE_PRINT_KILL_GRACE_MS,
|
|
1986
|
+
CLAUDE_PRINT_UNSUPPORTED_OPTIONS,
|
|
1795
1987
|
CODEX_APPROVAL_POLICIES,
|
|
1796
1988
|
CODEX_SANDBOXES,
|
|
1797
1989
|
DEFAULT_CODEX_EXECUTABLE,
|
|
@@ -1806,9 +1998,11 @@ export {
|
|
|
1806
1998
|
SUPPORTED_CODEX_EXEC_VERSION,
|
|
1807
1999
|
assertApiKeySourceAllowed,
|
|
1808
2000
|
assertAuthEnvOk,
|
|
2001
|
+
buildClaudePrintArgs,
|
|
1809
2002
|
buildCodexExecArgs,
|
|
1810
2003
|
classifyResult,
|
|
1811
2004
|
claudeCodeCapabilities,
|
|
2005
|
+
claudePrintCapabilities,
|
|
1812
2006
|
codexExecCapabilities,
|
|
1813
2007
|
createClaudeCodeAdapter,
|
|
1814
2008
|
createCodexExecAdapter,
|
|
@@ -1817,6 +2011,7 @@ export {
|
|
|
1817
2011
|
preflightHarnessRun,
|
|
1818
2012
|
prepareCodexEnv,
|
|
1819
2013
|
prepareEnv,
|
|
2014
|
+
resolveClaudeBin,
|
|
1820
2015
|
runAgent,
|
|
1821
2016
|
sumModelCost,
|
|
1822
2017
|
usageFromResult
|