@cydm/pie 2.6.12 → 2.7.1
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 +85 -3
- package/dist/builtin/extensions/ask-user/index.js +3 -3
- package/dist/builtin/extensions/plan-mode/index.js +130 -21
- package/dist/builtin/extensions/subagent/index.js +15 -6
- package/dist/builtin/extensions/todo/index.js +3 -3
- package/dist/builtin/skills/computer-use-axi/SKILL.md +172 -0
- package/dist/builtin/{extensions/computer-use/index.js → skills/computer-use-axi/computer-use-axi-broker.js} +2122 -708
- package/dist/builtin/skills/computer-use-axi/computer-use-axi-cli.js +37 -0
- package/dist/builtin/skills/computer-use-axi/computer-use-axi-runtime.js +728 -0
- package/dist/builtin/skills/computer-use-axi/package.json +11 -0
- package/dist/chunks/{chunk-PPEWRUMQ.js → chunk-M44CWVDZ.js} +1249 -752
- package/dist/chunks/{chunk-HHNOENEH.js → chunk-NJFPBU36.js} +14 -1
- package/dist/chunks/{chunk-AAEBH6KX.js → chunk-W74NRSRV.js} +239 -231
- package/dist/chunks/{chunk-7B4IIBVS.js → chunk-XUROMYTT.js} +1747 -14
- package/dist/chunks/{src-OWQI5M6W.js → src-C4KA4G75.js} +2 -2
- package/dist/chunks/{test-stream-Y7WXELAJ.js → test-stream-A5ZELKNG.js} +1 -1
- package/dist/cli.js +863 -305
- package/models.schema.json +57 -0
- package/package.json +3 -3
- package/dist/builtin/extensions/computer-use/package.json +0 -14
- package/dist/builtin/extensions/computer-use/scripts/build-native.mjs +0 -278
- package/dist/builtin/extensions/computer-use/scripts/test-native-retention.mjs +0 -204
- package/dist/chunks/chunk-5353DEEC.js +0 -130
- package/dist/chunks/webapi-MBCKO7ZV.js +0 -2481
- package/dist/code-intel-worker.cjs +0 -211227
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/linux/arm64/linux-bridge +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/linux/x64/linux-bridge +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/arm64/pie-computer-use +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/Info.plist +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/MacOS/pie-computer-use +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/_CodeSignature/CodeResources +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/x64/pie-computer-use +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/windows/windows-bridge.exe +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/scripts/helper-path.mjs +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/scripts/setup-helper.mjs +0 -0
|
@@ -0,0 +1,728 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// vendor/computer-use-axi/src/cli.ts
|
|
5
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
6
|
+
import { pathToFileURL } from "node:url";
|
|
7
|
+
|
|
8
|
+
// vendor/computer-use-axi/src/broker-client.ts
|
|
9
|
+
import { spawn } from "node:child_process";
|
|
10
|
+
import { closeSync, existsSync as existsSync2, mkdirSync as mkdirSync2, openSync } from "node:fs";
|
|
11
|
+
import net from "node:net";
|
|
12
|
+
import path3 from "node:path";
|
|
13
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
14
|
+
|
|
15
|
+
// vendor/computer-use-axi/src/broker-protocol.ts
|
|
16
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
17
|
+
import path2 from "node:path";
|
|
18
|
+
|
|
19
|
+
// vendor/computer-use-axi/src/persist.ts
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
|
|
22
|
+
// src/config.ts
|
|
23
|
+
import { existsSync, mkdirSync, readFileSync, renameSync } from "fs";
|
|
24
|
+
import { homedir } from "os";
|
|
25
|
+
import { dirname, join } from "path";
|
|
26
|
+
import { fileURLToPath } from "url";
|
|
27
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
28
|
+
var __dirname = dirname(__filename);
|
|
29
|
+
var isBunRuntime = !!process.versions.bun;
|
|
30
|
+
function getPackageDir() {
|
|
31
|
+
const envDir = process.env.PIE_PACKAGE_DIR;
|
|
32
|
+
if (envDir) {
|
|
33
|
+
if (envDir === "~") return homedir();
|
|
34
|
+
if (envDir.startsWith("~/")) return homedir() + envDir.slice(1);
|
|
35
|
+
return envDir;
|
|
36
|
+
}
|
|
37
|
+
let dir = __dirname;
|
|
38
|
+
while (dir !== dirname(dir)) {
|
|
39
|
+
if (existsSync(join(dir, "package.json"))) {
|
|
40
|
+
return dir;
|
|
41
|
+
}
|
|
42
|
+
dir = dirname(dir);
|
|
43
|
+
}
|
|
44
|
+
return __dirname;
|
|
45
|
+
}
|
|
46
|
+
function getPackageJsonPath() {
|
|
47
|
+
return join(getPackageDir(), "package.json");
|
|
48
|
+
}
|
|
49
|
+
var pkg = JSON.parse(readFileSync(getPackageJsonPath(), "utf-8"));
|
|
50
|
+
var CONFIG_DIR_NAME = ".pie";
|
|
51
|
+
var VERSION = pkg.version;
|
|
52
|
+
var ENV_AGENT_DIR = "PIE_CODING_AGENT_DIR";
|
|
53
|
+
function getConfigDir() {
|
|
54
|
+
const envDir = process.env[ENV_AGENT_DIR];
|
|
55
|
+
if (envDir) {
|
|
56
|
+
if (envDir === "~") return homedir();
|
|
57
|
+
if (envDir.startsWith("~/")) return homedir() + envDir.slice(1);
|
|
58
|
+
return envDir;
|
|
59
|
+
}
|
|
60
|
+
return join(homedir(), CONFIG_DIR_NAME);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// vendor/computer-use-axi/src/persist.ts
|
|
64
|
+
function stateRootDir(env = process.env) {
|
|
65
|
+
const override = env.PIE_COMPUTER_USE_STATE_DIR?.trim();
|
|
66
|
+
if (override) return override;
|
|
67
|
+
return path.join(getConfigDir(), "computer-use");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/runtime/computer-use-owner.ts
|
|
71
|
+
var COMPUTER_USE_OWNER_ENV = "PIE_COMPUTER_USE_OWNER_ID";
|
|
72
|
+
var COMPUTER_USE_EXECUTION_ENV = "PIE_COMPUTER_USE_EXECUTION_ID";
|
|
73
|
+
var COMPUTER_USE_STANDALONE_OWNER = "standalone";
|
|
74
|
+
var OWNER_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:@-]{0,255}$/;
|
|
75
|
+
function normalizeComputerUseOwner(value) {
|
|
76
|
+
if (typeof value !== "string") return COMPUTER_USE_STANDALONE_OWNER;
|
|
77
|
+
const trimmed = value.trim();
|
|
78
|
+
if (!trimmed) return COMPUTER_USE_STANDALONE_OWNER;
|
|
79
|
+
return OWNER_PATTERN.test(trimmed) ? trimmed : COMPUTER_USE_STANDALONE_OWNER;
|
|
80
|
+
}
|
|
81
|
+
function computerUseOwnerFromEnv(env = process.env) {
|
|
82
|
+
return normalizeComputerUseOwner(env[COMPUTER_USE_OWNER_ENV]);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// vendor/computer-use-axi/src/broker-protocol.ts
|
|
86
|
+
var BROKER_PROTOCOL_VERSION = 1;
|
|
87
|
+
var BROKER_ENGINE_VERSION = 1;
|
|
88
|
+
var BROKER_PACKAGE_VERSION = "0.5.1-pie.1";
|
|
89
|
+
var BROKER_MAX_FRAME_BYTES = 4 * 1024 * 1024;
|
|
90
|
+
var BROKER_MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
|
|
91
|
+
var BROKER_DEFAULT_REQUEST_BUDGET_MS = 12e4;
|
|
92
|
+
var BROKER_MAX_REQUEST_BUDGET_MS = 15 * 6e4;
|
|
93
|
+
var BROKER_IDLE_EXIT_MS = 30 * 6e4;
|
|
94
|
+
var BROKER_HANDSHAKE_TIMEOUT_MS = 3e3;
|
|
95
|
+
function computeBuildIdentity() {
|
|
96
|
+
const seed = `${BROKER_PROTOCOL_VERSION}:${BROKER_ENGINE_VERSION}:${BROKER_PACKAGE_VERSION}`;
|
|
97
|
+
return {
|
|
98
|
+
version: BROKER_PACKAGE_VERSION,
|
|
99
|
+
identity: createHash("sha256").update(seed).digest("hex").slice(0, 16)
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
var BROKER_BUILD = computeBuildIdentity();
|
|
103
|
+
var BrokerProtocolError = class extends Error {
|
|
104
|
+
constructor(code, message) {
|
|
105
|
+
super(message);
|
|
106
|
+
this.code = code;
|
|
107
|
+
this.name = "BrokerProtocolError";
|
|
108
|
+
}
|
|
109
|
+
code;
|
|
110
|
+
};
|
|
111
|
+
function encodeFrame(value, maxBytes = BROKER_MAX_FRAME_BYTES) {
|
|
112
|
+
let json;
|
|
113
|
+
try {
|
|
114
|
+
json = JSON.stringify(value);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
throw new BrokerProtocolError("encode_failed", error instanceof Error ? error.message : String(error));
|
|
117
|
+
}
|
|
118
|
+
const bytes = Buffer.byteLength(json, "utf8");
|
|
119
|
+
if (bytes > maxBytes) throw new BrokerProtocolError("frame_too_large", `Frame of ${bytes} bytes exceeds the ${maxBytes}-byte limit.`);
|
|
120
|
+
return Buffer.from(`${json}
|
|
121
|
+
`, "utf8");
|
|
122
|
+
}
|
|
123
|
+
var FrameDecoder = class {
|
|
124
|
+
constructor(maxBytes = BROKER_MAX_FRAME_BYTES) {
|
|
125
|
+
this.maxBytes = maxBytes;
|
|
126
|
+
}
|
|
127
|
+
maxBytes;
|
|
128
|
+
buffer = Buffer.alloc(0);
|
|
129
|
+
push(chunk) {
|
|
130
|
+
this.buffer = this.buffer.length === 0 ? chunk : Buffer.concat([this.buffer, chunk]);
|
|
131
|
+
const frames = [];
|
|
132
|
+
for (; ; ) {
|
|
133
|
+
const newline = this.buffer.indexOf(10);
|
|
134
|
+
if (newline < 0) break;
|
|
135
|
+
const line = this.buffer.subarray(0, newline).toString("utf8").trim();
|
|
136
|
+
this.buffer = this.buffer.subarray(newline + 1);
|
|
137
|
+
if (!line) continue;
|
|
138
|
+
let parsed;
|
|
139
|
+
try {
|
|
140
|
+
parsed = JSON.parse(line);
|
|
141
|
+
} catch {
|
|
142
|
+
throw new BrokerProtocolError("invalid_json", "Frame is not valid JSON.");
|
|
143
|
+
}
|
|
144
|
+
frames.push(parsed);
|
|
145
|
+
}
|
|
146
|
+
if (this.buffer.length > this.maxBytes) {
|
|
147
|
+
throw new BrokerProtocolError("frame_too_large", `Unterminated frame exceeds the ${this.maxBytes}-byte limit.`);
|
|
148
|
+
}
|
|
149
|
+
return frames;
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
function resolveBrokerEndpoint(env = process.env) {
|
|
153
|
+
const socketOverride = env.PIE_COMPUTER_USE_BROKER_SOCKET?.trim();
|
|
154
|
+
if (process.platform === "win32") {
|
|
155
|
+
const seed = socketOverride || stateRootDir(env);
|
|
156
|
+
const key = createHash("sha256").update(seed).digest("hex").slice(0, 16);
|
|
157
|
+
return { kind: "named-pipe", path: `\\\\.\\pipe\\pie-computer-use-axi-${key}` };
|
|
158
|
+
}
|
|
159
|
+
const socketPath = socketOverride || path2.join(stateRootDir(env), "run", "broker.sock");
|
|
160
|
+
if (Buffer.byteLength(socketPath, "utf8") > 100) {
|
|
161
|
+
throw new BrokerProtocolError("endpoint_too_long", `Unix socket path is ${Buffer.byteLength(socketPath)} bytes (limit ~104): ${socketPath}. Set PIE_COMPUTER_USE_BROKER_SOCKET to a shorter path.`);
|
|
162
|
+
}
|
|
163
|
+
return { kind: "unix-socket", path: socketPath, directory: path2.dirname(socketPath) };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// vendor/computer-use-axi/src/broker-client.ts
|
|
167
|
+
var BrokerCallError = class extends Error {
|
|
168
|
+
constructor(code, message, options = {}) {
|
|
169
|
+
super(message);
|
|
170
|
+
this.code = code;
|
|
171
|
+
this.options = options;
|
|
172
|
+
this.name = "BrokerCallError";
|
|
173
|
+
}
|
|
174
|
+
code;
|
|
175
|
+
options;
|
|
176
|
+
};
|
|
177
|
+
var SocketFrames = class {
|
|
178
|
+
constructor(socket) {
|
|
179
|
+
this.socket = socket;
|
|
180
|
+
socket.on("data", (chunk) => {
|
|
181
|
+
try {
|
|
182
|
+
for (const frame of this.decoder.push(chunk)) {
|
|
183
|
+
const waiter = this.waiters.shift();
|
|
184
|
+
if (waiter) waiter(frame);
|
|
185
|
+
else this.queue.push(frame);
|
|
186
|
+
}
|
|
187
|
+
} catch {
|
|
188
|
+
this.close();
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
socket.on("error", () => this.close());
|
|
192
|
+
socket.on("close", () => this.close());
|
|
193
|
+
}
|
|
194
|
+
socket;
|
|
195
|
+
decoder = new FrameDecoder();
|
|
196
|
+
queue = [];
|
|
197
|
+
waiters = [];
|
|
198
|
+
closed = false;
|
|
199
|
+
close() {
|
|
200
|
+
if (this.closed) return;
|
|
201
|
+
this.closed = true;
|
|
202
|
+
for (const waiter of this.waiters.splice(0)) waiter(null);
|
|
203
|
+
}
|
|
204
|
+
next(timeoutMs) {
|
|
205
|
+
const queued = this.queue.shift();
|
|
206
|
+
if (queued !== void 0) return Promise.resolve(queued);
|
|
207
|
+
if (this.closed) return Promise.resolve(null);
|
|
208
|
+
return new Promise((resolve2) => {
|
|
209
|
+
const timer = setTimeout(() => {
|
|
210
|
+
const index = this.waiters.indexOf(waiter);
|
|
211
|
+
if (index >= 0) this.waiters.splice(index, 1);
|
|
212
|
+
resolve2(null);
|
|
213
|
+
}, timeoutMs);
|
|
214
|
+
const waiter = (value) => {
|
|
215
|
+
clearTimeout(timer);
|
|
216
|
+
resolve2(value);
|
|
217
|
+
};
|
|
218
|
+
this.waiters.push(waiter);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
function tryConnect(endpoint, timeoutMs = 600) {
|
|
223
|
+
return new Promise((resolve2) => {
|
|
224
|
+
const socket = net.createConnection(endpoint.path);
|
|
225
|
+
const timer = setTimeout(() => {
|
|
226
|
+
socket.destroy();
|
|
227
|
+
resolve2(void 0);
|
|
228
|
+
}, timeoutMs);
|
|
229
|
+
socket.once("connect", () => {
|
|
230
|
+
clearTimeout(timer);
|
|
231
|
+
resolve2(socket);
|
|
232
|
+
});
|
|
233
|
+
socket.once("error", () => {
|
|
234
|
+
clearTimeout(timer);
|
|
235
|
+
resolve2(void 0);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
function sleep(ms) {
|
|
240
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
241
|
+
}
|
|
242
|
+
function resolveBrokerSpawn() {
|
|
243
|
+
const here = path3.dirname(fileURLToPath2(import.meta.url));
|
|
244
|
+
const override = process.env.PIE_COMPUTER_USE_BROKER_ENTRY?.trim();
|
|
245
|
+
const candidates = [
|
|
246
|
+
override,
|
|
247
|
+
path3.join(here, "computer-use-axi-broker.js"),
|
|
248
|
+
path3.join(here, "broker-main.ts")
|
|
249
|
+
].filter((candidate) => Boolean(candidate));
|
|
250
|
+
for (const candidate of candidates) {
|
|
251
|
+
if (!existsSync2(candidate)) continue;
|
|
252
|
+
if (candidate.endsWith(".ts")) return { file: process.execPath, args: ["--import", "tsx", candidate] };
|
|
253
|
+
return { file: process.execPath, args: [candidate] };
|
|
254
|
+
}
|
|
255
|
+
throw new BrokerCallError("broker_entry_missing", "Pie's computer-use broker entry is missing. Rebuild or reinstall Pie.", { exitCode: 1 });
|
|
256
|
+
}
|
|
257
|
+
function spawnBroker() {
|
|
258
|
+
const command = resolveBrokerSpawn();
|
|
259
|
+
let stdio = "ignore";
|
|
260
|
+
let logFd;
|
|
261
|
+
try {
|
|
262
|
+
const logDir = path3.join(stateRootDir(), "broker");
|
|
263
|
+
mkdirSync2(logDir, { recursive: true, mode: 448 });
|
|
264
|
+
logFd = openSync(path3.join(logDir, "broker.log"), "a", 384);
|
|
265
|
+
stdio = ["ignore", logFd, logFd];
|
|
266
|
+
} catch {
|
|
267
|
+
stdio = "ignore";
|
|
268
|
+
}
|
|
269
|
+
const child = spawn(command.file, command.args, {
|
|
270
|
+
detached: true,
|
|
271
|
+
stdio,
|
|
272
|
+
env: process.env,
|
|
273
|
+
windowsHide: true
|
|
274
|
+
});
|
|
275
|
+
if (logFd !== void 0) {
|
|
276
|
+
try {
|
|
277
|
+
closeSync(logFd);
|
|
278
|
+
} catch {
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
child.on("error", () => {
|
|
282
|
+
});
|
|
283
|
+
child.unref();
|
|
284
|
+
return { pid: child.pid };
|
|
285
|
+
}
|
|
286
|
+
async function connectOrSpawn(endpoint, spawnIfMissing, spawnState) {
|
|
287
|
+
const existing = await tryConnect(endpoint);
|
|
288
|
+
if (existing) return existing;
|
|
289
|
+
if (!spawnIfMissing) {
|
|
290
|
+
throw new BrokerCallError("broker_not_running", `No computer-use broker is running at ${endpoint.path}.`, { exitCode: 0 });
|
|
291
|
+
}
|
|
292
|
+
if (!spawnState.spawned) {
|
|
293
|
+
spawnState.spawned = true;
|
|
294
|
+
spawnState.pid = spawnBroker().pid;
|
|
295
|
+
}
|
|
296
|
+
const deadline = Date.now() + 12e3;
|
|
297
|
+
while (Date.now() < deadline) {
|
|
298
|
+
const socket = await tryConnect(endpoint, 500);
|
|
299
|
+
if (socket) return socket;
|
|
300
|
+
await sleep(120);
|
|
301
|
+
}
|
|
302
|
+
throw new BrokerCallError(
|
|
303
|
+
"broker_unavailable",
|
|
304
|
+
`The local computer-use broker did not become available at ${endpoint.path}${spawnState.pid ? ` (spawned pid ${spawnState.pid})` : ""}. Run 'computer-use-axi status' or inspect the broker log.`,
|
|
305
|
+
{ exitCode: 1 }
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
function isBrokerResponse(value) {
|
|
309
|
+
return Boolean(value) && typeof value === "object" && value.type === "response";
|
|
310
|
+
}
|
|
311
|
+
async function callBroker(options) {
|
|
312
|
+
const endpoint = resolveBrokerEndpoint();
|
|
313
|
+
const budgetMs = Math.min(Math.max(options.budgetMs ?? BROKER_DEFAULT_REQUEST_BUDGET_MS, 100), 15 * 6e4);
|
|
314
|
+
const spawnState = { spawned: false };
|
|
315
|
+
const control = options.command === "status" || options.command === "stop";
|
|
316
|
+
const drainRetryDeadline = Date.now() + 45e3;
|
|
317
|
+
for (; ; ) {
|
|
318
|
+
const socket = await connectOrSpawn(endpoint, options.spawnIfMissing !== false, spawnState);
|
|
319
|
+
const frames = new SocketFrames(socket);
|
|
320
|
+
try {
|
|
321
|
+
socket.write(encodeFrame({ type: "hello", protocolVersion: BROKER_PROTOCOL_VERSION, clientVersion: "cli" }));
|
|
322
|
+
const helloFrame = await frames.next(BROKER_HANDSHAKE_TIMEOUT_MS);
|
|
323
|
+
if (!helloFrame || typeof helloFrame !== "object" || helloFrame.type !== "hello") {
|
|
324
|
+
throw new BrokerCallError("broker_no_handshake", "The computer-use broker did not answer the protocol handshake.", { exitCode: 1 });
|
|
325
|
+
}
|
|
326
|
+
const hello = helloFrame;
|
|
327
|
+
if (hello.ok === false) {
|
|
328
|
+
if (hello.error.code === "broker_draining") {
|
|
329
|
+
if (options.command === "status") {
|
|
330
|
+
throw new BrokerCallError("broker_draining", "The computer-use broker is shutting down and draining in-flight work; status is unavailable until it exits.", { exitCode: 0 });
|
|
331
|
+
}
|
|
332
|
+
if (!control) {
|
|
333
|
+
socket.destroy();
|
|
334
|
+
if (Date.now() >= drainRetryDeadline) {
|
|
335
|
+
throw new BrokerCallError("broker_draining", "The computer-use broker is still draining in-flight work; no request was sent. Retry shortly.", { exitCode: 1 });
|
|
336
|
+
}
|
|
337
|
+
await sleep(150);
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (options.command !== "stop") {
|
|
342
|
+
const pidHint = hello.pid ? ` (pid ${hello.pid})` : "";
|
|
343
|
+
throw new BrokerCallError(
|
|
344
|
+
"broker_incompatible",
|
|
345
|
+
`A different computer-use broker is already running${pidHint}: ${hello.error.message}. Run 'computer-use-axi stop' to restart it safely, then retry. Refusing to start a second execution authority.`,
|
|
346
|
+
{ exitCode: 3, incompatible: true, brokerPid: hello.pid }
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
const brokerProtocol = hello.protocolVersion ?? BROKER_PROTOCOL_VERSION;
|
|
351
|
+
const request = {
|
|
352
|
+
type: "request",
|
|
353
|
+
protocolVersion: brokerProtocol,
|
|
354
|
+
requestId: options.requestId,
|
|
355
|
+
ownerId: options.ownerId,
|
|
356
|
+
executionId: options.executionId,
|
|
357
|
+
command: options.command,
|
|
358
|
+
params: options.params,
|
|
359
|
+
cwd: options.cwd,
|
|
360
|
+
budgetMs
|
|
361
|
+
};
|
|
362
|
+
socket.write(encodeFrame(request));
|
|
363
|
+
const responseTimeout = budgetMs + 15e3;
|
|
364
|
+
for (; ; ) {
|
|
365
|
+
const frame = await frames.next(responseTimeout);
|
|
366
|
+
if (!frame) {
|
|
367
|
+
throw new BrokerCallError(
|
|
368
|
+
"outcome_unknown",
|
|
369
|
+
"The broker connection closed before a result arrived. The native action may have been dispatched; do not replay it. Run 'computer-use-axi observe' to establish a successor state.",
|
|
370
|
+
{ exitCode: 1, dispatched: true, outcomeUnknown: true, brokerPid: hello.pid }
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
if (!isBrokerResponse(frame)) continue;
|
|
374
|
+
if (frame.requestId !== options.requestId) continue;
|
|
375
|
+
if (frame.state === "in-flight") {
|
|
376
|
+
throw new BrokerCallError(
|
|
377
|
+
"request_in_flight",
|
|
378
|
+
"This requestId is already in flight in the broker. Wait for its original result instead of dispatching again.",
|
|
379
|
+
{ exitCode: 1, dispatched: true, brokerPid: hello.pid }
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
if (frame.state === "outcome-unknown") {
|
|
383
|
+
return { state: "outcome-unknown", result: frame.result, generation: frame.generation, helperGeneration: frame.helperGeneration, brokerPid: hello.pid };
|
|
384
|
+
}
|
|
385
|
+
if (frame.state === "error" || frame.ok === false) {
|
|
386
|
+
throw new BrokerCallError(frame.error?.code ?? "broker_error", frame.error?.message ?? "The computer-use broker rejected the request.", {
|
|
387
|
+
exitCode: 1,
|
|
388
|
+
dispatched: frame.error?.dispatched,
|
|
389
|
+
brokerPid: hello.pid
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
return { state: "done", result: frame.result, generation: frame.generation, helperGeneration: frame.helperGeneration, brokerPid: hello.pid };
|
|
393
|
+
}
|
|
394
|
+
} finally {
|
|
395
|
+
socket.destroy();
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// vendor/computer-use-axi/src/cli.ts
|
|
401
|
+
var USAGE = `computer-use-axi \u2014 desktop & browser UI automation
|
|
402
|
+
|
|
403
|
+
Lifecycle: roots -> observe (returns stateId) -> search/expand/inspect -> act.
|
|
404
|
+
@r refs come from roots; @e refs + stateId come from observe/search;
|
|
405
|
+
@o refs continue long truncated output via read.
|
|
406
|
+
|
|
407
|
+
Commands:
|
|
408
|
+
roots [--text T] [--app A] [--bundle-id B] [--pid N] [--kind K]
|
|
409
|
+
observe [--root @rN] [--mode semantic|visual|fused]
|
|
410
|
+
search --state S (--text T | --role R | --capability C)
|
|
411
|
+
expand --state S --ref @eN [--depth 1-8]
|
|
412
|
+
inspect --state S --ref @eN
|
|
413
|
+
read --ref @oN|--eN [--offset BYTES] [--state S]
|
|
414
|
+
wait --state S (--text T | --role R | --ref @eN) [--until present|absent]
|
|
415
|
+
[--scope-ref @eN] [--value V] [--timeout-ms MS]
|
|
416
|
+
act --state S --actions '<JSON array>' [--expect '<JSON object>']
|
|
417
|
+
browser launch [--url U]
|
|
418
|
+
browser navigate --state S --url U
|
|
419
|
+
browser eval --state S --expr '<JavaScript>'
|
|
420
|
+
status Show the local broker status (never starts one)
|
|
421
|
+
stop Stop the local broker and release processes it owns
|
|
422
|
+
|
|
423
|
+
Options:
|
|
424
|
+
--json Print { content, details, isError } as JSON
|
|
425
|
+
--request-id ID Reuse an id to retrieve the same result (at-most-once)
|
|
426
|
+
--owner ID Opaque session identity (defaults to the standalone namespace)
|
|
427
|
+
--help, -h Show this help
|
|
428
|
+
|
|
429
|
+
Environment:
|
|
430
|
+
PIE_COMPUTER_USE_OWNER_ID Set by the Pie bash tool at spawn time
|
|
431
|
+
PIE_COMPUTER_USE_AXI_TIMEOUT_MS Per-command broker budget (default 120000)
|
|
432
|
+
|
|
433
|
+
Examples:
|
|
434
|
+
computer-use-axi roots --app Finder
|
|
435
|
+
computer-use-axi observe --root @r1 --mode visual
|
|
436
|
+
computer-use-axi search --state S1 --text Save
|
|
437
|
+
computer-use-axi act --state S1 --actions '[{"action":"press","ref":"@e12"}]'
|
|
438
|
+
computer-use-axi read --ref @o1 --offset 16384`;
|
|
439
|
+
var FLAG_ALIASES = {
|
|
440
|
+
"-h": "--help",
|
|
441
|
+
"--state-id": "--state",
|
|
442
|
+
"--window": "--root",
|
|
443
|
+
"--capability-filter": "--capability",
|
|
444
|
+
"--scope": "--scope-ref",
|
|
445
|
+
"--timeout": "--timeout-ms",
|
|
446
|
+
"--expression": "--expr"
|
|
447
|
+
};
|
|
448
|
+
function parseArgs(argv) {
|
|
449
|
+
const rest = [];
|
|
450
|
+
const flags = /* @__PURE__ */ new Map();
|
|
451
|
+
let command = "";
|
|
452
|
+
let json = false;
|
|
453
|
+
let help = false;
|
|
454
|
+
const booleanFlags = /* @__PURE__ */ new Set(["--json", "--help"]);
|
|
455
|
+
for (let i = 0; i < argv.length; i++) {
|
|
456
|
+
const token = argv[i];
|
|
457
|
+
const alias = FLAG_ALIASES[token] ?? token;
|
|
458
|
+
if (!alias.startsWith("-")) {
|
|
459
|
+
if (!command) command = token;
|
|
460
|
+
else rest.push(token);
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
if (alias === "--json") {
|
|
464
|
+
json = true;
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
if (alias === "--help") {
|
|
468
|
+
help = true;
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
let key = alias;
|
|
472
|
+
let value;
|
|
473
|
+
const eq = alias.indexOf("=");
|
|
474
|
+
if (eq >= 0) {
|
|
475
|
+
key = alias.slice(0, eq);
|
|
476
|
+
value = alias.slice(eq + 1);
|
|
477
|
+
}
|
|
478
|
+
if (!booleanFlags.has(key) && value === void 0) {
|
|
479
|
+
const next = argv[i + 1];
|
|
480
|
+
if (next !== void 0 && !next.startsWith("-")) {
|
|
481
|
+
value = next;
|
|
482
|
+
i += 1;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
flags.set(key, value ?? "");
|
|
486
|
+
}
|
|
487
|
+
return { command, flags, json, help, rest };
|
|
488
|
+
}
|
|
489
|
+
function requiredFlag(args, name) {
|
|
490
|
+
const value = args.flags.get(name);
|
|
491
|
+
if (value === void 0 || value === "") usageError(`missing required option ${name}`);
|
|
492
|
+
return value;
|
|
493
|
+
}
|
|
494
|
+
function optionalFlag(args, name) {
|
|
495
|
+
const value = args.flags.get(name);
|
|
496
|
+
return value === void 0 || value === "" ? void 0 : value;
|
|
497
|
+
}
|
|
498
|
+
function numericFlag(args, name) {
|
|
499
|
+
const value = optionalFlag(args, name);
|
|
500
|
+
if (value === void 0) return void 0;
|
|
501
|
+
const parsed = Number(value);
|
|
502
|
+
if (!Number.isFinite(parsed)) usageError(`${name} must be a number (got '${value}')`);
|
|
503
|
+
return parsed;
|
|
504
|
+
}
|
|
505
|
+
function jsonFlag(args, name) {
|
|
506
|
+
const value = requiredFlag(args, name);
|
|
507
|
+
try {
|
|
508
|
+
return JSON.parse(value);
|
|
509
|
+
} catch (error) {
|
|
510
|
+
usageError(`${name} must be valid JSON (${error.message})`);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
function usageError(message) {
|
|
514
|
+
process.stderr.write(`computer-use-axi: ${message}
|
|
515
|
+
|
|
516
|
+
${USAGE}
|
|
517
|
+
`);
|
|
518
|
+
process.exit(2);
|
|
519
|
+
}
|
|
520
|
+
function buildCommand(args) {
|
|
521
|
+
if (args.command === "browser") {
|
|
522
|
+
const sub = args.rest[0] ?? usageError("browser requires a subcommand: launch | navigate | eval");
|
|
523
|
+
if (sub === "launch") return { command: "launch_browser", params: { url: optionalFlag(args, "--url") } };
|
|
524
|
+
if (sub === "navigate") return { command: "navigate_browser", params: { stateId: requiredFlag(args, "--state"), url: requiredFlag(args, "--url") } };
|
|
525
|
+
if (sub === "eval") return { command: "evaluate_browser", params: { stateId: requiredFlag(args, "--state"), expression: requiredFlag(args, "--expr") } };
|
|
526
|
+
usageError(`unknown browser subcommand '${sub}' (expected launch | navigate | eval)`);
|
|
527
|
+
}
|
|
528
|
+
switch (args.command) {
|
|
529
|
+
case "status":
|
|
530
|
+
return { command: "status", params: {} };
|
|
531
|
+
case "stop":
|
|
532
|
+
return { command: "stop", params: {} };
|
|
533
|
+
case "roots":
|
|
534
|
+
return {
|
|
535
|
+
command: "find_roots",
|
|
536
|
+
params: {
|
|
537
|
+
text: optionalFlag(args, "--text"),
|
|
538
|
+
app: optionalFlag(args, "--app"),
|
|
539
|
+
bundleId: optionalFlag(args, "--bundle-id"),
|
|
540
|
+
pid: numericFlag(args, "--pid"),
|
|
541
|
+
kind: optionalFlag(args, "--kind")
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
case "observe":
|
|
545
|
+
return {
|
|
546
|
+
command: "observe_ui",
|
|
547
|
+
params: { root: optionalFlag(args, "--root"), mode: optionalFlag(args, "--mode") }
|
|
548
|
+
};
|
|
549
|
+
case "search": {
|
|
550
|
+
const params = {
|
|
551
|
+
text: optionalFlag(args, "--text"),
|
|
552
|
+
role: optionalFlag(args, "--role"),
|
|
553
|
+
capability: optionalFlag(args, "--capability"),
|
|
554
|
+
stateId: requiredFlag(args, "--state")
|
|
555
|
+
};
|
|
556
|
+
if (!params.text && !params.role && !params.capability) usageError("search requires at least one of --text, --role, --capability");
|
|
557
|
+
return { command: "search_ui", params };
|
|
558
|
+
}
|
|
559
|
+
case "expand":
|
|
560
|
+
return { command: "expand_ui", params: { stateId: requiredFlag(args, "--state"), ref: requiredFlag(args, "--ref"), depth: numericFlag(args, "--depth") } };
|
|
561
|
+
case "inspect":
|
|
562
|
+
return { command: "inspect_ui", params: { stateId: requiredFlag(args, "--state"), ref: requiredFlag(args, "--ref") } };
|
|
563
|
+
case "read": {
|
|
564
|
+
const ref = requiredFlag(args, "--ref");
|
|
565
|
+
const params = { ref, offset: numericFlag(args, "--offset") };
|
|
566
|
+
if (ref.startsWith("@e")) params.stateId = requiredFlag(args, "--state");
|
|
567
|
+
else params.stateId = optionalFlag(args, "--state");
|
|
568
|
+
return { command: "read_text", params };
|
|
569
|
+
}
|
|
570
|
+
case "wait": {
|
|
571
|
+
const params = {
|
|
572
|
+
stateId: requiredFlag(args, "--state"),
|
|
573
|
+
text: optionalFlag(args, "--text"),
|
|
574
|
+
role: optionalFlag(args, "--role"),
|
|
575
|
+
value: optionalFlag(args, "--value"),
|
|
576
|
+
ref: optionalFlag(args, "--ref"),
|
|
577
|
+
scopeRef: optionalFlag(args, "--scope-ref"),
|
|
578
|
+
until: optionalFlag(args, "--until"),
|
|
579
|
+
timeoutMs: numericFlag(args, "--timeout-ms")
|
|
580
|
+
};
|
|
581
|
+
if (!params.text && !params.role && !params.ref && !params.value) usageError("wait requires at least one of --text, --role, --value, --ref");
|
|
582
|
+
if (params.role && !params.text && !params.value && !params.ref && !params.scopeRef) usageError("wait --role requires --ref or --scope-ref (role-only conditions must be scoped)");
|
|
583
|
+
if (params.value && !params.ref) usageError("wait --value requires --ref (exact element value checks need an exact ref)");
|
|
584
|
+
return { command: "wait_for", params };
|
|
585
|
+
}
|
|
586
|
+
case "act": {
|
|
587
|
+
const actions = jsonFlag(args, "--actions");
|
|
588
|
+
if (!Array.isArray(actions) || actions.length === 0) usageError("--actions must be a non-empty JSON array");
|
|
589
|
+
const params = { stateId: requiredFlag(args, "--state"), actions };
|
|
590
|
+
const expect = optionalFlag(args, "--expect");
|
|
591
|
+
if (expect !== void 0) {
|
|
592
|
+
try {
|
|
593
|
+
params.expect = JSON.parse(expect);
|
|
594
|
+
} catch (error) {
|
|
595
|
+
usageError(`--expect must be valid JSON (${error.message})`);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return { command: "act_ui", params };
|
|
599
|
+
}
|
|
600
|
+
default:
|
|
601
|
+
usageError(args.command ? `unknown command '${args.command}'` : "missing command");
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
function adaptGuidance(text) {
|
|
605
|
+
return text.replace(/observe_ui\(\{ root: "(@r\d+)" \}\)/g, "computer-use-axi observe --root $1").replace(/read_text\(\{ ref: "(@o\d+)", offset: (\d+) \}\)/g, "computer-use-axi read --ref $1 --offset $2").replace(/read_text\(\{ ref: "(@o\d+)" \}\)/g, "computer-use-axi read --ref $1").replace(/\bfind_roots\b/g, "computer-use-axi roots").replace(/\bobserve_ui\b/g, "computer-use-axi observe").replace(/\bsearch_ui\b/g, "computer-use-axi search").replace(/\bexpand_ui\b/g, "computer-use-axi expand").replace(/\binspect_ui\b/g, "computer-use-axi inspect").replace(/\bread_text\b/g, "computer-use-axi read").replace(/\bwait_for\b/g, "computer-use-axi wait").replace(/\bact_ui\b/g, "computer-use-axi act").replace(/\blaunch_browser\b/g, "computer-use-axi browser launch").replace(/\bnavigate_browser\b/g, "computer-use-axi browser navigate").replace(/\bevaluate_browser\b/g, "computer-use-axi browser eval").replace(/computer-use-axi observe\(\{ root: "([^"]+)" \}\)/g, 'computer-use-axi observe --root "$1"');
|
|
606
|
+
}
|
|
607
|
+
function renderText(result) {
|
|
608
|
+
const text = (result.content ?? []).map((part) => part.type === "text" && typeof part.text === "string" ? part.text : void 0).filter(Boolean).join("\n");
|
|
609
|
+
if (text) return adaptGuidance(text);
|
|
610
|
+
if ((result.content ?? []).some((part) => part.type === "image")) {
|
|
611
|
+
return "(image-only observation; use --mode semantic for a text outline or --json for raw content)";
|
|
612
|
+
}
|
|
613
|
+
return "";
|
|
614
|
+
}
|
|
615
|
+
function renderStatus(value) {
|
|
616
|
+
if (!value || typeof value !== "object") return JSON.stringify(value);
|
|
617
|
+
const status = value;
|
|
618
|
+
const artifacts = status.artifacts ?? {};
|
|
619
|
+
const legacy = status.legacyCache ?? {};
|
|
620
|
+
return [
|
|
621
|
+
"computer-use broker: running",
|
|
622
|
+
`pid: ${status.pid}`,
|
|
623
|
+
`generation: ${status.generation}`,
|
|
624
|
+
`helper generation: ${status.helperGeneration}`,
|
|
625
|
+
`build: ${status.build?.version} (${status.build?.identity})`,
|
|
626
|
+
`protocol: ${status.protocolVersion}`,
|
|
627
|
+
`endpoint: ${status.endpoint?.kind} ${status.endpoint?.path}`,
|
|
628
|
+
`transport security: ${status.transportAcl}`,
|
|
629
|
+
`uptime: ${Math.round((status.uptimeMs ?? 0) / 1e3)}s`,
|
|
630
|
+
`active: ${status.active}, queued: ${status.queued}, uncertain: ${status.uncertain}, cached requests: ${status.requests}`,
|
|
631
|
+
`owners: ${status.ownerCount ?? 0} (fingerprints: ${(status.ownerFingerprints ?? []).join(", ") || "none"})`,
|
|
632
|
+
`artifacts: ${artifacts.count ?? 0} files, ${artifacts.bytes ?? 0} bytes (max ${artifacts.maxCount ?? "?"} / ${artifacts.maxBytes ?? "?"} bytes)`,
|
|
633
|
+
`legacy cache cleared at startup: runtime.json=${legacy.runtimeFile ? "yes" : "no"}, states=${legacy.states ?? 0}, outputs=${legacy.outputs ?? 0}`,
|
|
634
|
+
`idle exit: ${Math.round((status.idleExitMs ?? 0) / 6e4)} minutes`
|
|
635
|
+
].join("\n");
|
|
636
|
+
}
|
|
637
|
+
async function main() {
|
|
638
|
+
const args = parseArgs(process.argv.slice(2));
|
|
639
|
+
if (args.help || !args.command && args.flags.size === 0) {
|
|
640
|
+
process.stdout.write(`${USAGE}
|
|
641
|
+
`);
|
|
642
|
+
return 0;
|
|
643
|
+
}
|
|
644
|
+
const { command, params } = buildCommand(args);
|
|
645
|
+
const ownerId = normalizeComputerUseOwner(optionalFlag(args, "--owner") ?? computerUseOwnerFromEnv());
|
|
646
|
+
const executionId = optionalFlag(args, "--execution-id") ?? process.env[COMPUTER_USE_EXECUTION_ENV];
|
|
647
|
+
const requestId = optionalFlag(args, "--request-id") ?? randomUUID2();
|
|
648
|
+
const envBudget = Number(process.env.PIE_COMPUTER_USE_AXI_TIMEOUT_MS);
|
|
649
|
+
const budgetMs = Number.isFinite(envBudget) && envBudget > 0 ? envBudget : void 0;
|
|
650
|
+
const control = command === "status" || command === "stop";
|
|
651
|
+
try {
|
|
652
|
+
const outcome = await callBroker({
|
|
653
|
+
command,
|
|
654
|
+
params,
|
|
655
|
+
ownerId: ownerId === COMPUTER_USE_STANDALONE_OWNER ? ownerId : ownerId,
|
|
656
|
+
executionId,
|
|
657
|
+
requestId,
|
|
658
|
+
cwd: process.cwd(),
|
|
659
|
+
budgetMs,
|
|
660
|
+
spawnIfMissing: !control
|
|
661
|
+
});
|
|
662
|
+
if (outcome.state === "outcome-unknown") {
|
|
663
|
+
const message = `Outcome unknown (generation ${outcome.generation ?? "unknown"}). The native action may have been dispatched; do not replay it. Observe the resource again to establish a successor state.`;
|
|
664
|
+
if (args.json) process.stdout.write(`${JSON.stringify({ content: [{ type: "text", text: message }], isError: true, state: outcome.state, generation: outcome.generation, helperGeneration: outcome.helperGeneration })}
|
|
665
|
+
`);
|
|
666
|
+
else process.stderr.write(`${message}
|
|
667
|
+
`);
|
|
668
|
+
return 1;
|
|
669
|
+
}
|
|
670
|
+
const result = outcome.result ?? {};
|
|
671
|
+
if (args.json) {
|
|
672
|
+
const payload = command === "status" ? { ...result, broker: { requestId, owner: ownerId, generation: outcome.generation, state: outcome.state } } : { ...result, broker: { requestId, owner: ownerId, generation: outcome.generation, state: outcome.state } };
|
|
673
|
+
process.stdout.write(`${JSON.stringify(payload)}
|
|
674
|
+
`);
|
|
675
|
+
} else if (command === "status") {
|
|
676
|
+
process.stdout.write(`${renderStatus(result)}
|
|
677
|
+
`);
|
|
678
|
+
} else if (command === "stop") {
|
|
679
|
+
process.stdout.write("computer-use broker stop requested; owned processes are being released.\n");
|
|
680
|
+
} else {
|
|
681
|
+
const text = renderText(result);
|
|
682
|
+
if (text) process.stdout.write(`${text}
|
|
683
|
+
`);
|
|
684
|
+
}
|
|
685
|
+
return result.isError ? 1 : 0;
|
|
686
|
+
} catch (error) {
|
|
687
|
+
if (error instanceof BrokerCallError && error.code === "broker_not_running") {
|
|
688
|
+
if (args.json) process.stdout.write(`${JSON.stringify({ running: false, content: [{ type: "text", text: error.message }] })}
|
|
689
|
+
`);
|
|
690
|
+
else process.stdout.write(`${control ? "No computer-use broker is running" : error.message}.
|
|
691
|
+
`);
|
|
692
|
+
return 0;
|
|
693
|
+
}
|
|
694
|
+
const brokerError = error instanceof BrokerCallError ? error : void 0;
|
|
695
|
+
const message = adaptGuidance(error instanceof Error ? error.message : String(error));
|
|
696
|
+
if (args.json) {
|
|
697
|
+
process.stdout.write(`${JSON.stringify({ content: [{ type: "text", text: message }], isError: true, ...brokerError ? { error: { code: brokerError.code, dispatched: brokerError.options.dispatched ?? false } } : {} })}
|
|
698
|
+
`);
|
|
699
|
+
} else {
|
|
700
|
+
process.stderr.write(`${message}
|
|
701
|
+
`);
|
|
702
|
+
}
|
|
703
|
+
return brokerError?.options.exitCode ?? 1;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
var isDirectEntry = (() => {
|
|
707
|
+
try {
|
|
708
|
+
return import.meta.url === pathToFileURL(process.argv[1]).href;
|
|
709
|
+
} catch {
|
|
710
|
+
return false;
|
|
711
|
+
}
|
|
712
|
+
})();
|
|
713
|
+
if (isDirectEntry) {
|
|
714
|
+
main().then((code) => {
|
|
715
|
+
process.exitCode = code;
|
|
716
|
+
}).catch((error) => {
|
|
717
|
+
process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}
|
|
718
|
+
`);
|
|
719
|
+
process.exitCode = 1;
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
export {
|
|
723
|
+
USAGE,
|
|
724
|
+
adaptGuidance,
|
|
725
|
+
buildCommand,
|
|
726
|
+
parseArgs,
|
|
727
|
+
usageError
|
|
728
|
+
};
|