skydive-cli 0.2.0-beta.713 → 0.2.0-beta.742

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/dist/js/bin.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { C as setActiveWorkspace, S as listWorkspaces, T as version, _ as themes, b as getActiveWorkspaceId, o as brandHelpArt, t as installCrashHandler, w as name, x as getSessionIdentity, y as ensureActiveOrganization } from "./install-DqRwUu-M.mjs";
2
+ import { C as setActiveWorkspace, S as listWorkspaces, T as version, _ as themes, b as getActiveWorkspaceId, o as brandHelpArt, t as installCrashHandler, w as name, x as getSessionIdentity, y as ensureActiveOrganization } from "./install-Cv3sBZxr.mjs";
3
3
  import { A as resolveAppUrl, C as getPromptHistoryPath, D as getStoredApiKeyId, E as getShareMachineDefault, F as saveConfig, I as saveSession, M as resolveManagementAuth, N as resolveSession, O as getStoredApiKeyWorkspaceName, R as setLastSeenVersion, S as getLastSeenVersion, _ as API_KEY_PREFIX, b as deleteConfig, g as API_KEY_FAMILY_PREFIX, h as API_KEYS_URL, i as resolveAgent, j as resolveConfig, k as getUpdateCheckDisabled, v as DEFAULT_API_URL, x as getConfigPath } from "./print-Cd-bVSEJ.mjs";
4
4
  import { n as printError, r as printTable, t as output } from "./output-DYzzdXYV.mjs";
5
5
  import { n as createRestClient, t as HttpError } from "./rest-BlN_uWmL.mjs";
@@ -1500,7 +1500,7 @@ const importCommand = {
1500
1500
  process.exit(1);
1501
1501
  }
1502
1502
  }
