@hotcell/daemon 0.1.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.
Files changed (142) hide show
  1. package/dist/agent-check.d.ts +1 -0
  2. package/dist/agent-check.js +105 -0
  3. package/dist/agent-check.js.map +1 -0
  4. package/dist/api/server.d.ts +64 -0
  5. package/dist/api/server.js +1368 -0
  6. package/dist/api/server.js.map +1 -0
  7. package/dist/api/ws.d.ts +14 -0
  8. package/dist/api/ws.js +214 -0
  9. package/dist/api/ws.js.map +1 -0
  10. package/dist/applevz-check.d.ts +1 -0
  11. package/dist/applevz-check.js +280 -0
  12. package/dist/applevz-check.js.map +1 -0
  13. package/dist/backups.d.ts +29 -0
  14. package/dist/backups.js +76 -0
  15. package/dist/backups.js.map +1 -0
  16. package/dist/capacity.d.ts +63 -0
  17. package/dist/capacity.js +95 -0
  18. package/dist/capacity.js.map +1 -0
  19. package/dist/config.d.ts +241 -0
  20. package/dist/config.js +152 -0
  21. package/dist/config.js.map +1 -0
  22. package/dist/cost.d.ts +9 -0
  23. package/dist/cost.js +19 -0
  24. package/dist/cost.js.map +1 -0
  25. package/dist/density-bench.d.ts +1 -0
  26. package/dist/density-bench.js +97 -0
  27. package/dist/density-bench.js.map +1 -0
  28. package/dist/driver/agent-driver.d.ts +67 -0
  29. package/dist/driver/agent-driver.js +197 -0
  30. package/dist/driver/agent-driver.js.map +1 -0
  31. package/dist/driver/agent.d.ts +94 -0
  32. package/dist/driver/agent.js +319 -0
  33. package/dist/driver/agent.js.map +1 -0
  34. package/dist/driver/applevz.d.ts +95 -0
  35. package/dist/driver/applevz.js +527 -0
  36. package/dist/driver/applevz.js.map +1 -0
  37. package/dist/driver/container.d.ts +99 -0
  38. package/dist/driver/container.js +733 -0
  39. package/dist/driver/container.js.map +1 -0
  40. package/dist/driver/fc-api.d.ts +85 -0
  41. package/dist/driver/fc-api.js +173 -0
  42. package/dist/driver/fc-api.js.map +1 -0
  43. package/dist/driver/firecracker.d.ts +126 -0
  44. package/dist/driver/firecracker.js +560 -0
  45. package/dist/driver/firecracker.js.map +1 -0
  46. package/dist/driver/index.d.ts +17 -0
  47. package/dist/driver/index.js +61 -0
  48. package/dist/driver/index.js.map +1 -0
  49. package/dist/driver/router.d.ts +82 -0
  50. package/dist/driver/router.js +159 -0
  51. package/dist/driver/router.js.map +1 -0
  52. package/dist/driver/types.d.ts +234 -0
  53. package/dist/driver/types.js +2 -0
  54. package/dist/driver/types.js.map +1 -0
  55. package/dist/driver/unsupported.d.ts +50 -0
  56. package/dist/driver/unsupported.js +81 -0
  57. package/dist/driver/unsupported.js.map +1 -0
  58. package/dist/driver/vz-image.d.ts +35 -0
  59. package/dist/driver/vz-image.js +75 -0
  60. package/dist/driver/vz-image.js.map +1 -0
  61. package/dist/e2e-harness.d.ts +1 -0
  62. package/dist/e2e-harness.js +99 -0
  63. package/dist/e2e-harness.js.map +1 -0
  64. package/dist/egress-check.d.ts +8 -0
  65. package/dist/egress-check.js +317 -0
  66. package/dist/egress-check.js.map +1 -0
  67. package/dist/fc-check.d.ts +1 -0
  68. package/dist/fc-check.js +113 -0
  69. package/dist/fc-check.js.map +1 -0
  70. package/dist/index.d.ts +2 -0
  71. package/dist/index.js +114 -0
  72. package/dist/index.js.map +1 -0
  73. package/dist/kernels.d.ts +22 -0
  74. package/dist/kernels.js +134 -0
  75. package/dist/kernels.js.map +1 -0
  76. package/dist/lifecycle.d.ts +49 -0
  77. package/dist/lifecycle.js +111 -0
  78. package/dist/lifecycle.js.map +1 -0
  79. package/dist/logger.d.ts +16 -0
  80. package/dist/logger.js +67 -0
  81. package/dist/logger.js.map +1 -0
  82. package/dist/metrics.d.ts +46 -0
  83. package/dist/metrics.js +92 -0
  84. package/dist/metrics.js.map +1 -0
  85. package/dist/net/firewall.d.ts +4 -0
  86. package/dist/net/firewall.js +80 -0
  87. package/dist/net/firewall.js.map +1 -0
  88. package/dist/pricing.d.ts +36 -0
  89. package/dist/pricing.js +81 -0
  90. package/dist/pricing.js.map +1 -0
  91. package/dist/proxy/allowlist-default.d.ts +23 -0
  92. package/dist/proxy/allowlist-default.js +53 -0
  93. package/dist/proxy/allowlist-default.js.map +1 -0
  94. package/dist/proxy/allowlist.d.ts +43 -0
  95. package/dist/proxy/allowlist.js +87 -0
  96. package/dist/proxy/allowlist.js.map +1 -0
  97. package/dist/proxy/egress.d.ts +49 -0
  98. package/dist/proxy/egress.js +599 -0
  99. package/dist/proxy/egress.js.map +1 -0
  100. package/dist/proxy/ratelimit.d.ts +49 -0
  101. package/dist/proxy/ratelimit.js +74 -0
  102. package/dist/proxy/ratelimit.js.map +1 -0
  103. package/dist/proxy/server.d.ts +26 -0
  104. package/dist/proxy/server.js +202 -0
  105. package/dist/proxy/server.js.map +1 -0
  106. package/dist/router-check.d.ts +1 -0
  107. package/dist/router-check.js +97 -0
  108. package/dist/router-check.js.map +1 -0
  109. package/dist/smoke-fc.d.ts +1 -0
  110. package/dist/smoke-fc.js +183 -0
  111. package/dist/smoke-fc.js.map +1 -0
  112. package/dist/smoke-microvm.d.ts +1 -0
  113. package/dist/smoke-microvm.js +187 -0
  114. package/dist/smoke-microvm.js.map +1 -0
  115. package/dist/smoke-remote.d.ts +20 -0
  116. package/dist/smoke-remote.js +155 -0
  117. package/dist/smoke-remote.js.map +1 -0
  118. package/dist/smoke-vz.d.ts +1 -0
  119. package/dist/smoke-vz.js +161 -0
  120. package/dist/smoke-vz.js.map +1 -0
  121. package/dist/smoke.d.ts +7 -0
  122. package/dist/smoke.js +962 -0
  123. package/dist/smoke.js.map +1 -0
  124. package/dist/store.d.ts +124 -0
  125. package/dist/store.js +578 -0
  126. package/dist/store.js.map +1 -0
  127. package/dist/tracing.d.ts +45 -0
  128. package/dist/tracing.js +144 -0
  129. package/dist/tracing.js.map +1 -0
  130. package/dist/types.d.ts +274 -0
  131. package/dist/types.js +3 -0
  132. package/dist/types.js.map +1 -0
  133. package/dist/util.d.ts +27 -0
  134. package/dist/util.js +63 -0
  135. package/dist/util.js.map +1 -0
  136. package/dist/warmpool-check.d.ts +1 -0
  137. package/dist/warmpool-check.js +83 -0
  138. package/dist/warmpool-check.js.map +1 -0
  139. package/dist/web/dashboard.d.ts +1 -0
  140. package/dist/web/dashboard.js +456 -0
  141. package/dist/web/dashboard.js.map +1 -0
  142. package/package.json +53 -0
