skydive-cli 0.4.1-beta.6 → 0.5.0-beta.10
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 +15 -4
- package/dist/js/api-DG5W6iwx.mjs +131 -0
- package/dist/js/bin.mjs +79 -33
- package/dist/js/{boot-B48inW5D.mjs → boot-BuxaHgFi.mjs} +241 -74
- package/dist/js/client-BuU34IVE.mjs +5 -0
- package/dist/js/{client-mykp1DVb.mjs → client-DabRpc_T.mjs} +187 -118
- package/dist/js/{daemon-CfbpCjAw.mjs → daemon-CYYE2BTu.mjs} +179 -28
- package/dist/js/{daemon-D4ZX3wNG.mjs → daemon-Dk5LeS1S.mjs} +3 -2
- package/dist/js/{daemon-client-6xtta_n2.mjs → daemon-client-3A9afTFC.mjs} +35 -10
- package/dist/js/daemon-client-Dh7G9RxC.mjs +7 -0
- package/dist/js/forward-18QoL5dO.mjs +68 -0
- package/dist/js/{print-ba_0hiV9.mjs → print-Bo06tvfV.mjs} +2 -2
- package/dist/js/{print-CbayCa87.mjs → print-ClPkgR9z.mjs} +105 -29
- package/dist/js/{print-share-ZV88PqDu.mjs → print-share-CKLPmsg0.mjs} +5 -2
- package/dist/js/{profiler-94qrV53c.mjs → profiler-Zs3BHURc.mjs} +2 -2
- package/dist/js/{raw-pty-B6mAroiI.mjs → raw-pty-DY4KelZW.mjs} +1 -1
- package/dist/js/raw-pty-DmdUf4_w.mjs +5 -0
- package/dist/js/{rest-DADJh0bi.mjs → rest-D29qNkto.mjs} +1 -1
- package/dist/js/{rest-BY2nADw5.mjs → rest-I3imNduB.mjs} +6 -11
- package/package.json +2 -2
- package/dist/js/client-NBj0KZSP.mjs +0 -4
- package/dist/js/daemon-client-BHehCLrO.mjs +0 -6
- package/dist/js/raw-pty-3EkG-jjH.mjs +0 -5
- /package/dist/js/{client-Cn2af31H.mjs → client-c4c5MmgN.mjs} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { t as HttpError } from "./http-error-DzyrsLAZ.mjs";
|
|
3
|
-
import { a as isRecord, i as errorMessage, r as sendErrorMessage, t as createRestClient } from "./rest-
|
|
3
|
+
import { a as isRecord, i as errorMessage, r as sendErrorMessage, t as createRestClient } from "./rest-I3imNduB.mjs";
|
|
4
4
|
import { i as billingBlockedOutcomeFromSendResponse, n as BillingBlockedError } from "./billing-blocked-2wju4gC_.mjs";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import Conf from "conf";
|
|
@@ -9,7 +9,7 @@ import stableStringify from "safe-stable-stringify";
|
|
|
9
9
|
|
|
10
10
|
//#region src/config.ts
|
|
11
11
|
/** Default host for the public management API (`/v1`, API-key auth). */
|
|
12
|
-
const DEFAULT_API_URL = "https://api.skydive.com";
|
|
12
|
+
const DEFAULT_API_URL = typeof SKYDIVE_BUILD_API_URL === "string" ? SKYDIVE_BUILD_API_URL : "https://api.skydive.com";
|
|
13
13
|
/**
|
|
14
14
|
* Default origin for the interactive chat client (`skydive chat`).
|
|
15
15
|
*
|
|
@@ -20,9 +20,9 @@ const DEFAULT_API_URL = "https://api.skydive.com";
|
|
|
20
20
|
* `DEFAULT_API_URL`; override with `--api-url` / `SKYDIVE_APP_URL` for local
|
|
21
21
|
* dev or while the DNS record is still being provisioned.
|
|
22
22
|
*/
|
|
23
|
-
const DEFAULT_APP_URL =
|
|
23
|
+
const DEFAULT_APP_URL = DEFAULT_API_URL;
|
|
24
24
|
/** Web front door, for pages opened in the user's browser. */
|
|
25
|
-
const DEFAULT_WEB_URL = "https://skydive.com";
|
|
25
|
+
const DEFAULT_WEB_URL = typeof SKYDIVE_BUILD_WEB_URL === "string" ? SKYDIVE_BUILD_WEB_URL : "https://skydive.com";
|
|
26
26
|
function resolveWebUrl(appUrl) {
|
|
27
27
|
if (appUrl == null) return appUrl;
|
|
28
28
|
return appUrl === DEFAULT_APP_URL ? DEFAULT_WEB_URL : appUrl;
|
|
@@ -213,6 +213,32 @@ function saveUpdateCheck(value) {
|
|
|
213
213
|
}
|
|
214
214
|
store.set("updateCheck", value);
|
|
215
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Agent a bare `skydive chat` (no --agent/--resume) opens a new conversation
|
|
218
|
+
* with. Any selector `--agent` accepts works: an id, or a unique
|
|
219
|
+
* case-insensitive slug/name, resolved against the active workspace's roster
|
|
220
|
+
* at launch. Null when unset (the launch falls back to the agent picker).
|
|
221
|
+
* A hand-edited blank value counts as unset rather than as a selector no
|
|
222
|
+
* agent could ever match.
|
|
223
|
+
*/
|
|
224
|
+
function getDefaultAgent() {
|
|
225
|
+
const value = store.get("defaultAgent")?.trim();
|
|
226
|
+
return value ? value : null;
|
|
227
|
+
}
|
|
228
|
+
function saveDefaultAgent(value) {
|
|
229
|
+
store.set("defaultAgent", value);
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Remember the agent the chat TUI just opened a conversation with, so the
|
|
233
|
+
* next bare `skydive chat` returns to it (last used wins). Records the id —
|
|
234
|
+
* stable across renames, unlike a slug/name selector. Skips the write when
|
|
235
|
+
* the value already matches: this runs on every chat-screen entry, and an
|
|
236
|
+
* unchanged default shouldn't rewrite config.json.
|
|
237
|
+
*/
|
|
238
|
+
function recordDefaultAgent(agentId) {
|
|
239
|
+
if (getDefaultAgent() === agentId) return;
|
|
240
|
+
store.set("defaultAgent", agentId);
|
|
241
|
+
}
|
|
216
242
|
function parseBoolean(raw) {
|
|
217
243
|
const v = raw.trim().toLowerCase();
|
|
218
244
|
if ([
|
|
@@ -229,25 +255,40 @@ function parseBoolean(raw) {
|
|
|
229
255
|
].includes(v)) return ok(false);
|
|
230
256
|
return err(`Expected a boolean (true/false), got "${raw}".`);
|
|
231
257
|
}
|
|
232
|
-
const PREFERENCES = [
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
},
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
258
|
+
const PREFERENCES = [
|
|
259
|
+
{
|
|
260
|
+
key: "shareMachineDefault",
|
|
261
|
+
type: "boolean",
|
|
262
|
+
describe: "Share this machine over the portal on `skydive chat` launch, as if --share-machine were passed. Default false.",
|
|
263
|
+
read: () => getShareMachineDefault(),
|
|
264
|
+
isSet: () => store.has("shareMachineDefault"),
|
|
265
|
+
set: (raw) => parseBoolean(raw).map(saveShareMachineDefault),
|
|
266
|
+
clear: () => store.delete("shareMachineDefault")
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
key: "updateCheck",
|
|
270
|
+
type: "boolean",
|
|
271
|
+
describe: "Run the daily background update check and its \"Update available\" notice. Set false to disable. Default true.",
|
|
272
|
+
read: () => !getUpdateCheckDisabled(),
|
|
273
|
+
isSet: () => store.has("updateCheck"),
|
|
274
|
+
set: (raw) => parseBoolean(raw).map(saveUpdateCheck),
|
|
275
|
+
clear: () => store.delete("updateCheck")
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
key: "defaultAgent",
|
|
279
|
+
type: "string",
|
|
280
|
+
describe: "Agent (id, slug, or name) a bare `skydive chat` opens a new conversation with, skipping the agent picker. Unset by default.",
|
|
281
|
+
read: () => getDefaultAgent(),
|
|
282
|
+
isSet: () => getDefaultAgent() !== null,
|
|
283
|
+
set: (raw) => {
|
|
284
|
+
const value = raw.trim();
|
|
285
|
+
if (!value) return err("Expected an agent id, slug, or name (use `config unset defaultAgent` to clear it).");
|
|
286
|
+
saveDefaultAgent(value);
|
|
287
|
+
return ok(void 0);
|
|
288
|
+
},
|
|
289
|
+
clear: () => store.delete("defaultAgent")
|
|
290
|
+
}
|
|
291
|
+
];
|
|
251
292
|
function getPreference(key) {
|
|
252
293
|
return PREFERENCES.find((p) => p.key === key);
|
|
253
294
|
}
|
|
@@ -282,14 +323,15 @@ function parseButton(element) {
|
|
|
282
323
|
const params = isRecord(press.params) ? press.params : {};
|
|
283
324
|
const primary = props.variant === "primary";
|
|
284
325
|
if (press.action === "approve_portal_access") {
|
|
285
|
-
const agentId = params.agentId;
|
|
286
|
-
if (
|
|
326
|
+
const agentId = optionalString(params.agentId);
|
|
327
|
+
if (!agentId) return null;
|
|
287
328
|
return {
|
|
288
329
|
label,
|
|
289
330
|
action: {
|
|
290
331
|
kind: "grant_portal",
|
|
291
332
|
agentId,
|
|
292
|
-
deviceId:
|
|
333
|
+
deviceId: optionalString(params.deviceId),
|
|
334
|
+
conversationId: optionalString(params.conversationId)
|
|
293
335
|
},
|
|
294
336
|
primary
|
|
295
337
|
};
|
|
@@ -323,12 +365,46 @@ function parseButton(element) {
|
|
|
323
365
|
function specKeyFor(spec) {
|
|
324
366
|
return stableStringify(spec) ?? crypto.randomUUID();
|
|
325
367
|
}
|
|
368
|
+
/**
|
|
369
|
+
* The `platform portal request` consent card. The server emits one
|
|
370
|
+
* DesktopHandoffCard spec for every surface (api routes/portal.ts): the web
|
|
371
|
+
* renders it as the "continue in the Skydive desktop app" handoff, but this
|
|
372
|
+
* terminal's own portal daemon can provide the machine, so here it maps onto
|
|
373
|
+
* the existing grant_portal approval instead of a pointer to the app. Without
|
|
374
|
+
* this the spec is not a Card, parses to null, and the request is silently
|
|
375
|
+
* dropped — `platform portal request` looks desktop-only from the CLI
|
|
376
|
+
* (ANY-6521).
|
|
377
|
+
*/
|
|
378
|
+
function parseDesktopHandoffCard(rootEl) {
|
|
379
|
+
const props = isRecord(rootEl.props) ? rootEl.props : {};
|
|
380
|
+
const agentId = optionalString(props.agentId);
|
|
381
|
+
if (!agentId) return null;
|
|
382
|
+
const agentName = optionalString(props.agentName) ?? "This agent";
|
|
383
|
+
return {
|
|
384
|
+
title: `Let ${agentName} use your computer?`,
|
|
385
|
+
subtitle: null,
|
|
386
|
+
description: `Approving shares this machine with ${agentName} while you're signed in. Revoke anytime: skydive portal revoke --agent "${agentName}"`,
|
|
387
|
+
fields: [],
|
|
388
|
+
button: {
|
|
389
|
+
label: "Approve",
|
|
390
|
+
action: {
|
|
391
|
+
kind: "grant_portal",
|
|
392
|
+
agentId,
|
|
393
|
+
deviceId: optionalString(props.deviceId),
|
|
394
|
+
conversationId: optionalString(props.conversationId)
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
state: {}
|
|
398
|
+
};
|
|
399
|
+
}
|
|
326
400
|
function parseConnectCard(spec) {
|
|
327
401
|
if (!isRecord(spec)) return null;
|
|
328
402
|
const { root, elements } = spec;
|
|
329
403
|
if (typeof root !== "string" || !isRecord(elements)) return null;
|
|
330
404
|
const rootEl = elements[root];
|
|
331
|
-
if (!isRecord(rootEl)
|
|
405
|
+
if (!isRecord(rootEl)) return null;
|
|
406
|
+
if (rootEl.type === "DesktopHandoffCard") return parseDesktopHandoffCard(rootEl);
|
|
407
|
+
if (rootEl.type !== "Card") return null;
|
|
332
408
|
const rootProps = isRecord(rootEl.props) ? rootEl.props : {};
|
|
333
409
|
const title = optionalString(rootProps.title);
|
|
334
410
|
if (!title) return null;
|
|
@@ -572,7 +648,7 @@ async function runPrint({ appUrl, sessionToken, prompt, agentSelector, conversat
|
|
|
572
648
|
onPage: null
|
|
573
649
|
}), agentSelector);
|
|
574
650
|
if (machineShare) {
|
|
575
|
-
if (!machineShare.isGranted(agent.id) && grantTargetAgent) await machineShare.grantAgent(agent.id);
|
|
651
|
+
if (!machineShare.isGranted(agent.id) && grantTargetAgent) await machineShare.grantAgent(agent.id, null);
|
|
576
652
|
if (machineShare.isGranted(agent.id)) console.error(`portal: shared this machine with ${agent.name} for this run (grant persists until revoked)`);
|
|
577
653
|
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}\`.`);
|
|
578
654
|
}
|
|
@@ -760,4 +836,4 @@ async function readStdin() {
|
|
|
760
836
|
}
|
|
761
837
|
|
|
762
838
|
//#endregion
|
|
763
|
-
export {
|
|
839
|
+
export { getStoredApiKeyId as A, saveConfig as B, getDefaultAgent as C, getReviewStateDir as D, getPromptHistoryPath as E, resolveChatAuth as F, saveTheme as H, resolveConfig as I, resolveManagementAuth as L, getUpdateCheckDisabled as M, recordDefaultAgent as N, getSavedTheme as O, resolveAppUrl as P, resolveSession as R, getConfigPath as S, getPreference as T, setLastSeenVersion as U, saveSession as V, API_KEY_PREFIX as _, runPrint as a, PREFERENCES as b, cardActionErrorMessage as c, reconcileMaskedInput as d, resolveConnectUrl as f, API_KEY_FAMILY_PREFIX as g, API_KEYS_URL as h, resolveAgent as i, getStoredApiKeyWorkspaceName as j, getShareMachineDefault as k, parseExternalOauthConnectParams as l, specKeyFor as m, messageGet as n, toPrintError as o, parseConnectCard as p, readStdin as r, MASK_CHAR as s, collectRunText as t, parseOauthConnectParams as u, DEFAULT_API_URL as v, getLastSeenVersion as w, deleteConfig as x, DEFAULT_APP_URL as y, resolveWebUrl as z };
|
|
@@ -14,14 +14,17 @@ import { n as printError } from "./output-DYzzdXYV.mjs";
|
|
|
14
14
|
* the reply (and to --json).
|
|
15
15
|
*/
|
|
16
16
|
async function connectMachineShare({ appUrl, sessionToken, timeoutHint }) {
|
|
17
|
-
const { PortalClient } = await import("./client-
|
|
17
|
+
const { PortalClient } = await import("./client-BuU34IVE.mjs");
|
|
18
18
|
let signalConnected;
|
|
19
19
|
const connected = new Promise((resolve) => {
|
|
20
20
|
signalConnected = resolve;
|
|
21
21
|
});
|
|
22
22
|
const machineShare = new PortalClient({
|
|
23
23
|
appUrl,
|
|
24
|
-
|
|
24
|
+
credentials: () => ({
|
|
25
|
+
sessionToken,
|
|
26
|
+
deviceToken: null
|
|
27
|
+
}),
|
|
25
28
|
resolveCwd: () => process.cwd(),
|
|
26
29
|
onState: (state) => {
|
|
27
30
|
if (state.status === "connected") signalConnected();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { S as getConfigPath } from "./print-
|
|
2
|
+
import { S as getConfigPath } from "./print-ClPkgR9z.mjs";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { err, ok } from "neverthrow";
|
|
@@ -8,7 +8,7 @@ import fs from "node:fs";
|
|
|
8
8
|
|
|
9
9
|
//#region package.json
|
|
10
10
|
var name = "skydive-cli";
|
|
11
|
-
var version$1 = "0.
|
|
11
|
+
var version$1 = "0.5.0-beta.10";
|
|
12
12
|
|
|
13
13
|
//#endregion
|
|
14
14
|
//#region src/auth/organization.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { t as HttpError } from "./http-error-DzyrsLAZ.mjs";
|
|
3
|
-
import { n as errorDetail, r as sendErrorMessage, t as createRestClient } from "./rest-
|
|
3
|
+
import { n as errorDetail, r as sendErrorMessage, t as createRestClient } from "./rest-I3imNduB.mjs";
|
|
4
4
|
import "./billing-blocked-2wju4gC_.mjs";
|
|
5
5
|
|
|
6
6
|
export { createRestClient };
|
|
@@ -193,13 +193,14 @@ function createRestClient({ appUrl, sessionToken, workspaceId }) {
|
|
|
193
193
|
}
|
|
194
194
|
};
|
|
195
195
|
return {
|
|
196
|
-
listAgents: async ({ scope, onPage }) => {
|
|
196
|
+
listAgents: async ({ scope, onPage, limit }) => {
|
|
197
197
|
const all = [];
|
|
198
198
|
let cursor;
|
|
199
|
-
const maxAgents = 2e3;
|
|
199
|
+
const maxAgents = limit ?? 2e3;
|
|
200
|
+
const pageSize = Math.min(100, maxAgents);
|
|
200
201
|
do {
|
|
201
202
|
const params = new URLSearchParams({
|
|
202
|
-
limit:
|
|
203
|
+
limit: String(pageSize),
|
|
203
204
|
scope,
|
|
204
205
|
sort: "mine_first_usage",
|
|
205
206
|
includeStats: "false"
|
|
@@ -218,10 +219,7 @@ function createRestClient({ appUrl, sessionToken, workspaceId }) {
|
|
|
218
219
|
},
|
|
219
220
|
getAgent: async ({ agentId }) => {
|
|
220
221
|
const { agent } = await get(`/api/v1/agents/${encodeURIComponent(agentId)}`, getAgentResponseSchema);
|
|
221
|
-
return
|
|
222
|
-
id: agent.id,
|
|
223
|
-
name: agent.name
|
|
224
|
-
};
|
|
222
|
+
return agent;
|
|
225
223
|
},
|
|
226
224
|
suggestAgentIdentity: async () => {
|
|
227
225
|
const { suggestion } = await get("/api/v1/agents/suggest", suggestAgentResponseSchema);
|
|
@@ -453,10 +451,7 @@ const listAgentsResponseSchema = z.object({
|
|
|
453
451
|
totalCount: z.number().nullable().optional()
|
|
454
452
|
});
|
|
455
453
|
const createAgentResponseSchema = z.object({ agent: agentSummarySchema });
|
|
456
|
-
const getAgentResponseSchema = z.object({ agent:
|
|
457
|
-
id: z.string(),
|
|
458
|
-
name: z.string()
|
|
459
|
-
}).passthrough() });
|
|
454
|
+
const getAgentResponseSchema = z.object({ agent: agentSummarySchema });
|
|
460
455
|
const agentSuggestionSchema = z.object({ name: z.string() });
|
|
461
456
|
const suggestAgentResponseSchema = z.object({ suggestion: agentSuggestionSchema.nullable() });
|
|
462
457
|
const conversationAgentSchema = z.object({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skydive-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0-beta.10",
|
|
4
4
|
"description": "Skydive CLI — cloud agents from the command line",
|
|
5
5
|
"homepage": "https://skydive.com",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"build:binary": "node ./scripts/embed-changelog.mjs && bun scripts/build-binary.ts",
|
|
24
24
|
"test:unit": "vitest run --passWithNoTests && yarn test:tui",
|
|
25
25
|
"test:ci": "vitest run --coverage --coverage.reporter=lcovonly --reporter=default --reporter=github-actions --minWorkers=1 --maxWorkers=2 --passWithNoTests && yarn test:tui",
|
|
26
|
-
"test:tui": "
|
|
26
|
+
"test:tui": "node scripts/run-tui-tests.mjs",
|
|
27
27
|
"render:frames": "bun scripts/render-frames.tsx",
|
|
28
28
|
"render:send-errors": "bun scripts/render-send-errors.tsx",
|
|
29
29
|
"typecheck": "tsgo --noEmit"
|
|
File without changes
|