@opengeni/react 0.6.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -6
- package/dist/{chunk-DEW2ZNF2.js → chunk-5C7RGAWA.js} +70 -37
- package/dist/chunk-5C7RGAWA.js.map +1 -0
- package/dist/index.d.ts +45 -9
- package/dist/index.js +1385 -732
- package/dist/index.js.map +1 -1
- package/dist/{machines-BD6h9P_s.d.ts → machines-BeZ3bD3t.d.ts} +2 -2
- package/dist/machines.d.ts +1 -1
- package/dist/machines.js +1 -1
- package/package.json +2 -2
- package/src/client.ts +1 -0
- package/src/components/chat-composer.tsx +127 -60
- package/src/components/code-editor.tsx +15 -15
- package/src/components/desktop-viewer.tsx +40 -36
- package/src/components/diff-view.tsx +22 -22
- package/src/components/enrollment-consent.tsx +13 -13
- package/src/components/file-browser.tsx +74 -67
- package/src/components/fleet-tile.tsx +3 -3
- package/src/components/machine-card.tsx +6 -6
- package/src/components/machine-status-pill.tsx +3 -3
- package/src/components/machines-dashboard.tsx +28 -14
- package/src/components/markdown.tsx +6 -6
- package/src/components/message-timeline.tsx +207 -12
- package/src/components/pierre-diff.tsx +9 -10
- package/src/components/pierre-file.tsx +8 -8
- package/src/components/sandbox-files.tsx +37 -40
- package/src/components/sandbox-terminal.tsx +9 -11
- package/src/components/session-status.tsx +2 -2
- package/src/components/workspace-dock.tsx +153 -49
- package/src/hooks/use-file-attachments.ts +45 -15
- package/src/hooks/use-session-events.ts +283 -8
- package/src/index.ts +2 -2
- package/src/lib/format.ts +32 -0
- package/src/lib/xterm-theme.ts +8 -11
- package/src/timeline/activity-rail.tsx +5 -2
- package/src/timeline/entrance.tsx +30 -0
- package/src/timeline/parsers.ts +104 -0
- package/src/timeline/projection.ts +22 -5
- package/src/timeline/screenshot-lightbox.tsx +1 -1
- package/src/timeline/shared.tsx +4 -1
- package/src/timeline/tool-diff.tsx +1 -1
- package/src/timeline/tool-renderers.tsx +46 -7
- package/src/timeline/turn-summary.tsx +24 -4
- package/styles/tokens.css +8 -0
- package/dist/chunk-DEW2ZNF2.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
connectionStatusForState,
|
|
17
17
|
formatBytes,
|
|
18
18
|
formatRelativeTime,
|
|
19
|
+
humanizeFailureReason,
|
|
19
20
|
stringifyPayload,
|
|
20
21
|
truncate,
|
|
21
22
|
tryParseJson,
|
|
@@ -26,7 +27,7 @@ import {
|
|
|
26
27
|
useOpenGeniClient,
|
|
27
28
|
usePolledValue,
|
|
28
29
|
useSessionEventTrigger
|
|
29
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-5C7RGAWA.js";
|
|
30
31
|
|
|
31
32
|
// src/hooks/use-session.ts
|
|
32
33
|
import { useCallback, useState } from "react";
|
|
@@ -97,7 +98,7 @@ function useSession(sessionId, options = {}) {
|
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
// src/hooks/use-session-events.ts
|
|
100
|
-
import { useEffect as useEffect3, useMemo as useMemo2, useRef, useState as useState8 } from "react";
|
|
101
|
+
import { useCallback as useCallback3, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2, useState as useState8 } from "react";
|
|
101
102
|
|
|
102
103
|
// src/timeline/projection.ts
|
|
103
104
|
var WORKER_SPAWN_TOOL = "session_create";
|
|
@@ -351,7 +352,7 @@ ${message}` : message;
|
|
|
351
352
|
case "turn.failed": {
|
|
352
353
|
const hadActivity = hasTurnActivity(items, turnId);
|
|
353
354
|
const failureText = failureMessage(payload);
|
|
354
|
-
finalizeOpen(turnId, "
|
|
355
|
+
finalizeOpen(turnId, "cancelled");
|
|
355
356
|
items.push(turnEndItem(event, "failed", failureText));
|
|
356
357
|
if (!hadActivity) {
|
|
357
358
|
items.push({
|
|
@@ -593,8 +594,14 @@ function stampTurnOutcome(groups, turnEnd) {
|
|
|
593
594
|
}
|
|
594
595
|
}
|
|
595
596
|
function applyTurnOutcome(group, turnEnd) {
|
|
596
|
-
|
|
597
|
-
|
|
597
|
+
if (turnEnd.outcome === "complete") {
|
|
598
|
+
group.outcome = "complete";
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
const hasFailed = group.items.some((item) => "status" in item && item.status === "failed");
|
|
602
|
+
const hasInterrupted = group.items.some((item) => "status" in item && item.status === "cancelled");
|
|
603
|
+
group.outcome = hasFailed ? "failed" : hasInterrupted ? "cancelled" : "complete";
|
|
604
|
+
if (turnEnd.failureText && hasFailed) {
|
|
598
605
|
group.failureText = turnEnd.failureText;
|
|
599
606
|
}
|
|
600
607
|
}
|
|
@@ -732,7 +739,7 @@ function failureMessage(payload) {
|
|
|
732
739
|
for (const key of ["error", "message"]) {
|
|
733
740
|
const value = payload[key];
|
|
734
741
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
735
|
-
return value;
|
|
742
|
+
return humanizeFailureReason(value);
|
|
736
743
|
}
|
|
737
744
|
}
|
|
738
745
|
return null;
|
|
@@ -1028,6 +1035,88 @@ function unwrapMcpOutput(output) {
|
|
|
1028
1035
|
}
|
|
1029
1036
|
return { text: typeof output === "string" ? output : output == null ? "" : JSON.stringify(output), isError: false };
|
|
1030
1037
|
}
|
|
1038
|
+
function screenshotDataUrl(out) {
|
|
1039
|
+
if (typeof out === "string") {
|
|
1040
|
+
if (out.startsWith("data:image")) {
|
|
1041
|
+
return out;
|
|
1042
|
+
}
|
|
1043
|
+
if (out.startsWith("{") || out.startsWith("[")) {
|
|
1044
|
+
const parsed = tryParseJson(out);
|
|
1045
|
+
if (parsed !== void 0 && parsed !== out) {
|
|
1046
|
+
return screenshotDataUrl(parsed);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
return null;
|
|
1050
|
+
}
|
|
1051
|
+
if (Array.isArray(out)) {
|
|
1052
|
+
for (const entry of out) {
|
|
1053
|
+
const url = screenshotDataUrl(entry);
|
|
1054
|
+
if (url) {
|
|
1055
|
+
return url;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
return null;
|
|
1059
|
+
}
|
|
1060
|
+
if (out === null || typeof out !== "object") {
|
|
1061
|
+
return null;
|
|
1062
|
+
}
|
|
1063
|
+
const record = out;
|
|
1064
|
+
const imageUrl = record.image_url ?? record.imageUrl;
|
|
1065
|
+
if (typeof imageUrl === "string" && imageUrl.startsWith("data:image")) {
|
|
1066
|
+
return imageUrl;
|
|
1067
|
+
}
|
|
1068
|
+
if (imageUrl && typeof imageUrl === "object") {
|
|
1069
|
+
const url = imageUrl.url;
|
|
1070
|
+
if (typeof url === "string" && url.startsWith("data:image")) {
|
|
1071
|
+
return url;
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
const image = record.image;
|
|
1075
|
+
if (image && typeof image === "object") {
|
|
1076
|
+
const mediaType = typeof image.mediaType === "string" ? image.mediaType : "image/png";
|
|
1077
|
+
const base64 = bytesToBase64(image.data);
|
|
1078
|
+
if (base64) {
|
|
1079
|
+
return `data:${mediaType};base64,${base64}`;
|
|
1080
|
+
}
|
|
1081
|
+
if (typeof image.data === "string" && image.data.length > 0) {
|
|
1082
|
+
return `data:${mediaType};base64,${image.data}`;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
return null;
|
|
1086
|
+
}
|
|
1087
|
+
function bytesToBase64(data) {
|
|
1088
|
+
const isByte = (n) => typeof n === "number" && Number.isInteger(n) && n >= 0 && n <= 255;
|
|
1089
|
+
let bytes = null;
|
|
1090
|
+
if (Array.isArray(data) && data.every(isByte)) {
|
|
1091
|
+
bytes = data;
|
|
1092
|
+
} else if (data && typeof data === "object") {
|
|
1093
|
+
const record = data;
|
|
1094
|
+
if (record.type === "Buffer" && Array.isArray(record.data) && record.data.every(isByte)) {
|
|
1095
|
+
bytes = record.data;
|
|
1096
|
+
} else {
|
|
1097
|
+
const keys = Object.keys(record);
|
|
1098
|
+
if (keys.length > 0 && keys.every((key) => /^\d+$/.test(key))) {
|
|
1099
|
+
const values = keys.sort((a, b) => Number(a) - Number(b)).map((key) => record[key]);
|
|
1100
|
+
if (values.every(isByte)) {
|
|
1101
|
+
bytes = values;
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
if (!bytes || bytes.length === 0) {
|
|
1107
|
+
return null;
|
|
1108
|
+
}
|
|
1109
|
+
try {
|
|
1110
|
+
let binary = "";
|
|
1111
|
+
const CHUNK = 32768;
|
|
1112
|
+
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
1113
|
+
binary += String.fromCharCode(...bytes.slice(i, i + CHUNK));
|
|
1114
|
+
}
|
|
1115
|
+
return typeof btoa === "function" ? btoa(binary) : Buffer.from(binary, "binary").toString("base64");
|
|
1116
|
+
} catch {
|
|
1117
|
+
return null;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1031
1120
|
|
|
1032
1121
|
// src/timeline/shared.tsx
|
|
1033
1122
|
import { CameraIcon, CameraOffIcon, ChevronRightIcon } from "lucide-react";
|
|
@@ -1131,7 +1220,7 @@ function LightboxRoot({ children }) {
|
|
|
1131
1220
|
}
|
|
1132
1221
|
)
|
|
1133
1222
|
] }),
|
|
1134
|
-
state.caption ? /* @__PURE__ */ jsx2("figcaption", { className: "max-w-2xl text-center font-og-mono text-og-xs text-white/55", children: state.caption }) : /* @__PURE__ */ jsx2("figcaption", { className: "font-og-mono text-
|
|
1223
|
+
state.caption ? /* @__PURE__ */ jsx2("figcaption", { className: "max-w-2xl text-center font-og-mono text-og-xs text-white/55", children: state.caption }) : /* @__PURE__ */ jsx2("figcaption", { className: "font-og-mono text-og-xs uppercase tracking-[0.1em] text-white/35", children: "Esc or click outside to close" })
|
|
1135
1224
|
] })
|
|
1136
1225
|
]
|
|
1137
1226
|
}
|
|
@@ -1172,7 +1261,10 @@ function ActivityDisclosure({
|
|
|
1172
1261
|
const previewVisible = preview != null && !open;
|
|
1173
1262
|
const rowClass = cn(
|
|
1174
1263
|
"group/disclosure flex w-full min-w-0 items-center gap-2 rounded-og-sm px-1.5 py-1.5 text-left text-og-base",
|
|
1175
|
-
"text-og-fg-muted transition-colors duration-150"
|
|
1264
|
+
"text-og-fg-muted transition-colors duration-150",
|
|
1265
|
+
// A tool row is a touch target on coarse pointers: grow its padding so the
|
|
1266
|
+
// hit area clears the 40px minimum without loosening the dense desktop rail.
|
|
1267
|
+
"pointer-coarse:py-2.5"
|
|
1176
1268
|
);
|
|
1177
1269
|
const inner = /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1178
1270
|
hasBody ? /* @__PURE__ */ jsx3(ChevronRightIcon, { className: "size-3.5 shrink-0 text-og-fg-subtle transition-transform duration-150 ease-og-in-out group-data-[state=open]/disclosure:rotate-90" }) : /* @__PURE__ */ jsx3("span", { className: "size-3.5 shrink-0" }),
|
|
@@ -1247,7 +1339,7 @@ function TermBlock({
|
|
|
1247
1339
|
const shown = full || !big ? output : lines.slice(-tailLines).join("\n");
|
|
1248
1340
|
const showMore = big && !full;
|
|
1249
1341
|
const showHeader = command != null || workdir != null;
|
|
1250
|
-
return /* @__PURE__ */ jsxs2("div", { className: "overflow-hidden rounded-og-sm border border-og-border bg-og-bg/70", children: [
|
|
1342
|
+
return /* @__PURE__ */ jsxs2("div", { className: "min-w-0 overflow-hidden rounded-og-sm border border-og-border bg-og-bg/70", children: [
|
|
1251
1343
|
showHeader ? /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 border-b border-og-border/70 px-2.5 py-1.5", children: [
|
|
1252
1344
|
/* @__PURE__ */ jsx3("span", { className: "select-none text-og-status-idle", children: "$" }),
|
|
1253
1345
|
command != null ? /* @__PURE__ */ jsx3("span", { className: "min-w-0 flex-1 truncate font-og-mono text-og-sm text-og-fg-muted", children: command }) : /* @__PURE__ */ jsx3("span", { className: "flex-1" }),
|
|
@@ -1412,7 +1504,7 @@ function DiffView({
|
|
|
1412
1504
|
return /* @__PURE__ */ jsx4("div", { className, children: fallback });
|
|
1413
1505
|
}
|
|
1414
1506
|
if (diff.length === 0) {
|
|
1415
|
-
return /* @__PURE__ */ jsx4("div", { className: cn("p-3 text-
|
|
1507
|
+
return /* @__PURE__ */ jsx4("div", { className: cn("p-3 text-og-sm text-og-fg-subtle", className), children: emptyState ?? (isRepo ? "No changes" : "No repository mounted") });
|
|
1416
1508
|
}
|
|
1417
1509
|
return /* @__PURE__ */ jsx4("div", { className: cn("min-w-0 overflow-auto", className), "data-opengeni-diff": true, children: diff.map((file) => /* @__PURE__ */ jsx4(
|
|
1418
1510
|
FileDiffBlock,
|
|
@@ -1431,24 +1523,24 @@ function FileDiffBlock({
|
|
|
1431
1523
|
theme,
|
|
1432
1524
|
onSelect
|
|
1433
1525
|
}) {
|
|
1434
|
-
return /* @__PURE__ */ jsxs3("section", { className: "mb-2 overflow-hidden rounded border border-
|
|
1526
|
+
return /* @__PURE__ */ jsxs3("section", { className: "mb-2 overflow-hidden rounded-og-sm border border-og-border", children: [
|
|
1435
1527
|
/* @__PURE__ */ jsxs3(
|
|
1436
1528
|
"header",
|
|
1437
1529
|
{
|
|
1438
1530
|
className: cn(
|
|
1439
|
-
"flex items-center justify-between gap-2 border-b border-
|
|
1531
|
+
"flex items-center justify-between gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-sm",
|
|
1440
1532
|
onSelect && "cursor-pointer"
|
|
1441
1533
|
),
|
|
1442
1534
|
onClick: onSelect,
|
|
1443
1535
|
children: [
|
|
1444
|
-
/* @__PURE__ */ jsx4("span", { className: "truncate font-mono", children: file.oldPath && file.oldPath !== file.path ? `${file.oldPath} \u2192 ${file.path}` : file.path }),
|
|
1536
|
+
/* @__PURE__ */ jsx4("span", { className: "truncate font-og-mono", children: file.oldPath && file.oldPath !== file.path ? `${file.oldPath} \u2192 ${file.path}` : file.path }),
|
|
1445
1537
|
/* @__PURE__ */ jsxs3("span", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1446
|
-
/* @__PURE__ */ jsx4("span", { className: "rounded bg-
|
|
1447
|
-
/* @__PURE__ */ jsxs3("span", { className: "text-
|
|
1538
|
+
/* @__PURE__ */ jsx4("span", { className: "rounded-og-xs bg-og-bg px-1 py-0.5 text-og-xs text-og-fg-subtle", children: STATUS_LABEL[file.status] }),
|
|
1539
|
+
/* @__PURE__ */ jsxs3("span", { className: "text-og-status-idle", children: [
|
|
1448
1540
|
"+",
|
|
1449
1541
|
file.additions
|
|
1450
1542
|
] }),
|
|
1451
|
-
/* @__PURE__ */ jsxs3("span", { className: "text-
|
|
1543
|
+
/* @__PURE__ */ jsxs3("span", { className: "text-og-status-failed", children: [
|
|
1452
1544
|
"\u2212",
|
|
1453
1545
|
file.deletions
|
|
1454
1546
|
] })
|
|
@@ -1456,12 +1548,12 @@ function FileDiffBlock({
|
|
|
1456
1548
|
]
|
|
1457
1549
|
}
|
|
1458
1550
|
),
|
|
1459
|
-
file.isBinary ? /* @__PURE__ */ jsx4("div", { className: "px-2 py-3 text-
|
|
1551
|
+
file.isBinary ? /* @__PURE__ */ jsx4("div", { className: "px-2 py-3 text-og-sm text-og-fg-subtle", children: "Binary file not shown" }) : file.truncated ? /* @__PURE__ */ jsx4("div", { className: "px-2 py-3 text-og-sm text-og-fg-subtle", children: "Diff too large \u2014 truncated" }) : layout === "split" ? /* @__PURE__ */ jsx4(SplitHunks, { file, theme }) : /* @__PURE__ */ jsx4(UnifiedHunks, { file, theme })
|
|
1460
1552
|
] });
|
|
1461
1553
|
}
|
|
1462
1554
|
function lineBg(type, theme) {
|
|
1463
|
-
if (type === "add") return theme?.addBackground ?? "var(--color-diff-add
|
|
1464
|
-
if (type === "del") return theme?.delBackground ?? "var(--color-diff-del
|
|
1555
|
+
if (type === "add") return theme?.addBackground ?? "var(--og-color-diff-add-bg)";
|
|
1556
|
+
if (type === "del") return theme?.delBackground ?? "var(--og-color-diff-del-bg)";
|
|
1465
1557
|
if (type === "meta") return void 0;
|
|
1466
1558
|
return theme?.contextBackground;
|
|
1467
1559
|
}
|
|
@@ -1471,11 +1563,11 @@ function marker(type) {
|
|
|
1471
1563
|
return " ";
|
|
1472
1564
|
}
|
|
1473
1565
|
function UnifiedHunks({ file, theme }) {
|
|
1474
|
-
return /* @__PURE__ */ jsx4("div", { className: "font-mono text-
|
|
1566
|
+
return /* @__PURE__ */ jsx4("div", { className: "font-og-mono text-og-xs", children: file.hunks.map((hunk, hi) => /* @__PURE__ */ jsxs3("div", { children: [
|
|
1475
1567
|
/* @__PURE__ */ jsx4(
|
|
1476
1568
|
"div",
|
|
1477
1569
|
{
|
|
1478
|
-
className: "px-2 py-0.5 text-
|
|
1570
|
+
className: "px-2 py-0.5 text-og-accent",
|
|
1479
1571
|
style: { color: theme?.metaForeground },
|
|
1480
1572
|
children: hunk.header
|
|
1481
1573
|
}
|
|
@@ -1486,9 +1578,9 @@ function UnifiedHunks({ file, theme }) {
|
|
|
1486
1578
|
className: "flex",
|
|
1487
1579
|
style: { backgroundColor: lineBg(line.type, theme) },
|
|
1488
1580
|
children: [
|
|
1489
|
-
/* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-
|
|
1490
|
-
/* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-
|
|
1491
|
-
/* @__PURE__ */ jsx4("span", { className: "w-4 shrink-0 select-none text-center text-
|
|
1581
|
+
/* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle", children: line.oldNo ?? "" }),
|
|
1582
|
+
/* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle", children: line.newNo ?? "" }),
|
|
1583
|
+
/* @__PURE__ */ jsx4("span", { className: "w-4 shrink-0 select-none text-center text-og-fg-subtle", children: marker(line.type) }),
|
|
1492
1584
|
/* @__PURE__ */ jsx4("span", { className: "whitespace-pre-wrap break-all px-1", children: line.text })
|
|
1493
1585
|
]
|
|
1494
1586
|
},
|
|
@@ -1497,7 +1589,7 @@ function UnifiedHunks({ file, theme }) {
|
|
|
1497
1589
|
] }, `${file.path}-h${hi}`)) });
|
|
1498
1590
|
}
|
|
1499
1591
|
function SplitHunks({ file, theme }) {
|
|
1500
|
-
return /* @__PURE__ */ jsx4("div", { className: "font-mono text-
|
|
1592
|
+
return /* @__PURE__ */ jsx4("div", { className: "font-og-mono text-og-xs", children: file.hunks.map((hunk, hi) => {
|
|
1501
1593
|
const left = [];
|
|
1502
1594
|
const right = [];
|
|
1503
1595
|
for (const line of hunk.lines) {
|
|
@@ -1512,7 +1604,7 @@ function SplitHunks({ file, theme }) {
|
|
|
1512
1604
|
}
|
|
1513
1605
|
const rows = Math.max(left.length, right.length);
|
|
1514
1606
|
return /* @__PURE__ */ jsxs3("div", { children: [
|
|
1515
|
-
/* @__PURE__ */ jsx4("div", { className: "px-2 py-0.5 text-
|
|
1607
|
+
/* @__PURE__ */ jsx4("div", { className: "px-2 py-0.5 text-og-accent", style: { color: theme?.metaForeground }, children: hunk.header }),
|
|
1516
1608
|
Array.from({ length: rows }).map((_, ri) => {
|
|
1517
1609
|
const l = left[ri] ?? null;
|
|
1518
1610
|
const r = right[ri] ?? null;
|
|
@@ -1523,7 +1615,7 @@ function SplitHunks({ file, theme }) {
|
|
|
1523
1615
|
className: "flex w-1/2 min-w-0",
|
|
1524
1616
|
style: { backgroundColor: l ? lineBg(l.type, theme) : void 0 },
|
|
1525
1617
|
children: [
|
|
1526
|
-
/* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-
|
|
1618
|
+
/* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle", children: l?.oldNo ?? "" }),
|
|
1527
1619
|
/* @__PURE__ */ jsx4("span", { className: "whitespace-pre-wrap break-all px-1", children: l?.text ?? "" })
|
|
1528
1620
|
]
|
|
1529
1621
|
}
|
|
@@ -1531,10 +1623,10 @@ function SplitHunks({ file, theme }) {
|
|
|
1531
1623
|
/* @__PURE__ */ jsxs3(
|
|
1532
1624
|
"span",
|
|
1533
1625
|
{
|
|
1534
|
-
className: "flex w-1/2 min-w-0 border-l border-
|
|
1626
|
+
className: "flex w-1/2 min-w-0 border-l border-og-border",
|
|
1535
1627
|
style: { backgroundColor: r ? lineBg(r.type, theme) : void 0 },
|
|
1536
1628
|
children: [
|
|
1537
|
-
/* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-
|
|
1629
|
+
/* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle", children: r?.newNo ?? "" }),
|
|
1538
1630
|
/* @__PURE__ */ jsx4("span", { className: "whitespace-pre-wrap break-all px-1", children: r?.text ?? "" })
|
|
1539
1631
|
]
|
|
1540
1632
|
}
|
|
@@ -1619,12 +1711,12 @@ function PierreDiff({
|
|
|
1619
1711
|
themeType: themeType ?? "dark"
|
|
1620
1712
|
};
|
|
1621
1713
|
const pierreVars = {
|
|
1622
|
-
"--diffs-dark-bg": "var(--og-color-bg
|
|
1623
|
-
"--diffs-light-bg": "var(--og-color-bg
|
|
1624
|
-
"--diffs-bg-buffer-override": "var(--og-color-surface-1
|
|
1625
|
-
"--diffs-bg-separator-override": "var(--og-color-surface-1
|
|
1626
|
-
"--diffs-font-size": "
|
|
1627
|
-
"--diffs-line-height": "
|
|
1714
|
+
"--diffs-dark-bg": "var(--og-color-bg)",
|
|
1715
|
+
"--diffs-light-bg": "var(--og-color-bg)",
|
|
1716
|
+
"--diffs-bg-buffer-override": "var(--og-color-surface-1)",
|
|
1717
|
+
"--diffs-bg-separator-override": "var(--og-color-surface-1)",
|
|
1718
|
+
"--diffs-font-size": "var(--og-code-font-size)",
|
|
1719
|
+
"--diffs-line-height": "var(--og-code-line-height)"
|
|
1628
1720
|
};
|
|
1629
1721
|
return /* @__PURE__ */ jsx5(
|
|
1630
1722
|
"div",
|
|
@@ -1644,7 +1736,7 @@ function PierreDiff({
|
|
|
1644
1736
|
);
|
|
1645
1737
|
}
|
|
1646
1738
|
function DiffSkeleton() {
|
|
1647
|
-
return /* @__PURE__ */ jsx5("div", { className: "p-3 text-
|
|
1739
|
+
return /* @__PURE__ */ jsx5("div", { className: "p-3 text-og-sm text-og-fg-subtle", children: "Loading diff\u2026" });
|
|
1648
1740
|
}
|
|
1649
1741
|
|
|
1650
1742
|
// src/timeline/tool-diff.tsx
|
|
@@ -1672,7 +1764,7 @@ function LayoutToggle({ layout, onChange }) {
|
|
|
1672
1764
|
type: "button",
|
|
1673
1765
|
onClick: () => onChange(value),
|
|
1674
1766
|
className: cn(
|
|
1675
|
-
"rounded-
|
|
1767
|
+
"rounded-og-xs px-2 py-[3px] text-og-xs font-medium capitalize transition-colors",
|
|
1676
1768
|
layout === value ? "bg-og-surface-2 text-og-fg" : "text-og-fg-subtle hover:text-og-fg-muted"
|
|
1677
1769
|
),
|
|
1678
1770
|
children: value
|
|
@@ -2024,16 +2116,34 @@ function computerVerb(action) {
|
|
|
2024
2116
|
return action.type;
|
|
2025
2117
|
}
|
|
2026
2118
|
}
|
|
2119
|
+
function asComputerArgs(args) {
|
|
2120
|
+
if (!args) {
|
|
2121
|
+
return {};
|
|
2122
|
+
}
|
|
2123
|
+
const parsed = typeof args === "string" ? tryParseJson(args) : args;
|
|
2124
|
+
if (!parsed || typeof parsed !== "object") {
|
|
2125
|
+
return {};
|
|
2126
|
+
}
|
|
2127
|
+
const record = parsed;
|
|
2128
|
+
return {
|
|
2129
|
+
...typeof record.x === "number" ? { x: record.x } : {},
|
|
2130
|
+
...typeof record.y === "number" ? { y: record.y } : {},
|
|
2131
|
+
...typeof record.text === "string" ? { text: record.text } : {},
|
|
2132
|
+
...Array.isArray(record.keys) ? { keys: record.keys } : {},
|
|
2133
|
+
...typeof record.button === "string" ? { button: record.button } : {}
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2027
2136
|
function ComputerCallRenderer({ item }) {
|
|
2028
2137
|
const raw = item.raw ?? {};
|
|
2029
|
-
const
|
|
2138
|
+
const functionAction = !raw.action && item.name.startsWith("computer_") && item.name !== "computer_call" ? { type: item.name.slice("computer_".length), ...asComputerArgs(item.arguments) } : void 0;
|
|
2139
|
+
const action = raw.action ?? functionAction;
|
|
2030
2140
|
const actions = raw.actions ?? (action ? [action] : []);
|
|
2031
2141
|
const verb = computerVerb(action);
|
|
2032
2142
|
const out = item.output;
|
|
2033
2143
|
const running = item.status === "running";
|
|
2034
2144
|
const rejected = raw.providerData?.approvalStatus === "rejected";
|
|
2035
2145
|
const readOnly = typeof out === "string" && out.includes("read-only");
|
|
2036
|
-
const
|
|
2146
|
+
const shotUrl = screenshotDataUrl(out);
|
|
2037
2147
|
const empty = out === "" || out == null;
|
|
2038
2148
|
const batched = actions.length > 1 ? actions.map((a) => computerVerb(a)).join(" \xB7 ") : null;
|
|
2039
2149
|
const countSuffix = actions.length > 1 ? ` \xB7${actions.length}` : "";
|
|
@@ -2078,8 +2188,8 @@ function ComputerCallRenderer({ item }) {
|
|
|
2078
2188
|
}
|
|
2079
2189
|
const isFailed = item.status === "failed";
|
|
2080
2190
|
const isCancelled = item.status === "cancelled";
|
|
2081
|
-
if (
|
|
2082
|
-
const caption =
|
|
2191
|
+
if (shotUrl) {
|
|
2192
|
+
const caption = `${verb}${actions.length > 1 ? ` (+${actions.length - 1} more)` : ""}`;
|
|
2083
2193
|
return /* @__PURE__ */ jsxs5(
|
|
2084
2194
|
ActivityDisclosure,
|
|
2085
2195
|
{
|
|
@@ -2088,9 +2198,9 @@ function ComputerCallRenderer({ item }) {
|
|
|
2088
2198
|
title: `${verb}${countSuffix}`,
|
|
2089
2199
|
failed: isFailed,
|
|
2090
2200
|
cancelled: isCancelled,
|
|
2091
|
-
media: /* @__PURE__ */ jsx7(Thumbnail, { src:
|
|
2201
|
+
media: /* @__PURE__ */ jsx7(Thumbnail, { src: shotUrl, caption }),
|
|
2092
2202
|
children: [
|
|
2093
|
-
/* @__PURE__ */ jsx7(ScreenshotFigure, { src:
|
|
2203
|
+
/* @__PURE__ */ jsx7(ScreenshotFigure, { src: shotUrl, caption }),
|
|
2094
2204
|
batched ? /* @__PURE__ */ jsxs5(BodyNote, { children: [
|
|
2095
2205
|
"batched: ",
|
|
2096
2206
|
batched
|
|
@@ -2368,6 +2478,15 @@ var BASE_ENTRIES = [
|
|
|
2368
2478
|
{ match: "name", name: "write_stdin", render: WriteStdinRenderer },
|
|
2369
2479
|
{ match: "name", name: "apply_patch_call", render: ApplyPatchRenderer },
|
|
2370
2480
|
{ match: "name", name: "computer_call", render: ComputerCallRenderer },
|
|
2481
|
+
// Function-mode computer tools (codex / chat-wire transports).
|
|
2482
|
+
{ match: "name", name: "computer_screenshot", render: ComputerCallRenderer },
|
|
2483
|
+
{ match: "name", name: "computer_click", render: ComputerCallRenderer },
|
|
2484
|
+
{ match: "name", name: "computer_double_click", render: ComputerCallRenderer },
|
|
2485
|
+
{ match: "name", name: "computer_move", render: ComputerCallRenderer },
|
|
2486
|
+
{ match: "name", name: "computer_scroll", render: ComputerCallRenderer },
|
|
2487
|
+
{ match: "name", name: "computer_type", render: ComputerCallRenderer },
|
|
2488
|
+
{ match: "name", name: "computer_keypress", render: ComputerCallRenderer },
|
|
2489
|
+
{ match: "name", name: "computer_drag", render: ComputerCallRenderer },
|
|
2371
2490
|
{ match: "name", name: "web_search_call", render: WebSearchRenderer },
|
|
2372
2491
|
{ match: "name", name: "view_image", render: ViewImageRenderer },
|
|
2373
2492
|
{ match: "name", name: "environment_set_variable", render: SecretSetRenderer }
|
|
@@ -2379,6 +2498,18 @@ function createDefaultToolRegistry(options = {}) {
|
|
|
2379
2498
|
|
|
2380
2499
|
// src/timeline/activity-rail.tsx
|
|
2381
2500
|
import { BotIcon, BrainIcon, SquareTerminalIcon } from "lucide-react";
|
|
2501
|
+
|
|
2502
|
+
// src/timeline/entrance.tsx
|
|
2503
|
+
import { createContext as createContext3, useContext as useContext3, useRef } from "react";
|
|
2504
|
+
var EntranceAnimationContext = createContext3(true);
|
|
2505
|
+
var EntranceAnimationProvider = EntranceAnimationContext.Provider;
|
|
2506
|
+
function useEntranceAnimation() {
|
|
2507
|
+
const enabled = useContext3(EntranceAnimationContext);
|
|
2508
|
+
const captured = useRef(enabled);
|
|
2509
|
+
return captured.current;
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2512
|
+
// src/timeline/activity-rail.tsx
|
|
2382
2513
|
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2383
2514
|
function familyOf(item) {
|
|
2384
2515
|
if (item.kind === "tool-call") {
|
|
@@ -2387,6 +2518,7 @@ function familyOf(item) {
|
|
|
2387
2518
|
return item.kind;
|
|
2388
2519
|
}
|
|
2389
2520
|
function ActivityRail({ items, toolRegistry = defaultToolRegistry, onOpenSession, bare, className }) {
|
|
2521
|
+
const enter = useEntranceAnimation();
|
|
2390
2522
|
return /* @__PURE__ */ jsx8(
|
|
2391
2523
|
"div",
|
|
2392
2524
|
{
|
|
@@ -2395,7 +2527,8 @@ function ActivityRail({ items, toolRegistry = defaultToolRegistry, onOpenSession
|
|
|
2395
2527
|
// calm cluster; a family change opens real breathing room (mt-3) below,
|
|
2396
2528
|
// so a long rail reads as a few clusters, not a metronome of rows.
|
|
2397
2529
|
"flex flex-col gap-0.5",
|
|
2398
|
-
!bare && "
|
|
2530
|
+
!bare && "border-l-2 border-og-border pl-3 sm:pl-4",
|
|
2531
|
+
!bare && enter && "animate-og-enter",
|
|
2399
2532
|
className
|
|
2400
2533
|
),
|
|
2401
2534
|
children: items.map((item, index) => {
|
|
@@ -2497,7 +2630,7 @@ function WorkerRow({ item, onOpenSession }) {
|
|
|
2497
2630
|
type: "button",
|
|
2498
2631
|
onClick: () => item.workerSessionId && onOpenSession(item.workerSessionId),
|
|
2499
2632
|
className: cn(
|
|
2500
|
-
"shrink-0 self-center rounded-og-sm border border-og-border px-2.5 py-1 text-og-sm font-medium text-og-fg-muted",
|
|
2633
|
+
"shrink-0 self-center rounded-og-sm border border-og-border px-2.5 py-1 text-og-sm font-medium text-og-fg-muted pointer-coarse:py-2",
|
|
2501
2634
|
"outline-none transition-colors duration-150 hover:border-og-border-strong hover:text-og-fg",
|
|
2502
2635
|
"focus-visible:ring-2 focus-visible:ring-og-accent"
|
|
2503
2636
|
),
|
|
@@ -2517,13 +2650,17 @@ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
|
2517
2650
|
function TurnSummary({ items, outcome, failureText, durationMs, defaultOpen, children }) {
|
|
2518
2651
|
const forcedDefaultOpen = useForcedDefaultOpen();
|
|
2519
2652
|
const [open, setOpen] = useState7(defaultOpen ?? forcedDefaultOpen ?? false);
|
|
2653
|
+
const enter = useEntranceAnimation();
|
|
2520
2654
|
const facets = summarizeTurn(items, durationMs);
|
|
2521
|
-
return /* @__PURE__ */ jsxs7(Collapsible2.Root, { open, onOpenChange: setOpen, className: "animate-og-enter", children: [
|
|
2655
|
+
return /* @__PURE__ */ jsxs7(Collapsible2.Root, { open, onOpenChange: setOpen, className: enter ? "animate-og-enter" : void 0, children: [
|
|
2522
2656
|
/* @__PURE__ */ jsxs7(
|
|
2523
2657
|
Collapsible2.Trigger,
|
|
2524
2658
|
{
|
|
2525
2659
|
className: cn(
|
|
2526
2660
|
"group flex w-full items-center gap-2.5 rounded-og-md border px-3 py-2 text-left text-og-base transition-colors",
|
|
2661
|
+
// A folded turn is a touch target on coarse pointers: grow the row so
|
|
2662
|
+
// it clears the 40px minimum without disturbing the calm desktop rhythm.
|
|
2663
|
+
"pointer-coarse:py-2.5",
|
|
2527
2664
|
// Only a failed turn earns the one filled/tinted card in the timeline;
|
|
2528
2665
|
// complete and cancelled stay flat and calm.
|
|
2529
2666
|
outcome === "failed" ? "border-og-status-failed/30 bg-og-status-failed/[0.06] hover:border-og-status-failed/50" : "border-og-border bg-og-surface-1/50 hover:border-og-border-strong"
|
|
@@ -2547,7 +2684,19 @@ function TurnSummary({ items, outcome, failureText, durationMs, defaultOpen, chi
|
|
|
2547
2684
|
failureText
|
|
2548
2685
|
] }) : null,
|
|
2549
2686
|
outcome === "cancelled" ? /* @__PURE__ */ jsx9("span", { className: "text-og-fg-subtle", children: " \xB7 interrupted" }) : null
|
|
2550
|
-
] })
|
|
2687
|
+
] }),
|
|
2688
|
+
/* @__PURE__ */ jsx9(
|
|
2689
|
+
"span",
|
|
2690
|
+
{
|
|
2691
|
+
"aria-hidden": true,
|
|
2692
|
+
className: cn(
|
|
2693
|
+
"ml-auto shrink-0 pl-2 text-og-xs text-og-fg-subtle transition-opacity duration-150",
|
|
2694
|
+
"opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100",
|
|
2695
|
+
"pointer-coarse:opacity-100"
|
|
2696
|
+
),
|
|
2697
|
+
children: open ? "hide steps" : "show steps"
|
|
2698
|
+
}
|
|
2699
|
+
)
|
|
2551
2700
|
]
|
|
2552
2701
|
}
|
|
2553
2702
|
),
|
|
@@ -2566,8 +2715,8 @@ function summarizeTurn(items, durationMs) {
|
|
|
2566
2715
|
files += applyPatchOps(item.raw).length;
|
|
2567
2716
|
} else if (item.name === "exec_command") {
|
|
2568
2717
|
commands += 1;
|
|
2569
|
-
} else if (rawTypeOf(item) === "computer_call" || item.name === "computer_call") {
|
|
2570
|
-
if (
|
|
2718
|
+
} else if (rawTypeOf(item) === "computer_call" || item.name === "computer_call" || item.name === "computer_screenshot") {
|
|
2719
|
+
if (screenshotDataUrl(item.output) !== null) {
|
|
2571
2720
|
screenshots += 1;
|
|
2572
2721
|
}
|
|
2573
2722
|
}
|
|
@@ -2606,22 +2755,42 @@ function formatDurationFacet(durationMs) {
|
|
|
2606
2755
|
}
|
|
2607
2756
|
|
|
2608
2757
|
// src/hooks/use-session-events.ts
|
|
2758
|
+
var TAIL_PAGE_SIZE = 5e3;
|
|
2759
|
+
var INITIAL_GROUP_TARGET = 48;
|
|
2760
|
+
var INITIAL_FETCH_CAP = 3;
|
|
2761
|
+
var OLDER_GROUP_TARGET = 32;
|
|
2762
|
+
var OLDER_FETCH_CAP = 2;
|
|
2763
|
+
var BOUNDARY_PAGE_CAP = 4;
|
|
2609
2764
|
function useSessionEvents(sessionId, options = {}) {
|
|
2610
2765
|
const { client, workspaceId } = useOpenGeni(options);
|
|
2611
2766
|
const enabled = options.enabled ?? true;
|
|
2612
2767
|
const after = options.after ?? 0;
|
|
2768
|
+
const replay = options.replay ?? "windowed";
|
|
2769
|
+
const fullReplay = replay === "full" || after !== 0;
|
|
2613
2770
|
const [events, setEvents] = useState8([]);
|
|
2614
2771
|
const [connectionState, setConnectionState] = useState8("idle");
|
|
2615
2772
|
const [error, setError] = useState8(null);
|
|
2616
|
-
const
|
|
2617
|
-
const
|
|
2773
|
+
const [hasOlder, setHasOlder] = useState8(false);
|
|
2774
|
+
const [loadingOlder, setLoadingOlder] = useState8(false);
|
|
2775
|
+
const lastSequenceRef = useRef2(after);
|
|
2776
|
+
const oldestSequenceRef = useRef2(null);
|
|
2777
|
+
const hasOlderRef = useRef2(false);
|
|
2778
|
+
const loadingOlderRef = useRef2(false);
|
|
2779
|
+
const streamKeyRef = useRef2(null);
|
|
2780
|
+
const generationRef = useRef2(0);
|
|
2618
2781
|
useEffect3(() => {
|
|
2619
|
-
const streamKey = `${workspaceId}\0${sessionId ?? ""}\0${after}`;
|
|
2782
|
+
const streamKey = `${workspaceId}\0${sessionId ?? ""}\0${after}\0${fullReplay ? "full" : "windowed"}`;
|
|
2620
2783
|
if (streamKeyRef.current !== streamKey) {
|
|
2621
2784
|
streamKeyRef.current = streamKey;
|
|
2785
|
+
generationRef.current += 1;
|
|
2622
2786
|
setEvents([]);
|
|
2623
2787
|
setError(null);
|
|
2788
|
+
setHasOlder(false);
|
|
2789
|
+
setLoadingOlder(false);
|
|
2624
2790
|
lastSequenceRef.current = after;
|
|
2791
|
+
oldestSequenceRef.current = null;
|
|
2792
|
+
hasOlderRef.current = false;
|
|
2793
|
+
loadingOlderRef.current = false;
|
|
2625
2794
|
}
|
|
2626
2795
|
if (!sessionId || !enabled) {
|
|
2627
2796
|
setConnectionState("idle");
|
|
@@ -2639,7 +2808,7 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
2639
2808
|
pending = [];
|
|
2640
2809
|
const lastInBatch = batch[batch.length - 1];
|
|
2641
2810
|
if (lastInBatch) {
|
|
2642
|
-
lastSequenceRef.current =
|
|
2811
|
+
lastSequenceRef.current = Math.max(lastSequenceRef.current, ...batch.map(eventResumeSequence));
|
|
2643
2812
|
}
|
|
2644
2813
|
setEvents((existing) => [...existing, ...batch]);
|
|
2645
2814
|
};
|
|
@@ -2648,6 +2817,24 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
2648
2817
|
};
|
|
2649
2818
|
void (async () => {
|
|
2650
2819
|
try {
|
|
2820
|
+
if (!fullReplay) {
|
|
2821
|
+
setConnectionState("connecting");
|
|
2822
|
+
const window2 = await loadEventWindow(client, workspaceId, sessionId, {
|
|
2823
|
+
before: Number.MAX_SAFE_INTEGER,
|
|
2824
|
+
pageSize: TAIL_PAGE_SIZE,
|
|
2825
|
+
targetGroups: INITIAL_GROUP_TARGET,
|
|
2826
|
+
maxFetches: INITIAL_FETCH_CAP,
|
|
2827
|
+
signal: controller.signal
|
|
2828
|
+
});
|
|
2829
|
+
if (controller.signal.aborted) {
|
|
2830
|
+
return;
|
|
2831
|
+
}
|
|
2832
|
+
oldestSequenceRef.current = window2.oldestSequence;
|
|
2833
|
+
hasOlderRef.current = window2.hasOlder;
|
|
2834
|
+
lastSequenceRef.current = window2.newestSequence;
|
|
2835
|
+
setHasOlder(window2.hasOlder);
|
|
2836
|
+
setEvents(window2.events);
|
|
2837
|
+
}
|
|
2651
2838
|
const stream = client.streamEvents(workspaceId, sessionId, {
|
|
2652
2839
|
after: lastSequenceRef.current,
|
|
2653
2840
|
signal: controller.signal,
|
|
@@ -2679,7 +2866,51 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
2679
2866
|
clearTimeout(flushTimer);
|
|
2680
2867
|
}
|
|
2681
2868
|
};
|
|
2682
|
-
}, [client, workspaceId, sessionId, after, enabled]);
|
|
2869
|
+
}, [client, workspaceId, sessionId, after, enabled, fullReplay]);
|
|
2870
|
+
const loadOlder = useCallback3(async () => {
|
|
2871
|
+
if (!sessionId || fullReplay || loadingOlderRef.current || !hasOlderRef.current) {
|
|
2872
|
+
return false;
|
|
2873
|
+
}
|
|
2874
|
+
const before = oldestSequenceRef.current;
|
|
2875
|
+
if (before === null) {
|
|
2876
|
+
hasOlderRef.current = false;
|
|
2877
|
+
setHasOlder(false);
|
|
2878
|
+
return false;
|
|
2879
|
+
}
|
|
2880
|
+
const generation = generationRef.current;
|
|
2881
|
+
loadingOlderRef.current = true;
|
|
2882
|
+
setLoadingOlder(true);
|
|
2883
|
+
try {
|
|
2884
|
+
const window2 = await loadEventWindow(client, workspaceId, sessionId, {
|
|
2885
|
+
before,
|
|
2886
|
+
pageSize: TAIL_PAGE_SIZE,
|
|
2887
|
+
targetGroups: OLDER_GROUP_TARGET,
|
|
2888
|
+
maxFetches: OLDER_FETCH_CAP
|
|
2889
|
+
});
|
|
2890
|
+
if (generationRef.current !== generation) {
|
|
2891
|
+
return false;
|
|
2892
|
+
}
|
|
2893
|
+
if (window2.events.length === 0) {
|
|
2894
|
+
oldestSequenceRef.current = null;
|
|
2895
|
+
hasOlderRef.current = false;
|
|
2896
|
+
setHasOlder(false);
|
|
2897
|
+
return false;
|
|
2898
|
+
}
|
|
2899
|
+
oldestSequenceRef.current = window2.oldestSequence;
|
|
2900
|
+
hasOlderRef.current = window2.hasOlder;
|
|
2901
|
+
setHasOlder(window2.hasOlder);
|
|
2902
|
+
setEvents((existing) => {
|
|
2903
|
+
assertPrependOrder(existing, window2.events);
|
|
2904
|
+
return [...window2.events, ...existing];
|
|
2905
|
+
});
|
|
2906
|
+
return window2.hasOlder;
|
|
2907
|
+
} finally {
|
|
2908
|
+
if (generationRef.current === generation) {
|
|
2909
|
+
loadingOlderRef.current = false;
|
|
2910
|
+
setLoadingOlder(false);
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
}, [client, workspaceId, sessionId, fullReplay]);
|
|
2683
2914
|
const timeline = useMemo2(() => buildTimeline(events), [events]);
|
|
2684
2915
|
const sessionStatus = useMemo2(() => sessionStatusFromEvents(events), [events]);
|
|
2685
2916
|
return {
|
|
@@ -2688,12 +2919,143 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
2688
2919
|
sessionStatus,
|
|
2689
2920
|
connectionState,
|
|
2690
2921
|
lastSequence: lastSequenceRef.current,
|
|
2922
|
+
hasOlder: fullReplay ? false : hasOlder,
|
|
2923
|
+
loadingOlder: fullReplay ? false : loadingOlder,
|
|
2924
|
+
loadOlder,
|
|
2691
2925
|
error
|
|
2692
2926
|
};
|
|
2693
2927
|
}
|
|
2928
|
+
async function loadEventWindow(client, workspaceId, sessionId, options) {
|
|
2929
|
+
let cursor = options.before;
|
|
2930
|
+
let buffer = [];
|
|
2931
|
+
let reachedStart = false;
|
|
2932
|
+
let fetches = 0;
|
|
2933
|
+
while (fetches < options.maxFetches) {
|
|
2934
|
+
if (buffer.length > 0 && groupCount(buffer) >= options.targetGroups) {
|
|
2935
|
+
break;
|
|
2936
|
+
}
|
|
2937
|
+
const page = await loadPreviousPage(client, workspaceId, sessionId, cursor, {
|
|
2938
|
+
pageSize: options.pageSize,
|
|
2939
|
+
...options.signal ? { signal: options.signal } : {}
|
|
2940
|
+
});
|
|
2941
|
+
fetches += 1;
|
|
2942
|
+
if (page.length === 0) {
|
|
2943
|
+
reachedStart = true;
|
|
2944
|
+
break;
|
|
2945
|
+
}
|
|
2946
|
+
assertAscending(page);
|
|
2947
|
+
buffer = [...page, ...buffer];
|
|
2948
|
+
cursor = page[0].sequence;
|
|
2949
|
+
if (isLogStart(page[0])) {
|
|
2950
|
+
reachedStart = true;
|
|
2951
|
+
break;
|
|
2952
|
+
}
|
|
2953
|
+
}
|
|
2954
|
+
let snapPages = 0;
|
|
2955
|
+
while (!reachedStart && findBoundaryIndex(buffer) === -1 && snapPages < BOUNDARY_PAGE_CAP && fetches < options.maxFetches) {
|
|
2956
|
+
const page = await loadPreviousPage(client, workspaceId, sessionId, cursor, {
|
|
2957
|
+
pageSize: options.pageSize,
|
|
2958
|
+
...options.signal ? { signal: options.signal } : {}
|
|
2959
|
+
});
|
|
2960
|
+
fetches += 1;
|
|
2961
|
+
snapPages += 1;
|
|
2962
|
+
if (page.length === 0) {
|
|
2963
|
+
reachedStart = true;
|
|
2964
|
+
break;
|
|
2965
|
+
}
|
|
2966
|
+
assertAscending(page);
|
|
2967
|
+
buffer = [...page, ...buffer];
|
|
2968
|
+
cursor = page[0].sequence;
|
|
2969
|
+
if (isLogStart(page[0])) {
|
|
2970
|
+
reachedStart = true;
|
|
2971
|
+
break;
|
|
2972
|
+
}
|
|
2973
|
+
}
|
|
2974
|
+
if (!reachedStart) {
|
|
2975
|
+
const boundary = findBoundaryIndex(buffer);
|
|
2976
|
+
if (boundary > 0) {
|
|
2977
|
+
buffer = buffer.slice(boundary);
|
|
2978
|
+
}
|
|
2979
|
+
}
|
|
2980
|
+
const oldest = buffer[0] ?? null;
|
|
2981
|
+
const newest = buffer[buffer.length - 1] ?? null;
|
|
2982
|
+
return {
|
|
2983
|
+
events: buffer,
|
|
2984
|
+
oldestSequence: oldest?.sequence ?? null,
|
|
2985
|
+
newestSequence: newest ? maxResumeSequence(buffer) : 0,
|
|
2986
|
+
hasOlder: buffer.length > 0 && !reachedStart && oldest?.type !== "session.created"
|
|
2987
|
+
};
|
|
2988
|
+
}
|
|
2989
|
+
function findBoundaryIndex(events) {
|
|
2990
|
+
for (let index = 0; index < events.length; index += 1) {
|
|
2991
|
+
const type = events[index].type;
|
|
2992
|
+
if (type === "session.created" || type === "user.message") {
|
|
2993
|
+
return index;
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
return -1;
|
|
2997
|
+
}
|
|
2998
|
+
async function loadPreviousPage(client, workspaceId, sessionId, before, options) {
|
|
2999
|
+
if (options.signal?.aborted) {
|
|
3000
|
+
throw abortError();
|
|
3001
|
+
}
|
|
3002
|
+
const requested = options.pageSize;
|
|
3003
|
+
if (requested === 0) {
|
|
3004
|
+
return Object.assign([], { requested });
|
|
3005
|
+
}
|
|
3006
|
+
const page = await client.listEvents(workspaceId, sessionId, { before, limit: requested, compact: true });
|
|
3007
|
+
if (options.signal?.aborted) {
|
|
3008
|
+
throw abortError();
|
|
3009
|
+
}
|
|
3010
|
+
return Object.assign(page, { requested });
|
|
3011
|
+
}
|
|
3012
|
+
function groupCount(events) {
|
|
3013
|
+
if (events.length === 0) {
|
|
3014
|
+
return 0;
|
|
3015
|
+
}
|
|
3016
|
+
return groupTimeline(buildTimeline(events)).length;
|
|
3017
|
+
}
|
|
3018
|
+
function isLogStart(event) {
|
|
3019
|
+
return event.type === "session.created" || event.sequence <= 1;
|
|
3020
|
+
}
|
|
3021
|
+
function maxResumeSequence(events) {
|
|
3022
|
+
return events.reduce((max, event) => Math.max(max, eventResumeSequence(event)), 0);
|
|
3023
|
+
}
|
|
3024
|
+
function eventResumeSequence(event) {
|
|
3025
|
+
const payload = asRecord2(event.payload);
|
|
3026
|
+
const coalescedUntil = Number(payload.coalescedUntil);
|
|
3027
|
+
return Math.max(event.sequence, Number.isFinite(coalescedUntil) ? Math.floor(coalescedUntil) : 0);
|
|
3028
|
+
}
|
|
3029
|
+
function asRecord2(value) {
|
|
3030
|
+
return value && typeof value === "object" ? value : {};
|
|
3031
|
+
}
|
|
3032
|
+
function assertAscending(events) {
|
|
3033
|
+
for (let index = 1; index < events.length; index += 1) {
|
|
3034
|
+
if (events[index - 1].sequence >= events[index].sequence) {
|
|
3035
|
+
throw new Error("@opengeni/react: session events must be ordered by ascending sequence");
|
|
3036
|
+
}
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3039
|
+
function assertPrependOrder(existing, older) {
|
|
3040
|
+
if (!shouldAssertDevelopment() || existing.length === 0 || older.length === 0) {
|
|
3041
|
+
return;
|
|
3042
|
+
}
|
|
3043
|
+
if (older[older.length - 1].sequence >= existing[0].sequence) {
|
|
3044
|
+
throw new Error("@opengeni/react: loadOlder returned overlapping session events");
|
|
3045
|
+
}
|
|
3046
|
+
}
|
|
3047
|
+
function shouldAssertDevelopment() {
|
|
3048
|
+
const processEnv = globalThis.process?.env;
|
|
3049
|
+
return processEnv !== void 0 && processEnv.NODE_ENV !== "production";
|
|
3050
|
+
}
|
|
3051
|
+
function abortError() {
|
|
3052
|
+
const error = new Error("The operation was aborted.");
|
|
3053
|
+
error.name = "AbortError";
|
|
3054
|
+
return error;
|
|
3055
|
+
}
|
|
2694
3056
|
|
|
2695
3057
|
// src/hooks/use-composer.ts
|
|
2696
|
-
import { useCallback as
|
|
3058
|
+
import { useCallback as useCallback4, useEffect as useEffect4, useRef as useRef3, useState as useState9 } from "react";
|
|
2697
3059
|
function useComposer(sessionId, options = {}) {
|
|
2698
3060
|
const { client, workspaceId } = useOpenGeni(options);
|
|
2699
3061
|
const defaultMode = options.defaultMode ?? "queue";
|
|
@@ -2702,14 +3064,14 @@ function useComposer(sessionId, options = {}) {
|
|
|
2702
3064
|
const [sending, setSending] = useState9(false);
|
|
2703
3065
|
const [interrupting, setInterrupting] = useState9(false);
|
|
2704
3066
|
const [error, setError] = useState9(null);
|
|
2705
|
-
const pendingClientEventId =
|
|
3067
|
+
const pendingClientEventId = useRef3(null);
|
|
2706
3068
|
const onSent = options.onSent;
|
|
2707
|
-
const modeRef =
|
|
3069
|
+
const modeRef = useRef3(mode);
|
|
2708
3070
|
modeRef.current = mode;
|
|
2709
|
-
const sendExtrasRef =
|
|
3071
|
+
const sendExtrasRef = useRef3(options.sendExtras);
|
|
2710
3072
|
sendExtrasRef.current = options.sendExtras;
|
|
2711
3073
|
const targetKey = `${workspaceId}\0${sessionId ?? ""}`;
|
|
2712
|
-
const targetKeyRef =
|
|
3074
|
+
const targetKeyRef = useRef3(targetKey);
|
|
2713
3075
|
useEffect4(() => {
|
|
2714
3076
|
if (targetKeyRef.current !== targetKey) {
|
|
2715
3077
|
targetKeyRef.current = targetKey;
|
|
@@ -2719,7 +3081,7 @@ function useComposer(sessionId, options = {}) {
|
|
|
2719
3081
|
setMode(defaultMode);
|
|
2720
3082
|
}
|
|
2721
3083
|
}, [targetKey, defaultMode]);
|
|
2722
|
-
const send =
|
|
3084
|
+
const send = useCallback4(
|
|
2723
3085
|
async (explicit) => {
|
|
2724
3086
|
const draftAtSend = value;
|
|
2725
3087
|
const text = (explicit ?? draftAtSend).trim();
|
|
@@ -2755,7 +3117,7 @@ function useComposer(sessionId, options = {}) {
|
|
|
2755
3117
|
[client, workspaceId, sessionId, value, sending, onSent]
|
|
2756
3118
|
);
|
|
2757
3119
|
const hasReadyResources = (resolveSendExtras(sendExtrasRef.current).resources?.length ?? 0) > 0;
|
|
2758
|
-
const interrupt =
|
|
3120
|
+
const interrupt = useCallback4(
|
|
2759
3121
|
async (reason) => {
|
|
2760
3122
|
if (!sessionId || interrupting) {
|
|
2761
3123
|
return;
|
|
@@ -2772,7 +3134,7 @@ function useComposer(sessionId, options = {}) {
|
|
|
2772
3134
|
},
|
|
2773
3135
|
[client, workspaceId, sessionId, interrupting]
|
|
2774
3136
|
);
|
|
2775
|
-
const updateValue =
|
|
3137
|
+
const updateValue = useCallback4((next) => {
|
|
2776
3138
|
pendingClientEventId.current = null;
|
|
2777
3139
|
setValue(next);
|
|
2778
3140
|
}, []);
|
|
@@ -2787,7 +3149,7 @@ function useComposer(sessionId, options = {}) {
|
|
|
2787
3149
|
interrupt,
|
|
2788
3150
|
interrupting,
|
|
2789
3151
|
error,
|
|
2790
|
-
clearError:
|
|
3152
|
+
clearError: useCallback4(() => setError(null), [])
|
|
2791
3153
|
};
|
|
2792
3154
|
}
|
|
2793
3155
|
var FILE_ONLY_MESSAGE_TEXT = "(see attached files)";
|
|
@@ -2812,15 +3174,28 @@ function generateClientEventId() {
|
|
|
2812
3174
|
}
|
|
2813
3175
|
|
|
2814
3176
|
// src/hooks/use-file-attachments.ts
|
|
2815
|
-
import { useCallback as
|
|
3177
|
+
import { useCallback as useCallback5, useRef as useRef4, useState as useState10 } from "react";
|
|
2816
3178
|
var isImage = (file) => file.type.startsWith("image/");
|
|
2817
3179
|
function useFileAttachments(options = {}) {
|
|
2818
3180
|
const { client, workspaceId } = useOpenGeni(options);
|
|
2819
3181
|
const pasteFilter = options.pasteFilter ?? isImage;
|
|
2820
3182
|
const [attachments, setAttachments] = useState10([]);
|
|
2821
|
-
const
|
|
3183
|
+
const sources = useRef4(/* @__PURE__ */ new Map());
|
|
3184
|
+
const startUpload = useCallback5((id, file) => {
|
|
3185
|
+
void client.uploadFile(workspaceId, {
|
|
3186
|
+
filename: file.name || "file",
|
|
3187
|
+
contentType: file.type || "application/octet-stream",
|
|
3188
|
+
data: file
|
|
3189
|
+
}).then((asset) => {
|
|
3190
|
+
setAttachments((current) => current.map((attachment) => attachment.id === id ? { ...attachment, status: "ready", file: asset, name: asset.filename, contentType: asset.contentType, sizeBytes: asset.sizeBytes, error: void 0 } : attachment));
|
|
3191
|
+
}).catch((error) => {
|
|
3192
|
+
setAttachments((current) => current.map((attachment) => attachment.id === id ? { ...attachment, status: "failed", error: error instanceof Error ? error.message : String(error) } : attachment));
|
|
3193
|
+
});
|
|
3194
|
+
}, [client, workspaceId]);
|
|
3195
|
+
const addFiles = useCallback5((files) => {
|
|
2822
3196
|
for (const file of files) {
|
|
2823
3197
|
const id = crypto.randomUUID();
|
|
3198
|
+
sources.current.set(id, file);
|
|
2824
3199
|
const previewUrl = isImage(file) ? URL.createObjectURL(file) : void 0;
|
|
2825
3200
|
setAttachments((current) => [...current, {
|
|
2826
3201
|
id,
|
|
@@ -2830,18 +3205,18 @@ function useFileAttachments(options = {}) {
|
|
|
2830
3205
|
status: "uploading",
|
|
2831
3206
|
...previewUrl ? { previewUrl } : {}
|
|
2832
3207
|
}]);
|
|
2833
|
-
|
|
2834
|
-
filename: file.name || "file",
|
|
2835
|
-
contentType: file.type || "application/octet-stream",
|
|
2836
|
-
data: file
|
|
2837
|
-
}).then((asset) => {
|
|
2838
|
-
setAttachments((current) => current.map((attachment) => attachment.id === id ? { ...attachment, status: "ready", file: asset, name: asset.filename, contentType: asset.contentType, sizeBytes: asset.sizeBytes } : attachment));
|
|
2839
|
-
}).catch((error) => {
|
|
2840
|
-
setAttachments((current) => current.map((attachment) => attachment.id === id ? { ...attachment, status: "failed", error: error instanceof Error ? error.message : String(error) } : attachment));
|
|
2841
|
-
});
|
|
3208
|
+
startUpload(id, file);
|
|
2842
3209
|
}
|
|
2843
|
-
}, [
|
|
2844
|
-
const
|
|
3210
|
+
}, [startUpload]);
|
|
3211
|
+
const retry = useCallback5((id) => {
|
|
3212
|
+
const file = sources.current.get(id);
|
|
3213
|
+
if (!file) {
|
|
3214
|
+
return;
|
|
3215
|
+
}
|
|
3216
|
+
setAttachments((current) => current.map((attachment) => attachment.id === id ? { ...attachment, status: "uploading", error: void 0 } : attachment));
|
|
3217
|
+
startUpload(id, file);
|
|
3218
|
+
}, [startUpload]);
|
|
3219
|
+
const addFromPaste = useCallback5((event) => {
|
|
2845
3220
|
const clipboardFiles = event.clipboardData?.files;
|
|
2846
3221
|
if (!clipboardFiles) {
|
|
2847
3222
|
return;
|
|
@@ -2851,7 +3226,8 @@ function useFileAttachments(options = {}) {
|
|
|
2851
3226
|
addFiles(files);
|
|
2852
3227
|
}
|
|
2853
3228
|
}, [addFiles, pasteFilter]);
|
|
2854
|
-
const remove =
|
|
3229
|
+
const remove = useCallback5((id) => {
|
|
3230
|
+
sources.current.delete(id);
|
|
2855
3231
|
setAttachments((current) => {
|
|
2856
3232
|
const removed = current.find((attachment) => attachment.id === id);
|
|
2857
3233
|
if (removed?.previewUrl) {
|
|
@@ -2860,7 +3236,8 @@ function useFileAttachments(options = {}) {
|
|
|
2860
3236
|
return current.filter((attachment) => attachment.id !== id);
|
|
2861
3237
|
});
|
|
2862
3238
|
}, []);
|
|
2863
|
-
const clear =
|
|
3239
|
+
const clear = useCallback5(() => {
|
|
3240
|
+
sources.current.clear();
|
|
2864
3241
|
setAttachments((current) => {
|
|
2865
3242
|
for (const attachment of current) {
|
|
2866
3243
|
if (attachment.previewUrl) {
|
|
@@ -2876,13 +3253,14 @@ function useFileAttachments(options = {}) {
|
|
|
2876
3253
|
uploading: attachments.some((attachment) => attachment.status === "uploading"),
|
|
2877
3254
|
addFiles,
|
|
2878
3255
|
addFromPaste,
|
|
3256
|
+
retry,
|
|
2879
3257
|
remove,
|
|
2880
3258
|
clear
|
|
2881
3259
|
};
|
|
2882
3260
|
}
|
|
2883
3261
|
|
|
2884
3262
|
// src/hooks/use-turn-queue.ts
|
|
2885
|
-
import { useCallback as
|
|
3263
|
+
import { useCallback as useCallback6, useEffect as useEffect5, useRef as useRef5, useState as useState11 } from "react";
|
|
2886
3264
|
function isTurnQueueEvent(event) {
|
|
2887
3265
|
return event.type.startsWith("turn.");
|
|
2888
3266
|
}
|
|
@@ -2926,9 +3304,9 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
2926
3304
|
const [loading, setLoading] = useState11(enabled);
|
|
2927
3305
|
const [error, setError] = useState11(null);
|
|
2928
3306
|
const mutation = useMutationRunner();
|
|
2929
|
-
const generation =
|
|
2930
|
-
const targetKeyRef =
|
|
2931
|
-
const load =
|
|
3307
|
+
const generation = useRef5(0);
|
|
3308
|
+
const targetKeyRef = useRef5(null);
|
|
3309
|
+
const load = useCallback6(async () => {
|
|
2932
3310
|
if (!sessionId) {
|
|
2933
3311
|
return;
|
|
2934
3312
|
}
|
|
@@ -2977,7 +3355,7 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
2977
3355
|
enabled,
|
|
2978
3356
|
...options.events !== void 0 ? { events: options.events } : {}
|
|
2979
3357
|
});
|
|
2980
|
-
const editTurn =
|
|
3358
|
+
const editTurn = useCallback6(
|
|
2981
3359
|
async (turnId, update) => {
|
|
2982
3360
|
if (!sessionId) {
|
|
2983
3361
|
return null;
|
|
@@ -2993,7 +3371,7 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
2993
3371
|
},
|
|
2994
3372
|
[client, workspaceId, sessionId, mutation.run, load]
|
|
2995
3373
|
);
|
|
2996
|
-
const reorderTurns =
|
|
3374
|
+
const reorderTurns = useCallback6(
|
|
2997
3375
|
async (turnIds) => {
|
|
2998
3376
|
if (!sessionId || turnIds.length === 0) {
|
|
2999
3377
|
return null;
|
|
@@ -3012,7 +3390,7 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
3012
3390
|
},
|
|
3013
3391
|
[client, workspaceId, sessionId, mutation.run, load]
|
|
3014
3392
|
);
|
|
3015
|
-
const removeTurn =
|
|
3393
|
+
const removeTurn = useCallback6(
|
|
3016
3394
|
async (turnId) => {
|
|
3017
3395
|
if (!sessionId) {
|
|
3018
3396
|
return null;
|
|
@@ -3046,7 +3424,7 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
3046
3424
|
|
|
3047
3425
|
// src/hooks/use-goal.ts
|
|
3048
3426
|
import { OpenGeniApiError } from "@opengeni/sdk";
|
|
3049
|
-
import { useCallback as
|
|
3427
|
+
import { useCallback as useCallback7, useEffect as useEffect6, useRef as useRef6, useState as useState12 } from "react";
|
|
3050
3428
|
function isGoalEvent(event) {
|
|
3051
3429
|
return event.type.startsWith("goal.");
|
|
3052
3430
|
}
|
|
@@ -3059,9 +3437,9 @@ function useGoal(sessionId, options = {}) {
|
|
|
3059
3437
|
const [loading, setLoading] = useState12(enabled);
|
|
3060
3438
|
const [error, setError] = useState12(null);
|
|
3061
3439
|
const mutation = useMutationRunner();
|
|
3062
|
-
const generation =
|
|
3063
|
-
const targetKeyRef =
|
|
3064
|
-
const load =
|
|
3440
|
+
const generation = useRef6(0);
|
|
3441
|
+
const targetKeyRef = useRef6(null);
|
|
3442
|
+
const load = useCallback7(async () => {
|
|
3065
3443
|
if (!sessionId) {
|
|
3066
3444
|
return;
|
|
3067
3445
|
}
|
|
@@ -3122,7 +3500,7 @@ function useGoal(sessionId, options = {}) {
|
|
|
3122
3500
|
enabled,
|
|
3123
3501
|
...sharedEvents !== void 0 ? { events: sharedEvents } : {}
|
|
3124
3502
|
});
|
|
3125
|
-
const pause =
|
|
3503
|
+
const pause = useCallback7(
|
|
3126
3504
|
async (rationale) => {
|
|
3127
3505
|
if (!sessionId) {
|
|
3128
3506
|
return null;
|
|
@@ -3138,7 +3516,7 @@ function useGoal(sessionId, options = {}) {
|
|
|
3138
3516
|
},
|
|
3139
3517
|
[client, workspaceId, sessionId, mutation.run]
|
|
3140
3518
|
);
|
|
3141
|
-
const resume =
|
|
3519
|
+
const resume = useCallback7(async () => {
|
|
3142
3520
|
if (!sessionId) {
|
|
3143
3521
|
return null;
|
|
3144
3522
|
}
|
|
@@ -3165,12 +3543,12 @@ function useGoal(sessionId, options = {}) {
|
|
|
3165
3543
|
}
|
|
3166
3544
|
|
|
3167
3545
|
// src/hooks/use-session-control.ts
|
|
3168
|
-
import { useCallback as
|
|
3546
|
+
import { useCallback as useCallback8 } from "react";
|
|
3169
3547
|
function useSessionControl(sessionId, options = {}) {
|
|
3170
3548
|
const { client, workspaceId } = useOpenGeni(options);
|
|
3171
3549
|
const interruptMutation = useMutationRunner();
|
|
3172
3550
|
const approvalMutation = useMutationRunner();
|
|
3173
|
-
const interrupt =
|
|
3551
|
+
const interrupt = useCallback8(
|
|
3174
3552
|
async (reason) => {
|
|
3175
3553
|
if (!sessionId) {
|
|
3176
3554
|
return null;
|
|
@@ -3179,7 +3557,7 @@ function useSessionControl(sessionId, options = {}) {
|
|
|
3179
3557
|
},
|
|
3180
3558
|
[client, workspaceId, sessionId, interruptMutation.run]
|
|
3181
3559
|
);
|
|
3182
|
-
const decide =
|
|
3560
|
+
const decide = useCallback8(
|
|
3183
3561
|
async (approvalId, decision, message) => {
|
|
3184
3562
|
if (!sessionId) {
|
|
3185
3563
|
return null;
|
|
@@ -3192,16 +3570,16 @@ function useSessionControl(sessionId, options = {}) {
|
|
|
3192
3570
|
},
|
|
3193
3571
|
[client, workspaceId, sessionId, approvalMutation.run]
|
|
3194
3572
|
);
|
|
3195
|
-
const approve =
|
|
3573
|
+
const approve = useCallback8(
|
|
3196
3574
|
async (approvalId, message) => await decide(approvalId, "approve", message),
|
|
3197
3575
|
[decide]
|
|
3198
3576
|
);
|
|
3199
|
-
const reject =
|
|
3577
|
+
const reject = useCallback8(
|
|
3200
3578
|
async (approvalId, message) => await decide(approvalId, "reject", message),
|
|
3201
3579
|
[decide]
|
|
3202
3580
|
);
|
|
3203
3581
|
const error = approvalMutation.mutationError ?? interruptMutation.mutationError;
|
|
3204
|
-
const clearError =
|
|
3582
|
+
const clearError = useCallback8(() => {
|
|
3205
3583
|
interruptMutation.clearMutationError();
|
|
3206
3584
|
approvalMutation.clearMutationError();
|
|
3207
3585
|
}, [interruptMutation.clearMutationError, approvalMutation.clearMutationError]);
|
|
@@ -3217,11 +3595,11 @@ function useSessionControl(sessionId, options = {}) {
|
|
|
3217
3595
|
}
|
|
3218
3596
|
|
|
3219
3597
|
// src/hooks/use-scheduled-tasks.ts
|
|
3220
|
-
import { useCallback as
|
|
3598
|
+
import { useCallback as useCallback9 } from "react";
|
|
3221
3599
|
function useScheduledTasks(options = {}) {
|
|
3222
3600
|
const { client, workspaceId } = useOpenGeni(options);
|
|
3223
3601
|
const limit = options.limit;
|
|
3224
|
-
const load =
|
|
3602
|
+
const load = useCallback9(
|
|
3225
3603
|
async () => await client.listScheduledTasks(workspaceId, limit !== void 0 ? { limit } : {}),
|
|
3226
3604
|
[client, workspaceId, limit]
|
|
3227
3605
|
);
|
|
@@ -3230,11 +3608,11 @@ function useScheduledTasks(options = {}) {
|
|
|
3230
3608
|
}
|
|
3231
3609
|
|
|
3232
3610
|
// src/hooks/use-workspace-sessions.ts
|
|
3233
|
-
import { useCallback as
|
|
3611
|
+
import { useCallback as useCallback10 } from "react";
|
|
3234
3612
|
function useWorkspaceSessions(options = {}) {
|
|
3235
3613
|
const { client, workspaceId } = useOpenGeni(options);
|
|
3236
3614
|
const limit = options.limit;
|
|
3237
|
-
const load =
|
|
3615
|
+
const load = useCallback10(
|
|
3238
3616
|
async () => await client.listSessions(workspaceId, limit !== void 0 ? { limit } : {}),
|
|
3239
3617
|
[client, workspaceId, limit]
|
|
3240
3618
|
);
|
|
@@ -3243,13 +3621,13 @@ function useWorkspaceSessions(options = {}) {
|
|
|
3243
3621
|
}
|
|
3244
3622
|
|
|
3245
3623
|
// src/hooks/use-environments.ts
|
|
3246
|
-
import { useCallback as
|
|
3624
|
+
import { useCallback as useCallback11 } from "react";
|
|
3247
3625
|
function useEnvironments(options = {}) {
|
|
3248
3626
|
const { client, workspaceId } = useOpenGeni(options);
|
|
3249
|
-
const load =
|
|
3627
|
+
const load = useCallback11(async () => await client.listEnvironments(workspaceId), [client, workspaceId]);
|
|
3250
3628
|
const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });
|
|
3251
3629
|
const mutation = useMutationRunner();
|
|
3252
|
-
const create =
|
|
3630
|
+
const create = useCallback11(
|
|
3253
3631
|
async (request) => {
|
|
3254
3632
|
const result = await mutation.run(() => client.createEnvironment(workspaceId, request));
|
|
3255
3633
|
if (result) {
|
|
@@ -3259,7 +3637,7 @@ function useEnvironments(options = {}) {
|
|
|
3259
3637
|
},
|
|
3260
3638
|
[client, workspaceId, mutation.run, state.refresh]
|
|
3261
3639
|
);
|
|
3262
|
-
const update =
|
|
3640
|
+
const update = useCallback11(
|
|
3263
3641
|
async (environmentId, request) => {
|
|
3264
3642
|
const result = await mutation.run(() => client.updateEnvironment(workspaceId, environmentId, request));
|
|
3265
3643
|
if (result) {
|
|
@@ -3269,7 +3647,7 @@ function useEnvironments(options = {}) {
|
|
|
3269
3647
|
},
|
|
3270
3648
|
[client, workspaceId, mutation.run, state.refresh]
|
|
3271
3649
|
);
|
|
3272
|
-
const remove =
|
|
3650
|
+
const remove = useCallback11(
|
|
3273
3651
|
async (environmentId) => {
|
|
3274
3652
|
const result = await mutation.run(async () => {
|
|
3275
3653
|
await client.deleteEnvironment(workspaceId, environmentId);
|
|
@@ -3282,7 +3660,7 @@ function useEnvironments(options = {}) {
|
|
|
3282
3660
|
},
|
|
3283
3661
|
[client, workspaceId, mutation.run, state.refresh]
|
|
3284
3662
|
);
|
|
3285
|
-
const setVariable =
|
|
3663
|
+
const setVariable = useCallback11(
|
|
3286
3664
|
async (environmentId, name, value) => {
|
|
3287
3665
|
const result = await mutation.run(() => client.setEnvironmentVariable(workspaceId, environmentId, name, value));
|
|
3288
3666
|
if (result) {
|
|
@@ -3292,7 +3670,7 @@ function useEnvironments(options = {}) {
|
|
|
3292
3670
|
},
|
|
3293
3671
|
[client, workspaceId, mutation.run, state.refresh]
|
|
3294
3672
|
);
|
|
3295
|
-
const deleteVariable =
|
|
3673
|
+
const deleteVariable = useCallback11(
|
|
3296
3674
|
async (environmentId, name) => {
|
|
3297
3675
|
const result = await mutation.run(async () => {
|
|
3298
3676
|
await client.deleteEnvironmentVariable(workspaceId, environmentId, name);
|
|
@@ -3322,13 +3700,13 @@ function useEnvironments(options = {}) {
|
|
|
3322
3700
|
}
|
|
3323
3701
|
|
|
3324
3702
|
// src/hooks/use-packs.ts
|
|
3325
|
-
import { useCallback as
|
|
3703
|
+
import { useCallback as useCallback12 } from "react";
|
|
3326
3704
|
function usePacks(options = {}) {
|
|
3327
3705
|
const { client, workspaceId } = useOpenGeni(options);
|
|
3328
|
-
const load =
|
|
3706
|
+
const load = useCallback12(async () => await client.listPacks(workspaceId), [client, workspaceId]);
|
|
3329
3707
|
const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });
|
|
3330
3708
|
const mutation = useMutationRunner();
|
|
3331
|
-
const register =
|
|
3709
|
+
const register = useCallback12(
|
|
3332
3710
|
async (manifest) => {
|
|
3333
3711
|
const result = await mutation.run(() => client.registerPack(workspaceId, manifest));
|
|
3334
3712
|
if (result) {
|
|
@@ -3338,7 +3716,7 @@ function usePacks(options = {}) {
|
|
|
3338
3716
|
},
|
|
3339
3717
|
[client, workspaceId, mutation.run, state.refresh]
|
|
3340
3718
|
);
|
|
3341
|
-
const enable =
|
|
3719
|
+
const enable = useCallback12(
|
|
3342
3720
|
async (packId, request = {}) => {
|
|
3343
3721
|
const result = await mutation.run(() => client.enablePack(workspaceId, packId, request));
|
|
3344
3722
|
if (result) {
|
|
@@ -3348,7 +3726,7 @@ function usePacks(options = {}) {
|
|
|
3348
3726
|
},
|
|
3349
3727
|
[client, workspaceId, mutation.run, state.refresh]
|
|
3350
3728
|
);
|
|
3351
|
-
const remove =
|
|
3729
|
+
const remove = useCallback12(
|
|
3352
3730
|
async (packId) => {
|
|
3353
3731
|
const result = await mutation.run(async () => {
|
|
3354
3732
|
await client.deletePack(workspaceId, packId);
|
|
@@ -3362,7 +3740,7 @@ function usePacks(options = {}) {
|
|
|
3362
3740
|
[client, workspaceId, mutation.run, state.refresh]
|
|
3363
3741
|
);
|
|
3364
3742
|
const installations = state.data?.installations ?? [];
|
|
3365
|
-
const installationFor =
|
|
3743
|
+
const installationFor = useCallback12(
|
|
3366
3744
|
(packId) => installations.find((installation) => installation.packId === packId) ?? null,
|
|
3367
3745
|
[installations]
|
|
3368
3746
|
);
|
|
@@ -3383,13 +3761,13 @@ function usePacks(options = {}) {
|
|
|
3383
3761
|
}
|
|
3384
3762
|
|
|
3385
3763
|
// src/hooks/use-workspaces.ts
|
|
3386
|
-
import { useCallback as
|
|
3764
|
+
import { useCallback as useCallback13 } from "react";
|
|
3387
3765
|
function useWorkspaces(options = {}) {
|
|
3388
3766
|
const client = useOpenGeniClient(options);
|
|
3389
|
-
const load =
|
|
3767
|
+
const load = useCallback13(async () => await client.listWorkspaces(), [client]);
|
|
3390
3768
|
const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });
|
|
3391
3769
|
const mutation = useMutationRunner();
|
|
3392
|
-
const create =
|
|
3770
|
+
const create = useCallback13(
|
|
3393
3771
|
async (request) => {
|
|
3394
3772
|
const result = await mutation.run(() => client.createWorkspace(request));
|
|
3395
3773
|
if (result) {
|
|
@@ -3399,7 +3777,7 @@ function useWorkspaces(options = {}) {
|
|
|
3399
3777
|
},
|
|
3400
3778
|
[client, mutation.run, state.refresh]
|
|
3401
3779
|
);
|
|
3402
|
-
const update =
|
|
3780
|
+
const update = useCallback13(
|
|
3403
3781
|
async (workspaceId, request) => {
|
|
3404
3782
|
const result = await mutation.run(() => client.updateWorkspace(workspaceId, request));
|
|
3405
3783
|
if (result) {
|
|
@@ -3423,12 +3801,12 @@ function useWorkspaces(options = {}) {
|
|
|
3423
3801
|
}
|
|
3424
3802
|
|
|
3425
3803
|
// src/hooks/use-billing-usage.ts
|
|
3426
|
-
import { useCallback as
|
|
3804
|
+
import { useCallback as useCallback14 } from "react";
|
|
3427
3805
|
function useBillingUsage(options = {}) {
|
|
3428
3806
|
const client = useOpenGeniClient(options);
|
|
3429
3807
|
const accountId = options.accountId;
|
|
3430
3808
|
const workspaceId = options.workspaceId;
|
|
3431
|
-
const load =
|
|
3809
|
+
const load = useCallback14(
|
|
3432
3810
|
async () => await client.getBillingUsage({
|
|
3433
3811
|
...accountId !== void 0 ? { accountId } : {},
|
|
3434
3812
|
...workspaceId !== void 0 ? { workspaceId } : {}
|
|
@@ -3446,10 +3824,10 @@ function useBillingUsage(options = {}) {
|
|
|
3446
3824
|
}
|
|
3447
3825
|
|
|
3448
3826
|
// src/hooks/use-available-models.ts
|
|
3449
|
-
import { useCallback as
|
|
3827
|
+
import { useCallback as useCallback15 } from "react";
|
|
3450
3828
|
function useAvailableModels(options = {}) {
|
|
3451
3829
|
const client = useOpenGeniClient(options);
|
|
3452
|
-
const load =
|
|
3830
|
+
const load = useCallback15(async () => await client.getClientConfig(), [client]);
|
|
3453
3831
|
const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });
|
|
3454
3832
|
return {
|
|
3455
3833
|
models: state.data?.models ?? [],
|
|
@@ -3465,7 +3843,7 @@ import {
|
|
|
3465
3843
|
OpenGeniApiError as OpenGeniApiError2,
|
|
3466
3844
|
applyUrlRotation
|
|
3467
3845
|
} from "@opengeni/sdk";
|
|
3468
|
-
import { useCallback as
|
|
3846
|
+
import { useCallback as useCallback16, useEffect as useEffect7, useRef as useRef7, useState as useState13 } from "react";
|
|
3469
3847
|
function desktopAttachable(cell) {
|
|
3470
3848
|
if (cell.transport !== null) return true;
|
|
3471
3849
|
return cell.reason === "lease_cold" || cell.reason === "not_provisioned" || cell.reason === null;
|
|
@@ -3500,9 +3878,9 @@ function useSessionCapabilities(sessionId, options = {}) {
|
|
|
3500
3878
|
const [viewerCapReached, setViewerCapReached] = useState13(false);
|
|
3501
3879
|
const [viewerId, setViewerId] = useState13(null);
|
|
3502
3880
|
const [nonce, setNonce] = useState13(0);
|
|
3503
|
-
const epochRef =
|
|
3504
|
-
const viewerIdRef =
|
|
3505
|
-
const renegotiate =
|
|
3881
|
+
const epochRef = useRef7(0);
|
|
3882
|
+
const viewerIdRef = useRef7(null);
|
|
3883
|
+
const renegotiate = useCallback16(() => {
|
|
3506
3884
|
setNonce((n) => n + 1);
|
|
3507
3885
|
}, []);
|
|
3508
3886
|
useEffect7(() => {
|
|
@@ -3700,7 +4078,7 @@ import {
|
|
|
3700
4078
|
desktopSocketUrl,
|
|
3701
4079
|
nextDesktopState
|
|
3702
4080
|
} from "@opengeni/sdk";
|
|
3703
|
-
import { useEffect as useEffect9, useRef as
|
|
4081
|
+
import { useEffect as useEffect9, useRef as useRef9, useState as useState15 } from "react";
|
|
3704
4082
|
|
|
3705
4083
|
// src/lib/relay-wire.ts
|
|
3706
4084
|
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
|
|
@@ -3773,7 +4151,7 @@ function decodeStreamFrame(bytes) {
|
|
|
3773
4151
|
}
|
|
3774
4152
|
|
|
3775
4153
|
// src/hooks/use-relay-frame-stream.ts
|
|
3776
|
-
import { useEffect as useEffect8, useRef as
|
|
4154
|
+
import { useEffect as useEffect8, useRef as useRef8, useState as useState14 } from "react";
|
|
3777
4155
|
var TAG_OPEN = 1;
|
|
3778
4156
|
var TAG_OPENACK = 2;
|
|
3779
4157
|
var TAG_FRAME = 3;
|
|
@@ -3791,7 +4169,7 @@ function useRelayFrameStream(options) {
|
|
|
3791
4169
|
const [state, setState] = useState14("idle");
|
|
3792
4170
|
const [error, setError] = useState14(null);
|
|
3793
4171
|
const [nonce, setNonce] = useState14(0);
|
|
3794
|
-
const stateRef =
|
|
4172
|
+
const stateRef = useRef8("idle");
|
|
3795
4173
|
const setBoth = (next) => {
|
|
3796
4174
|
stateRef.current = next;
|
|
3797
4175
|
setState(next);
|
|
@@ -3800,7 +4178,7 @@ function useRelayFrameStream(options) {
|
|
|
3800
4178
|
const transport = capability?.transport ?? null;
|
|
3801
4179
|
const url = capability?.url ?? null;
|
|
3802
4180
|
const token = capability?.token ?? null;
|
|
3803
|
-
const factoryRef =
|
|
4181
|
+
const factoryRef = useRef8(webSocketFactory);
|
|
3804
4182
|
factoryRef.current = webSocketFactory;
|
|
3805
4183
|
useEffect8(() => {
|
|
3806
4184
|
if (typeof window === "undefined") return;
|
|
@@ -3994,7 +4372,7 @@ function useDesktopStream(options) {
|
|
|
3994
4372
|
const [state, setState] = useState15("idle");
|
|
3995
4373
|
const [error, setError] = useState15(null);
|
|
3996
4374
|
const [nonce, setNonce] = useState15(0);
|
|
3997
|
-
const stateRef =
|
|
4375
|
+
const stateRef = useRef9("idle");
|
|
3998
4376
|
const setBoth = (next) => {
|
|
3999
4377
|
stateRef.current = next;
|
|
4000
4378
|
setState(next);
|
|
@@ -4004,11 +4382,11 @@ function useDesktopStream(options) {
|
|
|
4004
4382
|
const token = capability?.token ?? null;
|
|
4005
4383
|
const transport = capability?.transport ?? null;
|
|
4006
4384
|
const mode = capability?.mode ?? "read-only";
|
|
4007
|
-
const rfbRef =
|
|
4008
|
-
const interactiveRef =
|
|
4009
|
-
const scaleViewportRef =
|
|
4010
|
-
const modeRef =
|
|
4011
|
-
const rfbFactoryRef =
|
|
4385
|
+
const rfbRef = useRef9(null);
|
|
4386
|
+
const interactiveRef = useRef9(interactive);
|
|
4387
|
+
const scaleViewportRef = useRef9(scaleViewport);
|
|
4388
|
+
const modeRef = useRef9(mode);
|
|
4389
|
+
const rfbFactoryRef = useRef9(rfbFactory);
|
|
4012
4390
|
interactiveRef.current = interactive;
|
|
4013
4391
|
scaleViewportRef.current = scaleViewport;
|
|
4014
4392
|
modeRef.current = mode;
|
|
@@ -4101,7 +4479,7 @@ import {
|
|
|
4101
4479
|
ttydResizeFrame,
|
|
4102
4480
|
TtydServerCommand
|
|
4103
4481
|
} from "@opengeni/sdk";
|
|
4104
|
-
import { useEffect as useEffect10, useMemo as useMemo3, useRef as
|
|
4482
|
+
import { useEffect as useEffect10, useMemo as useMemo3, useRef as useRef10, useState as useState16 } from "react";
|
|
4105
4483
|
function decodeFrame(data) {
|
|
4106
4484
|
if (typeof data === "string") {
|
|
4107
4485
|
return { command: data.charAt(0), payload: data.slice(1) };
|
|
@@ -4114,13 +4492,13 @@ function decodeFrame(data) {
|
|
|
4114
4492
|
function useTerminalStream(options) {
|
|
4115
4493
|
const { capability, onOutput, onTitle, initialCols, initialRows } = options;
|
|
4116
4494
|
const [status, setStatus] = useState16("closed");
|
|
4117
|
-
const wsRef =
|
|
4118
|
-
const sizeRef =
|
|
4495
|
+
const wsRef = useRef10(null);
|
|
4496
|
+
const sizeRef = useRef10({
|
|
4119
4497
|
cols: initialCols ?? 80,
|
|
4120
4498
|
rows: initialRows ?? 24
|
|
4121
4499
|
});
|
|
4122
|
-
const onOutputRef =
|
|
4123
|
-
const onTitleRef =
|
|
4500
|
+
const onOutputRef = useRef10(onOutput);
|
|
4501
|
+
const onTitleRef = useRef10(onTitle);
|
|
4124
4502
|
onOutputRef.current = onOutput;
|
|
4125
4503
|
onTitleRef.current = onTitle;
|
|
4126
4504
|
const transport = capability?.transport ?? null;
|
|
@@ -4223,7 +4601,7 @@ function useTerminalStream(options) {
|
|
|
4223
4601
|
|
|
4224
4602
|
// src/hooks/use-sandbox-terminal.ts
|
|
4225
4603
|
import { OpenGeniApiError as OpenGeniApiError3 } from "@opengeni/sdk";
|
|
4226
|
-
import { useCallback as
|
|
4604
|
+
import { useCallback as useCallback17, useEffect as useEffect11, useMemo as useMemo4, useRef as useRef11, useState as useState17 } from "react";
|
|
4227
4605
|
function useSandboxTerminal(sessionId, options) {
|
|
4228
4606
|
const { client, workspaceId } = useOpenGeni(options);
|
|
4229
4607
|
const includeAgentFirehose = options.includeAgentFirehose ?? true;
|
|
@@ -4233,7 +4611,7 @@ function useSandboxTerminal(sessionId, options) {
|
|
|
4233
4611
|
const [openedPtyId, setOpenedPtyId] = useState17(null);
|
|
4234
4612
|
const [openError, setOpenError] = useState17(null);
|
|
4235
4613
|
const [reopenNonce, setReopenNonce] = useState17(0);
|
|
4236
|
-
const openInFlight =
|
|
4614
|
+
const openInFlight = useRef11(false);
|
|
4237
4615
|
const boxWarm = liveness === void 0 || liveness === "warm" || liveness === "draining";
|
|
4238
4616
|
useEffect11(() => {
|
|
4239
4617
|
if (!interactive || !sessionId || ptyFilter || !boxWarm) return;
|
|
@@ -4323,7 +4701,7 @@ function useSandboxTerminal(sessionId, options) {
|
|
|
4323
4701
|
});
|
|
4324
4702
|
};
|
|
4325
4703
|
}, [client, workspaceId, sessionId, activePtyId, canWrite, openedPtyId]);
|
|
4326
|
-
const close =
|
|
4704
|
+
const close = useCallback17(() => {
|
|
4327
4705
|
if (!activePtyId || !sessionId) return;
|
|
4328
4706
|
void client.terminalPtyClose(workspaceId, sessionId, { ptyId: activePtyId }).catch(() => {
|
|
4329
4707
|
});
|
|
@@ -4339,7 +4717,7 @@ function useSandboxTerminal(sessionId, options) {
|
|
|
4339
4717
|
}
|
|
4340
4718
|
|
|
4341
4719
|
// src/hooks/use-sandbox-files.ts
|
|
4342
|
-
import { useCallback as
|
|
4720
|
+
import { useCallback as useCallback18, useEffect as useEffect12, useRef as useRef12, useState as useState18 } from "react";
|
|
4343
4721
|
function parentOf(path) {
|
|
4344
4722
|
const i = path.lastIndexOf("/");
|
|
4345
4723
|
return i <= 0 ? "" : path.slice(0, i);
|
|
@@ -4459,15 +4837,15 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4459
4837
|
const enabled = (options.enabled ?? true) && Boolean(sessionId);
|
|
4460
4838
|
const rootPath = options.rootPath ?? "";
|
|
4461
4839
|
const [tree, setTree] = useState18([]);
|
|
4462
|
-
const treeRef =
|
|
4840
|
+
const treeRef = useRef12([]);
|
|
4463
4841
|
const [loading, setLoading] = useState18(false);
|
|
4464
4842
|
const [expandingPaths, setExpandingPaths] = useState18(/* @__PURE__ */ new Set());
|
|
4465
4843
|
const [error, setError] = useState18(null);
|
|
4466
|
-
const statusRef =
|
|
4467
|
-
const ownRevisionsRef =
|
|
4844
|
+
const statusRef = useRef12(/* @__PURE__ */ new Map());
|
|
4845
|
+
const ownRevisionsRef = useRef12(/* @__PURE__ */ new Set());
|
|
4468
4846
|
const onMutationError = options.onMutationError;
|
|
4469
4847
|
treeRef.current = tree;
|
|
4470
|
-
const applyStatus =
|
|
4848
|
+
const applyStatus = useCallback18((nodes) => {
|
|
4471
4849
|
const overlay = statusRef.current;
|
|
4472
4850
|
if (overlay.size === 0) return nodes;
|
|
4473
4851
|
const walk = (list) => list.map((node) => {
|
|
@@ -4479,7 +4857,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4479
4857
|
});
|
|
4480
4858
|
return walk(nodes);
|
|
4481
4859
|
}, []);
|
|
4482
|
-
const refresh =
|
|
4860
|
+
const refresh = useCallback18(async () => {
|
|
4483
4861
|
if (!sessionId) return;
|
|
4484
4862
|
setLoading(true);
|
|
4485
4863
|
setError(null);
|
|
@@ -4505,7 +4883,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4505
4883
|
setLoading(false);
|
|
4506
4884
|
}
|
|
4507
4885
|
}, [client, workspaceId, sessionId, rootPath, applyStatus]);
|
|
4508
|
-
const expand =
|
|
4886
|
+
const expand = useCallback18(
|
|
4509
4887
|
async (path) => {
|
|
4510
4888
|
if (!sessionId) return;
|
|
4511
4889
|
setExpandingPaths((prev) => {
|
|
@@ -4530,14 +4908,14 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4530
4908
|
},
|
|
4531
4909
|
[client, workspaceId, sessionId, applyStatus]
|
|
4532
4910
|
);
|
|
4533
|
-
const readFile =
|
|
4911
|
+
const readFile = useCallback18(
|
|
4534
4912
|
async (path) => {
|
|
4535
4913
|
if (!sessionId) throw new Error("no session");
|
|
4536
4914
|
return await client.fsRead(workspaceId, sessionId, { path });
|
|
4537
4915
|
},
|
|
4538
4916
|
[client, workspaceId, sessionId]
|
|
4539
4917
|
);
|
|
4540
|
-
const reconcilePath =
|
|
4918
|
+
const reconcilePath = useCallback18(
|
|
4541
4919
|
async (path) => {
|
|
4542
4920
|
if (!sessionId) return;
|
|
4543
4921
|
if (!parentIsLoaded(treeRef.current, path)) return;
|
|
@@ -4556,7 +4934,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4556
4934
|
},
|
|
4557
4935
|
[client, workspaceId, sessionId, applyStatus]
|
|
4558
4936
|
);
|
|
4559
|
-
const runOptimistic =
|
|
4937
|
+
const runOptimistic = useCallback18(
|
|
4560
4938
|
async (opName, apply, op, reconcileParents) => {
|
|
4561
4939
|
const snapshot = treeRef.current;
|
|
4562
4940
|
setTree(applyStatus(apply(snapshot)));
|
|
@@ -4578,7 +4956,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4578
4956
|
},
|
|
4579
4957
|
[applyStatus, reconcilePath, onMutationError]
|
|
4580
4958
|
);
|
|
4581
|
-
const writeFile =
|
|
4959
|
+
const writeFile = useCallback18(
|
|
4582
4960
|
async (path, content) => {
|
|
4583
4961
|
if (!sessionId) throw new Error("no session");
|
|
4584
4962
|
const parent = parentOf(path);
|
|
@@ -4593,7 +4971,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4593
4971
|
},
|
|
4594
4972
|
[client, workspaceId, sessionId, tree, runOptimistic]
|
|
4595
4973
|
);
|
|
4596
|
-
const createFile =
|
|
4974
|
+
const createFile = useCallback18(
|
|
4597
4975
|
async (path) => {
|
|
4598
4976
|
if (!sessionId) throw new Error("no session");
|
|
4599
4977
|
const parent = parentOf(path);
|
|
@@ -4607,7 +4985,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4607
4985
|
},
|
|
4608
4986
|
[client, workspaceId, sessionId, runOptimistic]
|
|
4609
4987
|
);
|
|
4610
|
-
const createDir =
|
|
4988
|
+
const createDir = useCallback18(
|
|
4611
4989
|
async (path) => {
|
|
4612
4990
|
if (!sessionId) throw new Error("no session");
|
|
4613
4991
|
const parent = parentOf(path);
|
|
@@ -4621,7 +4999,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4621
4999
|
},
|
|
4622
5000
|
[client, workspaceId, sessionId, runOptimistic]
|
|
4623
5001
|
);
|
|
4624
|
-
const deleteEntry =
|
|
5002
|
+
const deleteEntry = useCallback18(
|
|
4625
5003
|
async (path, recursive = false) => {
|
|
4626
5004
|
if (!sessionId) throw new Error("no session");
|
|
4627
5005
|
await runOptimistic(
|
|
@@ -4633,7 +5011,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4633
5011
|
},
|
|
4634
5012
|
[client, workspaceId, sessionId, runOptimistic]
|
|
4635
5013
|
);
|
|
4636
|
-
const moveEntry =
|
|
5014
|
+
const moveEntry = useCallback18(
|
|
4637
5015
|
async (path, newPath, opts) => {
|
|
4638
5016
|
if (!sessionId) throw new Error("no session");
|
|
4639
5017
|
const from = parentOf(path);
|
|
@@ -4663,7 +5041,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4663
5041
|
}
|
|
4664
5042
|
void refresh();
|
|
4665
5043
|
}, [enabled, refresh]);
|
|
4666
|
-
const refreshGitOverlay =
|
|
5044
|
+
const refreshGitOverlay = useCallback18(async () => {
|
|
4667
5045
|
if (!sessionId) return;
|
|
4668
5046
|
try {
|
|
4669
5047
|
const status = await client.gitStatus(workspaceId, sessionId, { path: rootPath });
|
|
@@ -4679,10 +5057,10 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4679
5057
|
}
|
|
4680
5058
|
}, [client, workspaceId, sessionId, rootPath, applyStatus]);
|
|
4681
5059
|
const events = options.events;
|
|
4682
|
-
const lastSeqRef =
|
|
4683
|
-
const pendingParentsRef =
|
|
4684
|
-
const pendingGitRef =
|
|
4685
|
-
const debounceRef =
|
|
5060
|
+
const lastSeqRef = useRef12(0);
|
|
5061
|
+
const pendingParentsRef = useRef12(/* @__PURE__ */ new Set());
|
|
5062
|
+
const pendingGitRef = useRef12(false);
|
|
5063
|
+
const debounceRef = useRef12(null);
|
|
4686
5064
|
useEffect12(() => {
|
|
4687
5065
|
if (!enabled || !events) return;
|
|
4688
5066
|
let sawNew = false;
|
|
@@ -4726,7 +5104,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4726
5104
|
},
|
|
4727
5105
|
[]
|
|
4728
5106
|
);
|
|
4729
|
-
const wasLiveRef =
|
|
5107
|
+
const wasLiveRef = useRef12(false);
|
|
4730
5108
|
const liveness = options.liveness;
|
|
4731
5109
|
useEffect12(() => {
|
|
4732
5110
|
const live = liveness === "warm" || liveness === "draining";
|
|
@@ -4754,7 +5132,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4754
5132
|
}
|
|
4755
5133
|
|
|
4756
5134
|
// src/hooks/use-sandbox-git.ts
|
|
4757
|
-
import { useCallback as
|
|
5135
|
+
import { useCallback as useCallback19, useEffect as useEffect13, useRef as useRef13, useState as useState19 } from "react";
|
|
4758
5136
|
function useSandboxGit(sessionId, options = {}) {
|
|
4759
5137
|
const { client, workspaceId } = useOpenGeni(options);
|
|
4760
5138
|
const enabled = (options.enabled ?? true) && Boolean(sessionId);
|
|
@@ -4767,7 +5145,7 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
4767
5145
|
const [behind, setBehind] = useState19(0);
|
|
4768
5146
|
const [loading, setLoading] = useState19(false);
|
|
4769
5147
|
const [error, setError] = useState19(null);
|
|
4770
|
-
const refresh =
|
|
5148
|
+
const refresh = useCallback19(async () => {
|
|
4771
5149
|
if (!sessionId) return;
|
|
4772
5150
|
setLoading(true);
|
|
4773
5151
|
setError(null);
|
|
@@ -4799,7 +5177,7 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
4799
5177
|
void refresh();
|
|
4800
5178
|
}, [enabled, refresh]);
|
|
4801
5179
|
const events = options.events;
|
|
4802
|
-
const lastChangeRef =
|
|
5180
|
+
const lastChangeRef = useRef13(0);
|
|
4803
5181
|
useEffect13(() => {
|
|
4804
5182
|
if (!enabled || !events) return;
|
|
4805
5183
|
let latest = lastChangeRef.current;
|
|
@@ -5048,14 +5426,14 @@ function clearErrorMessage(cause) {
|
|
|
5048
5426
|
}
|
|
5049
5427
|
|
|
5050
5428
|
// src/hooks/use-slash-commands.ts
|
|
5051
|
-
import { useCallback as
|
|
5429
|
+
import { useCallback as useCallback20, useMemo as useMemo5, useRef as useRef14, useState as useState20 } from "react";
|
|
5052
5430
|
function useSlashCommands(options) {
|
|
5053
5431
|
const { commands, context, handlers, value, setValue } = options;
|
|
5054
5432
|
const [highlight, setHighlight] = useState20(0);
|
|
5055
5433
|
const [dismissedValue, setDismissedValue] = useState20(null);
|
|
5056
5434
|
const dismissed = dismissedValue !== null && dismissedValue === value;
|
|
5057
|
-
const navigatedRef =
|
|
5058
|
-
const navTokenRef =
|
|
5435
|
+
const navigatedRef = useRef14(false);
|
|
5436
|
+
const navTokenRef = useRef14(value);
|
|
5059
5437
|
if (navTokenRef.current !== value) {
|
|
5060
5438
|
navTokenRef.current = value;
|
|
5061
5439
|
navigatedRef.current = false;
|
|
@@ -5088,7 +5466,7 @@ function useSlashCommands(options) {
|
|
|
5088
5466
|
const isCommandDraft = parsed !== null && items.length > 0;
|
|
5089
5467
|
const clampedHighlight = items.length === 0 ? 0 : Math.min(highlight, items.length - 1);
|
|
5090
5468
|
const activeArgHint = activeCommand ? argHint(activeCommand.args) : "";
|
|
5091
|
-
const buildContext =
|
|
5469
|
+
const buildContext = useCallback20(
|
|
5092
5470
|
(command) => {
|
|
5093
5471
|
if (!context) {
|
|
5094
5472
|
return null;
|
|
@@ -5097,7 +5475,7 @@ function useSlashCommands(options) {
|
|
|
5097
5475
|
},
|
|
5098
5476
|
[context, handlers]
|
|
5099
5477
|
);
|
|
5100
|
-
const execute =
|
|
5478
|
+
const execute = useCallback20(
|
|
5101
5479
|
async (command, args) => {
|
|
5102
5480
|
const ctx = buildContext(command);
|
|
5103
5481
|
if (!ctx) {
|
|
@@ -5117,20 +5495,20 @@ function useSlashCommands(options) {
|
|
|
5117
5495
|
},
|
|
5118
5496
|
[buildContext, setValue]
|
|
5119
5497
|
);
|
|
5120
|
-
const autocomplete =
|
|
5498
|
+
const autocomplete = useCallback20(
|
|
5121
5499
|
(command) => {
|
|
5122
5500
|
setValue(`/${command.name} `);
|
|
5123
5501
|
setHighlight(0);
|
|
5124
5502
|
},
|
|
5125
5503
|
[setValue]
|
|
5126
5504
|
);
|
|
5127
|
-
const autocompleteHighlighted =
|
|
5505
|
+
const autocompleteHighlighted = useCallback20(() => {
|
|
5128
5506
|
const command = items[clampedHighlight];
|
|
5129
5507
|
if (command) {
|
|
5130
5508
|
autocomplete(command);
|
|
5131
5509
|
}
|
|
5132
5510
|
}, [items, clampedHighlight, autocomplete]);
|
|
5133
|
-
const runResolved =
|
|
5511
|
+
const runResolved = useCallback20(
|
|
5134
5512
|
async (command, options2) => {
|
|
5135
5513
|
if (!parsed) {
|
|
5136
5514
|
return;
|
|
@@ -5153,7 +5531,7 @@ function useSlashCommands(options) {
|
|
|
5153
5531
|
},
|
|
5154
5532
|
[parsed, activeCommand, autocomplete, execute]
|
|
5155
5533
|
);
|
|
5156
|
-
const runHighlighted =
|
|
5534
|
+
const runHighlighted = useCallback20(async () => {
|
|
5157
5535
|
if (!parsed) {
|
|
5158
5536
|
return;
|
|
5159
5537
|
}
|
|
@@ -5172,7 +5550,7 @@ function useSlashCommands(options) {
|
|
|
5172
5550
|
}
|
|
5173
5551
|
await runResolved(command);
|
|
5174
5552
|
}, [parsed, activeCommand, items, clampedHighlight, runResolved]);
|
|
5175
|
-
const runAt =
|
|
5553
|
+
const runAt = useCallback20(
|
|
5176
5554
|
async (index) => {
|
|
5177
5555
|
const command = items[index];
|
|
5178
5556
|
if (!command) {
|
|
@@ -5182,8 +5560,8 @@ function useSlashCommands(options) {
|
|
|
5182
5560
|
},
|
|
5183
5561
|
[items, runResolved]
|
|
5184
5562
|
);
|
|
5185
|
-
const runningRef =
|
|
5186
|
-
const onKeyDown =
|
|
5563
|
+
const runningRef = useRef14(false);
|
|
5564
|
+
const onKeyDown = useCallback20(
|
|
5187
5565
|
(event) => {
|
|
5188
5566
|
if (!open) {
|
|
5189
5567
|
return false;
|
|
@@ -5323,9 +5701,9 @@ function CommandPalette({ open, items, highlight, onHighlight, onRun, argHintTex
|
|
|
5323
5701
|
}
|
|
5324
5702
|
|
|
5325
5703
|
// src/components/chat-composer.tsx
|
|
5326
|
-
import { ArrowUpIcon, FileIcon, ImageIcon as ImageIcon2, LoaderCircleIcon, PaperclipIcon, SquareIcon, XIcon as XIcon2 } from "lucide-react";
|
|
5704
|
+
import { ArrowUpIcon, FileIcon, ImageIcon as ImageIcon2, LoaderCircleIcon, PaperclipIcon, RotateCwIcon, SquareIcon, XIcon as XIcon2 } from "lucide-react";
|
|
5327
5705
|
import { AnimatePresence as AnimatePresence3, motion as motion3 } from "motion/react";
|
|
5328
|
-
import { useCallback as
|
|
5706
|
+
import { useCallback as useCallback21, useEffect as useEffect14, useId as useId2, useMemo as useMemo7, useRef as useRef15, useState as useState21 } from "react";
|
|
5329
5707
|
|
|
5330
5708
|
// src/components/model-picker.tsx
|
|
5331
5709
|
import { ChevronDownIcon } from "lucide-react";
|
|
@@ -5402,15 +5780,15 @@ function ChatComposer({
|
|
|
5402
5780
|
commandContext,
|
|
5403
5781
|
onClearView
|
|
5404
5782
|
}) {
|
|
5405
|
-
const textareaRef =
|
|
5406
|
-
const fileInputRef =
|
|
5783
|
+
const textareaRef = useRef15(null);
|
|
5784
|
+
const fileInputRef = useRef15(null);
|
|
5407
5785
|
const active = status != null && ACTIVE_STATUSES.has(status);
|
|
5408
5786
|
const blockedByUpload = attachments?.uploading === true;
|
|
5409
5787
|
const hasReadyAttachment = (attachments?.readyResources.length ?? 0) > 0;
|
|
5410
5788
|
const canSend = (composer.canSend || hasReadyAttachment) && !blockedByUpload && !composer.sending;
|
|
5411
5789
|
const [dragging, setDragging] = useState21(false);
|
|
5412
5790
|
const dragCarriesFiles = (event) => event.dataTransfer != null && [...event.dataTransfer.types].includes("Files");
|
|
5413
|
-
const handleDragOver =
|
|
5791
|
+
const handleDragOver = useCallback21(
|
|
5414
5792
|
(event) => {
|
|
5415
5793
|
if (!attachments || !dragCarriesFiles(event)) {
|
|
5416
5794
|
return;
|
|
@@ -5420,7 +5798,7 @@ function ChatComposer({
|
|
|
5420
5798
|
},
|
|
5421
5799
|
[attachments]
|
|
5422
5800
|
);
|
|
5423
|
-
const handleDragLeave =
|
|
5801
|
+
const handleDragLeave = useCallback21(
|
|
5424
5802
|
(event) => {
|
|
5425
5803
|
if (!attachments) {
|
|
5426
5804
|
return;
|
|
@@ -5432,7 +5810,7 @@ function ChatComposer({
|
|
|
5432
5810
|
},
|
|
5433
5811
|
[attachments]
|
|
5434
5812
|
);
|
|
5435
|
-
const handleDrop =
|
|
5813
|
+
const handleDrop = useCallback21(
|
|
5436
5814
|
(event) => {
|
|
5437
5815
|
if (!attachments || !dragCarriesFiles(event)) {
|
|
5438
5816
|
return;
|
|
@@ -5449,7 +5827,7 @@ function ChatComposer({
|
|
|
5449
5827
|
const [helpOpen, setHelpOpen] = useState21(false);
|
|
5450
5828
|
const [confirmState, setConfirmState] = useState21(null);
|
|
5451
5829
|
const listboxId = useId2();
|
|
5452
|
-
const resize =
|
|
5830
|
+
const resize = useCallback21(() => {
|
|
5453
5831
|
const textarea = textareaRef.current;
|
|
5454
5832
|
if (!textarea) {
|
|
5455
5833
|
return;
|
|
@@ -5518,14 +5896,14 @@ function ChatComposer({
|
|
|
5518
5896
|
void composer.send();
|
|
5519
5897
|
}
|
|
5520
5898
|
};
|
|
5521
|
-
const handlePaste =
|
|
5899
|
+
const handlePaste = useCallback21(
|
|
5522
5900
|
(event) => {
|
|
5523
5901
|
onPaste?.(event);
|
|
5524
5902
|
attachments?.addFromPaste(event);
|
|
5525
5903
|
},
|
|
5526
5904
|
[onPaste, attachments]
|
|
5527
5905
|
);
|
|
5528
|
-
const handleFileChange =
|
|
5906
|
+
const handleFileChange = useCallback21(
|
|
5529
5907
|
(event) => {
|
|
5530
5908
|
if (event.target.files) {
|
|
5531
5909
|
attachments?.addFiles(event.target.files);
|
|
@@ -5545,217 +5923,258 @@ function ChatComposer({
|
|
|
5545
5923
|
[commands, commandContext]
|
|
5546
5924
|
);
|
|
5547
5925
|
const activeNotice = notice ?? (composer.error ? { tone: "error", message: composer.error.message || "Sending failed \u2014 your draft is still here. Try again." } : null);
|
|
5548
|
-
return
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
palette.
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
"div",
|
|
5582
|
-
{
|
|
5583
|
-
"aria-hidden": true,
|
|
5584
|
-
className: cn(
|
|
5585
|
-
"pointer-events-none absolute inset-0 z-10 flex items-center justify-center",
|
|
5586
|
-
"rounded-og-lg bg-og-surface-1/85 text-sm font-medium text-og-accent backdrop-blur-[1px]"
|
|
5587
|
-
),
|
|
5588
|
-
children: /* @__PURE__ */ jsxs10("span", { className: "inline-flex items-center gap-2", children: [
|
|
5589
|
-
/* @__PURE__ */ jsx12(PaperclipIcon, { className: "size-4" }),
|
|
5590
|
-
"Drop files to attach"
|
|
5591
|
-
] })
|
|
5592
|
-
}
|
|
5593
|
-
) : null,
|
|
5594
|
-
attachments && attachments.attachments.length > 0 ? /* @__PURE__ */ jsx12(AttachmentChips, { attachments: attachments.attachments, onRemove: attachments.remove }) : null,
|
|
5595
|
-
header,
|
|
5596
|
-
/* @__PURE__ */ jsx12(
|
|
5597
|
-
"textarea",
|
|
5598
|
-
{
|
|
5599
|
-
ref: textareaRef,
|
|
5600
|
-
rows: 1,
|
|
5601
|
-
value: composer.value,
|
|
5602
|
-
onChange: (event) => composer.setValue(event.target.value),
|
|
5603
|
-
onKeyDown,
|
|
5604
|
-
onPaste: handlePaste,
|
|
5605
|
-
placeholder: placeholder ?? "Message the agent\u2026",
|
|
5606
|
-
disabled,
|
|
5607
|
-
autoFocus,
|
|
5608
|
-
"aria-label": "Message the agent",
|
|
5609
|
-
role: paletteEnabled && palette.open ? "combobox" : void 0,
|
|
5610
|
-
"aria-expanded": paletteEnabled ? palette.open : void 0,
|
|
5611
|
-
"aria-controls": paletteEnabled && palette.open ? listboxId : void 0,
|
|
5612
|
-
"aria-activedescendant": paletteEnabled && palette.open ? `${listboxId}-option-${palette.highlight}` : void 0,
|
|
5613
|
-
className: cn(
|
|
5614
|
-
"block w-full resize-none bg-transparent px-4 pt-3.5 pb-1 text-[15px] leading-6",
|
|
5615
|
-
// The wrapper owns the whole-composer focus affordance (focus-within
|
|
5616
|
-
// border + soft glow). Suppress any self-scoped focus outline on the
|
|
5617
|
-
// textarea itself: `focus:outline-none` alone only sets outline-style
|
|
5618
|
-
// on `:focus`, which a host app's zero-specificity
|
|
5619
|
-
// `:where(...):focus-visible { outline: ... }` base rule re-applies as
|
|
5620
|
-
// the full shorthand. `focus-visible:outline-none` matches the same
|
|
5621
|
-
// state at class specificity and wins, so no second highlight (the
|
|
5622
|
-
// top-half rectangle bounded to the textarea box) ever paints.
|
|
5623
|
-
"text-og-fg placeholder:text-og-fg-subtle focus:outline-none focus-visible:outline-none",
|
|
5624
|
-
"disabled:cursor-not-allowed disabled:opacity-60"
|
|
5625
|
-
)
|
|
5626
|
-
}
|
|
5926
|
+
return (
|
|
5927
|
+
// Respect the iOS home-indicator inset so the sticky composer never sits
|
|
5928
|
+
// under it (0 on non-notch devices and desktop, so it's inert there).
|
|
5929
|
+
/* @__PURE__ */ jsxs10("div", { className: cn("og-root", className), style: { paddingBottom: "env(safe-area-inset-bottom)" }, children: [
|
|
5930
|
+
/* @__PURE__ */ jsxs10("div", { className: "relative", children: [
|
|
5931
|
+
paletteEnabled ? /* @__PURE__ */ jsx12(
|
|
5932
|
+
CommandPalette,
|
|
5933
|
+
{
|
|
5934
|
+
open: palette.open && confirmState === null,
|
|
5935
|
+
items: palette.items,
|
|
5936
|
+
highlight: palette.highlight,
|
|
5937
|
+
onHighlight: palette.setHighlight,
|
|
5938
|
+
onRun: (index) => {
|
|
5939
|
+
palette.setHighlight(index);
|
|
5940
|
+
void palette.runAt(index);
|
|
5941
|
+
},
|
|
5942
|
+
argHintText: palette.activeArgHint,
|
|
5943
|
+
listboxId
|
|
5944
|
+
}
|
|
5945
|
+
) : null,
|
|
5946
|
+
/* @__PURE__ */ jsxs10(
|
|
5947
|
+
"div",
|
|
5948
|
+
{
|
|
5949
|
+
onDragOver: attachments ? handleDragOver : void 0,
|
|
5950
|
+
onDragLeave: attachments ? handleDragLeave : void 0,
|
|
5951
|
+
onDrop: attachments ? handleDrop : void 0,
|
|
5952
|
+
className: cn(
|
|
5953
|
+
"relative rounded-og-lg border border-og-border bg-og-surface-1 shadow-og-sm",
|
|
5954
|
+
"transition-[border-color,box-shadow] duration-200",
|
|
5955
|
+
"focus-within:border-og-accent/60 focus-within:shadow-og-glow",
|
|
5956
|
+
// While files are dragged over, swap to a dashed accent border to
|
|
5957
|
+
// signal a live drop target (the overlay carries the label).
|
|
5958
|
+
dragging && "border-dashed border-og-accent"
|
|
5627
5959
|
),
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
attachments || models || controlsStart ? /* @__PURE__ */ jsxs10("span", { className: "flex min-w-0 items-center gap-1.5", children: [
|
|
5637
|
-
attachments ? /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
5638
|
-
/* @__PURE__ */ jsx12(
|
|
5639
|
-
"input",
|
|
5640
|
-
{
|
|
5641
|
-
ref: fileInputRef,
|
|
5642
|
-
type: "file",
|
|
5643
|
-
multiple: true,
|
|
5644
|
-
className: "hidden",
|
|
5645
|
-
onChange: handleFileChange
|
|
5646
|
-
}
|
|
5960
|
+
children: [
|
|
5961
|
+
dragging ? /* @__PURE__ */ jsx12(
|
|
5962
|
+
"div",
|
|
5963
|
+
{
|
|
5964
|
+
"aria-hidden": true,
|
|
5965
|
+
className: cn(
|
|
5966
|
+
"pointer-events-none absolute inset-0 z-10 flex items-center justify-center",
|
|
5967
|
+
"rounded-og-lg bg-og-surface-1/85 text-sm font-medium text-og-accent backdrop-blur-[1px]"
|
|
5647
5968
|
),
|
|
5969
|
+
children: /* @__PURE__ */ jsxs10("span", { className: "inline-flex items-center gap-2", children: [
|
|
5970
|
+
/* @__PURE__ */ jsx12(PaperclipIcon, { className: "size-4" }),
|
|
5971
|
+
"Drop files to attach"
|
|
5972
|
+
] })
|
|
5973
|
+
}
|
|
5974
|
+
) : null,
|
|
5975
|
+
attachments && attachments.attachments.length > 0 ? /* @__PURE__ */ jsx12(
|
|
5976
|
+
AttachmentChips,
|
|
5977
|
+
{
|
|
5978
|
+
attachments: attachments.attachments,
|
|
5979
|
+
onRemove: attachments.remove,
|
|
5980
|
+
onRetry: attachments.retry
|
|
5981
|
+
}
|
|
5982
|
+
) : null,
|
|
5983
|
+
header,
|
|
5984
|
+
/* @__PURE__ */ jsx12(
|
|
5985
|
+
"textarea",
|
|
5986
|
+
{
|
|
5987
|
+
ref: textareaRef,
|
|
5988
|
+
rows: 1,
|
|
5989
|
+
value: composer.value,
|
|
5990
|
+
onChange: (event) => composer.setValue(event.target.value),
|
|
5991
|
+
onKeyDown,
|
|
5992
|
+
onPaste: handlePaste,
|
|
5993
|
+
placeholder: placeholder ?? "Message the agent\u2026",
|
|
5994
|
+
disabled,
|
|
5995
|
+
autoFocus,
|
|
5996
|
+
"aria-label": "Message the agent",
|
|
5997
|
+
role: paletteEnabled && palette.open ? "combobox" : void 0,
|
|
5998
|
+
"aria-expanded": paletteEnabled ? palette.open : void 0,
|
|
5999
|
+
"aria-controls": paletteEnabled && palette.open ? listboxId : void 0,
|
|
6000
|
+
"aria-activedescendant": paletteEnabled && palette.open ? `${listboxId}-option-${palette.highlight}` : void 0,
|
|
6001
|
+
className: cn(
|
|
6002
|
+
// Font size steps up to 16px below `md` so iOS never zooms the
|
|
6003
|
+
// viewport on focus; desktop keeps the 15px og-md rhythm.
|
|
6004
|
+
"block w-full resize-none bg-transparent px-4 pt-3.5 pb-1 text-base leading-6 md:text-og-md",
|
|
6005
|
+
// The wrapper owns the whole-composer focus affordance (focus-within
|
|
6006
|
+
// border + soft glow). Suppress any self-scoped focus outline on the
|
|
6007
|
+
// textarea itself: `focus:outline-none` alone only sets outline-style
|
|
6008
|
+
// on `:focus`, which a host app's zero-specificity
|
|
6009
|
+
// `:where(...):focus-visible { outline: ... }` base rule re-applies as
|
|
6010
|
+
// the full shorthand. `focus-visible:outline-none` matches the same
|
|
6011
|
+
// state at class specificity and wins, so no second highlight (the
|
|
6012
|
+
// top-half rectangle bounded to the textarea box) ever paints.
|
|
6013
|
+
"text-og-fg placeholder:text-og-fg-subtle focus:outline-none focus-visible:outline-none",
|
|
6014
|
+
"disabled:cursor-not-allowed disabled:opacity-60"
|
|
6015
|
+
)
|
|
6016
|
+
}
|
|
6017
|
+
),
|
|
6018
|
+
confirmState && pendingDangerCommand ? /* @__PURE__ */ jsx12(
|
|
6019
|
+
ConfirmBar,
|
|
6020
|
+
{
|
|
6021
|
+
command: pendingDangerCommand,
|
|
6022
|
+
onCancel: () => confirmState.resolve(false),
|
|
6023
|
+
onConfirm: () => confirmState.resolve(true),
|
|
6024
|
+
returnFocusRef: textareaRef
|
|
6025
|
+
}
|
|
6026
|
+
) : /* @__PURE__ */ jsxs10("div", { className: "flex items-end gap-2 px-2.5 pb-2.5 pt-1", children: [
|
|
6027
|
+
attachments || models || controlsStart ? (
|
|
6028
|
+
// The control group wraps onto extra rows when it can't fit
|
|
6029
|
+
// (narrow viewports) instead of clipping under the rounded
|
|
6030
|
+
// corner; send/stop stays anchored bottom-right (shrink-0).
|
|
6031
|
+
/* @__PURE__ */ jsxs10("span", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-1.5", children: [
|
|
6032
|
+
attachments ? /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
6033
|
+
/* @__PURE__ */ jsx12(
|
|
6034
|
+
"input",
|
|
6035
|
+
{
|
|
6036
|
+
ref: fileInputRef,
|
|
6037
|
+
type: "file",
|
|
6038
|
+
multiple: true,
|
|
6039
|
+
className: "hidden",
|
|
6040
|
+
onChange: handleFileChange
|
|
6041
|
+
}
|
|
6042
|
+
),
|
|
6043
|
+
/* @__PURE__ */ jsx12(
|
|
6044
|
+
"button",
|
|
6045
|
+
{
|
|
6046
|
+
type: "button",
|
|
6047
|
+
disabled: disabled === true,
|
|
6048
|
+
onClick: () => fileInputRef.current?.click(),
|
|
6049
|
+
"aria-label": "Attach files",
|
|
6050
|
+
title: "Attach files",
|
|
6051
|
+
className: cn(
|
|
6052
|
+
"inline-flex size-8 items-center justify-center rounded-og-md",
|
|
6053
|
+
"text-og-fg-muted transition-colors duration-150 hover:bg-og-surface-2 hover:text-og-fg",
|
|
6054
|
+
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
6055
|
+
),
|
|
6056
|
+
children: /* @__PURE__ */ jsx12(PaperclipIcon, { className: "size-4" })
|
|
6057
|
+
}
|
|
6058
|
+
)
|
|
6059
|
+
] }) : null,
|
|
6060
|
+
models ? /* @__PURE__ */ jsx12(
|
|
6061
|
+
ModelPicker,
|
|
6062
|
+
{
|
|
6063
|
+
models,
|
|
6064
|
+
value: selectedModel,
|
|
6065
|
+
onChange: (modelId) => onSelectModel?.(modelId),
|
|
6066
|
+
disabled: disabled === true
|
|
6067
|
+
}
|
|
6068
|
+
) : null,
|
|
6069
|
+
controlsStart
|
|
6070
|
+
] })
|
|
6071
|
+
) : /* @__PURE__ */ jsx12("span", { className: "min-w-0 flex-1 px-1.5 text-og-xs text-og-fg-subtle max-sm:hidden", children: hint ?? "Enter to send \xB7 Shift+Enter for a new line \xB7 / for commands" }),
|
|
6072
|
+
/* @__PURE__ */ jsxs10("span", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: [
|
|
6073
|
+
/* @__PURE__ */ jsx12(AnimatePresence3, { initial: false, children: active ? /* @__PURE__ */ jsx12(
|
|
6074
|
+
motion3.button,
|
|
6075
|
+
{
|
|
6076
|
+
type: "button",
|
|
6077
|
+
initial: { opacity: 0, scale: 0.8 },
|
|
6078
|
+
animate: { opacity: 1, scale: 1 },
|
|
6079
|
+
exit: { opacity: 0, scale: 0.8 },
|
|
6080
|
+
transition: { duration: 0.15, ease: "easeOut" },
|
|
6081
|
+
onClick: () => void composer.interrupt(),
|
|
6082
|
+
disabled: composer.interrupting,
|
|
6083
|
+
"aria-label": "Stop the current turn",
|
|
6084
|
+
title: "Stop the current turn",
|
|
6085
|
+
className: cn(
|
|
6086
|
+
"inline-flex size-8 items-center justify-center rounded-og-md border border-og-border pointer-coarse:size-11",
|
|
6087
|
+
"bg-og-surface-2 text-og-fg-muted transition-colors duration-150",
|
|
6088
|
+
"hover:border-og-status-failed/50 hover:text-og-status-failed",
|
|
6089
|
+
"disabled:opacity-50"
|
|
6090
|
+
),
|
|
6091
|
+
children: composer.interrupting ? /* @__PURE__ */ jsx12(LoaderCircleIcon, { className: "size-3.5 animate-og-spin" }) : /* @__PURE__ */ jsx12(SquareIcon, { className: "size-3 fill-current" })
|
|
6092
|
+
},
|
|
6093
|
+
"stop"
|
|
6094
|
+
) : null }),
|
|
5648
6095
|
/* @__PURE__ */ jsx12(
|
|
5649
6096
|
"button",
|
|
5650
6097
|
{
|
|
5651
6098
|
type: "button",
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
6099
|
+
onClick: () => {
|
|
6100
|
+
if (blockedByUpload) {
|
|
6101
|
+
return;
|
|
6102
|
+
}
|
|
6103
|
+
void composer.send();
|
|
6104
|
+
},
|
|
6105
|
+
disabled: !canSend || disabled === true || commandDraftBlocked,
|
|
6106
|
+
"aria-label": "Send message",
|
|
5656
6107
|
className: cn(
|
|
5657
|
-
"inline-flex size-8 items-center justify-center rounded-og-md",
|
|
5658
|
-
"
|
|
5659
|
-
"
|
|
6108
|
+
"inline-flex size-8 items-center justify-center rounded-og-md pointer-coarse:size-11",
|
|
6109
|
+
"bg-og-accent text-og-accent-fg shadow-og-sm",
|
|
6110
|
+
"transition-[background-color,transform,opacity] duration-150 ease-og-spring",
|
|
6111
|
+
"hover:bg-og-accent-strong active:scale-95",
|
|
6112
|
+
"disabled:cursor-not-allowed disabled:bg-og-surface-3 disabled:text-og-fg-subtle disabled:shadow-none"
|
|
5660
6113
|
),
|
|
5661
|
-
children: /* @__PURE__ */ jsx12(
|
|
6114
|
+
children: composer.sending ? /* @__PURE__ */ jsx12(LoaderCircleIcon, { className: "size-4 animate-og-spin" }) : /* @__PURE__ */ jsx12(ArrowUpIcon, { className: "size-4" })
|
|
5662
6115
|
}
|
|
5663
6116
|
)
|
|
5664
|
-
] })
|
|
5665
|
-
models ? /* @__PURE__ */ jsx12(
|
|
5666
|
-
ModelPicker,
|
|
5667
|
-
{
|
|
5668
|
-
models,
|
|
5669
|
-
value: selectedModel,
|
|
5670
|
-
onChange: (modelId) => onSelectModel?.(modelId),
|
|
5671
|
-
disabled: disabled === true
|
|
5672
|
-
}
|
|
5673
|
-
) : null,
|
|
5674
|
-
controlsStart
|
|
5675
|
-
] }) : /* @__PURE__ */ jsx12("span", { className: "px-1.5 text-[11px] text-og-fg-subtle max-sm:hidden", children: hint ?? "Enter to send \xB7 Shift+Enter for a new line \xB7 / for commands" }),
|
|
5676
|
-
/* @__PURE__ */ jsxs10("span", { className: "flex items-center gap-1.5", children: [
|
|
5677
|
-
/* @__PURE__ */ jsx12(AnimatePresence3, { initial: false, children: active ? /* @__PURE__ */ jsx12(
|
|
5678
|
-
motion3.button,
|
|
5679
|
-
{
|
|
5680
|
-
type: "button",
|
|
5681
|
-
initial: { opacity: 0, scale: 0.8 },
|
|
5682
|
-
animate: { opacity: 1, scale: 1 },
|
|
5683
|
-
exit: { opacity: 0, scale: 0.8 },
|
|
5684
|
-
transition: { duration: 0.15, ease: "easeOut" },
|
|
5685
|
-
onClick: () => void composer.interrupt(),
|
|
5686
|
-
disabled: composer.interrupting,
|
|
5687
|
-
"aria-label": "Stop the current turn",
|
|
5688
|
-
title: "Stop the current turn",
|
|
5689
|
-
className: cn(
|
|
5690
|
-
"inline-flex size-8 items-center justify-center rounded-og-md border border-og-border",
|
|
5691
|
-
"bg-og-surface-2 text-og-fg-muted transition-colors duration-150",
|
|
5692
|
-
"hover:border-og-status-failed/50 hover:text-og-status-failed",
|
|
5693
|
-
"disabled:opacity-50"
|
|
5694
|
-
),
|
|
5695
|
-
children: composer.interrupting ? /* @__PURE__ */ jsx12(LoaderCircleIcon, { className: "size-3.5 animate-og-spin" }) : /* @__PURE__ */ jsx12(SquareIcon, { className: "size-3 fill-current" })
|
|
5696
|
-
},
|
|
5697
|
-
"stop"
|
|
5698
|
-
) : null }),
|
|
5699
|
-
/* @__PURE__ */ jsx12(
|
|
5700
|
-
"button",
|
|
5701
|
-
{
|
|
5702
|
-
type: "button",
|
|
5703
|
-
onClick: () => {
|
|
5704
|
-
if (blockedByUpload) {
|
|
5705
|
-
return;
|
|
5706
|
-
}
|
|
5707
|
-
void composer.send();
|
|
5708
|
-
},
|
|
5709
|
-
disabled: !canSend || disabled === true || commandDraftBlocked,
|
|
5710
|
-
"aria-label": "Send message",
|
|
5711
|
-
className: cn(
|
|
5712
|
-
"inline-flex size-8 items-center justify-center rounded-og-md",
|
|
5713
|
-
"bg-og-accent text-og-accent-fg shadow-og-sm",
|
|
5714
|
-
"transition-[background-color,transform,opacity] duration-150 ease-og-spring",
|
|
5715
|
-
"hover:bg-og-accent-strong active:scale-95",
|
|
5716
|
-
"disabled:cursor-not-allowed disabled:bg-og-surface-3 disabled:text-og-fg-subtle disabled:shadow-none"
|
|
5717
|
-
),
|
|
5718
|
-
children: composer.sending ? /* @__PURE__ */ jsx12(LoaderCircleIcon, { className: "size-4 animate-og-spin" }) : /* @__PURE__ */ jsx12(ArrowUpIcon, { className: "size-4" })
|
|
5719
|
-
}
|
|
5720
|
-
)
|
|
6117
|
+
] })
|
|
5721
6118
|
] })
|
|
5722
|
-
]
|
|
5723
|
-
]
|
|
5724
|
-
}
|
|
5725
|
-
)
|
|
5726
|
-
] }),
|
|
5727
|
-
/* @__PURE__ */ jsx12(AnimatePresence3, { children: helpOpen ? /* @__PURE__ */ jsx12(HelpPanel, { commands: helpCommands, onClose: () => setHelpOpen(false) }) : null }),
|
|
5728
|
-
/* @__PURE__ */ jsx12(AnimatePresence3, { children: activeNotice ? /* @__PURE__ */ jsx12(
|
|
5729
|
-
motion3.p,
|
|
5730
|
-
{
|
|
5731
|
-
initial: { opacity: 0, height: 0 },
|
|
5732
|
-
animate: { opacity: 1, height: "auto" },
|
|
5733
|
-
exit: { opacity: 0, height: 0 },
|
|
5734
|
-
className: cn(
|
|
5735
|
-
"overflow-hidden px-1 pt-1.5 text-xs",
|
|
5736
|
-
activeNotice.tone === "ok" ? "text-og-fg-muted" : "text-og-status-failed"
|
|
5737
|
-
),
|
|
5738
|
-
role: activeNotice.tone === "error" ? "alert" : "status",
|
|
5739
|
-
onAnimationComplete: () => {
|
|
5740
|
-
if (activeNotice.tone === "ok") {
|
|
5741
|
-
window.setTimeout(() => setNotice((current) => current === activeNotice ? null : current), 2400);
|
|
6119
|
+
]
|
|
5742
6120
|
}
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
}
|
|
5746
|
-
|
|
5747
|
-
|
|
6121
|
+
)
|
|
6122
|
+
] }),
|
|
6123
|
+
/* @__PURE__ */ jsx12(AnimatePresence3, { children: helpOpen ? /* @__PURE__ */ jsx12(HelpPanel, { commands: helpCommands, onClose: () => setHelpOpen(false) }) : null }),
|
|
6124
|
+
/* @__PURE__ */ jsx12(AnimatePresence3, { children: activeNotice ? /* @__PURE__ */ jsx12(
|
|
6125
|
+
motion3.p,
|
|
6126
|
+
{
|
|
6127
|
+
initial: { opacity: 0, height: 0 },
|
|
6128
|
+
animate: { opacity: 1, height: "auto" },
|
|
6129
|
+
exit: { opacity: 0, height: 0 },
|
|
6130
|
+
className: cn(
|
|
6131
|
+
"overflow-hidden px-1 pt-1.5 text-xs",
|
|
6132
|
+
activeNotice.tone === "ok" ? "text-og-fg-muted" : "text-og-status-failed"
|
|
6133
|
+
),
|
|
6134
|
+
role: activeNotice.tone === "error" ? "alert" : "status",
|
|
6135
|
+
onAnimationComplete: () => {
|
|
6136
|
+
if (activeNotice.tone === "ok") {
|
|
6137
|
+
window.setTimeout(() => setNotice((current) => current === activeNotice ? null : current), 2400);
|
|
6138
|
+
}
|
|
6139
|
+
},
|
|
6140
|
+
children: activeNotice.message
|
|
6141
|
+
}
|
|
6142
|
+
) : null })
|
|
6143
|
+
] })
|
|
6144
|
+
);
|
|
5748
6145
|
}
|
|
5749
|
-
function ConfirmBar({
|
|
6146
|
+
function ConfirmBar({
|
|
6147
|
+
command,
|
|
6148
|
+
onCancel,
|
|
6149
|
+
onConfirm,
|
|
6150
|
+
returnFocusRef
|
|
6151
|
+
}) {
|
|
6152
|
+
const confirmRef = useRef15(null);
|
|
6153
|
+
const descriptionId = useId2();
|
|
6154
|
+
useEffect14(() => {
|
|
6155
|
+
const returnTo = returnFocusRef?.current ?? null;
|
|
6156
|
+
confirmRef.current?.focus();
|
|
6157
|
+
return () => {
|
|
6158
|
+
returnTo?.focus();
|
|
6159
|
+
};
|
|
6160
|
+
}, [returnFocusRef]);
|
|
5750
6161
|
return /* @__PURE__ */ jsxs10(
|
|
5751
6162
|
"div",
|
|
5752
6163
|
{
|
|
5753
6164
|
role: "alertdialog",
|
|
5754
6165
|
"aria-label": `Confirm /${command.name}`,
|
|
6166
|
+
"aria-describedby": descriptionId,
|
|
5755
6167
|
"data-testid": "danger-confirm",
|
|
5756
|
-
|
|
6168
|
+
onKeyDown: (event) => {
|
|
6169
|
+
if (event.key === "Escape") {
|
|
6170
|
+
event.preventDefault();
|
|
6171
|
+
event.stopPropagation();
|
|
6172
|
+
onCancel();
|
|
6173
|
+
}
|
|
6174
|
+
},
|
|
6175
|
+
className: "flex items-end justify-between gap-2 px-2.5 pb-2.5 pt-1",
|
|
5757
6176
|
children: [
|
|
5758
|
-
/* @__PURE__ */ jsxs10("span", { className: "px-1.5 text-
|
|
6177
|
+
/* @__PURE__ */ jsxs10("span", { id: descriptionId, className: "min-w-0 flex-1 px-1.5 text-og-sm text-og-status-failed", children: [
|
|
5759
6178
|
"Run ",
|
|
5760
6179
|
/* @__PURE__ */ jsxs10("span", { className: "font-mono", children: [
|
|
5761
6180
|
"/",
|
|
@@ -5764,24 +6183,27 @@ function ConfirmBar({ command, onCancel, onConfirm }) {
|
|
|
5764
6183
|
"? ",
|
|
5765
6184
|
command.description
|
|
5766
6185
|
] }),
|
|
5767
|
-
/* @__PURE__ */ jsxs10("span", { className: "flex items-center gap-1.5", children: [
|
|
6186
|
+
/* @__PURE__ */ jsxs10("span", { className: "flex shrink-0 items-center gap-1.5", children: [
|
|
5768
6187
|
/* @__PURE__ */ jsx12(
|
|
5769
6188
|
"button",
|
|
5770
6189
|
{
|
|
5771
6190
|
type: "button",
|
|
5772
6191
|
onClick: onCancel,
|
|
5773
|
-
className: "rounded-og-md border border-og-border bg-og-surface-2 px-2.5 py-1 text-
|
|
6192
|
+
className: "rounded-og-md border border-og-border bg-og-surface-2 px-2.5 py-1 text-og-sm text-og-fg-muted hover:bg-og-surface-3 pointer-coarse:min-h-10",
|
|
5774
6193
|
children: "Cancel"
|
|
5775
6194
|
}
|
|
5776
6195
|
),
|
|
5777
|
-
/* @__PURE__ */
|
|
6196
|
+
/* @__PURE__ */ jsxs10(
|
|
5778
6197
|
"button",
|
|
5779
6198
|
{
|
|
6199
|
+
ref: confirmRef,
|
|
5780
6200
|
type: "button",
|
|
5781
|
-
autoFocus: true,
|
|
5782
6201
|
onClick: onConfirm,
|
|
5783
|
-
className: "rounded-og-md border border-og-status-failed/50 bg-og-status-failed/15 px-2.5 py-1 text-
|
|
5784
|
-
children:
|
|
6202
|
+
className: "rounded-og-md border border-og-status-failed/50 bg-og-status-failed/15 px-2.5 py-1 text-og-sm text-og-status-failed hover:bg-og-status-failed/25 pointer-coarse:min-h-10",
|
|
6203
|
+
children: [
|
|
6204
|
+
"Run /",
|
|
6205
|
+
command.name
|
|
6206
|
+
]
|
|
5785
6207
|
}
|
|
5786
6208
|
)
|
|
5787
6209
|
] })
|
|
@@ -5789,44 +6211,57 @@ function ConfirmBar({ command, onCancel, onConfirm }) {
|
|
|
5789
6211
|
}
|
|
5790
6212
|
);
|
|
5791
6213
|
}
|
|
5792
|
-
function AttachmentChips({ attachments, onRemove }) {
|
|
5793
|
-
return /* @__PURE__ */ jsx12("div", { className: "flex flex-wrap gap-2 border-b border-og-border px-3 py-2", children: attachments.map((attachment) =>
|
|
5794
|
-
"
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
6214
|
+
function AttachmentChips({ attachments, onRemove, onRetry }) {
|
|
6215
|
+
return /* @__PURE__ */ jsx12("div", { className: "flex flex-wrap gap-2 border-b border-og-border px-3 py-2", children: attachments.map((attachment) => {
|
|
6216
|
+
const failed = attachment.status === "failed";
|
|
6217
|
+
const statusText = attachment.status === "uploading" ? "Uploading" : failed ? attachment.error || "Upload failed" : formatBytes(attachment.sizeBytes);
|
|
6218
|
+
return /* @__PURE__ */ jsxs10(
|
|
6219
|
+
"div",
|
|
6220
|
+
{
|
|
6221
|
+
className: cn(
|
|
6222
|
+
"flex min-w-0 max-w-[240px] items-center gap-2 rounded-og-md border px-2 py-1.5 text-og-sm",
|
|
6223
|
+
failed ? "border-og-status-failed/40 bg-og-status-failed/10" : "border-og-border bg-og-surface-2"
|
|
6224
|
+
),
|
|
6225
|
+
children: [
|
|
6226
|
+
attachment.previewUrl ? /* @__PURE__ */ jsx12("img", { src: attachment.previewUrl, alt: "", className: "size-8 shrink-0 rounded object-cover" }) : attachment.contentType.startsWith("image/") ? /* @__PURE__ */ jsx12(ImageIcon2, { className: "size-4 shrink-0 text-og-fg-muted" }) : /* @__PURE__ */ jsx12(FileIcon, { className: "size-4 shrink-0 text-og-fg-muted" }),
|
|
6227
|
+
/* @__PURE__ */ jsxs10("div", { className: "min-w-0 flex-1", children: [
|
|
6228
|
+
/* @__PURE__ */ jsx12("div", { className: "truncate font-medium text-og-fg", children: attachment.name }),
|
|
6229
|
+
/* @__PURE__ */ jsx12(
|
|
6230
|
+
"div",
|
|
6231
|
+
{
|
|
6232
|
+
className: cn("truncate text-og-xs", failed ? "text-og-status-failed" : "text-og-fg-subtle"),
|
|
6233
|
+
title: failed ? statusText : void 0,
|
|
6234
|
+
children: statusText
|
|
6235
|
+
}
|
|
6236
|
+
)
|
|
6237
|
+
] }),
|
|
6238
|
+
attachment.status === "uploading" ? /* @__PURE__ */ jsx12(LoaderCircleIcon, { className: "size-3.5 shrink-0 animate-og-spin" }) : null,
|
|
6239
|
+
failed && onRetry ? /* @__PURE__ */ jsx12(
|
|
6240
|
+
"button",
|
|
6241
|
+
{
|
|
6242
|
+
type: "button",
|
|
6243
|
+
onClick: () => onRetry(attachment.id),
|
|
6244
|
+
className: "shrink-0 rounded-og-xs p-1 text-og-fg-muted hover:bg-og-surface-1 hover:text-og-fg pointer-coarse:size-8",
|
|
6245
|
+
"aria-label": `Retry ${attachment.name}`,
|
|
6246
|
+
title: "Retry upload",
|
|
6247
|
+
children: /* @__PURE__ */ jsx12(RotateCwIcon, { className: "size-3.5" })
|
|
6248
|
+
}
|
|
6249
|
+
) : null,
|
|
5804
6250
|
/* @__PURE__ */ jsx12(
|
|
5805
|
-
"
|
|
6251
|
+
"button",
|
|
5806
6252
|
{
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
children:
|
|
6253
|
+
type: "button",
|
|
6254
|
+
onClick: () => onRemove(attachment.id),
|
|
6255
|
+
className: "shrink-0 rounded-og-xs p-1 text-og-fg-muted hover:bg-og-surface-1 hover:text-og-fg pointer-coarse:size-8",
|
|
6256
|
+
"aria-label": `Remove ${attachment.name}`,
|
|
6257
|
+
children: /* @__PURE__ */ jsx12(XIcon2, { className: "size-3.5" })
|
|
5812
6258
|
}
|
|
5813
6259
|
)
|
|
5814
|
-
]
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
type: "button",
|
|
5820
|
-
onClick: () => onRemove(attachment.id),
|
|
5821
|
-
className: "shrink-0 rounded-og-xs p-1 text-og-fg-muted hover:bg-og-surface-1 hover:text-og-fg",
|
|
5822
|
-
"aria-label": `Remove ${attachment.name}`,
|
|
5823
|
-
children: /* @__PURE__ */ jsx12(XIcon2, { className: "size-3.5" })
|
|
5824
|
-
}
|
|
5825
|
-
)
|
|
5826
|
-
]
|
|
5827
|
-
},
|
|
5828
|
-
attachment.id
|
|
5829
|
-
)) });
|
|
6260
|
+
]
|
|
6261
|
+
},
|
|
6262
|
+
attachment.id
|
|
6263
|
+
);
|
|
6264
|
+
}) });
|
|
5830
6265
|
}
|
|
5831
6266
|
function HelpPanel({ commands, onClose }) {
|
|
5832
6267
|
return /* @__PURE__ */ jsxs10(
|
|
@@ -5838,19 +6273,19 @@ function HelpPanel({ commands, onClose }) {
|
|
|
5838
6273
|
className: "mt-2 overflow-hidden rounded-og-lg border border-og-border bg-og-surface-2",
|
|
5839
6274
|
children: [
|
|
5840
6275
|
/* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between border-b border-og-border px-3 py-1.5", children: [
|
|
5841
|
-
/* @__PURE__ */ jsx12("span", { className: "text-
|
|
5842
|
-
/* @__PURE__ */ jsx12("button", { type: "button", onClick: onClose, className: "text-
|
|
6276
|
+
/* @__PURE__ */ jsx12("span", { className: "text-og-sm font-medium text-og-fg", children: "Commands" }),
|
|
6277
|
+
/* @__PURE__ */ jsx12("button", { type: "button", onClick: onClose, className: "text-og-xs text-og-fg-subtle hover:text-og-fg", children: "Close" })
|
|
5843
6278
|
] }),
|
|
5844
6279
|
/* @__PURE__ */ jsx12("ul", { className: "py-1", children: commands.map((command) => {
|
|
5845
6280
|
const hint = argHint(command.args);
|
|
5846
6281
|
return /* @__PURE__ */ jsxs10("li", { className: "flex items-baseline gap-2 px-3 py-1", children: [
|
|
5847
|
-
/* @__PURE__ */ jsxs10("span", { className: "font-mono text-
|
|
6282
|
+
/* @__PURE__ */ jsxs10("span", { className: "font-mono text-og-sm text-og-accent", children: [
|
|
5848
6283
|
"/",
|
|
5849
6284
|
command.name,
|
|
5850
6285
|
hint ? /* @__PURE__ */ jsx12("span", { className: "ml-1 text-og-fg-subtle", children: hint }) : null
|
|
5851
6286
|
] }),
|
|
5852
|
-
/* @__PURE__ */ jsx12("span", { className: "text-
|
|
5853
|
-
command.danger ? /* @__PURE__ */ jsx12("span", { className: "ml-auto rounded-og-xs bg-og-status-failed/15 px-1 text-
|
|
6287
|
+
/* @__PURE__ */ jsx12("span", { className: "text-og-sm text-og-fg-muted", children: command.description }),
|
|
6288
|
+
command.danger ? /* @__PURE__ */ jsx12("span", { className: "ml-auto rounded-og-xs bg-og-status-failed/15 px-1 text-og-xs uppercase tracking-wide text-og-status-failed", children: "danger" }) : null
|
|
5854
6289
|
] }, command.name);
|
|
5855
6290
|
}) })
|
|
5856
6291
|
]
|
|
@@ -5870,7 +6305,7 @@ import {
|
|
|
5870
6305
|
TriangleAlertIcon as TriangleAlertIcon2
|
|
5871
6306
|
} from "lucide-react";
|
|
5872
6307
|
import { AnimatePresence as AnimatePresence4, motion as motion4 } from "motion/react";
|
|
5873
|
-
import { useEffect as useEffect15, useMemo as useMemo8, useRef as
|
|
6308
|
+
import { useCallback as useCallback22, useEffect as useEffect15, useLayoutEffect, useMemo as useMemo8, useRef as useRef16, useState as useState22 } from "react";
|
|
5874
6309
|
|
|
5875
6310
|
// src/components/markdown.tsx
|
|
5876
6311
|
import { memo } from "react";
|
|
@@ -5880,8 +6315,8 @@ import { jsx as jsx13 } from "react/jsx-runtime";
|
|
|
5880
6315
|
var components = {
|
|
5881
6316
|
h1: ({ children, ...props }) => /* @__PURE__ */ jsx13("h1", { className: "mt-5 mb-2.5 text-xl font-semibold tracking-tight text-og-fg first:mt-0", ...props, children }),
|
|
5882
6317
|
h2: ({ children, ...props }) => /* @__PURE__ */ jsx13("h2", { className: "mt-5 mb-2 text-lg font-semibold tracking-tight text-og-fg first:mt-0", ...props, children }),
|
|
5883
|
-
h3: ({ children, ...props }) => /* @__PURE__ */ jsx13("h3", { className: "mt-4 mb-1.5 text-
|
|
5884
|
-
h4: ({ children, ...props }) => /* @__PURE__ */ jsx13("h4", { className: "mt-4 mb-1.5 text-sm font-semibold uppercase tracking-[0.04em] text-og-fg-muted first:mt-0", ...props, children }),
|
|
6318
|
+
h3: ({ children, ...props }) => /* @__PURE__ */ jsx13("h3", { className: "mt-4 mb-1.5 text-og-md font-semibold tracking-tight text-og-fg first:mt-0", ...props, children }),
|
|
6319
|
+
h4: ({ children, ...props }) => /* @__PURE__ */ jsx13("h4", { className: "mt-4 mb-1.5 text-og-sm font-semibold uppercase tracking-[0.04em] text-og-fg-muted first:mt-0", ...props, children }),
|
|
5885
6320
|
p: ({ children, ...props }) => /* @__PURE__ */ jsx13("p", { className: "my-2.5 leading-7 first:mt-0 last:mb-0", ...props, children }),
|
|
5886
6321
|
strong: ({ children, ...props }) => /* @__PURE__ */ jsx13("strong", { className: "font-semibold text-og-fg", ...props, children }),
|
|
5887
6322
|
em: ({ children, ...props }) => /* @__PURE__ */ jsx13("em", { className: "italic", ...props, children }),
|
|
@@ -5907,7 +6342,7 @@ var components = {
|
|
|
5907
6342
|
...props,
|
|
5908
6343
|
type: "checkbox",
|
|
5909
6344
|
disabled: true,
|
|
5910
|
-
className: "mr-2 size-3.5 translate-y-[2px] cursor-default
|
|
6345
|
+
className: "mr-2 size-3.5 translate-y-[2px] cursor-default accent-og-accent align-baseline"
|
|
5911
6346
|
}
|
|
5912
6347
|
) : /* @__PURE__ */ jsx13("input", { type, ...props }),
|
|
5913
6348
|
blockquote: ({ children, ...props }) => /* @__PURE__ */ jsx13(
|
|
@@ -5925,7 +6360,7 @@ var components = {
|
|
|
5925
6360
|
code: ({ children, className: _className, ...props }) => /* @__PURE__ */ jsx13(
|
|
5926
6361
|
"code",
|
|
5927
6362
|
{
|
|
5928
|
-
className: "rounded-og-xs border border-og-border bg-og-surface-1 px-1 py-0.5 font-og-mono text-
|
|
6363
|
+
className: "rounded-og-xs border border-og-border bg-og-surface-1 px-1 py-0.5 font-og-mono text-og-sm text-og-fg",
|
|
5929
6364
|
...props,
|
|
5930
6365
|
children
|
|
5931
6366
|
}
|
|
@@ -5935,12 +6370,12 @@ var components = {
|
|
|
5935
6370
|
pre: ({ children, ...props }) => /* @__PURE__ */ jsx13(
|
|
5936
6371
|
"pre",
|
|
5937
6372
|
{
|
|
5938
|
-
className: "my-3 max-h-96 overflow-auto rounded-og-md border border-og-border bg-og-bg/60 p-3 font-og-mono text-
|
|
6373
|
+
className: "my-3 max-h-96 overflow-auto rounded-og-md border border-og-border bg-og-bg/60 p-3 font-og-mono text-og-sm text-og-fg-muted [&>code]:border-0 [&>code]:bg-transparent [&>code]:p-0 [&>code]:text-inherit first:mt-0 last:mb-0",
|
|
5939
6374
|
...props,
|
|
5940
6375
|
children
|
|
5941
6376
|
}
|
|
5942
6377
|
),
|
|
5943
|
-
table: ({ children, ...props }) => /* @__PURE__ */ jsx13("div", { className: "my-3 max-w-full overflow-x-auto rounded-og-md border border-og-border first:mt-0 last:mb-0", children: /* @__PURE__ */ jsx13("table", { className: "w-full border-collapse text-
|
|
6378
|
+
table: ({ children, ...props }) => /* @__PURE__ */ jsx13("div", { className: "my-3 max-w-full overflow-x-auto rounded-og-md border border-og-border first:mt-0 last:mb-0", children: /* @__PURE__ */ jsx13("table", { className: "w-full border-collapse text-og-base", ...props, children }) }),
|
|
5944
6379
|
thead: ({ children, ...props }) => /* @__PURE__ */ jsx13("thead", { className: "bg-og-surface-1", ...props, children }),
|
|
5945
6380
|
th: ({ children, ...props }) => /* @__PURE__ */ jsx13("th", { className: "border-b border-og-border px-3 py-1.5 text-left font-medium text-og-fg", ...props, children }),
|
|
5946
6381
|
td: ({ children, ...props }) => /* @__PURE__ */ jsx13("td", { className: "border-b border-og-border px-3 py-1.5 align-top text-og-fg-muted [tr:last-child>&]:border-b-0", ...props, children }),
|
|
@@ -5977,7 +6412,7 @@ var SESSION_STATUS_META = {
|
|
|
5977
6412
|
pulse: false
|
|
5978
6413
|
},
|
|
5979
6414
|
requires_action: {
|
|
5980
|
-
label: "
|
|
6415
|
+
label: "Waiting on you",
|
|
5981
6416
|
dotClassName: "bg-og-status-waiting",
|
|
5982
6417
|
badgeClassName: "text-og-status-waiting border-og-status-waiting/35 bg-og-status-waiting/10",
|
|
5983
6418
|
pulse: true
|
|
@@ -6003,7 +6438,7 @@ function SessionStatus({ status, label, size = "md", className }) {
|
|
|
6003
6438
|
"data-status": status,
|
|
6004
6439
|
className: cn(
|
|
6005
6440
|
"og-root inline-flex shrink-0 items-center rounded-full border font-medium",
|
|
6006
|
-
size === "sm" ? "gap-1 px-1.5 py-px text-
|
|
6441
|
+
size === "sm" ? "gap-1 px-1.5 py-px text-og-xs" : "gap-1.5 px-2 py-0.5 text-xs",
|
|
6007
6442
|
meta.badgeClassName,
|
|
6008
6443
|
className
|
|
6009
6444
|
),
|
|
@@ -6029,44 +6464,163 @@ function MessageTimeline({
|
|
|
6029
6464
|
onOpenSession,
|
|
6030
6465
|
toolRegistry = defaultToolRegistry,
|
|
6031
6466
|
autoFollow = true,
|
|
6467
|
+
hasOlder = false,
|
|
6468
|
+
loadingOlder = false,
|
|
6469
|
+
onLoadOlder,
|
|
6032
6470
|
emptyState,
|
|
6033
6471
|
className
|
|
6034
6472
|
}) {
|
|
6035
6473
|
const resolvedItems = useMemo8(() => items ?? buildTimeline(events ?? []), [items, events]);
|
|
6036
6474
|
const groups = useMemo8(() => groupTimeline(resolvedItems), [resolvedItems]);
|
|
6037
|
-
const
|
|
6475
|
+
const firstGroupKey = groups[0] ? timelineGroupKey(groups[0]) : null;
|
|
6476
|
+
const scrollRef = useRef16(null);
|
|
6477
|
+
const topSentinelRef = useRef16(null);
|
|
6478
|
+
const previousBulkFirstKeyRef = useRef16(void 0);
|
|
6038
6479
|
const [pinned, setPinned] = useState22(true);
|
|
6480
|
+
const [bulkActive, setBulkActive] = useState22(true);
|
|
6481
|
+
const [revealed, setRevealed] = useState22(false);
|
|
6482
|
+
const programmaticScrollRef = useRef16(false);
|
|
6483
|
+
const assignScrollTop = useCallback22((node, value) => {
|
|
6484
|
+
const previous = node.scrollTop;
|
|
6485
|
+
programmaticScrollRef.current = true;
|
|
6486
|
+
node.scrollTop = value;
|
|
6487
|
+
if (node.scrollTop === previous) {
|
|
6488
|
+
programmaticScrollRef.current = false;
|
|
6489
|
+
}
|
|
6490
|
+
}, []);
|
|
6491
|
+
const pinnedRef = useRef16(true);
|
|
6492
|
+
const anchorRef = useRef16(null);
|
|
6039
6493
|
const lastItem = resolvedItems[resolvedItems.length - 1];
|
|
6040
6494
|
const streaming = lastItem !== void 0 && (lastItem.kind === "agent-message" || lastItem.kind === "reasoning") && lastItem.streaming;
|
|
6041
6495
|
const working = status === "running" && !streaming;
|
|
6042
|
-
|
|
6496
|
+
const firstKeyChangedForBulk = previousBulkFirstKeyRef.current !== void 0 && previousBulkFirstKeyRef.current !== firstGroupKey;
|
|
6497
|
+
const bulkRender = groups.length > 0 && (bulkActive || firstKeyChangedForBulk);
|
|
6498
|
+
const captureAnchor = useCallback22(() => {
|
|
6499
|
+
const node = scrollRef.current;
|
|
6500
|
+
const inner = node?.firstElementChild;
|
|
6501
|
+
if (!node || !inner) {
|
|
6502
|
+
anchorRef.current = null;
|
|
6503
|
+
return;
|
|
6504
|
+
}
|
|
6505
|
+
const containerTop = node.getBoundingClientRect().top;
|
|
6506
|
+
for (const child of Array.from(inner.children)) {
|
|
6507
|
+
if (child instanceof HTMLElement && child.dataset.ogTimelineChrome !== void 0) {
|
|
6508
|
+
continue;
|
|
6509
|
+
}
|
|
6510
|
+
const rect = child.getBoundingClientRect();
|
|
6511
|
+
if (rect.bottom > containerTop + 1) {
|
|
6512
|
+
anchorRef.current = { el: child, top: rect.top - containerTop };
|
|
6513
|
+
return;
|
|
6514
|
+
}
|
|
6515
|
+
}
|
|
6516
|
+
anchorRef.current = null;
|
|
6517
|
+
}, []);
|
|
6518
|
+
useLayoutEffect(() => {
|
|
6043
6519
|
const node = scrollRef.current;
|
|
6044
6520
|
if (node && autoFollow && pinned) {
|
|
6045
|
-
node
|
|
6521
|
+
assignScrollTop(node, node.scrollHeight);
|
|
6522
|
+
}
|
|
6523
|
+
if (!revealed && groups.length > 0) {
|
|
6524
|
+
setRevealed(true);
|
|
6525
|
+
}
|
|
6526
|
+
}, [resolvedItems, working, autoFollow, pinned, revealed, groups.length, assignScrollTop]);
|
|
6527
|
+
useLayoutEffect(() => {
|
|
6528
|
+
if (groups.length === 0 && revealed) {
|
|
6529
|
+
setRevealed(false);
|
|
6530
|
+
}
|
|
6531
|
+
}, [groups.length, revealed]);
|
|
6532
|
+
useLayoutEffect(() => {
|
|
6533
|
+
previousBulkFirstKeyRef.current = firstGroupKey;
|
|
6534
|
+
if (!bulkRender) {
|
|
6535
|
+
return;
|
|
6536
|
+
}
|
|
6537
|
+
setBulkActive(true);
|
|
6538
|
+
const frame = requestFrame(() => setBulkActive(false));
|
|
6539
|
+
return () => cancelFrame(frame);
|
|
6540
|
+
}, [bulkRender, firstGroupKey]);
|
|
6541
|
+
useEffect15(() => {
|
|
6542
|
+
const root = scrollRef.current;
|
|
6543
|
+
const target = topSentinelRef.current;
|
|
6544
|
+
if (!root || !target || !hasOlder || loadingOlder || !onLoadOlder || typeof IntersectionObserver === "undefined") {
|
|
6545
|
+
return;
|
|
6046
6546
|
}
|
|
6047
|
-
|
|
6547
|
+
const observer = new IntersectionObserver((entries) => {
|
|
6548
|
+
if (entries.some((entry) => entry.isIntersecting)) {
|
|
6549
|
+
onLoadOlder();
|
|
6550
|
+
}
|
|
6551
|
+
}, { root, rootMargin: "1600px 0px 0px 0px" });
|
|
6552
|
+
observer.observe(target);
|
|
6553
|
+
return () => observer.disconnect();
|
|
6554
|
+
}, [hasOlder, loadingOlder, onLoadOlder, firstGroupKey]);
|
|
6555
|
+
useEffect15(() => {
|
|
6556
|
+
const node = scrollRef.current;
|
|
6557
|
+
const inner = node?.firstElementChild;
|
|
6558
|
+
if (!node || !inner || typeof ResizeObserver === "undefined") {
|
|
6559
|
+
return;
|
|
6560
|
+
}
|
|
6561
|
+
const observer = new ResizeObserver(() => {
|
|
6562
|
+
const current = scrollRef.current;
|
|
6563
|
+
if (!current) {
|
|
6564
|
+
return;
|
|
6565
|
+
}
|
|
6566
|
+
if (autoFollow && pinnedRef.current) {
|
|
6567
|
+
assignScrollTop(current, current.scrollHeight);
|
|
6568
|
+
} else {
|
|
6569
|
+
const anchor = anchorRef.current;
|
|
6570
|
+
if (anchor && anchor.el.isConnected) {
|
|
6571
|
+
const containerTop = current.getBoundingClientRect().top;
|
|
6572
|
+
const now = anchor.el.getBoundingClientRect().top - containerTop;
|
|
6573
|
+
const diff = now - anchor.top;
|
|
6574
|
+
if (diff !== 0) {
|
|
6575
|
+
assignScrollTop(current, current.scrollTop + diff);
|
|
6576
|
+
}
|
|
6577
|
+
}
|
|
6578
|
+
}
|
|
6579
|
+
captureAnchor();
|
|
6580
|
+
});
|
|
6581
|
+
observer.observe(inner);
|
|
6582
|
+
return () => observer.disconnect();
|
|
6583
|
+
}, [autoFollow, captureAnchor, assignScrollTop]);
|
|
6048
6584
|
const onScroll = () => {
|
|
6049
6585
|
const node = scrollRef.current;
|
|
6050
6586
|
if (!node) {
|
|
6051
6587
|
return;
|
|
6052
6588
|
}
|
|
6053
|
-
|
|
6589
|
+
const programmatic = programmaticScrollRef.current;
|
|
6590
|
+
programmaticScrollRef.current = false;
|
|
6591
|
+
const nextPinned = node.scrollHeight - node.scrollTop - node.clientHeight < 48;
|
|
6592
|
+
if (nextPinned || !programmatic) {
|
|
6593
|
+
pinnedRef.current = nextPinned;
|
|
6594
|
+
setPinned(nextPinned);
|
|
6595
|
+
}
|
|
6596
|
+
captureAnchor();
|
|
6054
6597
|
};
|
|
6055
|
-
return /* @__PURE__ */ jsx15(LightboxProvider, { children: /* @__PURE__ */ jsxs12("div", { className: cn("og-root relative flex min-h-0 flex-col", className), children: [
|
|
6056
|
-
/* @__PURE__ */ jsx15(
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6598
|
+
return /* @__PURE__ */ jsx15(LightboxProvider, { children: /* @__PURE__ */ jsx15(EntranceAnimationProvider, { value: !bulkRender, children: /* @__PURE__ */ jsxs12("div", { className: cn("og-root relative flex min-h-0 flex-col", className), children: [
|
|
6599
|
+
/* @__PURE__ */ jsx15(
|
|
6600
|
+
"div",
|
|
6601
|
+
{
|
|
6602
|
+
ref: scrollRef,
|
|
6603
|
+
onScroll,
|
|
6604
|
+
style: groups.length > 0 && !revealed ? { visibility: "hidden" } : void 0,
|
|
6605
|
+
className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-6 [overflow-anchor:none] sm:px-6",
|
|
6606
|
+
children: /* @__PURE__ */ jsxs12("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: [
|
|
6607
|
+
groups.length === 0 && !working ? emptyState ?? /* @__PURE__ */ jsx15("p", { className: "py-10 text-center text-sm text-og-fg-subtle", children: "No activity yet." }) : null,
|
|
6608
|
+
hasOlder ? /* @__PURE__ */ jsx15("div", { ref: topSentinelRef, "data-og-top-sentinel": "", "data-og-timeline-chrome": "", "aria-hidden": "true", className: "h-px w-full shrink-0" }) : null,
|
|
6609
|
+
loadingOlder ? /* @__PURE__ */ jsx15("div", { "data-og-timeline-chrome": "", className: "flex items-center gap-2 text-sm", children: /* @__PURE__ */ jsx15("span", { className: "og-shimmer-text font-medium", children: "Loading earlier activity\u2026" }) }) : null,
|
|
6610
|
+
groups.map((group) => /* @__PURE__ */ jsx15(
|
|
6611
|
+
TimelineGroupView,
|
|
6612
|
+
{
|
|
6613
|
+
group,
|
|
6614
|
+
renderMessageText,
|
|
6615
|
+
onOpenSession,
|
|
6616
|
+
toolRegistry
|
|
6617
|
+
},
|
|
6618
|
+
timelineGroupKey(group)
|
|
6619
|
+
)),
|
|
6620
|
+
working ? /* @__PURE__ */ jsx15("div", { className: "flex items-center gap-2 text-sm", children: /* @__PURE__ */ jsx15("span", { className: "og-shimmer-text font-medium", children: "Working\u2026" }) }) : null
|
|
6621
|
+
] })
|
|
6622
|
+
}
|
|
6623
|
+
),
|
|
6070
6624
|
/* @__PURE__ */ jsx15(AnimatePresence4, { children: !pinned && autoFollow ? /* @__PURE__ */ jsxs12(
|
|
6071
6625
|
motion4.button,
|
|
6072
6626
|
{
|
|
@@ -6080,6 +6634,7 @@ function MessageTimeline({
|
|
|
6080
6634
|
if (node) {
|
|
6081
6635
|
node.scrollTo({ top: node.scrollHeight, behavior: "smooth" });
|
|
6082
6636
|
}
|
|
6637
|
+
pinnedRef.current = true;
|
|
6083
6638
|
setPinned(true);
|
|
6084
6639
|
},
|
|
6085
6640
|
className: cn(
|
|
@@ -6094,7 +6649,20 @@ function MessageTimeline({
|
|
|
6094
6649
|
]
|
|
6095
6650
|
}
|
|
6096
6651
|
) : null })
|
|
6097
|
-
] }) });
|
|
6652
|
+
] }) }) });
|
|
6653
|
+
}
|
|
6654
|
+
function requestFrame(callback) {
|
|
6655
|
+
if (typeof requestAnimationFrame === "function") {
|
|
6656
|
+
return requestAnimationFrame(callback);
|
|
6657
|
+
}
|
|
6658
|
+
return window.setTimeout(() => callback(performance.now()), 16);
|
|
6659
|
+
}
|
|
6660
|
+
function cancelFrame(id) {
|
|
6661
|
+
if (typeof cancelAnimationFrame === "function") {
|
|
6662
|
+
cancelAnimationFrame(id);
|
|
6663
|
+
return;
|
|
6664
|
+
}
|
|
6665
|
+
window.clearTimeout(id);
|
|
6098
6666
|
}
|
|
6099
6667
|
function TimelineGroupView({
|
|
6100
6668
|
group,
|
|
@@ -6195,7 +6763,8 @@ function UserMessageRow({
|
|
|
6195
6763
|
item,
|
|
6196
6764
|
renderMessageText
|
|
6197
6765
|
}) {
|
|
6198
|
-
|
|
6766
|
+
const enter = useEntranceAnimation();
|
|
6767
|
+
return /* @__PURE__ */ jsx15("div", { className: cn(enter && "animate-og-enter", "flex justify-end"), children: /* @__PURE__ */ jsxs12("div", { className: "flex max-w-[85%] min-w-0 flex-col items-end gap-1", children: [
|
|
6199
6768
|
item.pending ? /* @__PURE__ */ jsx15("span", { className: "px-1 text-og-xs text-og-fg-subtle", children: "queued" }) : null,
|
|
6200
6769
|
/* @__PURE__ */ jsx15("div", { className: "w-fit max-w-full min-w-0 rounded-og-lg rounded-br-og-xs border border-og-border bg-og-surface-2 px-4 py-2.5 text-og-md leading-6 text-og-fg", children: renderMessageText ? renderMessageText(item.text, item) : /* @__PURE__ */ jsx15(Markdown, { children: item.text }) })
|
|
6201
6770
|
] }) });
|
|
@@ -6204,8 +6773,9 @@ function AgentMessageRow({
|
|
|
6204
6773
|
item,
|
|
6205
6774
|
renderMessageText
|
|
6206
6775
|
}) {
|
|
6776
|
+
const enter = useEntranceAnimation();
|
|
6207
6777
|
const caret = item.streaming ? /* @__PURE__ */ jsx15("span", { className: "ml-0.5 inline-block h-[1.1em] w-[2px] translate-y-[3px] animate-og-blink rounded-full bg-og-accent", "aria-hidden": true }) : null;
|
|
6208
|
-
return /* @__PURE__ */ jsx15("div", { className: "animate-og-enter min-w-0 text-og-md leading-7 text-og-fg", children: renderMessageText ? /* @__PURE__ */ jsxs12(Fragment4, { children: [
|
|
6778
|
+
return /* @__PURE__ */ jsx15("div", { className: cn(enter && "animate-og-enter", "min-w-0 text-og-md leading-7 text-og-fg"), children: renderMessageText ? /* @__PURE__ */ jsxs12(Fragment4, { children: [
|
|
6209
6779
|
renderMessageText(item.text, item),
|
|
6210
6780
|
caret
|
|
6211
6781
|
] }) : (
|
|
@@ -6219,8 +6789,9 @@ function AgentMessageRow({
|
|
|
6219
6789
|
) });
|
|
6220
6790
|
}
|
|
6221
6791
|
function SessionStatusRow({ item }) {
|
|
6792
|
+
const enter = useEntranceAnimation();
|
|
6222
6793
|
const meta = SESSION_STATUS_META[item.status];
|
|
6223
|
-
return /* @__PURE__ */ jsxs12("div", { className: "animate-og-enter flex items-center gap-3 text-og-xs text-og-fg-subtle", role: "status", children: [
|
|
6794
|
+
return /* @__PURE__ */ jsxs12("div", { className: cn(enter && "animate-og-enter", "flex items-center gap-3 text-og-xs text-og-fg-subtle"), role: "status", children: [
|
|
6224
6795
|
/* @__PURE__ */ jsx15("span", { className: "h-px flex-1 bg-og-border" }),
|
|
6225
6796
|
/* @__PURE__ */ jsxs12("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
6226
6797
|
/* @__PURE__ */ jsx15(StatusDot, { status: item.status, className: "size-1" }),
|
|
@@ -6241,8 +6812,9 @@ var GOAL_META = {
|
|
|
6241
6812
|
continuation: { label: "Continuing toward the goal", pill: NEUTRAL_PILL, icon: ArrowRightIcon }
|
|
6242
6813
|
};
|
|
6243
6814
|
function GoalRow({ item }) {
|
|
6815
|
+
const enter = useEntranceAnimation();
|
|
6244
6816
|
const { label, pill, icon: Icon } = GOAL_META[item.action];
|
|
6245
|
-
return /* @__PURE__ */ jsx15("div", { className: "animate-og-enter flex justify-center", children: /* @__PURE__ */ jsxs12("span", { className: cn("inline-flex max-w-full items-center gap-1.5 rounded-full border px-3 py-1 text-og-sm", pill), children: [
|
|
6817
|
+
return /* @__PURE__ */ jsx15("div", { className: cn(enter && "animate-og-enter", "flex justify-center"), children: /* @__PURE__ */ jsxs12("span", { className: cn("inline-flex max-w-full items-center gap-1.5 rounded-full border px-3 py-1 text-og-sm", pill), children: [
|
|
6246
6818
|
/* @__PURE__ */ jsx15(Icon, { className: "size-3.5 shrink-0" }),
|
|
6247
6819
|
/* @__PURE__ */ jsxs12("span", { className: "truncate", children: [
|
|
6248
6820
|
label,
|
|
@@ -6251,8 +6823,9 @@ function GoalRow({ item }) {
|
|
|
6251
6823
|
] }) });
|
|
6252
6824
|
}
|
|
6253
6825
|
function NoticeRow({ item }) {
|
|
6826
|
+
const enter = useEntranceAnimation();
|
|
6254
6827
|
const tone = item.tone === "failed" ? "border-og-status-failed/35 bg-og-status-failed/10 text-og-status-failed" : item.tone === "waiting" ? "border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting" : "border-og-border bg-og-surface-1 text-og-fg-muted";
|
|
6255
|
-
return /* @__PURE__ */ jsxs12("div", { className: cn("animate-og-enter flex items-start gap-2.5 rounded-og-md border px-3.5 py-2.5 text-sm", tone), role: "status", children: [
|
|
6828
|
+
return /* @__PURE__ */ jsxs12("div", { className: cn(enter && "animate-og-enter", "flex items-start gap-2.5 rounded-og-md border px-3.5 py-2.5 text-sm", tone), role: "status", children: [
|
|
6256
6829
|
/* @__PURE__ */ jsx15(TriangleAlertIcon2, { className: cn("mt-0.5 size-4 shrink-0", item.tone === "cancelled" && "opacity-60") }),
|
|
6257
6830
|
/* @__PURE__ */ jsx15("span", { className: "min-w-0 whitespace-pre-wrap break-words", children: item.text })
|
|
6258
6831
|
] });
|
|
@@ -6302,11 +6875,11 @@ function FleetTile({ session, title, subtitle, onOpen, className }) {
|
|
|
6302
6875
|
}
|
|
6303
6876
|
),
|
|
6304
6877
|
/* @__PURE__ */ jsxs13("span", { className: "flex w-full items-start justify-between gap-3", children: [
|
|
6305
|
-
/* @__PURE__ */ jsx16("span", { className: "line-clamp-2 min-w-0 text-
|
|
6878
|
+
/* @__PURE__ */ jsx16("span", { className: "line-clamp-2 min-w-0 text-og-base font-medium leading-snug text-og-fg", children: title ?? sessionDisplayTitle(session) }),
|
|
6306
6879
|
/* @__PURE__ */ jsx16(SessionStatus, { status: session.status, size: "sm", className: "mt-px" })
|
|
6307
6880
|
] }),
|
|
6308
|
-
subtitle ? /* @__PURE__ */ jsx16("span", { className: "line-clamp-1 text-
|
|
6309
|
-
/* @__PURE__ */ jsxs13("span", { className: "mt-auto flex w-full items-center gap-2 text-
|
|
6881
|
+
subtitle ? /* @__PURE__ */ jsx16("span", { className: "line-clamp-1 text-og-sm text-og-fg-muted", children: subtitle }) : null,
|
|
6882
|
+
/* @__PURE__ */ jsxs13("span", { className: "mt-auto flex w-full items-center gap-2 text-og-xs text-og-fg-subtle", children: [
|
|
6310
6883
|
/* @__PURE__ */ jsx16("span", { className: "font-og-mono", children: session.id.slice(0, 8) }),
|
|
6311
6884
|
/* @__PURE__ */ jsx16("span", { "aria-hidden": true, children: "\xB7" }),
|
|
6312
6885
|
/* @__PURE__ */ jsx16("span", { className: "truncate", children: session.model }),
|
|
@@ -6318,7 +6891,7 @@ function FleetTile({ session, title, subtitle, onOpen, className }) {
|
|
|
6318
6891
|
}
|
|
6319
6892
|
|
|
6320
6893
|
// src/components/sandbox-terminal.tsx
|
|
6321
|
-
import { useEffect as useEffect16, useRef as
|
|
6894
|
+
import { useEffect as useEffect16, useRef as useRef17, useState as useState23 } from "react";
|
|
6322
6895
|
import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
6323
6896
|
function SandboxTerminal({
|
|
6324
6897
|
result,
|
|
@@ -6333,13 +6906,13 @@ function SandboxTerminal({
|
|
|
6333
6906
|
onActivate,
|
|
6334
6907
|
className
|
|
6335
6908
|
}) {
|
|
6336
|
-
const containerRef =
|
|
6337
|
-
const termRef =
|
|
6338
|
-
const fitRef =
|
|
6339
|
-
const writtenRef =
|
|
6909
|
+
const containerRef = useRef17(null);
|
|
6910
|
+
const termRef = useRef17(null);
|
|
6911
|
+
const fitRef = useRef17(null);
|
|
6912
|
+
const writtenRef = useRef17(/* @__PURE__ */ new Set());
|
|
6340
6913
|
const [ready, setReady] = useState23(false);
|
|
6341
6914
|
const ptyWs = terminalCapability?.transport === "pty-ws" && Boolean(terminalCapability?.url);
|
|
6342
|
-
const ptyOutputQueueRef =
|
|
6915
|
+
const ptyOutputQueueRef = useRef17([]);
|
|
6343
6916
|
const ptyStream = useTerminalStream({
|
|
6344
6917
|
capability: ptyWs ? {
|
|
6345
6918
|
transport: terminalCapability.transport,
|
|
@@ -6387,7 +6960,7 @@ function SandboxTerminal({
|
|
|
6387
6960
|
convertEol: true,
|
|
6388
6961
|
disableStdin: !interactive,
|
|
6389
6962
|
cursorBlink: interactive,
|
|
6390
|
-
fontFamily: fontFamily ?? "var(--og-font-mono
|
|
6963
|
+
fontFamily: fontFamily ?? "var(--og-font-mono)",
|
|
6391
6964
|
fontSize: fontSize ?? 13,
|
|
6392
6965
|
lineHeight: 1.25,
|
|
6393
6966
|
// A little breathing room from the panel edge so output isn't flush to
|
|
@@ -6434,7 +7007,7 @@ function SandboxTerminal({
|
|
|
6434
7007
|
if (!ready || !term || !theme) return;
|
|
6435
7008
|
term.options.theme = theme;
|
|
6436
7009
|
}, [ready, theme]);
|
|
6437
|
-
const enteredPtyRef =
|
|
7010
|
+
const enteredPtyRef = useRef17(false);
|
|
6438
7011
|
useEffect16(() => {
|
|
6439
7012
|
const term = termRef.current;
|
|
6440
7013
|
if (!ready || !term) return;
|
|
@@ -6490,24 +7063,24 @@ function SandboxTerminal({
|
|
|
6490
7063
|
};
|
|
6491
7064
|
}, [ready]);
|
|
6492
7065
|
return /* @__PURE__ */ jsxs14("div", { className: cn("relative flex h-full w-full flex-col overflow-hidden", className), children: [
|
|
6493
|
-
showHeader && /* @__PURE__ */ jsxs14("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-
|
|
7066
|
+
showHeader && /* @__PURE__ */ jsxs14("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-og-border px-2 py-1 text-og-xs text-og-fg-subtle", children: [
|
|
6494
7067
|
/* @__PURE__ */ jsxs14("span", { className: "flex min-w-0 items-center gap-1.5", children: [
|
|
6495
7068
|
/* @__PURE__ */ jsx17(
|
|
6496
7069
|
"span",
|
|
6497
7070
|
{
|
|
6498
7071
|
className: cn(
|
|
6499
7072
|
"size-1.5 shrink-0 rounded-full",
|
|
6500
|
-
result.running ? "bg-
|
|
7073
|
+
result.running ? "bg-og-status-running" : "bg-og-fg-subtle"
|
|
6501
7074
|
)
|
|
6502
7075
|
}
|
|
6503
7076
|
),
|
|
6504
|
-
/* @__PURE__ */ jsxs14("span", { className: "truncate font-
|
|
7077
|
+
/* @__PURE__ */ jsxs14("span", { className: "truncate font-og-mono", children: [
|
|
6505
7078
|
"pty: ",
|
|
6506
7079
|
shell ?? "shell"
|
|
6507
7080
|
] })
|
|
6508
7081
|
] }),
|
|
6509
7082
|
/* @__PURE__ */ jsxs14("span", { className: "flex shrink-0 items-center gap-2", children: [
|
|
6510
|
-
!interactive && /* @__PURE__ */ jsx17("span", { className: "rounded-
|
|
7083
|
+
!interactive && /* @__PURE__ */ jsx17("span", { className: "rounded-og-sm bg-og-surface-2 px-1.5 py-0.5 text-og-xs uppercase tracking-wide", children: "read-only" }),
|
|
6511
7084
|
/* @__PURE__ */ jsx17(
|
|
6512
7085
|
"button",
|
|
6513
7086
|
{
|
|
@@ -6516,7 +7089,7 @@ function SandboxTerminal({
|
|
|
6516
7089
|
termRef.current?.clear();
|
|
6517
7090
|
writtenRef.current = /* @__PURE__ */ new Set();
|
|
6518
7091
|
},
|
|
6519
|
-
className: "rounded-
|
|
7092
|
+
className: "rounded-og-sm px-1.5 py-0.5 text-og-xs hover:text-og-fg pointer-coarse:min-h-10",
|
|
6520
7093
|
children: "Clear"
|
|
6521
7094
|
}
|
|
6522
7095
|
)
|
|
@@ -6525,7 +7098,7 @@ function SandboxTerminal({
|
|
|
6525
7098
|
/* @__PURE__ */ jsxs14(
|
|
6526
7099
|
"div",
|
|
6527
7100
|
{
|
|
6528
|
-
className: "relative min-h-0 flex-1 bg-
|
|
7101
|
+
className: "relative min-h-0 flex-1 bg-og-bg px-2 py-1.5",
|
|
6529
7102
|
onPointerDownCapture: onActivate,
|
|
6530
7103
|
onFocusCapture: onActivate,
|
|
6531
7104
|
children: [
|
|
@@ -6542,7 +7115,7 @@ var XTERM_BASE_CSS = `
|
|
|
6542
7115
|
.xterm.focus,.xterm:focus{outline:none}
|
|
6543
7116
|
.xterm .xterm-helpers{position:absolute;top:0;z-index:5}
|
|
6544
7117
|
.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}
|
|
6545
|
-
.xterm .composition-view{background
|
|
7118
|
+
.xterm .composition-view{background:var(--og-color-bg);color:var(--og-color-fg);display:none;position:absolute;white-space:nowrap;z-index:1}
|
|
6546
7119
|
.xterm .composition-view.active{display:block}
|
|
6547
7120
|
.xterm .xterm-viewport{background-color:transparent;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}
|
|
6548
7121
|
.xterm .xterm-screen{position:relative}
|
|
@@ -6578,7 +7151,7 @@ function ensureXtermBaseCss() {
|
|
|
6578
7151
|
document.head.appendChild(style);
|
|
6579
7152
|
}
|
|
6580
7153
|
function TerminalPlaceholder() {
|
|
6581
|
-
return /* @__PURE__ */ jsx17("div", { className: "absolute inset-0 flex items-center justify-center text-
|
|
7154
|
+
return /* @__PURE__ */ jsx17("div", { className: "absolute inset-0 flex items-center justify-center text-og-sm text-og-fg-subtle", children: "Loading terminal\u2026" });
|
|
6582
7155
|
}
|
|
6583
7156
|
|
|
6584
7157
|
// src/components/file-browser.tsx
|
|
@@ -6594,19 +7167,19 @@ import {
|
|
|
6594
7167
|
Trash2Icon
|
|
6595
7168
|
} from "lucide-react";
|
|
6596
7169
|
import {
|
|
6597
|
-
useCallback as
|
|
7170
|
+
useCallback as useCallback23,
|
|
6598
7171
|
useEffect as useEffect17,
|
|
6599
7172
|
useMemo as useMemo9,
|
|
6600
|
-
useRef as
|
|
7173
|
+
useRef as useRef18,
|
|
6601
7174
|
useState as useState24
|
|
6602
7175
|
} from "react";
|
|
6603
7176
|
import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
6604
7177
|
var STATUS_TINT = {
|
|
6605
|
-
added: "text-
|
|
6606
|
-
modified: "text-
|
|
6607
|
-
deleted: "text-
|
|
6608
|
-
renamed: "text-
|
|
6609
|
-
untracked: "text-
|
|
7178
|
+
added: "text-og-status-idle",
|
|
7179
|
+
modified: "text-og-status-running",
|
|
7180
|
+
deleted: "text-og-status-failed line-through",
|
|
7181
|
+
renamed: "text-og-accent",
|
|
7182
|
+
untracked: "text-og-fg-subtle"
|
|
6610
7183
|
};
|
|
6611
7184
|
function parentOf2(path) {
|
|
6612
7185
|
const i = path.lastIndexOf("/");
|
|
@@ -6644,9 +7217,9 @@ function FileBrowser({
|
|
|
6644
7217
|
const [dragOver, setDragOver] = useState24(null);
|
|
6645
7218
|
const [menu, setMenu] = useState24(null);
|
|
6646
7219
|
const [busy, setBusy] = useState24(false);
|
|
6647
|
-
const containerRef =
|
|
7220
|
+
const containerRef = useRef18(null);
|
|
6648
7221
|
const cursor = active ?? selectedPath ?? null;
|
|
6649
|
-
const expand =
|
|
7222
|
+
const expand = useCallback23(
|
|
6650
7223
|
async (path) => {
|
|
6651
7224
|
const node = findNode(result.tree, path);
|
|
6652
7225
|
if (node && node.kind === "dir" && node.children === void 0) {
|
|
@@ -6664,14 +7237,14 @@ function FileBrowser({
|
|
|
6664
7237
|
},
|
|
6665
7238
|
[result]
|
|
6666
7239
|
);
|
|
6667
|
-
const open =
|
|
7240
|
+
const open = useCallback23(
|
|
6668
7241
|
(path) => {
|
|
6669
7242
|
setExpanded((prev) => new Set(prev).add(path));
|
|
6670
7243
|
void expand(path);
|
|
6671
7244
|
},
|
|
6672
7245
|
[expand]
|
|
6673
7246
|
);
|
|
6674
|
-
const toggle =
|
|
7247
|
+
const toggle = useCallback23(
|
|
6675
7248
|
async (node) => {
|
|
6676
7249
|
if (node.kind !== "dir") return;
|
|
6677
7250
|
const isOpen = expanded.has(node.path);
|
|
@@ -6699,7 +7272,7 @@ function FileBrowser({
|
|
|
6699
7272
|
return rows;
|
|
6700
7273
|
}, [result.tree, expanded]);
|
|
6701
7274
|
const supportsMutation = editable;
|
|
6702
|
-
const runDelete =
|
|
7275
|
+
const runDelete = useCallback23(
|
|
6703
7276
|
async (node) => {
|
|
6704
7277
|
if (!supportsMutation) return;
|
|
6705
7278
|
const recursive = node.kind === "dir";
|
|
@@ -6718,7 +7291,7 @@ function FileBrowser({
|
|
|
6718
7291
|
},
|
|
6719
7292
|
[supportsMutation, confirmDelete, result]
|
|
6720
7293
|
);
|
|
6721
|
-
const commitCreate =
|
|
7294
|
+
const commitCreate = useCallback23(
|
|
6722
7295
|
async (name) => {
|
|
6723
7296
|
const draft = draftCreate;
|
|
6724
7297
|
setDraftCreate(null);
|
|
@@ -6743,7 +7316,7 @@ function FileBrowser({
|
|
|
6743
7316
|
},
|
|
6744
7317
|
[draftCreate, supportsMutation, result, open, onSelectFile]
|
|
6745
7318
|
);
|
|
6746
|
-
const commitRename =
|
|
7319
|
+
const commitRename = useCallback23(
|
|
6747
7320
|
async (name) => {
|
|
6748
7321
|
const draft = draftRename;
|
|
6749
7322
|
setDraftRename(null);
|
|
@@ -6766,7 +7339,7 @@ function FileBrowser({
|
|
|
6766
7339
|
},
|
|
6767
7340
|
[draftRename, supportsMutation, result, selectedPath, active, onSelectFile]
|
|
6768
7341
|
);
|
|
6769
|
-
const startCreate =
|
|
7342
|
+
const startCreate = useCallback23(
|
|
6770
7343
|
(kind) => {
|
|
6771
7344
|
if (!supportsMutation) return;
|
|
6772
7345
|
const anchor = cursor ? findNode(result.tree, cursor) : void 0;
|
|
@@ -6778,7 +7351,7 @@ function FileBrowser({
|
|
|
6778
7351
|
},
|
|
6779
7352
|
[supportsMutation, cursor, result.tree, open]
|
|
6780
7353
|
);
|
|
6781
|
-
const startRename =
|
|
7354
|
+
const startRename = useCallback23(
|
|
6782
7355
|
(node) => {
|
|
6783
7356
|
if (!supportsMutation) return;
|
|
6784
7357
|
setDraftCreate(null);
|
|
@@ -6787,7 +7360,7 @@ function FileBrowser({
|
|
|
6787
7360
|
},
|
|
6788
7361
|
[supportsMutation]
|
|
6789
7362
|
);
|
|
6790
|
-
const onDropOnto =
|
|
7363
|
+
const onDropOnto = useCallback23(
|
|
6791
7364
|
async (targetDir, sourcePath) => {
|
|
6792
7365
|
setDragOver(null);
|
|
6793
7366
|
if (!supportsMutation || !sourcePath) return;
|
|
@@ -6811,7 +7384,7 @@ function FileBrowser({
|
|
|
6811
7384
|
},
|
|
6812
7385
|
[supportsMutation, result, selectedPath, active, onSelectFile]
|
|
6813
7386
|
);
|
|
6814
|
-
const onKeyDown =
|
|
7387
|
+
const onKeyDown = useCallback23(
|
|
6815
7388
|
(e) => {
|
|
6816
7389
|
if (draftCreate || draftRename) return;
|
|
6817
7390
|
if (flatRows.length === 0) return;
|
|
@@ -6888,10 +7461,9 @@ function FileBrowser({
|
|
|
6888
7461
|
window.removeEventListener("resize", close);
|
|
6889
7462
|
};
|
|
6890
7463
|
}, [menu]);
|
|
6891
|
-
|
|
6892
|
-
return /* @__PURE__ */ jsx18("div", { className: cn("p-3 text-xs text-[color:var(--og-color-fg-subtle,var(--color-fg-subtle,#888))]", className), children: fallback ?? `Files unavailable: ${result.error.message}` });
|
|
6893
|
-
}
|
|
7464
|
+
const showErrorEmpty = result.error && result.tree.length === 0 && !draftCreate;
|
|
6894
7465
|
const showEmpty = !result.loading && result.tree.length === 0 && !draftCreate;
|
|
7466
|
+
const showToolbar = supportsMutation || Boolean(result.error) || result.loading;
|
|
6895
7467
|
const renderRow = (node, depth) => {
|
|
6896
7468
|
const isOpen = expanded.has(node.path);
|
|
6897
7469
|
if (renderNode) {
|
|
@@ -6959,11 +7531,11 @@ function FileBrowser({
|
|
|
6959
7531
|
setMenu({ node, x: e.clientX, y: e.clientY });
|
|
6960
7532
|
},
|
|
6961
7533
|
className: cn(
|
|
6962
|
-
"group flex w-full items-center gap-1 truncate rounded px-1 py-0.5 text-left text-
|
|
6963
|
-
"hover:bg-
|
|
6964
|
-
isSelected && "bg-
|
|
6965
|
-
isCursor && "outline outline-1 -outline-offset-1 outline-
|
|
6966
|
-
isDropTarget && "ring-1 ring-inset ring-
|
|
7534
|
+
"group flex w-full items-center gap-1 truncate rounded-og-sm px-1 py-0.5 text-left text-og-sm pointer-coarse:min-h-10",
|
|
7535
|
+
"hover:bg-og-surface-2",
|
|
7536
|
+
isSelected && "bg-og-surface-2",
|
|
7537
|
+
isCursor && "outline outline-1 -outline-offset-1 outline-og-accent",
|
|
7538
|
+
isDropTarget && "bg-og-accent-soft ring-1 ring-inset ring-og-accent",
|
|
6967
7539
|
node.status ? STATUS_TINT[node.status] : void 0
|
|
6968
7540
|
),
|
|
6969
7541
|
style: { paddingLeft: `${depth * 12 + 4}px` },
|
|
@@ -6971,7 +7543,7 @@ function FileBrowser({
|
|
|
6971
7543
|
isDir ? isLoading ? /* @__PURE__ */ jsx18(
|
|
6972
7544
|
Loader2Icon,
|
|
6973
7545
|
{
|
|
6974
|
-
className: "size-3 shrink-0 animate-spin text-
|
|
7546
|
+
className: "size-3 shrink-0 animate-spin text-og-fg-subtle",
|
|
6975
7547
|
"aria-label": "Loading"
|
|
6976
7548
|
}
|
|
6977
7549
|
) : /* @__PURE__ */ jsx18(ChevronRightIcon3, { className: cn("size-3 shrink-0 transition-transform", isOpen && "rotate-90") }) : /* @__PURE__ */ jsx18("span", { className: "inline-block w-3 shrink-0" }),
|
|
@@ -6990,7 +7562,7 @@ function FileBrowser({
|
|
|
6990
7562
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
6991
7563
|
setMenu({ node, x: rect.right, y: rect.bottom });
|
|
6992
7564
|
},
|
|
6993
|
-
className: "ml-auto hidden shrink-0 px-1 text-
|
|
7565
|
+
className: "ml-auto hidden shrink-0 px-1 text-og-fg-subtle hover:text-og-fg group-hover:inline",
|
|
6994
7566
|
children: "\u22EF"
|
|
6995
7567
|
}
|
|
6996
7568
|
)
|
|
@@ -7017,7 +7589,7 @@ function FileBrowser({
|
|
|
7017
7589
|
children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx18(
|
|
7018
7590
|
"div",
|
|
7019
7591
|
{
|
|
7020
|
-
className: "h-2.5 animate-pulse rounded bg-
|
|
7592
|
+
className: "h-2.5 animate-pulse rounded-og-sm bg-og-surface-2",
|
|
7021
7593
|
style: { width: `${70 - i * 12}%` }
|
|
7022
7594
|
},
|
|
7023
7595
|
i
|
|
@@ -7031,33 +7603,35 @@ function FileBrowser({
|
|
|
7031
7603
|
);
|
|
7032
7604
|
};
|
|
7033
7605
|
return /* @__PURE__ */ jsxs15("div", { className: cn("flex min-w-0 flex-col", className), children: [
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
|
|
7606
|
+
showToolbar && /* @__PURE__ */ jsxs15("div", { className: "flex shrink-0 flex-wrap items-center gap-0.5 border-b border-og-border px-1 py-1", children: [
|
|
7607
|
+
supportsMutation ? /* @__PURE__ */ jsxs15(Fragment5, { children: [
|
|
7608
|
+
/* @__PURE__ */ jsx18(ToolbarButton, { label: "New file", onClick: () => startCreate("file"), disabled: busy, children: /* @__PURE__ */ jsx18(FilePlusIcon, { className: "size-3.5" }) }),
|
|
7609
|
+
/* @__PURE__ */ jsx18(ToolbarButton, { label: "New folder", onClick: () => startCreate("dir"), disabled: busy, children: /* @__PURE__ */ jsx18(FolderPlusIcon, { className: "size-3.5" }) }),
|
|
7610
|
+
/* @__PURE__ */ jsx18(
|
|
7611
|
+
ToolbarButton,
|
|
7612
|
+
{
|
|
7613
|
+
label: "Rename",
|
|
7614
|
+
onClick: () => {
|
|
7615
|
+
const node = cursor ? findNode(result.tree, cursor) : void 0;
|
|
7616
|
+
if (node) startRename(node);
|
|
7617
|
+
},
|
|
7618
|
+
disabled: busy || !cursor,
|
|
7619
|
+
children: /* @__PURE__ */ jsx18(PencilIcon, { className: "size-3.5" })
|
|
7620
|
+
}
|
|
7621
|
+
),
|
|
7622
|
+
/* @__PURE__ */ jsx18(
|
|
7623
|
+
ToolbarButton,
|
|
7624
|
+
{
|
|
7625
|
+
label: "Delete",
|
|
7626
|
+
onClick: () => {
|
|
7627
|
+
const node = cursor ? findNode(result.tree, cursor) : void 0;
|
|
7628
|
+
if (node) void runDelete(node);
|
|
7629
|
+
},
|
|
7630
|
+
disabled: busy || !cursor,
|
|
7631
|
+
children: /* @__PURE__ */ jsx18(Trash2Icon, { className: "size-3.5" })
|
|
7632
|
+
}
|
|
7633
|
+
)
|
|
7634
|
+
] }) : null,
|
|
7061
7635
|
/* @__PURE__ */ jsx18("span", { className: "ml-auto" }),
|
|
7062
7636
|
/* @__PURE__ */ jsx18(ToolbarButton, { label: "Refresh", onClick: () => void result.refresh(), disabled: busy || result.loading, children: /* @__PURE__ */ jsx18(RefreshCwIcon, { className: cn("size-3.5", result.loading && "animate-spin") }) })
|
|
7063
7637
|
] }),
|
|
@@ -7081,7 +7655,7 @@ function FileBrowser({
|
|
|
7081
7655
|
} : void 0,
|
|
7082
7656
|
className: cn(
|
|
7083
7657
|
"min-w-0 flex-1 overflow-auto p-1 outline-none",
|
|
7084
|
-
dragOver === "" && "ring-1 ring-inset ring-
|
|
7658
|
+
dragOver === "" && "ring-1 ring-inset ring-og-accent"
|
|
7085
7659
|
),
|
|
7086
7660
|
"data-opengeni-file-tree": true,
|
|
7087
7661
|
children: [
|
|
@@ -7095,7 +7669,22 @@ function FileBrowser({
|
|
|
7095
7669
|
onCancel: () => setDraftCreate(null)
|
|
7096
7670
|
}
|
|
7097
7671
|
),
|
|
7098
|
-
|
|
7672
|
+
showErrorEmpty ? /* @__PURE__ */ jsxs15("div", { className: "flex flex-col items-start gap-2 p-2 text-og-sm text-og-fg-subtle", children: [
|
|
7673
|
+
/* @__PURE__ */ jsx18("div", { children: fallback ?? `Could not load files: ${result.error?.message ?? "refresh the file list to try again"}` }),
|
|
7674
|
+
/* @__PURE__ */ jsxs15(
|
|
7675
|
+
"button",
|
|
7676
|
+
{
|
|
7677
|
+
type: "button",
|
|
7678
|
+
onClick: () => void result.refresh(),
|
|
7679
|
+
disabled: result.loading,
|
|
7680
|
+
className: "inline-flex items-center gap-1.5 rounded-og-sm border border-og-border px-2 py-1 text-og-xs font-medium text-og-fg-muted transition-colors hover:border-og-border-strong hover:text-og-fg disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:min-h-10",
|
|
7681
|
+
children: [
|
|
7682
|
+
/* @__PURE__ */ jsx18(RefreshCwIcon, { className: cn("size-3.5", result.loading && "animate-spin"), "aria-hidden": true }),
|
|
7683
|
+
"Retry"
|
|
7684
|
+
]
|
|
7685
|
+
}
|
|
7686
|
+
)
|
|
7687
|
+
] }) : showEmpty ? /* @__PURE__ */ jsx18("div", { className: "p-2 text-og-sm text-og-fg-subtle", children: emptyState ?? "This directory is empty" }) : result.tree.map((node) => renderRow(node, 0))
|
|
7099
7688
|
]
|
|
7100
7689
|
}
|
|
7101
7690
|
),
|
|
@@ -7128,8 +7717,8 @@ function ToolbarButton({
|
|
|
7128
7717
|
onClick,
|
|
7129
7718
|
disabled,
|
|
7130
7719
|
className: cn(
|
|
7131
|
-
"inline-flex items-center justify-center rounded p-1 text-
|
|
7132
|
-
"hover:bg-
|
|
7720
|
+
"inline-flex items-center justify-center rounded-og-sm p-1 text-og-fg-muted pointer-coarse:min-h-10 pointer-coarse:min-w-10",
|
|
7721
|
+
"hover:bg-og-surface-2 hover:text-og-fg",
|
|
7133
7722
|
"disabled:cursor-not-allowed disabled:opacity-40"
|
|
7134
7723
|
),
|
|
7135
7724
|
children
|
|
@@ -7144,8 +7733,8 @@ function InlineInput({
|
|
|
7144
7733
|
onCancel
|
|
7145
7734
|
}) {
|
|
7146
7735
|
const [value, setValue] = useState24(initialValue);
|
|
7147
|
-
const ref =
|
|
7148
|
-
const doneRef =
|
|
7736
|
+
const ref = useRef18(null);
|
|
7737
|
+
const doneRef = useRef18(false);
|
|
7149
7738
|
useEffect17(() => {
|
|
7150
7739
|
const el = ref.current;
|
|
7151
7740
|
if (!el) return;
|
|
@@ -7184,8 +7773,8 @@ function InlineInput({
|
|
|
7184
7773
|
e.stopPropagation();
|
|
7185
7774
|
},
|
|
7186
7775
|
className: cn(
|
|
7187
|
-
"min-w-0 flex-1 rounded border bg-
|
|
7188
|
-
"border-
|
|
7776
|
+
"min-w-0 flex-1 rounded-og-sm border bg-og-bg px-1 py-0 text-og-sm",
|
|
7777
|
+
"border-og-accent text-og-fg",
|
|
7189
7778
|
"outline-none"
|
|
7190
7779
|
)
|
|
7191
7780
|
}
|
|
@@ -7215,9 +7804,9 @@ function ContextMenu({
|
|
|
7215
7804
|
onClick();
|
|
7216
7805
|
},
|
|
7217
7806
|
className: cn(
|
|
7218
|
-
"flex w-full items-center gap-2 px-2.5 py-1 text-left text-
|
|
7219
|
-
"hover:bg-
|
|
7220
|
-
danger ? "text-
|
|
7807
|
+
"flex w-full items-center gap-2 px-2.5 py-1 text-left text-og-sm pointer-coarse:min-h-10",
|
|
7808
|
+
"hover:bg-og-surface-2",
|
|
7809
|
+
danger ? "text-og-status-failed" : "text-og-fg"
|
|
7221
7810
|
),
|
|
7222
7811
|
children: [
|
|
7223
7812
|
icon,
|
|
@@ -7233,14 +7822,14 @@ function ContextMenu({
|
|
|
7233
7822
|
style: { left, top },
|
|
7234
7823
|
className: cn(
|
|
7235
7824
|
"fixed z-50 min-w-[160px] overflow-hidden rounded-md border py-1 shadow-lg",
|
|
7236
|
-
"border-
|
|
7237
|
-
"bg-
|
|
7825
|
+
"border-og-border",
|
|
7826
|
+
"bg-og-surface-1"
|
|
7238
7827
|
),
|
|
7239
7828
|
children: [
|
|
7240
7829
|
isDir && /* @__PURE__ */ jsxs15(Fragment5, { children: [
|
|
7241
7830
|
item("New file", /* @__PURE__ */ jsx18(FilePlusIcon, { className: "size-3.5" }), onNewFile),
|
|
7242
7831
|
item("New folder", /* @__PURE__ */ jsx18(FolderPlusIcon, { className: "size-3.5" }), onNewFolder),
|
|
7243
|
-
/* @__PURE__ */ jsx18("div", { className: "my-1 h-px bg-
|
|
7832
|
+
/* @__PURE__ */ jsx18("div", { className: "my-1 h-px bg-og-border" })
|
|
7244
7833
|
] }),
|
|
7245
7834
|
item("Rename", /* @__PURE__ */ jsx18(PencilIcon, { className: "size-3.5" }), onRename),
|
|
7246
7835
|
item("Delete", /* @__PURE__ */ jsx18(Trash2Icon, { className: "size-3.5" }), onDelete, true)
|
|
@@ -7293,12 +7882,12 @@ function PierreFile({
|
|
|
7293
7882
|
themeType: themeType ?? "dark"
|
|
7294
7883
|
};
|
|
7295
7884
|
const pierreVars = {
|
|
7296
|
-
"--diffs-dark-bg": "var(--og-color-bg
|
|
7297
|
-
"--diffs-light-bg": "var(--og-color-bg
|
|
7298
|
-
"--diffs-bg-buffer-override": "var(--og-color-surface-1
|
|
7299
|
-
"--diffs-bg-separator-override": "var(--og-color-surface-1
|
|
7300
|
-
"--diffs-font-size": "
|
|
7301
|
-
"--diffs-line-height": "
|
|
7885
|
+
"--diffs-dark-bg": "var(--og-color-bg)",
|
|
7886
|
+
"--diffs-light-bg": "var(--og-color-bg)",
|
|
7887
|
+
"--diffs-bg-buffer-override": "var(--og-color-surface-1)",
|
|
7888
|
+
"--diffs-bg-separator-override": "var(--og-color-surface-1)",
|
|
7889
|
+
"--diffs-font-size": "var(--og-code-font-size)",
|
|
7890
|
+
"--diffs-line-height": "var(--og-code-line-height)"
|
|
7302
7891
|
};
|
|
7303
7892
|
return /* @__PURE__ */ jsx19("div", { className: cn("min-w-0", className), "data-opengeni-pierre-file": true, style: pierreVars, children: /* @__PURE__ */ jsx19(Suspense2, { fallback: loading ?? /* @__PURE__ */ jsx19(FileSkeleton, {}), children: /* @__PURE__ */ jsx19(
|
|
7304
7893
|
LazyFile,
|
|
@@ -7313,14 +7902,14 @@ function PlainFile({ name, contents }) {
|
|
|
7313
7902
|
return /* @__PURE__ */ jsx19(
|
|
7314
7903
|
"pre",
|
|
7315
7904
|
{
|
|
7316
|
-
className: "overflow-auto whitespace-pre p-2 font-
|
|
7905
|
+
className: "overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg",
|
|
7317
7906
|
"data-file": name,
|
|
7318
7907
|
children: contents
|
|
7319
7908
|
}
|
|
7320
7909
|
);
|
|
7321
7910
|
}
|
|
7322
7911
|
function FileSkeleton() {
|
|
7323
|
-
return /* @__PURE__ */ jsx19("div", { className: "p-3 text-
|
|
7912
|
+
return /* @__PURE__ */ jsx19("div", { className: "p-3 text-og-sm text-og-fg-subtle", children: "Loading file\u2026" });
|
|
7324
7913
|
}
|
|
7325
7914
|
|
|
7326
7915
|
// src/components/code-editor.tsx
|
|
@@ -7328,10 +7917,10 @@ import { Loader2Icon as Loader2Icon2, SaveIcon } from "lucide-react";
|
|
|
7328
7917
|
import {
|
|
7329
7918
|
lazy as lazy3,
|
|
7330
7919
|
Suspense as Suspense3,
|
|
7331
|
-
useCallback as
|
|
7920
|
+
useCallback as useCallback24,
|
|
7332
7921
|
useEffect as useEffect19,
|
|
7333
7922
|
useMemo as useMemo10,
|
|
7334
|
-
useRef as
|
|
7923
|
+
useRef as useRef19,
|
|
7335
7924
|
useState as useState26
|
|
7336
7925
|
} from "react";
|
|
7337
7926
|
import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
@@ -7400,7 +7989,7 @@ function CodeEditor({
|
|
|
7400
7989
|
const [saveError, setSaveError] = useState26(null);
|
|
7401
7990
|
const [savedTick, setSavedTick] = useState26(false);
|
|
7402
7991
|
const dirty = value !== baseline;
|
|
7403
|
-
const lastSeed =
|
|
7992
|
+
const lastSeed = useRef19({ path, contents: initialContents });
|
|
7404
7993
|
useEffect19(() => {
|
|
7405
7994
|
const seedChanged = lastSeed.current.path !== path || lastSeed.current.contents !== initialContents;
|
|
7406
7995
|
if (!seedChanged) return;
|
|
@@ -7443,9 +8032,9 @@ function CodeEditor({
|
|
|
7443
8032
|
cancelled = true;
|
|
7444
8033
|
};
|
|
7445
8034
|
}, [langKey]);
|
|
7446
|
-
const saveRef =
|
|
8035
|
+
const saveRef = useRef19(() => {
|
|
7447
8036
|
});
|
|
7448
|
-
const save =
|
|
8037
|
+
const save = useCallback24(async () => {
|
|
7449
8038
|
if (readOnly) return;
|
|
7450
8039
|
const snapshot = value;
|
|
7451
8040
|
if (snapshot === baseline) return;
|
|
@@ -7498,18 +8087,18 @@ function CodeEditor({
|
|
|
7498
8087
|
"data-opengeni-code-editor": true,
|
|
7499
8088
|
style: editorVars,
|
|
7500
8089
|
children: [
|
|
7501
|
-
/* @__PURE__ */ jsxs16("div", { className: "flex shrink-0 items-center gap-2 border-b border-
|
|
8090
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1", children: [
|
|
7502
8091
|
/* @__PURE__ */ jsx20(
|
|
7503
8092
|
"span",
|
|
7504
8093
|
{
|
|
7505
8094
|
className: cn(
|
|
7506
8095
|
"size-1.5 shrink-0 rounded-full transition-colors",
|
|
7507
|
-
readOnly ? "bg-transparent" : dirty ? "bg-
|
|
8096
|
+
readOnly ? "bg-transparent" : dirty ? "bg-og-status-running" : "bg-og-status-idle"
|
|
7508
8097
|
),
|
|
7509
8098
|
title: readOnly ? "read-only" : dirty ? "unsaved changes" : "saved"
|
|
7510
8099
|
}
|
|
7511
8100
|
),
|
|
7512
|
-
/* @__PURE__ */ jsxs16("span", { className: "truncate font-
|
|
8101
|
+
/* @__PURE__ */ jsxs16("span", { className: "truncate font-og-mono text-og-xs text-og-fg-muted", children: [
|
|
7513
8102
|
fileName,
|
|
7514
8103
|
dirty && !readOnly ? " \u2022" : ""
|
|
7515
8104
|
] }),
|
|
@@ -7517,21 +8106,21 @@ function CodeEditor({
|
|
|
7517
8106
|
saveError && /* @__PURE__ */ jsx20(
|
|
7518
8107
|
"span",
|
|
7519
8108
|
{
|
|
7520
|
-
className: "max-w-[220px] truncate text-
|
|
8109
|
+
className: "max-w-[220px] truncate text-og-xs text-og-status-failed",
|
|
7521
8110
|
title: saveError.message,
|
|
7522
8111
|
children: saveError.message
|
|
7523
8112
|
}
|
|
7524
8113
|
),
|
|
7525
|
-
!saveError && savedTick && /* @__PURE__ */ jsx20("span", { className: "text-
|
|
7526
|
-
readOnly ? /* @__PURE__ */ jsx20("span", { className: "text-
|
|
8114
|
+
!saveError && savedTick && /* @__PURE__ */ jsx20("span", { className: "text-og-xs text-og-status-idle", children: "Saved" }),
|
|
8115
|
+
readOnly ? /* @__PURE__ */ jsx20("span", { className: "text-og-xs uppercase tracking-wide text-og-fg-subtle", children: "Read-only" }) : /* @__PURE__ */ jsxs16(
|
|
7527
8116
|
"button",
|
|
7528
8117
|
{
|
|
7529
8118
|
type: "button",
|
|
7530
8119
|
onClick: () => void save(),
|
|
7531
8120
|
disabled: saving || !dirty,
|
|
7532
8121
|
className: cn(
|
|
7533
|
-
"flex items-center gap-1 rounded-
|
|
7534
|
-
saving || !dirty ? "cursor-default text-
|
|
8122
|
+
"flex items-center gap-1 rounded-og-sm border border-og-border px-1.5 py-0.5 text-og-xs pointer-coarse:min-h-10",
|
|
8123
|
+
saving || !dirty ? "cursor-default text-og-fg-subtle opacity-60" : "text-og-fg hover:bg-og-accent-soft"
|
|
7535
8124
|
),
|
|
7536
8125
|
title: "Save (\u2318/Ctrl+S)",
|
|
7537
8126
|
children: [
|
|
@@ -7552,7 +8141,7 @@ function CodeEditor({
|
|
|
7552
8141
|
basicSetup: true,
|
|
7553
8142
|
extensions: cmExtensions,
|
|
7554
8143
|
height: "100%",
|
|
7555
|
-
className: "og-cm-editor min-h-full text-
|
|
8144
|
+
className: "og-cm-editor min-h-full text-og-sm",
|
|
7556
8145
|
onChange: readOnly ? void 0 : (next) => {
|
|
7557
8146
|
setValue(next);
|
|
7558
8147
|
setSavedTick(false);
|
|
@@ -7564,8 +8153,8 @@ function CodeEditor({
|
|
|
7564
8153
|
);
|
|
7565
8154
|
}
|
|
7566
8155
|
var editorVars = {
|
|
7567
|
-
"--og-cm-bg": "var(--og-color-bg
|
|
7568
|
-
fontFamily: "var(--og-font-mono
|
|
8156
|
+
"--og-cm-bg": "var(--og-color-bg)",
|
|
8157
|
+
fontFamily: "var(--og-font-mono)"
|
|
7569
8158
|
};
|
|
7570
8159
|
function PlainTextarea({
|
|
7571
8160
|
value,
|
|
@@ -7579,28 +8168,28 @@ function PlainTextarea({
|
|
|
7579
8168
|
readOnly,
|
|
7580
8169
|
spellCheck: false,
|
|
7581
8170
|
onChange: (e) => onChange(e.target.value),
|
|
7582
|
-
className: "h-full w-full resize-none bg-transparent p-2 font-
|
|
8171
|
+
className: "h-full w-full resize-none bg-transparent p-2 font-og-mono text-og-sm text-og-fg outline-none"
|
|
7583
8172
|
}
|
|
7584
8173
|
);
|
|
7585
8174
|
}
|
|
7586
8175
|
function EditorSkeleton() {
|
|
7587
|
-
return /* @__PURE__ */ jsx20("div", { className: "p-3 text-
|
|
8176
|
+
return /* @__PURE__ */ jsx20("div", { className: "p-3 text-og-sm text-og-fg-subtle", children: "Loading editor\u2026" });
|
|
7588
8177
|
}
|
|
7589
8178
|
|
|
7590
8179
|
// src/components/sandbox-files.tsx
|
|
7591
8180
|
import { FileIcon as FileIcon3 } from "lucide-react";
|
|
7592
|
-
import { useCallback as
|
|
8181
|
+
import { useCallback as useCallback25, useEffect as useEffect20, useMemo as useMemo11, useRef as useRef20, useState as useState27 } from "react";
|
|
7593
8182
|
import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
7594
8183
|
var STATUS_TINT2 = {
|
|
7595
|
-
added: "text-
|
|
7596
|
-
modified: "text-
|
|
7597
|
-
deleted: "text-
|
|
7598
|
-
renamed: "text-
|
|
7599
|
-
copied: "text-
|
|
7600
|
-
untracked: "text-
|
|
7601
|
-
ignored: "text-
|
|
7602
|
-
conflicted: "text-
|
|
7603
|
-
typechange: "text-
|
|
8184
|
+
added: "text-og-status-idle",
|
|
8185
|
+
modified: "text-og-status-running",
|
|
8186
|
+
deleted: "text-og-status-failed",
|
|
8187
|
+
renamed: "text-og-accent",
|
|
8188
|
+
copied: "text-og-accent",
|
|
8189
|
+
untracked: "text-og-fg-subtle",
|
|
8190
|
+
ignored: "text-og-fg-subtle",
|
|
8191
|
+
conflicted: "text-og-status-failed",
|
|
8192
|
+
typechange: "text-og-status-running"
|
|
7604
8193
|
};
|
|
7605
8194
|
var STATUS_LETTER = {
|
|
7606
8195
|
added: "A",
|
|
@@ -7627,7 +8216,7 @@ function SandboxFiles({
|
|
|
7627
8216
|
const [staged, setStaged] = useState27(false);
|
|
7628
8217
|
const [layout, setLayout] = useState27("unified");
|
|
7629
8218
|
const [editMode, setEditMode] = useState27(false);
|
|
7630
|
-
const rootRef =
|
|
8219
|
+
const rootRef = useRef20(null);
|
|
7631
8220
|
const [wide, setWide] = useState27(false);
|
|
7632
8221
|
useEffect20(() => {
|
|
7633
8222
|
const el = rootRef.current;
|
|
@@ -7647,7 +8236,7 @@ function SandboxFiles({
|
|
|
7647
8236
|
const selectedDiff = changed.find((f) => f.path === effectiveSelected) ?? null;
|
|
7648
8237
|
const viewPath = effectiveSelected && !selectedDiff ? effectiveSelected : null;
|
|
7649
8238
|
const fileView = useFileView(viewPath, files.readFile);
|
|
7650
|
-
const selectFile =
|
|
8239
|
+
const selectFile = useCallback25((path) => {
|
|
7651
8240
|
setSelected(path);
|
|
7652
8241
|
setEditMode(false);
|
|
7653
8242
|
}, []);
|
|
@@ -7664,11 +8253,11 @@ function SandboxFiles({
|
|
|
7664
8253
|
{
|
|
7665
8254
|
className: cn(
|
|
7666
8255
|
"min-h-0 overflow-auto",
|
|
7667
|
-
wide ? "w-[280px] shrink-0 border-r border-
|
|
8256
|
+
wide ? "w-[280px] shrink-0 border-r border-og-border" : "flex-1"
|
|
7668
8257
|
),
|
|
7669
8258
|
children: [
|
|
7670
|
-
changed.length > 0 && /* @__PURE__ */ jsxs17("div", { className: "border-b border-
|
|
7671
|
-
/* @__PURE__ */ jsxs17("div", { className: "px-2 py-1 text-
|
|
8259
|
+
changed.length > 0 && /* @__PURE__ */ jsxs17("div", { className: "border-b border-og-border", children: [
|
|
8260
|
+
/* @__PURE__ */ jsxs17("div", { className: "px-2 py-1 text-og-xs font-medium uppercase tracking-wide text-og-fg-subtle", children: [
|
|
7672
8261
|
"Changes \xB7 ",
|
|
7673
8262
|
changed.length
|
|
7674
8263
|
] }),
|
|
@@ -7678,15 +8267,15 @@ function SandboxFiles({
|
|
|
7678
8267
|
type: "button",
|
|
7679
8268
|
onClick: () => selectFile(file.path),
|
|
7680
8269
|
className: cn(
|
|
7681
|
-
"flex w-full items-center gap-1.5 truncate px-2 py-0.5 text-left text-
|
|
7682
|
-
file.path === effectiveSelected && "bg-
|
|
8270
|
+
"flex w-full items-center gap-1.5 truncate px-2 py-0.5 text-left text-og-sm hover:bg-og-surface-2 pointer-coarse:min-h-10",
|
|
8271
|
+
file.path === effectiveSelected && "bg-og-surface-2"
|
|
7683
8272
|
),
|
|
7684
8273
|
children: [
|
|
7685
8274
|
/* @__PURE__ */ jsx21(
|
|
7686
8275
|
"span",
|
|
7687
8276
|
{
|
|
7688
8277
|
className: cn(
|
|
7689
|
-
"w-3 shrink-0 text-center font-
|
|
8278
|
+
"w-3 shrink-0 text-center font-og-mono text-og-xs",
|
|
7690
8279
|
STATUS_TINT2[file.status]
|
|
7691
8280
|
),
|
|
7692
8281
|
children: STATUS_LETTER[file.status]
|
|
@@ -7694,12 +8283,12 @@ function SandboxFiles({
|
|
|
7694
8283
|
),
|
|
7695
8284
|
/* @__PURE__ */ jsx21(FileIcon3, { className: "size-3.5 shrink-0 opacity-70" }),
|
|
7696
8285
|
/* @__PURE__ */ jsx21("span", { className: "truncate", children: file.path }),
|
|
7697
|
-
/* @__PURE__ */ jsxs17("span", { className: "ml-auto flex shrink-0 items-center gap-1.5 pl-2 text-
|
|
7698
|
-
/* @__PURE__ */ jsxs17("span", { className: "text-
|
|
8286
|
+
/* @__PURE__ */ jsxs17("span", { className: "ml-auto flex shrink-0 items-center gap-1.5 pl-2 text-og-xs", children: [
|
|
8287
|
+
/* @__PURE__ */ jsxs17("span", { className: "text-og-status-idle", children: [
|
|
7699
8288
|
"+",
|
|
7700
8289
|
file.additions
|
|
7701
8290
|
] }),
|
|
7702
|
-
/* @__PURE__ */ jsxs17("span", { className: "text-
|
|
8291
|
+
/* @__PURE__ */ jsxs17("span", { className: "text-og-status-failed", children: [
|
|
7703
8292
|
"\u2212",
|
|
7704
8293
|
file.deletions
|
|
7705
8294
|
] })
|
|
@@ -7708,14 +8297,14 @@ function SandboxFiles({
|
|
|
7708
8297
|
}
|
|
7709
8298
|
) }, file.path)) })
|
|
7710
8299
|
] }),
|
|
7711
|
-
/* @__PURE__ */ jsx21("div", { className: "px-2 py-1 text-
|
|
8300
|
+
/* @__PURE__ */ jsx21("div", { className: "px-2 py-1 text-og-xs font-medium uppercase tracking-wide text-og-fg-subtle", children: "Files" }),
|
|
7712
8301
|
/* @__PURE__ */ jsx21(
|
|
7713
8302
|
FileBrowser,
|
|
7714
8303
|
{
|
|
7715
8304
|
result: files,
|
|
7716
8305
|
selectedPath: effectiveSelected ?? void 0,
|
|
7717
8306
|
onSelectFile: selectFile,
|
|
7718
|
-
emptyState: "
|
|
8307
|
+
emptyState: "This directory is empty",
|
|
7719
8308
|
className: "min-w-0"
|
|
7720
8309
|
}
|
|
7721
8310
|
)
|
|
@@ -7727,12 +8316,12 @@ function SandboxFiles({
|
|
|
7727
8316
|
{
|
|
7728
8317
|
className: cn(
|
|
7729
8318
|
"flex min-h-0 min-w-0 flex-col",
|
|
7730
|
-
wide ? "flex-1" : "flex-[1.4] border-t border-
|
|
8319
|
+
wide ? "flex-1" : "flex-[1.4] border-t border-og-border"
|
|
7731
8320
|
),
|
|
7732
8321
|
children: [
|
|
7733
|
-
/* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-
|
|
7734
|
-
/* @__PURE__ */ jsx21("span", { className: "truncate font-
|
|
7735
|
-
/* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
8322
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1", children: [
|
|
8323
|
+
/* @__PURE__ */ jsx21("span", { className: "min-w-0 truncate font-og-mono text-og-xs text-og-fg-muted", children: effectiveSelected ?? "No file selected" }),
|
|
8324
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex min-w-0 shrink-0 flex-wrap items-center justify-end gap-1", children: [
|
|
7736
8325
|
selectedDiff && stagedGit && /* @__PURE__ */ jsx21(
|
|
7737
8326
|
Segmented,
|
|
7738
8327
|
{
|
|
@@ -7809,7 +8398,7 @@ function SandboxFiles({
|
|
|
7809
8398
|
fileView.sizeBytes ?? 0,
|
|
7810
8399
|
" bytes)."
|
|
7811
8400
|
] }) : fileView.content !== null ? /* @__PURE__ */ jsxs17(Fragment6, { children: [
|
|
7812
|
-
fileView.truncated && /* @__PURE__ */ jsxs17("div", { className: "border-b border-
|
|
8401
|
+
fileView.truncated && /* @__PURE__ */ jsxs17("div", { className: "border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-xs text-og-status-running", children: [
|
|
7813
8402
|
"Large file \u2014 showing a truncated preview (",
|
|
7814
8403
|
fileView.sizeBytes ?? 0,
|
|
7815
8404
|
" bytes loaded). Editing is disabled to avoid corrupting the file."
|
|
@@ -7820,10 +8409,10 @@ function SandboxFiles({
|
|
|
7820
8409
|
path: viewPath,
|
|
7821
8410
|
contents: fileView.content,
|
|
7822
8411
|
themeType: resolvedTheme,
|
|
7823
|
-
fallback: /* @__PURE__ */ jsx21("pre", { className: "overflow-auto whitespace-pre p-2 font-
|
|
8412
|
+
fallback: /* @__PURE__ */ jsx21("pre", { className: "overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg", children: fileView.content }),
|
|
7824
8413
|
className: "p-1"
|
|
7825
8414
|
}
|
|
7826
|
-
) : /* @__PURE__ */ jsx21("pre", { className: "overflow-auto whitespace-pre p-2 font-
|
|
8415
|
+
) : /* @__PURE__ */ jsx21("pre", { className: "overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg", children: fileView.content })
|
|
7827
8416
|
] }) : /* @__PURE__ */ jsxs17(Notice, { children: [
|
|
7828
8417
|
"Loading ",
|
|
7829
8418
|
viewPath,
|
|
@@ -7842,19 +8431,19 @@ function SandboxFiles({
|
|
|
7842
8431
|
}
|
|
7843
8432
|
function GitHeader({ git, dirtyCount }) {
|
|
7844
8433
|
const dirty = dirtyCount > 0;
|
|
7845
|
-
return /* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center gap-2 border-b border-
|
|
8434
|
+
return /* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-sm", children: [
|
|
7846
8435
|
/* @__PURE__ */ jsx21(
|
|
7847
8436
|
"span",
|
|
7848
8437
|
{
|
|
7849
8438
|
className: cn(
|
|
7850
8439
|
"size-2 shrink-0 rounded-full",
|
|
7851
|
-
dirty ? "bg-
|
|
8440
|
+
dirty ? "bg-og-status-running" : "bg-og-status-idle"
|
|
7852
8441
|
),
|
|
7853
8442
|
title: dirty ? `${dirtyCount} changed` : "clean"
|
|
7854
8443
|
}
|
|
7855
8444
|
),
|
|
7856
|
-
/* @__PURE__ */ jsx21("span", { className: "truncate font-
|
|
7857
|
-
(git.ahead > 0 || git.behind > 0) && /* @__PURE__ */ jsxs17("span", { className: "flex shrink-0 items-center gap-1.5 text-
|
|
8445
|
+
/* @__PURE__ */ jsx21("span", { className: "truncate font-og-mono text-og-fg", children: git.branch ?? (git.isRepo ? "(detached)" : "no repo") }),
|
|
8446
|
+
(git.ahead > 0 || git.behind > 0) && /* @__PURE__ */ jsxs17("span", { className: "flex shrink-0 items-center gap-1.5 text-og-xs text-og-fg-subtle", children: [
|
|
7858
8447
|
git.ahead > 0 && /* @__PURE__ */ jsxs17("span", { children: [
|
|
7859
8448
|
"\u2191",
|
|
7860
8449
|
git.ahead
|
|
@@ -7864,7 +8453,7 @@ function GitHeader({ git, dirtyCount }) {
|
|
|
7864
8453
|
git.behind
|
|
7865
8454
|
] })
|
|
7866
8455
|
] }),
|
|
7867
|
-
dirty && /* @__PURE__ */ jsxs17("span", { className: "ml-auto shrink-0 text-
|
|
8456
|
+
dirty && /* @__PURE__ */ jsxs17("span", { className: "ml-auto shrink-0 text-og-xs text-og-fg-subtle", children: [
|
|
7868
8457
|
dirtyCount,
|
|
7869
8458
|
" changed"
|
|
7870
8459
|
] })
|
|
@@ -7875,14 +8464,14 @@ function Segmented({
|
|
|
7875
8464
|
value,
|
|
7876
8465
|
onChange
|
|
7877
8466
|
}) {
|
|
7878
|
-
return /* @__PURE__ */ jsx21("div", { className: "flex items-center rounded-
|
|
8467
|
+
return /* @__PURE__ */ jsx21("div", { className: "flex flex-wrap items-center rounded-og-sm border border-og-border p-0.5", children: options.map((opt) => /* @__PURE__ */ jsx21(
|
|
7879
8468
|
"button",
|
|
7880
8469
|
{
|
|
7881
8470
|
type: "button",
|
|
7882
8471
|
onClick: () => onChange(opt.value),
|
|
7883
8472
|
className: cn(
|
|
7884
|
-
"rounded-
|
|
7885
|
-
opt.value === value ? "bg-
|
|
8473
|
+
"rounded-og-xs px-1.5 py-0.5 text-og-xs pointer-coarse:min-h-10",
|
|
8474
|
+
opt.value === value ? "bg-og-accent-soft text-og-fg" : "text-og-fg-subtle hover:text-og-fg"
|
|
7886
8475
|
),
|
|
7887
8476
|
children: opt.label
|
|
7888
8477
|
},
|
|
@@ -7950,7 +8539,7 @@ function Notice({ children, className }) {
|
|
|
7950
8539
|
"div",
|
|
7951
8540
|
{
|
|
7952
8541
|
className: cn(
|
|
7953
|
-
"flex h-full items-center justify-center p-4 text-center text-
|
|
8542
|
+
"flex h-full items-center justify-center p-4 text-center text-og-sm text-og-fg-subtle",
|
|
7954
8543
|
className
|
|
7955
8544
|
),
|
|
7956
8545
|
children
|
|
@@ -7960,8 +8549,9 @@ function Notice({ children, className }) {
|
|
|
7960
8549
|
|
|
7961
8550
|
// src/components/desktop-viewer.tsx
|
|
7962
8551
|
import { LoaderCircleIcon as LoaderCircleIcon2, MonitorIcon, MousePointerClickIcon, WifiOffIcon } from "lucide-react";
|
|
7963
|
-
import { useEffect as useEffect21, useRef as
|
|
8552
|
+
import { useEffect as useEffect21, useRef as useRef21, useState as useState28 } from "react";
|
|
7964
8553
|
import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
8554
|
+
var DESKTOP_MEDIA_BACKGROUND = "#000";
|
|
7965
8555
|
function isHardUnavailable(reason) {
|
|
7966
8556
|
switch (reason) {
|
|
7967
8557
|
case "backend_unsupported":
|
|
@@ -7992,7 +8582,7 @@ function DesktopViewer({
|
|
|
7992
8582
|
connectTimeoutMs = 13e3,
|
|
7993
8583
|
className
|
|
7994
8584
|
}) {
|
|
7995
|
-
const containerRef =
|
|
8585
|
+
const containerRef = useRef21(null);
|
|
7996
8586
|
const [consented, setConsented] = useState28(false);
|
|
7997
8587
|
const [takeControl, setTakeControl] = useState28(interactive ?? false);
|
|
7998
8588
|
const externallyControlled = interactive !== void 0;
|
|
@@ -8034,9 +8624,9 @@ function DesktopViewer({
|
|
|
8034
8624
|
});
|
|
8035
8625
|
const connected = stream.state === "connected";
|
|
8036
8626
|
const hasLiveUrl = Boolean(connectCapability?.url);
|
|
8037
|
-
const streamStateRef =
|
|
8627
|
+
const streamStateRef = useRef21(stream.state);
|
|
8038
8628
|
streamStateRef.current = stream.state;
|
|
8039
|
-
const warmKeyRef =
|
|
8629
|
+
const warmKeyRef = useRef21(null);
|
|
8040
8630
|
useEffect21(() => {
|
|
8041
8631
|
if (!isWatching || !coldWarmable || needsAck || viewerCapReached) {
|
|
8042
8632
|
if (!coldWarmable) warmKeyRef.current = null;
|
|
@@ -8115,10 +8705,11 @@ function DesktopViewer({
|
|
|
8115
8705
|
"div",
|
|
8116
8706
|
{
|
|
8117
8707
|
className: cn(
|
|
8118
|
-
"relative h-full w-full overflow-hidden
|
|
8119
|
-
inControl && "ring-2 ring-inset ring-
|
|
8708
|
+
"relative h-full w-full overflow-hidden",
|
|
8709
|
+
inControl && "ring-2 ring-inset ring-og-accent",
|
|
8120
8710
|
className
|
|
8121
8711
|
),
|
|
8712
|
+
style: { backgroundColor: DESKTOP_MEDIA_BACKGROUND },
|
|
8122
8713
|
"data-opengeni-desktop": true,
|
|
8123
8714
|
"data-state": stream.state,
|
|
8124
8715
|
"data-ui-state": uiState,
|
|
@@ -8133,18 +8724,18 @@ function DesktopViewer({
|
|
|
8133
8724
|
"data-state": stream.state
|
|
8134
8725
|
}
|
|
8135
8726
|
),
|
|
8136
|
-
uiState === "connecting" && /* @__PURE__ */ jsxs18("div", { className: "pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-3 text-
|
|
8727
|
+
uiState === "connecting" && /* @__PURE__ */ jsxs18("div", { className: "pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-3 text-og-fg-subtle", children: [
|
|
8137
8728
|
/* @__PURE__ */ jsxs18("span", { className: "relative flex items-center justify-center", children: [
|
|
8138
8729
|
/* @__PURE__ */ jsx22(MonitorIcon, { className: "size-8 opacity-30", strokeWidth: 1.5 }),
|
|
8139
8730
|
/* @__PURE__ */ jsx22(
|
|
8140
8731
|
LoaderCircleIcon2,
|
|
8141
8732
|
{
|
|
8142
|
-
className: "absolute size-12 animate-og-spin text-
|
|
8733
|
+
className: "absolute size-12 animate-og-spin text-og-accent opacity-70",
|
|
8143
8734
|
strokeWidth: 1.25
|
|
8144
8735
|
}
|
|
8145
8736
|
)
|
|
8146
8737
|
] }),
|
|
8147
|
-
/* @__PURE__ */ jsx22("span", { className: "text-
|
|
8738
|
+
/* @__PURE__ */ jsx22("span", { className: "text-og-sm", children: "Connecting to the desktop\u2026" })
|
|
8148
8739
|
] }),
|
|
8149
8740
|
showToggle && !externallyControlled && inControl && /* @__PURE__ */ jsx22(
|
|
8150
8741
|
InControlBar,
|
|
@@ -8157,7 +8748,7 @@ function DesktopViewer({
|
|
|
8157
8748
|
TakeControlCallToAction,
|
|
8158
8749
|
{
|
|
8159
8750
|
disabled: !serverAllowsControl,
|
|
8160
|
-
disabledReason: !serverAllowsControl ? capability?.client === "frames" ? "View-only \u2014 live control isn't available for this machine yet." : "This deployment streams the desktop read-only" : void 0,
|
|
8751
|
+
disabledReason: !serverAllowsControl ? capability?.client === "frames" ? "View-only \u2014 live control isn't available for this machine yet." : "This deployment streams the desktop read-only." : void 0,
|
|
8161
8752
|
onTakeControl: () => setTakeControl(true)
|
|
8162
8753
|
}
|
|
8163
8754
|
),
|
|
@@ -8183,16 +8774,16 @@ function TakeControlCallToAction({
|
|
|
8183
8774
|
title: disabled ? disabledReason : "Take control of the desktop",
|
|
8184
8775
|
onClick: onTakeControl,
|
|
8185
8776
|
className: cn(
|
|
8186
|
-
"group pointer-events-auto flex items-center gap-3 rounded-
|
|
8187
|
-
"border-
|
|
8188
|
-
"bg-
|
|
8189
|
-
"shadow-
|
|
8777
|
+
"group pointer-events-auto flex items-center gap-3 rounded-og-lg border px-5 py-3",
|
|
8778
|
+
"border-og-border",
|
|
8779
|
+
"bg-og-bg/85 backdrop-blur-md",
|
|
8780
|
+
"shadow-og-lg",
|
|
8190
8781
|
"outline-none transition-all duration-150 ease-out",
|
|
8191
|
-
"focus-visible:ring-2 focus-visible:ring-
|
|
8782
|
+
"focus-visible:ring-2 focus-visible:ring-og-accent focus-visible:ring-offset-2 focus-visible:ring-offset-og-bg",
|
|
8192
8783
|
disabled ? "cursor-not-allowed opacity-60" : cn(
|
|
8193
8784
|
"cursor-pointer opacity-90 hover:-translate-y-0.5 hover:opacity-100",
|
|
8194
|
-
"hover:border-
|
|
8195
|
-
"hover:bg-
|
|
8785
|
+
"hover:border-og-accent",
|
|
8786
|
+
"hover:bg-og-accent/10"
|
|
8196
8787
|
)
|
|
8197
8788
|
),
|
|
8198
8789
|
children: [
|
|
@@ -8201,16 +8792,16 @@ function TakeControlCallToAction({
|
|
|
8201
8792
|
{
|
|
8202
8793
|
className: cn(
|
|
8203
8794
|
"flex size-9 shrink-0 items-center justify-center rounded-full transition-colors",
|
|
8204
|
-
"bg-
|
|
8205
|
-
"text-
|
|
8795
|
+
"bg-og-accent",
|
|
8796
|
+
"text-og-accent-fg",
|
|
8206
8797
|
disabled ? "" : "group-hover:scale-105"
|
|
8207
8798
|
),
|
|
8208
8799
|
children: /* @__PURE__ */ jsx22(MousePointerClickIcon, { className: "size-5", strokeWidth: 2 })
|
|
8209
8800
|
}
|
|
8210
8801
|
),
|
|
8211
8802
|
/* @__PURE__ */ jsxs18("span", { className: "flex flex-col items-start leading-tight", children: [
|
|
8212
|
-
/* @__PURE__ */ jsx22("span", { className: "text-
|
|
8213
|
-
/* @__PURE__ */ jsx22("span", { className: "text-
|
|
8803
|
+
/* @__PURE__ */ jsx22("span", { className: "text-og-base font-semibold text-og-fg", children: "Take control" }),
|
|
8804
|
+
/* @__PURE__ */ jsx22("span", { className: "text-og-xs text-og-fg-subtle", children: disabled && disabledReason ? disabledReason : "Drive the mouse & keyboard" })
|
|
8214
8805
|
] })
|
|
8215
8806
|
]
|
|
8216
8807
|
}
|
|
@@ -8219,13 +8810,13 @@ function TakeControlCallToAction({
|
|
|
8219
8810
|
}
|
|
8220
8811
|
function InControlBar({ shared, onRelease }) {
|
|
8221
8812
|
return /* @__PURE__ */ jsxs18("div", { className: "pointer-events-none absolute inset-x-0 top-0 flex items-center justify-between gap-2 p-2", children: [
|
|
8222
|
-
/* @__PURE__ */ jsxs18("span", { className: "pointer-events-auto inline-flex items-center gap-2 rounded-
|
|
8813
|
+
/* @__PURE__ */ jsxs18("span", { className: "pointer-events-auto inline-flex items-center gap-2 rounded-og-sm bg-og-accent px-2.5 py-1 text-og-xs font-medium text-og-accent-fg shadow-og-md", children: [
|
|
8223
8814
|
/* @__PURE__ */ jsx22("span", { className: "size-1.5 animate-pulse rounded-full bg-current", "aria-hidden": true }),
|
|
8224
8815
|
"You're in control",
|
|
8225
8816
|
/* @__PURE__ */ jsx22("span", { className: "opacity-75", children: "\xB7 click Return control (or Ctrl+Alt+Shift)" })
|
|
8226
8817
|
] }),
|
|
8227
8818
|
/* @__PURE__ */ jsxs18("div", { className: "pointer-events-auto flex items-center gap-1.5", children: [
|
|
8228
|
-
shared && /* @__PURE__ */ jsx22("span", { className: "rounded-
|
|
8819
|
+
shared && /* @__PURE__ */ jsx22("span", { className: "rounded-og-sm bg-og-status-failed/85 px-2 py-0.5 text-og-xs text-og-accent-fg", children: "Shared sandbox \u2014 others are watching" }),
|
|
8229
8820
|
/* @__PURE__ */ jsxs18(
|
|
8230
8821
|
"button",
|
|
8231
8822
|
{
|
|
@@ -8233,9 +8824,9 @@ function InControlBar({ shared, onRelease }) {
|
|
|
8233
8824
|
onClick: onRelease,
|
|
8234
8825
|
title: "Return control (or press Ctrl+Alt+Shift)",
|
|
8235
8826
|
className: cn(
|
|
8236
|
-
"inline-flex items-center gap-1.5 rounded-
|
|
8237
|
-
"border-
|
|
8238
|
-
"outline-none hover:bg-
|
|
8827
|
+
"inline-flex items-center gap-1.5 rounded-og-sm border px-2.5 py-1 text-og-xs font-semibold shadow-og-md transition-colors",
|
|
8828
|
+
"border-og-accent bg-og-bg/90 text-og-fg backdrop-blur-sm",
|
|
8829
|
+
"outline-none hover:bg-og-accent hover:text-og-accent-fg focus-visible:ring-2 focus-visible:ring-og-accent"
|
|
8239
8830
|
),
|
|
8240
8831
|
children: [
|
|
8241
8832
|
/* @__PURE__ */ jsx22(MonitorIcon, { className: "size-3.5", strokeWidth: 2, "aria-hidden": true }),
|
|
@@ -8255,7 +8846,7 @@ function unavailableCopy(reason) {
|
|
|
8255
8846
|
case "os_unsupported":
|
|
8256
8847
|
return "The sandbox OS does not support a desktop stream.";
|
|
8257
8848
|
case "not_provisioned":
|
|
8258
|
-
return "
|
|
8849
|
+
return "This sandbox doesn't have a desktop yet.";
|
|
8259
8850
|
case "disabled_by_policy":
|
|
8260
8851
|
return "Desktop streaming is disabled on this deployment.";
|
|
8261
8852
|
case "lease_cold":
|
|
@@ -8265,62 +8856,62 @@ function unavailableCopy(reason) {
|
|
|
8265
8856
|
}
|
|
8266
8857
|
}
|
|
8267
8858
|
function WarmingNotice({ onRetry }) {
|
|
8268
|
-
return /* @__PURE__ */ jsxs18("div", { className: "flex max-w-sm flex-col items-center gap-3 rounded-lg border border-
|
|
8859
|
+
return /* @__PURE__ */ jsxs18("div", { className: "flex max-w-sm flex-col items-center gap-3 rounded-og-lg border border-og-border bg-og-bg/90 p-5 text-center text-og-base text-og-fg backdrop-blur-sm", children: [
|
|
8269
8860
|
/* @__PURE__ */ jsx22(
|
|
8270
8861
|
LoaderCircleIcon2,
|
|
8271
8862
|
{
|
|
8272
|
-
className: "size-7 animate-og-spin text-
|
|
8863
|
+
className: "size-7 animate-og-spin text-og-accent",
|
|
8273
8864
|
strokeWidth: 1.5
|
|
8274
8865
|
}
|
|
8275
8866
|
),
|
|
8276
8867
|
/* @__PURE__ */ jsxs18("div", { className: "space-y-1", children: [
|
|
8277
8868
|
/* @__PURE__ */ jsx22("div", { className: "font-medium", children: "Warming the sandbox\u2026" }),
|
|
8278
|
-
/* @__PURE__ */ jsx22("p", { className: "text-
|
|
8869
|
+
/* @__PURE__ */ jsx22("p", { className: "text-og-sm text-og-fg-subtle", children: "Spinning up the desktop \u2014 this takes a few seconds." })
|
|
8279
8870
|
] }),
|
|
8280
8871
|
onRetry && /* @__PURE__ */ jsx22(
|
|
8281
8872
|
"button",
|
|
8282
8873
|
{
|
|
8283
8874
|
type: "button",
|
|
8284
8875
|
onClick: onRetry,
|
|
8285
|
-
className: "rounded border border-
|
|
8876
|
+
className: "rounded-og-sm border border-og-border px-3 py-1.5 text-og-sm text-og-fg-muted transition-colors hover:text-og-fg pointer-coarse:min-h-10",
|
|
8286
8877
|
children: "Taking too long? Retry"
|
|
8287
8878
|
}
|
|
8288
8879
|
)
|
|
8289
8880
|
] });
|
|
8290
8881
|
}
|
|
8291
8882
|
function DefaultConsentGate({ shared, onAccept }) {
|
|
8292
|
-
return /* @__PURE__ */ jsxs18("div", { className: "max-w-sm rounded-lg border border-
|
|
8883
|
+
return /* @__PURE__ */ jsxs18("div", { className: "max-w-sm rounded-og-lg border border-og-border bg-og-bg p-4 text-center text-og-base text-og-fg", children: [
|
|
8293
8884
|
/* @__PURE__ */ jsx22("div", { className: "mb-1 font-medium", children: "Watch the live desktop?" }),
|
|
8294
|
-
/* @__PURE__ */ jsxs18("p", { className: "mb-3 text-
|
|
8885
|
+
/* @__PURE__ */ jsxs18("p", { className: "mb-3 text-og-sm text-og-fg-subtle", children: [
|
|
8295
8886
|
"The desktop pixel stream is ",
|
|
8296
8887
|
/* @__PURE__ */ jsx22("strong", { children: "un-redacted" }),
|
|
8297
8888
|
" \u2014 it can show secrets the agent prints on screen.",
|
|
8298
|
-
shared ? " This
|
|
8889
|
+
shared ? " This sandbox is shared: you'll also see other sessions' agents on the same screen." : ""
|
|
8299
8890
|
] }),
|
|
8300
8891
|
/* @__PURE__ */ jsx22(
|
|
8301
8892
|
"button",
|
|
8302
8893
|
{
|
|
8303
8894
|
type: "button",
|
|
8304
8895
|
onClick: onAccept,
|
|
8305
|
-
className: "rounded bg-
|
|
8896
|
+
className: "rounded-og-sm bg-og-accent px-3 py-1.5 text-og-sm font-medium text-og-accent-fg pointer-coarse:min-h-10",
|
|
8306
8897
|
children: "I understand \u2014 show the desktop"
|
|
8307
8898
|
}
|
|
8308
8899
|
)
|
|
8309
8900
|
] });
|
|
8310
8901
|
}
|
|
8311
8902
|
function defaultNotice(title, body, onRetry) {
|
|
8312
|
-
return /* @__PURE__ */ jsxs18("div", { className: "max-w-sm rounded-lg border border-
|
|
8903
|
+
return /* @__PURE__ */ jsxs18("div", { className: "max-w-sm rounded-og-lg border border-og-border bg-og-bg p-4 text-center text-og-base text-og-fg", children: [
|
|
8313
8904
|
/* @__PURE__ */ jsxs18("div", { className: "mb-1 flex items-center justify-center gap-1.5 font-medium", children: [
|
|
8314
8905
|
onRetry && /* @__PURE__ */ jsx22(WifiOffIcon, { className: "size-4 opacity-70", strokeWidth: 1.75 }),
|
|
8315
8906
|
title
|
|
8316
8907
|
] }),
|
|
8317
|
-
/* @__PURE__ */ jsx22("p", { className: "text-
|
|
8908
|
+
/* @__PURE__ */ jsx22("p", { className: "text-og-sm text-og-fg-subtle", children: body }),
|
|
8318
8909
|
onRetry && /* @__PURE__ */ jsx22(
|
|
8319
8910
|
"button",
|
|
8320
8911
|
{
|
|
8321
8912
|
type: "button",
|
|
8322
8913
|
onClick: onRetry,
|
|
8323
|
-
className: "mt-3 rounded border border-
|
|
8914
|
+
className: "mt-3 rounded-og-sm border border-og-border px-3 py-1.5 text-og-sm transition-colors hover:border-og-accent pointer-coarse:min-h-10",
|
|
8324
8915
|
children: "Reconnect"
|
|
8325
8916
|
}
|
|
8326
8917
|
)
|
|
@@ -8328,12 +8919,13 @@ function defaultNotice(title, body, onRetry) {
|
|
|
8328
8919
|
}
|
|
8329
8920
|
|
|
8330
8921
|
// src/components/workspace-dock.tsx
|
|
8331
|
-
import { useCallback as
|
|
8922
|
+
import { useCallback as useCallback26, useEffect as useEffect22, useLayoutEffect as useLayoutEffect2, useState as useState29 } from "react";
|
|
8332
8923
|
import {
|
|
8333
8924
|
ChevronsLeftRightIcon,
|
|
8334
8925
|
Maximize2Icon,
|
|
8335
8926
|
Minimize2Icon,
|
|
8336
|
-
PanelRightCloseIcon
|
|
8927
|
+
PanelRightCloseIcon,
|
|
8928
|
+
XIcon as XIcon3
|
|
8337
8929
|
} from "lucide-react";
|
|
8338
8930
|
import {
|
|
8339
8931
|
Group,
|
|
@@ -8343,7 +8935,26 @@ import {
|
|
|
8343
8935
|
usePanelRef
|
|
8344
8936
|
} from "react-resizable-panels";
|
|
8345
8937
|
import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
8346
|
-
var useDockLayoutEffect = typeof window === "undefined" ? useEffect22 :
|
|
8938
|
+
var useDockLayoutEffect = typeof window === "undefined" ? useEffect22 : useLayoutEffect2;
|
|
8939
|
+
var DOCK_OVERLAY_BREAKPOINT = 1024;
|
|
8940
|
+
function useIsNarrow(maxWidth) {
|
|
8941
|
+
const [narrow, setNarrow] = useState29(false);
|
|
8942
|
+
useDockLayoutEffect(() => {
|
|
8943
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
8944
|
+
return;
|
|
8945
|
+
}
|
|
8946
|
+
const mql = window.matchMedia(`(max-width: ${maxWidth - 1}px)`);
|
|
8947
|
+
const update = () => setNarrow(mql.matches);
|
|
8948
|
+
update();
|
|
8949
|
+
if (typeof mql.addEventListener === "function") {
|
|
8950
|
+
mql.addEventListener("change", update);
|
|
8951
|
+
return () => mql.removeEventListener("change", update);
|
|
8952
|
+
}
|
|
8953
|
+
mql.addListener(update);
|
|
8954
|
+
return () => mql.removeListener(update);
|
|
8955
|
+
}, [maxWidth]);
|
|
8956
|
+
return narrow;
|
|
8957
|
+
}
|
|
8347
8958
|
function WorkspaceDock({
|
|
8348
8959
|
primary,
|
|
8349
8960
|
tabs,
|
|
@@ -8357,11 +8968,13 @@ function WorkspaceDock({
|
|
|
8357
8968
|
maxSize = 70,
|
|
8358
8969
|
className
|
|
8359
8970
|
}) {
|
|
8971
|
+
const narrow = useIsNarrow(DOCK_OVERLAY_BREAKPOINT);
|
|
8360
8972
|
const dockPanelRef = usePanelRef();
|
|
8361
8973
|
const [internalCollapsed, setInternalCollapsed] = useState29(false);
|
|
8362
8974
|
const [maximized, setMaximized] = useState29(false);
|
|
8363
8975
|
const [internalTab, setInternalTab] = useState29(tabs[0]?.id ?? "");
|
|
8364
8976
|
const collapsed = collapsedProp ?? internalCollapsed;
|
|
8977
|
+
const hostControlled = collapsedProp !== void 0;
|
|
8365
8978
|
const { defaultLayout, onLayoutChanged } = useDefaultLayout({
|
|
8366
8979
|
panelIds: ["primary", "dock"],
|
|
8367
8980
|
storage: typeof window !== "undefined" ? window.localStorage : void 0,
|
|
@@ -8370,14 +8983,14 @@ function WorkspaceDock({
|
|
|
8370
8983
|
const current = activeTab ?? internalTab;
|
|
8371
8984
|
const tabIds = tabs.map((tab) => tab.id).join("\0");
|
|
8372
8985
|
const firstTabId = tabs[0]?.id ?? "";
|
|
8373
|
-
const setTab =
|
|
8986
|
+
const setTab = useCallback26(
|
|
8374
8987
|
(id) => {
|
|
8375
8988
|
setInternalTab(id);
|
|
8376
8989
|
onActiveTabChange?.(id);
|
|
8377
8990
|
},
|
|
8378
8991
|
[onActiveTabChange]
|
|
8379
8992
|
);
|
|
8380
|
-
const setCollapsed =
|
|
8993
|
+
const setCollapsed = useCallback26(
|
|
8381
8994
|
(next) => {
|
|
8382
8995
|
setInternalCollapsed((previous) => previous === next ? previous : next);
|
|
8383
8996
|
onCollapsedChange?.(next);
|
|
@@ -8400,31 +9013,70 @@ function WorkspaceDock({
|
|
|
8400
9013
|
setTab(firstTabId);
|
|
8401
9014
|
}
|
|
8402
9015
|
}, [tabIds, firstTabId, current, setTab]);
|
|
8403
|
-
|
|
8404
|
-
if (!maximized) return;
|
|
8405
|
-
const onKey = (event) => {
|
|
8406
|
-
if (event.key === "Escape") setMaximized(false);
|
|
8407
|
-
};
|
|
8408
|
-
window.addEventListener("keydown", onKey);
|
|
8409
|
-
return () => window.removeEventListener("keydown", onKey);
|
|
8410
|
-
}, [maximized]);
|
|
8411
|
-
const collapse = useCallback24(() => {
|
|
9016
|
+
const collapse = useCallback26(() => {
|
|
8412
9017
|
dockPanelRef.current?.collapse();
|
|
8413
9018
|
setCollapsed(true);
|
|
8414
9019
|
}, [dockPanelRef, setCollapsed]);
|
|
8415
|
-
const expand =
|
|
9020
|
+
const expand = useCallback26(() => {
|
|
8416
9021
|
dockPanelRef.current?.expand();
|
|
8417
9022
|
setCollapsed(false);
|
|
8418
9023
|
}, [dockPanelRef, setCollapsed]);
|
|
9024
|
+
useEffect22(() => {
|
|
9025
|
+
const overlayOpen = maximized || narrow && !collapsed;
|
|
9026
|
+
if (!overlayOpen) return;
|
|
9027
|
+
const onKey = (event) => {
|
|
9028
|
+
if (event.key !== "Escape") return;
|
|
9029
|
+
if (maximized) setMaximized(false);
|
|
9030
|
+
else collapse();
|
|
9031
|
+
};
|
|
9032
|
+
window.addEventListener("keydown", onKey);
|
|
9033
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
9034
|
+
}, [maximized, narrow, collapsed, collapse]);
|
|
9035
|
+
if (narrow) {
|
|
9036
|
+
return /* @__PURE__ */ jsxs19("div", { className: cn("relative flex h-full min-h-0 w-full min-w-0", className), children: [
|
|
9037
|
+
/* @__PURE__ */ jsx23("div", { className: "min-h-0 min-w-0 flex-1", children: primary }),
|
|
9038
|
+
!collapsed && /* @__PURE__ */ jsx23(
|
|
9039
|
+
"div",
|
|
9040
|
+
{
|
|
9041
|
+
role: "dialog",
|
|
9042
|
+
"aria-modal": "true",
|
|
9043
|
+
"aria-label": "Workspace",
|
|
9044
|
+
className: "fixed inset-0 z-40 flex flex-col bg-og-bg",
|
|
9045
|
+
style: {
|
|
9046
|
+
paddingTop: "env(safe-area-inset-top)",
|
|
9047
|
+
paddingBottom: "env(safe-area-inset-bottom)"
|
|
9048
|
+
},
|
|
9049
|
+
children: /* @__PURE__ */ jsx23(
|
|
9050
|
+
DockChrome,
|
|
9051
|
+
{
|
|
9052
|
+
tabs,
|
|
9053
|
+
current,
|
|
9054
|
+
onTab: setTab,
|
|
9055
|
+
controls: /* @__PURE__ */ jsx23(ChromeButton, { onClick: collapse, title: "Close workspace", label: "Close workspace", children: /* @__PURE__ */ jsx23(XIcon3, { className: "size-4" }) })
|
|
9056
|
+
}
|
|
9057
|
+
)
|
|
9058
|
+
}
|
|
9059
|
+
)
|
|
9060
|
+
] });
|
|
9061
|
+
}
|
|
8419
9062
|
const dockChrome = /* @__PURE__ */ jsx23(
|
|
8420
9063
|
DockChrome,
|
|
8421
9064
|
{
|
|
8422
9065
|
tabs,
|
|
8423
9066
|
current,
|
|
8424
9067
|
onTab: setTab,
|
|
8425
|
-
|
|
8426
|
-
|
|
8427
|
-
|
|
9068
|
+
controls: /* @__PURE__ */ jsxs19(Fragment7, { children: [
|
|
9069
|
+
/* @__PURE__ */ jsx23(
|
|
9070
|
+
ChromeButton,
|
|
9071
|
+
{
|
|
9072
|
+
onClick: () => setMaximized((m) => !m),
|
|
9073
|
+
title: maximized ? "Restore (Esc)" : "Maximize",
|
|
9074
|
+
label: maximized ? "Restore dock" : "Maximize dock",
|
|
9075
|
+
children: maximized ? /* @__PURE__ */ jsx23(Minimize2Icon, { className: "size-3.5" }) : /* @__PURE__ */ jsx23(Maximize2Icon, { className: "size-3.5" })
|
|
9076
|
+
}
|
|
9077
|
+
),
|
|
9078
|
+
hostControlled ? null : /* @__PURE__ */ jsx23(ChromeButton, { onClick: collapse, title: "Collapse", label: "Collapse dock", children: /* @__PURE__ */ jsx23(PanelRightCloseIcon, { className: "size-3.5" }) })
|
|
9079
|
+
] })
|
|
8428
9080
|
}
|
|
8429
9081
|
);
|
|
8430
9082
|
return /* @__PURE__ */ jsxs19("div", { className: cn("relative flex h-full min-h-0 w-full min-w-0", className), children: [
|
|
@@ -8437,7 +9089,7 @@ function WorkspaceDock({
|
|
|
8437
9089
|
onLayoutChanged,
|
|
8438
9090
|
children: [
|
|
8439
9091
|
/* @__PURE__ */ jsx23(Panel, { id: "primary", minSize: "30%", className: "min-h-0 min-w-0", children: primary }),
|
|
8440
|
-
!collapsed && /* @__PURE__ */ jsx23(Separator, { className: "group relative w-1.5 shrink-0 outline-none", children: /* @__PURE__ */ jsx23("span", { className: "absolute inset-y-0 left-1/2 w-px -translate-x-1/2 bg-
|
|
9092
|
+
!collapsed && /* @__PURE__ */ jsx23(Separator, { className: "group relative w-1.5 shrink-0 outline-none", children: /* @__PURE__ */ jsx23("span", { className: "absolute inset-y-0 left-1/2 w-px -translate-x-1/2 bg-og-border transition-colors group-hover:bg-og-accent group-data-[separator-state=dragging]:bg-og-accent" }) }),
|
|
8441
9093
|
/* @__PURE__ */ jsx23(
|
|
8442
9094
|
Panel,
|
|
8443
9095
|
{
|
|
@@ -8456,83 +9108,85 @@ function WorkspaceDock({
|
|
|
8456
9108
|
}
|
|
8457
9109
|
},
|
|
8458
9110
|
className: "min-h-0 min-w-0",
|
|
8459
|
-
children: !collapsed && !maximized && /* @__PURE__ */ jsx23("div", { className: "flex h-full min-h-0 min-w-0 flex-col border-l border-
|
|
9111
|
+
children: !collapsed && !maximized && /* @__PURE__ */ jsx23("div", { className: "flex h-full min-h-0 min-w-0 flex-col border-l border-og-border bg-og-bg", children: dockChrome })
|
|
8460
9112
|
}
|
|
8461
9113
|
)
|
|
8462
9114
|
]
|
|
8463
9115
|
}
|
|
8464
9116
|
),
|
|
8465
|
-
collapsed && !maximized && /* @__PURE__ */ jsx23(
|
|
9117
|
+
collapsed && !maximized && !hostControlled && /* @__PURE__ */ jsx23(
|
|
8466
9118
|
"button",
|
|
8467
9119
|
{
|
|
8468
9120
|
type: "button",
|
|
8469
9121
|
onClick: expand,
|
|
8470
9122
|
title: "Open workspace",
|
|
8471
|
-
className: "absolute inset-y-0 right-0 flex w-6 shrink-0 items-center justify-center border-l border-
|
|
9123
|
+
className: "absolute inset-y-0 right-0 flex w-6 shrink-0 items-center justify-center border-l border-og-border bg-og-surface-1 text-og-fg-subtle hover:text-og-fg",
|
|
8472
9124
|
children: /* @__PURE__ */ jsx23(ChevronsLeftRightIcon, { className: "size-3.5" })
|
|
8473
9125
|
}
|
|
8474
9126
|
),
|
|
8475
|
-
maximized && /* @__PURE__ */ jsx23("div", { className: "fixed inset-0 z-40 flex flex-col bg-
|
|
9127
|
+
maximized && /* @__PURE__ */ jsx23("div", { className: "fixed inset-0 z-40 flex flex-col bg-og-bg", children: dockChrome })
|
|
8476
9128
|
] });
|
|
8477
9129
|
}
|
|
9130
|
+
function ChromeButton({
|
|
9131
|
+
onClick,
|
|
9132
|
+
title,
|
|
9133
|
+
label,
|
|
9134
|
+
children
|
|
9135
|
+
}) {
|
|
9136
|
+
return /* @__PURE__ */ jsx23(
|
|
9137
|
+
"button",
|
|
9138
|
+
{
|
|
9139
|
+
type: "button",
|
|
9140
|
+
onClick,
|
|
9141
|
+
title,
|
|
9142
|
+
"aria-label": label,
|
|
9143
|
+
className: "inline-flex items-center justify-center rounded-og-sm p-1 transition-colors hover:bg-og-surface-2 hover:text-og-fg pointer-coarse:size-10",
|
|
9144
|
+
children
|
|
9145
|
+
}
|
|
9146
|
+
);
|
|
9147
|
+
}
|
|
8478
9148
|
function DockChrome({
|
|
8479
9149
|
tabs,
|
|
8480
9150
|
current,
|
|
8481
9151
|
onTab,
|
|
8482
|
-
|
|
8483
|
-
onToggleMaximize,
|
|
8484
|
-
onCollapse
|
|
9152
|
+
controls
|
|
8485
9153
|
}) {
|
|
8486
9154
|
const active = tabs.find((t) => t.id === current) ?? tabs[0];
|
|
8487
9155
|
return /* @__PURE__ */ jsxs19(Fragment7, { children: [
|
|
8488
|
-
/* @__PURE__ */ jsxs19("div", { className: "flex shrink-0 items-center
|
|
8489
|
-
/* @__PURE__ */ jsx23(
|
|
8490
|
-
"
|
|
9156
|
+
/* @__PURE__ */ jsxs19("div", { className: "flex shrink-0 items-center gap-2 border-b border-og-border px-1.5 py-1", children: [
|
|
9157
|
+
/* @__PURE__ */ jsx23(
|
|
9158
|
+
"div",
|
|
8491
9159
|
{
|
|
8492
|
-
|
|
8493
|
-
role: "
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
children: maximized ? /* @__PURE__ */ jsx23(Minimize2Icon, { className: "size-3.5" }) : /* @__PURE__ */ jsx23(Maximize2Icon, { className: "size-3.5" })
|
|
8516
|
-
}
|
|
8517
|
-
),
|
|
8518
|
-
/* @__PURE__ */ jsx23(
|
|
8519
|
-
"button",
|
|
8520
|
-
{
|
|
8521
|
-
type: "button",
|
|
8522
|
-
onClick: onCollapse,
|
|
8523
|
-
title: maximized ? "Restore" : "Collapse",
|
|
8524
|
-
className: "rounded-[var(--og-radius-sm,4px)] p-1 hover:bg-[color:var(--og-color-surface-2,var(--color-surface-2,#222))] hover:text-[color:var(--og-color-fg,var(--color-fg,#e6e6e6))]",
|
|
8525
|
-
children: /* @__PURE__ */ jsx23(PanelRightCloseIcon, { className: "size-3.5" })
|
|
8526
|
-
}
|
|
8527
|
-
)
|
|
8528
|
-
] })
|
|
9160
|
+
className: "flex min-w-0 flex-1 items-center gap-0.5 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
9161
|
+
role: "tablist",
|
|
9162
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsxs19(
|
|
9163
|
+
"button",
|
|
9164
|
+
{
|
|
9165
|
+
type: "button",
|
|
9166
|
+
role: "tab",
|
|
9167
|
+
"aria-selected": tab.id === current,
|
|
9168
|
+
onClick: () => onTab(tab.id),
|
|
9169
|
+
className: cn(
|
|
9170
|
+
"flex shrink-0 items-center gap-1 rounded-og-sm px-2 py-1 text-og-xs font-medium transition-colors pointer-coarse:min-h-10",
|
|
9171
|
+
tab.id === current ? "bg-og-accent-soft text-og-fg" : "text-og-fg-subtle hover:text-og-fg"
|
|
9172
|
+
),
|
|
9173
|
+
children: [
|
|
9174
|
+
/* @__PURE__ */ jsx23("span", { children: tab.label }),
|
|
9175
|
+
tab.badge
|
|
9176
|
+
]
|
|
9177
|
+
},
|
|
9178
|
+
tab.id
|
|
9179
|
+
))
|
|
9180
|
+
}
|
|
9181
|
+
),
|
|
9182
|
+
/* @__PURE__ */ jsx23("div", { className: "flex shrink-0 items-center gap-0.5 text-og-fg-subtle", children: controls })
|
|
8529
9183
|
] }),
|
|
8530
9184
|
/* @__PURE__ */ jsx23("div", { className: "min-h-0 min-w-0 flex-1 overflow-hidden", role: "tabpanel", children: active?.content })
|
|
8531
9185
|
] });
|
|
8532
9186
|
}
|
|
8533
9187
|
|
|
8534
9188
|
// src/hooks/use-codex-accounts.ts
|
|
8535
|
-
import { useCallback as
|
|
9189
|
+
import { useCallback as useCallback27, useState as useState30 } from "react";
|
|
8536
9190
|
function isCodexAccountEvent(event) {
|
|
8537
9191
|
return event.type === "codex.account.switched" || event.type === "turn.started";
|
|
8538
9192
|
}
|
|
@@ -8549,7 +9203,7 @@ function useCodexAccounts(options = {}) {
|
|
|
8549
9203
|
const codexClient = options.codexClient ?? client;
|
|
8550
9204
|
const sessionId = options.sessionId;
|
|
8551
9205
|
const sharedEvents = options.events;
|
|
8552
|
-
const load =
|
|
9206
|
+
const load = useCallback27(async () => {
|
|
8553
9207
|
const accountsP = codexClient.listCodexAccounts(workspaceId);
|
|
8554
9208
|
const sessionP = sessionId && codexClient.getSession ? codexClient.getSession(workspaceId, sessionId).catch(() => null) : Promise.resolve(null);
|
|
8555
9209
|
const [acc, session] = await Promise.all([accountsP, sessionP]);
|
|
@@ -8573,7 +9227,7 @@ function useCodexAccounts(options = {}) {
|
|
|
8573
9227
|
() => void state.refresh(),
|
|
8574
9228
|
{ enabled: options.enabled ?? true, ...sharedEvents !== void 0 ? { events: sharedEvents } : {} }
|
|
8575
9229
|
);
|
|
8576
|
-
const pin =
|
|
9230
|
+
const pin = useCallback27(
|
|
8577
9231
|
async (target) => {
|
|
8578
9232
|
if (!sessionId || !codexClient.pinSessionCodexAccount) {
|
|
8579
9233
|
return false;
|
|
@@ -8589,7 +9243,7 @@ function useCodexAccounts(options = {}) {
|
|
|
8589
9243
|
},
|
|
8590
9244
|
[codexClient, workspaceId, sessionId, mutation.run, state.refresh]
|
|
8591
9245
|
);
|
|
8592
|
-
const refreshUsage =
|
|
9246
|
+
const refreshUsage = useCallback27(
|
|
8593
9247
|
async () => {
|
|
8594
9248
|
if (!codexClient.refreshCodexUsage) {
|
|
8595
9249
|
return false;
|
|
@@ -8628,16 +9282,13 @@ function xtermThemeFromTokens(root) {
|
|
|
8628
9282
|
if (typeof window === "undefined" || typeof getComputedStyle === "undefined") return void 0;
|
|
8629
9283
|
const el = root ?? document.documentElement;
|
|
8630
9284
|
const style = getComputedStyle(el);
|
|
8631
|
-
const read = (
|
|
8632
|
-
|
|
8633
|
-
|
|
8634
|
-
if (value) return value;
|
|
8635
|
-
}
|
|
8636
|
-
return void 0;
|
|
9285
|
+
const read = (name) => {
|
|
9286
|
+
const value = style.getPropertyValue(name).trim();
|
|
9287
|
+
return value || void 0;
|
|
8637
9288
|
};
|
|
8638
|
-
const bg = read(
|
|
8639
|
-
const fg = read(
|
|
8640
|
-
const accent = read(
|
|
9289
|
+
const bg = read("--og-color-bg");
|
|
9290
|
+
const fg = read("--og-color-fg");
|
|
9291
|
+
const accent = read("--og-color-accent");
|
|
8641
9292
|
const theme = {};
|
|
8642
9293
|
if (bg) theme.background = bg;
|
|
8643
9294
|
if (fg) theme.foreground = fg;
|
|
@@ -8663,6 +9314,7 @@ export {
|
|
|
8663
9314
|
DisclosureDefaultsProvider,
|
|
8664
9315
|
EnrollmentConsent,
|
|
8665
9316
|
EnrollmentDeviceFlow,
|
|
9317
|
+
FILE_ONLY_MESSAGE_TEXT,
|
|
8666
9318
|
FileBrowser,
|
|
8667
9319
|
FleetTile,
|
|
8668
9320
|
LightboxProvider,
|
|
@@ -8718,6 +9370,7 @@ export {
|
|
|
8718
9370
|
gitFileDiffToPatch,
|
|
8719
9371
|
groupTimeline,
|
|
8720
9372
|
hasPermission,
|
|
9373
|
+
humanizeFailureReason,
|
|
8721
9374
|
isApplyPatch,
|
|
8722
9375
|
isCodexAccountEvent,
|
|
8723
9376
|
isExecSessionLostBanner,
|