skydive-cli 0.1.0-beta.314 → 0.1.0-beta.321

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
@@ -249,9 +249,9 @@ environments, and driving agents from other tools:
249
249
 
250
250
  ```sh
251
251
  skydive portal open # connect and stay in the foreground (ctrl+c to close)
252
- skydive portal open --agent grace # \u2026and grant that agent on first connect
252
+ skydive portal open --agent grace # …and grant that agent on first connect
253
253
  skydive portal open --cwd ~/some/repo # working directory for the agent's commands
254
- skydive portal grant --agent grace # allow an agent (machine must have opened once)
254
+ skydive portal grant --agent grace # allow an agent (registers this machine if needed)
255
255
  skydive portal revoke --agent grace # remove an agent's access
256
256
  skydive portal status # machines, connection state, granted agents
257
257
  ```
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.314";
19
+ var version$1 = "0.1.0-beta.321";
20
20
 
21
21
  //#endregion
22
22
  //#region src/types.ts
@@ -2617,7 +2617,7 @@ const chatCommand = {
2617
2617
  printError(`Unknown theme "${themeId}". Valid themes: ${themes.map((t) => t.id).join(", ")}`);
2618
2618
  process.exit(1);
2619
2619
  }
2620
- const { runChat } = await import("./boot-DEX6CwVM.mjs");
2620
+ const { runChat } = await import("./boot-DmPfuIod.mjs");
2621
2621
  await runChat({
2622
2622
  appUrl,
2623
2623
  sessionToken: session.value.sessionToken,
@@ -3410,7 +3410,7 @@ const switchCommand = {
3410
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.");
3411
3411
  process.exit(1);
3412
3412
  }
3413
- const { runWorkspacePicker } = await import("./boot-DEX6CwVM.mjs");
3413
+ const { runWorkspacePicker } = await import("./boot-DmPfuIod.mjs");
3414
3414
  await runWorkspacePicker(session);
3415
3415
  return;
3416
3416
  }
@@ -3547,6 +3547,22 @@ async function fetchPortalDevices(auth) {
3547
3547
  const json = await portalFetch(auth, "/api/v1/portal/devices", { method: "GET" });
3548
3548
  return devicesResponseSchema.parse(json);
3549
3549
  }
3550
+ const registerResponseSchema = z.object({ device: z.object({ id: z.string() }) });
3551
+ /**
3552
+ * Register this machine's device row without connecting. Connecting registers
3553
+ * as a side effect; this covers granting an agent on a machine that has never
3554
+ * shared yet (the grant references the device row).
3555
+ */
3556
+ async function registerPortalDevice(auth, { machineName, friendlyName }) {
3557
+ const json = await portalFetch(auth, "/api/v1/portal/devices", {
3558
+ method: "POST",
3559
+ body: JSON.stringify({
3560
+ machineName,
3561
+ friendlyName
3562
+ })
3563
+ });
3564
+ return registerResponseSchema.parse(json).device;
3565
+ }
3550
3566
  /** Short-lived token the machine presents when dialing the portal WebSocket. */
3551
3567
  async function mintPortalDeviceToken(auth) {
3552
3568
  const json = await portalFetch(auth, "/api/v1/portal/device-token", { method: "POST" });
@@ -3576,19 +3592,17 @@ function findThisDevice(devices, machineName) {
3576
3592
  * Resolve everything a grant/revoke needs in one round trip: the devices
3577
3593
  * response carries both the user's machines and the org's agent roster, so
3578
3594
  * the `--agent` selector (id or name) resolves without a separate paginated
3579
- * agent listing.
3595
+ * agent listing. `device` is null when this machine has no device row yet
3596
+ * (it has never shared or been registered) — grant registers on the fly,
3597
+ * revoke has nothing to remove.
3580
3598
  */
3581
3599
  async function resolveGrantTarget(argv) {
3582
3600
  const session = requireSession(argv);
3583
3601
  const { devices, agents } = await fetchPortalDevices(session);
3584
- const agent = resolveAgent(agents, argv.agent);
3585
- const { machineName } = machineIdentity();
3586
- const device = findThisDevice(devices, machineName);
3587
- if (!device) throw new Error(`this machine (${machineName}) isn't registered with the portal yet — run \`skydive portal open\` once to register it.`);
3588
3602
  return {
3589
3603
  session,
3590
- agent,
3591
- device
3604
+ agent: resolveAgent(agents, argv.agent),
3605
+ device: findThisDevice(devices, machineIdentity().machineName)
3592
3606
  };
3593
3607
  }
3594
3608
  function agentOption(y) {
@@ -3654,18 +3668,23 @@ const grantCommand = {
3654
3668
  builder: agentOption,
3655
3669
  handler: async (argv) => {
3656
3670
  const { session, agent, device } = await resolveGrantTarget(argv);
3671
+ const { machineName, friendlyName } = machineIdentity();
3672
+ const deviceId = device ? device.id : (await registerPortalDevice(session, {
3673
+ machineName,
3674
+ friendlyName
3675
+ })).id;
3657
3676
  await grantPortalAccess(session, {
3658
- deviceId: device.id,
3677
+ deviceId,
3659
3678
  agentId: agent.id
3660
3679
  });
3661
3680
  if (argv.json) {
3662
3681
  output(argv, {
3663
- deviceId: device.id,
3682
+ deviceId,
3664
3683
  agentId: agent.id
3665
3684
  });
3666
3685
  return;
3667
3686
  }
3668
- console.log(`Granted ${agent.name} access to ${device.friendlyName}. The agent can run commands here whenever its portal is open (\`skydive portal open\` or the chat TUI). Revoke with \`skydive portal revoke --agent ${agent.name}\`.`);
3687
+ console.log(`Granted ${agent.name} access to ${device?.friendlyName ?? friendlyName}. The agent can run commands here whenever its portal is open — start with \`skydive portal open\`, or pass \`--share-machine\` on a \`chat -p\` run. Revoke with \`skydive portal revoke --agent ${agent.name}\`.`);
3669
3688
  }
3670
3689
  };
3671
3690
  const revokeCommand = {
@@ -3674,6 +3693,7 @@ const revokeCommand = {
3674
3693
  builder: agentOption,
3675
3694
  handler: async (argv) => {
3676
3695
  const { session, agent, device } = await resolveGrantTarget(argv);
3696
+ if (!device) throw new Error(`this machine (${machineIdentity().machineName}) isn't registered with the portal — there's nothing to revoke.`);
3677
3697
  await revokePortalAccess(session, {
3678
3698
  deviceId: device.id,
3679
3699
  agentId: agent.id
@@ -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.314",
3
+ "version": "0.1.0-beta.321",
4
4
  "description": "Skydive CLI — manage AI agents from the command line",
5
5
  "homepage": "https://skydive.com",
6
6
  "license": "MIT",