skydive-cli 0.5.0-beta.41 → 0.5.0-beta.46

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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as isRecord, t as PortalClient } from "./client-DMYwKALl.mjs";
2
+ import { n as isRecord, t as PortalClient } from "./client-C2lPer4b.mjs";
3
3
  import { t as defaultTlsCertSource } from "./tls-cert-CV-pwxVN.mjs";
4
4
  import os from "node:os";
5
5
  import path from "node:path";
@@ -21,7 +21,7 @@ import { access, appendFile, mkdir, readFile, unlink, writeFile } from "node:fs/
21
21
  * the commit time of the built tree is one monotonic clock they share.
22
22
  */
23
23
  function portalDaemonBuild() {
24
- return "1786915412";
24
+ return "1787048488";
25
25
  }
26
26
  /**
27
27
  * Whether a client carrying `mine` should replace a running daemon carrying
@@ -220,6 +220,20 @@ const clientStatusSchema = z.object({ t: z.literal("status") });
220
220
  * exits — cutting live exec/tunnel connections, not just refusing new ones.
221
221
  */
222
222
  const clientShutdownSchema = z.object({ t: z.literal("shutdown") });
223
+ /**
224
+ * `shutdown_handoff` — a newer daemon taking over (self-update / newest-build-
225
+ * wins) asks the incumbent to step down WITHOUT dropping the portal connection
226
+ * first. The incumbent frees the control socket and disconnects attached CLIs
227
+ * (they reconnect to the new daemon in ~500ms, unchanged), but KEEPS its
228
+ * outbound portal WebSocket — and thus its presence claim — alive until the
229
+ * new daemon has dialled out and claimed the machine's presence slot, at which
230
+ * point the server supersedes the incumbent's socket and it exits. This is a
231
+ * make-before-break handoff: the presence key is owned by one daemon or the
232
+ * other for the entire takeover, so `exec`/`file write` never sees a
233
+ * `registered but not connected` gap mid-upgrade. A bounded fallback timeout
234
+ * ensures the incumbent still exits if the successor never comes up.
235
+ */
236
+ const clientShutdownHandoffSchema = z.object({ t: z.literal("shutdown_handoff") });
223
237
  const clientMessageSchema = z.discriminatedUnion("t", [
224
238
  clientHelloSchema,
225
239
  clientBindSchema,
@@ -230,7 +244,8 @@ const clientMessageSchema = z.discriminatedUnion("t", [
230
244
  clientDeclineSchema,
231
245
  clientByeSchema,
232
246
  clientStatusSchema,
233
- clientShutdownSchema
247
+ clientShutdownSchema,
248
+ clientShutdownHandoffSchema
234
249
  ]);
235
250
  /**
236
251
  * `state` — the shared portal status, pushed to every attached client so each
@@ -357,6 +372,14 @@ function parseDaemonMessage(line) {
357
372
  */
358
373
  /** Grace period after the last client detaches before the daemon exits. */
359
374
  const IDLE_SHUTDOWN_MS = 3e4;
375
+ /**
376
+ * Upper bound an incumbent daemon waits, during a graceful handoff, for the
377
+ * successor to dial out and claim presence before giving up and releasing the
378
+ * slot itself. Comfortably above a normal successor boot + WS dial (a few
379
+ * hundred ms to a couple of seconds), and short enough that a failed successor
380
+ * doesn't strand the machine as reachable-but-dead for long.
381
+ */
382
+ const HANDOFF_MAX_WAIT_MS = 1e4;
360
383
  var PortalDaemon = class {
361
384
  appUrl;
362
385
  paths;
@@ -369,6 +392,7 @@ var PortalDaemon = class {
369
392
  persistedMachineName = null;
370
393
  fallbackCwd;
371
394
  idleTimer = null;
395
+ handingOff = false;
372
396
  sessionToken = null;
373
397
  deviceToken = null;
374
398
  constructor(appUrl) {
@@ -478,6 +502,9 @@ var PortalDaemon = class {
478
502
  case "shutdown":
479
503
  this.forceShutdown();
480
504
  return;
505
+ case "shutdown_handoff":
506
+ this.gracefulHandoffShutdown();
507
+ return;
481
508
  default: return msg;
482
509
  }
483
510
  }
@@ -615,6 +642,37 @@ var PortalDaemon = class {
615
642
  this.server?.close();
616
643
  process.exit(0);
617
644
  }
645
+ /**
646
+ * Graceful takeover step-down (a newer daemon is replacing us). Unlike
647
+ * `forceShutdown`, this does NOT drop the portal connection up front: doing so
648
+ * would let this machine's presence key expire (10s TTL) before the successor
649
+ * dials out and re-claims it, which is the `registered but not connected` gap
650
+ * that made `exec`/`file write` fail mid-self-update.
651
+ *
652
+ * Order matters. We free the control socket and disconnect attached CLIs
653
+ * first, because the successor cannot bind the singleton socket (and thus
654
+ * cannot start its own portal client) until we release it. But we KEEP our
655
+ * outbound portal WebSocket — and its presence claim — alive across that
656
+ * window. When the successor connects and `claim()`s the slot, the server
657
+ * supersedes us and closes our socket; `beginHandoff` resolves on that close
658
+ * and we exit. A bounded fallback inside `beginHandoff` still exits us if the
659
+ * successor never comes up, so we never hold a dead slot forever.
660
+ */
661
+ async gracefulHandoffShutdown() {
662
+ if (this.handingOff) return;
663
+ this.handingOff = true;
664
+ for (const conn of this.conns) try {
665
+ conn.socket.destroy();
666
+ } catch (_error) {}
667
+ this.conns.clear();
668
+ this.server?.close();
669
+ this.server = null;
670
+ if (this.client) {
671
+ await this.client.beginHandoff(HANDOFF_MAX_WAIT_MS);
672
+ this.client.dispose();
673
+ }
674
+ process.exit(0);
675
+ }
618
676
  async loadState() {
619
677
  try {
620
678
  const raw = await readFile(this.paths.statePath, "utf8");
@@ -663,7 +721,7 @@ async function ensureDaemonRunning(appUrl) {
663
721
  if (await isDaemonListening(socketPath)) {
664
722
  const status = await queryDaemonStatus(appUrl);
665
723
  if (!status || !isNewerBuild(portalDaemonBuild(), status.build)) return;
666
- if (await stopDaemon(appUrl) === "failed") return;
724
+ if (await stopDaemonForHandoff(appUrl) === "failed") return;
667
725
  }
668
726
  const entry = process.argv[1];
669
727
  const args = entry ? [
@@ -758,6 +816,37 @@ async function queryDaemonStatus(appUrl) {
758
816
  });
759
817
  }
760
818
  /**
819
+ * Ask a running incumbent daemon to step down for a make-before-break handoff
820
+ * (see the daemon's `gracefulHandoffShutdown`). Sends `shutdown_handoff` and
821
+ * waits for the incumbent to release the CONTROL SOCKET — at which point the
822
+ * successor can bind it and start its own portal client. Crucially, the
823
+ * incumbent keeps its portal connection (and presence) alive past this point,
824
+ * so the successor's subsequent `claim()` supersedes it with no presence gap.
825
+ *
826
+ * Returns `stopped` once the socket is free, `failed` if it never freed (the
827
+ * caller should then leave the incumbent alone rather than fight it — same
828
+ * fallback semantics as `stopDaemon`), or `not-running` if nothing was there.
829
+ * Unlike `stopDaemon` this never SIGKILLs: the incumbent is intentionally still
830
+ * alive (holding presence) after it frees the socket, so killing it by pid is
831
+ * exactly the gap this path exists to avoid.
832
+ */
833
+ async function stopDaemonForHandoff(appUrl) {
834
+ const { socketPath } = daemonPaths(appUrl);
835
+ if (!await isDaemonListening(socketPath)) return "not-running";
836
+ const sock = await connectControl(socketPath);
837
+ if (!sock) return "failed";
838
+ sock.write(encodeLine({ t: "shutdown_handoff" }));
839
+ for (let i = 0; i < 50; i += 1) {
840
+ await sleep(100);
841
+ if (!await isDaemonListening(socketPath)) {
842
+ sock.destroy();
843
+ return "stopped";
844
+ }
845
+ }
846
+ sock.destroy();
847
+ return "failed";
848
+ }
849
+ /**
761
850
  * Hard-stop a running daemon. Preferred path: send `shutdown` over the control
762
851
  * socket so it drains clients and exits cleanly. If the socket is unresponsive
763
852
  * (a wedged daemon), fall back to SIGTERM then SIGKILL by the pid the status
@@ -809,4 +898,4 @@ function sleep(ms) {
809
898
  }
810
899
 
811
900
  //#endregion
812
- 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 };
901
+ 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,7 @@
1
+ #!/usr/bin/env node
2
+ import "./client-C2lPer4b.mjs";
3
+ 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-MZN78SYL.mjs";
4
+ import "./tls-cert-CV-pwxVN.mjs";
5
+ import "./api-TwLD7ibI.mjs";
6
+
7
+ export { runPortalDaemon };
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import "./client-C2lPer4b.mjs";
3
+ import "./daemon-MZN78SYL.mjs";
4
+ import "./tls-cert-CV-pwxVN.mjs";
5
+ import "./api-TwLD7ibI.mjs";
6
+ import { t as PortalDaemonClient } from "./daemon-client-qNlw9inL.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-D8WoX21I.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-MZN78SYL.mjs";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { connect } from "node:net";
5
5
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { r as warnOnRebindProtection } from "./tls-cert-CV-pwxVN.mjs";
3
- import { l as startTlsForward, t as fetchForwardTarget } from "./api-DQCaztBg.mjs";
3
+ import { l as startTlsForward, t as fetchForwardTarget } from "./api-TwLD7ibI.mjs";
4
4
  import net from "node:net";
5
5
  import { WebSocket, createWebSocketStream } from "ws";
6
6
 
@@ -1,16 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { C as getConfigPath } from "./print-CwbdwCeQ.mjs";
2
+ import { s as version$1 } from "./rest-BtHVI0y6.mjs";
3
+ import { w as getConfigPath } from "./print-Bg8rzq9t.mjs";
3
4
  import os from "node:os";
4
5
  import path from "node:path";
5
6
  import { err, ok } from "neverthrow";
6
7
  import { z } from "zod";
7
8
  import fs from "node:fs";
8
9
 
9
- //#region package.json
10
- var name = "skydive-cli";
11
- var version$1 = "0.5.0-beta.41";
12
-
13
- //#endregion
14
10
  //#region src/auth/organization.ts
15
11
  const workspaceSchema = z.object({
16
12
  id: z.string(),
@@ -1582,4 +1578,4 @@ function printFatalNotice(file, memory) {
1582
1578
  }
1583
1579
 
1584
1580
  //#endregion
1585
- export { installAgentAlias as A, resolveWorkspaceId as B, themeVersion as C, machineOsFromPlatform as D, buildImportSeedPrompt as E, detectShell as F, name as H, ensureActiveOrganization as I, getActiveWorkspaceId as L, takenAliasNames as M, SUPPORTED_SHELLS as N, aliasActivationHint as O, defaultInstallEnv as P, getSessionIdentity as R, themeModeFromColorFgBg as S, themesForMode as T, version$1 as U, setActiveWorkspace as V, monoTheme as _, WORDMARK as a, themeForMode as b, getAutomaticLogsDir as c, profilingEnabled as d, record as f, findTheme as g, applyTheme as h, MARK_CELLS as i, slugifyAliasName as j, dedupeAliasName as k, maybeStartProfiling as l, DEFAULT_THEME_ID as m, buildCrashReport as n, brandHelpArt as o, writeArtifact as p, writeCrashReport as r, splashFitsWidth as s, installCrashHandler as t, profileDir as u, noColorRequested as v, themes as w, themeMode as x, theme as y, listWorkspaces as z };
1581
+ export { installAgentAlias as A, resolveWorkspaceId as B, themeVersion as C, machineOsFromPlatform as D, buildImportSeedPrompt as E, detectShell as F, ensureActiveOrganization as I, getActiveWorkspaceId as L, takenAliasNames as M, SUPPORTED_SHELLS as N, aliasActivationHint as O, defaultInstallEnv as P, getSessionIdentity as R, themeModeFromColorFgBg as S, themesForMode as T, setActiveWorkspace as V, monoTheme as _, WORDMARK as a, themeForMode as b, getAutomaticLogsDir as c, profilingEnabled as d, record as f, findTheme as g, applyTheme as h, MARK_CELLS as i, slugifyAliasName as j, dedupeAliasName as k, maybeStartProfiling as l, DEFAULT_THEME_ID as m, buildCrashReport as n, brandHelpArt as o, writeArtifact as p, writeCrashReport as r, splashFitsWidth as s, installCrashHandler as t, profileDir as u, noColorRequested as v, themes as w, themeMode as x, theme as y, listWorkspaces as z };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { a as runPrint, i as resolveAgent, n as messageGet, o as toPrintError, r as readStdin, t as collectRunText } from "./print-CwbdwCeQ.mjs";
3
- import "./rest-Bbe-RhMy.mjs";
2
+ import "./rest-BtHVI0y6.mjs";
3
+ import { a as runPrint, i as resolveAgent, n as messageGet, o as toPrintError, r as readStdin, t as collectRunText } from "./print-Bg8rzq9t.mjs";
4
4
  import "./billing-blocked-D3l5kJlX.mjs";
5
5
 
6
6
  export { messageGet, readStdin, resolveAgent, runPrint };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { t as HttpError } from "./http-error-UHH3mVBF.mjs";
3
- import { a as isRecord, i as errorMessage, r as sendErrorMessage, t as createRestClient } from "./rest-Bbe-RhMy.mjs";
2
+ import { a as isRecord, i as errorMessage, r as sendErrorMessage, t as createRestClient } from "./rest-BtHVI0y6.mjs";
3
+ import { t as HttpError } from "./http-error-BF2NZZE3.mjs";
4
4
  import { i as billingBlockedOutcomeFromSendResponse, n as BillingBlockedError } from "./billing-blocked-D3l5kJlX.mjs";
5
5
  import path from "node:path";
6
6
  import Conf from "conf";
@@ -440,7 +440,8 @@ function parseDesktopHandoffCard(rootEl) {
440
440
  },
441
441
  state: {},
442
442
  computeRequestId: null,
443
- settled: null
443
+ settled: null,
444
+ questions: []
444
445
  };
445
446
  }
446
447
  /**
@@ -478,7 +479,70 @@ function parseComputeRequestCard(rootEl) {
478
479
  },
479
480
  state: {},
480
481
  computeRequestId: requestId,
481
- settled
482
+ settled,
483
+ questions: []
484
+ };
485
+ }
486
+ function readQuestionOptions(raw) {
487
+ if (!Array.isArray(raw)) return [];
488
+ return raw.flatMap((o) => {
489
+ if (!isRecord(o)) return [];
490
+ const label = optionalString(o.label);
491
+ if (!label) return [];
492
+ return [{ label }];
493
+ });
494
+ }
495
+ function readQuestionEntries(raw) {
496
+ if (!Array.isArray(raw)) return [];
497
+ return raw.flatMap((q) => {
498
+ if (!isRecord(q)) return [];
499
+ const question = optionalString(q.question);
500
+ if (!question) return [];
501
+ const options = readQuestionOptions(q.options);
502
+ if (options.length < 2) return [];
503
+ return [{
504
+ question,
505
+ options,
506
+ multiSelect: Boolean(q.multiSelect)
507
+ }];
508
+ });
509
+ }
510
+ /**
511
+ * The `platform ask` form. The web renders it as an interactive picker; here
512
+ * it maps onto an answer_question button so ctrl+r (and letter shortcuts)
513
+ * open an in-TUI picker. The composed answer is sent as a normal user
514
+ * message — same non-blocking model as the web card. Without this the spec
515
+ * is not a Card, parses to null, and the question is silently dropped.
516
+ */
517
+ /** Compose the user-message body the web card also sends. */
518
+ function composeQuestionAnswer(questions, answers) {
519
+ if (questions.length === 1) return (answers[0] ?? []).join(", ");
520
+ return questions.map((q, i) => `${q.question} → ${(answers[i] ?? []).join(", ")}`).join("\n");
521
+ }
522
+ function parseQuestionCard(rootEl) {
523
+ const props = isRecord(rootEl.props) ? rootEl.props : {};
524
+ const cardId = optionalString(props.cardId);
525
+ if (!cardId) return null;
526
+ const questions = readQuestionEntries(props.questions);
527
+ if (questions.length === 0) return null;
528
+ const settled = (props.status === "answered" ? "answered" : "pending") === "answered" ? optionalString(props.answerSummary) ?? "answered" : null;
529
+ const only = questions.length === 1 ? questions[0] : void 0;
530
+ return {
531
+ title: only ? only.question : "Questions",
532
+ subtitle: null,
533
+ description: null,
534
+ fields: [],
535
+ button: settled ? null : {
536
+ label: "Answer",
537
+ action: {
538
+ kind: "answer_question",
539
+ cardId
540
+ }
541
+ },
542
+ state: {},
543
+ computeRequestId: null,
544
+ settled,
545
+ questions
482
546
  };
483
547
  }
484
548
  function parseConnectCard(spec) {
@@ -489,6 +553,7 @@ function parseConnectCard(spec) {
489
553
  if (!isRecord(rootEl)) return null;
490
554
  if (rootEl.type === "DesktopHandoffCard") return parseDesktopHandoffCard(rootEl);
491
555
  if (rootEl.type === "ComputeRequestCard") return parseComputeRequestCard(rootEl);
556
+ if (rootEl.type === "QuestionCard") return parseQuestionCard(rootEl);
492
557
  if (rootEl.type !== "Card") return null;
493
558
  const rootProps = isRecord(rootEl.props) ? rootEl.props : {};
494
559
  const title = optionalString(rootProps.title);
@@ -529,7 +594,8 @@ function parseConnectCard(spec) {
529
594
  } : null,
530
595
  state: isRecord(spec.state) ? spec.state : {},
531
596
  computeRequestId: null,
532
- settled: null
597
+ settled: null,
598
+ questions: []
533
599
  };
534
600
  }
535
601
 
@@ -677,6 +743,13 @@ function summarizeConnectCard(card, appUrl) {
677
743
  requestId: act.requestId
678
744
  }
679
745
  };
746
+ case "answer_question": return {
747
+ ...base,
748
+ action: {
749
+ kind: "answer_question",
750
+ questions: card.questions.map((q) => q.question)
751
+ }
752
+ };
680
753
  default: return {
681
754
  ...base,
682
755
  action: { kind: "unsupported" }
@@ -717,6 +790,9 @@ function formatConnectCard(card) {
717
790
  case "decide_compute":
718
791
  lines.push("Approve or deny this compute increase in the interactive TUI or web app.");
719
792
  break;
793
+ case "answer_question":
794
+ lines.push(`Answer in the interactive TUI or web app: ${card.action.questions.join("; ")}`);
795
+ break;
720
796
  case "unsupported":
721
797
  lines.push("Open this conversation in the web app to continue.");
722
798
  break;
@@ -936,4 +1012,4 @@ async function readStdin() {
936
1012
  }
937
1013
 
938
1014
  //#endregion
939
- export { getShareMachineDefault as A, resolveWebUrl as B, getConfigPath as C, getPromptHistoryPath as D, getPreference as E, resolveAppUrl as F, saveSession as H, resolveChatAuth as I, resolveConfig as L, getStoredApiKeyWorkspaceName as M, getUpdateCheckDisabled as N, getReviewStateDir as O, recordDefaultAgent as P, resolveManagementAuth as R, deleteConfig as S, getLastSeenVersion as T, saveTheme as U, saveConfig as V, setLastSeenVersion as W, API_KEY_FAMILY_PREFIX as _, runPrint as a, DEFAULT_APP_URL as b, cardActionErrorMessage as c, reconcileMaskedInput as d, resolveConnectUrl as f, API_KEYS_URL as g, specKeyFor as h, resolveAgent as i, getStoredApiKeyId as j, getSavedTheme as k, parseExternalOauthConnectParams as l, parseConnectCard as m, messageGet as n, toPrintError as o, computeSettledLabel as p, readStdin as r, MASK_CHAR as s, collectRunText as t, parseOauthConnectParams as u, API_KEY_PREFIX as v, getDefaultAgent as w, PREFERENCES as x, DEFAULT_API_URL as y, resolveSession as z };
1015
+ export { getSavedTheme as A, resolveSession as B, deleteConfig as C, getPreference as D, getLastSeenVersion as E, recordDefaultAgent as F, setLastSeenVersion as G, saveConfig as H, resolveAppUrl as I, resolveChatAuth as L, getStoredApiKeyId as M, getStoredApiKeyWorkspaceName as N, getPromptHistoryPath as O, getUpdateCheckDisabled as P, resolveConfig as R, PREFERENCES as S, getDefaultAgent as T, saveSession as U, resolveWebUrl as V, saveTheme as W, API_KEYS_URL as _, runPrint as a, DEFAULT_API_URL as b, cardActionErrorMessage as c, reconcileMaskedInput as d, resolveConnectUrl as f, specKeyFor as g, parseConnectCard as h, resolveAgent as i, getShareMachineDefault as j, getReviewStateDir as k, parseExternalOauthConnectParams as l, computeSettledLabel as m, messageGet as n, toPrintError as o, composeQuestionAnswer as p, readStdin as r, MASK_CHAR as s, collectRunText as t, parseOauthConnectParams as u, API_KEY_FAMILY_PREFIX as v, getConfigPath as w, DEFAULT_APP_URL as x, API_KEY_PREFIX as y, resolveManagementAuth as z };
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as printError } from "./output-wY0VQDea.mjs";
2
+ import { n as printError } from "./output-C9mb3sUB.mjs";
3
3
 
4
4
  //#region src/chat/print-share.ts
5
5
  /**
@@ -14,7 +14,7 @@ import { n as printError } from "./output-wY0VQDea.mjs";
14
14
  * the reply (and to --json).
15
15
  */
16
16
  async function connectMachineShare({ appUrl, sessionToken, timeoutHint }) {
17
- const { PortalClient } = await import("./client-DCwVlAal.mjs");
17
+ const { PortalClient } = await import("./client-CSKr4Swa.mjs");
18
18
  const { defaultTlsCertSource } = await import("./tls-cert-CLgSQALB.mjs");
19
19
  let signalConnected;
20
20
  const connected = new Promise((resolve) => {
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { t as HttpError } from "./http-error-UHH3mVBF.mjs";
3
- import { n as errorDetail, r as sendErrorMessage, t as createRestClient } from "./rest-Bbe-RhMy.mjs";
2
+ import { n as errorDetail, r as sendErrorMessage, t as createRestClient } from "./rest-BtHVI0y6.mjs";
3
+ import { t as HttpError } from "./http-error-BF2NZZE3.mjs";
4
4
  import "./billing-blocked-D3l5kJlX.mjs";
5
5
 
6
6
  export { createRestClient };
@@ -1,9 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import { t as HttpError } from "./http-error-UHH3mVBF.mjs";
2
+ import { t as HttpError } from "./http-error-BF2NZZE3.mjs";
3
3
  import { a as billingBlockedOutcomeSchema } from "./billing-blocked-D3l5kJlX.mjs";
4
4
  import { z } from "zod";
5
5
  import { createParser } from "eventsource-parser";
6
6
 
7
+ //#region package.json
8
+ var name = "skydive-cli";
9
+ var version = "0.5.0-beta.46";
10
+
11
+ //#endregion
7
12
  //#region src/chat/util.ts
8
13
  /** Narrowing helper for the many `unknown` payloads the chat stream and
9
14
  * tool inputs/outputs carry. A type predicate (not an `as` cast), so call
@@ -18,6 +23,7 @@ function errorMessage(err) {
18
23
 
19
24
  //#endregion
20
25
  //#region src/chat/api/rest.ts
26
+ const CLI_VERSION_HEADER = "x-skydive-cli-version";
21
27
  const ERROR_DETAIL_MAX_BODY = 2e3;
22
28
  /**
23
29
  * Fullest renderable text for a thrown value. `HttpError.message` clips the
@@ -104,7 +110,8 @@ const MAX_STREAM_RECONNECTS = 5;
104
110
  function createRestClient({ appUrl, sessionToken, workspaceId }) {
105
111
  const baseHeaders = {
106
112
  authorization: `Bearer ${sessionToken}`,
107
- accept: "application/json"
113
+ accept: "application/json",
114
+ [CLI_VERSION_HEADER]: version
108
115
  };
109
116
  if (workspaceId) baseHeaders["x-workspace-id"] = workspaceId;
110
117
  async function get(path, schema) {
@@ -147,7 +154,8 @@ function createRestClient({ appUrl, sessionToken, workspaceId }) {
147
154
  try {
148
155
  const headers = {
149
156
  authorization: `Bearer ${sessionToken}`,
150
- accept: "text/event-stream"
157
+ accept: "text/event-stream",
158
+ [CLI_VERSION_HEADER]: version
151
159
  };
152
160
  if (workspaceId) headers["x-workspace-id"] = workspaceId;
153
161
  if (lastEventId) headers["last-event-id"] = lastEventId;
@@ -441,6 +449,7 @@ function createRestClient({ appUrl, sessionToken, workspaceId }) {
441
449
  headers: {
442
450
  authorization: `Bearer ${sessionToken}`,
443
451
  accept: "text/event-stream",
452
+ [CLI_VERSION_HEADER]: version,
444
453
  ...workspaceId ? { "x-workspace-id": workspaceId } : {}
445
454
  },
446
455
  signal
@@ -687,4 +696,4 @@ const conversationStreamEventSchema = z.discriminatedUnion("kind", [
687
696
  ]);
688
697
 
689
698
  //#endregion
690
- export { isRecord as a, errorMessage as i, errorDetail as n, sendErrorMessage as r, createRestClient as t };
699
+ export { isRecord as a, errorMessage as i, errorDetail as n, name as o, sendErrorMessage as r, version as s, createRestClient as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skydive-cli",
3
- "version": "0.5.0-beta.41",
3
+ "version": "0.5.0-beta.46",
4
4
  "description": "Skydive CLI — cloud agents from the command line",
5
5
  "homepage": "https://skydive.com",
6
6
  "license": "MIT",
@@ -69,9 +69,9 @@
69
69
  },
70
70
  "//optionalDependencies": "The per-platform binary packages (skydive-cli-<os>-<arch>) are INTENTIONALLY not committed here. They are published by release-skydive-cli-binaries.yml and injected — pinned to the exact version being published — into the published launcher's optionalDependencies at release time (scripts/prepare-platform-packages.mjs --pin-version, run in release-skydive-cli.yml). Committing them would make `yarn install` try to resolve versions that only exist post-publish, breaking local dev and CI. npm installs of a published skydive-cli still get them (os/cpu-gated); the launcher (src/launcher.ts) resolves and execs the matching one. Local dev never needs them: it runs the JS bundle or `build:binary` directly.",
71
71
  "optionalDependencies": {
72
- "skydive-cli-darwin-arm64": "0.5.0-beta.41",
73
- "skydive-cli-darwin-x64": "0.5.0-beta.41",
74
- "skydive-cli-linux-x64": "0.5.0-beta.41",
75
- "skydive-cli-linux-arm64": "0.5.0-beta.41"
72
+ "skydive-cli-darwin-arm64": "0.5.0-beta.46",
73
+ "skydive-cli-darwin-x64": "0.5.0-beta.46",
74
+ "skydive-cli-linux-x64": "0.5.0-beta.46",
75
+ "skydive-cli-linux-arm64": "0.5.0-beta.46"
76
76
  }
77
77
  }
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
- import { t as PortalClient } from "./client-DMYwKALl.mjs";
3
- import "./api-DQCaztBg.mjs";
4
-
5
- export { PortalClient };
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./client-DMYwKALl.mjs";
3
- import { a as runPortalDaemon, i as queryDaemonStatus, n as ensureDaemonRunning, o as startPortalDaemon, r as isDaemonListening, s as stopDaemon, t as PortalDaemon } from "./daemon-D8WoX21I.mjs";
4
- import "./tls-cert-CV-pwxVN.mjs";
5
- import "./api-DQCaztBg.mjs";
6
-
7
- export { runPortalDaemon };
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./client-DMYwKALl.mjs";
3
- import "./daemon-D8WoX21I.mjs";
4
- import "./tls-cert-CV-pwxVN.mjs";
5
- import "./api-DQCaztBg.mjs";
6
- import { t as PortalDaemonClient } from "./daemon-client-Bp5DMeIi.mjs";
7
-
8
- export { PortalDaemonClient };