@agentsky/sky 2.10.0 → 2.12.0

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.
@@ -0,0 +1,102 @@
1
+ import "./chunk-MLKGABMK.js";
2
+
3
+ // src/harness-connect.ts
4
+ import { spawn } from "child_process";
5
+ import { createInterface } from "readline";
6
+ function agentCommandFrom(argv) {
7
+ const separator = argv.indexOf("--");
8
+ return separator >= 0 ? argv.slice(separator + 1) : [];
9
+ }
10
+ function harnessRelayUrl(apiBase, session) {
11
+ const base = apiBase.replace(/\/$/, "").replace(/^http(s?):\/\//, (_, secure) => `ws${secure}://`);
12
+ return `${base}/api/v1/sessions/${encodeURIComponent(session)}/harness`;
13
+ }
14
+ async function connectHarness(options) {
15
+ const [program, ...args] = options.command;
16
+ if (!program) throw new Error("give the ACP agent command after --, e.g. sky harness connect sess_\u2026 -- npx my-agent --acp");
17
+ if (!options.token.startsWith("hct_")) throw new Error("the connect token must start with hct_");
18
+ const url = options.url ?? (options.apiBase && options.session ? harnessRelayUrl(options.apiBase, options.session) : null);
19
+ if (!url) throw new Error("give --session (or set AGENTSKY_HARNESS_RELAY_URL)");
20
+ const log = options.log ?? ((line) => console.error(line));
21
+ const { default: WebSocket } = await import("ws");
22
+ return new Promise((resolve, reject) => {
23
+ const socket = new WebSocket(url, { headers: { authorization: `Bearer ${options.token}` } });
24
+ let child = null;
25
+ let settled = false;
26
+ const finish = (code) => {
27
+ if (settled) return;
28
+ settled = true;
29
+ if (child && child.exitCode === null) child.kill("SIGTERM");
30
+ if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) socket.close();
31
+ resolve(code);
32
+ };
33
+ options.signal?.addEventListener("abort", () => finish(0), { once: true });
34
+ socket.on("unexpected-response", (_request, response) => {
35
+ settled = true;
36
+ reject(new RelayRefused(response.statusCode ?? 0, `the relay refused the connection: ${response.statusCode} ${response.statusMessage ?? ""}`.trim()));
37
+ });
38
+ socket.on("error", (error) => {
39
+ if (!settled) {
40
+ settled = true;
41
+ reject(error);
42
+ }
43
+ });
44
+ socket.on("open", () => {
45
+ log(`[sky harness] connected; running ${program}`);
46
+ child = spawn(program, args, { stdio: ["pipe", "pipe", "inherit"] });
47
+ child.on("error", (error) => {
48
+ log(`[sky harness] agent failed to start: ${error.message}`);
49
+ finish(1);
50
+ });
51
+ child.on("exit", (code) => {
52
+ log(`[sky harness] agent exited (${code ?? "signal"})`);
53
+ finish(code ?? 1);
54
+ });
55
+ createInterface({ input: child.stdout }).on("line", (line) => {
56
+ if (line.trim() && socket.readyState === WebSocket.OPEN) socket.send(line);
57
+ });
58
+ });
59
+ socket.on("message", (data) => {
60
+ child?.stdin?.write(`${data.toString()}
61
+ `);
62
+ });
63
+ socket.on("close", (code) => {
64
+ log(`[sky harness] relay closed (${code})`);
65
+ finish(0);
66
+ });
67
+ });
68
+ }
69
+ var RelayRefused = class extends Error {
70
+ constructor(status, message) {
71
+ super(message);
72
+ this.status = status;
73
+ this.name = "RelayRefused";
74
+ }
75
+ status;
76
+ };
77
+ async function serveHarness(options, wait = (ms) => new Promise((r) => setTimeout(r, ms))) {
78
+ const log = options.log ?? ((line) => console.error(line));
79
+ let backoff = 1e3;
80
+ while (!options.signal?.aborted) {
81
+ const started = Date.now();
82
+ try {
83
+ await connectHarness(options);
84
+ } catch (error) {
85
+ if (error instanceof RelayRefused && [401, 403, 404].includes(error.status)) throw error;
86
+ log(`[sky harness] ${error instanceof Error ? error.message : String(error)}`);
87
+ }
88
+ if (options.signal?.aborted) break;
89
+ if (Date.now() - started > 6e4) backoff = 1e3;
90
+ log(`[sky harness] reconnecting in ${Math.round(backoff / 1e3)} s`);
91
+ await wait(backoff);
92
+ backoff = Math.min(backoff * 2, 3e4);
93
+ }
94
+ return 0;
95
+ }
96
+ export {
97
+ RelayRefused,
98
+ agentCommandFrom,
99
+ connectHarness,
100
+ harnessRelayUrl,
101
+ serveHarness
102
+ };