poe-code 3.0.266 → 3.0.267
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/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Readable, type Writable } from "node:stream";
|
|
2
2
|
import type { SpawnResult, SpawnUsage } from "../../agent-spawn/dist/index.js";
|
|
3
3
|
export type SpawnProcess = typeof import("node:child_process").spawn;
|
|
4
4
|
export type AgentChildProcessKind = "exec" | "execFile" | "spawn";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn as defaultSpawn } from "node:child_process";
|
|
2
|
+
import { PassThrough } from "node:stream";
|
|
2
3
|
import { StringDecoder } from "node:string_decoder";
|
|
3
4
|
export class AgentChildProcessError extends Error {
|
|
4
5
|
result;
|
|
@@ -9,7 +10,10 @@ export class AgentChildProcessError extends Error {
|
|
|
9
10
|
}
|
|
10
11
|
}
|
|
11
12
|
export async function exec(command, options) {
|
|
12
|
-
|
|
13
|
+
assertNonBlank(command, "command");
|
|
14
|
+
const shell = process.platform === "win32"
|
|
15
|
+
? (options?.env?.ComSpec ?? process.env.ComSpec ?? "cmd.exe")
|
|
16
|
+
: (options?.env?.SHELL ?? process.env.SHELL ?? "sh");
|
|
13
17
|
const shellArgs = process.platform === "win32" ? ["/d", "/s", "/c", command] : ["-c", command];
|
|
14
18
|
return runExecution({
|
|
15
19
|
kind: "exec",
|
|
@@ -21,6 +25,7 @@ export async function exec(command, options) {
|
|
|
21
25
|
});
|
|
22
26
|
}
|
|
23
27
|
export async function execFile(file, argsOrOptions = [], maybeOptions) {
|
|
28
|
+
assertNonBlank(file, "file");
|
|
24
29
|
const args = Array.isArray(argsOrOptions) ? argsOrOptions : [];
|
|
25
30
|
const options = Array.isArray(argsOrOptions) ? maybeOptions : argsOrOptions;
|
|
26
31
|
return runExecution({
|
|
@@ -33,10 +38,11 @@ export async function execFile(file, argsOrOptions = [], maybeOptions) {
|
|
|
33
38
|
});
|
|
34
39
|
}
|
|
35
40
|
export function spawn(file, argsOrOptions = [], maybeOptions) {
|
|
36
|
-
const args = Array.isArray(argsOrOptions) ? argsOrOptions : [];
|
|
37
|
-
const options = Array.isArray(argsOrOptions) ? maybeOptions : argsOrOptions;
|
|
38
41
|
let child;
|
|
39
42
|
try {
|
|
43
|
+
assertNonBlank(file, "file");
|
|
44
|
+
const args = Array.isArray(argsOrOptions) ? argsOrOptions : [];
|
|
45
|
+
const options = Array.isArray(argsOrOptions) ? maybeOptions : argsOrOptions;
|
|
40
46
|
child = startChildProcess({
|
|
41
47
|
kind: "spawn",
|
|
42
48
|
file,
|
|
@@ -59,8 +65,8 @@ export function spawn(file, argsOrOptions = [], maybeOptions) {
|
|
|
59
65
|
return {
|
|
60
66
|
pid: child.process.pid,
|
|
61
67
|
stdin: child.process.stdin,
|
|
62
|
-
stdout: child.
|
|
63
|
-
stderr: child.
|
|
68
|
+
stdout: child.stdout,
|
|
69
|
+
stderr: child.stderr,
|
|
64
70
|
kill(signal) {
|
|
65
71
|
return child.process.kill(signal);
|
|
66
72
|
},
|
|
@@ -72,8 +78,13 @@ async function runExecution(spec) {
|
|
|
72
78
|
}
|
|
73
79
|
function startChildProcess(spec) {
|
|
74
80
|
const child = spawnChild(spec);
|
|
75
|
-
const
|
|
76
|
-
|
|
81
|
+
const stdout = createOutputPipes(child.stdout, spec.kind === "spawn");
|
|
82
|
+
const stderr = createOutputPipes(child.stderr, spec.kind === "spawn");
|
|
83
|
+
const result = collectResult(child, spec, {
|
|
84
|
+
stdout: stdout.result,
|
|
85
|
+
stderr: stderr.result
|
|
86
|
+
}).then((commandResult) => applyExitPolicy(commandResult, spec.options));
|
|
87
|
+
return { process: child, stdout: stdout.user, stderr: stderr.user, result };
|
|
77
88
|
}
|
|
78
89
|
function spawnChild(spec) {
|
|
79
90
|
const options = spec.options;
|
|
@@ -89,22 +100,22 @@ function spawnChild(spec) {
|
|
|
89
100
|
function getStdio(kind) {
|
|
90
101
|
return kind === "spawn" ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"];
|
|
91
102
|
}
|
|
92
|
-
function collectResult(child, spec) {
|
|
103
|
+
function collectResult(child, spec, streams) {
|
|
93
104
|
const stdoutDecoder = new StringDecoder("utf8");
|
|
94
105
|
const stderrDecoder = new StringDecoder("utf8");
|
|
95
106
|
let stdout = "";
|
|
96
107
|
let stderr = "";
|
|
97
108
|
let childClosed = false;
|
|
98
|
-
let stdoutFinished =
|
|
99
|
-
let stderrFinished =
|
|
109
|
+
let stdoutFinished = streams.stdout === null;
|
|
110
|
+
let stderrFinished = streams.stderr === null;
|
|
100
111
|
let exitCode = 1;
|
|
101
112
|
let exitSignal = null;
|
|
102
113
|
let processError;
|
|
103
114
|
let outputError;
|
|
104
|
-
|
|
115
|
+
streams.stdout?.on("data", (chunk) => {
|
|
105
116
|
stdout += typeof chunk === "string" ? chunk : stdoutDecoder.write(chunk);
|
|
106
117
|
});
|
|
107
|
-
|
|
118
|
+
streams.stderr?.on("data", (chunk) => {
|
|
108
119
|
stderr += typeof chunk === "string" ? chunk : stderrDecoder.write(chunk);
|
|
109
120
|
});
|
|
110
121
|
return new Promise((resolve) => {
|
|
@@ -127,20 +138,20 @@ function collectResult(child, spec) {
|
|
|
127
138
|
});
|
|
128
139
|
resolve({ ...attempt, attempts: [attempt] });
|
|
129
140
|
};
|
|
130
|
-
|
|
141
|
+
streams.stdout?.once("end", () => {
|
|
131
142
|
stdoutFinished = true;
|
|
132
143
|
finish();
|
|
133
144
|
});
|
|
134
|
-
|
|
145
|
+
streams.stderr?.once("end", () => {
|
|
135
146
|
stderrFinished = true;
|
|
136
147
|
finish();
|
|
137
148
|
});
|
|
138
|
-
|
|
149
|
+
streams.stdout?.once("error", (error) => {
|
|
139
150
|
outputError = error;
|
|
140
151
|
stdoutFinished = true;
|
|
141
152
|
finish();
|
|
142
153
|
});
|
|
143
|
-
|
|
154
|
+
streams.stderr?.once("error", (error) => {
|
|
144
155
|
outputError = error;
|
|
145
156
|
stderrFinished = true;
|
|
146
157
|
finish();
|
|
@@ -161,6 +172,22 @@ function collectResult(child, spec) {
|
|
|
161
172
|
});
|
|
162
173
|
});
|
|
163
174
|
}
|
|
175
|
+
function createOutputPipes(source, exposeUserStream) {
|
|
176
|
+
if (source === null) {
|
|
177
|
+
return { result: null, user: null };
|
|
178
|
+
}
|
|
179
|
+
const result = new PassThrough();
|
|
180
|
+
const user = exposeUserStream ? new PassThrough() : null;
|
|
181
|
+
source.once("error", (error) => {
|
|
182
|
+
result.destroy(error);
|
|
183
|
+
user?.destroy();
|
|
184
|
+
});
|
|
185
|
+
source.pipe(result);
|
|
186
|
+
if (user !== null) {
|
|
187
|
+
source.pipe(user);
|
|
188
|
+
}
|
|
189
|
+
return { result, user };
|
|
190
|
+
}
|
|
164
191
|
function createAttempt(spec, output) {
|
|
165
192
|
return {
|
|
166
193
|
kind: spec.kind,
|
|
@@ -195,6 +222,14 @@ async function maybeRunAgent(result, options) {
|
|
|
195
222
|
cause: error
|
|
196
223
|
});
|
|
197
224
|
}
|
|
225
|
+
try {
|
|
226
|
+
validateExitPolicy(policy);
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
throw new AgentChildProcessError("Agent exit policy is invalid", result, {
|
|
230
|
+
cause: error
|
|
231
|
+
});
|
|
232
|
+
}
|
|
198
233
|
const runAgent = options.runAgent ?? defaultRunAgent;
|
|
199
234
|
let agentResult;
|
|
200
235
|
try {
|
|
@@ -225,6 +260,15 @@ async function maybeRunAgent(result, options) {
|
|
|
225
260
|
}
|
|
226
261
|
};
|
|
227
262
|
}
|
|
263
|
+
function validateExitPolicy(policy) {
|
|
264
|
+
assertNonBlank(policy.agent, "onExit.agent");
|
|
265
|
+
assertNonBlank(policy.prompt, "onExit.prompt");
|
|
266
|
+
}
|
|
267
|
+
function assertNonBlank(value, field) {
|
|
268
|
+
if (value.trim().length === 0) {
|
|
269
|
+
throw new TypeError(`${field} must not be empty`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
228
272
|
async function defaultRunAgent(input) {
|
|
229
273
|
const { spawn: spawnAgent } = await import("@poe-code/agent-spawn");
|
|
230
274
|
return spawnAgent(input.agent, {
|