skydive-cli 0.6.0-beta.23 → 0.6.0-beta.24

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,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import { c as version, s as name, t as createRestClient } from "./rest-CQ76yHFR.mjs";
3
- import { A as getPromptHistoryPath, B as resolveConfig, D as getDefaultAgent, E as getConfigPath, F as getStoredApiKeyWorkspaceName, G as saveSession, H as resolveSession$1, I as getUpdateCheckDisabled, N as getShareMachineDefault, O as getLastSeenVersion, P as getStoredApiKeyId, R as resolveAppUrl, S as DEFAULT_API_URL, T as deleteConfig, V as resolveManagementAuth, W as saveConfig, b as API_KEY_FAMILY_PREFIX, i as resolveAgent$1, k as getPreference, q as setLastSeenVersion, w as PREFERENCES, x as API_KEY_PREFIX, y as API_KEYS_URL, z as resolveChatAuth } from "./print-CHSPHoin.mjs";
4
- import { A as installAgentAlias, B as resolveWorkspaceId, D as machineOsFromPlatform, E as buildImportSeedPrompt, F as detectShell, I as ensureActiveOrganization, L as getActiveWorkspaceId, M as takenAliasNames, N as SUPPORTED_SHELLS, O as aliasActivationHint, P as defaultInstallEnv, R as getSessionIdentity, V as setActiveWorkspace, c as getAutomaticLogsDir, j as slugifyAliasName, k as dedupeAliasName, l as maybeStartProfiling, o as brandHelpArt, t as installCrashHandler, u as profileDir, w as themes, z as listWorkspaces } from "./install-CdbqsofY.mjs";
2
+ import { c as version, s as name, t as createRestClient } from "./rest-si3NhA-L.mjs";
3
+ import { A as getPromptHistoryPath, B as resolveConfig, D as getDefaultAgent, E as getConfigPath, F as getStoredApiKeyWorkspaceName, G as saveSession, H as resolveSession$1, I as getUpdateCheckDisabled, N as getShareMachineDefault, O as getLastSeenVersion, P as getStoredApiKeyId, R as resolveAppUrl, S as DEFAULT_API_URL, T as deleteConfig, V as resolveManagementAuth, W as saveConfig, b as API_KEY_FAMILY_PREFIX, i as resolveAgent$1, k as getPreference, q as setLastSeenVersion, w as PREFERENCES, x as API_KEY_PREFIX, y as API_KEYS_URL, z as resolveChatAuth } from "./print-DDI8g0HX.mjs";
4
+ import { A as installAgentAlias, B as resolveWorkspaceId, D as machineOsFromPlatform, E as buildImportSeedPrompt, F as detectShell, I as ensureActiveOrganization, L as getActiveWorkspaceId, M as takenAliasNames, N as SUPPORTED_SHELLS, O as aliasActivationHint, P as defaultInstallEnv, R as getSessionIdentity, V as setActiveWorkspace, c as getAutomaticLogsDir, j as slugifyAliasName, k as dedupeAliasName, l as maybeStartProfiling, o as brandHelpArt, t as installCrashHandler, u as profileDir, w as themes, z as listWorkspaces } from "./install-KL5zAlW8.mjs";
5
5
  import { n as printError, r as printTable, t as output } from "./output-C9mb3sUB.mjs";
6
6
  import { t as HttpError } from "./http-error-BF2NZZE3.mjs";
7
7
  import "./billing-blocked-D3l5kJlX.mjs";
8
- import { a as resolveMachineIdentity } from "./client-DJ0bPjqx.mjs";
8
+ import { a as resolveMachineIdentity } from "./client-CNF1DFAQ.mjs";
9
9
  import "./tls-cert-Rua2oV7n.mjs";
10
10
  import { i as grantPortalAccess, n as fetchPortalDevices, o as registerPortalDevice, r as findThisDevice, s as revokePortalAccess } from "./api-BFQ4PQDA.mjs";
11
- import { d as daemonPaths, i as queryDaemonStatus, n as ensureDaemonRunning, s as stopDaemon, u as PORTAL_DAEMON_FLAG } from "./daemon-ccNQRdJd.mjs";
11
+ import { d as daemonPaths, i as queryDaemonStatus, n as ensureDaemonRunning, s as stopDaemon, u as PORTAL_DAEMON_FLAG } from "./daemon-D4B5LeNQ.mjs";
12
12
  import { a as encodeFsRequest, i as decodeFsResponse, n as SANDBOX_STREAM_PATH, r as streamSpecToQuery, t as SandboxStream } from "./client-l6orYfqq.mjs";
13
13
  import { hideBin } from "yargs/helpers";
14
14
  import yargs from "yargs";
