skydive-cli 0.2.0-beta.455 → 0.2.0-beta.482
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-zUf_Vrzh.mjs → api-BHq-5eW_.mjs} +1 -1
- package/dist/js/bin.mjs +20 -17
- package/dist/js/{boot-SxcKHfwY.mjs → boot-B8ownO3n.mjs} +310 -45
- package/dist/js/{theme-CuQhvqzN.mjs → brand-BVALAEf1.mjs} +144 -1
- package/dist/js/client-CRAGDqp0.mjs +6 -0
- package/dist/js/{client-DuPxkSoH.mjs → client-t6GmE8TI.mjs} +1 -1
- package/dist/js/{print-DUsH9Dlh.mjs → print-Chg635Ye.mjs} +2 -2
- package/dist/js/{print-YqNIRwdf.mjs → print-XvAHDKqu.mjs} +1 -1
- package/dist/js/{print-share-B8sZ0w-M.mjs → print-share-DT89ADa6.mjs} +1 -1
- package/dist/js/{rest-Cz0VLhmi.mjs → rest-Ci_yRwoi.mjs} +1 -1
- package/dist/js/{rest-BBQrPIwq.mjs → rest-DZnAT7BG.mjs} +20 -7
- package/package.json +1 -1
- package/dist/js/client-A4m7lNDg.mjs +0 -6
package/dist/js/bin.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { A as
|
|
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-
|
|
4
|
+
import { n as createRestClient } from "./rest-DZnAT7BG.mjs";
|
|
5
|
+
import { i as resolveAgent } from "./print-XvAHDKqu.mjs";
|
|
6
|
+
import { a as registerPortalDevice, c as machineIdentity, n as findThisDevice, o as revokePortalAccess, r as grantPortalAccess, t as fetchPortalDevices } from "./api-BHq-5eW_.mjs";
|
|
7
7
|
import { t as SandboxStream } from "./client-CpEvH2Pq.mjs";
|
|
8
8
|
import { hideBin } from "yargs/helpers";
|
|
9
9
|
import yargs from "yargs";
|
|
@@ -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.482";
|
|
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-B8ownO3n.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-DT89ADa6.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-Chg635Ye.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-B8ownO3n.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-Chg635Ye.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-DT89ADa6.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-Chg635Ye.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-B8ownO3n.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-CRAGDqp0.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-Ci_yRwoi.mjs");
|
|
2064
|
+
const { resolveAgent } = await import("./print-Chg635Ye.mjs");
|
|
2065
2065
|
const client = createRestClient({
|
|
2066
2066
|
appUrl: session.appUrl,
|
|
2067
2067
|
sessionToken: session.sessionToken
|
|
@@ -2608,7 +2608,10 @@ if (process.argv.includes(UPDATE_WORKER_FLAG)) {
|
|
|
2608
2608
|
}
|
|
2609
2609
|
maybePrintWhatsNew();
|
|
2610
2610
|
setupUpdateCheck(hideBin(process.argv));
|
|
2611
|
-
|
|
2611
|
+
const resolved = resolveArgv(hideBin(process.argv));
|
|
2612
|
+
const raw = hideBin(process.argv);
|
|
2613
|
+
if ((raw.includes("--help") || raw.includes("-h")) && !raw.some((a) => !a.startsWith("-")) && !raw.includes("--json") && !raw.includes("--quiet")) process.stdout.write(brandHelpArt());
|
|
2614
|
+
createCli(resolved).parse();
|
|
2612
2615
|
|
|
2613
2616
|
//#endregion
|
|
2614
2617
|
export { };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { n as createRestClient, r as errorDetail, t as HttpError } from "./rest-
|
|
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-DZnAT7BG.mjs";
|
|
4
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, m as specKeyFor, p as parseConnectCard, s as MASK_CHAR, u as parseOauthConnectParams } from "./print-
|
|
6
|
-
import "./api-
|
|
5
|
+
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-XvAHDKqu.mjs";
|
|
6
|
+
import "./api-BHq-5eW_.mjs";
|
|
7
7
|
import { t as SandboxStream } from "./client-CpEvH2Pq.mjs";
|
|
8
|
-
import { t as PortalClient } from "./client-
|
|
8
|
+
import { t as PortalClient } from "./client-t6GmE8TI.mjs";
|
|
9
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";
|
|
@@ -183,8 +183,8 @@ async function resolveInitialScreen({ rest, agentSelector, conversationId, newCo
|
|
|
183
183
|
createdAt: conversation.createdAt,
|
|
184
184
|
updatedAt: conversation.updatedAt,
|
|
185
185
|
preview: null,
|
|
186
|
-
channel:
|
|
187
|
-
channelLabel:
|
|
186
|
+
channel: conversation.channel,
|
|
187
|
+
channelLabel: conversation.channelLabel,
|
|
188
188
|
agent: {
|
|
189
189
|
id: agent.id,
|
|
190
190
|
name: agent.name,
|
|
@@ -931,6 +931,76 @@ function FuzzyText({ text, indexes, fg }) {
|
|
|
931
931
|
}, i)) });
|
|
932
932
|
}
|
|
933
933
|
|
|
934
|
+
//#endregion
|
|
935
|
+
//#region src/chat/tui/skydive-mark.tsx
|
|
936
|
+
/**
|
|
937
|
+
* The Skydive brand splash for the interactive TUI, rendered as OpenTUI React
|
|
938
|
+
* nodes (not raw ANSI). Two variants:
|
|
939
|
+
*
|
|
940
|
+
* - `variant="full"` — the six-petal mark beside the SKYDIVE wordmark.
|
|
941
|
+
* - `variant="mark"` — just the pinwheel mark (compact picker headers).
|
|
942
|
+
*
|
|
943
|
+
* The mark paints fixed brand hexes (a logo is a logo). The wordmark follows
|
|
944
|
+
* the current theme's body text (`theme.fg`) so it reads white-ish on dark
|
|
945
|
+
* themes and dark on light ones. Under NO_COLOR the theme palette is all
|
|
946
|
+
* `undefined`; we detect that and render uncolored so it degrades with the
|
|
947
|
+
* rest of the UI.
|
|
948
|
+
*/
|
|
949
|
+
function noColor() {
|
|
950
|
+
return theme.fg === void 0;
|
|
951
|
+
}
|
|
952
|
+
function MarkRows({ mono }) {
|
|
953
|
+
return /* @__PURE__ */ jsx("box", {
|
|
954
|
+
style: { flexDirection: "column" },
|
|
955
|
+
children: MARK_CELLS.map((row, r) => /* @__PURE__ */ jsx("text", { children: row.map((cell, c) => cell === " " ? /* @__PURE__ */ jsx("span", { children: " " }, c) : /* @__PURE__ */ jsx("span", {
|
|
956
|
+
fg: mono ? void 0 : cell[1],
|
|
957
|
+
children: cell[0]
|
|
958
|
+
}, c)) }, r))
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
function WordmarkRows({ mono }) {
|
|
962
|
+
const color = mono ? void 0 : theme.fg;
|
|
963
|
+
return /* @__PURE__ */ jsx("box", {
|
|
964
|
+
style: { flexDirection: "column" },
|
|
965
|
+
children: WORDMARK.map((line, r) => /* @__PURE__ */ jsx("text", { children: /* @__PURE__ */ jsx("span", {
|
|
966
|
+
fg: color,
|
|
967
|
+
children: line
|
|
968
|
+
}) }, r))
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Height-aware brand header for the pickers. Always shown (including while the
|
|
973
|
+
* list is loading / empty / erroring) so the splash is never gated on data.
|
|
974
|
+
* Full mark + wordmark when the terminal is tall enough; compact one-liner on
|
|
975
|
+
* short terminals so the list still has room.
|
|
976
|
+
*/
|
|
977
|
+
function BrandHeader({ height }) {
|
|
978
|
+
if (height >= 24) return /* @__PURE__ */ jsxs("box", {
|
|
979
|
+
style: { flexDirection: "column" },
|
|
980
|
+
children: [/* @__PURE__ */ jsx(SkydiveMark, { variant: "full" }), /* @__PURE__ */ jsx("box", { style: { height: 1 } })]
|
|
981
|
+
});
|
|
982
|
+
return /* @__PURE__ */ jsx("text", {
|
|
983
|
+
fg: theme.fg,
|
|
984
|
+
children: "✦ Skydive"
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
/** Row budget the BrandHeader consumes; callers subtract this from visibleRows. */
|
|
988
|
+
function brandHeaderRows(height) {
|
|
989
|
+
return height >= 24 ? 7 : 1;
|
|
990
|
+
}
|
|
991
|
+
function SkydiveMark({ variant = "full" }) {
|
|
992
|
+
const mono = noColor();
|
|
993
|
+
if (variant === "mark") return /* @__PURE__ */ jsx(MarkRows, { mono });
|
|
994
|
+
return /* @__PURE__ */ jsxs("box", {
|
|
995
|
+
style: { flexDirection: "row" },
|
|
996
|
+
children: [
|
|
997
|
+
/* @__PURE__ */ jsx(MarkRows, { mono }),
|
|
998
|
+
/* @__PURE__ */ jsx("box", { style: { width: 3 } }),
|
|
999
|
+
/* @__PURE__ */ jsx(WordmarkRows, { mono })
|
|
1000
|
+
]
|
|
1001
|
+
});
|
|
1002
|
+
}
|
|
1003
|
+
|
|
934
1004
|
//#endregion
|
|
935
1005
|
//#region src/chat/tui/screens/agent-picker.tsx
|
|
936
1006
|
function AgentPickerScreen() {
|
|
@@ -998,17 +1068,36 @@ function AgentPickerScreen() {
|
|
|
998
1068
|
scope,
|
|
999
1069
|
cache
|
|
1000
1070
|
]);
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1071
|
+
const { height } = useTerminalDimensions();
|
|
1072
|
+
if (state.kind === "loading") return /* @__PURE__ */ jsxs("box", {
|
|
1073
|
+
style: {
|
|
1074
|
+
flexDirection: "column",
|
|
1075
|
+
flexGrow: 1
|
|
1076
|
+
},
|
|
1077
|
+
children: [/* @__PURE__ */ jsx(BrandHeader, { height }), /* @__PURE__ */ jsx("text", {
|
|
1078
|
+
fg: theme.muted,
|
|
1079
|
+
children: "loading agents…"
|
|
1080
|
+
})]
|
|
1004
1081
|
});
|
|
1005
|
-
if (state.kind === "error") return /* @__PURE__ */ jsxs("
|
|
1006
|
-
|
|
1007
|
-
|
|
1082
|
+
if (state.kind === "error") return /* @__PURE__ */ jsxs("box", {
|
|
1083
|
+
style: {
|
|
1084
|
+
flexDirection: "column",
|
|
1085
|
+
flexGrow: 1
|
|
1086
|
+
},
|
|
1087
|
+
children: [/* @__PURE__ */ jsx(BrandHeader, { height }), /* @__PURE__ */ jsxs("text", {
|
|
1088
|
+
fg: theme.error,
|
|
1089
|
+
children: ["error: ", state.message]
|
|
1090
|
+
})]
|
|
1008
1091
|
});
|
|
1009
|
-
if (state.agents.length === 0) return /* @__PURE__ */
|
|
1010
|
-
|
|
1011
|
-
|
|
1092
|
+
if (state.agents.length === 0) return /* @__PURE__ */ jsxs("box", {
|
|
1093
|
+
style: {
|
|
1094
|
+
flexDirection: "column",
|
|
1095
|
+
flexGrow: 1
|
|
1096
|
+
},
|
|
1097
|
+
children: [/* @__PURE__ */ jsx(BrandHeader, { height }), /* @__PURE__ */ jsx("text", {
|
|
1098
|
+
fg: theme.muted,
|
|
1099
|
+
children: scope === "mine" ? "no agents of yours yet. press tab to see all agents, ctrl+w to switch workspace, or ctrl+n to create one." : "no agents in this workspace. press ctrl+w to switch workspace, or ctrl+n to create one."
|
|
1100
|
+
})]
|
|
1012
1101
|
});
|
|
1013
1102
|
return /* @__PURE__ */ jsx(FilterableAgentList, {
|
|
1014
1103
|
agents: state.agents,
|
|
@@ -1026,7 +1115,7 @@ function FilterableAgentList({ agents, scope, onPick }) {
|
|
|
1026
1115
|
const hits = fuzzyFilter(query, agents, agentKeys);
|
|
1027
1116
|
const filtered = hits.map((h) => h.item);
|
|
1028
1117
|
const clamped = Math.min(highlight, Math.max(0, filtered.length - 1));
|
|
1029
|
-
const visibleRows = Math.max(3, height - 6);
|
|
1118
|
+
const visibleRows = Math.max(3, height - 6 - brandHeaderRows(height));
|
|
1030
1119
|
const start = windowStart(clamped, filtered.length, visibleRows);
|
|
1031
1120
|
const windowed = hits.slice(start, start + visibleRows);
|
|
1032
1121
|
useKeyboard((key) => {
|
|
@@ -1055,6 +1144,7 @@ function FilterableAgentList({ agents, scope, onPick }) {
|
|
|
1055
1144
|
flexGrow: 1
|
|
1056
1145
|
},
|
|
1057
1146
|
children: [
|
|
1147
|
+
/* @__PURE__ */ jsx(BrandHeader, { height }),
|
|
1058
1148
|
/* @__PURE__ */ jsxs("box", {
|
|
1059
1149
|
style: {
|
|
1060
1150
|
flexDirection: "row",
|
|
@@ -1515,27 +1605,45 @@ function singleLine(text) {
|
|
|
1515
1605
|
return out;
|
|
1516
1606
|
}
|
|
1517
1607
|
/**
|
|
1518
|
-
* Fit a row's title
|
|
1519
|
-
*
|
|
1520
|
-
*
|
|
1608
|
+
* Fit a row's title, an optional mid-row `tag` and a trailing detail into
|
|
1609
|
+
* `width` columns, each rendered separated by one space. The title identifies
|
|
1610
|
+
* the row so it gets the space first; the tag comes next because it carries
|
|
1611
|
+
* information the detail does not; the detail takes what is left and is
|
|
1612
|
+
* dropped when nothing is.
|
|
1521
1613
|
*/
|
|
1522
|
-
function fitRowText(title, detail, width) {
|
|
1614
|
+
function fitRowText(title, detail, width, tag = "") {
|
|
1523
1615
|
if (width <= 0) return {
|
|
1524
1616
|
title: "",
|
|
1525
|
-
detail: ""
|
|
1617
|
+
detail: "",
|
|
1618
|
+
tag: ""
|
|
1526
1619
|
};
|
|
1527
|
-
|
|
1620
|
+
const segment = (text) => text ? text.length + 1 : 0;
|
|
1621
|
+
if (title.length + segment(tag) + segment(detail) <= width) return {
|
|
1528
1622
|
title,
|
|
1529
|
-
detail
|
|
1623
|
+
detail,
|
|
1624
|
+
tag
|
|
1530
1625
|
};
|
|
1531
1626
|
const room = width - title.length - 1;
|
|
1532
1627
|
if (room < 2) return {
|
|
1533
1628
|
title: truncate(title, width),
|
|
1534
|
-
detail: ""
|
|
1629
|
+
detail: "",
|
|
1630
|
+
tag: ""
|
|
1631
|
+
};
|
|
1632
|
+
if (title.length + segment(tag) > width) return {
|
|
1633
|
+
title,
|
|
1634
|
+
detail: "",
|
|
1635
|
+
tag: truncate(tag, room)
|
|
1636
|
+
};
|
|
1637
|
+
const detailRoom = room - segment(tag);
|
|
1638
|
+
if (detailRoom < 2) return {
|
|
1639
|
+
title,
|
|
1640
|
+
detail: "",
|
|
1641
|
+
tag
|
|
1535
1642
|
};
|
|
1536
1643
|
return {
|
|
1537
1644
|
title,
|
|
1538
|
-
detail: truncate(detail,
|
|
1645
|
+
detail: truncate(detail, detailRoom),
|
|
1646
|
+
tag
|
|
1539
1647
|
};
|
|
1540
1648
|
}
|
|
1541
1649
|
/**
|
|
@@ -1624,13 +1732,26 @@ function ConversationPickerScreen({ agent }) {
|
|
|
1624
1732
|
cacheKey,
|
|
1625
1733
|
cache
|
|
1626
1734
|
]);
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1735
|
+
const { height } = useTerminalDimensions();
|
|
1736
|
+
if (state.kind === "loading") return /* @__PURE__ */ jsxs("box", {
|
|
1737
|
+
style: {
|
|
1738
|
+
flexDirection: "column",
|
|
1739
|
+
flexGrow: 1
|
|
1740
|
+
},
|
|
1741
|
+
children: [/* @__PURE__ */ jsx(BrandHeader, { height }), /* @__PURE__ */ jsx("text", {
|
|
1742
|
+
fg: theme.muted,
|
|
1743
|
+
children: "loading conversations…"
|
|
1744
|
+
})]
|
|
1630
1745
|
});
|
|
1631
|
-
if (state.kind === "error") return /* @__PURE__ */ jsxs("
|
|
1632
|
-
|
|
1633
|
-
|
|
1746
|
+
if (state.kind === "error") return /* @__PURE__ */ jsxs("box", {
|
|
1747
|
+
style: {
|
|
1748
|
+
flexDirection: "column",
|
|
1749
|
+
flexGrow: 1
|
|
1750
|
+
},
|
|
1751
|
+
children: [/* @__PURE__ */ jsx(BrandHeader, { height }), /* @__PURE__ */ jsxs("text", {
|
|
1752
|
+
fg: theme.error,
|
|
1753
|
+
children: ["error: ", state.message]
|
|
1754
|
+
})]
|
|
1634
1755
|
});
|
|
1635
1756
|
return /* @__PURE__ */ jsx(ConversationList, {
|
|
1636
1757
|
agent,
|
|
@@ -1687,7 +1808,7 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
|
|
|
1687
1808
|
"↵ open"
|
|
1688
1809
|
], innerWidth)
|
|
1689
1810
|
};
|
|
1690
|
-
const visibleRows = Math.max(3, height - 6);
|
|
1811
|
+
const visibleRows = Math.max(3, height - 6 - brandHeaderRows(height));
|
|
1691
1812
|
const start = windowStart(clamped, rows.length, visibleRows);
|
|
1692
1813
|
const windowed = rows.slice(start, start + visibleRows);
|
|
1693
1814
|
const open = (row) => {
|
|
@@ -1786,6 +1907,7 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
|
|
|
1786
1907
|
flexGrow: 1
|
|
1787
1908
|
},
|
|
1788
1909
|
children: [
|
|
1910
|
+
/* @__PURE__ */ jsx(BrandHeader, { height }),
|
|
1789
1911
|
/* @__PURE__ */ jsxs("box", {
|
|
1790
1912
|
style: {
|
|
1791
1913
|
flexDirection: "row",
|
|
@@ -1822,7 +1944,7 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
|
|
|
1822
1944
|
children: [marker, truncate("+ new conversation", rowWidth)]
|
|
1823
1945
|
}, "new");
|
|
1824
1946
|
const archived = isArchived(row.hit.item);
|
|
1825
|
-
const { title, detail } = fitRowText(singleLine(row.hit.item.title ?? "(untitled)"), `${archived ? "archived · " : ""}${previewLine(row.hit.item)}`, rowWidth);
|
|
1947
|
+
const { title, detail, tag } = fitRowText(singleLine(row.hit.item.title ?? "(untitled)"), `${archived ? "archived · " : ""}${previewLine(row.hit.item)}`, rowWidth, coAgentsTag(row.hit.item, agent.id));
|
|
1826
1948
|
return /* @__PURE__ */ jsxs("text", {
|
|
1827
1949
|
fg: archived && !selected ? theme.dim : fg,
|
|
1828
1950
|
children: [
|
|
@@ -1831,6 +1953,10 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
|
|
|
1831
1953
|
text: title,
|
|
1832
1954
|
indexes: row.hit.item.title ? row.hit.highlights[0] : null
|
|
1833
1955
|
}),
|
|
1956
|
+
tag ? /* @__PURE__ */ jsxs("span", {
|
|
1957
|
+
fg: theme.muted,
|
|
1958
|
+
children: [" ", tag]
|
|
1959
|
+
}) : null,
|
|
1834
1960
|
detail ? /* @__PURE__ */ jsxs("span", {
|
|
1835
1961
|
fg: theme.dim,
|
|
1836
1962
|
children: [" ", detail]
|
|
@@ -1842,7 +1968,27 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
|
|
|
1842
1968
|
]
|
|
1843
1969
|
});
|
|
1844
1970
|
}
|
|
1845
|
-
|
|
1971
|
+
/**
|
|
1972
|
+
* Tags a row with the thread's other agents (`+Grace, Ada`). The picker is
|
|
1973
|
+
* entered per agent, so that agent stays implicit and only its co-participants
|
|
1974
|
+
* are named — this tag is the only thing in the list distinguishing a
|
|
1975
|
+
* multi-agent thread from a solo one. Empty for a solo thread.
|
|
1976
|
+
*
|
|
1977
|
+
* A string rather than a component because the row's one-line budget has to
|
|
1978
|
+
* account for it (see list-line.ts).
|
|
1979
|
+
*/
|
|
1980
|
+
function coAgentsTag(conv, viewerAgentId) {
|
|
1981
|
+
const names = conversationAgents(conv).filter((a) => a.id !== viewerAgentId).map((a) => a.name);
|
|
1982
|
+
return names.length > 0 ? `+${names.join(", ")}` : "";
|
|
1983
|
+
}
|
|
1984
|
+
function conversationAgents(c) {
|
|
1985
|
+
return c.agents && c.agents.length > 0 ? c.agents : [c.agent];
|
|
1986
|
+
}
|
|
1987
|
+
const conversationKeys = [
|
|
1988
|
+
(c) => singleLine(c.title ?? ""),
|
|
1989
|
+
(c) => c.preview ?? "",
|
|
1990
|
+
(c) => conversationAgents(c).map((a) => a.name).join(" ")
|
|
1991
|
+
];
|
|
1846
1992
|
function previewLine(c) {
|
|
1847
1993
|
const when = relativeTime(c.updatedAt);
|
|
1848
1994
|
const prefix = c.preview ? c.preview.replace(/\s+/g, " ").trim() : "";
|
|
@@ -3949,10 +4095,13 @@ function TodoCardView({ todos, isActive }) {
|
|
|
3949
4095
|
//#endregion
|
|
3950
4096
|
//#region src/chat/tui/chat/footer-hints.ts
|
|
3951
4097
|
/** Build the chat footer copy independently of its colors and layout. */
|
|
3952
|
-
function formatChatFooterStatus({ runKind, ctrlCArmed, isShared, hasPendingSteer, hasActionableCard }) {
|
|
4098
|
+
function formatChatFooterStatus({ runKind, ctrlCArmed, isShared, hasPendingSteer, hasActionableCard, nonWebChannel }) {
|
|
3953
4099
|
const connectHint = hasActionableCard ? "ctrl+r connect · " : "";
|
|
3954
4100
|
switch (runKind) {
|
|
3955
|
-
case "idle":
|
|
4101
|
+
case "idle":
|
|
4102
|
+
if (ctrlCArmed) return "press ctrl+c again to quit";
|
|
4103
|
+
if (nonWebChannel) return `esc back · ctrl+c quit · ctrl+t ${isShared ? "revoke access" : "local access"} · ? keybinds`;
|
|
4104
|
+
return `${connectHint}↵ send · / commands · esc back · ctrl+c quit · ctrl+t ${isShared ? "revoke access" : "local access"} · ? keybinds`;
|
|
3956
4105
|
case "sending": return "sending…";
|
|
3957
4106
|
case "streaming": return hasPendingSteer ? `${connectHint}↵ steer · esc cancel steer · ctrl+c cancel run` : `${connectHint}↵ steer · esc leave (keeps running) · ctrl+c cancel`;
|
|
3958
4107
|
}
|
|
@@ -4288,6 +4437,10 @@ const keybindGroups = [
|
|
|
4288
4437
|
keys: "ctrl+l",
|
|
4289
4438
|
action: "open this conversation in the browser"
|
|
4290
4439
|
},
|
|
4440
|
+
{
|
|
4441
|
+
keys: "ctrl+f",
|
|
4442
|
+
action: "fork a channel conversation into a chat you can continue here"
|
|
4443
|
+
},
|
|
4291
4444
|
{
|
|
4292
4445
|
keys: "ctrl+r",
|
|
4293
4446
|
action: "run the newest connect card (auth cards)"
|
|
@@ -7797,6 +7950,47 @@ async function runPtySession(opts) {
|
|
|
7797
7950
|
}
|
|
7798
7951
|
}
|
|
7799
7952
|
|
|
7953
|
+
//#endregion
|
|
7954
|
+
//#region src/chat/tui/screens/conversation-channel.ts
|
|
7955
|
+
function isNewConversation(c) {
|
|
7956
|
+
return "kind" in c && c.kind === "new";
|
|
7957
|
+
}
|
|
7958
|
+
/**
|
|
7959
|
+
* The channel a conversation belongs to when it isn't the web channel, else
|
|
7960
|
+
* null. A brand-new conversation is always web, and the list route reports the
|
|
7961
|
+
* web channel as either `'web'` or (legacy) null — both mean "post from here".
|
|
7962
|
+
* Anything else (slack, email, imessage, webhook, cron) is owned by that
|
|
7963
|
+
* channel: the message has to go through it, so the TUI can't send here.
|
|
7964
|
+
* Mirrors the web app's `channel !== null && channel !== 'web'` gate.
|
|
7965
|
+
*/
|
|
7966
|
+
function nonWebChannelLabel(c) {
|
|
7967
|
+
if (isNewConversation(c)) return null;
|
|
7968
|
+
if (c.channel === null || c.channel === "web") return null;
|
|
7969
|
+
return c.channelLabel ?? c.channel;
|
|
7970
|
+
}
|
|
7971
|
+
/**
|
|
7972
|
+
* The list-row shape for a conversation the TUI just forked, so the chat
|
|
7973
|
+
* screen can reopen on the copy without waiting for a list refetch. A fork
|
|
7974
|
+
* carries none of the source's channel binding — that's what makes it
|
|
7975
|
+
* sendable from here — so it is always a web conversation.
|
|
7976
|
+
*/
|
|
7977
|
+
function forkedConversationRef({ agent, forked }) {
|
|
7978
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7979
|
+
return {
|
|
7980
|
+
id: forked.id,
|
|
7981
|
+
title: forked.title,
|
|
7982
|
+
createdAt: now,
|
|
7983
|
+
updatedAt: now,
|
|
7984
|
+
preview: null,
|
|
7985
|
+
channel: "web",
|
|
7986
|
+
channelLabel: null,
|
|
7987
|
+
agent: {
|
|
7988
|
+
id: agent.id,
|
|
7989
|
+
name: agent.name
|
|
7990
|
+
}
|
|
7991
|
+
};
|
|
7992
|
+
}
|
|
7993
|
+
|
|
7800
7994
|
//#endregion
|
|
7801
7995
|
//#region src/chat/tui/screens/chat.tsx
|
|
7802
7996
|
/**
|
|
@@ -7833,9 +8027,6 @@ const pageScrollFraction = .75;
|
|
|
7833
8027
|
/** Cap composer growth; past this the textarea scrolls its content instead. */
|
|
7834
8028
|
const maxComposerRows = 8;
|
|
7835
8029
|
const maxAttachments = 10;
|
|
7836
|
-
function isNewConversation(c) {
|
|
7837
|
-
return "kind" in c && c.kind === "new";
|
|
7838
|
-
}
|
|
7839
8030
|
/**
|
|
7840
8031
|
* A server timestamp as local epoch ms, or null when it is missing or
|
|
7841
8032
|
* unparseable so the caller can fall back to its own clock.
|
|
@@ -7888,6 +8079,7 @@ function ChatScreen({ agent, conversation }) {
|
|
|
7888
8079
|
const isShared = portal.status !== "off";
|
|
7889
8080
|
const initialConversationId = isNewConversation(conversation) ? null : conversation.id;
|
|
7890
8081
|
const agentHost = useAgentHost();
|
|
8082
|
+
const nonWebChannel = nonWebChannelLabel(conversation);
|
|
7891
8083
|
const [conversationId, setConversationId] = useState(initialConversationId);
|
|
7892
8084
|
const [items, setItems] = useState([]);
|
|
7893
8085
|
const [todos, setTodos] = useState(null);
|
|
@@ -7920,6 +8112,8 @@ function ChatScreen({ agent, conversation }) {
|
|
|
7920
8112
|
const [composerRows, setComposerRows] = useState(1);
|
|
7921
8113
|
const [attachments, setAttachments] = useState([]);
|
|
7922
8114
|
const uploadsRef = useRef(/* @__PURE__ */ new Map());
|
|
8115
|
+
const [forking, setForking] = useState(false);
|
|
8116
|
+
const forkingRef = useRef(false);
|
|
7923
8117
|
const [credPrompt, setCredPrompt] = useState(null);
|
|
7924
8118
|
const credPromptOpen = credPrompt !== null;
|
|
7925
8119
|
const [menuDismissed, setMenuDismissed] = useState(false);
|
|
@@ -7958,10 +8152,11 @@ function ChatScreen({ agent, conversation }) {
|
|
|
7958
8152
|
const reviewBelowBoxRef = useRef(null);
|
|
7959
8153
|
const paneDragRef = useRef(null);
|
|
7960
8154
|
const composerBoxHeight = composerRows + 2;
|
|
7961
|
-
const pendingVisible = !grantPrompt && !credPrompt && attachments.length > 0;
|
|
8155
|
+
const pendingVisible = !grantPrompt && !credPrompt && !nonWebChannel && attachments.length > 0;
|
|
7962
8156
|
const pendingRows = pendingVisible ? attachments.length + 2 : 0;
|
|
7963
8157
|
const credPromptHeight = 4 + (credPrompt && (credPrompt.error || credPrompt.submitting) ? 1 : 0);
|
|
7964
|
-
const
|
|
8158
|
+
const nonWebNoticeHeight = 5;
|
|
8159
|
+
const bottomBoxHeight = credPrompt ? credPromptHeight : nonWebChannel ? nonWebNoticeHeight : composerBoxHeight;
|
|
7965
8160
|
const bodyWidth = Math.max(1, width - 2);
|
|
7966
8161
|
const bodyHeight = Math.max(1, height - 3);
|
|
7967
8162
|
const reviewPlacement = filePanePlacement({
|
|
@@ -8608,7 +8803,7 @@ function ChatScreen({ agent, conversation }) {
|
|
|
8608
8803
|
stageAttachment(image);
|
|
8609
8804
|
}, [stageAttachment]);
|
|
8610
8805
|
usePaste((event) => {
|
|
8611
|
-
if (modelPickerOpen || themePickerOpen || helpOpen || credPromptOpen || grantPrompt) return;
|
|
8806
|
+
if (modelPickerOpen || themePickerOpen || helpOpen || credPromptOpen || grantPrompt || nonWebChannel) return;
|
|
8612
8807
|
const text = event.metadata?.kind === "binary" ? "" : decodePasteBytes(event.bytes);
|
|
8613
8808
|
const route = routePaste({
|
|
8614
8809
|
kind: event.metadata?.kind,
|
|
@@ -8694,6 +8889,39 @@ function ChatScreen({ agent, conversation }) {
|
|
|
8694
8889
|
text: `couldn't open a browser — visit ${url} (${errorMessage(err)})`
|
|
8695
8890
|
}]));
|
|
8696
8891
|
}, [appUrl, conversationId]);
|
|
8892
|
+
const forkAndContinue = useCallback(() => {
|
|
8893
|
+
if (!rest || !conversationId || forkingRef.current) return;
|
|
8894
|
+
forkingRef.current = true;
|
|
8895
|
+
setForking(true);
|
|
8896
|
+
const stillHere = () => {
|
|
8897
|
+
const screen = useStore.getState().screen;
|
|
8898
|
+
return screen.kind === "chat" && !isNewConversation(screen.conversation) && screen.conversation.id === conversationId;
|
|
8899
|
+
};
|
|
8900
|
+
rest.forkConversation({ conversationId }).then((forked) => {
|
|
8901
|
+
if (!stillHere()) return;
|
|
8902
|
+
goTo({
|
|
8903
|
+
kind: "chat",
|
|
8904
|
+
agent,
|
|
8905
|
+
conversation: forkedConversationRef({
|
|
8906
|
+
agent,
|
|
8907
|
+
forked
|
|
8908
|
+
})
|
|
8909
|
+
});
|
|
8910
|
+
}).catch((err) => {
|
|
8911
|
+
forkingRef.current = false;
|
|
8912
|
+
setForking(false);
|
|
8913
|
+
if (!stillHere()) return;
|
|
8914
|
+
useStore.getState().showToast({
|
|
8915
|
+
variant: "error",
|
|
8916
|
+
message: `couldn't fork this conversation: ${errorMessage(err)}`
|
|
8917
|
+
});
|
|
8918
|
+
});
|
|
8919
|
+
}, [
|
|
8920
|
+
rest,
|
|
8921
|
+
conversationId,
|
|
8922
|
+
agent,
|
|
8923
|
+
goTo
|
|
8924
|
+
]);
|
|
8697
8925
|
const toggleShare = useCallback(() => {
|
|
8698
8926
|
if (!portalClient) return;
|
|
8699
8927
|
if (portal.status === "off") {
|
|
@@ -8989,11 +9217,17 @@ function ChatScreen({ agent, conversation }) {
|
|
|
8989
9217
|
toggleShare();
|
|
8990
9218
|
return;
|
|
8991
9219
|
}
|
|
9220
|
+
if (nonWebChannel && key.name === "f" && key.ctrl) {
|
|
9221
|
+
forkAndContinue();
|
|
9222
|
+
return;
|
|
9223
|
+
}
|
|
8992
9224
|
if (key.name === "v" && key.ctrl) {
|
|
9225
|
+
if (nonWebChannel) return;
|
|
8993
9226
|
pasteImage();
|
|
8994
9227
|
return;
|
|
8995
9228
|
}
|
|
8996
9229
|
if (key.name === "x" && key.ctrl || key.name === "backspace" && attachmentsRef.current.length > 0 && !composerRef.current?.plainText) {
|
|
9230
|
+
if (nonWebChannel) return;
|
|
8997
9231
|
const last = attachmentsRef.current.at(-1);
|
|
8998
9232
|
if (last) {
|
|
8999
9233
|
uploadsRef.current.delete(last.tempId);
|
|
@@ -9058,13 +9292,15 @@ function ChatScreen({ agent, conversation }) {
|
|
|
9058
9292
|
ctrlCArmed,
|
|
9059
9293
|
isShared,
|
|
9060
9294
|
hasPendingSteer,
|
|
9061
|
-
hasActionableCard
|
|
9295
|
+
hasActionableCard,
|
|
9296
|
+
nonWebChannel: nonWebChannel !== null
|
|
9062
9297
|
}), [
|
|
9063
9298
|
run.kind,
|
|
9064
9299
|
ctrlCArmed,
|
|
9065
9300
|
isShared,
|
|
9066
9301
|
hasPendingSteer,
|
|
9067
|
-
hasActionableCard
|
|
9302
|
+
hasActionableCard,
|
|
9303
|
+
nonWebChannel
|
|
9068
9304
|
]);
|
|
9069
9305
|
const modelHint = formatModelHint(model);
|
|
9070
9306
|
if (modelPickerOpen) return /* @__PURE__ */ jsx(ModelPicker, {
|
|
@@ -9293,6 +9529,35 @@ function ChatScreen({ agent, conversation }) {
|
|
|
9293
9529
|
children: "n"
|
|
9294
9530
|
})
|
|
9295
9531
|
]
|
|
9532
|
+
}) : nonWebChannel ? /* @__PURE__ */ jsxs("box", {
|
|
9533
|
+
style: {
|
|
9534
|
+
border: true,
|
|
9535
|
+
borderColor: theme.faint,
|
|
9536
|
+
paddingLeft: 1,
|
|
9537
|
+
paddingRight: 1,
|
|
9538
|
+
height: nonWebNoticeHeight,
|
|
9539
|
+
flexShrink: 0,
|
|
9540
|
+
marginTop: 1,
|
|
9541
|
+
flexDirection: "column"
|
|
9542
|
+
},
|
|
9543
|
+
children: [
|
|
9544
|
+
/* @__PURE__ */ jsxs("text", {
|
|
9545
|
+
fg: theme.muted,
|
|
9546
|
+
children: [
|
|
9547
|
+
"this conversation is on ",
|
|
9548
|
+
nonWebChannel,
|
|
9549
|
+
"."
|
|
9550
|
+
]
|
|
9551
|
+
}),
|
|
9552
|
+
/* @__PURE__ */ jsx("text", {
|
|
9553
|
+
fg: theme.dim,
|
|
9554
|
+
children: "reply there to continue it."
|
|
9555
|
+
}),
|
|
9556
|
+
/* @__PURE__ */ jsx("text", {
|
|
9557
|
+
fg: theme.dim,
|
|
9558
|
+
children: forking ? "forking into a new chat…" : "ctrl+f fork it into a chat you can continue here."
|
|
9559
|
+
})
|
|
9560
|
+
]
|
|
9296
9561
|
}) : /* @__PURE__ */ jsx("box", {
|
|
9297
9562
|
style: {
|
|
9298
9563
|
border: true,
|
|
@@ -987,4 +987,147 @@ function applyTheme(def) {
|
|
|
987
987
|
}
|
|
988
988
|
|
|
989
989
|
//#endregion
|
|
990
|
-
|
|
990
|
+
//#region src/brand.ts
|
|
991
|
+
const MARK_CELLS = [
|
|
992
|
+
[
|
|
993
|
+
" ",
|
|
994
|
+
" ",
|
|
995
|
+
["▆", "#517a9d"],
|
|
996
|
+
["█", "#6192bb"],
|
|
997
|
+
["█", "#6191ba"],
|
|
998
|
+
["▌", "#4d7494"],
|
|
999
|
+
["▆", "#90572e"],
|
|
1000
|
+
["█", "#e18948"],
|
|
1001
|
+
["█", "#df8747"],
|
|
1002
|
+
["▅", "#bd733c"],
|
|
1003
|
+
" ",
|
|
1004
|
+
" "
|
|
1005
|
+
],
|
|
1006
|
+
[
|
|
1007
|
+
" ",
|
|
1008
|
+
["▂", "#cb5556"],
|
|
1009
|
+
["▝", "#6699c4"],
|
|
1010
|
+
["█", "#446683"],
|
|
1011
|
+
["█", "#527c9f"],
|
|
1012
|
+
["▘", "#436582"],
|
|
1013
|
+
["▝", "#ba713b"],
|
|
1014
|
+
["█", "#be733c"],
|
|
1015
|
+
["█", "#9c5e31"],
|
|
1016
|
+
["▚", "#9d6345"],
|
|
1017
|
+
["▂", "#c1859b"],
|
|
1018
|
+
" "
|
|
1019
|
+
],
|
|
1020
|
+
[
|
|
1021
|
+
["█", "#c05152"],
|
|
1022
|
+
["█", "#e15f60"],
|
|
1023
|
+
["█", "#d65a5b"],
|
|
1024
|
+
["▅", "#a24445"],
|
|
1025
|
+
" ",
|
|
1026
|
+
" ",
|
|
1027
|
+
" ",
|
|
1028
|
+
" ",
|
|
1029
|
+
["▅", "#b17a8e"],
|
|
1030
|
+
["█", "#d895ad"],
|
|
1031
|
+
["█", "#df9ab3"],
|
|
1032
|
+
["▉", "#c3869c"]
|
|
1033
|
+
],
|
|
1034
|
+
[
|
|
1035
|
+
["▝", "#d25859"],
|
|
1036
|
+
["█", "#953f3f"],
|
|
1037
|
+
["▘", "#df5e5f"],
|
|
1038
|
+
["▂", "#4d8d6f"],
|
|
1039
|
+
["▃", "#539877"],
|
|
1040
|
+
" ",
|
|
1041
|
+
" ",
|
|
1042
|
+
["▃", "#e5aa47"],
|
|
1043
|
+
["▂", "#d29d41"],
|
|
1044
|
+
["█", "#7f585e"],
|
|
1045
|
+
["█", "#916475"],
|
|
1046
|
+
["▘", "#c6899f"]
|
|
1047
|
+
],
|
|
1048
|
+
[
|
|
1049
|
+
" ",
|
|
1050
|
+
" ",
|
|
1051
|
+
["█", "#4e8f70"],
|
|
1052
|
+
["█", "#569d7b"],
|
|
1053
|
+
["█", "#569d7b"],
|
|
1054
|
+
["▌", "#4a876a"],
|
|
1055
|
+
["▆", "#8f6a2c"],
|
|
1056
|
+
["█", "#efb24a"],
|
|
1057
|
+
["█", "#efb24a"],
|
|
1058
|
+
["▉", "#e2a845"],
|
|
1059
|
+
" ",
|
|
1060
|
+
" "
|
|
1061
|
+
],
|
|
1062
|
+
[
|
|
1063
|
+
" ",
|
|
1064
|
+
" ",
|
|
1065
|
+
" ",
|
|
1066
|
+
["▝", "#488467"],
|
|
1067
|
+
["▘", "#488367"],
|
|
1068
|
+
" ",
|
|
1069
|
+
" ",
|
|
1070
|
+
["▝", "#ca963e"],
|
|
1071
|
+
["▘", "#c8953d"],
|
|
1072
|
+
" ",
|
|
1073
|
+
" ",
|
|
1074
|
+
" "
|
|
1075
|
+
]
|
|
1076
|
+
];
|
|
1077
|
+
const MARK_WIDTH = 12;
|
|
1078
|
+
/** Accent hex used for the compact one-liner star (matches the blue petal). */
|
|
1079
|
+
const BRAND_ACCENT = "#5b8fc7";
|
|
1080
|
+
/** "Skydive" in an ANSI-shadow block font. */
|
|
1081
|
+
const WORDMARK = [
|
|
1082
|
+
"███████╗██╗ ██╗██╗ ██╗██████╗ ██╗██╗ ██╗███████╗",
|
|
1083
|
+
"██╔════╝██║ ██╔╝╚██╗ ██╔╝██╔══██╗██║██║ ██║██╔════╝",
|
|
1084
|
+
"███████╗█████╔╝ ╚████╔╝ ██║ ██║██║██║ ██║█████╗ ",
|
|
1085
|
+
"╚════██║██╔═██╗ ╚██╔╝ ██║ ██║██║╚██╗ ██╔╝██╔══╝ ",
|
|
1086
|
+
"███████║██║ ██╗ ██║ ██████╔╝██║ ╚████╔╝ ███████╗",
|
|
1087
|
+
"╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚══════╝"
|
|
1088
|
+
];
|
|
1089
|
+
const RESET = "\x1B[0m";
|
|
1090
|
+
function hexToRgb(hex) {
|
|
1091
|
+
const n = Number.parseInt(hex.slice(1), 16);
|
|
1092
|
+
return [
|
|
1093
|
+
n >> 16 & 255,
|
|
1094
|
+
n >> 8 & 255,
|
|
1095
|
+
n & 255
|
|
1096
|
+
];
|
|
1097
|
+
}
|
|
1098
|
+
function sgr(text, hex) {
|
|
1099
|
+
const [r, g, b] = hexToRgb(hex);
|
|
1100
|
+
return `\x1b[38;2;${r};${g};${b}m${text}${RESET}`;
|
|
1101
|
+
}
|
|
1102
|
+
function markLinesAnsi() {
|
|
1103
|
+
return MARK_CELLS.map((row) => row.map((cell) => cell === " " ? " " : sgr(cell[0], cell[1])).join(""));
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* Build the splash for the `skydive --help` screen as a string, gated on the
|
|
1107
|
+
* terminal's capabilities. Returns '' when it should be suppressed (non-TTY
|
|
1108
|
+
* target such as a pipe or CI). The wordmark is left uncolored (terminal default
|
|
1109
|
+
* fg = neutral on both light and dark); only the mark uses brand petal hexes.
|
|
1110
|
+
* A narrow terminal collapses to a one-liner.
|
|
1111
|
+
*/
|
|
1112
|
+
function brandHelpArt(stream = process.stdout) {
|
|
1113
|
+
if (!stream.isTTY) return "";
|
|
1114
|
+
const truecolor = (typeof stream.getColorDepth === "function" ? stream.getColorDepth() : 1) >= 24;
|
|
1115
|
+
if ((stream.columns ?? 80) < 66) return truecolor ? `\n ${sgr("✦", BRAND_ACCENT)} Skydive\n` : "\n ✦ Skydive\n";
|
|
1116
|
+
if (!truecolor) return `\n${WORDMARK.map((l) => ` ${l}`).join("\n")}\n`;
|
|
1117
|
+
const mark = markLinesAnsi();
|
|
1118
|
+
const word = [...WORDMARK];
|
|
1119
|
+
const height = Math.max(mark.length, word.length);
|
|
1120
|
+
const topPad = Math.max(0, Math.floor((word.length - mark.length) / 2));
|
|
1121
|
+
const blank = " ".repeat(MARK_WIDTH);
|
|
1122
|
+
const lines = [];
|
|
1123
|
+
for (let i = 0; i < height; i++) {
|
|
1124
|
+
const mi = i - topPad;
|
|
1125
|
+
const m = mi >= 0 && mi < mark.length ? mark[mi] : blank;
|
|
1126
|
+
const w = i < word.length ? word[i] : "";
|
|
1127
|
+
lines.push(` ${m} ${w}`);
|
|
1128
|
+
}
|
|
1129
|
+
return `\n${lines.join("\n")}\n`;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
//#endregion
|
|
1133
|
+
export { getPromptHistoryPath as A, resolveSession as B, API_KEY_PREFIX as C, deleteConfig as D, DEFAULT_WEB_URL as E, getStoredApiKeyWorkspaceName as F, setLastSeenVersion as G, saveConfig as H, getUpdateCheckDisabled as I, resolveAppUrl as L, getSavedTheme as M, getShareMachineDefault as N, getConfigPath as O, getStoredApiKeyId as P, resolveConfig as R, API_KEY_FAMILY_PREFIX as S, DEFAULT_APP_URL as T, saveSession as U, resolveWebUrl as V, saveTheme as W, getActiveWorkspaceId as _, applyTheme as a, setActiveWorkspace as b, noColorRequested as c, themeMode as d, themeModeFromColorFgBg as f, ensureActiveOrganization as g, themesForMode as h, DEFAULT_THEME_ID as i, getReviewStateDir as j, getLastSeenVersion as k, theme as l, themes as m, WORDMARK as n, findTheme as o, themeVersion as p, brandHelpArt as r, monoTheme as s, MARK_CELLS as t, themeForMode as u, getSessionIdentity as v, DEFAULT_API_URL as w, API_KEYS_URL as x, listWorkspaces as y, resolveManagementAuth as z };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
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-
|
|
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-BHq-5eW_.mjs";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
6
|
import { WebSocket } from "ws";
|
|
@@ -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-DZnAT7BG.mjs";
|
|
3
|
+
import { a as runPrint, i as resolveAgent, n as messageGet, o as toPrintError, r as readStdin, t as collectRunText } from "./print-XvAHDKqu.mjs";
|
|
4
4
|
|
|
5
5
|
export { messageGet, readStdin, resolveAgent, runPrint };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as createRestClient, t as HttpError } from "./rest-
|
|
2
|
+
import { n as createRestClient, t as HttpError } from "./rest-DZnAT7BG.mjs";
|
|
3
3
|
import { n as isRecord, t as errorMessage } from "./util-CeisaZVY.mjs";
|
|
4
4
|
import stableStringify from "safe-stable-stringify";
|
|
5
5
|
|
|
@@ -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-CRAGDqp0.mjs");
|
|
18
18
|
let signalConnected;
|
|
19
19
|
const connected = new Promise((resolve) => {
|
|
20
20
|
signalConnected = resolve;
|
|
@@ -223,6 +223,10 @@ function createRestClient({ appUrl, sessionToken }) {
|
|
|
223
223
|
sizeBytes: finalized.sizeBytes ?? size
|
|
224
224
|
};
|
|
225
225
|
},
|
|
226
|
+
forkConversation: async ({ conversationId }) => {
|
|
227
|
+
const { conversation } = await post(`/api/v1/conversations/${encodeURIComponent(conversationId)}/fork`, {}, forkConversationResponseSchema);
|
|
228
|
+
return conversation;
|
|
229
|
+
},
|
|
226
230
|
deleteConversation: async ({ conversationId }) => {
|
|
227
231
|
await del(`/api/v1/conversations/${encodeURIComponent(conversationId)}`);
|
|
228
232
|
},
|
|
@@ -347,6 +351,12 @@ const listAgentsResponseSchema = z.object({
|
|
|
347
351
|
totalCount: z.number().nullable().optional()
|
|
348
352
|
});
|
|
349
353
|
const createAgentResponseSchema = z.object({ agent: agentSummarySchema });
|
|
354
|
+
const conversationAgentSchema = z.object({
|
|
355
|
+
id: z.string().uuid(),
|
|
356
|
+
name: z.string(),
|
|
357
|
+
slug: z.string().nullable().optional(),
|
|
358
|
+
title: z.string().nullable().optional()
|
|
359
|
+
});
|
|
350
360
|
const conversationSummarySchema = z.object({
|
|
351
361
|
id: z.string().uuid(),
|
|
352
362
|
title: z.string().nullable(),
|
|
@@ -356,20 +366,23 @@ const conversationSummarySchema = z.object({
|
|
|
356
366
|
channel: z.string().nullable(),
|
|
357
367
|
channelLabel: z.string().nullable(),
|
|
358
368
|
viewerArchivedAt: z.string().nullable().optional(),
|
|
359
|
-
agent:
|
|
360
|
-
|
|
361
|
-
name: z.string(),
|
|
362
|
-
slug: z.string().nullable().optional(),
|
|
363
|
-
title: z.string().nullable().optional()
|
|
364
|
-
})
|
|
369
|
+
agent: conversationAgentSchema,
|
|
370
|
+
agents: z.array(conversationAgentSchema).optional()
|
|
365
371
|
});
|
|
366
372
|
const conversationDetailSchema = z.object({
|
|
367
373
|
id: z.string().uuid(),
|
|
368
374
|
title: z.string().nullable(),
|
|
369
375
|
agentId: z.string().uuid(),
|
|
370
376
|
createdAt: z.string(),
|
|
371
|
-
updatedAt: z.string()
|
|
377
|
+
updatedAt: z.string(),
|
|
378
|
+
channel: z.string().nullable(),
|
|
379
|
+
channelLabel: z.string().nullable()
|
|
380
|
+
});
|
|
381
|
+
const conversationTitleSchema = z.object({
|
|
382
|
+
id: z.string().uuid(),
|
|
383
|
+
title: z.string().nullable()
|
|
372
384
|
});
|
|
385
|
+
const forkConversationResponseSchema = z.object({ conversation: conversationTitleSchema });
|
|
373
386
|
const getConversationResponseSchema = z.object({ conversation: conversationDetailSchema });
|
|
374
387
|
const listConversationsResponseSchema = z.object({
|
|
375
388
|
conversations: z.array(conversationSummarySchema),
|
package/package.json
CHANGED