patchwork-os 1.1.0-beta.4.canary.441 → 1.1.0-beta.4.canary.442
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/dist/drivers/codex/streamParser.d.ts +65 -0
- package/dist/drivers/codex/streamParser.js +38 -0
- package/dist/drivers/codex/streamParser.js.map +1 -0
- package/dist/drivers/codex/subprocess.d.ts +44 -0
- package/dist/drivers/codex/subprocess.js +261 -0
- package/dist/drivers/codex/subprocess.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shape of a parsed NDJSON event from `codex exec --json`.
|
|
3
|
+
*
|
|
4
|
+
* Event types confirmed via OpenAI's developer docs (developers.openai.com/
|
|
5
|
+
* codex/noninteractive, redirects to learn.chatgpt.com/docs/non-interactive-mode):
|
|
6
|
+
* thread.started, turn.started, turn.completed, turn.failed, item.started,
|
|
7
|
+
* item.completed, error. The final agent response text lives in an
|
|
8
|
+
* item.completed event whose item.type === "agent_message" — NOT at the
|
|
9
|
+
* top level of the event, unlike Claude's stream-json "result" event.
|
|
10
|
+
*
|
|
11
|
+
* The exact field shape of the `error` and `turn.failed` event types is not
|
|
12
|
+
* documented on the pages fetched — parseStreamLine defensively checks a few
|
|
13
|
+
* plausible field names (`message`, `error`) for both and falls back to
|
|
14
|
+
* stringifying the event so an error is never silently dropped even if the
|
|
15
|
+
* real field name differs.
|
|
16
|
+
*/
|
|
17
|
+
export interface CodexEvent {
|
|
18
|
+
type: "thread.started" | "turn.started" | "turn.completed" | "turn.failed" | "item.started" | "item.completed" | "error" | string;
|
|
19
|
+
/** Present on type === "thread.started". */
|
|
20
|
+
thread_id?: string;
|
|
21
|
+
/** Present on type === "turn.completed". */
|
|
22
|
+
usage?: {
|
|
23
|
+
input_tokens?: number;
|
|
24
|
+
cached_input_tokens?: number;
|
|
25
|
+
output_tokens?: number;
|
|
26
|
+
reasoning_output_tokens?: number;
|
|
27
|
+
};
|
|
28
|
+
/** Present on type === "item.started" / "item.completed". */
|
|
29
|
+
item?: {
|
|
30
|
+
id?: string;
|
|
31
|
+
type?: string;
|
|
32
|
+
command?: string;
|
|
33
|
+
status?: string;
|
|
34
|
+
/** Present when item.type === "agent_message" on a completed item. */
|
|
35
|
+
text?: string;
|
|
36
|
+
};
|
|
37
|
+
/** Field name unconfirmed for type === "error" — checked defensively. */
|
|
38
|
+
message?: string;
|
|
39
|
+
error?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface ParsedLine {
|
|
42
|
+
kind: "event";
|
|
43
|
+
event: CodexEvent;
|
|
44
|
+
/** Extracted response/error text for this event, "" if the event carries none. */
|
|
45
|
+
text: string;
|
|
46
|
+
}
|
|
47
|
+
export interface RawLine {
|
|
48
|
+
kind: "raw";
|
|
49
|
+
text: string;
|
|
50
|
+
}
|
|
51
|
+
export type ParsedStreamLine = ParsedLine | RawLine;
|
|
52
|
+
/**
|
|
53
|
+
* Parse a single NDJSON line from `codex exec --json`. Returns a raw line
|
|
54
|
+
* entry for non-JSON lines (defensive — mirrors the Claude parser's
|
|
55
|
+
* backward-compat handling for unexpected output).
|
|
56
|
+
*/
|
|
57
|
+
export declare function parseStreamLine(line: string): ParsedStreamLine;
|
|
58
|
+
/** Split a chunk into complete lines + a leftover partial. Identical logic to
|
|
59
|
+
* the Claude driver's splitLines (pure, format-agnostic) — kept as a local
|
|
60
|
+
* copy rather than a cross-driver import so codex/ has no dependency on
|
|
61
|
+
* claude/ internals. */
|
|
62
|
+
export declare function splitLines(buf: string, chunk: string): {
|
|
63
|
+
lines: string[];
|
|
64
|
+
remainder: string;
|
|
65
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a single NDJSON line from `codex exec --json`. Returns a raw line
|
|
3
|
+
* entry for non-JSON lines (defensive — mirrors the Claude parser's
|
|
4
|
+
* backward-compat handling for unexpected output).
|
|
5
|
+
*/
|
|
6
|
+
export function parseStreamLine(line) {
|
|
7
|
+
try {
|
|
8
|
+
const event = JSON.parse(line);
|
|
9
|
+
let text = "";
|
|
10
|
+
if (event.type === "item.completed" &&
|
|
11
|
+
event.item?.type === "agent_message") {
|
|
12
|
+
text = typeof event.item.text === "string" ? event.item.text : "";
|
|
13
|
+
}
|
|
14
|
+
else if (event.type === "error" || event.type === "turn.failed") {
|
|
15
|
+
text =
|
|
16
|
+
typeof event.message === "string"
|
|
17
|
+
? event.message
|
|
18
|
+
: typeof event.error === "string"
|
|
19
|
+
? event.error
|
|
20
|
+
: JSON.stringify(event);
|
|
21
|
+
}
|
|
22
|
+
return { kind: "event", event, text };
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return { kind: "raw", text: `${line}\n` };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** Split a chunk into complete lines + a leftover partial. Identical logic to
|
|
29
|
+
* the Claude driver's splitLines (pure, format-agnostic) — kept as a local
|
|
30
|
+
* copy rather than a cross-driver import so codex/ has no dependency on
|
|
31
|
+
* claude/ internals. */
|
|
32
|
+
export function splitLines(buf, chunk) {
|
|
33
|
+
const combined = buf + chunk;
|
|
34
|
+
const parts = combined.split("\n");
|
|
35
|
+
const remainder = parts.pop() ?? "";
|
|
36
|
+
return { lines: parts, remainder };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=streamParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamParser.js","sourceRoot":"","sources":["../../../src/drivers/codex/streamParser.ts"],"names":[],"mappings":"AA+DA;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAe,CAAC;QAC7C,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IACE,KAAK,CAAC,IAAI,KAAK,gBAAgB;YAC/B,KAAK,CAAC,IAAI,EAAE,IAAI,KAAK,eAAe,EACpC,CAAC;YACD,IAAI,GAAG,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAClE,IAAI;gBACF,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ;oBAC/B,CAAC,CAAC,KAAK,CAAC,OAAO;oBACf,CAAC,CAAC,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;wBAC/B,CAAC,CAAC,KAAK,CAAC,KAAK;wBACb,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC;IAC5C,CAAC;AACH,CAAC;AAED;;;wBAGwB;AACxB,MAAM,UAAU,UAAU,CACxB,GAAW,EACX,KAAa;IAEb,MAAM,QAAQ,GAAG,GAAG,GAAG,KAAK,CAAC;IAC7B,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;IACpC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ProviderDriver, ProviderTaskInput, ProviderTaskResult } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Scrub secrets from a string before storing or surfacing it. Same patterns
|
|
4
|
+
* as the Claude driver's scrubSecrets, plus an OpenAI-shaped API key pattern
|
|
5
|
+
* (sk-proj-.../sk-...) in case a user has OPENAI_API_KEY-based auth rather
|
|
6
|
+
* than the default ChatGPT-subscription login.
|
|
7
|
+
*/
|
|
8
|
+
export declare function scrubSecrets(text: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Codex subprocess driver — spawns `codex exec` with ChatGPT-subscription
|
|
11
|
+
* auth (whatever `codex login` already established; no API key handling
|
|
12
|
+
* here, mirroring how the Claude subprocess driver relies on `claude`'s own
|
|
13
|
+
* stored subscription auth rather than passing a credential itself).
|
|
14
|
+
*
|
|
15
|
+
* FAIL-CLOSED BY DEFAULT — this is a deliberate divergence from the Claude
|
|
16
|
+
* subprocess driver, whose default (no sandbox opt-in) is
|
|
17
|
+
* `--dangerously-skip-permissions` (fail-OPEN: full native tool access).
|
|
18
|
+
* Codex CLI's own non-interactive docs explicitly warn that `codex exec`
|
|
19
|
+
* does NOT default to something safe for unattended callers — every
|
|
20
|
+
* restrictive flag below is passed unconditionally unless a caller
|
|
21
|
+
* explicitly escalates via providerOptions:
|
|
22
|
+
*
|
|
23
|
+
* sandboxMode: "read-only" (default) | "workspace-write" | "danger-full-access"
|
|
24
|
+
* approvalMode: "never" (default) | "on-request" | "untrusted"
|
|
25
|
+
* networkAccess: false (default) — passed as `-c sandbox.network_access=false`
|
|
26
|
+
* webSearch: false (default) — omitting --search leaves Codex's own
|
|
27
|
+
* default ("cached"); NOT the same as fully disabled, but
|
|
28
|
+
* there is no documented flag to disable it outright as of
|
|
29
|
+
* this writing. Flagged here rather than silently assumed.
|
|
30
|
+
*
|
|
31
|
+
* Codex CLI's own cancellation has confirmed upstream bugs (orphaned MCP
|
|
32
|
+
* stdio subprocesses, shell-wrapper children surviving interrupt — see
|
|
33
|
+
* openai/codex issues #4337, #7985, #12491, #15379, #20869) — treeKill
|
|
34
|
+
* (process-group kill, not a direct-child-only kill()) is used from the
|
|
35
|
+
* start, not added later.
|
|
36
|
+
*/
|
|
37
|
+
export declare class CodexDriver implements ProviderDriver {
|
|
38
|
+
private readonly binary;
|
|
39
|
+
private readonly log;
|
|
40
|
+
readonly name = "codex";
|
|
41
|
+
constructor(binary: string, log: (msg: string) => void);
|
|
42
|
+
run(input: ProviderTaskInput): Promise<ProviderTaskResult>;
|
|
43
|
+
runOutcome(input: ProviderTaskInput): Promise<import("../types.js").ProviderTaskOutcome>;
|
|
44
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { treeKill } from "../../processTree.js";
|
|
3
|
+
import { ensureCmdShim } from "../../winShim.js";
|
|
4
|
+
import { sanitizeEnv } from "../claude/envSanitizer.js";
|
|
5
|
+
import { truncateToBytes, truncateUtf8Bytes } from "../outputCap.js";
|
|
6
|
+
import { toProviderTaskOutcome } from "../types.js";
|
|
7
|
+
import { parseStreamLine, splitLines } from "./streamParser.js";
|
|
8
|
+
const OUTPUT_CAP = 50 * 1024; // 50KB — matches the Claude subprocess driver's cap
|
|
9
|
+
/**
|
|
10
|
+
* Scrub secrets from a string before storing or surfacing it. Same patterns
|
|
11
|
+
* as the Claude driver's scrubSecrets, plus an OpenAI-shaped API key pattern
|
|
12
|
+
* (sk-proj-.../sk-...) in case a user has OPENAI_API_KEY-based auth rather
|
|
13
|
+
* than the default ChatGPT-subscription login.
|
|
14
|
+
*/
|
|
15
|
+
export function scrubSecrets(text) {
|
|
16
|
+
return text
|
|
17
|
+
.replace(/sk-(proj-)?[A-Za-z0-9_-]{20,}/g, "[REDACTED_API_KEY]")
|
|
18
|
+
.replace(/Bearer\s+[A-Za-z0-9._-]{16,}/gi, "Bearer [REDACTED]")
|
|
19
|
+
.replace(/\btoken[=:]\s*[A-Za-z0-9._-]{16,}/gi, "token=[REDACTED]");
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Codex subprocess driver — spawns `codex exec` with ChatGPT-subscription
|
|
23
|
+
* auth (whatever `codex login` already established; no API key handling
|
|
24
|
+
* here, mirroring how the Claude subprocess driver relies on `claude`'s own
|
|
25
|
+
* stored subscription auth rather than passing a credential itself).
|
|
26
|
+
*
|
|
27
|
+
* FAIL-CLOSED BY DEFAULT — this is a deliberate divergence from the Claude
|
|
28
|
+
* subprocess driver, whose default (no sandbox opt-in) is
|
|
29
|
+
* `--dangerously-skip-permissions` (fail-OPEN: full native tool access).
|
|
30
|
+
* Codex CLI's own non-interactive docs explicitly warn that `codex exec`
|
|
31
|
+
* does NOT default to something safe for unattended callers — every
|
|
32
|
+
* restrictive flag below is passed unconditionally unless a caller
|
|
33
|
+
* explicitly escalates via providerOptions:
|
|
34
|
+
*
|
|
35
|
+
* sandboxMode: "read-only" (default) | "workspace-write" | "danger-full-access"
|
|
36
|
+
* approvalMode: "never" (default) | "on-request" | "untrusted"
|
|
37
|
+
* networkAccess: false (default) — passed as `-c sandbox.network_access=false`
|
|
38
|
+
* webSearch: false (default) — omitting --search leaves Codex's own
|
|
39
|
+
* default ("cached"); NOT the same as fully disabled, but
|
|
40
|
+
* there is no documented flag to disable it outright as of
|
|
41
|
+
* this writing. Flagged here rather than silently assumed.
|
|
42
|
+
*
|
|
43
|
+
* Codex CLI's own cancellation has confirmed upstream bugs (orphaned MCP
|
|
44
|
+
* stdio subprocesses, shell-wrapper children surviving interrupt — see
|
|
45
|
+
* openai/codex issues #4337, #7985, #12491, #15379, #20869) — treeKill
|
|
46
|
+
* (process-group kill, not a direct-child-only kill()) is used from the
|
|
47
|
+
* start, not added later.
|
|
48
|
+
*/
|
|
49
|
+
export class CodexDriver {
|
|
50
|
+
binary;
|
|
51
|
+
log;
|
|
52
|
+
name = "codex";
|
|
53
|
+
constructor(binary, log) {
|
|
54
|
+
this.binary = binary;
|
|
55
|
+
this.log = log;
|
|
56
|
+
}
|
|
57
|
+
async run(input) {
|
|
58
|
+
const opts = input.providerOptions ?? {};
|
|
59
|
+
// Defense-in-depth: reject argv-confusable user-controlled strings.
|
|
60
|
+
// Spawn is called with an array (no shell), so this is argv defense for
|
|
61
|
+
// the child's flag parser, not shell-injection defense. Mirrors the
|
|
62
|
+
// Claude driver's identical guard.
|
|
63
|
+
if (input.prompt.startsWith("-")) {
|
|
64
|
+
throw new Error("[CodexDriver] prompt cannot start with '-' (argv injection guard)");
|
|
65
|
+
}
|
|
66
|
+
const effectiveBinary = ensureCmdShim(this.binary);
|
|
67
|
+
const sandboxMode = opts.sandboxMode === "workspace-write" ||
|
|
68
|
+
opts.sandboxMode === "danger-full-access"
|
|
69
|
+
? opts.sandboxMode
|
|
70
|
+
: "read-only";
|
|
71
|
+
const approvalMode = opts.approvalMode === "on-request" || opts.approvalMode === "untrusted"
|
|
72
|
+
? opts.approvalMode
|
|
73
|
+
: "never";
|
|
74
|
+
const networkAccess = opts.networkAccess === true;
|
|
75
|
+
const webSearch = opts.webSearch === true;
|
|
76
|
+
const args = [
|
|
77
|
+
"exec",
|
|
78
|
+
input.prompt,
|
|
79
|
+
"--json",
|
|
80
|
+
"--sandbox",
|
|
81
|
+
sandboxMode,
|
|
82
|
+
"--ask-for-approval",
|
|
83
|
+
approvalMode,
|
|
84
|
+
"--ignore-user-config",
|
|
85
|
+
"--ignore-rules",
|
|
86
|
+
"--skip-git-repo-check",
|
|
87
|
+
"--ephemeral",
|
|
88
|
+
"-c",
|
|
89
|
+
`sandbox.network_access=${networkAccess ? "true" : "false"}`,
|
|
90
|
+
];
|
|
91
|
+
if (webSearch)
|
|
92
|
+
args.push("--search");
|
|
93
|
+
// env sanitization: reuse the Claude driver's sanitizeEnv as-is (a
|
|
94
|
+
// generic cross-provider-secret strip with no Claude-specific coupling —
|
|
95
|
+
// see envSanitizer.ts's own doc comment). Codex's subscription auth
|
|
96
|
+
// lives in codex's own config/auth file, not an env var, so no
|
|
97
|
+
// `preserve` entry is needed for the default (subscription) auth path.
|
|
98
|
+
const env = sanitizeEnv(process.env);
|
|
99
|
+
this.log(`[CodexDriver] spawning: ${effectiveBinary} exec <prompt> (workspace: ${input.workspace}, sandbox: ${sandboxMode})`);
|
|
100
|
+
const child = spawn(effectiveBinary, args, {
|
|
101
|
+
cwd: input.workspace,
|
|
102
|
+
env,
|
|
103
|
+
signal: input.signal,
|
|
104
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
105
|
+
// setsid() — prevents subprocess from opening /dev/tty for interactive
|
|
106
|
+
// prompts, and makes it its own process-group leader for treeKill.
|
|
107
|
+
detached: true,
|
|
108
|
+
});
|
|
109
|
+
// Node's `signal` option calls `child.kill()` on abort, which only
|
|
110
|
+
// signals the immediate child — insufficient given Codex's confirmed
|
|
111
|
+
// upstream orphaned-child-process bugs (see class doc comment).
|
|
112
|
+
const onAbort = () => treeKill(child);
|
|
113
|
+
input.signal.addEventListener("abort", onAbort, { once: true });
|
|
114
|
+
child.once("close", () => {
|
|
115
|
+
input.signal.removeEventListener("abort", onAbort);
|
|
116
|
+
});
|
|
117
|
+
let lineBuf = "";
|
|
118
|
+
let accumulated = "";
|
|
119
|
+
let outputBytesSent = 0;
|
|
120
|
+
let firstAgentMessageAt;
|
|
121
|
+
let sawError = false;
|
|
122
|
+
let errorText = "";
|
|
123
|
+
let resultUsage;
|
|
124
|
+
const emitText = (text) => {
|
|
125
|
+
if (text.length === 0)
|
|
126
|
+
return;
|
|
127
|
+
accumulated += text;
|
|
128
|
+
if (outputBytesSent < OUTPUT_CAP) {
|
|
129
|
+
const { send, bytes } = truncateToBytes(text, OUTPUT_CAP - outputBytesSent);
|
|
130
|
+
if (bytes > 0) {
|
|
131
|
+
input.onChunk?.(send);
|
|
132
|
+
outputBytesSent += bytes;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
const handleLine = (line) => {
|
|
137
|
+
if (line.trim() === "")
|
|
138
|
+
return;
|
|
139
|
+
const parsed = parseStreamLine(line);
|
|
140
|
+
if (parsed.kind === "raw") {
|
|
141
|
+
emitText(parsed.text);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const { event, text } = parsed;
|
|
145
|
+
if (event.type === "item.completed" &&
|
|
146
|
+
event.item?.type === "agent_message") {
|
|
147
|
+
if (firstAgentMessageAt === undefined)
|
|
148
|
+
firstAgentMessageAt = Date.now();
|
|
149
|
+
emitText(text);
|
|
150
|
+
}
|
|
151
|
+
else if (event.type === "turn.completed") {
|
|
152
|
+
resultUsage = event.usage;
|
|
153
|
+
}
|
|
154
|
+
else if (event.type === "error" || event.type === "turn.failed") {
|
|
155
|
+
sawError = true;
|
|
156
|
+
errorText = text || errorText;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
child.stdout.setEncoding("utf-8");
|
|
160
|
+
child.stdout.on("data", (chunk) => {
|
|
161
|
+
const { lines, remainder } = splitLines(lineBuf, chunk);
|
|
162
|
+
lineBuf = remainder;
|
|
163
|
+
for (const line of lines)
|
|
164
|
+
handleLine(line);
|
|
165
|
+
});
|
|
166
|
+
let stderr = "";
|
|
167
|
+
child.stderr.setEncoding("utf-8");
|
|
168
|
+
child.stderr.on("data", (chunk) => {
|
|
169
|
+
if (Buffer.byteLength(stderr, "utf8") < OUTPUT_CAP) {
|
|
170
|
+
stderr += chunk;
|
|
171
|
+
if (Buffer.byteLength(stderr, "utf8") > OUTPUT_CAP) {
|
|
172
|
+
stderr = truncateUtf8Bytes(stderr, OUTPUT_CAP);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
const start = Date.now();
|
|
177
|
+
const stderrTailOf = (s) => s.length > 0 ? scrubSecrets(s.slice(-2048)) : undefined;
|
|
178
|
+
const startupMsOf = () => firstAgentMessageAt !== undefined
|
|
179
|
+
? firstAgentMessageAt - start
|
|
180
|
+
: undefined;
|
|
181
|
+
let startupTimedOut = false;
|
|
182
|
+
const startupHandle = input.startupTimeoutMs
|
|
183
|
+
? setTimeout(() => {
|
|
184
|
+
if (firstAgentMessageAt === undefined) {
|
|
185
|
+
startupTimedOut = true;
|
|
186
|
+
treeKill(child);
|
|
187
|
+
}
|
|
188
|
+
}, input.startupTimeoutMs)
|
|
189
|
+
: null;
|
|
190
|
+
let exitCode;
|
|
191
|
+
try {
|
|
192
|
+
exitCode = await new Promise((resolve, reject) => {
|
|
193
|
+
child.on("close", (code) => resolve(code ?? 0));
|
|
194
|
+
child.on("error", reject);
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
if (startupHandle)
|
|
199
|
+
clearTimeout(startupHandle);
|
|
200
|
+
const isAbort = (err instanceof Error && err.name === "AbortError") ||
|
|
201
|
+
input.signal.aborted;
|
|
202
|
+
if (isAbort) {
|
|
203
|
+
return {
|
|
204
|
+
text: truncateUtf8Bytes(accumulated, OUTPUT_CAP),
|
|
205
|
+
exitCode: -1,
|
|
206
|
+
durationMs: Date.now() - start,
|
|
207
|
+
stderrTail: stderrTailOf(stderr),
|
|
208
|
+
wasAborted: true,
|
|
209
|
+
startupMs: startupMsOf(),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
throw err;
|
|
213
|
+
}
|
|
214
|
+
if (startupHandle)
|
|
215
|
+
clearTimeout(startupHandle);
|
|
216
|
+
// Flush any partial line remaining in lineBuf after stdout closes —
|
|
217
|
+
// mirrors the Claude driver's identical flush-on-close handling.
|
|
218
|
+
if (lineBuf.trim().length > 0) {
|
|
219
|
+
handleLine(lineBuf);
|
|
220
|
+
lineBuf = "";
|
|
221
|
+
}
|
|
222
|
+
if (startupTimedOut) {
|
|
223
|
+
return {
|
|
224
|
+
text: truncateUtf8Bytes(accumulated, OUTPUT_CAP),
|
|
225
|
+
exitCode: -1,
|
|
226
|
+
durationMs: Date.now() - start,
|
|
227
|
+
stderrTail: stderrTailOf(stderr),
|
|
228
|
+
wasAborted: true,
|
|
229
|
+
startupTimedOut: true,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
const effectiveExitCode = sawError ? 1 : exitCode;
|
|
233
|
+
if (effectiveExitCode !== 0 && stderr) {
|
|
234
|
+
this.log(`[CodexDriver] stderr: ${stderr.slice(0, 500)}`);
|
|
235
|
+
}
|
|
236
|
+
const providerMeta = {};
|
|
237
|
+
if (typeof resultUsage?.input_tokens === "number" &&
|
|
238
|
+
typeof resultUsage?.output_tokens === "number") {
|
|
239
|
+
providerMeta.inputTokens = resultUsage.input_tokens;
|
|
240
|
+
providerMeta.outputTokens = resultUsage.output_tokens;
|
|
241
|
+
}
|
|
242
|
+
if (input.model && !input.model.startsWith("-")) {
|
|
243
|
+
providerMeta.model = input.model;
|
|
244
|
+
}
|
|
245
|
+
return {
|
|
246
|
+
text: truncateUtf8Bytes(sawError && accumulated.length === 0 ? errorText : accumulated, OUTPUT_CAP),
|
|
247
|
+
exitCode: effectiveExitCode,
|
|
248
|
+
errorMessage: sawError
|
|
249
|
+
? errorText || "codex exec reported an error"
|
|
250
|
+
: undefined,
|
|
251
|
+
durationMs: Date.now() - start,
|
|
252
|
+
stderrTail: stderrTailOf(stderr),
|
|
253
|
+
startupMs: startupMsOf(),
|
|
254
|
+
providerMeta: Object.keys(providerMeta).length > 0 ? providerMeta : undefined,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
async runOutcome(input) {
|
|
258
|
+
return toProviderTaskOutcome(await this.run(input));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=subprocess.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subprocess.js","sourceRoot":"","sources":["../../../src/drivers/codex/subprocess.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "patchwork-os",
|
|
3
|
-
"version": "1.1.0-beta.4.canary.
|
|
3
|
+
"version": "1.1.0-beta.4.canary.442",
|
|
4
4
|
"description": "Your personal AI runtime, local-first. Patchwork OS gives any AI model a consistent set of tools, YAML recipes, a delegation policy with approval queue, and a durable trace memory — all on your machine, all under your policy.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|