@@ -1586,7 +1586,7 @@ const importCommand = {
1586
1586
  process.exit(1);
1587
1587
  }
1588
1588
  }
1589
- const { runChat } = await import("./boot-BtEzGVMb.mjs");
1589
+ const { runChat } = await import("./boot-CZ_17jJG.mjs");
1590
1590
  await runChat({
1591
1591
  appUrl,
1592
1592
  sessionToken: session.value.sessionToken,
@@ -1616,7 +1616,7 @@ async function runImportPrintMode({ argv, appUrl }) {
1616
1616
  printError(`${session.error.message} For non-interactive use, run \`skydive auth login --web\` first, or set SKYDIVE_SESSION_TOKEN.`);
1617
1617
  process.exit(1);
1618
1618
  }
1619
- const { connectMachineShare } = await import("./print-share-ZtOgZIWk.mjs");
1619
+ const { connectMachineShare } = await import("./print-share-Cp-UubZb.mjs");
1620
1620
  const machineShare = await connectMachineShare({
1621
1621
  appUrl,
1622
1622
  sessionToken: session.value.sessionToken,
@@ -1624,7 +1624,7 @@ async function runImportPrintMode({ argv, appUrl }) {
1624
1624
  });
1625
1625
  const extra = (argv.print ?? "").trim();
1626
1626
  const prompt = buildImportSeedPrompt(process.cwd(), machineOsFromPlatform(process.platform)) + (extra ? `\n\nAdditional instructions: ${extra}` : "");
1627
- const { runPrint } = await import("./print-D79MKwnp.mjs");
1627
+ const { runPrint } = await import("./print-Dfj7y9pt.mjs");
1628
1628
  try {
1629
1629
  const result = await runPrint({
1630
1630
  appUrl,
@@ -2031,7 +2031,7 @@ const chatCommand = {
2031
2031
  sessionToken: auth.value.token,
2032
2032
  agentSelector: argv.agent ?? null
2033
2033
  });
2034
- const { runChat } = await import("./boot-BtEzGVMb.mjs");
2034
+ const { runChat } = await import("./boot-CZ_17jJG.mjs");
2035
2035
  await runChat({
2036
2036
  appUrl: auth.value.appUrl,
2037
2037
  sessionToken: auth.value.token,
@@ -2115,7 +2115,7 @@ async function runPrintMode({ argv, appUrl }) {
2115
2115
  printError(`${auth.error.message} For non-interactive use, run \`skydive auth login\` first, or set SKYDIVE_API_KEY / SKYDIVE_SESSION_TOKEN.`);
2116
2116
  process.exit(1);
2117
2117
  }
2118
- const { runPrint, readStdin } = await import("./print-D79MKwnp.mjs");
2118
+ const { runPrint, readStdin } = await import("./print-Dfj7y9pt.mjs");
2119
2119
  const workspaceId = await resolveWorkspaceFlag({
2120
2120
  appUrl,
2121
2121
  sessionToken: auth.value.token,
@@ -2145,7 +2145,7 @@ async function runPrintMode({ argv, appUrl }) {
2145
2145
  process.exit(1);
2146
2146
  }
2147
2147
  } else {
2148
- const { connectMachineShare } = await import("./print-share-ZtOgZIWk.mjs");
2148
+ const { connectMachineShare } = await import("./print-share-Cp-UubZb.mjs");
2149
2149
  machineShare = await connectMachineShare({
2150
2150
  appUrl: auth.value.appUrl,
2151
2151
  sessionToken: auth.value.token,
@@ -2210,7 +2210,7 @@ const getCommand$1 = {
2210
2210
  printError(`${auth.error.message} Run \`skydive auth login\` first, or set SKYDIVE_API_KEY / SKYDIVE_SESSION_TOKEN.`);
2211
2211
  process.exit(1);
2212
2212
  }
2213
- const { messageGet } = await import("./print-D79MKwnp.mjs");
2213
+ const { messageGet } = await import("./print-Dfj7y9pt.mjs");
2214
2214
  try {
2215
2215
  const result = await messageGet({
2216
2216
  appUrl: auth.value.appUrl,
@@ -2413,7 +2413,7 @@ const switchCommand = {
2413
2413
  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.");
2414
2414
  process.exit(1);
2415
2415
  }
2416
- const { runWorkspacePicker } = await import("./boot-BtEzGVMb.mjs");
2416
+ const { runWorkspacePicker } = await import("./boot-CZ_17jJG.mjs");
2417
2417
  await runWorkspacePicker(session);
2418
2418
  return;
2419
2419
  }
@@ -2492,7 +2492,7 @@ const openCommand = {
2492
2492
  const agent = argv.agent ? resolveAgent$1((await fetchPortalDevices(session)).agents, argv.agent) : null;
2493
2493
  const cwd = argv.cwd ? path.resolve(argv.cwd) : process.cwd();
2494
2494
  const { machineName } = await resolveMachineIdentity(null);
2495
- const { PortalDaemonClient } = await import("./daemon-client-BvbBPCJF.mjs");
2495
+ const { PortalDaemonClient } = await import("./daemon-client-C7efcR_u.mjs");
2496
2496
  let lastLine = "";
2497
2497
  let signalConnected;
2498
2498
  const connected = new Promise((resolve) => {
@@ -2849,8 +2849,8 @@ const sandboxCommand = {
2849
2849
  }).example("skydive sandbox --agent grace", "Live terminal (Ctrl-] detaches)").example("skydive sandbox --agent grace -- tail -n 50 /tmp/harness.log", "One-shot command (use `--` so its flags reach the sandbox)").example("skydive sandbox --agent grace -- sh -c 'ls /tmp | wc -l'", "Shell features go through an explicit `sh -c`"),
2850
2850
  handler: async (argv) => {
2851
2851
  const session = requireSession(argv);
2852
- const { createRestClient } = await import("./rest-B5EVWw0j.mjs");
2853
- const { resolveAgent } = await import("./print-D79MKwnp.mjs");
2852
+ const { createRestClient } = await import("./rest-dBXbTmRP.mjs");
2853
+ const { resolveAgent } = await import("./print-Dfj7y9pt.mjs");
2854
2854
  const client = createRestClient({
2855
2855
  appUrl: session.appUrl,
2856
2856
  sessionToken: session.sessionToken
@@ -3121,8 +3121,8 @@ const fsEditCommand = {
3121
3121
  handler: async (argv) => {
3122
3122
  const session = requireSession(argv);
3123
3123
  const remotePath = argv.path;
3124
- const { createRestClient } = await import("./rest-B5EVWw0j.mjs");
3125
- const { resolveAgent } = await import("./print-D79MKwnp.mjs");
3124
+ const { createRestClient } = await import("./rest-dBXbTmRP.mjs");
3125
+ const { resolveAgent } = await import("./print-Dfj7y9pt.mjs");
3126
3126
  const client = createRestClient({
3127
3127
  appUrl: session.appUrl,
3128
3128
  sessionToken: session.sessionToken
@@ -4575,7 +4575,7 @@ if (process.argv.includes(UPDATE_WORKER_FLAG)) {
4575
4575
  process.exit(0);
4576
4576
  }
4577
4577
  if (process.argv.includes(PORTAL_DAEMON_FLAG)) {
4578
- const { runPortalDaemon } = await import("./daemon-BNxycRkd.mjs");
4578
+ const { runPortalDaemon } = await import("./daemon-CN5CdzEt.mjs");
4579
4579
  runPortalDaemon(process.argv);
4580
4580
  } else runCli();
4581
4581
  function runCli() {
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
- import { a as errorMessage, i as sendErrorMessage, n as errorDetail, o as isRecord, t as createRestClient } from "./rest-CQ76yHFR.mjs";
3
- import { C as DEFAULT_APP_URL, E as getConfigPath, K as saveTheme, L as recordDefaultAgent, M as getSavedTheme, S as DEFAULT_API_URL, U as resolveWebUrl, _ as parseConnectCard, c as actionableCardVerb, d as parseOauthConnectParams, f as prioritizeActionableCards, g as computeSettledLabel, h as composeQuestionAnswer, i as resolveAgent, j as getReviewStateDir, l as cardActionErrorMessage, m as resolveConnectUrl, p as reconcileMaskedInput, s as MASK_CHAR, u as parseExternalOauthConnectParams, v as specKeyFor } from "./print-CHSPHoin.mjs";
4
- import { A as installAgentAlias, C as themeVersion, D as machineOsFromPlatform, F as detectShell, L as getActiveWorkspaceId, M as takenAliasNames, O as aliasActivationHint, S as themeModeFromColorFgBg, T as themesForMode, V as setActiveWorkspace, _ as monoTheme, a as WORDMARK, b as themeForMode, d as profilingEnabled, f as record, g as findTheme, h as applyTheme, i as MARK_CELLS, j as slugifyAliasName, k as dedupeAliasName, m as DEFAULT_THEME_ID, n as buildCrashReport, p as writeArtifact, r as writeCrashReport, s as splashFitsWidth, t as installCrashHandler, v as noColorRequested, x as themeMode, y as theme, z as listWorkspaces } from "./install-CdbqsofY.mjs";
2
+ import { a as errorMessage, i as sendErrorMessage, n as errorDetail, o as isRecord, t as createRestClient } from "./rest-si3NhA-L.mjs";
3
+ import { C as DEFAULT_APP_URL, E as getConfigPath, K as saveTheme, L as recordDefaultAgent, M as getSavedTheme, S as DEFAULT_API_URL, U as resolveWebUrl, _ as parseConnectCard, c as actionableCardVerb, d as parseOauthConnectParams, f as prioritizeActionableCards, g as computeSettledLabel, h as composeQuestionAnswer, i as resolveAgent, j as getReviewStateDir, l as cardActionErrorMessage, m as resolveConnectUrl, p as reconcileMaskedInput, s as MASK_CHAR, u as parseExternalOauthConnectParams, v as specKeyFor } from "./print-DDI8g0HX.mjs";
4
+ import { A as installAgentAlias, C as themeVersion, D as machineOsFromPlatform, F as detectShell, L as getActiveWorkspaceId, M as takenAliasNames, O as aliasActivationHint, S as themeModeFromColorFgBg, T as themesForMode, V as setActiveWorkspace, _ as monoTheme, a as WORDMARK, b as themeForMode, d as profilingEnabled, f as record, g as findTheme, h as applyTheme, i as MARK_CELLS, j as slugifyAliasName, k as dedupeAliasName, m as DEFAULT_THEME_ID, n as buildCrashReport, p as writeArtifact, r as writeCrashReport, s as splashFitsWidth, t as installCrashHandler, v as noColorRequested, x as themeMode, y as theme, z as listWorkspaces } from "./install-KL5zAlW8.mjs";
5
5
  import { t as HttpError } from "./http-error-BF2NZZE3.mjs";
6
6
  import { i as billingBlockedOutcomeFromSendResponse } from "./billing-blocked-D3l5kJlX.mjs";
7
- import { t as PortalClient } from "./client-DJ0bPjqx.mjs";
7
+ import { t as PortalClient } from "./client-CNF1DFAQ.mjs";
8
8
  import { t as defaultTlsCertSource } from "./tls-cert-Rua2oV7n.mjs";
9
9
  import "./api-BFQ4PQDA.mjs";
10
- import "./daemon-ccNQRdJd.mjs";
10
+ import "./daemon-D4B5LeNQ.mjs";
11
11
  import { t as SandboxStream } from "./client-l6orYfqq.mjs";
12
- import { t as PortalDaemonClient } from "./daemon-client-1Nh5ITt9.mjs";
12
+ import { t as PortalDaemonClient } from "./daemon-client-Eoo24bVH.mjs";
13
13
  import { t as runRawPtyPassthrough } from "./raw-pty-dndn1Kxc.mjs";
14
14
  import * as os$1 from "node:os";
15
15
  import { homedir, platform, release, tmpdir } from "node:os";
@@ -10432,9 +10432,74 @@ function effortLabel(model, level) {
10432
10432
  return model.thinkingLevelLabels?.[level] ?? level;
10433
10433
  }
10434
10434
 
10435
+ //#endregion
10436
+ //#region src/chat/tui/screens/model-floor.ts
10437
+ /** No floor on offer: the picker behaves as it did before the floor existed. */
10438
+ const NO_FREE_FLOOR = {
10439
+ freeModels: null,
10440
+ lock: null
10441
+ };
10442
+ /**
10443
+ * Derives the picker's floor view from the org's billing summary and the
10444
+ * floor's live state, with the same verdicts as the web switcher
10445
+ * (`use-models.ts`), so the two pickers never disagree about what is free
10446
+ * or locked.
10447
+ *
10448
+ * The floor is offered to ENFORCED orgs only (with enforcement off no gate
10449
+ * runs, so nothing is free and nothing is locked), and only while
10450
+ * `available`: in the capped state the gate refuses floor runs too, so the
10451
+ * picker falls back to its plain treatment instead of tagging models free
10452
+ * that the gate would bill.
10453
+ */
10454
+ function resolveFreeFloor({ summary, floor }) {
10455
+ if (!summary.billingEnforcementEnabled || floor === null || !floor.available) return NO_FREE_FLOOR;
10456
+ const freeModels = new Set(floor.models);
10457
+ return {
10458
+ freeModels,
10459
+ lock: summary.blockReason === "insufficient_balance" ? {
10460
+ models: freeModels,
10461
+ pinnedModelId: floor.models[0] ?? null,
10462
+ onPaidPlan: summary.planKey !== null && summary.planKey !== "free"
10463
+ } : null
10464
+ };
10465
+ }
10466
+ /**
10467
+ * The model the picker marks as current. Under the lock the gate pins any
10468
+ * off-floor selection to the floor, so the marker follows the pin: the saved
10469
+ * model when it is on the floor, else the pinned floor model. Mirrors the
10470
+ * server (`resolveFreeFloor` pins off-floor requests) so the row with the
10471
+ * marker is the model the next run really uses.
10472
+ */
10473
+ function effectiveCurrentModel({ currentModel, lock }) {
10474
+ if (lock === null) return currentModel;
10475
+ return currentModel !== null && lock.models.has(currentModel) ? currentModel : lock.pinnedModelId;
10476
+ }
10477
+
10435
10478
  //#endregion
10436
10479
  //#region src/chat/tui/screens/model-picker.tsx
10437
10480
  /**
10481
+ * The free floor's view for the picker (ANY-8042 / ANY-8661), or none. Both
10482
+ * reads are best-effort and fail OPEN together: a billing read that errors
10483
+ * (an api that predates the routes, a session with no active org, a
10484
+ * transient failure) leaves the picker exactly as it was before the floor
10485
+ * existed. A fetch error must never lock a paying org's picker; the run gate
10486
+ * stays authoritative either way. The two reads run alongside each other and
10487
+ * the floor is discarded for a non-enforced org inside `resolveFreeFloor`,
10488
+ * which costs one small query on such orgs but keeps the picker's open to a
10489
+ * single round-trip.
10490
+ */
10491
+ async function loadFreeFloor(rest) {
10492
+ try {
10493
+ const [summary, floor] = await Promise.all([rest.getBillingSummary(), rest.getFreeFloorState()]);
10494
+ return resolveFreeFloor({
10495
+ summary,
10496
+ floor
10497
+ });
10498
+ } catch (_error) {
10499
+ return NO_FREE_FLOOR;
10500
+ }
10501
+ }
10502
+ /**
10438
10503
  * A 404 from the pin route means the server predates it, not that the pick
10439
10504
  * failed: a canary CLI publishes minutes after its release push while the
10440
10505
  * API deploy on that same push takes far longer (ANY-8191, ANY-8202), so a
@@ -10481,12 +10546,17 @@ function ModelPicker({ agentId, conversationId, currentModel, currentEffort, mod
10481
10546
  let cancelled = false;
10482
10547
  (async () => {
10483
10548
  try {
10484
- const [models, savedEfforts] = await Promise.all([rest.listModels(), rest.listModelEfforts().catch(() => ({}))]);
10549
+ const [models, savedEfforts, floor] = await Promise.all([
10550
+ rest.listModels(),
10551
+ rest.listModelEfforts().catch(() => ({})),
10552
+ loadFreeFloor(rest)
10553
+ ]);
10485
10554
  if (cancelled) return;
10486
10555
  setState({
10487
10556
  kind: "ready",
10488
10557
  models,
10489
- savedEfforts
10558
+ savedEfforts,
10559
+ floor
10490
10560
  });
10491
10561
  } catch (err) {
10492
10562
  if (cancelled) return;
@@ -10517,6 +10587,7 @@ function ModelPicker({ agentId, conversationId, currentModel, currentEffort, mod
10517
10587
  return /* @__PURE__ */ jsx(ModelSwitcher, {
10518
10588
  models: state.models,
10519
10589
  initialSavedEfforts: state.savedEfforts,
10590
+ floor: state.floor,
10520
10591
  currentModel,
10521
10592
  currentEffort,
10522
10593
  modelLocked,
@@ -10554,7 +10625,7 @@ function ModelPickerFrame({ hint, children }) {
10554
10625
  ]
10555
10626
  });
10556
10627
  }
10557
- function ModelSwitcher({ models, initialSavedEfforts, currentModel, currentEffort, modelLocked, initialView, agentId, conversationId, onModelSelected, onEffortSelected, onCancel }) {
10628
+ function ModelSwitcher({ models, initialSavedEfforts, floor, currentModel, currentEffort, modelLocked, initialView, agentId, conversationId, onModelSelected, onEffortSelected, onCancel }) {
10558
10629
  const rest = useStore((s) => s.rest);
10559
10630
  const [savedEfforts, setSavedEfforts] = useState(initialSavedEfforts);
10560
10631
  const [view, setView] = useState(() => {
@@ -10669,6 +10740,7 @@ function ModelSwitcher({ models, initialSavedEfforts, currentModel, currentEffor
10669
10740
  });
10670
10741
  return /* @__PURE__ */ jsx(ModelList, {
10671
10742
  models,
10743
+ floor,
10672
10744
  currentModel,
10673
10745
  modelLocked,
10674
10746
  saving,
@@ -10685,10 +10757,26 @@ function ModelSwitcher({ models, initialSavedEfforts, currentModel, currentEffor
10685
10757
  onCancel
10686
10758
  });
10687
10759
  }
10688
- function ModelList({ models, currentModel, modelLocked, saving, saveError, effortFor, onSelect, onEditEffort, onCancel }) {
10760
+ function ModelList({ models, floor, currentModel, modelLocked, saving, saveError, effortFor, onSelect, onEditEffort, onCancel }) {
10689
10761
  const { width, height } = useTerminalDimensions();
10690
10762
  const [query, setQuery] = useState("");
10691
- const [highlight, setHighlight] = useState(0);
10763
+ const { lock } = floor;
10764
+ const markedModel = effectiveCurrentModel({
10765
+ currentModel,
10766
+ lock
10767
+ });
10768
+ const [highlight, setHighlight] = useState(() => {
10769
+ if (lock === null) return 0;
10770
+ const index = models.findIndex((m) => m.id === markedModel);
10771
+ return index < 0 ? 0 : index;
10772
+ });
10773
+ /**
10774
+ * Locked rows stay visible (so the user sees what credits would unlock),
10775
+ * dimmed, navigable, and answer to no key but movement; the status line
10776
+ * says why while one is highlighted. No per-row marker: on a long catalog
10777
+ * it wraps every row for a fact the notice already states.
10778
+ */
10779
+ const isLocked = (model) => lock !== null && !lock.models.has(model.id);
10692
10780
  const hits = fuzzyFilter(query, models, modelKeys);
10693
10781
  const filtered = hits.map((h) => h.item);
10694
10782
  const clamped = Math.min(highlight, Math.max(0, filtered.length - 1));
@@ -10705,15 +10793,16 @@ function ModelList({ models, currentModel, modelLocked, saving, saveError, effor
10705
10793
  else if (key.name === "down") setHighlight(Math.min(Math.max(0, filtered.length - 1), clamped + 1));
10706
10794
  else if (key.name === "tab") {
10707
10795
  const model = filtered[clamped];
10708
- if (model && effortFor(model)) onEditEffort(model);
10796
+ if (model && !isLocked(model) && effortFor(model)) onEditEffort(model);
10709
10797
  } else if (key.name === "return") {
10710
10798
  const model = filtered[clamped];
10711
- if (model) onSelect(model);
10799
+ if (model && !isLocked(model)) onSelect(model);
10712
10800
  }
10713
10801
  });
10714
10802
  const highlighted = filtered[clamped];
10715
- const canEditEffort = !!highlighted && !!effortFor(highlighted);
10716
- const statusLine = saving ? "saving…" : saveError ? saveError : `${filtered.length}/${models.length} · ↑/↓ move · ↵ select${canEditEffort ? " · tab effort" : ""} · esc cancel`;
10803
+ const highlightedLocked = !!highlighted && isLocked(highlighted);
10804
+ const canEditEffort = !!highlighted && !highlightedLocked && !!effortFor(highlighted);
10805
+ const statusLine = saving ? "saving…" : saveError ? saveError : `${filtered.length}/${models.length} · ↑/↓ move · ${highlightedLocked ? "↵ needs credits" : "↵ select"}${canEditEffort ? " · tab effort" : ""} · esc cancel`;
10717
10806
  return /* @__PURE__ */ jsxs("box", {
10718
10807
  style: {
10719
10808
  flexDirection: "column",
@@ -10728,7 +10817,19 @@ function ModelList({ models, currentModel, modelLocked, saving, saveError, effor
10728
10817
  fg: theme.warning,
10729
10818
  children: "model choice is limited while this agent uses a Google integration. models without a zero-data-retention route will be rejected."
10730
10819
  }) : null,
10731
- /* @__PURE__ */ jsxs("box", {
10820
+ lock !== null ? /* @__PURE__ */ jsxs("box", {
10821
+ style: {
10822
+ flexDirection: "column",
10823
+ marginTop: 1
10824
+ },
10825
+ children: [/* @__PURE__ */ jsx("text", {
10826
+ fg: theme.fg,
10827
+ children: lock.onPaidPlan ? "You're out of credits" : "You're on the Free plan"
10828
+ }), /* @__PURE__ */ jsx("text", {
10829
+ fg: theme.muted,
10830
+ children: "Some models are unavailable."
10831
+ })]
10832
+ }) : /* @__PURE__ */ jsxs("box", {
10732
10833
  style: {
10733
10834
  flexDirection: "row",
10734
10835
  height: 1,
@@ -10766,10 +10867,11 @@ function ModelList({ models, currentModel, modelLocked, saving, saveError, effor
10766
10867
  }) : windowed.map((hit, i) => {
10767
10868
  const m = hit.item;
10768
10869
  const selected = start + i === clamped;
10769
- const isCurrent = m.id === currentModel;
10870
+ const isCurrent = m.id === markedModel;
10871
+ const locked = isLocked(m);
10770
10872
  const effort = effortFor(m);
10771
10873
  return /* @__PURE__ */ jsxs("text", {
10772
- fg: selected ? theme.accent : theme.fg,
10874
+ fg: selected ? theme.accent : locked ? theme.dim : theme.fg,
10773
10875
  children: [
10774
10876
  selected ? "› " : " ",
10775
10877
  isCurrent ? "● " : " ",
@@ -10789,6 +10891,10 @@ function ModelList({ models, currentModel, modelLocked, saving, saveError, effor
10789
10891
  effort ? /* @__PURE__ */ jsx("span", {
10790
10892
  fg: theme.dim,
10791
10893
  children: ` ${effortLabel(m, effort)}`
10894
+ }) : null,
10895
+ floor.freeModels?.has(m.id) ? /* @__PURE__ */ jsx("span", {
10896
+ fg: theme.success,
10897
+ children: " free"
10792
10898
  }) : null
10793
10899
  ]
10794
10900
  }, m.id);
@@ -160,7 +160,7 @@ function errorMessage(err) {
160
160
  * the commit time of the built tree is one monotonic clock they share.
161
161
  */
162
162
  function portalDaemonBuild() {
163
- return "1789516264";
163
+ return "1789577256";
164
164
  }
165
165
  /**
166
166
  * Whether a client carrying `mine` should replace a running daemon carrying
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import { t as PortalClient } from "./client-CNF1DFAQ.mjs";
3
+ import "./api-BFQ4PQDA.mjs";
4
+
5
+ export { PortalClient };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import "./client-DJ0bPjqx.mjs";
2
+ import "./client-CNF1DFAQ.mjs";
3
3
  import "./tls-cert-Rua2oV7n.mjs";
4
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-ccNQRdJd.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-D4B5LeNQ.mjs";
6
6
 
7
7
  export { runPortalDaemon };
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { i as isRecord, n as isNewerBuild, r as portalDaemonBuild, t as PortalClient } from "./client-DJ0bPjqx.mjs";
2
+ import { i as isRecord, n as isNewerBuild, r as portalDaemonBuild, t as PortalClient } from "./client-CNF1DFAQ.mjs";
3
3
  import { t as defaultTlsCertSource } from "./tls-cert-Rua2oV7n.mjs";
4
4
  import os from "node:os";
5
5
  import path from "node:path";
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import "./client-CNF1DFAQ.mjs";
3
+ import "./tls-cert-Rua2oV7n.mjs";
4
+ import "./api-BFQ4PQDA.mjs";
5
+ import "./daemon-D4B5LeNQ.mjs";
6
+ import { t as PortalDaemonClient } from "./daemon-client-Eoo24bVH.mjs";
7
+
8
+ export { PortalDaemonClient };
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { d as daemonPaths, f as encodeLine, l as LOCAL_PROTOCOL_VERSION, m as parseDaemonMessage, n as ensureDaemonRunning, p as makeLineParser } from "./daemon-ccNQRdJd.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-D4B5LeNQ.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
- import { c as version$1 } from "./rest-CQ76yHFR.mjs";
3
- import { E as getConfigPath } from "./print-CHSPHoin.mjs";
2
+ import { c as version$1 } from "./rest-si3NhA-L.mjs";
3
+ import { E as getConfigPath } from "./print-DDI8g0HX.mjs";
4
4
  import os from "node:os";
5
5
  import path from "node:path";
6
6
  import { err, ok } from "neverthrow";
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as errorMessage, i as sendErrorMessage, o as isRecord, t as createRestClient } from "./rest-CQ76yHFR.mjs";
2
+ import { a as errorMessage, i as sendErrorMessage, o as isRecord, t as createRestClient } from "./rest-si3NhA-L.mjs";
3
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";
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import "./rest-CQ76yHFR.mjs";
3
- import { a as runPrint, i as resolveAgent, n as messageGet, o as toPrintError, r as readStdin, t as collectRunText } from "./print-CHSPHoin.mjs";
2
+ import "./rest-si3NhA-L.mjs";
3
+ import { a as runPrint, i as resolveAgent, n as messageGet, o as toPrintError, r as readStdin, t as collectRunText } from "./print-DDI8g0HX.mjs";
4
4
  import "./billing-blocked-D3l5kJlX.mjs";
5
5
 
6
6
  export { messageGet, readStdin, resolveAgent, runPrint };
@@ -14,7 +14,7 @@ import { n as printError } from "./output-C9mb3sUB.mjs";
14
14
  * the reply (and to --json).
15
15
  */
16
16
  async function connectMachineShare({ appUrl, sessionToken, timeoutHint }) {
17
- const { PortalClient } = await import("./client-rIw2WPPz.mjs");
17
+ const { PortalClient } = await import("./client-CNmM4aEa.mjs");
18
18
  const { defaultTlsCertSource } = await import("./tls-cert-BpCaD5AT.mjs");
19
19
  let signalConnected;
20
20
  const connected = new Promise((resolve) => {
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { i as sendErrorMessage, n as errorDetail, r as filenameFromContentDisposition, t as createRestClient } from "./rest-CQ76yHFR.mjs";
2
+ import { i as sendErrorMessage, n as errorDetail, r as filenameFromContentDisposition, t as createRestClient } from "./rest-si3NhA-L.mjs";
3
3
  import { t as HttpError } from "./http-error-BF2NZZE3.mjs";
4
4
  import "./billing-blocked-D3l5kJlX.mjs";
5
5
 
@@ -6,7 +6,7 @@ import { createParser } from "eventsource-parser";
6
6
 
7
7
  //#region package.json
8
8
  var name = "skydive-cli";
9
- var version = "0.6.0-beta.23";
9
+ var version = "0.6.0-beta.24";
10
10
 
11
11
  //#endregion
12
12
  //#region src/chat/util.ts
@@ -279,6 +279,14 @@ function createRestClient({ appUrl, sessionToken, workspaceId }) {
279
279
  for (const [modelId, config] of Object.entries(modelConfigOverrides ?? {})) if (config.thinkingLevel) efforts[modelId] = config.thinkingLevel;
280
280
  return efforts;
281
281
  },
282
+ getBillingSummary: async () => {
283
+ const { result } = await get("/api/v1/trpc/v2.billing.getBillingOrgSummary", billingSummaryResponseSchema);
284
+ return result.data;
285
+ },
286
+ getFreeFloorState: async () => {
287
+ const { result } = await get("/api/v1/trpc/v2.billing.freeFloorState", freeFloorStateResponseSchema);
288
+ return result.data;
289
+ },
282
290
  setModelEffort: async ({ modelId, thinkingLevel }) => {
283
291
  await post("/api/v1/models/config", {
284
292
  modelId,
@@ -546,6 +554,16 @@ const platformModelSchema = z.object({
546
554
  }).passthrough();
547
555
  const listModelsResponseSchema = z.object({ models: z.array(platformModelSchema) });
548
556
  const modelEffortPreferencesResponseSchema = z.object({ modelConfigOverrides: z.record(z.string(), z.object({ thinkingLevel: z.string().optional() })).optional() });
557
+ const billingSummaryResponseSchema = z.object({ result: z.object({ data: z.object({
558
+ planKey: z.string().nullable(),
559
+ blockReason: z.string().nullable(),
560
+ billingEnforcementEnabled: z.boolean()
561
+ }) }) });
562
+ const freeFloorStateResponseSchema = z.object({ result: z.object({ data: z.object({
563
+ available: z.boolean(),
564
+ models: z.array(z.string()),
565
+ resetsAt: z.string().nullable()
566
+ }).nullable() }) });
549
567
  const conversationModelResponseSchema = z.object({
550
568
  model: z.string().nullable(),
551
569
  thinkingLevel: z.string().nullable()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skydive-cli",
3
- "version": "0.6.0-beta.23",
3
+ "version": "0.6.0-beta.24",
4
4
  "description": "Skydive CLI — cloud agents from the command line",
5
5
  "homepage": "https://skydive.com",
6
6
  "license": "MIT",
@@ -71,9 +71,9 @@
71
71
  },
72
72
  "//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.",
73
73
  "optionalDependencies": {
74
- "skydive-cli-darwin-arm64": "0.6.0-beta.23",
75
- "skydive-cli-darwin-x64": "0.6.0-beta.23",
76
- "skydive-cli-linux-x64": "0.6.0-beta.23",
77
- "skydive-cli-linux-arm64": "0.6.0-beta.23"
74
+ "skydive-cli-darwin-arm64": "0.6.0-beta.24",
75
+ "skydive-cli-darwin-x64": "0.6.0-beta.24",
76
+ "skydive-cli-linux-x64": "0.6.0-beta.24",
77
+ "skydive-cli-linux-arm64": "0.6.0-beta.24"
78
78
  }
79
79
  }
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
- import { t as PortalClient } from "./client-DJ0bPjqx.mjs";
3
- import "./api-BFQ4PQDA.mjs";
4
-
5
- export { PortalClient };
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./client-DJ0bPjqx.mjs";
3
- import "./tls-cert-Rua2oV7n.mjs";
4
- import "./api-BFQ4PQDA.mjs";
5
- import "./daemon-ccNQRdJd.mjs";
6
- import { t as PortalDaemonClient } from "./daemon-client-1Nh5ITt9.mjs";
7
-
8
- export { PortalDaemonClient };