skydive-cli 0.2.0-beta.594 → 0.2.0-beta.600
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/dist/js/{api-BHq-5eW_.mjs → api-Bx5VyWaC.mjs} +1 -1
- package/dist/js/bin.mjs +17 -17
- package/dist/js/{boot-C-sSzYb6.mjs → boot-Dj_fZZA_.mjs} +119 -11
- package/dist/js/client-BYYp0E6M.mjs +6 -0
- package/dist/js/{client-t6GmE8TI.mjs → client-BsLCAWf1.mjs} +2 -2
- package/dist/js/{print-XvAHDKqu.mjs → print-DLGCpIM9.mjs} +13 -7
- package/dist/js/{print-Chg635Ye.mjs → print-QPPaRx38.mjs} +2 -2
- package/dist/js/{print-share-DT89ADa6.mjs → print-share-DPsQq2Cy.mjs} +1 -1
- package/dist/js/{raw-pty-GAvxm2ol.mjs → raw-pty-Dbi2kb9v.mjs} +1 -1
- package/dist/js/raw-pty-pspO57gT.mjs +5 -0
- package/dist/js/rest-nx0AmgJy.mjs +4 -0
- package/dist/js/{rest-DZnAT7BG.mjs → rest-vu2-Lrsa.mjs} +100 -10
- package/package.json +2 -1
- package/dist/js/client-CRAGDqp0.mjs +0 -6
- package/dist/js/raw-pty-2_VA1kw_.mjs +0 -5
- package/dist/js/rest-Ci_yRwoi.mjs +0 -4
- package/dist/js/util-CeisaZVY.mjs +0 -15
- /package/dist/js/{client-CpEvH2Pq.mjs → client-BVOAwU8M.mjs} +0 -0
package/dist/js/bin.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { A as getPromptHistoryPath, B as resolveSession, C as API_KEY_PREFIX, D as deleteConfig, E as DEFAULT_WEB_URL, F as getStoredApiKeyWorkspaceName, G as setLastSeenVersion, H as saveConfig, I as getUpdateCheckDisabled, L as resolveAppUrl, N as getShareMachineDefault, O as getConfigPath, P as getStoredApiKeyId, R as resolveConfig, S as API_KEY_FAMILY_PREFIX, U as saveSession, _ as getActiveWorkspaceId, b as setActiveWorkspace, g as ensureActiveOrganization, k as getLastSeenVersion, m as themes, r as brandHelpArt, v as getSessionIdentity, w as DEFAULT_API_URL, x as API_KEYS_URL, y as listWorkspaces, z as resolveManagementAuth } from "./brand-BVALAEf1.mjs";
|
|
3
3
|
import { n as printError, r as printTable, t as output } from "./output-B4cW10Ph.mjs";
|
|
4
|
-
import { n as createRestClient } from "./rest-
|
|
5
|
-
import { i as resolveAgent } from "./print-
|
|
6
|
-
import { a as registerPortalDevice, c as machineIdentity, n as findThisDevice, o as revokePortalAccess, r as grantPortalAccess, t as fetchPortalDevices } from "./api-
|
|
7
|
-
import { t as SandboxStream } from "./client-
|
|
4
|
+
import { n as createRestClient } from "./rest-vu2-Lrsa.mjs";
|
|
5
|
+
import { i as resolveAgent } from "./print-DLGCpIM9.mjs";
|
|
6
|
+
import { a as registerPortalDevice, c as machineIdentity, n as findThisDevice, o as revokePortalAccess, r as grantPortalAccess, t as fetchPortalDevices } from "./api-Bx5VyWaC.mjs";
|
|
7
|
+
import { t as SandboxStream } from "./client-BVOAwU8M.mjs";
|
|
8
8
|
import { hideBin } from "yargs/helpers";
|
|
9
9
|
import yargs from "yargs";
|
|
10
10
|
import { hostname } from "node:os";
|
|
@@ -20,7 +20,7 @@ import semver from "semver";
|
|
|
20
20
|
|
|
21
21
|
//#region package.json
|
|
22
22
|
var name = "skydive-cli";
|
|
23
|
-
var version = "0.2.0-beta.
|
|
23
|
+
var version = "0.2.0-beta.600";
|
|
24
24
|
|
|
25
25
|
//#endregion
|
|
26
26
|
//#region src/types.ts
|
|
@@ -1200,7 +1200,7 @@ const importCommand = {
|
|
|
1200
1200
|
process.exit(1);
|
|
1201
1201
|
}
|
|
1202
1202
|
}
|
|
1203
|
-
const { runChat } = await import("./boot-
|
|
1203
|
+
const { runChat } = await import("./boot-Dj_fZZA_.mjs");
|
|
1204
1204
|
await runChat({
|
|
1205
1205
|
appUrl,
|
|
1206
1206
|
sessionToken: session.value.sessionToken,
|
|
@@ -1226,7 +1226,7 @@ async function runImportPrintMode({ argv, appUrl }) {
|
|
|
1226
1226
|
printError(`${session.error.message} For non-interactive use, run \`skydive auth login --web\` first, or set SKYDIVE_SESSION_TOKEN.`);
|
|
1227
1227
|
process.exit(1);
|
|
1228
1228
|
}
|
|
1229
|
-
const { connectMachineShare } = await import("./print-share-
|
|
1229
|
+
const { connectMachineShare } = await import("./print-share-DPsQq2Cy.mjs");
|
|
1230
1230
|
const machineShare = await connectMachineShare({
|
|
1231
1231
|
appUrl,
|
|
1232
1232
|
sessionToken: session.value.sessionToken,
|
|
@@ -1234,7 +1234,7 @@ async function runImportPrintMode({ argv, appUrl }) {
|
|
|
1234
1234
|
});
|
|
1235
1235
|
const extra = (argv.print ?? "").trim();
|
|
1236
1236
|
const prompt = buildImportSeedPrompt(process.cwd()) + (extra ? `\n\nAdditional instructions: ${extra}` : "");
|
|
1237
|
-
const { runPrint } = await import("./print-
|
|
1237
|
+
const { runPrint } = await import("./print-QPPaRx38.mjs");
|
|
1238
1238
|
try {
|
|
1239
1239
|
const result = await runPrint({
|
|
1240
1240
|
appUrl,
|
|
@@ -1511,7 +1511,7 @@ const chatCommand = {
|
|
|
1511
1511
|
printError(`Unknown theme "${themeId}". Valid themes: ${themes.map((t) => t.id).join(", ")}`);
|
|
1512
1512
|
process.exit(1);
|
|
1513
1513
|
}
|
|
1514
|
-
const { runChat } = await import("./boot-
|
|
1514
|
+
const { runChat } = await import("./boot-Dj_fZZA_.mjs");
|
|
1515
1515
|
await runChat({
|
|
1516
1516
|
appUrl,
|
|
1517
1517
|
sessionToken: session.value.sessionToken,
|
|
@@ -1539,7 +1539,7 @@ async function runPrintMode({ argv, appUrl }) {
|
|
|
1539
1539
|
printError(`${session.error.message} For non-interactive use, run \`skydive auth login\` first, or set SKYDIVE_SESSION_TOKEN.`);
|
|
1540
1540
|
process.exit(1);
|
|
1541
1541
|
}
|
|
1542
|
-
const { runPrint, readStdin } = await import("./print-
|
|
1542
|
+
const { runPrint, readStdin } = await import("./print-QPPaRx38.mjs");
|
|
1543
1543
|
let prompt = (argv.print ?? "").trim();
|
|
1544
1544
|
if (!prompt) {
|
|
1545
1545
|
if (process.stdin.isTTY) {
|
|
@@ -1554,7 +1554,7 @@ async function runPrintMode({ argv, appUrl }) {
|
|
|
1554
1554
|
}
|
|
1555
1555
|
let machineShare = null;
|
|
1556
1556
|
if (resolveShareMachine(argv)) {
|
|
1557
|
-
const { connectMachineShare } = await import("./print-share-
|
|
1557
|
+
const { connectMachineShare } = await import("./print-share-DPsQq2Cy.mjs");
|
|
1558
1558
|
machineShare = await connectMachineShare({
|
|
1559
1559
|
appUrl,
|
|
1560
1560
|
sessionToken: session.value.sessionToken,
|
|
@@ -1613,7 +1613,7 @@ const getCommand = {
|
|
|
1613
1613
|
printError(`${session.error.message} Run \`skydive auth login\` first, or set SKYDIVE_SESSION_TOKEN.`);
|
|
1614
1614
|
process.exit(1);
|
|
1615
1615
|
}
|
|
1616
|
-
const { messageGet } = await import("./print-
|
|
1616
|
+
const { messageGet } = await import("./print-QPPaRx38.mjs");
|
|
1617
1617
|
try {
|
|
1618
1618
|
const result = await messageGet({
|
|
1619
1619
|
appUrl,
|
|
@@ -1810,7 +1810,7 @@ const switchCommand = {
|
|
|
1810
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.");
|
|
1811
1811
|
process.exit(1);
|
|
1812
1812
|
}
|
|
1813
|
-
const { runWorkspacePicker } = await import("./boot-
|
|
1813
|
+
const { runWorkspacePicker } = await import("./boot-Dj_fZZA_.mjs");
|
|
1814
1814
|
await runWorkspacePicker(session);
|
|
1815
1815
|
return;
|
|
1816
1816
|
}
|
|
@@ -1888,7 +1888,7 @@ const openCommand = {
|
|
|
1888
1888
|
const agent = argv.agent ? resolveAgent((await fetchPortalDevices(session)).agents, argv.agent) : null;
|
|
1889
1889
|
const cwd = argv.cwd ? path.resolve(argv.cwd) : process.cwd();
|
|
1890
1890
|
const { machineName } = machineIdentity();
|
|
1891
|
-
const { PortalClient } = await import("./client-
|
|
1891
|
+
const { PortalClient } = await import("./client-BYYp0E6M.mjs");
|
|
1892
1892
|
let lastLine = "";
|
|
1893
1893
|
let signalConnected;
|
|
1894
1894
|
const connected = new Promise((resolve) => {
|
|
@@ -2060,8 +2060,8 @@ const sandboxCommand = {
|
|
|
2060
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`"),
|
|
2061
2061
|
handler: async (argv) => {
|
|
2062
2062
|
const session = requireSession(argv);
|
|
2063
|
-
const { createRestClient } = await import("./rest-
|
|
2064
|
-
const { resolveAgent } = await import("./print-
|
|
2063
|
+
const { createRestClient } = await import("./rest-nx0AmgJy.mjs");
|
|
2064
|
+
const { resolveAgent } = await import("./print-QPPaRx38.mjs");
|
|
2065
2065
|
const client = createRestClient({
|
|
2066
2066
|
appUrl: session.appUrl,
|
|
2067
2067
|
sessionToken: session.sessionToken
|
|
@@ -2130,7 +2130,7 @@ async function runPty({ session, agentId, agentName }) {
|
|
|
2130
2130
|
return 1;
|
|
2131
2131
|
}
|
|
2132
2132
|
console.error(`Connecting to ${agentName}'s sandbox… (Ctrl-] detaches)`);
|
|
2133
|
-
const { runRawPtyPassthrough } = await import("./raw-pty-
|
|
2133
|
+
const { runRawPtyPassthrough } = await import("./raw-pty-pspO57gT.mjs");
|
|
2134
2134
|
const result = await runRawPtyPassthrough({
|
|
2135
2135
|
stdin: process.stdin,
|
|
2136
2136
|
stdout: process.stdout,
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { M as getSavedTheme, O as getConfigPath, T as DEFAULT_APP_URL, V as resolveWebUrl, W as saveTheme, _ as getActiveWorkspaceId, a as applyTheme, b as setActiveWorkspace, c as noColorRequested, d as themeMode, f as themeModeFromColorFgBg, h as themesForMode, i as DEFAULT_THEME_ID, j as getReviewStateDir, l as theme, n as WORDMARK, o as findTheme, p as themeVersion, s as monoTheme, t as MARK_CELLS, u as themeForMode, w as DEFAULT_API_URL, y as listWorkspaces } from "./brand-BVALAEf1.mjs";
|
|
3
|
-
import { n as createRestClient, r as errorDetail, t as HttpError } from "./rest-
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import "./
|
|
7
|
-
import { t as
|
|
8
|
-
import { t as
|
|
9
|
-
import { t as runRawPtyPassthrough } from "./raw-pty-GAvxm2ol.mjs";
|
|
3
|
+
import { a as errorMessage, i as sendErrorMessage, n as createRestClient, o as isRecord, r as errorDetail, t as HttpError } from "./rest-vu2-Lrsa.mjs";
|
|
4
|
+
import { c as cardActionErrorMessage, d as reconcileMaskedInput, f as resolveConnectUrl, i as resolveAgent, l as parseExternalOauthConnectParams, m as specKeyFor, p as parseConnectCard, s as MASK_CHAR, u as parseOauthConnectParams } from "./print-DLGCpIM9.mjs";
|
|
5
|
+
import "./api-Bx5VyWaC.mjs";
|
|
6
|
+
import { t as SandboxStream } from "./client-BVOAwU8M.mjs";
|
|
7
|
+
import { t as PortalClient } from "./client-BsLCAWf1.mjs";
|
|
8
|
+
import { t as runRawPtyPassthrough } from "./raw-pty-Dbi2kb9v.mjs";
|
|
10
9
|
import * as os$1 from "node:os";
|
|
11
10
|
import { homedir, platform, release, tmpdir } from "node:os";
|
|
12
11
|
import path, { basename, extname, isAbsolute, join, win32 } from "node:path";
|
|
@@ -4320,6 +4319,74 @@ function TodoCardView({ todos, isActive }) {
|
|
|
4320
4319
|
});
|
|
4321
4320
|
}
|
|
4322
4321
|
|
|
4322
|
+
//#endregion
|
|
4323
|
+
//#region src/chat/tui/chat/use-compaction.ts
|
|
4324
|
+
const COMPACTING_INDICATOR_TIMEOUT_MS = 12e4;
|
|
4325
|
+
/**
|
|
4326
|
+
* Owns everything about manual conversation compaction (`/compact`): the
|
|
4327
|
+
* persistent "compacting…" indicator state, the fire-and-forget command, the
|
|
4328
|
+
* reaction to conversation-stream `compaction` events, and the safety timeout
|
|
4329
|
+
* that clears a stranded `started` so the indicator can never pin forever.
|
|
4330
|
+
*
|
|
4331
|
+
* The screen keeps a single `streamConversation` subscription (which also
|
|
4332
|
+
* carries `run`/`conversation` events), so compaction events arrive there and
|
|
4333
|
+
* are forwarded in via {@link UseCompaction.onCompactionEvent} rather than this
|
|
4334
|
+
* hook opening its own stream.
|
|
4335
|
+
*/
|
|
4336
|
+
function useCompaction({ rest, conversationId }) {
|
|
4337
|
+
const [compacting, setCompacting] = useState(false);
|
|
4338
|
+
const timerRef = useRef(null);
|
|
4339
|
+
const clearTimer = useCallback(() => {
|
|
4340
|
+
if (timerRef.current) {
|
|
4341
|
+
clearTimeout(timerRef.current);
|
|
4342
|
+
timerRef.current = null;
|
|
4343
|
+
}
|
|
4344
|
+
}, []);
|
|
4345
|
+
const armIndicator = useCallback(() => {
|
|
4346
|
+
clearTimer();
|
|
4347
|
+
setCompacting(true);
|
|
4348
|
+
timerRef.current = setTimeout(() => setCompacting(false), COMPACTING_INDICATOR_TIMEOUT_MS);
|
|
4349
|
+
}, [clearTimer]);
|
|
4350
|
+
const onCompactionEvent = useCallback((status) => {
|
|
4351
|
+
if (status === "started") {
|
|
4352
|
+
armIndicator();
|
|
4353
|
+
return;
|
|
4354
|
+
}
|
|
4355
|
+
clearTimer();
|
|
4356
|
+
setCompacting(false);
|
|
4357
|
+
if (status === "failed") useStore.getState().showToast({
|
|
4358
|
+
variant: "error",
|
|
4359
|
+
message: "compaction failed"
|
|
4360
|
+
});
|
|
4361
|
+
}, [armIndicator, clearTimer]);
|
|
4362
|
+
const compactConversation = useCallback(() => {
|
|
4363
|
+
if (!rest || !conversationId) {
|
|
4364
|
+
useStore.getState().showToast({ message: "nothing to compact yet — send a message first" });
|
|
4365
|
+
return;
|
|
4366
|
+
}
|
|
4367
|
+
armIndicator();
|
|
4368
|
+
rest.compactConversation({ conversationId }).catch((err) => {
|
|
4369
|
+
clearTimer();
|
|
4370
|
+
setCompacting(false);
|
|
4371
|
+
useStore.getState().showToast({
|
|
4372
|
+
variant: "error",
|
|
4373
|
+
message: `couldn't compact: ${errorDetail(err)}`
|
|
4374
|
+
});
|
|
4375
|
+
});
|
|
4376
|
+
}, [
|
|
4377
|
+
rest,
|
|
4378
|
+
conversationId,
|
|
4379
|
+
armIndicator,
|
|
4380
|
+
clearTimer
|
|
4381
|
+
]);
|
|
4382
|
+
useEffect(() => clearTimer, [clearTimer]);
|
|
4383
|
+
return {
|
|
4384
|
+
compacting,
|
|
4385
|
+
compactConversation,
|
|
4386
|
+
onCompactionEvent
|
|
4387
|
+
};
|
|
4388
|
+
}
|
|
4389
|
+
|
|
4323
4390
|
//#endregion
|
|
4324
4391
|
//#region src/chat/tui/chat/footer-hints.ts
|
|
4325
4392
|
/** Build the chat footer copy independently of its colors and layout. */
|
|
@@ -5216,6 +5283,13 @@ const slashCommands = [
|
|
|
5216
5283
|
description: "allow this agent to access your computer",
|
|
5217
5284
|
action: { kind: "portal" }
|
|
5218
5285
|
},
|
|
5286
|
+
{
|
|
5287
|
+
name: "compact",
|
|
5288
|
+
aliases: [],
|
|
5289
|
+
argsHint: null,
|
|
5290
|
+
description: "summarize older turns to free up context now",
|
|
5291
|
+
action: { kind: "compact" }
|
|
5292
|
+
},
|
|
5219
5293
|
{
|
|
5220
5294
|
name: "help",
|
|
5221
5295
|
aliases: [],
|
|
@@ -8276,6 +8350,7 @@ function routeInput(raw) {
|
|
|
8276
8350
|
case "connect":
|
|
8277
8351
|
case "copy":
|
|
8278
8352
|
case "portal":
|
|
8353
|
+
case "compact":
|
|
8279
8354
|
case "help":
|
|
8280
8355
|
case "quit": return { kind: action.kind };
|
|
8281
8356
|
default: {
|
|
@@ -8468,6 +8543,10 @@ function ChatScreen({ agent, conversation }) {
|
|
|
8468
8543
|
const agentHost = useAgentHost();
|
|
8469
8544
|
const nonWebChannel = nonWebChannelLabel(conversation);
|
|
8470
8545
|
const [conversationId, setConversationId] = useState(initialConversationId);
|
|
8546
|
+
const { compacting, compactConversation, onCompactionEvent } = useCompaction({
|
|
8547
|
+
rest,
|
|
8548
|
+
conversationId
|
|
8549
|
+
});
|
|
8471
8550
|
const [items, setItems] = useState([]);
|
|
8472
8551
|
const [todos, setTodos] = useState(null);
|
|
8473
8552
|
const [planHidden, setPlanHidden] = useState(false);
|
|
@@ -8732,15 +8811,22 @@ function ChatScreen({ agent, conversation }) {
|
|
|
8732
8811
|
attachToRun(event.runId, null, parseStampMs(event.createdAt));
|
|
8733
8812
|
return;
|
|
8734
8813
|
}
|
|
8735
|
-
if (event.
|
|
8814
|
+
if (event.kind === "compaction") {
|
|
8815
|
+
onCompactionEvent(event.status);
|
|
8816
|
+
return;
|
|
8817
|
+
}
|
|
8818
|
+
if (event.kind === "conversation" && event.title) setChatTitle(event.title);
|
|
8736
8819
|
}
|
|
8737
8820
|
}).catch(() => {});
|
|
8738
|
-
return () =>
|
|
8821
|
+
return () => {
|
|
8822
|
+
abort.abort();
|
|
8823
|
+
};
|
|
8739
8824
|
}, [
|
|
8740
8825
|
rest,
|
|
8741
8826
|
conversationId,
|
|
8742
8827
|
setChatTitle,
|
|
8743
|
-
attachToRun
|
|
8828
|
+
attachToRun,
|
|
8829
|
+
onCompactionEvent
|
|
8744
8830
|
]);
|
|
8745
8831
|
const sendContent = useCallback(async (content, staged, opts) => {
|
|
8746
8832
|
if (!rest) return;
|
|
@@ -8813,7 +8899,7 @@ function ChatScreen({ agent, conversation }) {
|
|
|
8813
8899
|
setItems((prev) => [...prev.filter((m) => m.id !== optimisticId), {
|
|
8814
8900
|
kind: "error",
|
|
8815
8901
|
id: crypto.randomUUID(),
|
|
8816
|
-
text:
|
|
8902
|
+
text: sendErrorMessage(err)
|
|
8817
8903
|
}]);
|
|
8818
8904
|
if (echo) setInput((existing) => existing ? existing : trimmed);
|
|
8819
8905
|
const restore = staged.filter((a) => uploadsRef.current.has(a.tempId));
|
|
@@ -8859,6 +8945,7 @@ function ChatScreen({ agent, conversation }) {
|
|
|
8859
8945
|
portalStatus,
|
|
8860
8946
|
portalClient,
|
|
8861
8947
|
agent.id,
|
|
8948
|
+
agent.name,
|
|
8862
8949
|
sendContent
|
|
8863
8950
|
]);
|
|
8864
8951
|
const cancelLatestSteer = useCallback(() => {
|
|
@@ -9584,6 +9671,9 @@ function ChatScreen({ agent, conversation }) {
|
|
|
9584
9671
|
case "portal":
|
|
9585
9672
|
openPortalAccess();
|
|
9586
9673
|
break;
|
|
9674
|
+
case "compact":
|
|
9675
|
+
compactConversation();
|
|
9676
|
+
break;
|
|
9587
9677
|
case "connect":
|
|
9588
9678
|
if (!promptForCards()) useStore.getState().showToast({ message: "no connect card waiting for action" });
|
|
9589
9679
|
break;
|
|
@@ -9618,6 +9708,7 @@ function ChatScreen({ agent, conversation }) {
|
|
|
9618
9708
|
openInBrowser,
|
|
9619
9709
|
copyLastMessage,
|
|
9620
9710
|
openPortalAccess,
|
|
9711
|
+
compactConversation,
|
|
9621
9712
|
quit,
|
|
9622
9713
|
sendContent,
|
|
9623
9714
|
goTo,
|
|
@@ -10043,6 +10134,23 @@ function ChatScreen({ agent, conversation }) {
|
|
|
10043
10134
|
todos,
|
|
10044
10135
|
isActive: run.kind !== "idle"
|
|
10045
10136
|
}) : null,
|
|
10137
|
+
compacting ? /* @__PURE__ */ jsxs("box", {
|
|
10138
|
+
style: {
|
|
10139
|
+
flexDirection: "row",
|
|
10140
|
+
paddingLeft: 1,
|
|
10141
|
+
paddingRight: 1,
|
|
10142
|
+
height: 1,
|
|
10143
|
+
flexShrink: 0,
|
|
10144
|
+
marginTop: 1
|
|
10145
|
+
},
|
|
10146
|
+
children: [/* @__PURE__ */ jsx("text", {
|
|
10147
|
+
fg: theme.accent,
|
|
10148
|
+
children: "● compacting conversation…"
|
|
10149
|
+
}), /* @__PURE__ */ jsxs("text", {
|
|
10150
|
+
fg: theme.dim,
|
|
10151
|
+
children: [" ", "you can keep typing"]
|
|
10152
|
+
})]
|
|
10153
|
+
}) : null,
|
|
10046
10154
|
pendingVisible ? /* @__PURE__ */ jsxs("box", {
|
|
10047
10155
|
style: {
|
|
10048
10156
|
paddingLeft: 1,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
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 { a as errorMessage } from "./rest-vu2-Lrsa.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-Bx5VyWaC.mjs";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
6
|
import { WebSocket } from "ws";
|
|
@@ -1,6 +1,5 @@
|
|
|
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-CeisaZVY.mjs";
|
|
2
|
+
import { a as errorMessage, i as sendErrorMessage, n as createRestClient, o as isRecord, t as HttpError } from "./rest-vu2-Lrsa.mjs";
|
|
4
3
|
import stableStringify from "safe-stable-stringify";
|
|
5
4
|
|
|
6
5
|
//#region src/chat/tui/chat/card.ts
|
|
@@ -355,17 +354,24 @@ async function runPrint({ appUrl, sessionToken, prompt, agentSelector, conversat
|
|
|
355
354
|
};
|
|
356
355
|
}
|
|
357
356
|
/**
|
|
358
|
-
* Turn a transport failure into an actionable CLI error.
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
357
|
+
* Turn a transport failure into an actionable CLI error. Two failure classes
|
|
358
|
+
* reach here, both of which otherwise leak a raw HTML/JSON error page to stdout:
|
|
359
|
+
*
|
|
360
|
+
* - A Cloudflare edge 5xx (502/504) on a long run. When a messageId is known
|
|
361
|
+
* and recoverable we point the user at `skydive messages get <messageId>`
|
|
362
|
+
* rather than a blind retry (a retry re-executes an agent that may have
|
|
363
|
+
* write access).
|
|
364
|
+
* - A 4xx from the send/stream endpoints (a validation 400 whose body is a raw
|
|
365
|
+
* Zod issues array, a billing/permission block, an expired session). These
|
|
366
|
+
* go through {@link sendErrorMessage} so the `-p` path prints the same plain,
|
|
367
|
+
* actionable copy the interactive TUI shows instead of an obtuse blob.
|
|
363
368
|
*/
|
|
364
369
|
function toPrintError(err, messageId) {
|
|
365
370
|
if (err instanceof HttpError && err.status >= 500) {
|
|
366
371
|
const recovery = messageId ? ` The run may still be completing server-side. Do NOT blindly retry (it would re-run the agent). Fetch the result with: skydive messages get ${messageId}` : "";
|
|
367
372
|
return /* @__PURE__ */ new Error(`The request to Skydive timed out at the edge (HTTP ${err.status}).${recovery}`);
|
|
368
373
|
}
|
|
374
|
+
if (err instanceof HttpError) return new Error(sendErrorMessage(err));
|
|
369
375
|
return err instanceof Error ? err : new Error(String(err));
|
|
370
376
|
}
|
|
371
377
|
/**
|
|
@@ -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-vu2-Lrsa.mjs";
|
|
3
|
+
import { a as runPrint, i as resolveAgent, n as messageGet, o as toPrintError, r as readStdin, t as collectRunText } from "./print-DLGCpIM9.mjs";
|
|
4
4
|
|
|
5
5
|
export { messageGet, readStdin, resolveAgent, runPrint };
|
|
@@ -14,7 +14,7 @@ import { n as printError } from "./output-B4cW10Ph.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-BYYp0E6M.mjs");
|
|
18
18
|
let signalConnected;
|
|
19
19
|
const connected = new Promise((resolve) => {
|
|
20
20
|
signalConnected = resolve;
|
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { createParser } from "eventsource-parser";
|
|
4
4
|
|
|
5
|
+
//#region src/chat/util.ts
|
|
6
|
+
/** Narrowing helper for the many `unknown` payloads the chat stream and
|
|
7
|
+
* tool inputs/outputs carry. A type predicate (not an `as` cast), so call
|
|
8
|
+
* sites can read properties without asserting. */
|
|
9
|
+
function isRecord(value) {
|
|
10
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11
|
+
}
|
|
12
|
+
/** Best-effort message from an unknown thrown value. */
|
|
13
|
+
function errorMessage(err) {
|
|
14
|
+
return err instanceof Error ? err.message : String(err);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
5
18
|
//#region src/chat/api/rest.ts
|
|
6
19
|
var HttpError = class extends Error {
|
|
7
20
|
constructor(status, body) {
|
|
@@ -25,6 +38,69 @@ function errorDetail(err) {
|
|
|
25
38
|
}
|
|
26
39
|
return err instanceof Error ? err.message : String(err);
|
|
27
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* The server's human-readable line out of an error response body, or null when
|
|
43
|
+
* the body carries none. Two shapes reach the CLI on a failed send:
|
|
44
|
+
*
|
|
45
|
+
* - `{ error: string }` — the chat route's own errors (a ChatClientError like
|
|
46
|
+
* "agent not found" / "attachment not found: <id>", the 429 "Too many
|
|
47
|
+
* requests", the generic "send failed"). Returned verbatim; these are
|
|
48
|
+
* written to be shown.
|
|
49
|
+
* - `{ success: false, error: { issues: [{ message }, …] } }` — a Zod request
|
|
50
|
+
* validation failure from `zValidator` (e.g. the message-too-long copy).
|
|
51
|
+
* Without this the CLI printed the whole issues array as a raw JSON blob,
|
|
52
|
+
* which is the "obtuse 400 with no recourse" a user sees. We lift the first
|
|
53
|
+
* issue's message, which the schema authors wrote for humans.
|
|
54
|
+
*
|
|
55
|
+
* Anything else (a Cloudflare/ALB HTML error page, an empty body) yields null
|
|
56
|
+
* so the caller can fall back to a status-based line.
|
|
57
|
+
*/
|
|
58
|
+
function serverErrorMessage(body) {
|
|
59
|
+
let parsed;
|
|
60
|
+
try {
|
|
61
|
+
parsed = JSON.parse(body);
|
|
62
|
+
} catch (_error) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
if (!isRecord(parsed)) return null;
|
|
66
|
+
if (typeof parsed.error === "string" && parsed.error.length > 0) return parsed.error;
|
|
67
|
+
if (isRecord(parsed.error) && Array.isArray(parsed.error.issues)) {
|
|
68
|
+
const first = parsed.error.issues.find((issue) => isRecord(issue) && typeof issue.message === "string" && !!issue.message);
|
|
69
|
+
if (first) return first.message;
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A short, actionable line for a failed chat send, for both the interactive
|
|
75
|
+
* TUI error row and the headless `-p` path. The raw transport error is an
|
|
76
|
+
* `HTTP 400: {"success":false,"error":{"issues":[…]}}` blob that a user can do
|
|
77
|
+
* nothing with; this maps every send failure the server can produce to plain
|
|
78
|
+
* language and, where possible, a next step.
|
|
79
|
+
*
|
|
80
|
+
* Precedence: a message the SERVER wrote for humans always wins (validation
|
|
81
|
+
* copy, "agent not found", a billing/permission reason) — we only synthesize a
|
|
82
|
+
* line from the HTTP status when the body carried nothing usable. This keeps
|
|
83
|
+
* new server-side error copy flowing through without a CLI change, while never
|
|
84
|
+
* leaving the user staring at a bare status code.
|
|
85
|
+
*/
|
|
86
|
+
function sendErrorMessage(err) {
|
|
87
|
+
if (!(err instanceof HttpError)) return `Couldn't reach Skydive (${err instanceof Error ? err.message : String(err)}). Check your connection and try again.`;
|
|
88
|
+
const fromServer = serverErrorMessage(err.body);
|
|
89
|
+
switch (err.status) {
|
|
90
|
+
case 401: return "Your session has expired. Run `skydive auth login --web`, then send again.";
|
|
91
|
+
case 403: return fromServer ?? "You don't have permission to send to this agent in the current workspace.";
|
|
92
|
+
case 404: return fromServer ?? "This conversation or agent no longer exists.";
|
|
93
|
+
case 413: return fromServer ?? "That message is too large to send. Attach it as a file instead of pasting it inline.";
|
|
94
|
+
case 429: return "You're sending messages too quickly. Wait a moment and try again.";
|
|
95
|
+
default: break;
|
|
96
|
+
}
|
|
97
|
+
if (err.status >= 500) return `Skydive had a problem sending that (HTTP ${err.status}). Wait a moment and try again.`;
|
|
98
|
+
if (err.status === 400) {
|
|
99
|
+
if (fromServer && fromServer !== "send failed") return fromServer;
|
|
100
|
+
return "Skydive couldn't send that message. Try again in a moment.";
|
|
101
|
+
}
|
|
102
|
+
return fromServer ?? `Send failed (HTTP ${err.status}).`;
|
|
103
|
+
}
|
|
28
104
|
const MAX_STREAM_RECONNECTS = 5;
|
|
29
105
|
function createRestClient({ appUrl, sessionToken }) {
|
|
30
106
|
const baseHeaders = {
|
|
@@ -227,6 +303,9 @@ function createRestClient({ appUrl, sessionToken }) {
|
|
|
227
303
|
const { conversation } = await post(`/api/v1/conversations/${encodeURIComponent(conversationId)}/fork`, {}, forkConversationResponseSchema);
|
|
228
304
|
return conversation;
|
|
229
305
|
},
|
|
306
|
+
compactConversation: async ({ conversationId }) => {
|
|
307
|
+
await post(`/api/v1/conversations/${encodeURIComponent(conversationId)}/compact`, {}, z.object({ status: z.string() }));
|
|
308
|
+
},
|
|
230
309
|
deleteConversation: async ({ conversationId }) => {
|
|
231
310
|
await del(`/api/v1/conversations/${encodeURIComponent(conversationId)}`);
|
|
232
311
|
},
|
|
@@ -462,15 +541,26 @@ const runStreamEventSchema = z.union([z.object({
|
|
|
462
541
|
error: z.string().nullish()
|
|
463
542
|
})]);
|
|
464
543
|
const streamErrorSchema = z.object({ error: z.string() });
|
|
465
|
-
const conversationStreamEventSchema = z.discriminatedUnion("kind", [
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
544
|
+
const conversationStreamEventSchema = z.discriminatedUnion("kind", [
|
|
545
|
+
z.object({
|
|
546
|
+
kind: z.literal("conversation"),
|
|
547
|
+
id: z.string(),
|
|
548
|
+
title: z.string().nullable()
|
|
549
|
+
}),
|
|
550
|
+
z.object({
|
|
551
|
+
kind: z.literal("run"),
|
|
552
|
+
runId: z.string(),
|
|
553
|
+
createdAt: z.string().nullish()
|
|
554
|
+
}),
|
|
555
|
+
z.object({
|
|
556
|
+
kind: z.literal("compaction"),
|
|
557
|
+
status: z.enum([
|
|
558
|
+
"started",
|
|
559
|
+
"completed",
|
|
560
|
+
"failed"
|
|
561
|
+
])
|
|
562
|
+
})
|
|
563
|
+
]);
|
|
474
564
|
|
|
475
565
|
//#endregion
|
|
476
|
-
export { createRestClient as n, errorDetail as r, HttpError as t };
|
|
566
|
+
export { errorMessage as a, sendErrorMessage as i, createRestClient as n, isRecord as o, errorDetail as r, HttpError as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skydive-cli",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.600",
|
|
4
4
|
"description": "Skydive CLI — cloud agents from the command line",
|
|
5
5
|
"homepage": "https://skydive.com",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"test:ci": "vitest run --coverage --coverage.reporter=lcovonly --reporter=default --reporter=github-actions --minWorkers=1 --maxWorkers=2 --passWithNoTests && yarn test:tui",
|
|
26
26
|
"test:tui": "bun test .tui.test",
|
|
27
27
|
"render:frames": "bun scripts/render-frames.tsx",
|
|
28
|
+
"render:send-errors": "bun scripts/render-send-errors.tsx",
|
|
28
29
|
"typecheck": "tsgo --noEmit"
|
|
29
30
|
},
|
|
30
31
|
"dependencies": {
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
//#region src/chat/util.ts
|
|
3
|
-
/** Narrowing helper for the many `unknown` payloads the chat stream and
|
|
4
|
-
* tool inputs/outputs carry. A type predicate (not an `as` cast), so call
|
|
5
|
-
* sites can read properties without asserting. */
|
|
6
|
-
function isRecord(value) {
|
|
7
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
|
-
}
|
|
9
|
-
/** Best-effort message from an unknown thrown value. */
|
|
10
|
-
function errorMessage(err) {
|
|
11
|
-
return err instanceof Error ? err.message : String(err);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
//#endregion
|
|
15
|
-
export { isRecord as n, errorMessage as t };
|
|
File without changes
|