skydive-cli 0.5.0-beta.8 → 0.5.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 (39) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +61 -13
  3. package/dist/js/api-BFQ4PQDA.mjs +315 -0
  4. package/dist/js/{billing-blocked-Dgu5-oDy.mjs → billing-blocked-SE6tySLd.mjs} +1 -1
  5. package/dist/js/bin.mjs +674 -307
  6. package/dist/js/{boot-BCClEpCM.mjs → boot-DD4T-61U.mjs} +4558 -930
  7. package/dist/js/chunk-BbwQpWto.mjs +33 -0
  8. package/dist/js/{client-DabRpc_T.mjs → client--k9cjfkX.mjs} +437 -39
  9. package/dist/js/{client-c4c5MmgN.mjs → client-Btq6bMzX.mjs} +108 -2
  10. package/dist/js/client-Ct0-JZSS.mjs +5 -0
  11. package/dist/js/daemon-CCgNLD0H.mjs +7 -0
  12. package/dist/js/{daemon-k2kVkJ8D.mjs → daemon-Do1jU2UF.mjs} +123 -43
  13. package/dist/js/daemon-client-C7nE-lLK.mjs +8 -0
  14. package/dist/js/{daemon-client-fxf1A25Z.mjs → daemon-client-Dvad009G.mjs} +1 -1
  15. package/dist/js/dist-CRtjM7ba.mjs +1750 -0
  16. package/dist/js/forward-C-f04uyE.mjs +208 -0
  17. package/dist/js/{profiler-DawY0V0Z.mjs → install-CtAVvERm.mjs} +545 -215
  18. package/dist/js/launcher.mjs +49 -0
  19. package/dist/js/localhost-cert-Bn-UBUmj.mjs +67 -0
  20. package/dist/js/{print-Wakr3GJd.mjs → print-Bx8qUC9U.mjs} +3 -3
  21. package/dist/js/{print-BpuyEfWX.mjs → print-D_UEjdSw.mjs} +257 -35
  22. package/dist/js/{print-share-CKLPmsg0.mjs → print-share-Cz0EO2RK.mjs} +9 -3
  23. package/dist/js/raw-pty-Ci2qFR9F.mjs +5 -0
  24. package/dist/js/{raw-pty-DY4KelZW.mjs → raw-pty-D5PhKZSl.mjs} +1 -1
  25. package/dist/js/{rest-I3imNduB.mjs → rest-B9__Zsuk.mjs} +144 -19
  26. package/dist/js/rest-Dc0EEok3.mjs +6 -0
  27. package/dist/js/tls-cert-BpCaD5AT.mjs +4 -0
  28. package/dist/js/tls-cert-Rua2oV7n.mjs +67 -0
  29. package/package.json +12 -4
  30. package/dist/js/api-DG5W6iwx.mjs +0 -131
  31. package/dist/js/client-BuU34IVE.mjs +0 -5
  32. package/dist/js/daemon-BxU59xie.mjs +0 -6
  33. package/dist/js/daemon-client-C2BvZgKO.mjs +0 -7
  34. package/dist/js/forward-18QoL5dO.mjs +0 -68
  35. package/dist/js/raw-pty-DmdUf4_w.mjs +0 -5
  36. package/dist/js/rest-D29qNkto.mjs +0 -6
  37. /package/dist/js/{billing-blocked-2wju4gC_.mjs → billing-blocked-D3l5kJlX.mjs} +0 -0
  38. /package/dist/js/{http-error-DzyrsLAZ.mjs → http-error-BF2NZZE3.mjs} +0 -0
  39. /package/dist/js/{output-DYzzdXYV.mjs → output-C9mb3sUB.mjs} +0 -0
@@ -1,6 +1,108 @@
1
1
  #!/usr/bin/env node
2
2
  import { WebSocket } from "ws";
3
3
 