1503
- const { runChat } = await import("./boot-CjKGwVjP.mjs");
1503
+ const { runChat } = await import("./boot-DhorgAxS.mjs");
1504
1504
  await runChat({
1505
1505
  appUrl,
1506
1506
  sessionToken: session.value.sessionToken,
@@ -1912,7 +1912,7 @@ const chatCommand = {
1912
1912
  sessionToken: session.value.sessionToken,
1913
1913
  agentSelector: argv.agent ?? null
1914
1914
  });
1915
- const { runChat } = await import("./boot-CjKGwVjP.mjs");
1915
+ const { runChat } = await import("./boot-DhorgAxS.mjs");
1916
1916
  await runChat({
1917
1917
  appUrl,
1918
1918
  sessionToken: session.value.sessionToken,
@@ -2254,7 +2254,7 @@ const switchCommand = {
2254
2254
  printError("The workspace picker needs the Bun runtime and it could not be set up automatically. Pass a workspace slug instead, or install Bun and retry.");
2255
2255
  process.exit(1);
2256
2256
  }
2257
- const { runWorkspacePicker } = await import("./boot-CjKGwVjP.mjs");
2257
+ const { runWorkspacePicker } = await import("./boot-DhorgAxS.mjs");
2258
2258
  await runWorkspacePicker(session);
2259
2259
  return;
2260
2260
  }
@@ -2794,9 +2794,10 @@ function isNewerVersion(candidate, current) {
2794
2794
  *
2795
2795
  * package-manager installs are never self-mutated here — that's the install
2796
2796
  * mode's own tool's job, and silently reaching into a global npm/yarn/pnpm
2797
- * prefix is exactly the footgun the existing notice policy avoids. The
2798
- * command handles that mode by printing the upgrade command; this module is
2799
- * binary-only.
2797
+ * prefix is exactly the footgun the existing notice policy avoids. They still
2798
+ * go through the same {@link planUpdate} version comparison (an install that
2799
+ * skips it has no way to know it is already current); only the *action*
2800
+ * differs — the command prints, or offers to run, the upgrade command.
2800
2801
  *
2801
2802
  * The dangerous part is replacing a running executable in place, so the flow
2802
2803
  * is split: a pure {@link planUpdate} decides *whether* and *what* (testable
@@ -2806,28 +2807,56 @@ function isNewerVersion(candidate, current) {
2806
2807
  /** Cap so a wrong URL or a hung CDN can't wedge `skydive update` forever. */
2807
2808
  const DOWNLOAD_TIMEOUT_MS = 6e4;
2808
2809
  /**
2810
+ * The single version comparison every install mode goes through: only a
2811
+ * strictly newer release is an update. `allowSameVersion` (`--force`) and
2812
+ * `allowDowngrade` (rollback) are the two explicit escape hatches.
2813
+ */
2814
+ function wantsInstall(opts) {
2815
+ const newer = isNewerVersion(opts.latestVersion, opts.currentVersion);
2816
+ const same = opts.latestVersion === opts.currentVersion;
2817
+ return newer || same && opts.allowSameVersion === true || !newer && !same && opts.allowDowngrade === true;
2818
+ }
2819
+ /**
2809
2820
  * Decide what `skydive update` should do, given the running version, the
2810
- * install source, the fetched manifest (or null), and this host. Pure — no
2821
+ * install source, the channel's newest release, and this host. Pure — no
2811
2822
  * network, no filesystem — so every branch is unit-testable.
2812
2823
  *
2824
+ * `latestVersion` is the channel's current version for a **package-manager**
2825
+ * install (an npm dist-tag lookup). A binary install reads it off `manifest`
2826
+ * instead, because there the manifest is both the version pointer and the
2827
+ * byte source. Either way it must be a real fetched answer: a package-manager
2828
+ * install that skips the comparison is what made `skydive update` announce
2829
+ * "0.2.0 → 0.2.0" on every invocation.
2830
+ *
2813
2831
  * `allowSameVersion` forces a reinstall of the current version (the `--force`
2814
2832
  * escape hatch for a corrupt binary); `allowDowngrade` lets an explicit
2815
2833
  * pinned/older manifest install over a newer running binary (rollback).
2816
2834
  */
2817
2835
  function planUpdate(opts) {
2818
2836
  const { currentVersion, source, manifest, platform, arch } = opts;
2819
- if (source !== "binary") return {
2820
- kind: "unsupported-source",
2821
- source,
2822
- latestVersion: manifest?.version ?? currentVersion
2823
- };
2837
+ if (source !== "binary") {
2838
+ const { latestVersion } = opts;
2839
+ if (!latestVersion || !wantsInstall({
2840
+ ...opts,
2841
+ latestVersion
2842
+ })) return {
2843
+ kind: "up-to-date",
2844
+ currentVersion
2845
+ };
2846
+ return {
2847
+ kind: "unsupported-source",
2848
+ source,
2849
+ latestVersion
2850
+ };
2851
+ }
2824
2852
  if (!manifest) return {
2825
2853
  kind: "up-to-date",
2826
2854
  currentVersion
2827
2855
  };
2828
- const newer = isNewerVersion(manifest.version, currentVersion);
2829
- const same = manifest.version === currentVersion;
2830
- if (!(newer || same && opts.allowSameVersion === true || !newer && !same && opts.allowDowngrade === true)) return {
2856
+ if (!wantsInstall({
2857
+ ...opts,
2858
+ latestVersion: manifest.version
2859
+ })) return {
2831
2860
  kind: "up-to-date",
2832
2861
  currentVersion
2833
2862
  };
@@ -3146,6 +3175,15 @@ async function promptYesNo(question) {
3146
3175
  }
3147
3176
  }
3148
3177
  /**
3178
+ * Heading shared by the prompt and the printed instruction, so the two can't
3179
+ * disagree about what is happening. `--force` asks to reinstall the version
3180
+ * already running, and calling that an update is exactly the lie this path
3181
+ * used to tell on every invocation — so it gets its own wording.
3182
+ */
3183
+ function renderPmUpdateHeading(opts) {
3184
+ return opts.latestVersion === opts.currentVersion ? `Reinstalling ${opts.currentVersion}.` : `Update available: ${opts.currentVersion} \u2192 ${opts.latestVersion}`;
3185
+ }
3186
+ /**
3149
3187
  * Offer + run the package-manager upgrade. Returns a result the caller turns
3150
3188
  * into output and an exit/relaunch decision — kept separate from the actual
3151
3189
  * relaunch so it's testable without re-execing the test runner.
@@ -3158,7 +3196,7 @@ async function offerPackageManagerUpdate(opts) {
3158
3196
  const command = installCommand(manager, opts.channel);
3159
3197
  const commandStr = installCommandString(manager, opts.channel);
3160
3198
  if (!opts.interactive) return { status: "skipped-noninteractive" };
3161
- if (!await (opts.ask ?? promptYesNo)(`Update available: ${opts.currentVersion} \u2192 ${opts.latestVersion}\nRun \`${commandStr}\` now? [Y/n] `)) return { status: "declined" };
3199
+ if (!await (opts.ask ?? promptYesNo)(`${renderPmUpdateHeading(opts)}\nRun \`${commandStr}\` now? [Y/n] `)) return { status: "declined" };
3162
3200
  const { status } = (opts.run ?? ((cmd) => {
3163
3201
  const [bin, ...args] = cmd;
3164
3202
  return { status: spawnSync(bin ?? "", args, { stdio: "inherit" }).status };
@@ -3210,7 +3248,10 @@ function normalizeChannel(raw, currentVersion) {
3210
3248
  function describePlan(plan, channel, isCheck) {
3211
3249
  switch (plan.kind) {
3212
3250
  case "up-to-date": return `Already on the latest ${channel} release (${plan.currentVersion}).`;
3213
- case "unsupported-source": return `This is a ${plan.source} install, so update through your package manager:\n ${renderUpdateCommand(channel, plan.source)}`;
3251
+ case "unsupported-source": return `${renderPmUpdateHeading({
3252
+ currentVersion: version,
3253
+ latestVersion: plan.latestVersion
3254
+ })}\nThis is a ${plan.source} install, so update through your package manager:\n ${renderUpdateCommand(channel, plan.source)}`;
3214
3255
  case "unsupported-host": return `No Skydive binary is published for ${plan.platform}/${plan.arch}.`;
3215
3256
  case "missing-from-manifest": return `The ${channel} ${plan.version} release has no binary for your platform (${plan.target}).`;
3216
3257
  case "update": return isCheck ? `Update available: ${version} \u2192 ${plan.version} (${channel}, ${plan.target}).\nRun \`skydive update\` to install it.` : `Updating ${version} \u2192 ${plan.version} (${channel}, ${plan.target})...`;
@@ -3236,8 +3277,11 @@ const updateCommand = {
3236
3277
  const currentVersion = version;
3237
3278
  const source = resolveInstallSource();
3238
3279
  const channel = normalizeChannel(argv.channel, currentVersion);
3239
- const manifest = await releaseSourceForInstall(source).fetchManifest(channel, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS$1) }).catch(() => null);
3240
- if (source === "binary" && manifest === null) {
3280
+ const releaseSource = releaseSourceForInstall(source);
3281
+ const signal = AbortSignal.timeout(FETCH_TIMEOUT_MS$1);
3282
+ const manifest = source === "binary" ? await releaseSource.fetchManifest(channel, { signal }).catch(() => null) : null;
3283
+ const latestVersion = source === "binary" ? manifest?.version ?? null : await releaseSource.fetchLatestVersion(channel, { signal }).catch(() => null);
3284
+ if (latestVersion === null) {
3241
3285
  if (argv.json) {
3242
3286
  output(argv, {
3243
3287
  status: "unavailable",
@@ -3246,11 +3290,12 @@ const updateCommand = {
3246
3290
  });
3247
3291
  return;
3248
3292
  }
3249
- throw new UpdateError(`couldn't reach the ${channel} release channel — check your connection and try again.`);
3293
+ throw new UpdateError(source === "binary" ? `couldn't reach the ${channel} release channel — check your connection and try again.` : `couldn't reach the npm registry to look up the ${channel} release — check your connection and try again.`);
3250
3294
  }
3251
3295
  const plan = planUpdate({
3252
3296
  currentVersion,
3253
3297
  source,
3298
+ latestVersion,
3254
3299
  manifest,
3255
3300
  platform: process.platform,
3256
3301
  arch: process.arch,
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { C as setActiveWorkspace, S as listWorkspaces, a as WORDMARK, b as getActiveWorkspaceId, c as applyTheme, d as noColorRequested, f as theme, g as themeVersion, h as themeModeFromColorFgBg, i as MARK_CELLS, l as findTheme, m as themeMode, n as buildCrashReport, p as themeForMode, r as writeCrashReport, s as DEFAULT_THEME_ID, t as installCrashHandler, u as monoTheme, v as themesForMode } from "./install-DqRwUu-M.mjs";
2
+ import { C as setActiveWorkspace, S as listWorkspaces, a as WORDMARK, b as getActiveWorkspaceId, c as applyTheme, d as noColorRequested, f as theme, g as themeVersion, h as themeModeFromColorFgBg, i as MARK_CELLS, l as findTheme, m as themeMode, n as buildCrashReport, p as themeForMode, r as writeCrashReport, s as DEFAULT_THEME_ID, t as installCrashHandler, u as monoTheme, v as themesForMode } from "./install-Cv3sBZxr.mjs";
3
3
  import { L as saveTheme, P as resolveWebUrl, T as getSavedTheme, c as cardActionErrorMessage, d as reconcileMaskedInput, f as resolveConnectUrl, i as resolveAgent, l as parseExternalOauthConnectParams, m as specKeyFor, p as parseConnectCard, s as MASK_CHAR, u as parseOauthConnectParams, v as DEFAULT_API_URL, w as getReviewStateDir, x as getConfigPath, y as DEFAULT_APP_URL } from "./print-Cd-bVSEJ.mjs";
4
4
  import { a as errorMessage, i as sendErrorMessage, n as createRestClient, o as isRecord, r as errorDetail, t as HttpError } from "./rest-BlN_uWmL.mjs";
5
5
  import { t as PortalClient } from "./client-Dc7GZ3PG.mjs";
@@ -6038,6 +6038,13 @@ const slashCommands = [
6038
6038
  description: "start a new conversation with this agent",
6039
6039
  action: { kind: "new-conversation" }
6040
6040
  },
6041
+ {
6042
+ name: "fork",
6043
+ aliases: [],
6044
+ argsHint: null,
6045
+ description: "fork this conversation into a new one (full copy)",
6046
+ action: { kind: "fork" }
6047
+ },
6041
6048
  {
6042
6049
  name: "archive",
6043
6050
  aliases: [],
@@ -9186,6 +9193,7 @@ function routeInput(raw) {
9186
9193
  };
9187
9194
  }
9188
9195
  case "new-conversation":
9196
+ case "fork":
9189
9197
  case "archive-conversation":
9190
9198
  case "model-picker":
9191
9199
  case "theme-picker":
@@ -10300,10 +10308,9 @@ function ChatScreen({ agent, conversation }) {
10300
10308
  if (!rest || !conversationId || forkingRef.current) return;
10301
10309
  forkingRef.current = true;
10302
10310
  setForking(true);
10303
- const stillHere = () => {
10304
- const screen = useStore.getState().screen;
10305
- return screen.kind === "chat" && !isNewConversation(screen.conversation) && screen.conversation.id === conversationId;
10306
- };
10311
+ useStore.getState().showToast({ message: "forking into a new chat…" });
10312
+ const screenAtFork = useStore.getState().screen;
10313
+ const stillHere = () => useStore.getState().screen === screenAtFork;
10307
10314
  rest.forkConversation({ conversationId }).then((forked) => {
10308
10315
  if (!stillHere()) return;
10309
10316
  goTo({
@@ -10314,6 +10321,10 @@ function ChatScreen({ agent, conversation }) {
10314
10321
  forked
10315
10322
  })
10316
10323
  });
10324
+ useStore.getState().showToast({
10325
+ variant: "success",
10326
+ message: "Forked conversation"
10327
+ });
10317
10328
  }).catch((err) => {
10318
10329
  forkingRef.current = false;
10319
10330
  setForking(false);
@@ -10506,6 +10517,10 @@ function ChatScreen({ agent, conversation }) {
10506
10517
  ]);
10507
10518
  const executeLine = useCallback((content, staged) => {
10508
10519
  if (!content && staged.length === 0) return;
10520
+ if (forkingRef.current) {
10521
+ useStore.getState().showToast({ message: "forking… hang on" });
10522
+ return;
10523
+ }
10509
10524
  const routed = routeInput(content);
10510
10525
  if (routed.kind !== "message") {
10511
10526
  history.append(content);
@@ -10540,6 +10555,17 @@ function ChatScreen({ agent, conversation }) {
10540
10555
  }
10541
10556
  });
10542
10557
  break;
10558
+ case "fork":
10559
+ if (runRef.current.kind !== "idle") {
10560
+ useStore.getState().showToast({ message: "finish or cancel the run first (ctrl+c)" });
10561
+ break;
10562
+ }
10563
+ if (!conversationId) {
10564
+ useStore.getState().showToast({ message: "nothing to fork yet — send a message first" });
10565
+ break;
10566
+ }
10567
+ forkAndContinue();
10568
+ break;
10543
10569
  case "conversation-picker":
10544
10570
  leaveForScreen({
10545
10571
  kind: "conversation-picker",
@@ -10627,6 +10653,7 @@ function ChatScreen({ agent, conversation }) {
10627
10653
  runSandboxExec,
10628
10654
  runSandboxPty,
10629
10655
  archiveConversation,
10656
+ forkAndContinue,
10630
10657
  leaveForScreen,
10631
10658
  openConversationRef,
10632
10659
  toggleShare,
@@ -11208,7 +11235,7 @@ function ChatScreen({ agent, conversation }) {
11208
11235
  },
11209
11236
  children: /* @__PURE__ */ jsx("textarea", {
11210
11237
  ref: composerRef,
11211
- placeholder: `message ${agent.name}…`,
11238
+ placeholder: forking ? "forking into a new chat…" : `message ${agent.name}…`,
11212
11239
  keyBindings: composerKeyBindings,
11213
11240
  onContentChange: handleComposerChange,
11214
11241
  onSubmit: submit,
@@ -8,7 +8,7 @@ import fs from "node:fs";
8
8
 
9
9
  //#region package.json
10
10
  var name = "skydive-cli";
11
- var version$1 = "0.2.0-beta.713";
11
+ var version$1 = "0.2.0-beta.742";
12
12
 
13
13
  //#endregion
14
14
  //#region src/auth/organization.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skydive-cli",
3
- "version": "0.2.0-beta.713",
3
+ "version": "0.2.0-beta.742",
4
4
  "description": "Skydive CLI — cloud agents from the command line",
5
5
  "homepage": "https://skydive.com",
6
6
  "license": "MIT",