@agentqueue/worker 0.0.0 → 0.3.1-ci.g02c90ca5cd192c5a75a7d1d19329683cefb22d6e
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 +159 -0
- package/THIRD_PARTY_NOTICES.md +27 -0
- package/dist/bin/aq-askpass.d.ts +2 -0
- package/dist/bin/aq-askpass.js +5 -0
- package/dist/bin/aq-askpass.js.map +1 -0
- package/dist/bin/aq.d.ts +2 -0
- package/dist/bin/aq.js +9 -0
- package/dist/bin/aq.js.map +1 -0
- package/dist/release.json +16 -0
- package/dist/src/app-server/checkpoint-codec.d.ts +4 -0
- package/dist/src/app-server/checkpoint-codec.js +31 -0
- package/dist/src/app-server/checkpoint-codec.js.map +1 -0
- package/dist/src/app-server/codex-token-snapshot.d.ts +11 -0
- package/dist/src/app-server/codex-token-snapshot.js +45 -0
- package/dist/src/app-server/codex-token-snapshot.js.map +1 -0
- package/dist/src/app-server/index.d.ts +70 -0
- package/dist/src/app-server/index.js +319 -0
- package/dist/src/app-server/index.js.map +1 -0
- package/dist/src/app-server/native-checkpoint.d.ts +12 -0
- package/dist/src/app-server/native-checkpoint.js +179 -0
- package/dist/src/app-server/native-checkpoint.js.map +1 -0
- package/dist/src/app-server/process-group.d.ts +6 -0
- package/dist/src/app-server/process-group.js +122 -0
- package/dist/src/app-server/process-group.js.map +1 -0
- package/dist/src/app-server/transports.d.ts +68 -0
- package/dist/src/app-server/transports.js +228 -0
- package/dist/src/app-server/transports.js.map +1 -0
- package/dist/src/app-server/worker-checkpoint.d.ts +15 -0
- package/dist/src/app-server/worker-checkpoint.js +76 -0
- package/dist/src/app-server/worker-checkpoint.js.map +1 -0
- package/dist/src/broker.d.ts +4 -0
- package/dist/src/broker.js +104 -0
- package/dist/src/broker.js.map +1 -0
- package/dist/src/cli.d.ts +14 -0
- package/dist/src/cli.js +212 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/client.d.ts +19 -0
- package/dist/src/client.js +116 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/codex-owner-auth.d.ts +14 -0
- package/dist/src/codex-owner-auth.js +155 -0
- package/dist/src/codex-owner-auth.js.map +1 -0
- package/dist/src/codex-runtime.d.ts +32 -0
- package/dist/src/codex-runtime.js +383 -0
- package/dist/src/codex-runtime.js.map +1 -0
- package/dist/src/completion-outbox.d.ts +38 -0
- package/dist/src/completion-outbox.js +90 -0
- package/dist/src/completion-outbox.js.map +1 -0
- package/dist/src/config.d.ts +16 -0
- package/dist/src/config.js +57 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/diagnostics.d.ts +3 -0
- package/dist/src/diagnostics.js +40 -0
- package/dist/src/diagnostics.js.map +1 -0
- package/dist/src/isolation.d.ts +34 -0
- package/dist/src/isolation.js +690 -0
- package/dist/src/isolation.js.map +1 -0
- package/dist/src/planning-dev/analysis-runtime.d.ts +6 -0
- package/dist/src/planning-dev/analysis-runtime.js +65 -0
- package/dist/src/planning-dev/analysis-runtime.js.map +1 -0
- package/dist/src/planning-dev/index.d.ts +35 -0
- package/dist/src/planning-dev/index.js +244 -0
- package/dist/src/planning-dev/index.js.map +1 -0
- package/dist/src/planning-dev/native-binary.d.ts +1 -0
- package/dist/src/planning-dev/native-binary.js +67 -0
- package/dist/src/planning-dev/native-binary.js.map +1 -0
- package/dist/src/planning-dev/protocol.d.ts +30 -0
- package/dist/src/planning-dev/protocol.js +43 -0
- package/dist/src/planning-dev/protocol.js.map +1 -0
- package/dist/src/planning-dev/runtime.d.ts +11 -0
- package/dist/src/planning-dev/runtime.js +437 -0
- package/dist/src/planning-dev/runtime.js.map +1 -0
- package/dist/src/process-lock.d.ts +4 -0
- package/dist/src/process-lock.js +44 -0
- package/dist/src/process-lock.js.map +1 -0
- package/dist/src/provider-status.d.ts +21 -0
- package/dist/src/provider-status.js +73 -0
- package/dist/src/provider-status.js.map +1 -0
- package/dist/src/readiness.d.ts +15 -0
- package/dist/src/readiness.js +145 -0
- package/dist/src/readiness.js.map +1 -0
- package/dist/src/register.d.ts +5 -0
- package/dist/src/register.js +178 -0
- package/dist/src/register.js.map +1 -0
- package/dist/src/runtime.d.ts +100 -0
- package/dist/src/runtime.js +2288 -0
- package/dist/src/runtime.js.map +1 -0
- package/dist/src/service.d.ts +11 -0
- package/dist/src/service.js +119 -0
- package/dist/src/service.js.map +1 -0
- package/dist/src/supervisor.d.ts +9 -0
- package/dist/src/supervisor.js +157 -0
- package/dist/src/supervisor.js.map +1 -0
- package/dist/src/turn-checkpoint.d.ts +58 -0
- package/dist/src/turn-checkpoint.js +314 -0
- package/dist/src/turn-checkpoint.js.map +1 -0
- package/dist/src/types.d.ts +168 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/usage-limit.d.ts +13 -0
- package/dist/src/usage-limit.js +75 -0
- package/dist/src/usage-limit.js.map +1 -0
- package/dist/src/version.d.ts +6 -0
- package/dist/src/version.js +49 -0
- package/dist/src/version.js.map +1 -0
- package/dist/src/worker-types.d.ts +12 -0
- package/dist/src/worker-types.js +2 -0
- package/dist/src/worker-types.js.map +1 -0
- package/package.json +56 -4
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
3
|
+
const groups = new WeakMap();
|
|
4
|
+
export function spawnProcessGroup(command, args, options, termination = {}) {
|
|
5
|
+
if (process.platform === "win32")
|
|
6
|
+
throw new Error("Core harness process groups require a POSIX host");
|
|
7
|
+
const child = spawn(command, args, { ...options, detached: true });
|
|
8
|
+
const closed = new Promise((resolve) => {
|
|
9
|
+
child.once("error", () => resolve());
|
|
10
|
+
child.once("close", () => resolve());
|
|
11
|
+
});
|
|
12
|
+
const group = { closed, graceMs: termination.graceMs ?? 2_000, killMs: termination.killMs ?? 2_000 };
|
|
13
|
+
groups.set(child, group);
|
|
14
|
+
child.once("exit", () => startStopping(child, group));
|
|
15
|
+
return child;
|
|
16
|
+
}
|
|
17
|
+
function signalGroup(pid, signal) {
|
|
18
|
+
try {
|
|
19
|
+
process.kill(-pid, signal);
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
if (error.code === "ESRCH")
|
|
24
|
+
return false;
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function groupRunning(pid) {
|
|
29
|
+
if (!signalGroup(pid, 0))
|
|
30
|
+
return false;
|
|
31
|
+
if (process.platform !== "linux")
|
|
32
|
+
return true;
|
|
33
|
+
for (let inspection = 0; inspection < 2; inspection++) {
|
|
34
|
+
for (const entry of readdirSync("/proc")) {
|
|
35
|
+
if (!/^\d+$/.test(entry))
|
|
36
|
+
continue;
|
|
37
|
+
let stat;
|
|
38
|
+
try {
|
|
39
|
+
stat = readFileSync(`/proc/${entry}/stat`, "utf8");
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (["ENOENT", "ESRCH", "EACCES"].includes(error.code ?? ""))
|
|
43
|
+
continue;
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
const [state, , group] = stat.slice(stat.lastIndexOf(")") + 2).split(" ");
|
|
47
|
+
if (Number(group) === pid && state !== "Z" && state !== "X")
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
async function waitForGroup(pid, deadline, group) {
|
|
54
|
+
let absentSince;
|
|
55
|
+
while (!group.gone) {
|
|
56
|
+
if (!signalGroup(pid, 0))
|
|
57
|
+
break;
|
|
58
|
+
if (groupRunning(pid)) {
|
|
59
|
+
absentSince = undefined;
|
|
60
|
+
if (Date.now() >= deadline())
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
absentSince ??= Date.now();
|
|
65
|
+
if (Date.now() - absentSince >= 100)
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
await sleep(25);
|
|
69
|
+
}
|
|
70
|
+
group.gone = true;
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
function startStopping(child, group) {
|
|
74
|
+
if (group.stopping)
|
|
75
|
+
return;
|
|
76
|
+
group.stopping = true;
|
|
77
|
+
if (child.pid && signalGroup(child.pid, "SIGTERM")) {
|
|
78
|
+
group.graceUntil ??= Date.now() + group.graceMs;
|
|
79
|
+
group.retiring = (async () => {
|
|
80
|
+
if (!(await waitForGroup(child.pid, () => group.graceUntil, group))) {
|
|
81
|
+
signalGroup(child.pid, "SIGKILL");
|
|
82
|
+
const killDeadline = Date.now() + group.killMs;
|
|
83
|
+
if (!(await waitForGroup(child.pid, () => killDeadline, group)))
|
|
84
|
+
throw new Error("Process group did not stop after SIGKILL");
|
|
85
|
+
}
|
|
86
|
+
})();
|
|
87
|
+
void group.retiring.catch(() => { });
|
|
88
|
+
}
|
|
89
|
+
else
|
|
90
|
+
group.gone = true;
|
|
91
|
+
}
|
|
92
|
+
export function closeProcessGroup(child, graceMs, killMs) {
|
|
93
|
+
const group = groups.get(child);
|
|
94
|
+
if (!group)
|
|
95
|
+
return Promise.reject(new Error("Process was not created as an owned process group"));
|
|
96
|
+
group.closing ??= (async () => {
|
|
97
|
+
group.graceUntil = Date.now() + (graceMs ?? group.graceMs);
|
|
98
|
+
group.killMs = killMs ?? group.killMs;
|
|
99
|
+
startStopping(child, group);
|
|
100
|
+
if (group.retiring)
|
|
101
|
+
await group.retiring;
|
|
102
|
+
await withTimeout(() => group.closed, group.killMs, "Process group stdio close");
|
|
103
|
+
})();
|
|
104
|
+
return group.closing;
|
|
105
|
+
}
|
|
106
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
107
|
+
async function withTimeout(start, ms, label) {
|
|
108
|
+
let timer;
|
|
109
|
+
try {
|
|
110
|
+
await Promise.race([
|
|
111
|
+
start(),
|
|
112
|
+
new Promise((_, reject) => {
|
|
113
|
+
timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);
|
|
114
|
+
timer.unref();
|
|
115
|
+
}),
|
|
116
|
+
]);
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
clearTimeout(timer);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=process-group.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-group.js","sourceRoot":"","sources":["../../../src/app-server/process-group.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { ChildProcess } from "node:child_process";
|
|
2
|
+
import type { TLSSocket } from "node:tls";
|
|
3
|
+
export interface AppServerTransport {
|
|
4
|
+
readonly ready: Promise<void>;
|
|
5
|
+
listen(message: (frame: string) => void, failure: (error: Error) => void): void;
|
|
6
|
+
write(frame: string): Promise<void>;
|
|
7
|
+
close(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export interface StdioOptions {
|
|
10
|
+
binaryPath: string;
|
|
11
|
+
cwd: string;
|
|
12
|
+
env?: NodeJS.ProcessEnv;
|
|
13
|
+
args?: string[];
|
|
14
|
+
expectedVersion?: string;
|
|
15
|
+
launch?: {
|
|
16
|
+
command: string;
|
|
17
|
+
args: string[];
|
|
18
|
+
};
|
|
19
|
+
maxFrameBytes?: number;
|
|
20
|
+
redactValues?: readonly string[];
|
|
21
|
+
}
|
|
22
|
+
export declare function stdioRedactions(options: StdioOptions): string[];
|
|
23
|
+
export declare function frameLimit(limit?: number): number;
|
|
24
|
+
export declare class StdioTransport implements AppServerTransport {
|
|
25
|
+
readonly process: ChildProcess;
|
|
26
|
+
readonly ready: Promise<void>;
|
|
27
|
+
private message;
|
|
28
|
+
private failure;
|
|
29
|
+
private readonly maxFrameBytes;
|
|
30
|
+
private pending;
|
|
31
|
+
private stderr;
|
|
32
|
+
private outputEnded;
|
|
33
|
+
private outputError;
|
|
34
|
+
private endTimer;
|
|
35
|
+
private closing;
|
|
36
|
+
constructor(options: StdioOptions);
|
|
37
|
+
listen(message: (frame: string) => void, failure: (error: Error) => void): void;
|
|
38
|
+
write(frame: string): Promise<void>;
|
|
39
|
+
close(): Promise<void>;
|
|
40
|
+
private endOutput;
|
|
41
|
+
private finishOutput;
|
|
42
|
+
private receive;
|
|
43
|
+
private deliver;
|
|
44
|
+
}
|
|
45
|
+
export interface WebSocketOptions {
|
|
46
|
+
url: string;
|
|
47
|
+
headers?: Record<string, string>;
|
|
48
|
+
tls?: {
|
|
49
|
+
ca: Buffer;
|
|
50
|
+
certificate: Buffer;
|
|
51
|
+
privateKey: Buffer;
|
|
52
|
+
servername: string;
|
|
53
|
+
};
|
|
54
|
+
socket?: TLSSocket;
|
|
55
|
+
connectTimeoutMs?: number;
|
|
56
|
+
maxFrameBytes?: number;
|
|
57
|
+
}
|
|
58
|
+
export declare class WebSocketTransport implements AppServerTransport {
|
|
59
|
+
readonly ready: Promise<void>;
|
|
60
|
+
private readonly socket;
|
|
61
|
+
private message;
|
|
62
|
+
private failure;
|
|
63
|
+
private closing;
|
|
64
|
+
constructor(options: WebSocketOptions);
|
|
65
|
+
listen(message: (frame: string) => void, failure: (error: Error) => void): void;
|
|
66
|
+
write(frame: string): Promise<void>;
|
|
67
|
+
close(): Promise<void>;
|
|
68
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import WebSocket from "ws";
|
|
3
|
+
import { closeProcessGroup, spawnProcessGroup } from "./process-group.js";
|
|
4
|
+
export function stdioRedactions(options) {
|
|
5
|
+
const environment = options.env ?? process.env;
|
|
6
|
+
return [
|
|
7
|
+
...(options.redactValues ?? []),
|
|
8
|
+
...["AWS_BEARER_TOKEN_BEDROCK", "OPENAI_API_KEY", "CODEX_ACCESS_TOKEN"].flatMap((name) => environment[name] ? [environment[name]] : []),
|
|
9
|
+
];
|
|
10
|
+
}
|
|
11
|
+
const DEFAULT_MAX_FRAME_BYTES = 16 * 1024 * 1024;
|
|
12
|
+
export function frameLimit(limit = DEFAULT_MAX_FRAME_BYTES) {
|
|
13
|
+
if (!Number.isSafeInteger(limit) || limit < 64 || limit > 64 * 1024 * 1024)
|
|
14
|
+
throw new Error("App Server frame limit must be between 64 bytes and 64 MiB");
|
|
15
|
+
return limit;
|
|
16
|
+
}
|
|
17
|
+
export class StdioTransport {
|
|
18
|
+
process;
|
|
19
|
+
ready;
|
|
20
|
+
message = () => { };
|
|
21
|
+
failure = () => { };
|
|
22
|
+
maxFrameBytes;
|
|
23
|
+
pending = Buffer.alloc(0);
|
|
24
|
+
stderr = "";
|
|
25
|
+
outputEnded = false;
|
|
26
|
+
outputError = Promise.withResolvers();
|
|
27
|
+
endTimer;
|
|
28
|
+
closing;
|
|
29
|
+
constructor(options) {
|
|
30
|
+
this.maxFrameBytes = frameLimit(options.maxFrameBytes);
|
|
31
|
+
if (options.expectedVersion) {
|
|
32
|
+
const version = spawnSync(options.binaryPath, ["--version"], {
|
|
33
|
+
cwd: options.cwd,
|
|
34
|
+
...(options.env ? { env: options.env } : {}),
|
|
35
|
+
encoding: "utf8",
|
|
36
|
+
timeout: 5000,
|
|
37
|
+
maxBuffer: 65536,
|
|
38
|
+
});
|
|
39
|
+
if (version.status !== 0 || version.stdout.trim() !== `codex-cli ${options.expectedVersion}`)
|
|
40
|
+
throw new Error("Codex binary does not match the expected official version");
|
|
41
|
+
}
|
|
42
|
+
this.process = spawnProcessGroup(options.launch?.command ?? options.binaryPath, options.launch?.args ?? ["app-server", ...(options.args ?? [])], {
|
|
43
|
+
cwd: options.cwd,
|
|
44
|
+
...(options.env ? { env: options.env } : {}),
|
|
45
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
46
|
+
});
|
|
47
|
+
this.ready = new Promise((resolve, reject) => {
|
|
48
|
+
this.process.once("spawn", resolve);
|
|
49
|
+
this.process.once("error", reject);
|
|
50
|
+
});
|
|
51
|
+
void this.ready.catch(() => { });
|
|
52
|
+
this.process.stdout.on("data", (chunk) => this.receive(chunk));
|
|
53
|
+
this.process.stdout.on("end", () => {
|
|
54
|
+
if (this.pending.length)
|
|
55
|
+
this.deliver(this.pending);
|
|
56
|
+
this.pending = Buffer.alloc(0);
|
|
57
|
+
this.endOutput("stdout ended");
|
|
58
|
+
});
|
|
59
|
+
this.process.stdout.on("error", () => this.endOutput("stdout failed"));
|
|
60
|
+
this.process.stdin.on("error", () => this.endOutput("stdin failed"));
|
|
61
|
+
this.process.stderr.setEncoding("utf8");
|
|
62
|
+
const secrets = stdioRedactions(options);
|
|
63
|
+
const capacity = 16384 + Math.max(0, ...secrets.map((value) => value.length));
|
|
64
|
+
this.process.stderr.on("data", (chunk) => {
|
|
65
|
+
let next = `${this.stderr}${chunk}`;
|
|
66
|
+
for (const secret of secrets)
|
|
67
|
+
if (secret)
|
|
68
|
+
next = next.replaceAll(secret, "[redacted]");
|
|
69
|
+
this.stderr = next.slice(-capacity);
|
|
70
|
+
});
|
|
71
|
+
this.process.once("error", () => this.failure(new Error("Codex app-server spawn failed")));
|
|
72
|
+
this.process.once("close", (code, signal) => {
|
|
73
|
+
this.finishOutput(new Error(`Codex app-server exited (${code ?? signal ?? "unknown"})${this.stderr ? `: ${this.stderr}` : ""}`));
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
listen(message, failure) {
|
|
77
|
+
this.message = message;
|
|
78
|
+
this.failure = failure;
|
|
79
|
+
}
|
|
80
|
+
async write(frame) {
|
|
81
|
+
await this.ready;
|
|
82
|
+
if (this.outputEnded)
|
|
83
|
+
throw await this.outputError.promise;
|
|
84
|
+
if (!this.process.stdin?.writable) {
|
|
85
|
+
this.endOutput("stdin is closed");
|
|
86
|
+
throw await this.outputError.promise;
|
|
87
|
+
}
|
|
88
|
+
await new Promise((resolve, reject) => this.process.stdin.write(`${frame}\n`, (error) => {
|
|
89
|
+
if (!error)
|
|
90
|
+
return resolve();
|
|
91
|
+
this.endOutput("stdin failed");
|
|
92
|
+
void this.outputError.promise.then(reject);
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
close() {
|
|
96
|
+
clearTimeout(this.endTimer);
|
|
97
|
+
this.outputError.resolve(new Error("Codex app-server is closed"));
|
|
98
|
+
this.pending = Buffer.alloc(0);
|
|
99
|
+
this.closing ??= closeProcessGroup(this.process);
|
|
100
|
+
return this.closing;
|
|
101
|
+
}
|
|
102
|
+
endOutput(reason) {
|
|
103
|
+
if (this.outputEnded)
|
|
104
|
+
return;
|
|
105
|
+
this.outputEnded = true;
|
|
106
|
+
this.endTimer = setTimeout(() => this.finishOutput(new Error(`Codex app-server ${reason}${this.stderr ? `: ${this.stderr}` : ""}`)), 250);
|
|
107
|
+
this.endTimer.unref();
|
|
108
|
+
}
|
|
109
|
+
finishOutput(error) {
|
|
110
|
+
clearTimeout(this.endTimer);
|
|
111
|
+
this.outputError.resolve(error);
|
|
112
|
+
this.failure(error);
|
|
113
|
+
}
|
|
114
|
+
receive(chunk) {
|
|
115
|
+
if (this.closing)
|
|
116
|
+
return;
|
|
117
|
+
this.pending = Buffer.concat([this.pending, chunk]);
|
|
118
|
+
let newline;
|
|
119
|
+
while ((newline = this.pending.indexOf(10)) >= 0) {
|
|
120
|
+
const frame = this.pending.subarray(0, newline);
|
|
121
|
+
this.pending = this.pending.subarray(newline + 1);
|
|
122
|
+
this.deliver(frame);
|
|
123
|
+
}
|
|
124
|
+
if (this.pending.length > this.maxFrameBytes)
|
|
125
|
+
this.failure(new Error("Codex app-server frame exceeds the byte limit"));
|
|
126
|
+
}
|
|
127
|
+
deliver(frame) {
|
|
128
|
+
if (frame.length > this.maxFrameBytes)
|
|
129
|
+
return this.failure(new Error("Codex app-server frame exceeds the byte limit"));
|
|
130
|
+
try {
|
|
131
|
+
this.message(new TextDecoder("utf-8", { fatal: true }).decode(frame));
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
this.failure(new Error("Codex app-server emitted invalid UTF-8"));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
export class WebSocketTransport {
|
|
139
|
+
ready;
|
|
140
|
+
socket;
|
|
141
|
+
message = () => { };
|
|
142
|
+
failure = () => { };
|
|
143
|
+
closing;
|
|
144
|
+
constructor(options) {
|
|
145
|
+
let url;
|
|
146
|
+
try {
|
|
147
|
+
url = new URL(options.url);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
throw new Error("Invalid App Server WebSocket URL");
|
|
151
|
+
}
|
|
152
|
+
const timeout = options.connectTimeoutMs ?? 10000;
|
|
153
|
+
if (!Number.isSafeInteger(timeout) || timeout < 1 || timeout > 120000)
|
|
154
|
+
throw new Error("Invalid App Server connection timeout");
|
|
155
|
+
const loopback = ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
|
|
156
|
+
if (url.username ||
|
|
157
|
+
url.password ||
|
|
158
|
+
url.hash ||
|
|
159
|
+
!["ws:", "wss:"].includes(url.protocol) ||
|
|
160
|
+
(url.protocol === "ws:" && !loopback))
|
|
161
|
+
throw new Error("App Server requires WSS remotely or loopback WS without URL credentials");
|
|
162
|
+
if (options.socket && (url.protocol !== "wss:" || !options.socket.encrypted || !options.socket.authorized))
|
|
163
|
+
throw new Error("App Server requires a verified TLS socket");
|
|
164
|
+
this.socket = new WebSocket(url, {
|
|
165
|
+
headers: options.headers,
|
|
166
|
+
...(options.socket ? { createConnection: () => options.socket } : {}),
|
|
167
|
+
...(options.tls
|
|
168
|
+
? {
|
|
169
|
+
ca: options.tls.ca,
|
|
170
|
+
cert: options.tls.certificate,
|
|
171
|
+
key: options.tls.privateKey,
|
|
172
|
+
servername: options.tls.servername,
|
|
173
|
+
rejectUnauthorized: true,
|
|
174
|
+
}
|
|
175
|
+
: {}),
|
|
176
|
+
maxPayload: frameLimit(options.maxFrameBytes),
|
|
177
|
+
handshakeTimeout: timeout,
|
|
178
|
+
perMessageDeflate: false,
|
|
179
|
+
followRedirects: false,
|
|
180
|
+
});
|
|
181
|
+
this.ready = new Promise((resolve, reject) => {
|
|
182
|
+
this.socket.once("open", resolve);
|
|
183
|
+
this.socket.once("error", () => reject(new Error("App Server WebSocket handshake failed")));
|
|
184
|
+
this.socket.once("close", () => reject(new Error("App Server WebSocket closed before connecting")));
|
|
185
|
+
});
|
|
186
|
+
void this.ready.catch(() => { });
|
|
187
|
+
this.socket.on("error", () => this.failure(new Error("App Server WebSocket failed")));
|
|
188
|
+
this.socket.on("close", (code) => this.failure(new Error(`App Server WebSocket closed (${code})`)));
|
|
189
|
+
this.socket.on("message", (data, binary) => {
|
|
190
|
+
if (binary)
|
|
191
|
+
return this.failure(new Error("App Server WebSocket emitted a binary frame"));
|
|
192
|
+
try {
|
|
193
|
+
this.message(new TextDecoder("utf-8", { fatal: true }).decode(Buffer.from(data)));
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
this.failure(new Error("App Server WebSocket emitted invalid UTF-8"));
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
listen(message, failure) {
|
|
201
|
+
this.message = message;
|
|
202
|
+
this.failure = failure;
|
|
203
|
+
}
|
|
204
|
+
async write(frame) {
|
|
205
|
+
await this.ready;
|
|
206
|
+
if (this.socket.readyState !== WebSocket.OPEN)
|
|
207
|
+
throw new Error("App Server WebSocket is closed");
|
|
208
|
+
await new Promise((resolve, reject) => this.socket.send(frame, (error) => (error ? reject(error) : resolve())));
|
|
209
|
+
}
|
|
210
|
+
close() {
|
|
211
|
+
this.closing ??= new Promise((resolve) => {
|
|
212
|
+
if (this.socket.readyState === WebSocket.CLOSED)
|
|
213
|
+
return resolve();
|
|
214
|
+
const timer = setTimeout(() => this.socket.terminate(), 1000);
|
|
215
|
+
timer.unref();
|
|
216
|
+
this.socket.once("close", () => {
|
|
217
|
+
clearTimeout(timer);
|
|
218
|
+
resolve();
|
|
219
|
+
});
|
|
220
|
+
if (this.socket.readyState === WebSocket.OPEN)
|
|
221
|
+
this.socket.close();
|
|
222
|
+
else
|
|
223
|
+
this.socket.terminate();
|
|
224
|
+
});
|
|
225
|
+
return this.closing;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=transports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transports.js","sourceRoot":"","sources":["../../../src/app-server/transports.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const WORKER_CODEX_VERSION = "0.166.0";
|
|
2
|
+
export declare const WORKER_CODEX_NATIVE_FORMAT = "qm-worker-codex.v1";
|
|
3
|
+
export declare const WORKER_CODEX_STATE = ".aq-codex";
|
|
4
|
+
export declare const WORKER_CODEX_FEATURES: readonly ["codexAppServerV1", "codexNativeV1"];
|
|
5
|
+
export declare function codexWorkspaceRootFeature(root: string, platform?: string): string;
|
|
6
|
+
export declare const CODEX_RESUMES_OLDER_FEATURE = "codexResumesOlderV1";
|
|
7
|
+
export declare function codexVersionFeature(version: string): string;
|
|
8
|
+
export declare function codexResumes(running: string, recorded: string): boolean;
|
|
9
|
+
export declare function codexCheckpointBinding(archive: string): Record<string, unknown> | null;
|
|
10
|
+
export type CodexCheckpointRequirement = {
|
|
11
|
+
codexVersion: string;
|
|
12
|
+
workspaceRootFeature: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function codexCheckpointRequirement(archive: string): CodexCheckpointRequirement | null;
|
|
15
|
+
export declare function featuresResumeCheckpoint(features: readonly string[] | undefined, requirement: CodexCheckpointRequirement): boolean;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { decodeCheckpoint } from "./checkpoint-codec.js";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
export const WORKER_CODEX_VERSION = "0.166.0";
|
|
5
|
+
export const WORKER_CODEX_NATIVE_FORMAT = "qm-worker-codex.v1";
|
|
6
|
+
export const WORKER_CODEX_STATE = ".aq-codex";
|
|
7
|
+
export const WORKER_CODEX_FEATURES = ["codexAppServerV1", "codexNativeV1"];
|
|
8
|
+
export function codexWorkspaceRootFeature(root, platform = process.platform) {
|
|
9
|
+
return `codexRoot:${createHash("sha256")
|
|
10
|
+
.update(JSON.stringify([platform, resolve(root)]))
|
|
11
|
+
.digest("hex")}`;
|
|
12
|
+
}
|
|
13
|
+
const CODEX_VERSION_FEATURE = "codexVersion:";
|
|
14
|
+
export const CODEX_RESUMES_OLDER_FEATURE = "codexResumesOlderV1";
|
|
15
|
+
const CODEX_RELEASE = /^(0|[1-9]\d{0,8})\.(0|[1-9]\d{0,8})\.(0|[1-9]\d{0,8})$/;
|
|
16
|
+
export function codexVersionFeature(version) {
|
|
17
|
+
return `${CODEX_VERSION_FEATURE}${version}`;
|
|
18
|
+
}
|
|
19
|
+
export function codexResumes(running, recorded) {
|
|
20
|
+
if (running === recorded)
|
|
21
|
+
return true;
|
|
22
|
+
const current = CODEX_RELEASE.exec(running);
|
|
23
|
+
const previous = CODEX_RELEASE.exec(recorded);
|
|
24
|
+
if (!current || !previous)
|
|
25
|
+
return false;
|
|
26
|
+
for (let part = 1; part <= 3; part++) {
|
|
27
|
+
const difference = Number(current[part]) - Number(previous[part]);
|
|
28
|
+
if (difference)
|
|
29
|
+
return difference > 0;
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
export function codexCheckpointBinding(archive) {
|
|
34
|
+
const entries = decodeCheckpoint(archive);
|
|
35
|
+
const bindings = entries.filter((entry) => entry?.path === `${WORKER_CODEX_STATE}/qm-thread.json`);
|
|
36
|
+
if (!bindings.length)
|
|
37
|
+
return null;
|
|
38
|
+
const entry = bindings[0];
|
|
39
|
+
if (!entry ||
|
|
40
|
+
bindings.length !== 1 ||
|
|
41
|
+
entry.type !== "file" ||
|
|
42
|
+
typeof entry.data !== "string" ||
|
|
43
|
+
entry.data.length > 32768)
|
|
44
|
+
throw new Error("Native worker checkpoint binding is invalid");
|
|
45
|
+
const binding = JSON.parse(Buffer.from(entry.data, "base64").toString("utf8"));
|
|
46
|
+
if (binding.format !== WORKER_CODEX_NATIVE_FORMAT ||
|
|
47
|
+
typeof binding.codexVersion !== "string" ||
|
|
48
|
+
!/^[0-9A-Za-z.+-]{1,64}$/.test(binding.codexVersion) ||
|
|
49
|
+
typeof binding.nativeHome !== "string" ||
|
|
50
|
+
!["linux", "darwin"].includes(String(binding.platform)) ||
|
|
51
|
+
binding.workspaceRootFeature !==
|
|
52
|
+
codexWorkspaceRootFeature(resolve(binding.nativeHome, "../.."), String(binding.platform)))
|
|
53
|
+
throw new Error("Native worker checkpoint format is unsupported");
|
|
54
|
+
return binding;
|
|
55
|
+
}
|
|
56
|
+
export function codexCheckpointRequirement(archive) {
|
|
57
|
+
const binding = codexCheckpointBinding(archive);
|
|
58
|
+
if (!binding)
|
|
59
|
+
return null;
|
|
60
|
+
return {
|
|
61
|
+
codexVersion: binding.codexVersion,
|
|
62
|
+
workspaceRootFeature: binding.workspaceRootFeature,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export function featuresResumeCheckpoint(features, requirement) {
|
|
66
|
+
if (!features?.includes(requirement.workspaceRootFeature))
|
|
67
|
+
return false;
|
|
68
|
+
const resumesOlder = features.includes(CODEX_RESUMES_OLDER_FEATURE);
|
|
69
|
+
return features.some((feature) => {
|
|
70
|
+
if (!feature.startsWith(CODEX_VERSION_FEATURE))
|
|
71
|
+
return false;
|
|
72
|
+
const version = feature.slice(CODEX_VERSION_FEATURE.length);
|
|
73
|
+
return resumesOlder ? codexResumes(version, requirement.codexVersion) : version === requirement.codexVersion;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=worker-checkpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-checkpoint.js","sourceRoot":"","sources":["../../../src/app-server/worker-checkpoint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { AgentQueueClient } from "./client.ts";
|
|
2
|
+
import type { ActiveAssignment } from "./types.ts";
|
|
3
|
+
export declare function brokerOperation(provider: string, raw: string, active: ActiveAssignment, client: AgentQueueClient): Promise<unknown>;
|
|
4
|
+
export declare function broker(provider: string, raw: string): Promise<void>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { request as httpRequest } from "node:http";
|
|
3
|
+
import { AgentQueueClient } from "./client.js";
|
|
4
|
+
function canonical(value) {
|
|
5
|
+
if (Array.isArray(value))
|
|
6
|
+
return value.map(canonical);
|
|
7
|
+
if (!value || typeof value !== "object")
|
|
8
|
+
return value;
|
|
9
|
+
return Object.fromEntries(Object.entries(value)
|
|
10
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
11
|
+
.map(([key, entry]) => [key, canonical(entry)]));
|
|
12
|
+
}
|
|
13
|
+
function operationHash(provider, operation) {
|
|
14
|
+
return createHash("sha256")
|
|
15
|
+
.update(provider)
|
|
16
|
+
.update("\0")
|
|
17
|
+
.update(JSON.stringify(canonical(operation)))
|
|
18
|
+
.digest("hex");
|
|
19
|
+
}
|
|
20
|
+
export async function brokerOperation(provider, raw, active, client) {
|
|
21
|
+
if (!["agentqueue", "linear", "github", "git", "publication"].includes(provider))
|
|
22
|
+
throw new Error("broker provider must be agentqueue, linear, github, git, or publication");
|
|
23
|
+
const body = JSON.parse(raw);
|
|
24
|
+
if (!body || typeof body !== "object" || Array.isArray(body))
|
|
25
|
+
throw new Error("broker operation must be an object");
|
|
26
|
+
if (provider === "agentqueue") {
|
|
27
|
+
const capability = active.capabilities.find((entry) => entry.audience === "worker-control-plane-broker" &&
|
|
28
|
+
entry.toolIds.includes("agentqueue.control_plane") &&
|
|
29
|
+
entry.actionIds.includes("invoke"));
|
|
30
|
+
if (!capability)
|
|
31
|
+
throw new Error("this assignment has no Agent Queue control-plane capability");
|
|
32
|
+
const response = await client.request("POST", "/v1/self-hosted-workers/brokers/agentqueue", body, { "x-aq-capability": capability.token });
|
|
33
|
+
return response.value?.value ?? null;
|
|
34
|
+
}
|
|
35
|
+
let brokerName = provider;
|
|
36
|
+
if (provider === "github")
|
|
37
|
+
brokerName = "github-api";
|
|
38
|
+
else if (provider === "git")
|
|
39
|
+
brokerName = "git-http";
|
|
40
|
+
const audience = `worker-${brokerName}-broker`;
|
|
41
|
+
const action = "action" in body && typeof body.action === "string" ? body.action : "";
|
|
42
|
+
if (provider === "git" && !active.repository)
|
|
43
|
+
throw new Error("this assignment has no repository");
|
|
44
|
+
const boundedBody = provider === "git" ? { action, branch: active.repository.branch } : body;
|
|
45
|
+
const hash = operationHash(provider, boundedBody);
|
|
46
|
+
const capability = active.capabilities.find((entry) => entry.audience === audience &&
|
|
47
|
+
entry.actionIds.includes(action) &&
|
|
48
|
+
(!entry.approvalId || entry.operationHash === hash));
|
|
49
|
+
if (!capability) {
|
|
50
|
+
const requested = await client.request("POST", `/v1/self-hosted-workers/runs/${encodeURIComponent(active.runId)}/approvals`, {
|
|
51
|
+
leaseToken: active.leaseToken,
|
|
52
|
+
provider,
|
|
53
|
+
operation: boundedBody,
|
|
54
|
+
summary: `${provider} ${action || "operation"}`,
|
|
55
|
+
});
|
|
56
|
+
throw new Error(`Agent Queue approval ${requested.value?.approval.id ?? "requested"} is ${requested.value?.approval.status ?? "pending"}; retry this operation after approval`);
|
|
57
|
+
}
|
|
58
|
+
if (provider === "git") {
|
|
59
|
+
return { approved: true, action, branch: active.repository.branch };
|
|
60
|
+
}
|
|
61
|
+
const response = await client.request("POST", `/v1/self-hosted-workers/brokers/${provider}`, body, { "x-aq-capability": capability.token });
|
|
62
|
+
return response.value?.value ?? null;
|
|
63
|
+
}
|
|
64
|
+
async function supervisorRequest(provider, raw) {
|
|
65
|
+
const socketPath = process.env.AQ_SUPERVISOR_SOCKET;
|
|
66
|
+
const secret = process.env.AQ_SUPERVISOR_SECRET;
|
|
67
|
+
if (!socketPath || !secret)
|
|
68
|
+
throw new Error("broker commands are available only inside an active workflow");
|
|
69
|
+
return await new Promise((resolve, reject) => {
|
|
70
|
+
const request = httpRequest({
|
|
71
|
+
socketPath,
|
|
72
|
+
path: "/broker",
|
|
73
|
+
method: "POST",
|
|
74
|
+
headers: {
|
|
75
|
+
authorization: `Bearer ${secret}`,
|
|
76
|
+
"content-type": "application/json",
|
|
77
|
+
},
|
|
78
|
+
}, (response) => {
|
|
79
|
+
let value = "";
|
|
80
|
+
response.setEncoding("utf8");
|
|
81
|
+
response.on("data", (chunk) => (value += chunk));
|
|
82
|
+
response.on("end", () => {
|
|
83
|
+
let parsed;
|
|
84
|
+
try {
|
|
85
|
+
parsed = JSON.parse(value);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return reject(new Error("invalid response from worker supervisor"));
|
|
89
|
+
}
|
|
90
|
+
if ((response.statusCode ?? 500) >= 400)
|
|
91
|
+
reject(new Error(parsed.error ?? "broker request failed"));
|
|
92
|
+
else
|
|
93
|
+
resolve(parsed.value);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
request.once("error", reject);
|
|
97
|
+
request.end(JSON.stringify({ provider, raw }));
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
export async function broker(provider, raw) {
|
|
101
|
+
const value = await supervisorRequest(provider, raw);
|
|
102
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=broker.js.map
|