4
+ //#region ../sandbox-stream-protocol/src/fs.ts
5
+ /** fs frame type bytes. Disjoint from FRAME.* in ./index.ts. */
6
+ const FS_FRAME = {
7
+ REQ: 32,
8
+ RES: 33
9
+ };
10
+ /** Filesystem operations the channel supports. One byte on the wire. */
11
+ const FS_OP = {
12
+ LIST: 1,
13
+ STAT: 2,
14
+ READ: 3,
15
+ WRITE: 4,
16
+ MKDIR: 5,
17
+ RENAME: 6,
18
+ REMOVE: 7,
19
+ EXISTS: 8
20
+ };
21
+ /** Reply status. OK carries a result; ERR carries a message in `json.message`. */
22
+ const FS_STATUS = {
23
+ OK: 0,
24
+ ERR: 1
25
+ };
26
+ const FS_MAX_BLOB_BYTES = 8 * 1024 * 1024;
27
+ const OP_TO_CODE = {
28
+ list: FS_OP.LIST,
29
+ stat: FS_OP.STAT,
30
+ read: FS_OP.READ,
31
+ write: FS_OP.WRITE,
32
+ mkdir: FS_OP.MKDIR,
33
+ rename: FS_OP.RENAME,
34
+ remove: FS_OP.REMOVE,
35
+ exists: FS_OP.EXISTS
36
+ };
37
+ const CODE_TO_OP = new Map(Object.entries(OP_TO_CODE).map(([op, code]) => [code, op]));
38
+ const textEncoder = new TextEncoder();
39
+ const textDecoder = new TextDecoder();
40
+ function frame(type, reqId, byte2, json, blob) {
41
+ const jsonBytes = textEncoder.encode(JSON.stringify(json ?? {}));
42
+ const out = new Uint8Array(10 + jsonBytes.length + blob.length);
43
+ const dv = new DataView(out.buffer);
44
+ out[0] = type;
45
+ dv.setUint32(1, reqId >>> 0);
46
+ out[5] = byte2;
47
+ dv.setUint32(6, jsonBytes.length);
48
+ out.set(jsonBytes, 10);
49
+ out.set(blob, 10 + jsonBytes.length);
50
+ return out;
51
+ }
52
+ const EMPTY = new Uint8Array(0);
53
+ /** client → server: encode an fs request. `blob` is the write payload, or null. */
54
+ function encodeFsRequest(reqId, req, blob) {
55
+ return frame(FS_FRAME.REQ, reqId, OP_TO_CODE[req.op], req, blob ?? EMPTY);
56
+ }
57
+ /**
58
+ * Decode a server fs reply frame. Returns null for a malformed frame so a peer
59
+ * on a newer protocol can't crash the client.
60
+ */
61
+ function decodeFsResponse(frameBytes) {
62
+ const parsed = parseFrame(FS_FRAME.RES, frameBytes);
63
+ if (!parsed) return null;
64
+ if (parsed.byte2 === FS_STATUS.ERR) {
65
+ const message = typeof parsed.json.message === "string" ? parsed.json.message : "fs operation failed";
66
+ return {
67
+ reqId: parsed.reqId,
68
+ status: "error",
69
+ message
70
+ };
71
+ }
72
+ return {
73
+ reqId: parsed.reqId,
74
+ status: "ok",
75
+ result: parsed.json,
76
+ blob: parsed.blob
77
+ };
78
+ }
79
+ function parseFrame(expectedType, frameBytes) {
80
+ if (frameBytes.length < 10) return null;
81
+ if (frameBytes[0] !== expectedType) return null;
82
+ const dv = new DataView(frameBytes.buffer, frameBytes.byteOffset, frameBytes.byteLength);
83
+ const reqId = dv.getUint32(1);
84
+ const byte2 = frameBytes[5] ?? 0;
85
+ const jsonLen = dv.getUint32(6);
86
+ const jsonStart = 10;
87
+ const jsonEnd = jsonStart + jsonLen;
88
+ if (jsonEnd > frameBytes.length) return null;
89
+ let json;
90
+ try {
91
+ const parsed = jsonLen ? JSON.parse(textDecoder.decode(frameBytes.subarray(jsonStart, jsonEnd))) : {};
92
+ if (typeof parsed !== "object" || parsed === null) return null;
93
+ json = parsed;
94
+ } catch {
95
+ return null;
96
+ }
97
+ return {
98
+ reqId,
99
+ byte2,
100
+ json,
101
+ blob: frameBytes.subarray(jsonEnd)
102
+ };
103
+ }
104
+
105
+ //#endregion
4
106
  //#region ../sandbox-stream-protocol/src/index.ts
5
107
  const SANDBOX_STREAM_PATH = "/api/v1/sandbox/stream";
