skydive-cli 0.1.0-beta.396 → 0.1.0-beta.397
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 +27 -0
- package/dist/js/{api-DRpbKHz6.mjs → api-CDTKq_5Q.mjs} +1 -1
- package/dist/js/bin.mjs +325 -250
- package/dist/js/{boot-BhSVccnq.mjs → boot-DN1ynJwU.mjs} +87 -16
- package/dist/js/{client-DyRs3o5E.mjs → client-B3ZhhF7e.mjs} +2 -2
- package/dist/js/client-D6NAkL9e.mjs +6 -0
- package/dist/js/output-B4cW10Ph.mjs +27 -0
- package/dist/js/{print-DFPzQQk8.mjs → print-BZH0b3KB.mjs} +2 -2
- package/dist/js/{print-BhfjRrxI.mjs → print-Bin4u16d.mjs} +2 -2
- package/dist/js/print-share-D7OSxvE2.mjs +41 -0
- package/dist/js/raw-pty-2_VA1kw_.mjs +5 -0
- package/dist/js/{raw-pty-Dbi2kb9v.mjs → raw-pty-GAvxm2ol.mjs} +1 -1
- package/dist/js/{rest-DQruM5kj.mjs → rest-COkLEZOB.mjs} +1 -1
- package/package.json +1 -1
- package/dist/js/client-C-s6b9Yu.mjs +0 -6
- package/dist/js/raw-pty-pspO57gT.mjs +0 -5
- /package/dist/js/{client-BVOAwU8M.mjs → client-CpEvH2Pq.mjs} +0 -0
- /package/dist/js/{rest-DTlkPko_.mjs → rest-CamHVOce.mjs} +0 -0
- /package/dist/js/{util-z9Pne47f.mjs → util-CeisaZVY.mjs} +0 -0
package/README.md
CHANGED
|
@@ -78,6 +78,8 @@ skydive secrets rm <KEY> --agent-id <id>
|
|
|
78
78
|
skydive chat # interactive chat TUI (Node; fetches Bun on first run)
|
|
79
79
|
skydive chat -p "<prompt>" # one-shot, non-interactive (runs under Node)
|
|
80
80
|
|
|
81
|
+
skydive import # agent imports your Claude Code / Cursor / OpenCode setup
|
|
82
|
+
|
|
81
83
|
skydive portal open # open the portal to this machine, headless
|
|
82
84
|
skydive portal grant --agent <id|name>
|
|
83
85
|
skydive portal revoke --agent <id|name>
|
|
@@ -86,6 +88,31 @@ skydive portal status
|
|
|
86
88
|
|
|
87
89
|
Global flags: `--json`, `--quiet`, `--api-url <url>`.
|
|
88
90
|
|
|
91
|
+
## `skydive import`
|
|
92
|
+
|
|
93
|
+
Migrating from Claude Code, Cursor, or OpenCode? `skydive import` opens a
|
|
94
|
+
chat with your agent, shares this machine with it, and asks it to import
|
|
95
|
+
your setup — instruction files, skills, slash commands, memory, MCP
|
|
96
|
+
servers. The agent inventories what you have, shows you a plan (including
|
|
97
|
+
what it will NOT bring: credentials never come along; hooks and
|
|
98
|
+
settings have no equivalent here), and only commits to its repo after you
|
|
99
|
+
say yes. Run it from a project directory so project-level config is found
|
|
100
|
+
too.
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
skydive import # picks your only agent, or opens the picker
|
|
104
|
+
skydive import --agent kit # import into a specific agent
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The heavy lifting is the agent's `import-config` skill, so you can also just
|
|
108
|
+
ask in any machine-shared chat: "import my Claude Code setup".
|
|
109
|
+
|
|
110
|
+
Non-interactive (scripts, or driving it from another coding agent):
|
|
111
|
+
`skydive import -p --agent kit` sends the request as a one-shot and prints
|
|
112
|
+
the agent's plan — the agent still waits for approval, so continue with
|
|
113
|
+
`skydive chat -p "go ahead" --agent <id> --resume <conversation> --share-machine`
|
|
114
|
+
to apply it. Runs under Node, no TTY needed.
|
|
115
|
+
|
|
89
116
|
## Workspaces
|
|
90
117
|
|
|
91
118
|
Every `skydive` command acts inside one **workspace** — the org/team boundary
|
package/dist/js/bin.mjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { A as getStoredApiKeyId, C as DEFAULT_WEB_URL, E as getPromptHistoryPath, F as resolveManagementAuth, I as resolveSession, M as getUpdateCheckDisabled, N as resolveAppUrl, P as resolveConfig, R as saveConfig, T as getConfigPath, _ as setActiveWorkspace, b as API_KEY_PREFIX, d as themes, g as listWorkspaces, h as getSessionIdentity, j as getStoredApiKeyWorkspaceName, k as getShareMachineDefault, m as getActiveWorkspaceId, p as ensureActiveOrganization, v as API_KEYS_URL, w as deleteConfig, x as DEFAULT_API_URL, y as API_KEY_FAMILY_PREFIX, z as saveSession } from "./theme-C_Fqxi-U.mjs";
|
|
3
|
-
import { n as
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { t as
|
|
3
|
+
import { n as printError, r as printTable, t as output } from "./output-B4cW10Ph.mjs";
|
|
4
|
+
import { n as createRestClient } from "./rest-CamHVOce.mjs";
|
|
5
|
+
import { i as resolveAgent } from "./print-Bin4u16d.mjs";
|
|
6
|
+
import { a as registerPortalDevice, c as machineIdentity, n as findThisDevice, o as revokePortalAccess, r as grantPortalAccess, t as fetchPortalDevices } from "./api-CDTKq_5Q.mjs";
|
|
7
|
+
import { t as SandboxStream } from "./client-CpEvH2Pq.mjs";
|
|
7
8
|
import { hideBin } from "yargs/helpers";
|
|
8
9
|
import yargs from "yargs";
|
|
9
10
|
import { hostname } from "node:os";
|
|
@@ -19,7 +20,7 @@ import semver from "semver";
|
|
|
19
20
|
|
|
20
21
|
//#region package.json
|
|
21
22
|
var name = "skydive-cli";
|
|
22
|
-
var version = "0.1.0-beta.
|
|
23
|
+
var version = "0.1.0-beta.397";
|
|
23
24
|
|
|
24
25
|
//#endregion
|
|
25
26
|
//#region src/types.ts
|
|
@@ -484,31 +485,6 @@ async function revokeApiKey({ appUrl, token, id }) {
|
|
|
484
485
|
}
|
|
485
486
|
}
|
|
486
487
|
|
|
487
|
-
//#endregion
|
|
488
|
-
//#region src/output.ts
|
|
489
|
-
function output(argv, data) {
|
|
490
|
-
if (argv.json) {
|
|
491
|
-
console.log(JSON.stringify(data, null, 2));
|
|
492
|
-
return;
|
|
493
|
-
}
|
|
494
|
-
if (typeof data === "string") {
|
|
495
|
-
console.log(data);
|
|
496
|
-
return;
|
|
497
|
-
}
|
|
498
|
-
console.log(JSON.stringify(data, null, 2));
|
|
499
|
-
}
|
|
500
|
-
function printTable(headers, rows) {
|
|
501
|
-
const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? "").length)));
|
|
502
|
-
const pad = (s, w) => s.padEnd(w);
|
|
503
|
-
const line = (cells) => cells.map((c, i) => pad(c, widths[i] ?? 0)).join(" ");
|
|
504
|
-
console.log(line(headers));
|
|
505
|
-
console.log(widths.map((w) => "-".repeat(w)).join(" "));
|
|
506
|
-
for (const row of rows) console.log(line(row));
|
|
507
|
-
}
|
|
508
|
-
function printError(message) {
|
|
509
|
-
console.error(`Error: ${message}`);
|
|
510
|
-
}
|
|
511
|
-
|
|
512
488
|
//#endregion
|
|
513
489
|
//#region src/commands/auth.ts
|
|
514
490
|
const loginCommand = {
|
|
@@ -929,199 +905,6 @@ const agentsCommand = {
|
|
|
929
905
|
handler: () => {}
|
|
930
906
|
};
|
|
931
907
|
|
|
932
|
-
//#endregion
|
|
933
|
-
//#region src/commands/keys.ts
|
|
934
|
-
const listCommand$3 = {
|
|
935
|
-
command: "list",
|
|
936
|
-
describe: "List API keys for an agent",
|
|
937
|
-
handler: async (argv) => {
|
|
938
|
-
const result = await requireManagementClient(argv).listKeys(argv["agent-id"]);
|
|
939
|
-
if (result.isErr()) {
|
|
940
|
-
printError(result.error.message);
|
|
941
|
-
process.exit(1);
|
|
942
|
-
}
|
|
943
|
-
const keys = result.value;
|
|
944
|
-
if (argv.json) {
|
|
945
|
-
output(argv, keys);
|
|
946
|
-
return;
|
|
947
|
-
}
|
|
948
|
-
if (keys.length === 0) {
|
|
949
|
-
console.log("No API keys found.");
|
|
950
|
-
return;
|
|
951
|
-
}
|
|
952
|
-
printTable([
|
|
953
|
-
"Name",
|
|
954
|
-
"Prefix",
|
|
955
|
-
"Last Used",
|
|
956
|
-
"Created"
|
|
957
|
-
], keys.map((k) => [
|
|
958
|
-
k.name,
|
|
959
|
-
k.prefix,
|
|
960
|
-
k.lastUsedAt ? new Date(k.lastUsedAt).toLocaleDateString() : "Never",
|
|
961
|
-
new Date(k.createdAt).toLocaleDateString()
|
|
962
|
-
]));
|
|
963
|
-
}
|
|
964
|
-
};
|
|
965
|
-
const createCommand = {
|
|
966
|
-
command: "create <name>",
|
|
967
|
-
describe: "Create a new API key for an agent",
|
|
968
|
-
builder: (y) => y.positional("name", {
|
|
969
|
-
type: "string",
|
|
970
|
-
demandOption: true,
|
|
971
|
-
describe: "Key name"
|
|
972
|
-
}),
|
|
973
|
-
handler: async (argv) => {
|
|
974
|
-
const result = await requireManagementClient(argv).createKey(argv["agent-id"], argv.name);
|
|
975
|
-
if (result.isErr()) {
|
|
976
|
-
printError(result.error.message);
|
|
977
|
-
process.exit(1);
|
|
978
|
-
}
|
|
979
|
-
const key = result.value;
|
|
980
|
-
if (argv.json) {
|
|
981
|
-
output(argv, key);
|
|
982
|
-
return;
|
|
983
|
-
}
|
|
984
|
-
if (argv.quiet) {
|
|
985
|
-
console.log(key.key);
|
|
986
|
-
return;
|
|
987
|
-
}
|
|
988
|
-
console.log(`API key created.`);
|
|
989
|
-
console.log(` Name: ${key.name}`);
|
|
990
|
-
console.log(` Key: ${key.key}`);
|
|
991
|
-
console.log("");
|
|
992
|
-
console.log(" Save this key — it will not be shown again.");
|
|
993
|
-
}
|
|
994
|
-
};
|
|
995
|
-
const revokeCommand$1 = {
|
|
996
|
-
command: "revoke <id>",
|
|
997
|
-
describe: "Revoke an API key",
|
|
998
|
-
builder: (y) => y.positional("id", {
|
|
999
|
-
type: "string",
|
|
1000
|
-
demandOption: true,
|
|
1001
|
-
describe: "Key ID"
|
|
1002
|
-
}),
|
|
1003
|
-
handler: async (argv) => {
|
|
1004
|
-
const result = await requireManagementClient(argv).revokeKey(argv["agent-id"], argv.id);
|
|
1005
|
-
if (result.isErr()) {
|
|
1006
|
-
printError(result.error.message);
|
|
1007
|
-
process.exit(1);
|
|
1008
|
-
}
|
|
1009
|
-
if (argv.json) output(argv, {
|
|
1010
|
-
revoked: true,
|
|
1011
|
-
id: argv.id
|
|
1012
|
-
});
|
|
1013
|
-
else if (!argv.quiet) console.log(`Key ${argv.id} revoked.`);
|
|
1014
|
-
}
|
|
1015
|
-
};
|
|
1016
|
-
const keysCommand = {
|
|
1017
|
-
command: "keys",
|
|
1018
|
-
describe: "Manage API keys for an agent",
|
|
1019
|
-
builder: (y) => y.option("agent-id", {
|
|
1020
|
-
type: "string",
|
|
1021
|
-
demandOption: true,
|
|
1022
|
-
describe: "Agent ID"
|
|
1023
|
-
}).command(listCommand$3).command(createCommand).command(revokeCommand$1).demandCommand(1, "Specify a subcommand: list, create, revoke"),
|
|
1024
|
-
handler: () => {}
|
|
1025
|
-
};
|
|
1026
|
-
|
|
1027
|
-
//#endregion
|
|
1028
|
-
//#region src/commands/secrets.ts
|
|
1029
|
-
/** Read all of stdin as UTF-8, trimming a single trailing newline. */
|
|
1030
|
-
async function readStdin() {
|
|
1031
|
-
const chunks = [];
|
|
1032
|
-
for await (const chunk of process.stdin) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
1033
|
-
return Buffer.concat(chunks).toString("utf8").replace(/\n$/, "");
|
|
1034
|
-
}
|
|
1035
|
-
const listCommand$2 = {
|
|
1036
|
-
command: "list",
|
|
1037
|
-
describe: "List secret names for an agent (values are never shown)",
|
|
1038
|
-
handler: async (argv) => {
|
|
1039
|
-
const result = await requireManagementClient(argv).listSecrets(argv["agent-id"]);
|
|
1040
|
-
if (result.isErr()) {
|
|
1041
|
-
printError(result.error.message);
|
|
1042
|
-
process.exit(1);
|
|
1043
|
-
}
|
|
1044
|
-
const keys = result.value;
|
|
1045
|
-
if (argv.json) {
|
|
1046
|
-
output(argv, keys);
|
|
1047
|
-
return;
|
|
1048
|
-
}
|
|
1049
|
-
if (keys.length === 0) {
|
|
1050
|
-
console.log("No secrets found.");
|
|
1051
|
-
return;
|
|
1052
|
-
}
|
|
1053
|
-
printTable(["Name"], keys.map((k) => [k]));
|
|
1054
|
-
}
|
|
1055
|
-
};
|
|
1056
|
-
const setCommand = {
|
|
1057
|
-
command: "set <key> [value]",
|
|
1058
|
-
describe: "Set (create or overwrite) a secret. Reads value from stdin if omitted.",
|
|
1059
|
-
builder: (y) => y.positional("key", {
|
|
1060
|
-
type: "string",
|
|
1061
|
-
demandOption: true,
|
|
1062
|
-
describe: "Secret name (uppercase letters, digits, underscores)"
|
|
1063
|
-
}).positional("value", {
|
|
1064
|
-
type: "string",
|
|
1065
|
-
describe: "Secret value. If omitted, read from stdin — keeps the value out of shell history."
|
|
1066
|
-
}),
|
|
1067
|
-
handler: async (argv) => {
|
|
1068
|
-
let value = argv.value;
|
|
1069
|
-
if (value === void 0) {
|
|
1070
|
-
if (process.stdin.isTTY) {
|
|
1071
|
-
printError("No value given. Pass it as an argument or pipe it on stdin, e.g. `echo -n \"$TOKEN\" | skydive secrets set MY_KEY --agent-id <id>`.");
|
|
1072
|
-
process.exit(1);
|
|
1073
|
-
}
|
|
1074
|
-
value = await readStdin();
|
|
1075
|
-
}
|
|
1076
|
-
if (!value) {
|
|
1077
|
-
printError("Empty secret value.");
|
|
1078
|
-
process.exit(1);
|
|
1079
|
-
}
|
|
1080
|
-
const result = await requireManagementClient(argv).setSecret(argv["agent-id"], argv.key, value);
|
|
1081
|
-
if (result.isErr()) {
|
|
1082
|
-
printError(result.error.message);
|
|
1083
|
-
process.exit(1);
|
|
1084
|
-
}
|
|
1085
|
-
if (argv.json) output(argv, {
|
|
1086
|
-
key: result.value,
|
|
1087
|
-
set: true
|
|
1088
|
-
});
|
|
1089
|
-
else if (!argv.quiet) console.log(`Secret ${result.value} set.`);
|
|
1090
|
-
}
|
|
1091
|
-
};
|
|
1092
|
-
const rmCommand = {
|
|
1093
|
-
command: "rm <key>",
|
|
1094
|
-
aliases: ["delete"],
|
|
1095
|
-
describe: "Remove a secret from the agent",
|
|
1096
|
-
builder: (y) => y.positional("key", {
|
|
1097
|
-
type: "string",
|
|
1098
|
-
demandOption: true,
|
|
1099
|
-
describe: "Secret name"
|
|
1100
|
-
}),
|
|
1101
|
-
handler: async (argv) => {
|
|
1102
|
-
const result = await requireManagementClient(argv).deleteSecret(argv["agent-id"], argv.key);
|
|
1103
|
-
if (result.isErr()) {
|
|
1104
|
-
printError(result.error.message);
|
|
1105
|
-
process.exit(1);
|
|
1106
|
-
}
|
|
1107
|
-
if (argv.json) output(argv, {
|
|
1108
|
-
key: argv.key,
|
|
1109
|
-
removed: true
|
|
1110
|
-
});
|
|
1111
|
-
else if (!argv.quiet) console.log(`Secret ${argv.key} removed.`);
|
|
1112
|
-
}
|
|
1113
|
-
};
|
|
1114
|
-
const secretsCommand = {
|
|
1115
|
-
command: "secrets",
|
|
1116
|
-
describe: "Manage an agent’s secrets",
|
|
1117
|
-
builder: (y) => y.option("agent-id", {
|
|
1118
|
-
type: "string",
|
|
1119
|
-
demandOption: true,
|
|
1120
|
-
describe: "Agent ID"
|
|
1121
|
-
}).command(listCommand$2).command(setCommand).command(rmCommand).demandCommand(1, "Specify a subcommand: list, set, rm"),
|
|
1122
|
-
handler: () => {}
|
|
1123
|
-
};
|
|
1124
|
-
|
|
1125
908
|
//#endregion
|
|
1126
909
|
//#region src/chat/bun-runtime.ts
|
|
1127
910
|
/**
|
|
@@ -1361,6 +1144,311 @@ function ensureBunAndReexec(onProgress) {
|
|
|
1361
1144
|
});
|
|
1362
1145
|
}
|
|
1363
1146
|
|
|
1147
|
+
//#endregion
|
|
1148
|
+
//#region src/commands/import.ts
|
|
1149
|
+
/**
|
|
1150
|
+
* The first message of the import conversation, sent as the user. It hands
|
|
1151
|
+
* the real work to the agent's `import-config` skill; this text only needs
|
|
1152
|
+
* to establish intent, anchor the starting directory, and set the two
|
|
1153
|
+
* expectations the user cares about most (plan first, no credentials).
|
|
1154
|
+
*/
|
|
1155
|
+
function buildImportSeedPrompt(projectDir) {
|
|
1156
|
+
return [
|
|
1157
|
+
"I'm migrating from another coding agent — import my setup from this machine.",
|
|
1158
|
+
"",
|
|
1159
|
+
`Use your import-config skill. I ran this from \`${projectDir}\`, so start there (and my home directory) when you inventory what I have. Show me the plan first — what you'll bring over, where it lands in you, and anything you're leaving out (credentials especially) — and wait for my OK before committing anything.`
|
|
1160
|
+
].join("\n");
|
|
1161
|
+
}
|
|
1162
|
+
const importCommand = {
|
|
1163
|
+
command: "import",
|
|
1164
|
+
describe: "Import your Claude Code / Cursor / OpenCode setup into an agent (opens a machine-shared chat)",
|
|
1165
|
+
builder: (y) => y.option("agent", {
|
|
1166
|
+
type: "string",
|
|
1167
|
+
describe: "Target agent, by id, slug, or name. Optional: with one agent on the account it is auto-picked; otherwise the agent picker opens first (interactive) or resolution follows the -p rules."
|
|
1168
|
+
}).option("print", {
|
|
1169
|
+
alias: "p",
|
|
1170
|
+
type: "string",
|
|
1171
|
+
describe: "Non-interactive: send the import request as a one-shot, print the agent's plan, and exit (drivable from scripts or another coding agent). An optional value adds extra instructions to the request. The agent still waits for approval — continue the printed conversation with `skydive chat -p \"go ahead\" --resume <id> --share-machine`. Runs under Node."
|
|
1172
|
+
}).example("skydive import", "Import from the current directory").example("skydive import --agent kit", "Import into a specific agent, skipping the picker").example("skydive import -p --agent kit", "One-shot: print the agent's import plan and exit"),
|
|
1173
|
+
handler: async (argv) => {
|
|
1174
|
+
const appUrl = resolveAppUrl({ appUrl: argv["api-url"] });
|
|
1175
|
+
if (argv.print !== void 0) {
|
|
1176
|
+
await runImportPrintMode({
|
|
1177
|
+
argv,
|
|
1178
|
+
appUrl
|
|
1179
|
+
});
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
if (isNonInteractive()) {
|
|
1183
|
+
printError("import without -p is an interactive chat session and needs a terminal. For scripts (or driving this from another agent), use `skydive import -p --agent <agent>`.");
|
|
1184
|
+
process.exit(1);
|
|
1185
|
+
}
|
|
1186
|
+
if (await ensureBunAndReexec((msg) => process.stderr.write(`${msg}\n`)) === "unavailable") {
|
|
1187
|
+
printError(`import needs the Bun runtime and it couldn't be set up automatically. Install Bun (https://bun.sh) and run \`bun ${process.argv[1] ?? "skydive"} import\`, point SKYDIVE_BUN_PATH at an existing bun binary, or use the non-interactive \`import -p\` (runs under Node).`);
|
|
1188
|
+
process.exit(1);
|
|
1189
|
+
}
|
|
1190
|
+
let session = resolveSession({ appUrl });
|
|
1191
|
+
if (session.isErr()) {
|
|
1192
|
+
const login = await loginWithDevice({ appUrl });
|
|
1193
|
+
if (login.isErr()) {
|
|
1194
|
+
printError(login.error.message);
|
|
1195
|
+
process.exit(1);
|
|
1196
|
+
}
|
|
1197
|
+
session = resolveSession({ appUrl });
|
|
1198
|
+
if (session.isErr()) {
|
|
1199
|
+
printError("Signed in, but no session was stored.");
|
|
1200
|
+
process.exit(1);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
const { runChat } = await import("./boot-DN1ynJwU.mjs");
|
|
1204
|
+
await runChat({
|
|
1205
|
+
appUrl,
|
|
1206
|
+
sessionToken: session.value.sessionToken,
|
|
1207
|
+
shareMachine: true,
|
|
1208
|
+
promptHistoryPath: getPromptHistoryPath(),
|
|
1209
|
+
notifications: true,
|
|
1210
|
+
agentSelector: argv.agent ?? null,
|
|
1211
|
+
conversationId: null,
|
|
1212
|
+
seedPrompt: buildImportSeedPrompt(process.cwd())
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
};
|
|
1216
|
+
/**
|
|
1217
|
+
* `import -p`: the same seeded, machine-shared request as the TUI flow, as a
|
|
1218
|
+
* one-shot print run (no TTY, no Bun). The agent's reply is its import plan —
|
|
1219
|
+
* per the import-config skill it must NOT commit anything until approved, so
|
|
1220
|
+
* the caller reviews the plan and continues the conversation
|
|
1221
|
+
* (`chat -p "go ahead" --resume <id> --share-machine`) to apply it.
|
|
1222
|
+
*/
|
|
1223
|
+
async function runImportPrintMode({ argv, appUrl }) {
|
|
1224
|
+
const session = resolveSession({ appUrl });
|
|
1225
|
+
if (session.isErr()) {
|
|
1226
|
+
printError(`${session.error.message} For non-interactive use, run \`skydive auth login --web\` first, or set SKYDIVE_SESSION_TOKEN.`);
|
|
1227
|
+
process.exit(1);
|
|
1228
|
+
}
|
|
1229
|
+
const { connectMachineShare } = await import("./print-share-D7OSxvE2.mjs");
|
|
1230
|
+
const machineShare = await connectMachineShare({
|
|
1231
|
+
appUrl,
|
|
1232
|
+
sessionToken: session.value.sessionToken,
|
|
1233
|
+
timeoutHint: "Check `skydive portal status`, then re-run."
|
|
1234
|
+
});
|
|
1235
|
+
const extra = (argv.print ?? "").trim();
|
|
1236
|
+
const prompt = buildImportSeedPrompt(process.cwd()) + (extra ? `\n\nAdditional instructions: ${extra}` : "");
|
|
1237
|
+
const { runPrint } = await import("./print-BZH0b3KB.mjs");
|
|
1238
|
+
try {
|
|
1239
|
+
const result = await runPrint({
|
|
1240
|
+
appUrl,
|
|
1241
|
+
sessionToken: session.value.sessionToken,
|
|
1242
|
+
prompt,
|
|
1243
|
+
agentSelector: argv.agent ?? null,
|
|
1244
|
+
conversationId: null,
|
|
1245
|
+
json: argv.json,
|
|
1246
|
+
machineShare,
|
|
1247
|
+
grantTargetAgent: true
|
|
1248
|
+
});
|
|
1249
|
+
if (argv.json) output(argv, result);
|
|
1250
|
+
else console.error(`\nTo approve or adjust this plan: skydive chat -p "<your answer>" --agent ${result.agentId} --resume ${result.conversationId} --share-machine`);
|
|
1251
|
+
} catch (error) {
|
|
1252
|
+
printError(error instanceof Error ? error.message : String(error));
|
|
1253
|
+
process.exit(1);
|
|
1254
|
+
} finally {
|
|
1255
|
+
machineShare.dispose();
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
//#endregion
|
|
1260
|
+
//#region src/commands/keys.ts
|
|
1261
|
+
const listCommand$3 = {
|
|
1262
|
+
command: "list",
|
|
1263
|
+
describe: "List API keys for an agent",
|
|
1264
|
+
handler: async (argv) => {
|
|
1265
|
+
const result = await requireManagementClient(argv).listKeys(argv["agent-id"]);
|
|
1266
|
+
if (result.isErr()) {
|
|
1267
|
+
printError(result.error.message);
|
|
1268
|
+
process.exit(1);
|
|
1269
|
+
}
|
|
1270
|
+
const keys = result.value;
|
|
1271
|
+
if (argv.json) {
|
|
1272
|
+
output(argv, keys);
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
if (keys.length === 0) {
|
|
1276
|
+
console.log("No API keys found.");
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
printTable([
|
|
1280
|
+
"Name",
|
|
1281
|
+
"Prefix",
|
|
1282
|
+
"Last Used",
|
|
1283
|
+
"Created"
|
|
1284
|
+
], keys.map((k) => [
|
|
1285
|
+
k.name,
|
|
1286
|
+
k.prefix,
|
|
1287
|
+
k.lastUsedAt ? new Date(k.lastUsedAt).toLocaleDateString() : "Never",
|
|
1288
|
+
new Date(k.createdAt).toLocaleDateString()
|
|
1289
|
+
]));
|
|
1290
|
+
}
|
|
1291
|
+
};
|
|
1292
|
+
const createCommand = {
|
|
1293
|
+
command: "create <name>",
|
|
1294
|
+
describe: "Create a new API key for an agent",
|
|
1295
|
+
builder: (y) => y.positional("name", {
|
|
1296
|
+
type: "string",
|
|
1297
|
+
demandOption: true,
|
|
1298
|
+
describe: "Key name"
|
|
1299
|
+
}),
|
|
1300
|
+
handler: async (argv) => {
|
|
1301
|
+
const result = await requireManagementClient(argv).createKey(argv["agent-id"], argv.name);
|
|
1302
|
+
if (result.isErr()) {
|
|
1303
|
+
printError(result.error.message);
|
|
1304
|
+
process.exit(1);
|
|
1305
|
+
}
|
|
1306
|
+
const key = result.value;
|
|
1307
|
+
if (argv.json) {
|
|
1308
|
+
output(argv, key);
|
|
1309
|
+
return;
|
|
1310
|
+
}
|
|
1311
|
+
if (argv.quiet) {
|
|
1312
|
+
console.log(key.key);
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1315
|
+
console.log(`API key created.`);
|
|
1316
|
+
console.log(` Name: ${key.name}`);
|
|
1317
|
+
console.log(` Key: ${key.key}`);
|
|
1318
|
+
console.log("");
|
|
1319
|
+
console.log(" Save this key — it will not be shown again.");
|
|
1320
|
+
}
|
|
1321
|
+
};
|
|
1322
|
+
const revokeCommand$1 = {
|
|
1323
|
+
command: "revoke <id>",
|
|
1324
|
+
describe: "Revoke an API key",
|
|
1325
|
+
builder: (y) => y.positional("id", {
|
|
1326
|
+
type: "string",
|
|
1327
|
+
demandOption: true,
|
|
1328
|
+
describe: "Key ID"
|
|
1329
|
+
}),
|
|
1330
|
+
handler: async (argv) => {
|
|
1331
|
+
const result = await requireManagementClient(argv).revokeKey(argv["agent-id"], argv.id);
|
|
1332
|
+
if (result.isErr()) {
|
|
1333
|
+
printError(result.error.message);
|
|
1334
|
+
process.exit(1);
|
|
1335
|
+
}
|
|
1336
|
+
if (argv.json) output(argv, {
|
|
1337
|
+
revoked: true,
|
|
1338
|
+
id: argv.id
|
|
1339
|
+
});
|
|
1340
|
+
else if (!argv.quiet) console.log(`Key ${argv.id} revoked.`);
|
|
1341
|
+
}
|
|
1342
|
+
};
|
|
1343
|
+
const keysCommand = {
|
|
1344
|
+
command: "keys",
|
|
1345
|
+
describe: "Manage API keys for an agent",
|
|
1346
|
+
builder: (y) => y.option("agent-id", {
|
|
1347
|
+
type: "string",
|
|
1348
|
+
demandOption: true,
|
|
1349
|
+
describe: "Agent ID"
|
|
1350
|
+
}).command(listCommand$3).command(createCommand).command(revokeCommand$1).demandCommand(1, "Specify a subcommand: list, create, revoke"),
|
|
1351
|
+
handler: () => {}
|
|
1352
|
+
};
|
|
1353
|
+
|
|
1354
|
+
//#endregion
|
|
1355
|
+
//#region src/commands/secrets.ts
|
|
1356
|
+
/** Read all of stdin as UTF-8, trimming a single trailing newline. */
|
|
1357
|
+
async function readStdin() {
|
|
1358
|
+
const chunks = [];
|
|
1359
|
+
for await (const chunk of process.stdin) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
1360
|
+
return Buffer.concat(chunks).toString("utf8").replace(/\n$/, "");
|
|
1361
|
+
}
|
|
1362
|
+
const listCommand$2 = {
|
|
1363
|
+
command: "list",
|
|
1364
|
+
describe: "List secret names for an agent (values are never shown)",
|
|
1365
|
+
handler: async (argv) => {
|
|
1366
|
+
const result = await requireManagementClient(argv).listSecrets(argv["agent-id"]);
|
|
1367
|
+
if (result.isErr()) {
|
|
1368
|
+
printError(result.error.message);
|
|
1369
|
+
process.exit(1);
|
|
1370
|
+
}
|
|
1371
|
+
const keys = result.value;
|
|
1372
|
+
if (argv.json) {
|
|
1373
|
+
output(argv, keys);
|
|
1374
|
+
return;
|
|
1375
|
+
}
|
|
1376
|
+
if (keys.length === 0) {
|
|
1377
|
+
console.log("No secrets found.");
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
printTable(["Name"], keys.map((k) => [k]));
|
|
1381
|
+
}
|
|
1382
|
+
};
|
|
1383
|
+
const setCommand = {
|
|
1384
|
+
command: "set <key> [value]",
|
|
1385
|
+
describe: "Set (create or overwrite) a secret. Reads value from stdin if omitted.",
|
|
1386
|
+
builder: (y) => y.positional("key", {
|
|
1387
|
+
type: "string",
|
|
1388
|
+
demandOption: true,
|
|
1389
|
+
describe: "Secret name (uppercase letters, digits, underscores)"
|
|
1390
|
+
}).positional("value", {
|
|
1391
|
+
type: "string",
|
|
1392
|
+
describe: "Secret value. If omitted, read from stdin — keeps the value out of shell history."
|
|
1393
|
+
}),
|
|
1394
|
+
handler: async (argv) => {
|
|
1395
|
+
let value = argv.value;
|
|
1396
|
+
if (value === void 0) {
|
|
1397
|
+
if (process.stdin.isTTY) {
|
|
1398
|
+
printError("No value given. Pass it as an argument or pipe it on stdin, e.g. `echo -n \"$TOKEN\" | skydive secrets set MY_KEY --agent-id <id>`.");
|
|
1399
|
+
process.exit(1);
|
|
1400
|
+
}
|
|
1401
|
+
value = await readStdin();
|
|
1402
|
+
}
|
|
1403
|
+
if (!value) {
|
|
1404
|
+
printError("Empty secret value.");
|
|
1405
|
+
process.exit(1);
|
|
1406
|
+
}
|
|
1407
|
+
const result = await requireManagementClient(argv).setSecret(argv["agent-id"], argv.key, value);
|
|
1408
|
+
if (result.isErr()) {
|
|
1409
|
+
printError(result.error.message);
|
|
1410
|
+
process.exit(1);
|
|
1411
|
+
}
|
|
1412
|
+
if (argv.json) output(argv, {
|
|
1413
|
+
key: result.value,
|
|
1414
|
+
set: true
|
|
1415
|
+
});
|
|
1416
|
+
else if (!argv.quiet) console.log(`Secret ${result.value} set.`);
|
|
1417
|
+
}
|
|
1418
|
+
};
|
|
1419
|
+
const rmCommand = {
|
|
1420
|
+
command: "rm <key>",
|
|
1421
|
+
aliases: ["delete"],
|
|
1422
|
+
describe: "Remove a secret from the agent",
|
|
1423
|
+
builder: (y) => y.positional("key", {
|
|
1424
|
+
type: "string",
|
|
1425
|
+
demandOption: true,
|
|
1426
|
+
describe: "Secret name"
|
|
1427
|
+
}),
|
|
1428
|
+
handler: async (argv) => {
|
|
1429
|
+
const result = await requireManagementClient(argv).deleteSecret(argv["agent-id"], argv.key);
|
|
1430
|
+
if (result.isErr()) {
|
|
1431
|
+
printError(result.error.message);
|
|
1432
|
+
process.exit(1);
|
|
1433
|
+
}
|
|
1434
|
+
if (argv.json) output(argv, {
|
|
1435
|
+
key: argv.key,
|
|
1436
|
+
removed: true
|
|
1437
|
+
});
|
|
1438
|
+
else if (!argv.quiet) console.log(`Secret ${argv.key} removed.`);
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1441
|
+
const secretsCommand = {
|
|
1442
|
+
command: "secrets",
|
|
1443
|
+
describe: "Manage an agent’s secrets",
|
|
1444
|
+
builder: (y) => y.option("agent-id", {
|
|
1445
|
+
type: "string",
|
|
1446
|
+
demandOption: true,
|
|
1447
|
+
describe: "Agent ID"
|
|
1448
|
+
}).command(listCommand$2).command(setCommand).command(rmCommand).demandCommand(1, "Specify a subcommand: list, set, rm"),
|
|
1449
|
+
handler: () => {}
|
|
1450
|
+
};
|
|
1451
|
+
|
|
1364
1452
|
//#endregion
|
|
1365
1453
|
//#region src/commands/chat.ts
|
|
1366
1454
|
const chatCommand = {
|
|
@@ -1423,7 +1511,7 @@ const chatCommand = {
|
|
|
1423
1511
|
printError(`Unknown theme "${themeId}". Valid themes: ${themes.map((t) => t.id).join(", ")}`);
|
|
1424
1512
|
process.exit(1);
|
|
1425
1513
|
}
|
|
1426
|
-
const { runChat } = await import("./boot-
|
|
1514
|
+
const { runChat } = await import("./boot-DN1ynJwU.mjs");
|
|
1427
1515
|
await runChat({
|
|
1428
1516
|
appUrl,
|
|
1429
1517
|
sessionToken: session.value.sessionToken,
|
|
@@ -1432,7 +1520,8 @@ const chatCommand = {
|
|
|
1432
1520
|
theme: themeId,
|
|
1433
1521
|
notifications: argv.notify,
|
|
1434
1522
|
agentSelector: argv.agent ?? null,
|
|
1435
|
-
conversationId: argv.conversation ?? null
|
|
1523
|
+
conversationId: argv.conversation ?? null,
|
|
1524
|
+
seedPrompt: null
|
|
1436
1525
|
});
|
|
1437
1526
|
}
|
|
1438
1527
|
};
|
|
@@ -1450,7 +1539,7 @@ async function runPrintMode({ argv, appUrl }) {
|
|
|
1450
1539
|
printError(`${session.error.message} For non-interactive use, run \`skydive auth login\` first, or set SKYDIVE_SESSION_TOKEN.`);
|
|
1451
1540
|
process.exit(1);
|
|
1452
1541
|
}
|
|
1453
|
-
const { runPrint, readStdin } = await import("./print-
|
|
1542
|
+
const { runPrint, readStdin } = await import("./print-BZH0b3KB.mjs");
|
|
1454
1543
|
let prompt = (argv.print ?? "").trim();
|
|
1455
1544
|
if (!prompt) {
|
|
1456
1545
|
if (process.stdin.isTTY) {
|
|
@@ -1465,26 +1554,12 @@ async function runPrintMode({ argv, appUrl }) {
|
|
|
1465
1554
|
}
|
|
1466
1555
|
let machineShare = null;
|
|
1467
1556
|
if (resolveShareMachine(argv)) {
|
|
1468
|
-
const {
|
|
1469
|
-
|
|
1470
|
-
const connected = new Promise((resolve) => {
|
|
1471
|
-
signalConnected = resolve;
|
|
1472
|
-
});
|
|
1473
|
-
machineShare = new PortalClient({
|
|
1557
|
+
const { connectMachineShare } = await import("./print-share-D7OSxvE2.mjs");
|
|
1558
|
+
machineShare = await connectMachineShare({
|
|
1474
1559
|
appUrl,
|
|
1475
1560
|
sessionToken: session.value.sessionToken,
|
|
1476
|
-
|
|
1477
|
-
onState: (state) => {
|
|
1478
|
-
if (state.status === "connected") signalConnected();
|
|
1479
|
-
if (state.status === "error") console.error(`portal: connection error: ${state.error ?? "unknown"} — retrying`);
|
|
1480
|
-
}
|
|
1561
|
+
timeoutHint: "Re-run with --no-share-machine (or unset `shareMachineDefault` in the CLI config), or check `skydive portal status`."
|
|
1481
1562
|
});
|
|
1482
|
-
machineShare.enable();
|
|
1483
|
-
if (await Promise.race([connected.then(() => false), new Promise((resolve) => setTimeout(() => resolve(true), 3e4).unref())])) {
|
|
1484
|
-
machineShare.dispose();
|
|
1485
|
-
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`.");
|
|
1486
|
-
process.exit(1);
|
|
1487
|
-
}
|
|
1488
1563
|
}
|
|
1489
1564
|
try {
|
|
1490
1565
|
const result = await runPrint({
|
|
@@ -1538,7 +1613,7 @@ const getCommand = {
|
|
|
1538
1613
|
printError(`${session.error.message} Run \`skydive auth login\` first, or set SKYDIVE_SESSION_TOKEN.`);
|
|
1539
1614
|
process.exit(1);
|
|
1540
1615
|
}
|
|
1541
|
-
const { messageGet } = await import("./print-
|
|
1616
|
+
const { messageGet } = await import("./print-BZH0b3KB.mjs");
|
|
1542
1617
|
try {
|
|
1543
1618
|
const result = await messageGet({
|
|
1544
1619
|
appUrl,
|
|
@@ -1735,7 +1810,7 @@ const switchCommand = {
|
|
|
1735
1810
|
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.");
|
|
1736
1811
|
process.exit(1);
|
|
1737
1812
|
}
|
|
1738
|
-
const { runWorkspacePicker } = await import("./boot-
|
|
1813
|
+
const { runWorkspacePicker } = await import("./boot-DN1ynJwU.mjs");
|
|
1739
1814
|
await runWorkspacePicker(session);
|
|
1740
1815
|
return;
|
|
1741
1816
|
}
|
|
@@ -1813,7 +1888,7 @@ const openCommand = {
|
|
|
1813
1888
|
const agent = argv.agent ? resolveAgent((await fetchPortalDevices(session)).agents, argv.agent) : null;
|
|
1814
1889
|
const cwd = argv.cwd ? path.resolve(argv.cwd) : process.cwd();
|
|
1815
1890
|
const { machineName } = machineIdentity();
|
|
1816
|
-
const { PortalClient } = await import("./client-
|
|
1891
|
+
const { PortalClient } = await import("./client-D6NAkL9e.mjs");
|
|
1817
1892
|
let lastLine = "";
|
|
1818
1893
|
let signalConnected;
|
|
1819
1894
|
const connected = new Promise((resolve) => {
|
|
@@ -1985,8 +2060,8 @@ const sandboxCommand = {
|
|
|
1985
2060
|
}).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`"),
|
|
1986
2061
|
handler: async (argv) => {
|
|
1987
2062
|
const session = requireSession(argv);
|
|
1988
|
-
const { createRestClient } = await import("./rest-
|
|
1989
|
-
const { resolveAgent } = await import("./print-
|
|
2063
|
+
const { createRestClient } = await import("./rest-COkLEZOB.mjs");
|
|
2064
|
+
const { resolveAgent } = await import("./print-BZH0b3KB.mjs");
|
|
1990
2065
|
const client = createRestClient({
|
|
1991
2066
|
appUrl: session.appUrl,
|
|
1992
2067
|
sessionToken: session.sessionToken
|
|
@@ -2055,7 +2130,7 @@ async function runPty({ session, agentId, agentName }) {
|
|
|
2055
2130
|
return 1;
|
|
2056
2131
|
}
|
|
2057
2132
|
console.error(`Connecting to ${agentName}'s sandbox… (Ctrl-] detaches)`);
|
|
2058
|
-
const { runRawPtyPassthrough } = await import("./raw-pty-
|
|
2133
|
+
const { runRawPtyPassthrough } = await import("./raw-pty-2_VA1kw_.mjs");
|
|
2059
2134
|
const result = await runRawPtyPassthrough({
|
|
2060
2135
|
stdin: process.stdin,
|
|
2061
2136
|
stdout: process.stdout,
|
|
@@ -2084,7 +2159,7 @@ function createCli(argv) {
|
|
|
2084
2159
|
type: "string",
|
|
2085
2160
|
global: true,
|
|
2086
2161
|
describe: "Override API base URL"
|
|
2087
|
-
}).command(authCommand).command(chatCommand).command(messagesCommand).command(conversationsCommand).command(agentsCommand).command(keysCommand).command(secretsCommand).command(workspaceCommand).command(portalCommand).command(sandboxCommand).demandCommand(1, "Specify a command. Run --help for usage.").strict().wrap(null).version(version).alias("v", "version").alias("h", "help").help().fail((msg, err) => {
|
|
2162
|
+
}).command(authCommand).command(chatCommand).command(messagesCommand).command(conversationsCommand).command(agentsCommand).command(importCommand).command(keysCommand).command(secretsCommand).command(workspaceCommand).command(portalCommand).command(sandboxCommand).demandCommand(1, "Specify a command. Run --help for usage.").strict().wrap(null).version(version).alias("v", "version").alias("h", "help").help().fail((msg, err) => {
|
|
2088
2163
|
printError(err ? err instanceof Error ? err.message : String(err) : msg ?? "Unknown error");
|
|
2089
2164
|
process.exit(1);
|
|
2090
2165
|
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { B as saveTheme, D as getReviewStateDir, L as resolveWebUrl, O as getSavedTheme, S as DEFAULT_APP_URL, T as getConfigPath, _ as setActiveWorkspace, a as noColorRequested, c as themeMode, f as themesForMode, g as listWorkspaces, i as monoTheme, l as themeModeFromColorFgBg, m as getActiveWorkspaceId, n as applyTheme, o as theme, r as findTheme, s as themeForMode, t as DEFAULT_THEME_ID, u as themeVersion, x as DEFAULT_API_URL } from "./theme-C_Fqxi-U.mjs";
|
|
3
|
-
import { n as createRestClient, r as errorDetail, t as HttpError } from "./rest-
|
|
4
|
-
import { n as isRecord, t as errorMessage } from "./util-
|
|
5
|
-
import { c as cardActionErrorMessage, d as reconcileMaskedInput, f as resolveConnectUrl, i as resolveAgent, l as parseExternalOauthConnectParams, p as parseConnectCard, s as MASK_CHAR, u as parseOauthConnectParams } from "./print-
|
|
6
|
-
import "./api-
|
|
7
|
-
import { t as SandboxStream } from "./client-
|
|
8
|
-
import { t as PortalClient } from "./client-
|
|
9
|
-
import { t as runRawPtyPassthrough } from "./raw-pty-
|
|
3
|
+
import { n as createRestClient, r as errorDetail, t as HttpError } from "./rest-CamHVOce.mjs";
|
|
4
|
+
import { n as isRecord, t as errorMessage } from "./util-CeisaZVY.mjs";
|
|
5
|
+
import { c as cardActionErrorMessage, d as reconcileMaskedInput, f as resolveConnectUrl, i as resolveAgent, l as parseExternalOauthConnectParams, p as parseConnectCard, s as MASK_CHAR, u as parseOauthConnectParams } from "./print-Bin4u16d.mjs";
|
|
6
|
+
import "./api-CDTKq_5Q.mjs";
|
|
7
|
+
import { t as SandboxStream } from "./client-CpEvH2Pq.mjs";
|
|
8
|
+
import { t as PortalClient } from "./client-B3ZhhF7e.mjs";
|
|
9
|
+
import { t as runRawPtyPassthrough } from "./raw-pty-GAvxm2ol.mjs";
|
|
10
10
|
import * as os$1 from "node:os";
|
|
11
11
|
import { homedir, platform, release, tmpdir } from "node:os";
|
|
12
12
|
import path, { basename, extname, isAbsolute, join, win32 } from "node:path";
|
|
@@ -77,6 +77,8 @@ const useStore = create((set, get) => ({
|
|
|
77
77
|
portal: initialPortalUi,
|
|
78
78
|
portalClient: null,
|
|
79
79
|
toast: null,
|
|
80
|
+
seedPrompt: null,
|
|
81
|
+
autoGrantMachine: false,
|
|
80
82
|
goTo: (screen) => set({
|
|
81
83
|
screen,
|
|
82
84
|
chatTitle: initialChatTitle(screen)
|
|
@@ -161,7 +163,7 @@ const useStore = create((set, get) => ({
|
|
|
161
163
|
* Kept out of the React component so it's unit-testable under Node (the
|
|
162
164
|
* component itself can't render without Bun + OpenTUI).
|
|
163
165
|
*/
|
|
164
|
-
async function resolveInitialScreen({ rest, agentSelector, conversationId }) {
|
|
166
|
+
async function resolveInitialScreen({ rest, agentSelector, conversationId, newConversation }) {
|
|
165
167
|
if (conversationId) {
|
|
166
168
|
const [conversation, agents] = await Promise.all([rest.getConversation({ conversationId }).catch((err) => {
|
|
167
169
|
if (err instanceof HttpError && err.status === 404) throw new Error(`No conversation with id ${conversationId} — it may have been deleted, or belong to another workspace.`);
|
|
@@ -192,13 +194,37 @@ async function resolveInitialScreen({ rest, agentSelector, conversationId }) {
|
|
|
192
194
|
}
|
|
193
195
|
};
|
|
194
196
|
}
|
|
195
|
-
if (!agentSelector) return { kind: "agent-picker" };
|
|
197
|
+
if (!agentSelector && !newConversation) return { kind: "agent-picker" };
|
|
198
|
+
const agents = await rest.listAgents({
|
|
199
|
+
scope: "org",
|
|
200
|
+
onPage: null
|
|
201
|
+
});
|
|
202
|
+
if (!agentSelector && newConversation) {
|
|
203
|
+
const only = agents.length === 1 ? agents[0] : null;
|
|
204
|
+
if (!only) return { kind: "agent-picker" };
|
|
205
|
+
return {
|
|
206
|
+
kind: "chat",
|
|
207
|
+
agent: only,
|
|
208
|
+
conversation: {
|
|
209
|
+
kind: "new",
|
|
210
|
+
agentId: only.id,
|
|
211
|
+
nonce: crypto.randomUUID()
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
const agent = resolveAgent(agents, agentSelector);
|
|
216
|
+
if (newConversation) return {
|
|
217
|
+
kind: "chat",
|
|
218
|
+
agent,
|
|
219
|
+
conversation: {
|
|
220
|
+
kind: "new",
|
|
221
|
+
agentId: agent.id,
|
|
222
|
+
nonce: crypto.randomUUID()
|
|
223
|
+
}
|
|
224
|
+
};
|
|
196
225
|
return {
|
|
197
226
|
kind: "conversation-picker",
|
|
198
|
-
agent
|
|
199
|
-
scope: "org",
|
|
200
|
-
onPage: null
|
|
201
|
-
}), agentSelector)
|
|
227
|
+
agent
|
|
202
228
|
};
|
|
203
229
|
}
|
|
204
230
|
|
|
@@ -1008,7 +1034,16 @@ function FilterableAgentList({ agents, scope, onPick }) {
|
|
|
1008
1034
|
else if (key.name === "down") setHighlight(Math.min(Math.max(0, filtered.length - 1), clamped + 1));
|
|
1009
1035
|
else if (key.name === "return") {
|
|
1010
1036
|
const agent = filtered[clamped];
|
|
1011
|
-
if (agent)
|
|
1037
|
+
if (!agent) return;
|
|
1038
|
+
onPick(useStore.getState().seedPrompt !== null ? {
|
|
1039
|
+
kind: "chat",
|
|
1040
|
+
agent,
|
|
1041
|
+
conversation: {
|
|
1042
|
+
kind: "new",
|
|
1043
|
+
agentId: agent.id,
|
|
1044
|
+
nonce: crypto.randomUUID()
|
|
1045
|
+
}
|
|
1046
|
+
} : {
|
|
1012
1047
|
kind: "conversation-picker",
|
|
1013
1048
|
agent
|
|
1014
1049
|
});
|
|
@@ -8011,6 +8046,37 @@ function ChatScreen({ agent, conversation }) {
|
|
|
8011
8046
|
conversationId,
|
|
8012
8047
|
attachToRun
|
|
8013
8048
|
]);
|
|
8049
|
+
const portalStatus = portal.status;
|
|
8050
|
+
useEffect(() => {
|
|
8051
|
+
const { seedPrompt, autoGrantMachine } = useStore.getState();
|
|
8052
|
+
if (!seedPrompt || !isNewConversation(conversation)) return;
|
|
8053
|
+
if (autoGrantMachine && (portalStatus === "off" || portalStatus === "connecting")) return;
|
|
8054
|
+
useStore.setState({
|
|
8055
|
+
seedPrompt: null,
|
|
8056
|
+
autoGrantMachine: false
|
|
8057
|
+
});
|
|
8058
|
+
(async () => {
|
|
8059
|
+
if (autoGrantMachine && portalClient && portalStatus === "connected" && !portalClient.isGranted(agent.id)) try {
|
|
8060
|
+
await portalClient.grantAgent(agent.id);
|
|
8061
|
+
useStore.getState().showToast({
|
|
8062
|
+
message: `Shared this machine with ${agent.name} for the import. The grant persists — revoke anytime: skydive portal revoke --agent ${agent.name}`,
|
|
8063
|
+
durationMs: 1e4
|
|
8064
|
+
});
|
|
8065
|
+
} catch (err) {
|
|
8066
|
+
useStore.getState().showToast({
|
|
8067
|
+
message: `Couldn't grant machine access automatically (${errorMessage(err)}) — the agent will ask in chat instead.`,
|
|
8068
|
+
variant: "warning"
|
|
8069
|
+
});
|
|
8070
|
+
}
|
|
8071
|
+
await sendContent(seedPrompt, []);
|
|
8072
|
+
})();
|
|
8073
|
+
}, [
|
|
8074
|
+
conversation,
|
|
8075
|
+
portalStatus,
|
|
8076
|
+
portalClient,
|
|
8077
|
+
agent.id,
|
|
8078
|
+
sendContent
|
|
8079
|
+
]);
|
|
8014
8080
|
const cancelLatestSteer = useCallback(() => {
|
|
8015
8081
|
if (!rest) return false;
|
|
8016
8082
|
const pending = itemsRef.current.filter((m) => m.kind === "pending-steer");
|
|
@@ -9364,7 +9430,8 @@ function App({ appUrl, sessionToken, shareMachine, promptHistoryPath, notificati
|
|
|
9364
9430
|
const screen = await resolveInitialScreen({
|
|
9365
9431
|
rest,
|
|
9366
9432
|
agentSelector,
|
|
9367
|
-
conversationId
|
|
9433
|
+
conversationId,
|
|
9434
|
+
newConversation: useStore.getState().seedPrompt !== null
|
|
9368
9435
|
});
|
|
9369
9436
|
if (cancelled) return;
|
|
9370
9437
|
goTo(screen);
|
|
@@ -9689,9 +9756,13 @@ var LinkifiedMarkdownRenderable = class extends MarkdownRenderable {
|
|
|
9689
9756
|
* module — and the heavy OpenTUI dependency graph it pulls in — is
|
|
9690
9757
|
* dynamically imported and never loaded on the Node management path.
|
|
9691
9758
|
*/
|
|
9692
|
-
async function runChat({ appUrl, sessionToken, shareMachine, promptHistoryPath, theme: themeOverride, notifications, agentSelector, conversationId }) {
|
|
9759
|
+
async function runChat({ appUrl, sessionToken, shareMachine, promptHistoryPath, theme: themeOverride, notifications, agentSelector, conversationId, seedPrompt }) {
|
|
9693
9760
|
const renderer = await createCliRenderer({ exitOnCtrlC: false });
|
|
9694
9761
|
extend({ markdown: LinkifiedMarkdownRenderable });
|
|
9762
|
+
useStore.setState({
|
|
9763
|
+
seedPrompt: seedPrompt ?? null,
|
|
9764
|
+
autoGrantMachine: Boolean(seedPrompt && shareMachine)
|
|
9765
|
+
});
|
|
9695
9766
|
const store = useStore.getState();
|
|
9696
9767
|
if (noColorRequested()) {
|
|
9697
9768
|
applyTheme(monoTheme);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as errorMessage } from "./util-
|
|
3
|
-
import { c as machineIdentity, i as mintPortalDeviceToken, l as portalWsUrl, n as findThisDevice, r as grantPortalAccess, s as buildEnv, t as fetchPortalDevices } from "./api-
|
|
2
|
+
import { t as errorMessage } from "./util-CeisaZVY.mjs";
|
|
3
|
+
import { c as machineIdentity, i as mintPortalDeviceToken, l as portalWsUrl, n as findThisDevice, r as grantPortalAccess, s as buildEnv, t as fetchPortalDevices } from "./api-CDTKq_5Q.mjs";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
6
|
import { WebSocket } from "ws";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
//#region src/output.ts
|
|
3
|
+
function output(argv, data) {
|
|
4
|
+
if (argv.json) {
|
|
5
|
+
console.log(JSON.stringify(data, null, 2));
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
if (typeof data === "string") {
|
|
9
|
+
console.log(data);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
console.log(JSON.stringify(data, null, 2));
|
|
13
|
+
}
|
|
14
|
+
function printTable(headers, rows) {
|
|
15
|
+
const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? "").length)));
|
|
16
|
+
const pad = (s, w) => s.padEnd(w);
|
|
17
|
+
const line = (cells) => cells.map((c, i) => pad(c, widths[i] ?? 0)).join(" ");
|
|
18
|
+
console.log(line(headers));
|
|
19
|
+
console.log(widths.map((w) => "-".repeat(w)).join(" "));
|
|
20
|
+
for (const row of rows) console.log(line(row));
|
|
21
|
+
}
|
|
22
|
+
function printError(message) {
|
|
23
|
+
console.error(`Error: ${message}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
export { printError as n, printTable as r, output as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./rest-
|
|
3
|
-
import { a as runPrint, i as resolveAgent, n as messageGet, o as toPrintError, r as readStdin, t as collectRunText } from "./print-
|
|
2
|
+
import "./rest-CamHVOce.mjs";
|
|
3
|
+
import { a as runPrint, i as resolveAgent, n as messageGet, o as toPrintError, r as readStdin, t as collectRunText } from "./print-Bin4u16d.mjs";
|
|
4
4
|
|
|
5
5
|
export { messageGet, readStdin, resolveAgent, runPrint };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as createRestClient, t as HttpError } from "./rest-
|
|
3
|
-
import { n as isRecord, t as errorMessage } from "./util-
|
|
2
|
+
import { n as createRestClient, t as HttpError } from "./rest-CamHVOce.mjs";
|
|
3
|
+
import { n as isRecord, t as errorMessage } from "./util-CeisaZVY.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/chat/tui/chat/card.ts
|
|
6
6
|
const urlActionKinds = [
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { n as printError } from "./output-B4cW10Ph.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/chat/print-share.ts
|
|
5
|
+
/**
|
|
6
|
+
* Machine sharing for a scripted one-shot run (`chat -p --share-machine`,
|
|
7
|
+
* `import -p`): connect the portal from launch and hand back the client so
|
|
8
|
+
* the caller can pass it to `runPrint` (which grants the resolved target
|
|
9
|
+
* agent) and dispose it when the run ends.
|
|
10
|
+
*
|
|
11
|
+
* The client retries forever by design; a scripted one-shot needs a bounded
|
|
12
|
+
* failure instead of a silent hang, so a 30s connect timeout exits the
|
|
13
|
+
* process with guidance. Portal telemetry goes to stderr — stdout belongs to
|
|
14
|
+
* the reply (and to --json).
|
|
15
|
+
*/
|
|
16
|
+
async function connectMachineShare({ appUrl, sessionToken, timeoutHint }) {
|
|
17
|
+
const { PortalClient } = await import("./client-D6NAkL9e.mjs");
|
|
18
|
+
let signalConnected;
|
|
19
|
+
const connected = new Promise((resolve) => {
|
|
20
|
+
signalConnected = resolve;
|
|
21
|
+
});
|
|
22
|
+
const machineShare = new PortalClient({
|
|
23
|
+
appUrl,
|
|
24
|
+
sessionToken,
|
|
25
|
+
cwd: process.cwd(),
|
|
26
|
+
onState: (state) => {
|
|
27
|
+
if (state.status === "connected") signalConnected();
|
|
28
|
+
if (state.status === "error") console.error(`portal: connection error: ${state.error ?? "unknown"} — retrying`);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
machineShare.enable();
|
|
32
|
+
if (await Promise.race([connected.then(() => false), new Promise((resolve) => setTimeout(() => resolve(true), 3e4).unref())])) {
|
|
33
|
+
machineShare.dispose();
|
|
34
|
+
printError(`Could not connect the portal within 30s — machine sharing is unavailable (network, or the portal kill switch is off). ${timeoutHint ?? "Check `skydive portal status`."}`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
return machineShare;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
export { connectMachineShare };
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|