@atolis-hq/wake 0.3.62 → 0.3.63
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.
|
@@ -1,34 +1,82 @@
|
|
|
1
|
-
import {
|
|
2
|
-
// Agent CLIs can emit arbitrarily large machine-readable transcripts.
|
|
3
|
-
//
|
|
4
|
-
// below the resident's heap limit and surface the existing output-limit failure.
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
// Agent CLIs can emit arbitrarily large machine-readable transcripts. Capture
|
|
3
|
+
// raw bytes ourselves so overflow never enters a third-party string buffer.
|
|
5
4
|
const maximumCapturedProcessOutputBytes = 1024 * 1024;
|
|
6
5
|
export function runProcess(command, args, cwd, signal, timeoutMs) {
|
|
7
|
-
const child =
|
|
6
|
+
const child = spawn(command, args, {
|
|
8
7
|
...(cwd === undefined ? {} : { cwd }),
|
|
9
8
|
shell: false,
|
|
10
|
-
|
|
11
|
-
stdout: 'pipe',
|
|
12
|
-
stderr: 'pipe',
|
|
13
|
-
maxBuffer: maximumCapturedProcessOutputBytes,
|
|
14
|
-
cancelSignal: signal,
|
|
15
|
-
...(timeoutMs === undefined ? {} : { timeout: timeoutMs }),
|
|
16
|
-
reject: false,
|
|
17
|
-
stripFinalNewline: false,
|
|
9
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
18
10
|
});
|
|
11
|
+
const result = captureProcessOutput(child, signal, timeoutMs);
|
|
19
12
|
return {
|
|
20
|
-
result
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
timedOut: result.timedOut,
|
|
25
|
-
...(result.isMaxBuffer
|
|
26
|
-
? {
|
|
27
|
-
failureKind: 'output-limit',
|
|
28
|
-
...(result.shortMessage === undefined ? {} : { failureMessage: result.shortMessage }),
|
|
29
|
-
}
|
|
30
|
-
: {}),
|
|
31
|
-
})),
|
|
32
|
-
cancel: async () => void child.kill(),
|
|
13
|
+
result,
|
|
14
|
+
cancel: async () => {
|
|
15
|
+
terminate(child);
|
|
16
|
+
},
|
|
33
17
|
};
|
|
34
18
|
}
|
|
19
|
+
function captureProcessOutput(child, signal, timeoutMs) {
|
|
20
|
+
return new Promise((resolve) => {
|
|
21
|
+
const stdout = [];
|
|
22
|
+
const stderr = [];
|
|
23
|
+
let capturedBytes = 0;
|
|
24
|
+
let timedOut = false;
|
|
25
|
+
let overflowed = false;
|
|
26
|
+
let error;
|
|
27
|
+
const terminateForOverflow = () => {
|
|
28
|
+
overflowed = true;
|
|
29
|
+
child.stdout?.destroy();
|
|
30
|
+
child.stderr?.destroy();
|
|
31
|
+
terminate(child);
|
|
32
|
+
};
|
|
33
|
+
const capture = (destination) => (chunk) => {
|
|
34
|
+
if (overflowed)
|
|
35
|
+
return;
|
|
36
|
+
const remaining = maximumCapturedProcessOutputBytes - capturedBytes;
|
|
37
|
+
if (remaining <= 0 || chunk.length > remaining) {
|
|
38
|
+
if (remaining > 0)
|
|
39
|
+
destination.push(chunk.subarray(0, remaining));
|
|
40
|
+
capturedBytes = maximumCapturedProcessOutputBytes;
|
|
41
|
+
terminateForOverflow();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
destination.push(chunk);
|
|
45
|
+
capturedBytes += chunk.length;
|
|
46
|
+
};
|
|
47
|
+
child.stdout?.on('data', capture(stdout));
|
|
48
|
+
child.stderr?.on('data', capture(stderr));
|
|
49
|
+
const timeout = timeoutMs === undefined
|
|
50
|
+
? undefined
|
|
51
|
+
: setTimeout(() => {
|
|
52
|
+
timedOut = true;
|
|
53
|
+
terminate(child);
|
|
54
|
+
}, timeoutMs);
|
|
55
|
+
const onAbort = () => terminate(child);
|
|
56
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
57
|
+
child.once('error', (caught) => {
|
|
58
|
+
error = caught;
|
|
59
|
+
});
|
|
60
|
+
child.once('close', (exitCode) => {
|
|
61
|
+
if (timeout !== undefined)
|
|
62
|
+
clearTimeout(timeout);
|
|
63
|
+
signal.removeEventListener('abort', onAbort);
|
|
64
|
+
resolve({
|
|
65
|
+
stdout: Buffer.concat(stdout).toString('utf8'),
|
|
66
|
+
stderr: error?.message ?? Buffer.concat(stderr).toString('utf8'),
|
|
67
|
+
exitCode: exitCode ?? undefined,
|
|
68
|
+
timedOut,
|
|
69
|
+
...(overflowed
|
|
70
|
+
? {
|
|
71
|
+
failureKind: 'output-limit',
|
|
72
|
+
failureMessage: `Process output exceeded ${maximumCapturedProcessOutputBytes} bytes`,
|
|
73
|
+
}
|
|
74
|
+
: {}),
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function terminate(child) {
|
|
80
|
+
if (!child.killed && child.exitCode === null)
|
|
81
|
+
child.kill();
|
|
82
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atolis-hq/wake",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.63",
|
|
4
4
|
"description": "Local autonomous agent control plane for software development",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -73,7 +73,6 @@
|
|
|
73
73
|
"dependencies": {
|
|
74
74
|
"@octokit/rest": "^22.0.0",
|
|
75
75
|
"cron-parser": "^5.10.0",
|
|
76
|
-
"execa": "^10.0.1",
|
|
77
76
|
"handlebars": "^4.7.9",
|
|
78
77
|
"ulid": "^3.0.2",
|
|
79
78
|
"yaml": "^2.9.0",
|