6
108
  const FRAME = {
@@ -19,11 +121,15 @@ function streamSpecToQuery(spec) {
19
121
  cols: String(spec.cols),
20
122
  rows: String(spec.rows)
21
123
  };
22
- return {
124
+ if (spec.mode === "exec") return {
23
125
  agentId: spec.agentId,
24
126
  mode: "exec",
25
127
  command: spec.command
26
128
  };
129
+ return {
130
+ agentId: spec.agentId,
131
+ mode: "fs"
132
+ };
27
133
  }
28
134
  function withType(type, payload) {
29
135
  const frame = new Uint8Array(1 + payload.length);
@@ -166,4 +272,4 @@ function toBuffer(data) {
166
272
  }
167
273
 
168
274
  //#endregion
169
- export { SandboxStream as t };
275
+ export { encodeFsRequest as a, decodeFsResponse as i, SANDBOX_STREAM_PATH as n, streamSpecToQuery as r, SandboxStream as t };
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import { t as PortalClient } from "./client--k9cjfkX.mjs";
3
+ import "./api-BFQ4PQDA.mjs";
4
+
5
+ export { PortalClient };
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import "./client--k9cjfkX.mjs";
3
+ import "./tls-cert-Rua2oV7n.mjs";
4
+ import "./api-BFQ4PQDA.mjs";
5
+ import { a as runPortalDaemon, c as stopDaemonForHandoff, i as queryDaemonStatus, n as ensureDaemonRunning, o as startPortalDaemon, r as isDaemonListening, s as stopDaemon, t as PortalDaemon } from "./daemon-Do1jU2UF.mjs";
6
+
7
+ export { runPortalDaemon };
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { n as isRecord, t as PortalClient } from "./client-DabRpc_T.mjs";
2
+ import { i as isRecord, n as isNewerBuild, r as portalDaemonBuild, t as PortalClient } from "./client--k9cjfkX.mjs";
3
+ import { t as defaultTlsCertSource } from "./tls-cert-Rua2oV7n.mjs";
3
4
  import os from "node:os";
4
5
  import path from "node:path";
5
6
  import { z } from "zod";
@@ -8,43 +9,6 @@ import { createHash } from "node:crypto";
8
9
  import { connect, createServer } from "node:net";
9
10
  import { access, appendFile, mkdir, readFile, unlink, writeFile } from "node:fs/promises";
10
11
 
11
- //#region ../portal-daemon/src/build-stamp.ts
12
- /**
13
- * This build's stamp: the unix commit time (seconds) of the source it was
14
- * compiled from. Empty string when unstamped (a dev source run without the
15
- * env override).
16
- *
17
- * Why a commit time and not a package version: the daemon ships inside two
18
- * independently-versioned installers (the skydive CLI and the desktop app),
19
- * so their semvers are not comparable — but both build from this repo, so
20
- * the commit time of the built tree is one monotonic clock they share.
21
- */
22
- function portalDaemonBuild() {
23
- return "1786596877";
24
- }
25
- /**
26
- * Whether a client carrying `mine` should replace a running daemon carrying
27
- * `theirs` (newest build wins):
28
- *
29
- * - an unstamped client never takes over — it can't prove it's newer;
30
- * - a stamped client replaces an unstamped daemon — every stamped build
31
- * postdates stamping, so the unstamped daemon is older by construction;
32
- * - otherwise strictly greater wins; equal keeps the incumbent, so two
33
- * identical builds never bounce the daemon between them.
34
- */
35
- function isNewerBuild(mine, theirs) {
36
- const mineAt = parseStamp(mine);
37
- if (mineAt === null) return false;
38
- const theirsAt = parseStamp(theirs);
39
- if (theirsAt === null) return true;
40
- return mineAt > theirsAt;
41
- }
42
- function parseStamp(stamp) {
43
- if (!/^[0-9]+$/.test(stamp)) return null;
44
- return Number(stamp);
45
- }
46
-
47
- //#endregion
48
12
  //#region ../portal-daemon/src/local-protocol.ts
49
13
  /**
50
14
  * Local IPC between the portal DAEMON and the `skydive` CLI processes attached
@@ -219,6 +183,20 @@ const clientStatusSchema = z.object({ t: z.literal("status") });
219
183
  * exits — cutting live exec/tunnel connections, not just refusing new ones.
220
184
  */
221
185
  const clientShutdownSchema = z.object({ t: z.literal("shutdown") });
186
+ /**
187
+ * `shutdown_handoff` — a newer daemon taking over (self-update / newest-build-
188
+ * wins) asks the incumbent to step down WITHOUT dropping the portal connection
189
+ * first. The incumbent frees the control socket and disconnects attached CLIs
190
+ * (they reconnect to the new daemon in ~500ms, unchanged), but KEEPS its
191
+ * outbound portal WebSocket — and thus its presence claim — alive until the
192
+ * new daemon has dialled out and claimed the machine's presence slot, at which
193
+ * point the server supersedes the incumbent's socket and it exits. This is a
194
+ * make-before-break handoff: the presence key is owned by one daemon or the
195
+ * other for the entire takeover, so `exec`/`file write` never sees a
196
+ * `registered but not connected` gap mid-upgrade. A bounded fallback timeout
197
+ * ensures the incumbent still exits if the successor never comes up.
198
+ */
199
+ const clientShutdownHandoffSchema = z.object({ t: z.literal("shutdown_handoff") });
222
200
  const clientMessageSchema = z.discriminatedUnion("t", [
223
201
  clientHelloSchema,
224
202
  clientBindSchema,
@@ -229,7 +207,8 @@ const clientMessageSchema = z.discriminatedUnion("t", [
229
207
  clientDeclineSchema,
230
208
  clientByeSchema,
231
209
  clientStatusSchema,
232
- clientShutdownSchema
210
+ clientShutdownSchema,
211
+ clientShutdownHandoffSchema
233
212
  ]);
234
213
  /**
235
214
  * `state` — the shared portal status, pushed to every attached client so each
@@ -356,6 +335,14 @@ function parseDaemonMessage(line) {
356
335
  */
357
336
  /** Grace period after the last client detaches before the daemon exits. */
358
337
  const IDLE_SHUTDOWN_MS = 3e4;
338
+ /**
339
+ * Upper bound an incumbent daemon waits, during a graceful handoff, for the
340
+ * successor to dial out and claim presence before giving up and releasing the
341
+ * slot itself. Comfortably above a normal successor boot + WS dial (a few
342
+ * hundred ms to a couple of seconds), and short enough that a failed successor
343
+ * doesn't strand the machine as reachable-but-dead for long.
344
+ */
345
+ const HANDOFF_MAX_WAIT_MS = 1e4;
359
346
  var PortalDaemon = class {
360
347
  appUrl;
361
348
  paths;
@@ -365,8 +352,10 @@ var PortalDaemon = class {
365
352
  conns = /* @__PURE__ */ new Set();
366
353
  cwds = /* @__PURE__ */ new Map();
367
354
  declined = /* @__PURE__ */ new Set();
355
+ persistedMachineName = null;
368
356
  fallbackCwd;
369
357
  idleTimer = null;
358
+ handingOff = false;
370
359
  sessionToken = null;
371
360
  deviceToken = null;
372
361
  constructor(appUrl) {
@@ -476,6 +465,9 @@ var PortalDaemon = class {
476
465
  case "shutdown":
477
466
  this.forceShutdown();
478
467
  return;
468
+ case "shutdown_handoff":
469
+ this.gracefulHandoffShutdown();
470
+ return;
479
471
  default: return msg;
480
472
  }
481
473
  }
@@ -499,12 +491,29 @@ var PortalDaemon = class {
499
491
  deviceToken: this.deviceToken
500
492
  }),
501
493
  resolveCwd: (conversationId) => this.resolveCwd(conversationId),
494
+ tlsCertSource: defaultTlsCertSource(process.env, (msg) => this.logInfo(msg)),
495
+ persistedMachineName: this.persistedMachineName,
496
+ onMachineName: (name, source) => this.onMachineName(name, source),
502
497
  onState: (state) => {
503
498
  this.lastState = state;
504
499
  this.broadcastState();
505
500
  }
506
501
  });
507
502
  }
503
+ /**
504
+ * The identity resolved on connect. Persist the name so a later scutil
505
+ * failure reuses it instead of adopting the volatile hostname, and log the
506
+ * source — a `hostname-fallback` after we'd previously registered under
507
+ * scutil is the tell that a flap just orphaned this machine's grants.
508
+ */
509
+ onMachineName(name, source) {
510
+ if (source === "hostname-fallback" && this.persistedMachineName) this.logInfo(`portal identity WARNING: fell back to hostname "${name}" but had previously registered as "${this.persistedMachineName}" — grants may be orphaned`);
511
+ else this.logInfo(`portal identity: "${name}" (source=${source})`);
512
+ if (name && name !== this.persistedMachineName) {
513
+ this.persistedMachineName = name;
514
+ this.persistState();
515
+ }
516
+ }
508
517
  /** The cwd an exec for `conversationId` runs in. */
509
518
  resolveCwd(conversationId) {
510
519
  if (conversationId) {
@@ -538,7 +547,14 @@ var PortalDaemon = class {
538
547
  /** Append a line to the daemon log file (best-effort, for post-hoc debugging). */
539
548
  logError(context, error) {
540
549
  const message = error instanceof Error ? error.message : String(error);
541
- const line = `${(/* @__PURE__ */ new Date()).toISOString()} ${context}: ${message}\n`;
550
+ this.logLine(`${context}: ${message}`);
551
+ }
552
+ /** Append an informational line to the daemon log file (best-effort). */
553
+ logInfo(message) {
554
+ this.logLine(message);
555
+ }
556
+ logLine(message) {
557
+ const line = `${(/* @__PURE__ */ new Date()).toISOString()} ${message}\n`;
542
558
  appendFile(this.paths.logPath, line).catch((_error) => {});
543
559
  }
544
560
  /** Close the listener without exiting the process (tests own the process). */
@@ -589,6 +605,37 @@ var PortalDaemon = class {
589
605
  this.server?.close();
590
606
  process.exit(0);
591
607
  }
608
+ /**
609
+ * Graceful takeover step-down (a newer daemon is replacing us). Unlike
610
+ * `forceShutdown`, this does NOT drop the portal connection up front: doing so
611
+ * would let this machine's presence key expire (10s TTL) before the successor
612
+ * dials out and re-claims it, which is the `registered but not connected` gap
613
+ * that made `exec`/`file write` fail mid-self-update.
614
+ *
615
+ * Order matters. We free the control socket and disconnect attached CLIs
616
+ * first, because the successor cannot bind the singleton socket (and thus
617
+ * cannot start its own portal client) until we release it. But we KEEP our
618
+ * outbound portal WebSocket — and its presence claim — alive across that
619
+ * window. When the successor connects and `claim()`s the slot, the server
620
+ * supersedes us and closes our socket; `beginHandoff` resolves on that close
621
+ * and we exit. A bounded fallback inside `beginHandoff` still exits us if the
622
+ * successor never comes up, so we never hold a dead slot forever.
623
+ */
624
+ async gracefulHandoffShutdown() {
625
+ if (this.handingOff) return;
626
+ this.handingOff = true;
627
+ for (const conn of this.conns) try {
628
+ conn.socket.destroy();
629
+ } catch (_error) {}
630
+ this.conns.clear();
631
+ this.server?.close();
632
+ this.server = null;
633
+ if (this.client) {
634
+ await this.client.beginHandoff(HANDOFF_MAX_WAIT_MS);
635
+ this.client.dispose();
636
+ }
637
+ process.exit(0);
638
+ }
592
639
  async loadState() {
593
640
  try {
594
641
  const raw = await readFile(this.paths.statePath, "utf8");
@@ -598,6 +645,7 @@ var PortalDaemon = class {
598
645
  if (Array.isArray(parsed.declined)) {
599
646
  for (const id of parsed.declined) if (typeof id === "string") this.declined.add(id);
600
647
  }
648
+ if (typeof parsed.machineName === "string" && parsed.machineName) this.persistedMachineName = parsed.machineName;
601
649
  }
602
650
  } catch (_error) {}
603
651
  }
@@ -605,7 +653,8 @@ var PortalDaemon = class {
605
653
  const state = {
606
654
  version: LOCAL_PROTOCOL_VERSION,
607
655
  cwds: Object.fromEntries(this.cwds),
608
- declined: [...this.declined]
656
+ declined: [...this.declined],
657
+ machineName: this.persistedMachineName ?? void 0
609
658
  };
610
659
  writeFile(this.paths.statePath, JSON.stringify(state)).catch((error) => {
611
660
  this.logError("persistState failed", error);
@@ -635,7 +684,7 @@ async function ensureDaemonRunning(appUrl) {
635
684
  if (await isDaemonListening(socketPath)) {
636
685
  const status = await queryDaemonStatus(appUrl);
637
686
  if (!status || !isNewerBuild(portalDaemonBuild(), status.build)) return;
638
- if (await stopDaemon(appUrl) === "failed") return;
687
+ if (await stopDaemonForHandoff(appUrl) === "failed") return;
639
688
  }
640
689
  const entry = process.argv[1];
641
690
  const args = entry ? [
@@ -730,6 +779,37 @@ async function queryDaemonStatus(appUrl) {
730
779
  });
731
780
  }
732
781
  /**
782
+ * Ask a running incumbent daemon to step down for a make-before-break handoff
783
+ * (see the daemon's `gracefulHandoffShutdown`). Sends `shutdown_handoff` and
784
+ * waits for the incumbent to release the CONTROL SOCKET — at which point the
785
+ * successor can bind it and start its own portal client. Crucially, the
786
+ * incumbent keeps its portal connection (and presence) alive past this point,
787
+ * so the successor's subsequent `claim()` supersedes it with no presence gap.
788
+ *
789
+ * Returns `stopped` once the socket is free, `failed` if it never freed (the
790
+ * caller should then leave the incumbent alone rather than fight it — same
791
+ * fallback semantics as `stopDaemon`), or `not-running` if nothing was there.
792
+ * Unlike `stopDaemon` this never SIGKILLs: the incumbent is intentionally still
793
+ * alive (holding presence) after it frees the socket, so killing it by pid is
794
+ * exactly the gap this path exists to avoid.
795
+ */
796
+ async function stopDaemonForHandoff(appUrl) {
797
+ const { socketPath } = daemonPaths(appUrl);
798
+ if (!await isDaemonListening(socketPath)) return "not-running";
799
+ const sock = await connectControl(socketPath);
800
+ if (!sock) return "failed";
801
+ sock.write(encodeLine({ t: "shutdown_handoff" }));
802
+ for (let i = 0; i < 50; i += 1) {
803
+ await sleep(100);
804
+ if (!await isDaemonListening(socketPath)) {
805
+ sock.destroy();
806
+ return "stopped";
807
+ }
808
+ }
809
+ sock.destroy();
810
+ return "failed";
811
+ }
812
+ /**
733
813
  * Hard-stop a running daemon. Preferred path: send `shutdown` over the control
734
814
  * socket so it drains clients and exits cleanly. If the socket is unresponsive
735
815
  * (a wedged daemon), fall back to SIGTERM then SIGKILL by the pid the status
@@ -781,4 +861,4 @@ function sleep(ms) {
781
861
  }
782
862
 
783
863
  //#endregion
784
- export { runPortalDaemon as a, LOCAL_PROTOCOL_VERSION as c, encodeLine as d, makeLineParser as f, queryDaemonStatus as i, PORTAL_DAEMON_FLAG as l, ensureDaemonRunning as n, startPortalDaemon as o, parseDaemonMessage as p, isDaemonListening as r, stopDaemon as s, PortalDaemon as t, daemonPaths as u };
864
+ export { runPortalDaemon as a, stopDaemonForHandoff as c, daemonPaths as d, encodeLine as f, queryDaemonStatus as i, LOCAL_PROTOCOL_VERSION as l, parseDaemonMessage as m, ensureDaemonRunning as n, startPortalDaemon as o, makeLineParser as p, isDaemonListening as r, stopDaemon as s, PortalDaemon as t, PORTAL_DAEMON_FLAG as u };
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import "./client--k9cjfkX.mjs";
3
+ import "./tls-cert-Rua2oV7n.mjs";
4
+ import "./api-BFQ4PQDA.mjs";
5
+ import "./daemon-Do1jU2UF.mjs";
6
+ import { t as PortalDaemonClient } from "./daemon-client-Dvad009G.mjs";
7
+
8
+ export { PortalDaemonClient };
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { c as LOCAL_PROTOCOL_VERSION, d as encodeLine, f as makeLineParser, n as ensureDaemonRunning, p as parseDaemonMessage, u as daemonPaths } from "./daemon-k2kVkJ8D.mjs";
2
+ import { d as daemonPaths, f as encodeLine, l as LOCAL_PROTOCOL_VERSION, m as parseDaemonMessage, n as ensureDaemonRunning, p as makeLineParser } from "./daemon-Do1jU2UF.mjs";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { connect } from "node:net";
5
5