skydive-cli 0.1.0-beta.311 → 0.1.0-beta.316

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/README.md CHANGED
@@ -209,7 +209,10 @@ This is off by default (default-deny) and you opt in explicitly:
209
209
 
210
210
  - `skydive chat --share-machine` enables it at launch, or
211
211
  - `ctrl+t` toggles it from the chat screen (the status bar shows `local access`
212
- when on, `revoke access` when off).
212
+ when on, `revoke access` when off), or
213
+ - set `"shareMachineDefault": true` in the CLI config file to share on every
214
+ launch (see [Configuration](#configuration); `--no-share-machine` overrides
215
+ once).
213
216
 
214
217
  What to know before enabling it:
215
218
 
@@ -234,6 +237,10 @@ What to know before enabling it:
234
237
  sent, the target agent is granted access (the flag is the consent — there is
235
238
  no prompt to approve), and the connection is torn down when the run ends.
236
239
  For access that outlives a single run, use `skydive portal open` (below).
240
+ When sharing comes from `shareMachineDefault` rather than the explicit
241
+ flag, no new grant is minted — the machine connects and already-granted
242
+ agents can run, but an ungranted agent still needs `skydive portal grant`
243
+ (or an approved request).
237
244
 
238
245
  ### Headless machine access (`skydive portal`)
239
246
 
@@ -262,6 +269,27 @@ Two unattended patterns:
262
269
  `skydive chat -p "<prompt>" --agent <name>` one-shots from another shell \u2014
263
270
  cheaper when firing many prompts, since each one skips the connect/grant.
264
271
 
272
+ ## Configuration
273
+
274
+ Persistent state lives in a per-user JSON file managed by
275
+ [`conf`](https://github.com/sindresorhus/conf):
276
+ `~/Library/Preferences/skydive/config.json` on macOS,
277
+ `~/.config/skydive/config.json` on Linux (profile name follows
278
+ `SKYDIVE_CONFIG_NAME`). Most keys are written by flows — `auth login`, the
279
+ device-login flow, the in-TUI theme picker — but the file is plain JSON and
280
+ read fresh on every invocation, so preference keys can be set by editing it
281
+ directly. There is deliberately no `skydive config` command.
282
+
283
+ Hand-editable keys:
284
+
285
+ | Key | Type | Effect |
286
+ | --------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
287
+ | `shareMachineDefault` | boolean | When `true`, `skydive chat` (TUI and `-p`) shares this machine over the portal on launch, as if `--share-machine` were passed. An explicit `--share-machine`/`--no-share-machine` overrides it per invocation. Default `false`. |
288
+
289
+ The remaining keys (`apiKey`, `apiUrl`, `sessionToken`, `appUrl`, `themeDark`,
290
+ `themeLight`, …) are credentials or flow-managed state — leave them to the
291
+ CLI.
292
+
265
293
  ## Environment variables
266
294
 
267
295
  | Variable | Effect |
package/dist/js/bin.mjs CHANGED
@@ -16,7 +16,7 @@ import zlib from "node:zlib";
16
16
  import os from "node:os";
17
17
 
18
18
  //#region package.json
19
- var version$1 = "0.1.0-beta.311";
19
+ var version$1 = "0.1.0-beta.316";
20
20
 
21
21
  //#endregion
22
22
  //#region src/types.ts
@@ -157,6 +157,17 @@ function getSavedTheme(mode) {
157
157
  function saveTheme(mode, themeId) {
158
158
  store.set(mode === "dark" ? "themeDark" : "themeLight", themeId);
159
159
  }
160
+ /**
161
+ * Whether `skydive chat` should enable portal machine sharing on launch
162
+ * without `--share-machine`. Set by hand-editing `shareMachineDefault` in
163
+ * config.json — deliberately no CLI command (kept off the API surface).
164
+ * Sharing only makes the machine reachable — agents still need a
165
+ * (persistent) grant to run anything, so this default skips the per-session
166
+ * enable step, not the consent step.
167
+ */
168
+ function getShareMachineDefault() {
169
+ return store.get("shareMachineDefault") ?? false;
170
+ }
160
171
 
161
172
  //#endregion
162
173
  //#region src/api-client.ts
@@ -2562,8 +2573,7 @@ const chatCommand = {
2562
2573
  describe: "For -p: continue an existing conversation by id instead of starting a new one."
2563
2574
  }).option("share-machine", {
2564
2575
  type: "boolean",
2565
- default: false,
2566
- describe: "Share this machine with the agent over the portal so it can run commands here (default-deny; in the TUI you approve per agent, with -p the flag grants the target agent for the run)"
2576
+ describe: "Share this machine with the agent over the portal so it can run commands here (default-deny; in the TUI you approve per agent, with -p the flag grants the target agent for the run). Defaults to `shareMachineDefault` in the CLI config file; --no-share-machine disables for this invocation."
2567
2577
  }).option("theme", {
2568
2578
  type: "string",
2569
2579
  describe: `Pin a colorscheme (disables automatic light/dark switching). One of: ${themes.map((t) => t.id).join(", ")}. Defaults to following the terminal background; also settable via SKYDIVE_THEME.`
@@ -2607,11 +2617,11 @@ const chatCommand = {
2607
2617
  printError(`Unknown theme "${themeId}". Valid themes: ${themes.map((t) => t.id).join(", ")}`);
2608
2618
  process.exit(1);
2609
2619
  }
2610
- const { runChat } = await import("./boot-DEX6CwVM.mjs");
2620
+ const { runChat } = await import("./boot-DmPfuIod.mjs");
2611
2621
  await runChat({
2612
2622
  appUrl,
2613
2623
  sessionToken: session.value.sessionToken,
2614
- shareMachine: argv["share-machine"],
2624
+ shareMachine: resolveShareMachine(argv),
2615
2625
  promptHistoryPath: getPromptHistoryPath(),
2616
2626
  theme: themeId,
2617
2627
  notifications: argv.notify,
@@ -2619,6 +2629,14 @@ const chatCommand = {
2619
2629
  });
2620
2630
  }
2621
2631
  };
2632
+ /**
2633
+ * Whether this invocation shares the machine: an explicit
2634
+ * --share-machine/--no-share-machine wins; otherwise fall back to the
2635
+ * persisted `shareMachineDefault` config value.
2636
+ */
2637
+ function resolveShareMachine(argv) {
2638
+ return argv["share-machine"] ?? getShareMachineDefault();
2639
+ }
2622
2640
  async function runPrintMode({ argv, appUrl }) {
2623
2641
  const session = resolveSession({ appUrl });
2624
2642
  if (session.isErr()) {
@@ -2639,7 +2657,7 @@ async function runPrintMode({ argv, appUrl }) {
2639
2657
  }
2640
2658
  }
2641
2659
  let machineShare = null;
2642
- if (argv["share-machine"]) {
2660
+ if (resolveShareMachine(argv)) {
2643
2661
  const { PortalClient } = await import("./client-_OL8-XGH.mjs").then((n) => n.n);
2644
2662
  let signalConnected;
2645
2663
  const connected = new Promise((resolve) => {
@@ -2657,7 +2675,7 @@ async function runPrintMode({ argv, appUrl }) {
2657
2675
  machineShare.enable();
2658
2676
  if (await Promise.race([connected.then(() => false), new Promise((resolve) => setTimeout(() => resolve(true), 3e4).unref())])) {
2659
2677
  machineShare.dispose();
2660
- printError("Could not connect the portal within 30s — machine sharing is unavailable (network, or the portal kill switch is off). Re-run without --share-machine, or check `skydive portal status`.");
2678
+ printError("Could not connect the portal within 30s — machine sharing is unavailable (network, or the portal kill switch is off). Re-run with --no-share-machine (or unset `shareMachineDefault` in the CLI config), or check `skydive portal status`.");
2661
2679
  process.exit(1);
2662
2680
  }
2663
2681
  }
@@ -2669,7 +2687,8 @@ async function runPrintMode({ argv, appUrl }) {
2669
2687
  agentSelector: argv.agent ?? null,
2670
2688
  conversationId: argv.conversation ?? null,
2671
2689
  json: argv.json,
2672
- machineShare
2690
+ machineShare,
2691
+ grantTargetAgent: argv["share-machine"] === true
2673
2692
  });
2674
2693
  if (argv.json) output(argv, result);
2675
2694
  } catch (error) {
@@ -3042,7 +3061,7 @@ var print_exports = /* @__PURE__ */ __exportAll({
3042
3061
  * disambiguate: an `--agent` selector must match exactly one agent, and
3043
3062
  * when it's omitted we only auto-pick if the account has exactly one.
3044
3063
  */
3045
- async function runPrint({ appUrl, sessionToken, prompt, agentSelector, conversationId, json, machineShare }) {
3064
+ async function runPrint({ appUrl, sessionToken, prompt, agentSelector, conversationId, json, machineShare, grantTargetAgent }) {
3046
3065
  const client = createRestClient({
3047
3066
  appUrl,
3048
3067
  sessionToken
@@ -3052,8 +3071,9 @@ async function runPrint({ appUrl, sessionToken, prompt, agentSelector, conversat
3052
3071
  onPage: null
3053
3072
  }), agentSelector);
3054
3073
  if (machineShare) {
3055
- if (!machineShare.isGranted(agent.id)) await machineShare.grantAgent(agent.id);
3056
- console.error(`portal: shared this machine with ${agent.name} for this run (grant persists until revoked)`);
3074
+ if (!machineShare.isGranted(agent.id) && grantTargetAgent) await machineShare.grantAgent(agent.id);
3075
+ if (machineShare.isGranted(agent.id)) console.error(`portal: shared this machine with ${agent.name} for this run (grant persists until revoked)`);
3076
+ else console.error(`portal: this machine is shared (shareMachineDefault), but ${agent.name} has no grant — approve its request, or run \`skydive portal grant --agent ${agent.name}\`.`);
3057
3077
  }
3058
3078
  let send;
3059
3079
  try {
@@ -3390,7 +3410,7 @@ const switchCommand = {
3390
3410
  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.");
3391
3411
  process.exit(1);
3392
3412
  }
3393
- const { runWorkspacePicker } = await import("./boot-DEX6CwVM.mjs");
3413
+ const { runWorkspacePicker } = await import("./boot-DmPfuIod.mjs");
3394
3414
  await runWorkspacePicker(session);
3395
3415
  return;
3396
3416
  }
@@ -3471,7 +3471,7 @@ function formatChatFooterStatus({ runKind, ctrlCArmed, isShared, hasPendingSteer
3471
3471
  switch (runKind) {
3472
3472
  case "idle": return ctrlCArmed ? "press ctrl+c again to quit" : `${connectHint}↵ send · / commands · esc back · ctrl+c quit · ctrl+t ${isShared ? "revoke access" : "local access"} · ? keybinds`;
3473
3473
  case "sending": return "sending…";
3474
- case "streaming": return hasPendingSteer ? `${connectHint}↵ steer · esc cancel steer · ctrl+c cancel run` : `${connectHint}↵ steer · ctrl+c cancel`;
3474
+ case "streaming": return hasPendingSteer ? `${connectHint}↵ steer · esc cancel steer · ctrl+c cancel run` : `${connectHint}↵ steer · esc leave (keeps running) · ctrl+c cancel`;
3475
3475
  }
3476
3476
  }
3477
3477
  /** Keep model switching discoverable beside the current model. */
@@ -3742,6 +3742,10 @@ const keybindGroups = [
3742
3742
  keys: "esc",
3743
3743
  action: "cancel latest steer (while running)"
3744
3744
  },
3745
+ {
3746
+ keys: "esc",
3747
+ action: "leave a running agent (it keeps working; reopen to reattach)"
3748
+ },
3745
3749
  {
3746
3750
  keys: "ctrl+c",
3747
3751
  action: "cancel run (while running)"
@@ -6435,7 +6439,13 @@ function ChatScreen({ agent, conversation }) {
6435
6439
  }
6436
6440
  if (key.name === "escape") {
6437
6441
  if (runRef.current.kind === "streaming") {
6438
- cancelLatestSteer();
6442
+ if (cancelLatestSteer()) return;
6443
+ runRef.current.abort.abort();
6444
+ useStore.getState().showToast({ message: `${agent.name} keeps working — reopen to reattach` });
6445
+ goTo({
6446
+ kind: "conversation-picker",
6447
+ agent
6448
+ });
6439
6449
  return;
6440
6450
  }
6441
6451
  if (runRef.current.kind === "idle") goTo({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skydive-cli",
3
- "version": "0.1.0-beta.311",
3
+ "version": "0.1.0-beta.316",
4
4
  "description": "Skydive CLI — manage AI agents from the command line",
5
5
  "homepage": "https://skydive.com",
6
6
  "license": "MIT",