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 +2 -2
- package/dist/js/bin.mjs +33 -13
- package/dist/js/{boot-DEX6CwVM.mjs → boot-DmPfuIod.mjs} +12 -2
- package/package.json +1 -1
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 #
|
|
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 (
|
|
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.
|
|
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-
|
|
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-
|
|
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
|
|
3677
|
+
deviceId,
|
|
3659
3678
|
agentId: agent.id
|
|
3660
3679
|
});
|
|
3661
3680
|
if (argv.json) {
|
|
3662
3681
|
output(argv, {
|
|
3663
|
-
deviceId
|
|
3682
|
+
deviceId,
|
|
3664
3683
|
agentId: agent.id
|
|
3665
3684
|
});
|
|
3666
3685
|
return;
|
|
3667
3686
|
}
|
|
3668
|
-
console.log(`Granted ${agent.name} access to ${device
|
|
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({
|