skydive-cli 0.2.0-beta.427 → 0.2.0-beta.457
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/bin.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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
4
|
import { n as createRestClient } from "./rest-BBQrPIwq.mjs";
|
|
5
5
|
import { i as resolveAgent } from "./print-YqNIRwdf.mjs";
|
|
@@ -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.457";
|
|
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-D_H3xGxt.mjs");
|
|
1204
1204
|
await runChat({
|
|
1205
1205
|
appUrl,
|
|
1206
1206
|
sessionToken: session.value.sessionToken,
|
|
@@ -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-D_H3xGxt.mjs");
|
|
1515
1515
|
await runChat({
|
|
1516
1516
|
appUrl,
|
|
1517
1517
|
sessionToken: session.value.sessionToken,
|
|
@@ -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-D_H3xGxt.mjs");
|
|
1814
1814
|
await runWorkspacePicker(session);
|
|
1815
1815
|
return;
|
|
1816
1816
|
}
|
|
@@ -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,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
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
3
|
import { n as createRestClient, r as errorDetail, t as HttpError } from "./rest-BBQrPIwq.mjs";
|
|
4
4
|
import { n as isRecord, t as errorMessage } from "./util-CeisaZVY.mjs";
|
|
5
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-YqNIRwdf.mjs";
|
|
@@ -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",
|
|
@@ -1624,13 +1714,26 @@ function ConversationPickerScreen({ agent }) {
|
|
|
1624
1714
|
cacheKey,
|
|
1625
1715
|
cache
|
|
1626
1716
|
]);
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1717
|
+
const { height } = useTerminalDimensions();
|
|
1718
|
+
if (state.kind === "loading") return /* @__PURE__ */ jsxs("box", {
|
|
1719
|
+
style: {
|
|
1720
|
+
flexDirection: "column",
|
|
1721
|
+
flexGrow: 1
|
|
1722
|
+
},
|
|
1723
|
+
children: [/* @__PURE__ */ jsx(BrandHeader, { height }), /* @__PURE__ */ jsx("text", {
|
|
1724
|
+
fg: theme.muted,
|
|
1725
|
+
children: "loading conversations…"
|
|
1726
|
+
})]
|
|
1630
1727
|
});
|
|
1631
|
-
if (state.kind === "error") return /* @__PURE__ */ jsxs("
|
|
1632
|
-
|
|
1633
|
-
|
|
1728
|
+
if (state.kind === "error") return /* @__PURE__ */ jsxs("box", {
|
|
1729
|
+
style: {
|
|
1730
|
+
flexDirection: "column",
|
|
1731
|
+
flexGrow: 1
|
|
1732
|
+
},
|
|
1733
|
+
children: [/* @__PURE__ */ jsx(BrandHeader, { height }), /* @__PURE__ */ jsxs("text", {
|
|
1734
|
+
fg: theme.error,
|
|
1735
|
+
children: ["error: ", state.message]
|
|
1736
|
+
})]
|
|
1634
1737
|
});
|
|
1635
1738
|
return /* @__PURE__ */ jsx(ConversationList, {
|
|
1636
1739
|
agent,
|
|
@@ -1687,7 +1790,7 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
|
|
|
1687
1790
|
"↵ open"
|
|
1688
1791
|
], innerWidth)
|
|
1689
1792
|
};
|
|
1690
|
-
const visibleRows = Math.max(3, height - 6);
|
|
1793
|
+
const visibleRows = Math.max(3, height - 6 - brandHeaderRows(height));
|
|
1691
1794
|
const start = windowStart(clamped, rows.length, visibleRows);
|
|
1692
1795
|
const windowed = rows.slice(start, start + visibleRows);
|
|
1693
1796
|
const open = (row) => {
|
|
@@ -1786,6 +1889,7 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
|
|
|
1786
1889
|
flexGrow: 1
|
|
1787
1890
|
},
|
|
1788
1891
|
children: [
|
|
1892
|
+
/* @__PURE__ */ jsx(BrandHeader, { height }),
|
|
1789
1893
|
/* @__PURE__ */ jsxs("box", {
|
|
1790
1894
|
style: {
|
|
1791
1895
|
flexDirection: "row",
|
|
@@ -4357,6 +4461,10 @@ const keybindGroups = [
|
|
|
4357
4461
|
keys: "1 / 2",
|
|
4358
4462
|
action: "switch Changes / Files"
|
|
4359
4463
|
},
|
|
4464
|
+
{
|
|
4465
|
+
keys: "\\",
|
|
4466
|
+
action: "toggle side / stacked layout"
|
|
4467
|
+
},
|
|
4360
4468
|
{
|
|
4361
4469
|
keys: "↵ / o / l",
|
|
4362
4470
|
action: "focus selected file preview"
|
|
@@ -6747,7 +6855,7 @@ function gcOnce() {
|
|
|
6747
6855
|
gcStarted = true;
|
|
6748
6856
|
store.gc();
|
|
6749
6857
|
}
|
|
6750
|
-
function ReviewPane({ agentId, conversationId, items, viewportWidth, viewportHeight, active, shellLayout, tab, onTabChange, selectedChangeFile, onSelectedChangeFileChange, selectedWorkspaceFile, onSelectedWorkspaceFileChange, navigatorSize, onNavigatorResize, onInsertToComposer, onRequestChatFocus, onClose }) {
|
|
6858
|
+
function ReviewPane({ agentId, conversationId, items, viewportWidth, viewportHeight, active, shellLayout, tab, onTabChange, selectedChangeFile, onSelectedChangeFileChange, selectedWorkspaceFile, onSelectedWorkspaceFileChange, navigatorSize, onNavigatorResize, onToggleOrientation, onInsertToComposer, onRequestChatFocus, onClose }) {
|
|
6751
6859
|
const width = viewportWidth;
|
|
6752
6860
|
const height = viewportHeight;
|
|
6753
6861
|
const shellHeight = Math.max(6, height - 2);
|
|
@@ -6898,6 +7006,10 @@ function ReviewPane({ agentId, conversationId, items, viewportWidth, viewportHei
|
|
|
6898
7006
|
onTabChange("files");
|
|
6899
7007
|
return;
|
|
6900
7008
|
}
|
|
7009
|
+
if (key.name === "\\") {
|
|
7010
|
+
if (onToggleOrientation() === "unavailable") setStatus("no room to change layout in this terminal");
|
|
7011
|
+
return;
|
|
7012
|
+
}
|
|
6901
7013
|
if (key.name === "s") {
|
|
6902
7014
|
if (comments.length === 0) {
|
|
6903
7015
|
setStatus("no pending comments");
|
|
@@ -7288,18 +7400,93 @@ function PaneRowView({ row, width, isCursor, inSelection, isAnchor, isCommented
|
|
|
7288
7400
|
//#endregion
|
|
7289
7401
|
//#region src/chat/tui/file-pane-layout.ts
|
|
7290
7402
|
/**
|
|
7403
|
+
* Terminal cells are about twice as tall as they are wide, so a raw
|
|
7404
|
+
* cols-vs-rows compare would call almost any terminal "wide". Scale rows by
|
|
7405
|
+
* this factor to compare the *visual* aspect: a square-looking terminal has
|
|
7406
|
+
* `width ≈ height * CELL_ASPECT`.
|
|
7407
|
+
*/
|
|
7408
|
+
const CELL_ASPECT = 2;
|
|
7409
|
+
/**
|
|
7410
|
+
* The automatic split follows the terminal's visual aspect: wider than tall
|
|
7411
|
+
* places review beside the chat (a vertical divider), taller than wide stacks
|
|
7412
|
+
* it underneath (a horizontal divider). This is the responsive default when
|
|
7413
|
+
* the user hasn't pinned an orientation.
|
|
7414
|
+
*/
|
|
7415
|
+
function autoPrefersSide({ width, height }) {
|
|
7416
|
+
return width >= height * CELL_ASPECT;
|
|
7417
|
+
}
|
|
7418
|
+
/**
|
|
7419
|
+
* Bare-minimum room to render a split at all (as opposed to the higher
|
|
7420
|
+
* comfort thresholds the automatic choice uses). A user pin is honored down
|
|
7421
|
+
* to these: chat + review each need a usable strip, but we don't insist on
|
|
7422
|
+
* the roomier auto breakpoints. Mirrors the clamps in clampSidePaneWidth /
|
|
7423
|
+
* clampBelowPaneHeight so a pinned split never renders narrower than those.
|
|
7424
|
+
*/
|
|
7425
|
+
function canRenderSide({ width, height }) {
|
|
7426
|
+
return width >= 76 && height >= 8;
|
|
7427
|
+
}
|
|
7428
|
+
function canRenderBelow({ width, height }) {
|
|
7429
|
+
return height >= 24 && width >= 24;
|
|
7430
|
+
}
|
|
7431
|
+
/**
|
|
7291
7432
|
* Responsive placement for the file pane.
|
|
7292
7433
|
*
|
|
7293
|
-
*
|
|
7294
|
-
*
|
|
7295
|
-
*
|
|
7296
|
-
*
|
|
7434
|
+
* With no user pin the split follows the terminal's visual aspect (see
|
|
7435
|
+
* autoPrefersSide): wider than tall -> side, taller than wide -> stacked.
|
|
7436
|
+
* The preferred split still has to be renderable; if it isn't we use the
|
|
7437
|
+
* other, and cramped terminals that can render neither get the full body.
|
|
7438
|
+
*
|
|
7439
|
+
* A user `orientation` pin always wins as long as the terminal can render
|
|
7440
|
+
* that split at all (the lower canRender* bar) — so you get the layout you
|
|
7441
|
+
* asked for even on a smallish terminal. Only when the pinned split
|
|
7442
|
+
* genuinely can't fit do we fall back: to the other split if it can render,
|
|
7443
|
+
* else to `fullscreen`.
|
|
7297
7444
|
*/
|
|
7298
|
-
function filePanePlacement({ width, height }) {
|
|
7299
|
-
|
|
7300
|
-
|
|
7445
|
+
function filePanePlacement({ width, height, orientation }) {
|
|
7446
|
+
const renderSide = canRenderSide({
|
|
7447
|
+
width,
|
|
7448
|
+
height
|
|
7449
|
+
});
|
|
7450
|
+
const renderBelow = canRenderBelow({
|
|
7451
|
+
width,
|
|
7452
|
+
height
|
|
7453
|
+
});
|
|
7454
|
+
if (orientation === "side") {
|
|
7455
|
+
if (renderSide) return "side";
|
|
7456
|
+
if (renderBelow) return "below";
|
|
7457
|
+
return "fullscreen";
|
|
7458
|
+
}
|
|
7459
|
+
if (orientation === "below") {
|
|
7460
|
+
if (renderBelow) return "below";
|
|
7461
|
+
if (renderSide) return "side";
|
|
7462
|
+
return "fullscreen";
|
|
7463
|
+
}
|
|
7464
|
+
if (autoPrefersSide({
|
|
7465
|
+
width,
|
|
7466
|
+
height
|
|
7467
|
+
})) {
|
|
7468
|
+
if (renderSide) return "side";
|
|
7469
|
+
if (renderBelow) return "below";
|
|
7470
|
+
return "fullscreen";
|
|
7471
|
+
}
|
|
7472
|
+
if (renderBelow) return "below";
|
|
7473
|
+
if (renderSide) return "side";
|
|
7301
7474
|
return "fullscreen";
|
|
7302
7475
|
}
|
|
7476
|
+
/**
|
|
7477
|
+
* Whether toggling the orientation would actually change anything: both
|
|
7478
|
+
* splits must be renderable. When only one (or neither) can render, the
|
|
7479
|
+
* caller surfaces a hint instead of a silent no-op.
|
|
7480
|
+
*/
|
|
7481
|
+
function canToggleOrientation({ width, height }) {
|
|
7482
|
+
return canRenderSide({
|
|
7483
|
+
width,
|
|
7484
|
+
height
|
|
7485
|
+
}) && canRenderBelow({
|
|
7486
|
+
width,
|
|
7487
|
+
height
|
|
7488
|
+
});
|
|
7489
|
+
}
|
|
7303
7490
|
/** Keep a dragged side pane wide enough to use and leave the chat usable. */
|
|
7304
7491
|
function clampSidePaneWidth(width, bodyWidth) {
|
|
7305
7492
|
return Math.max(44, Math.min(bodyWidth - 30, width));
|
|
@@ -7827,6 +8014,7 @@ function ChatScreen({ agent, conversation }) {
|
|
|
7827
8014
|
side: null,
|
|
7828
8015
|
stacked: null
|
|
7829
8016
|
});
|
|
8017
|
+
const [reviewOrientation, setReviewOrientation] = useState(null);
|
|
7830
8018
|
const [reviewWorkspaceFile, setReviewWorkspaceFile] = useState(null);
|
|
7831
8019
|
useEffect(() => {
|
|
7832
8020
|
setReviewChangeFile(null);
|
|
@@ -7882,7 +8070,8 @@ function ChatScreen({ agent, conversation }) {
|
|
|
7882
8070
|
const bodyHeight = Math.max(1, height - 3);
|
|
7883
8071
|
const reviewPlacement = filePanePlacement({
|
|
7884
8072
|
width,
|
|
7885
|
-
height
|
|
8073
|
+
height,
|
|
8074
|
+
orientation: reviewOrientation
|
|
7886
8075
|
});
|
|
7887
8076
|
const reviewWidth = reviewPlacement === "side" ? clampSidePaneWidth(reviewSizePref.side ?? sidePaneWidth(bodyWidth), bodyWidth) : bodyWidth;
|
|
7888
8077
|
const reviewHeight = reviewPlacement === "below" ? clampBelowPaneHeight(reviewSizePref.below ?? belowPaneHeight(bodyHeight), bodyHeight) : bodyHeight;
|
|
@@ -7925,6 +8114,7 @@ function ChatScreen({ agent, conversation }) {
|
|
|
7925
8114
|
helpOpen,
|
|
7926
8115
|
reviewOpen,
|
|
7927
8116
|
reviewFocused,
|
|
8117
|
+
reviewPlacement,
|
|
7928
8118
|
credPromptOpen
|
|
7929
8119
|
]);
|
|
7930
8120
|
useEffect(() => {
|
|
@@ -9019,6 +9209,14 @@ function ChatScreen({ agent, conversation }) {
|
|
|
9019
9209
|
...prev,
|
|
9020
9210
|
side: size
|
|
9021
9211
|
}),
|
|
9212
|
+
onToggleOrientation: () => {
|
|
9213
|
+
if (!canToggleOrientation({
|
|
9214
|
+
width,
|
|
9215
|
+
height
|
|
9216
|
+
})) return "unavailable";
|
|
9217
|
+
setReviewOrientation(reviewPlacement === "below" ? "side" : "below");
|
|
9218
|
+
return "toggled";
|
|
9219
|
+
},
|
|
9022
9220
|
onInsertToComposer: (review) => {
|
|
9023
9221
|
const next = [inputRef.current.trimEnd(), review].filter((part) => part.length > 0).join("\n\n");
|
|
9024
9222
|
setInput(next);
|
|
@@ -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 };
|