@@ -0,0 +1,197 @@
1
+ import { createReadStream, createWriteStream } from "node:fs";
2
+ import { UnsupportedDriver } from "./unsupported.js";
3
+ import { shellEscape } from "../util.js";
4
+ /**
5
+ * Shared base for microVM drivers whose in-guest work is served by the `sbx-agent`
6
+ * over the A.4 wire protocol (`AgentConn`). Every agent-served `Driver` method —
7
+ * exec, files, watch, processes, preview bridge, terminal, stats, backup/restore —
8
+ * is implemented here **once**, in terms of a single abstract `openConn(id)` that
9
+ * each concrete driver provides for its transport (Apple VZ relays a unix socket
10
+ * to the guest vsock; Firecracker connects to a vsock UDS with a CONNECT
11
+ * handshake). Concrete drivers only implement lifecycle (`create`/`stop`/`start`/
12
+ * `destroy`), `openConn`, and the host probes (`ping`/`hostInfo`) — the whole
13
+ * point of the abstraction is that the surface above the driver is identical.
14
+ */
15
+ export class AgentDriver extends UnsupportedDriver {
16
+ /** Open a connection, run `fn`, always close it. For one-shot request/response ops. */
17
+ async withConn(id, fn) {
18
+ const conn = await this.openConn(id);
19
+ try {
20
+ return await fn(conn);
21
+ }
22
+ finally {
23
+ conn.close();
24
+ }
25
+ }
26
+ // --- agent-served ops -----------------------------------------------------
27
+ async exec(id, command, opts, onEvent) {
28
+ return this.withConn(id, (c) => c.exec(command, { cwd: opts.cwd, env: opts.env }, onEvent));
29
+ }
30
+ async writeFile(id, opts) {
31
+ return this.withConn(id, (c) => c.writeFile(opts.path, opts.content, opts.mode));
32
+ }
33
+ async readFile(id, opts) {
34
+ return this.withConn(id, (c) => c.readFile(opts.path));
35
+ }
36
+ async mkdir(id, opts) {
37
+ return this.withConn(id, (c) => c.mkdir(opts.path, opts.parents ?? true));
38
+ }
39
+ async listFiles(id, opts) {
40
+ return this.withConn(id, (c) => c.listFiles(opts.path));
41
+ }
42
+ async waitForPort(id, port, opts) {
43
+ return this.withConn(id, (c) => c.waitForPort(port, { host: opts.host, timeoutMs: opts.timeoutMs, intervalMs: opts.intervalMs }));
44
+ }
45
+ /** Watch a path recursively for changes over the agent (poll-based mtime diff),
46
+ * streaming events until `opts.signal` aborts. Holds a connection for its life. */
47
+ async watchFiles(id, path, opts, onEvent) {
48
+ return this.withConn(id, (c) => c.watch(path, opts.intervalMs ?? 1000, opts.signal, onEvent));
49
+ }
50
+ // --- background processes (via exec, same shell patterns as the container driver) -
51
+ async startProcess(id, procId, command, opts) {
52
+ const logPath = `/tmp/hotcell-proc-${procId}.log`;
53
+ // Background `sh -c CMD` and echo its real pid. No `setsid`: busybox setsid
54
+ // forks when the caller is a process-group leader, making `$!` the wrapper pid
55
+ // rather than the command's. The backgrounded process orphans to PID 1 (the
56
+ // agent) when the launching exec returns, so it survives without setsid; kill
57
+ // then targets the right pid.
58
+ const launch = `sh -c ${shellEscape(command)} > ${shellEscape(logPath)} 2>&1 & echo $!`;
59
+ const { stdout, stderr, exitCode } = await this.execCapture(id, launch, opts);
60
+ const pid = Number.parseInt(stdout.trim(), 10);
61
+ if (exitCode !== 0 || !Number.isFinite(pid)) {
62
+ throw new Error(stderr.trim() || `startProcess failed (exit ${exitCode})`);
63
+ }
64
+ return { procId, pid, logPath };
65
+ }
66
+ async listProcesses(id, procs) {
67
+ if (procs.length === 0)
68
+ return [];
69
+ const pids = procs.map((p) => p.pid).join(" ");
70
+ // A killed process orphaned to the agent (PID 1) lingers as a zombie since the
71
+ // agent doesn't reap, and `kill -0` succeeds on a zombie. So read the proc state
72
+ // and count only a present, non-`Z` (non-zombie) process as running.
73
+ const cmd = `for p in ${pids}; do s=$(sed 's/^.*) //;s/ .*//' /proc/$p/stat 2>/dev/null); ` +
74
+ `if [ -n "$s" ] && [ "$s" != "Z" ]; then echo "$p 1"; else echo "$p 0"; fi; done`;
75
+ const { stdout } = await this.execCapture(id, cmd);
76
+ const alive = new Map();
77
+ for (const line of stdout.split("\n")) {
78
+ const [p, state] = line.trim().split(" ");
79
+ if (p)
80
+ alive.set(Number(p), state === "1");
81
+ }
82
+ return procs.map((p) => ({ procId: p.procId, pid: p.pid, running: alive.get(p.pid) ?? false }));
83
+ }
84
+ async killProcess(id, pid, signal = "TERM") {
85
+ const stripped = signal.replace(/^SIG/, "");
86
+ const sig = /^[A-Z0-9]+$/.test(stripped) ? stripped : "TERM";
87
+ const cmd = `kill -${sig} -${pid} 2>/dev/null; kill -${sig} ${pid} 2>/dev/null; true`;
88
+ await this.execCapture(id, cmd);
89
+ }
90
+ async streamProcessLogs(id, logPath, opts, onData) {
91
+ const conn = await this.openConn(id);
92
+ const cmd = opts.follow ? `tail -n +1 -F ${shellEscape(logPath)}` : `cat ${shellEscape(logPath)}`;
93
+ const onAbort = () => conn.close();
94
+ opts.signal.addEventListener("abort", onAbort);
95
+ try {
96
+ await conn.exec(cmd, {}, (e) => {
97
+ if (e.type !== "exit")
98
+ onData(e.data);
99
+ });
100
+ }
101
+ catch {
102
+ /* connection closed on abort */
103
+ }
104
+ finally {
105
+ opts.signal.removeEventListener("abort", onAbort);
106
+ conn.close();
107
+ }
108
+ }
109
+ /** Raw byte bridge to `host:port` inside the guest — backs the preview-URL proxy.
110
+ * Each bridge holds its own connection (the duplex is long-lived). */
111
+ async openTcpBridge(id, port, host) {
112
+ const conn = await this.openConn(id);
113
+ const { stream } = conn.openStream({ method: "tcpConnect", host, port });
114
+ return {
115
+ stream,
116
+ close: () => {
117
+ stream.destroy();
118
+ conn.close();
119
+ },
120
+ };
121
+ }
122
+ /** Interactive PTY shell — backs the dashboard/CLI terminal. */
123
+ async openTerminal(id, opts) {
124
+ const conn = await this.openConn(id);
125
+ const { stream, streamId } = conn.openStream({
126
+ method: "openPty",
127
+ cols: opts.cols,
128
+ rows: opts.rows,
129
+ cwd: opts.cwd,
130
+ env: opts.env,
131
+ });
132
+ return {
133
+ stream,
134
+ resize: (cols, rows) => conn.controlStream(streamId, { method: "resize", cols, rows }),
135
+ close: () => {
136
+ stream.destroy();
137
+ conn.close();
138
+ },
139
+ };
140
+ }
141
+ // --- stats + backup/restore -----------------------------------------------
142
+ /** Live resource snapshot from the guest's /proc + cgroup files (via the agent).
143
+ * cpuPercent is left 0 by the guest — the metrics sampler derives it from the
144
+ * delta of successive cpuTotalUsageNs samples, exactly as for the container driver. */
145
+ async stats(id) {
146
+ const s = await this.withConn(id, (c) => c.stats());
147
+ return s;
148
+ }
149
+ /** Tar the guest's /workspace to `tarPath` on the host (over the agent). */
150
+ async createBackup(id, tarPath) {
151
+ const conn = await this.openConn(id);
152
+ try {
153
+ const out = createWriteStream(tarPath);
154
+ let bytes = 0;
155
+ await conn.readStream({ method: "tarWorkspace", path: "/workspace" }, (b) => {
156
+ bytes += b.length;
157
+ out.write(b);
158
+ });
159
+ await new Promise((resolve, reject) => out.end((err) => (err ? reject(err) : resolve())));
160
+ return { bytes };
161
+ }
162
+ finally {
163
+ conn.close();
164
+ }
165
+ }
166
+ /** Replace the guest's /workspace with the tar at `tarPath` (cleared first). */
167
+ async restoreBackup(id, tarPath) {
168
+ const conn = await this.openConn(id);
169
+ try {
170
+ const up = conn.writeStream({ method: "untarWorkspace", path: "/workspace" });
171
+ await new Promise((resolve, reject) => {
172
+ const rs = createReadStream(tarPath);
173
+ rs.on("data", (chunk) => up.write(chunk));
174
+ rs.on("end", resolve);
175
+ rs.on("error", reject);
176
+ });
177
+ up.end();
178
+ await up.done;
179
+ }
180
+ finally {
181
+ conn.close();
182
+ }
183
+ }
184
+ /** Run a command and collect its full stdout/stderr/exit (for the process shims). */
185
+ async execCapture(id, command, opts = {}) {
186
+ let stdout = "";
187
+ let stderr = "";
188
+ const exitCode = await this.exec(id, command, opts, (e) => {
189
+ if (e.type === "stdout")
190
+ stdout += e.data;
191
+ else if (e.type === "stderr")
192
+ stderr += e.data;
193
+ });
194
+ return { stdout, stderr, exitCode };
195
+ }
196
+ }
197
+ //# sourceMappingURL=agent-driver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-driver.js","sourceRoot":"","sources":["../../src/driver/agent-driver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import { type Socket } from "node:net";
2
+ import { Duplex } from "node:stream";
3
+ import type { ExecEvent, FileChangeEvent, FileInfo } from "../types.js";
4
+ export interface AgentHello {
5
+ event: string;
6
+ agent: string;
7
+ version: string;
8
+ proto: number;
9
+ }
10
+ export declare class AgentConn {
11
+ private socket;
12
+ private buf;
13
+ private nextStreamId;
14
+ private pending;
15
+ hello?: AgentHello;
16
+ private constructor();
17
+ /** Connect to the agent (via the helper's unix socket, or a test socket) and
18
+ * resolve once the Hello greeting arrives. */
19
+ static connect(opts: {
20
+ path: string;
21
+ timeoutMs?: number;
22
+ }): Promise<AgentConn>;
23
+ /**
24
+ * Wrap an already-connected byte stream (e.g. a Firecracker vsock socket after
25
+ * its `CONNECT` handshake) and resolve once the agent's Hello arrives. `leftover`
26
+ * is any bytes that arrived with the handshake reply but belong to the agent
27
+ * stream (possibly the Hello itself), fed in before live data.
28
+ */
29
+ static attach(socket: Socket, leftover?: Buffer, timeoutMs?: number): Promise<AgentConn>;
30
+ private onHello?;
31
+ /** Accumulate bytes and dispatch whole frames. */
32
+ private feed;
33
+ private handleFrame;
34
+ private failAll;
35
+ private writeFrame;
36
+ /** Send a Control request on a fresh stream; resolve on its Result frame. */
37
+ private request;
38
+ /** Run a command, streaming stdout/stderr as ExecEvents; resolves with exit code. */
39
+ exec(command: string, opts: {
40
+ cwd?: string;
41
+ env?: Record<string, string>;
42
+ }, onEvent: (e: ExecEvent) => void): Promise<number>;
43
+ writeFile(path: string, content: string, mode?: string): Promise<void>;
44
+ readFile(path: string): Promise<string>;
45
+ mkdir(path: string, parents?: boolean): Promise<void>;
46
+ listFiles(path: string): Promise<FileInfo[]>;
47
+ waitForPort(port: number, opts?: {
48
+ host?: string;
49
+ timeoutMs?: number;
50
+ intervalMs?: number;
51
+ }): Promise<boolean>;
52
+ setEnv(env: Record<string, string>): Promise<void>;
53
+ /** Start the in-guest loopback→vsock egress relay (idempotent per port): the
54
+ * agent listens on 127.0.0.1:`port` and forwards each connection over vsock
55
+ * to the host, which relays it to the egress gateway. */
56
+ egressListen(port: number, vsockPort?: number): Promise<void>;
57
+ /**
58
+ * Watch `path` recursively, invoking `onEvent` per change until `signal`
59
+ * aborts (which sends a Close frame; the agent stops and replies Result).
60
+ * The agent streams `<type>\t<path>` lines as Stdout frames.
61
+ */
62
+ watch(path: string, intervalMs: number, signal: AbortSignal, onEvent: (e: FileChangeEvent) => void): Promise<void>;
63
+ /**
64
+ * Open a bidirectional stream for a method that bridges raw bytes (tcpConnect /
65
+ * pty): writes become Stdin frames host→guest, guest Stdout frames become
66
+ * readable data, the terminal Result frame ends the readable side, and
67
+ * destroying the Duplex sends a Close frame. Returns a Node Duplex the caller
68
+ * (preview proxy / terminal WS) pipes like any socket.
69
+ */
70
+ openStream(req: Record<string, unknown>): {
71
+ stream: Duplex;
72
+ streamId: number;
73
+ };
74
+ /**
75
+ * Receive a guest→host byte stream for `req` (e.g. tarWorkspace): each Stdout
76
+ * frame's raw bytes are handed to `onChunk` (binary-safe — Buffers, no UTF-8
77
+ * decode), and the promise resolves on the terminal Result (rejects on error).
78
+ */
79
+ readStream(req: Record<string, unknown>, onChunk: (b: Buffer) => void): Promise<void>;
80
+ /**
81
+ * Send a host→guest byte stream for `req` (e.g. untarWorkspace): write payload
82
+ * chunks with `write`, signal end-of-input with `end`, and await `done` for the
83
+ * terminal Result. Bytes go as raw Stdin frames; EOF as an EOF frame.
84
+ */
85
+ writeStream(req: Record<string, unknown>): {
86
+ write: (b: Buffer) => void;
87
+ end: () => void;
88
+ done: Promise<void>;
89
+ };
90
+ /** Send a control message (e.g. pty resize) on an existing stream. */
91
+ controlStream(streamId: number, msg: Record<string, unknown>): void;
92
+ stats(): Promise<unknown>;
93
+ close(): void;
94
+ }
@@ -0,0 +1,319 @@
1
+ import { connect } from "node:net";
2
+ import { Duplex } from "node:stream";
3
+ /**
4
+ * Host-side client for the in-sandbox `sbx-agent` wire protocol (see `agent/proto`).
5
+ * One `AgentConn` wraps a single byte stream to the agent — a unix socket the VZ
6
+ * helper relays to the guest's vsock in production, or a direct unix/tcp socket
7
+ * in tests — and multiplexes concurrent requests over it by `streamId`, exactly
8
+ * as the Go server expects.
9
+ *
10
+ * Frame: `[u32 length BE][u8 type][u32 streamId BE][payload]`. The agent sends an
11
+ * unsolicited Hello (Control on stream 0) on connect; `connect()` resolves once
12
+ * it arrives, so the caller knows the guest is up and serving.
13
+ */
14
+ const FRAME = {
15
+ Control: 1,
16
+ Stdin: 2,
17
+ Stdout: 3,
18
+ Stderr: 4,
19
+ EOF: 5,
20
+ Result: 6,
21
+ Close: 7,
22
+ };
23
+ const HEADER = 9;
24
+ export class AgentConn {
25
+ socket;
26
+ buf = Buffer.alloc(0);
27
+ nextStreamId = 1; // 0 is reserved for the agent's Hello
28
+ pending = new Map();
29
+ hello;
30
+ constructor(socket) {
31
+ this.socket = socket;
32
+ }
33
+ /** Connect to the agent (via the helper's unix socket, or a test socket) and
34
+ * resolve once the Hello greeting arrives. */
35
+ static connect(opts) {
36
+ return new Promise((resolve, reject) => {
37
+ const socket = connect(opts.path);
38
+ const conn = new AgentConn(socket);
39
+ const timer = setTimeout(() => {
40
+ socket.destroy();
41
+ reject(new Error(`agent connect timed out (${opts.path})`));
42
+ }, opts.timeoutMs ?? 10000);
43
+ conn.onHello = (hello) => {
44
+ clearTimeout(timer);
45
+ conn.hello = hello;
46
+ resolve(conn);
47
+ };
48
+ socket.on("data", (d) => conn.feed(d));
49
+ socket.on("error", (e) => {
50
+ clearTimeout(timer);
51
+ conn.failAll(e);
52
+ reject(e);
53
+ });
54
+ socket.on("close", () => conn.failAll(new Error("agent connection closed")));
55
+ });
56
+ }
57
+ /**
58
+ * Wrap an already-connected byte stream (e.g. a Firecracker vsock socket after
59
+ * its `CONNECT` handshake) and resolve once the agent's Hello arrives. `leftover`
60
+ * is any bytes that arrived with the handshake reply but belong to the agent
61
+ * stream (possibly the Hello itself), fed in before live data.
62
+ */
63
+ static attach(socket, leftover, timeoutMs = 10000) {
64
+ return new Promise((resolve, reject) => {
65
+ const conn = new AgentConn(socket);
66
+ const timer = setTimeout(() => {
67
+ socket.destroy();
68
+ reject(new Error("agent hello timed out"));
69
+ }, timeoutMs);
70
+ conn.onHello = (hello) => {
71
+ clearTimeout(timer);
72
+ conn.hello = hello;
73
+ resolve(conn);
74
+ };
75
+ socket.on("data", (d) => conn.feed(d));
76
+ socket.on("error", (e) => {
77
+ clearTimeout(timer);
78
+ conn.failAll(e);
79
+ reject(e);
80
+ });
81
+ socket.on("close", () => conn.failAll(new Error("agent connection closed")));
82
+ if (leftover && leftover.length)
83
+ conn.feed(leftover);
84
+ });
85
+ }
86
+ onHello;
87
+ /** Accumulate bytes and dispatch whole frames. */
88
+ feed(data) {
89
+ this.buf = this.buf.length ? Buffer.concat([this.buf, data]) : data;
90
+ while (this.buf.length >= HEADER) {
91
+ const length = this.buf.readUInt32BE(0);
92
+ if (this.buf.length < HEADER + length)
93
+ break;
94
+ const type = this.buf[4];
95
+ const streamId = this.buf.readUInt32BE(5);
96
+ const payload = this.buf.subarray(HEADER, HEADER + length);
97
+ this.handleFrame(type, streamId, payload);
98
+ this.buf = this.buf.subarray(HEADER + length);
99
+ }
100
+ }
101
+ handleFrame(type, streamId, payload) {
102
+ if (streamId === 0 && type === FRAME.Control) {
103
+ try {
104
+ this.onHello?.(JSON.parse(payload.toString("utf8")));
105
+ }
106
+ catch {
107
+ /* ignore a malformed hello */
108
+ }
109
+ return;
110
+ }
111
+ const p = this.pending.get(streamId);
112
+ if (!p)
113
+ return;
114
+ switch (type) {
115
+ case FRAME.Stdout:
116
+ p.onStdout?.(Buffer.from(payload));
117
+ break;
118
+ case FRAME.Stderr:
119
+ p.onStderr?.(Buffer.from(payload));
120
+ break;
121
+ case FRAME.Result: {
122
+ this.pending.delete(streamId);
123
+ let r;
124
+ try {
125
+ r = JSON.parse(payload.toString("utf8"));
126
+ }
127
+ catch (e) {
128
+ return p.reject(new Error(`bad result json: ${String(e)}`));
129
+ }
130
+ if (!r.ok)
131
+ p.reject(new Error(r.error || "agent error"));
132
+ else
133
+ p.resolve(r);
134
+ break;
135
+ }
136
+ }
137
+ }
138
+ failAll(err) {
139
+ for (const p of this.pending.values())
140
+ p.reject(err);
141
+ this.pending.clear();
142
+ }
143
+ writeFrame(type, streamId, payload) {
144
+ const hdr = Buffer.allocUnsafe(HEADER);
145
+ hdr.writeUInt32BE(payload.length, 0);
146
+ hdr[4] = type;
147
+ hdr.writeUInt32BE(streamId, 5);
148
+ this.socket.write(hdr);
149
+ if (payload.length)
150
+ this.socket.write(payload);
151
+ }
152
+ /** Send a Control request on a fresh stream; resolve on its Result frame. */
153
+ request(req, handlers) {
154
+ const streamId = this.nextStreamId++;
155
+ const done = new Promise((resolve, reject) => {
156
+ this.pending.set(streamId, { resolve, reject, ...handlers });
157
+ });
158
+ this.writeFrame(FRAME.Control, streamId, Buffer.from(JSON.stringify(req), "utf8"));
159
+ return { streamId, done };
160
+ }
161
+ // --- Driver-surface RPCs --------------------------------------------------
162
+ /** Run a command, streaming stdout/stderr as ExecEvents; resolves with exit code. */
163
+ async exec(command, opts, onEvent) {
164
+ const { done } = this.request({ method: "exec", command, cwd: opts.cwd, env: opts.env }, {
165
+ onStdout: (b) => onEvent({ type: "stdout", data: b.toString("utf8") }),
166
+ onStderr: (b) => onEvent({ type: "stderr", data: b.toString("utf8") }),
167
+ });
168
+ const r = await done;
169
+ return r.exitCode ?? 0;
170
+ }
171
+ async writeFile(path, content, mode) {
172
+ await this.request({ method: "writeFile", path, content, mode }).done;
173
+ }
174
+ async readFile(path) {
175
+ const r = await this.request({ method: "readFile", path }).done;
176
+ return String(r.value ?? "");
177
+ }
178
+ async mkdir(path, parents = true) {
179
+ await this.request({ method: "mkdir", path, parents }).done;
180
+ }
181
+ async listFiles(path) {
182
+ const r = await this.request({ method: "listFiles", path }).done;
183
+ return r.value ?? [];
184
+ }
185
+ async waitForPort(port, opts = {}) {
186
+ const r = await this.request({
187
+ method: "waitForPort",
188
+ port,
189
+ host: opts.host,
190
+ timeoutMs: opts.timeoutMs,
191
+ intervalMs: opts.intervalMs,
192
+ }).done;
193
+ return Boolean(r.value);
194
+ }
195
+ async setEnv(env) {
196
+ await this.request({ method: "setEnv", env }).done;
197
+ }
198
+ /** Start the in-guest loopback→vsock egress relay (idempotent per port): the
199
+ * agent listens on 127.0.0.1:`port` and forwards each connection over vsock
200
+ * to the host, which relays it to the egress gateway. */
201
+ async egressListen(port, vsockPort) {
202
+ await this.request({ method: "egressListen", port, vsockPort }).done;
203
+ }
204
+ /**
205
+ * Watch `path` recursively, invoking `onEvent` per change until `signal`
206
+ * aborts (which sends a Close frame; the agent stops and replies Result).
207
+ * The agent streams `<type>\t<path>` lines as Stdout frames.
208
+ */
209
+ async watch(path, intervalMs, signal, onEvent) {
210
+ const streamId = this.nextStreamId++;
211
+ let lineBuf = "";
212
+ const parse = (b) => {
213
+ lineBuf += b.toString("utf8");
214
+ let idx;
215
+ while ((idx = lineBuf.indexOf("\n")) !== -1) {
216
+ const line = lineBuf.slice(0, idx);
217
+ lineBuf = lineBuf.slice(idx + 1);
218
+ const tab = line.indexOf("\t");
219
+ if (tab === -1)
220
+ continue;
221
+ const type = line.slice(0, tab);
222
+ if (type === "created" || type === "modified" || type === "deleted") {
223
+ onEvent({ type, path: line.slice(tab + 1) });
224
+ }
225
+ }
226
+ };
227
+ await new Promise((resolve, reject) => {
228
+ this.pending.set(streamId, { onStdout: parse, resolve: () => resolve(), reject });
229
+ // Open the watch stream first, then arm cancellation, so the Control frame
230
+ // always precedes any Close frame.
231
+ this.writeFrame(FRAME.Control, streamId, Buffer.from(JSON.stringify({ method: "watch", path, intervalMs }), "utf8"));
232
+ const onAbort = () => {
233
+ if (this.pending.has(streamId))
234
+ this.writeFrame(FRAME.Close, streamId, Buffer.alloc(0));
235
+ };
236
+ if (signal.aborted)
237
+ onAbort();
238
+ else
239
+ signal.addEventListener("abort", onAbort, { once: true });
240
+ });
241
+ }
242
+ /**
243
+ * Open a bidirectional stream for a method that bridges raw bytes (tcpConnect /
244
+ * pty): writes become Stdin frames host→guest, guest Stdout frames become
245
+ * readable data, the terminal Result frame ends the readable side, and
246
+ * destroying the Duplex sends a Close frame. Returns a Node Duplex the caller
247
+ * (preview proxy / terminal WS) pipes like any socket.
248
+ */
249
+ openStream(req) {
250
+ const streamId = this.nextStreamId++;
251
+ const writeFrame = this.writeFrame.bind(this);
252
+ const pending = this.pending;
253
+ const duplex = new Duplex({
254
+ write(chunk, _enc, cb) {
255
+ writeFrame(FRAME.Stdin, streamId, Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
256
+ cb();
257
+ },
258
+ read() {
259
+ /* data is pushed as Stdout frames arrive */
260
+ },
261
+ destroy(err, cb) {
262
+ if (pending.has(streamId)) {
263
+ writeFrame(FRAME.Close, streamId, Buffer.alloc(0));
264
+ pending.delete(streamId);
265
+ }
266
+ cb(err);
267
+ },
268
+ });
269
+ this.pending.set(streamId, {
270
+ onStdout: (b) => duplex.push(b),
271
+ onStderr: (b) => duplex.push(b),
272
+ resolve: () => duplex.push(null), // Result frame → readable EOF
273
+ reject: (e) => duplex.destroy(e),
274
+ });
275
+ this.writeFrame(FRAME.Control, streamId, Buffer.from(JSON.stringify(req), "utf8"));
276
+ return { stream: duplex, streamId };
277
+ }
278
+ /**
279
+ * Receive a guest→host byte stream for `req` (e.g. tarWorkspace): each Stdout
280
+ * frame's raw bytes are handed to `onChunk` (binary-safe — Buffers, no UTF-8
281
+ * decode), and the promise resolves on the terminal Result (rejects on error).
282
+ */
283
+ async readStream(req, onChunk) {
284
+ const streamId = this.nextStreamId++;
285
+ await new Promise((resolve, reject) => {
286
+ this.pending.set(streamId, { onStdout: onChunk, resolve: () => resolve(), reject });
287
+ this.writeFrame(FRAME.Control, streamId, Buffer.from(JSON.stringify(req), "utf8"));
288
+ });
289
+ }
290
+ /**
291
+ * Send a host→guest byte stream for `req` (e.g. untarWorkspace): write payload
292
+ * chunks with `write`, signal end-of-input with `end`, and await `done` for the
293
+ * terminal Result. Bytes go as raw Stdin frames; EOF as an EOF frame.
294
+ */
295
+ writeStream(req) {
296
+ const streamId = this.nextStreamId++;
297
+ const done = new Promise((resolve, reject) => {
298
+ this.pending.set(streamId, { resolve: () => resolve(), reject });
299
+ });
300
+ this.writeFrame(FRAME.Control, streamId, Buffer.from(JSON.stringify(req), "utf8"));
301
+ return {
302
+ write: (b) => this.writeFrame(FRAME.Stdin, streamId, b),
303
+ end: () => this.writeFrame(FRAME.EOF, streamId, Buffer.alloc(0)),
304
+ done,
305
+ };
306
+ }
307
+ /** Send a control message (e.g. pty resize) on an existing stream. */
308
+ controlStream(streamId, msg) {
309
+ this.writeFrame(FRAME.Control, streamId, Buffer.from(JSON.stringify(msg), "utf8"));
310
+ }
311
+ async stats() {
312
+ const r = await this.request({ method: "stats" }).done;
313
+ return r.value;
314
+ }
315
+ close() {
316
+ this.socket.destroy();
317
+ }
318
+ }
319
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/driver/agent.ts"],"names":[],"mappings":"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"}