@opengeni/react 0.6.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-DEW2ZNF2.js → chunk-5C7RGAWA.js} +70 -37
- package/dist/chunk-5C7RGAWA.js.map +1 -0
- package/dist/index.d.ts +29 -5
- package/dist/index.js +1061 -618
- package/dist/index.js.map +1 -1
- package/dist/{machines-BD6h9P_s.d.ts → machines-Bv9tG7qZ.d.ts} +1 -1
- package/dist/machines.d.ts +1 -1
- package/dist/machines.js +1 -1
- package/package.json +2 -2
- 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 +75 -4
- 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/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 +1 -1
- package/src/timeline/parsers.ts +104 -0
- package/src/timeline/projection.ts +135 -3
- 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 +21 -3
- package/src/timeline/types.ts +2 -0
- 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";
|
|
@@ -105,7 +106,8 @@ var WORKER_MESSAGE_TOOL = "session_send_message";
|
|
|
105
106
|
var WORKER_INTERRUPT_TOOL = "session_interrupt";
|
|
106
107
|
function buildTimeline(events) {
|
|
107
108
|
const items = [];
|
|
108
|
-
const
|
|
109
|
+
const prescan = prescanTurnAnchors(events);
|
|
110
|
+
const ordered = orderTimelineEvents(events, prescan);
|
|
109
111
|
const last = () => items[items.length - 1];
|
|
110
112
|
const closeStreamingTail = () => {
|
|
111
113
|
const open = last();
|
|
@@ -139,6 +141,7 @@ function buildTimeline(events) {
|
|
|
139
141
|
kind: "user-message",
|
|
140
142
|
id: event.id,
|
|
141
143
|
text: typeof payload.text === "string" ? payload.text : "",
|
|
144
|
+
...event.pendingUserMessage ? { pending: true } : {},
|
|
142
145
|
resources: resourceRefs(payload.resources),
|
|
143
146
|
tools: toolRefs(payload.tools),
|
|
144
147
|
occurredAt: event.occurredAt
|
|
@@ -363,6 +366,9 @@ ${message}` : message;
|
|
|
363
366
|
break;
|
|
364
367
|
}
|
|
365
368
|
case "turn.cancelled": {
|
|
369
|
+
if (turnId && !prescan.startedTurnIds.has(turnId)) {
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
366
372
|
const hadActivity = hasTurnActivity(items, turnId);
|
|
367
373
|
finalizeOpen(turnId, "cancelled");
|
|
368
374
|
items.push(turnEndItem(event, "cancelled", null));
|
|
@@ -443,6 +449,108 @@ function groupTimeline(items) {
|
|
|
443
449
|
}
|
|
444
450
|
return groups;
|
|
445
451
|
}
|
|
452
|
+
function prescanTurnAnchors(events) {
|
|
453
|
+
const ordered = [...events].sort((a, b) => a.sequence - b.sequence);
|
|
454
|
+
const queuedTurnByTrigger = /* @__PURE__ */ new Map();
|
|
455
|
+
const startSeqByTrigger = /* @__PURE__ */ new Map();
|
|
456
|
+
const cancelledTurnIds = /* @__PURE__ */ new Set();
|
|
457
|
+
const fallbackSeqByTurn = /* @__PURE__ */ new Map();
|
|
458
|
+
const startedTurnIds = /* @__PURE__ */ new Set();
|
|
459
|
+
for (const event of ordered) {
|
|
460
|
+
const payload = asRecord(event.payload);
|
|
461
|
+
const turnId = event.turnId ?? null;
|
|
462
|
+
if (event.type === "turn.queued") {
|
|
463
|
+
const triggerEventId = typeof payload.triggerEventId === "string" ? payload.triggerEventId : null;
|
|
464
|
+
const queuedTurnId = typeof payload.turnId === "string" ? payload.turnId : turnId;
|
|
465
|
+
if (triggerEventId && queuedTurnId) {
|
|
466
|
+
queuedTurnByTrigger.set(triggerEventId, queuedTurnId);
|
|
467
|
+
}
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
if (event.type === "turn.started") {
|
|
471
|
+
const triggerEventId = typeof payload.triggerEventId === "string" ? payload.triggerEventId : null;
|
|
472
|
+
if (triggerEventId) {
|
|
473
|
+
startSeqByTrigger.set(triggerEventId, event.sequence);
|
|
474
|
+
}
|
|
475
|
+
if (turnId) {
|
|
476
|
+
startedTurnIds.add(turnId);
|
|
477
|
+
}
|
|
478
|
+
} else if (event.type === "turn.cancelled" && turnId) {
|
|
479
|
+
cancelledTurnIds.add(turnId);
|
|
480
|
+
}
|
|
481
|
+
if (turnId && event.type !== "turn.queued" && event.type !== "turn.cancelled") {
|
|
482
|
+
const previous = fallbackSeqByTurn.get(turnId);
|
|
483
|
+
if (previous === void 0 || event.sequence < previous) {
|
|
484
|
+
fallbackSeqByTurn.set(turnId, event.sequence);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
if (turnId && isAgentActivityEvent(event.type)) {
|
|
488
|
+
startedTurnIds.add(turnId);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
for (const [triggerEventId, turnId] of queuedTurnByTrigger) {
|
|
492
|
+
if (!startSeqByTrigger.has(triggerEventId)) {
|
|
493
|
+
const fallbackSeq = fallbackSeqByTurn.get(turnId);
|
|
494
|
+
if (fallbackSeq !== void 0) {
|
|
495
|
+
startSeqByTrigger.set(triggerEventId, fallbackSeq);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
const cancelledBeforeStartTriggers = /* @__PURE__ */ new Set();
|
|
500
|
+
for (const [triggerEventId, turnId] of queuedTurnByTrigger) {
|
|
501
|
+
if (cancelledTurnIds.has(turnId) && !startSeqByTrigger.has(triggerEventId) && !fallbackSeqByTurn.has(turnId)) {
|
|
502
|
+
cancelledBeforeStartTriggers.add(triggerEventId);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return { queuedTurnByTrigger, startSeqByTrigger, cancelledBeforeStartTriggers, startedTurnIds };
|
|
506
|
+
}
|
|
507
|
+
function orderTimelineEvents(events, prescan) {
|
|
508
|
+
const ordered = [...events].sort((a, b) => a.sequence - b.sequence);
|
|
509
|
+
const insertions = /* @__PURE__ */ new Map();
|
|
510
|
+
const pending = [];
|
|
511
|
+
for (const event of ordered) {
|
|
512
|
+
if (event.type !== "user.message") {
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
const queuedTurnId = prescan.queuedTurnByTrigger.get(event.id);
|
|
516
|
+
if (!queuedTurnId) {
|
|
517
|
+
pushInsertion(insertions, event.sequence, event);
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
if (prescan.cancelledBeforeStartTriggers.has(event.id)) {
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
const startSeq = prescan.startSeqByTrigger.get(event.id);
|
|
524
|
+
if (startSeq !== void 0) {
|
|
525
|
+
pushInsertion(insertions, startSeq, event);
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
pending.push({ ...event, pendingUserMessage: true });
|
|
529
|
+
}
|
|
530
|
+
const projected = [];
|
|
531
|
+
for (const event of ordered) {
|
|
532
|
+
const before = insertions.get(event.sequence);
|
|
533
|
+
if (before) {
|
|
534
|
+
projected.push(...before);
|
|
535
|
+
}
|
|
536
|
+
if (event.type !== "user.message") {
|
|
537
|
+
projected.push(event);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
projected.push(...pending);
|
|
541
|
+
return projected;
|
|
542
|
+
}
|
|
543
|
+
function pushInsertion(insertions, sequence, event) {
|
|
544
|
+
const bucket = insertions.get(sequence);
|
|
545
|
+
if (bucket) {
|
|
546
|
+
bucket.push(event);
|
|
547
|
+
} else {
|
|
548
|
+
insertions.set(sequence, [event]);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
function isAgentActivityEvent(type) {
|
|
552
|
+
return type.startsWith("agent.") || type.startsWith("sandbox.");
|
|
553
|
+
}
|
|
446
554
|
function turnEndItem(event, outcome, failureText) {
|
|
447
555
|
return {
|
|
448
556
|
kind: "turn-end",
|
|
@@ -625,7 +733,7 @@ function failureMessage(payload) {
|
|
|
625
733
|
for (const key of ["error", "message"]) {
|
|
626
734
|
const value = payload[key];
|
|
627
735
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
628
|
-
return value;
|
|
736
|
+
return humanizeFailureReason(value);
|
|
629
737
|
}
|
|
630
738
|
}
|
|
631
739
|
return null;
|
|
@@ -921,6 +1029,88 @@ function unwrapMcpOutput(output) {
|
|
|
921
1029
|
}
|
|
922
1030
|
return { text: typeof output === "string" ? output : output == null ? "" : JSON.stringify(output), isError: false };
|
|
923
1031
|
}
|
|
1032
|
+
function screenshotDataUrl(out) {
|
|
1033
|
+
if (typeof out === "string") {
|
|
1034
|
+
if (out.startsWith("data:image")) {
|
|
1035
|
+
return out;
|
|
1036
|
+
}
|
|
1037
|
+
if (out.startsWith("{") || out.startsWith("[")) {
|
|
1038
|
+
const parsed = tryParseJson(out);
|
|
1039
|
+
if (parsed !== void 0 && parsed !== out) {
|
|
1040
|
+
return screenshotDataUrl(parsed);
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
return null;
|
|
1044
|
+
}
|
|
1045
|
+
if (Array.isArray(out)) {
|
|
1046
|
+
for (const entry of out) {
|
|
1047
|
+
const url = screenshotDataUrl(entry);
|
|
1048
|
+
if (url) {
|
|
1049
|
+
return url;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
return null;
|
|
1053
|
+
}
|
|
1054
|
+
if (out === null || typeof out !== "object") {
|
|
1055
|
+
return null;
|
|
1056
|
+
}
|
|
1057
|
+
const record = out;
|
|
1058
|
+
const imageUrl = record.image_url ?? record.imageUrl;
|
|
1059
|
+
if (typeof imageUrl === "string" && imageUrl.startsWith("data:image")) {
|
|
1060
|
+
return imageUrl;
|
|
1061
|
+
}
|
|
1062
|
+
if (imageUrl && typeof imageUrl === "object") {
|
|
1063
|
+
const url = imageUrl.url;
|
|
1064
|
+
if (typeof url === "string" && url.startsWith("data:image")) {
|
|
1065
|
+
return url;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
const image = record.image;
|
|
1069
|
+
if (image && typeof image === "object") {
|
|
1070
|
+
const mediaType = typeof image.mediaType === "string" ? image.mediaType : "image/png";
|
|
1071
|
+
const base64 = bytesToBase64(image.data);
|
|
1072
|
+
if (base64) {
|
|
1073
|
+
return `data:${mediaType};base64,${base64}`;
|
|
1074
|
+
}
|
|
1075
|
+
if (typeof image.data === "string" && image.data.length > 0) {
|
|
1076
|
+
return `data:${mediaType};base64,${image.data}`;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
return null;
|
|
1080
|
+
}
|
|
1081
|
+
function bytesToBase64(data) {
|
|
1082
|
+
const isByte = (n) => typeof n === "number" && Number.isInteger(n) && n >= 0 && n <= 255;
|
|
1083
|
+
let bytes = null;
|
|
1084
|
+
if (Array.isArray(data) && data.every(isByte)) {
|
|
1085
|
+
bytes = data;
|
|
1086
|
+
} else if (data && typeof data === "object") {
|
|
1087
|
+
const record = data;
|
|
1088
|
+
if (record.type === "Buffer" && Array.isArray(record.data) && record.data.every(isByte)) {
|
|
1089
|
+
bytes = record.data;
|
|
1090
|
+
} else {
|
|
1091
|
+
const keys = Object.keys(record);
|
|
1092
|
+
if (keys.length > 0 && keys.every((key) => /^\d+$/.test(key))) {
|
|
1093
|
+
const values = keys.sort((a, b) => Number(a) - Number(b)).map((key) => record[key]);
|
|
1094
|
+
if (values.every(isByte)) {
|
|
1095
|
+
bytes = values;
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
if (!bytes || bytes.length === 0) {
|
|
1101
|
+
return null;
|
|
1102
|
+
}
|
|
1103
|
+
try {
|
|
1104
|
+
let binary = "";
|
|
1105
|
+
const CHUNK = 32768;
|
|
1106
|
+
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
1107
|
+
binary += String.fromCharCode(...bytes.slice(i, i + CHUNK));
|
|
1108
|
+
}
|
|
1109
|
+
return typeof btoa === "function" ? btoa(binary) : Buffer.from(binary, "binary").toString("base64");
|
|
1110
|
+
} catch {
|
|
1111
|
+
return null;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
924
1114
|
|
|
925
1115
|
// src/timeline/shared.tsx
|
|
926
1116
|
import { CameraIcon, CameraOffIcon, ChevronRightIcon } from "lucide-react";
|
|
@@ -1024,7 +1214,7 @@ function LightboxRoot({ children }) {
|
|
|
1024
1214
|
}
|
|
1025
1215
|
)
|
|
1026
1216
|
] }),
|
|
1027
|
-
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-
|
|
1217
|
+
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" })
|
|
1028
1218
|
] })
|
|
1029
1219
|
]
|
|
1030
1220
|
}
|
|
@@ -1065,7 +1255,10 @@ function ActivityDisclosure({
|
|
|
1065
1255
|
const previewVisible = preview != null && !open;
|
|
1066
1256
|
const rowClass = cn(
|
|
1067
1257
|
"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",
|
|
1068
|
-
"text-og-fg-muted transition-colors duration-150"
|
|
1258
|
+
"text-og-fg-muted transition-colors duration-150",
|
|
1259
|
+
// A tool row is a touch target on coarse pointers: grow its padding so the
|
|
1260
|
+
// hit area clears the 40px minimum without loosening the dense desktop rail.
|
|
1261
|
+
"pointer-coarse:py-2.5"
|
|
1069
1262
|
);
|
|
1070
1263
|
const inner = /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1071
1264
|
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" }),
|
|
@@ -1140,7 +1333,7 @@ function TermBlock({
|
|
|
1140
1333
|
const shown = full || !big ? output : lines.slice(-tailLines).join("\n");
|
|
1141
1334
|
const showMore = big && !full;
|
|
1142
1335
|
const showHeader = command != null || workdir != null;
|
|
1143
|
-
return /* @__PURE__ */ jsxs2("div", { className: "overflow-hidden rounded-og-sm border border-og-border bg-og-bg/70", children: [
|
|
1336
|
+
return /* @__PURE__ */ jsxs2("div", { className: "min-w-0 overflow-hidden rounded-og-sm border border-og-border bg-og-bg/70", children: [
|
|
1144
1337
|
showHeader ? /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 border-b border-og-border/70 px-2.5 py-1.5", children: [
|
|
1145
1338
|
/* @__PURE__ */ jsx3("span", { className: "select-none text-og-status-idle", children: "$" }),
|
|
1146
1339
|
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" }),
|
|
@@ -1305,7 +1498,7 @@ function DiffView({
|
|
|
1305
1498
|
return /* @__PURE__ */ jsx4("div", { className, children: fallback });
|
|
1306
1499
|
}
|
|
1307
1500
|
if (diff.length === 0) {
|
|
1308
|
-
return /* @__PURE__ */ jsx4("div", { className: cn("p-3 text-
|
|
1501
|
+
return /* @__PURE__ */ jsx4("div", { className: cn("p-3 text-og-sm text-og-fg-subtle", className), children: emptyState ?? (isRepo ? "No changes" : "No repository mounted") });
|
|
1309
1502
|
}
|
|
1310
1503
|
return /* @__PURE__ */ jsx4("div", { className: cn("min-w-0 overflow-auto", className), "data-opengeni-diff": true, children: diff.map((file) => /* @__PURE__ */ jsx4(
|
|
1311
1504
|
FileDiffBlock,
|
|
@@ -1324,24 +1517,24 @@ function FileDiffBlock({
|
|
|
1324
1517
|
theme,
|
|
1325
1518
|
onSelect
|
|
1326
1519
|
}) {
|
|
1327
|
-
return /* @__PURE__ */ jsxs3("section", { className: "mb-2 overflow-hidden rounded border border-
|
|
1520
|
+
return /* @__PURE__ */ jsxs3("section", { className: "mb-2 overflow-hidden rounded-og-sm border border-og-border", children: [
|
|
1328
1521
|
/* @__PURE__ */ jsxs3(
|
|
1329
1522
|
"header",
|
|
1330
1523
|
{
|
|
1331
1524
|
className: cn(
|
|
1332
|
-
"flex items-center justify-between gap-2 border-b border-
|
|
1525
|
+
"flex items-center justify-between gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-sm",
|
|
1333
1526
|
onSelect && "cursor-pointer"
|
|
1334
1527
|
),
|
|
1335
1528
|
onClick: onSelect,
|
|
1336
1529
|
children: [
|
|
1337
|
-
/* @__PURE__ */ jsx4("span", { className: "truncate font-mono", children: file.oldPath && file.oldPath !== file.path ? `${file.oldPath} \u2192 ${file.path}` : file.path }),
|
|
1530
|
+
/* @__PURE__ */ jsx4("span", { className: "truncate font-og-mono", children: file.oldPath && file.oldPath !== file.path ? `${file.oldPath} \u2192 ${file.path}` : file.path }),
|
|
1338
1531
|
/* @__PURE__ */ jsxs3("span", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1339
|
-
/* @__PURE__ */ jsx4("span", { className: "rounded bg-
|
|
1340
|
-
/* @__PURE__ */ jsxs3("span", { className: "text-
|
|
1532
|
+
/* @__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] }),
|
|
1533
|
+
/* @__PURE__ */ jsxs3("span", { className: "text-og-status-idle", children: [
|
|
1341
1534
|
"+",
|
|
1342
1535
|
file.additions
|
|
1343
1536
|
] }),
|
|
1344
|
-
/* @__PURE__ */ jsxs3("span", { className: "text-
|
|
1537
|
+
/* @__PURE__ */ jsxs3("span", { className: "text-og-status-failed", children: [
|
|
1345
1538
|
"\u2212",
|
|
1346
1539
|
file.deletions
|
|
1347
1540
|
] })
|
|
@@ -1349,12 +1542,12 @@ function FileDiffBlock({
|
|
|
1349
1542
|
]
|
|
1350
1543
|
}
|
|
1351
1544
|
),
|
|
1352
|
-
file.isBinary ? /* @__PURE__ */ jsx4("div", { className: "px-2 py-3 text-
|
|
1545
|
+
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 })
|
|
1353
1546
|
] });
|
|
1354
1547
|
}
|
|
1355
1548
|
function lineBg(type, theme) {
|
|
1356
|
-
if (type === "add") return theme?.addBackground ?? "var(--color-diff-add
|
|
1357
|
-
if (type === "del") return theme?.delBackground ?? "var(--color-diff-del
|
|
1549
|
+
if (type === "add") return theme?.addBackground ?? "var(--og-color-diff-add-bg)";
|
|
1550
|
+
if (type === "del") return theme?.delBackground ?? "var(--og-color-diff-del-bg)";
|
|
1358
1551
|
if (type === "meta") return void 0;
|
|
1359
1552
|
return theme?.contextBackground;
|
|
1360
1553
|
}
|
|
@@ -1364,11 +1557,11 @@ function marker(type) {
|
|
|
1364
1557
|
return " ";
|
|
1365
1558
|
}
|
|
1366
1559
|
function UnifiedHunks({ file, theme }) {
|
|
1367
|
-
return /* @__PURE__ */ jsx4("div", { className: "font-mono text-
|
|
1560
|
+
return /* @__PURE__ */ jsx4("div", { className: "font-og-mono text-og-xs", children: file.hunks.map((hunk, hi) => /* @__PURE__ */ jsxs3("div", { children: [
|
|
1368
1561
|
/* @__PURE__ */ jsx4(
|
|
1369
1562
|
"div",
|
|
1370
1563
|
{
|
|
1371
|
-
className: "px-2 py-0.5 text-
|
|
1564
|
+
className: "px-2 py-0.5 text-og-accent",
|
|
1372
1565
|
style: { color: theme?.metaForeground },
|
|
1373
1566
|
children: hunk.header
|
|
1374
1567
|
}
|
|
@@ -1379,9 +1572,9 @@ function UnifiedHunks({ file, theme }) {
|
|
|
1379
1572
|
className: "flex",
|
|
1380
1573
|
style: { backgroundColor: lineBg(line.type, theme) },
|
|
1381
1574
|
children: [
|
|
1382
|
-
/* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-
|
|
1383
|
-
/* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-
|
|
1384
|
-
/* @__PURE__ */ jsx4("span", { className: "w-4 shrink-0 select-none text-center text-
|
|
1575
|
+
/* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle", children: line.oldNo ?? "" }),
|
|
1576
|
+
/* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle", children: line.newNo ?? "" }),
|
|
1577
|
+
/* @__PURE__ */ jsx4("span", { className: "w-4 shrink-0 select-none text-center text-og-fg-subtle", children: marker(line.type) }),
|
|
1385
1578
|
/* @__PURE__ */ jsx4("span", { className: "whitespace-pre-wrap break-all px-1", children: line.text })
|
|
1386
1579
|
]
|
|
1387
1580
|
},
|
|
@@ -1390,7 +1583,7 @@ function UnifiedHunks({ file, theme }) {
|
|
|
1390
1583
|
] }, `${file.path}-h${hi}`)) });
|
|
1391
1584
|
}
|
|
1392
1585
|
function SplitHunks({ file, theme }) {
|
|
1393
|
-
return /* @__PURE__ */ jsx4("div", { className: "font-mono text-
|
|
1586
|
+
return /* @__PURE__ */ jsx4("div", { className: "font-og-mono text-og-xs", children: file.hunks.map((hunk, hi) => {
|
|
1394
1587
|
const left = [];
|
|
1395
1588
|
const right = [];
|
|
1396
1589
|
for (const line of hunk.lines) {
|
|
@@ -1405,7 +1598,7 @@ function SplitHunks({ file, theme }) {
|
|
|
1405
1598
|
}
|
|
1406
1599
|
const rows = Math.max(left.length, right.length);
|
|
1407
1600
|
return /* @__PURE__ */ jsxs3("div", { children: [
|
|
1408
|
-
/* @__PURE__ */ jsx4("div", { className: "px-2 py-0.5 text-
|
|
1601
|
+
/* @__PURE__ */ jsx4("div", { className: "px-2 py-0.5 text-og-accent", style: { color: theme?.metaForeground }, children: hunk.header }),
|
|
1409
1602
|
Array.from({ length: rows }).map((_, ri) => {
|
|
1410
1603
|
const l = left[ri] ?? null;
|
|
1411
1604
|
const r = right[ri] ?? null;
|
|
@@ -1416,7 +1609,7 @@ function SplitHunks({ file, theme }) {
|
|
|
1416
1609
|
className: "flex w-1/2 min-w-0",
|
|
1417
1610
|
style: { backgroundColor: l ? lineBg(l.type, theme) : void 0 },
|
|
1418
1611
|
children: [
|
|
1419
|
-
/* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-
|
|
1612
|
+
/* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle", children: l?.oldNo ?? "" }),
|
|
1420
1613
|
/* @__PURE__ */ jsx4("span", { className: "whitespace-pre-wrap break-all px-1", children: l?.text ?? "" })
|
|
1421
1614
|
]
|
|
1422
1615
|
}
|
|
@@ -1424,10 +1617,10 @@ function SplitHunks({ file, theme }) {
|
|
|
1424
1617
|
/* @__PURE__ */ jsxs3(
|
|
1425
1618
|
"span",
|
|
1426
1619
|
{
|
|
1427
|
-
className: "flex w-1/2 min-w-0 border-l border-
|
|
1620
|
+
className: "flex w-1/2 min-w-0 border-l border-og-border",
|
|
1428
1621
|
style: { backgroundColor: r ? lineBg(r.type, theme) : void 0 },
|
|
1429
1622
|
children: [
|
|
1430
|
-
/* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-
|
|
1623
|
+
/* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle", children: r?.newNo ?? "" }),
|
|
1431
1624
|
/* @__PURE__ */ jsx4("span", { className: "whitespace-pre-wrap break-all px-1", children: r?.text ?? "" })
|
|
1432
1625
|
]
|
|
1433
1626
|
}
|
|
@@ -1512,12 +1705,12 @@ function PierreDiff({
|
|
|
1512
1705
|
themeType: themeType ?? "dark"
|
|
1513
1706
|
};
|
|
1514
1707
|
const pierreVars = {
|
|
1515
|
-
"--diffs-dark-bg": "var(--og-color-bg
|
|
1516
|
-
"--diffs-light-bg": "var(--og-color-bg
|
|
1517
|
-
"--diffs-bg-buffer-override": "var(--og-color-surface-1
|
|
1518
|
-
"--diffs-bg-separator-override": "var(--og-color-surface-1
|
|
1519
|
-
"--diffs-font-size": "
|
|
1520
|
-
"--diffs-line-height": "
|
|
1708
|
+
"--diffs-dark-bg": "var(--og-color-bg)",
|
|
1709
|
+
"--diffs-light-bg": "var(--og-color-bg)",
|
|
1710
|
+
"--diffs-bg-buffer-override": "var(--og-color-surface-1)",
|
|
1711
|
+
"--diffs-bg-separator-override": "var(--og-color-surface-1)",
|
|
1712
|
+
"--diffs-font-size": "var(--og-code-font-size)",
|
|
1713
|
+
"--diffs-line-height": "var(--og-code-line-height)"
|
|
1521
1714
|
};
|
|
1522
1715
|
return /* @__PURE__ */ jsx5(
|
|
1523
1716
|
"div",
|
|
@@ -1537,7 +1730,7 @@ function PierreDiff({
|
|
|
1537
1730
|
);
|
|
1538
1731
|
}
|
|
1539
1732
|
function DiffSkeleton() {
|
|
1540
|
-
return /* @__PURE__ */ jsx5("div", { className: "p-3 text-
|
|
1733
|
+
return /* @__PURE__ */ jsx5("div", { className: "p-3 text-og-sm text-og-fg-subtle", children: "Loading diff\u2026" });
|
|
1541
1734
|
}
|
|
1542
1735
|
|
|
1543
1736
|
// src/timeline/tool-diff.tsx
|
|
@@ -1565,7 +1758,7 @@ function LayoutToggle({ layout, onChange }) {
|
|
|
1565
1758
|
type: "button",
|
|
1566
1759
|
onClick: () => onChange(value),
|
|
1567
1760
|
className: cn(
|
|
1568
|
-
"rounded-
|
|
1761
|
+
"rounded-og-xs px-2 py-[3px] text-og-xs font-medium capitalize transition-colors",
|
|
1569
1762
|
layout === value ? "bg-og-surface-2 text-og-fg" : "text-og-fg-subtle hover:text-og-fg-muted"
|
|
1570
1763
|
),
|
|
1571
1764
|
children: value
|
|
@@ -1917,16 +2110,34 @@ function computerVerb(action) {
|
|
|
1917
2110
|
return action.type;
|
|
1918
2111
|
}
|
|
1919
2112
|
}
|
|
2113
|
+
function asComputerArgs(args) {
|
|
2114
|
+
if (!args) {
|
|
2115
|
+
return {};
|
|
2116
|
+
}
|
|
2117
|
+
const parsed = typeof args === "string" ? tryParseJson(args) : args;
|
|
2118
|
+
if (!parsed || typeof parsed !== "object") {
|
|
2119
|
+
return {};
|
|
2120
|
+
}
|
|
2121
|
+
const record = parsed;
|
|
2122
|
+
return {
|
|
2123
|
+
...typeof record.x === "number" ? { x: record.x } : {},
|
|
2124
|
+
...typeof record.y === "number" ? { y: record.y } : {},
|
|
2125
|
+
...typeof record.text === "string" ? { text: record.text } : {},
|
|
2126
|
+
...Array.isArray(record.keys) ? { keys: record.keys } : {},
|
|
2127
|
+
...typeof record.button === "string" ? { button: record.button } : {}
|
|
2128
|
+
};
|
|
2129
|
+
}
|
|
1920
2130
|
function ComputerCallRenderer({ item }) {
|
|
1921
2131
|
const raw = item.raw ?? {};
|
|
1922
|
-
const
|
|
2132
|
+
const functionAction = !raw.action && item.name.startsWith("computer_") && item.name !== "computer_call" ? { type: item.name.slice("computer_".length), ...asComputerArgs(item.arguments) } : void 0;
|
|
2133
|
+
const action = raw.action ?? functionAction;
|
|
1923
2134
|
const actions = raw.actions ?? (action ? [action] : []);
|
|
1924
2135
|
const verb = computerVerb(action);
|
|
1925
2136
|
const out = item.output;
|
|
1926
2137
|
const running = item.status === "running";
|
|
1927
2138
|
const rejected = raw.providerData?.approvalStatus === "rejected";
|
|
1928
2139
|
const readOnly = typeof out === "string" && out.includes("read-only");
|
|
1929
|
-
const
|
|
2140
|
+
const shotUrl = screenshotDataUrl(out);
|
|
1930
2141
|
const empty = out === "" || out == null;
|
|
1931
2142
|
const batched = actions.length > 1 ? actions.map((a) => computerVerb(a)).join(" \xB7 ") : null;
|
|
1932
2143
|
const countSuffix = actions.length > 1 ? ` \xB7${actions.length}` : "";
|
|
@@ -1971,8 +2182,8 @@ function ComputerCallRenderer({ item }) {
|
|
|
1971
2182
|
}
|
|
1972
2183
|
const isFailed = item.status === "failed";
|
|
1973
2184
|
const isCancelled = item.status === "cancelled";
|
|
1974
|
-
if (
|
|
1975
|
-
const caption =
|
|
2185
|
+
if (shotUrl) {
|
|
2186
|
+
const caption = `${verb}${actions.length > 1 ? ` (+${actions.length - 1} more)` : ""}`;
|
|
1976
2187
|
return /* @__PURE__ */ jsxs5(
|
|
1977
2188
|
ActivityDisclosure,
|
|
1978
2189
|
{
|
|
@@ -1981,9 +2192,9 @@ function ComputerCallRenderer({ item }) {
|
|
|
1981
2192
|
title: `${verb}${countSuffix}`,
|
|
1982
2193
|
failed: isFailed,
|
|
1983
2194
|
cancelled: isCancelled,
|
|
1984
|
-
media: /* @__PURE__ */ jsx7(Thumbnail, { src:
|
|
2195
|
+
media: /* @__PURE__ */ jsx7(Thumbnail, { src: shotUrl, caption }),
|
|
1985
2196
|
children: [
|
|
1986
|
-
/* @__PURE__ */ jsx7(ScreenshotFigure, { src:
|
|
2197
|
+
/* @__PURE__ */ jsx7(ScreenshotFigure, { src: shotUrl, caption }),
|
|
1987
2198
|
batched ? /* @__PURE__ */ jsxs5(BodyNote, { children: [
|
|
1988
2199
|
"batched: ",
|
|
1989
2200
|
batched
|
|
@@ -2261,6 +2472,15 @@ var BASE_ENTRIES = [
|
|
|
2261
2472
|
{ match: "name", name: "write_stdin", render: WriteStdinRenderer },
|
|
2262
2473
|
{ match: "name", name: "apply_patch_call", render: ApplyPatchRenderer },
|
|
2263
2474
|
{ match: "name", name: "computer_call", render: ComputerCallRenderer },
|
|
2475
|
+
// Function-mode computer tools (codex / chat-wire transports).
|
|
2476
|
+
{ match: "name", name: "computer_screenshot", render: ComputerCallRenderer },
|
|
2477
|
+
{ match: "name", name: "computer_click", render: ComputerCallRenderer },
|
|
2478
|
+
{ match: "name", name: "computer_double_click", render: ComputerCallRenderer },
|
|
2479
|
+
{ match: "name", name: "computer_move", render: ComputerCallRenderer },
|
|
2480
|
+
{ match: "name", name: "computer_scroll", render: ComputerCallRenderer },
|
|
2481
|
+
{ match: "name", name: "computer_type", render: ComputerCallRenderer },
|
|
2482
|
+
{ match: "name", name: "computer_keypress", render: ComputerCallRenderer },
|
|
2483
|
+
{ match: "name", name: "computer_drag", render: ComputerCallRenderer },
|
|
2264
2484
|
{ match: "name", name: "web_search_call", render: WebSearchRenderer },
|
|
2265
2485
|
{ match: "name", name: "view_image", render: ViewImageRenderer },
|
|
2266
2486
|
{ match: "name", name: "environment_set_variable", render: SecretSetRenderer }
|
|
@@ -2390,7 +2610,7 @@ function WorkerRow({ item, onOpenSession }) {
|
|
|
2390
2610
|
type: "button",
|
|
2391
2611
|
onClick: () => item.workerSessionId && onOpenSession(item.workerSessionId),
|
|
2392
2612
|
className: cn(
|
|
2393
|
-
"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",
|
|
2613
|
+
"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",
|
|
2394
2614
|
"outline-none transition-colors duration-150 hover:border-og-border-strong hover:text-og-fg",
|
|
2395
2615
|
"focus-visible:ring-2 focus-visible:ring-og-accent"
|
|
2396
2616
|
),
|
|
@@ -2417,6 +2637,9 @@ function TurnSummary({ items, outcome, failureText, durationMs, defaultOpen, chi
|
|
|
2417
2637
|
{
|
|
2418
2638
|
className: cn(
|
|
2419
2639
|
"group flex w-full items-center gap-2.5 rounded-og-md border px-3 py-2 text-left text-og-base transition-colors",
|
|
2640
|
+
// A folded turn is a touch target on coarse pointers: grow the row so
|
|
2641
|
+
// it clears the 40px minimum without disturbing the calm desktop rhythm.
|
|
2642
|
+
"pointer-coarse:py-2.5",
|
|
2420
2643
|
// Only a failed turn earns the one filled/tinted card in the timeline;
|
|
2421
2644
|
// complete and cancelled stay flat and calm.
|
|
2422
2645
|
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"
|
|
@@ -2440,7 +2663,19 @@ function TurnSummary({ items, outcome, failureText, durationMs, defaultOpen, chi
|
|
|
2440
2663
|
failureText
|
|
2441
2664
|
] }) : null,
|
|
2442
2665
|
outcome === "cancelled" ? /* @__PURE__ */ jsx9("span", { className: "text-og-fg-subtle", children: " \xB7 interrupted" }) : null
|
|
2443
|
-
] })
|
|
2666
|
+
] }),
|
|
2667
|
+
/* @__PURE__ */ jsx9(
|
|
2668
|
+
"span",
|
|
2669
|
+
{
|
|
2670
|
+
"aria-hidden": true,
|
|
2671
|
+
className: cn(
|
|
2672
|
+
"ml-auto shrink-0 pl-2 text-og-xs text-og-fg-subtle transition-opacity duration-150",
|
|
2673
|
+
"opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100",
|
|
2674
|
+
"pointer-coarse:opacity-100"
|
|
2675
|
+
),
|
|
2676
|
+
children: open ? "hide steps" : "show steps"
|
|
2677
|
+
}
|
|
2678
|
+
)
|
|
2444
2679
|
]
|
|
2445
2680
|
}
|
|
2446
2681
|
),
|
|
@@ -2459,8 +2694,8 @@ function summarizeTurn(items, durationMs) {
|
|
|
2459
2694
|
files += applyPatchOps(item.raw).length;
|
|
2460
2695
|
} else if (item.name === "exec_command") {
|
|
2461
2696
|
commands += 1;
|
|
2462
|
-
} else if (rawTypeOf(item) === "computer_call" || item.name === "computer_call") {
|
|
2463
|
-
if (
|
|
2697
|
+
} else if (rawTypeOf(item) === "computer_call" || item.name === "computer_call" || item.name === "computer_screenshot") {
|
|
2698
|
+
if (screenshotDataUrl(item.output) !== null) {
|
|
2464
2699
|
screenshots += 1;
|
|
2465
2700
|
}
|
|
2466
2701
|
}
|
|
@@ -2705,15 +2940,28 @@ function generateClientEventId() {
|
|
|
2705
2940
|
}
|
|
2706
2941
|
|
|
2707
2942
|
// src/hooks/use-file-attachments.ts
|
|
2708
|
-
import { useCallback as useCallback4, useState as useState10 } from "react";
|
|
2943
|
+
import { useCallback as useCallback4, useRef as useRef3, useState as useState10 } from "react";
|
|
2709
2944
|
var isImage = (file) => file.type.startsWith("image/");
|
|
2710
2945
|
function useFileAttachments(options = {}) {
|
|
2711
2946
|
const { client, workspaceId } = useOpenGeni(options);
|
|
2712
2947
|
const pasteFilter = options.pasteFilter ?? isImage;
|
|
2713
2948
|
const [attachments, setAttachments] = useState10([]);
|
|
2949
|
+
const sources = useRef3(/* @__PURE__ */ new Map());
|
|
2950
|
+
const startUpload = useCallback4((id, file) => {
|
|
2951
|
+
void client.uploadFile(workspaceId, {
|
|
2952
|
+
filename: file.name || "file",
|
|
2953
|
+
contentType: file.type || "application/octet-stream",
|
|
2954
|
+
data: file
|
|
2955
|
+
}).then((asset) => {
|
|
2956
|
+
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));
|
|
2957
|
+
}).catch((error) => {
|
|
2958
|
+
setAttachments((current) => current.map((attachment) => attachment.id === id ? { ...attachment, status: "failed", error: error instanceof Error ? error.message : String(error) } : attachment));
|
|
2959
|
+
});
|
|
2960
|
+
}, [client, workspaceId]);
|
|
2714
2961
|
const addFiles = useCallback4((files) => {
|
|
2715
2962
|
for (const file of files) {
|
|
2716
2963
|
const id = crypto.randomUUID();
|
|
2964
|
+
sources.current.set(id, file);
|
|
2717
2965
|
const previewUrl = isImage(file) ? URL.createObjectURL(file) : void 0;
|
|
2718
2966
|
setAttachments((current) => [...current, {
|
|
2719
2967
|
id,
|
|
@@ -2723,17 +2971,17 @@ function useFileAttachments(options = {}) {
|
|
|
2723
2971
|
status: "uploading",
|
|
2724
2972
|
...previewUrl ? { previewUrl } : {}
|
|
2725
2973
|
}]);
|
|
2726
|
-
|
|
2727
|
-
filename: file.name || "file",
|
|
2728
|
-
contentType: file.type || "application/octet-stream",
|
|
2729
|
-
data: file
|
|
2730
|
-
}).then((asset) => {
|
|
2731
|
-
setAttachments((current) => current.map((attachment) => attachment.id === id ? { ...attachment, status: "ready", file: asset, name: asset.filename, contentType: asset.contentType, sizeBytes: asset.sizeBytes } : attachment));
|
|
2732
|
-
}).catch((error) => {
|
|
2733
|
-
setAttachments((current) => current.map((attachment) => attachment.id === id ? { ...attachment, status: "failed", error: error instanceof Error ? error.message : String(error) } : attachment));
|
|
2734
|
-
});
|
|
2974
|
+
startUpload(id, file);
|
|
2735
2975
|
}
|
|
2736
|
-
}, [
|
|
2976
|
+
}, [startUpload]);
|
|
2977
|
+
const retry = useCallback4((id) => {
|
|
2978
|
+
const file = sources.current.get(id);
|
|
2979
|
+
if (!file) {
|
|
2980
|
+
return;
|
|
2981
|
+
}
|
|
2982
|
+
setAttachments((current) => current.map((attachment) => attachment.id === id ? { ...attachment, status: "uploading", error: void 0 } : attachment));
|
|
2983
|
+
startUpload(id, file);
|
|
2984
|
+
}, [startUpload]);
|
|
2737
2985
|
const addFromPaste = useCallback4((event) => {
|
|
2738
2986
|
const clipboardFiles = event.clipboardData?.files;
|
|
2739
2987
|
if (!clipboardFiles) {
|
|
@@ -2745,6 +2993,7 @@ function useFileAttachments(options = {}) {
|
|
|
2745
2993
|
}
|
|
2746
2994
|
}, [addFiles, pasteFilter]);
|
|
2747
2995
|
const remove = useCallback4((id) => {
|
|
2996
|
+
sources.current.delete(id);
|
|
2748
2997
|
setAttachments((current) => {
|
|
2749
2998
|
const removed = current.find((attachment) => attachment.id === id);
|
|
2750
2999
|
if (removed?.previewUrl) {
|
|
@@ -2754,6 +3003,7 @@ function useFileAttachments(options = {}) {
|
|
|
2754
3003
|
});
|
|
2755
3004
|
}, []);
|
|
2756
3005
|
const clear = useCallback4(() => {
|
|
3006
|
+
sources.current.clear();
|
|
2757
3007
|
setAttachments((current) => {
|
|
2758
3008
|
for (const attachment of current) {
|
|
2759
3009
|
if (attachment.previewUrl) {
|
|
@@ -2769,13 +3019,14 @@ function useFileAttachments(options = {}) {
|
|
|
2769
3019
|
uploading: attachments.some((attachment) => attachment.status === "uploading"),
|
|
2770
3020
|
addFiles,
|
|
2771
3021
|
addFromPaste,
|
|
3022
|
+
retry,
|
|
2772
3023
|
remove,
|
|
2773
3024
|
clear
|
|
2774
3025
|
};
|
|
2775
3026
|
}
|
|
2776
3027
|
|
|
2777
3028
|
// src/hooks/use-turn-queue.ts
|
|
2778
|
-
import { useCallback as useCallback5, useEffect as useEffect5, useRef as
|
|
3029
|
+
import { useCallback as useCallback5, useEffect as useEffect5, useRef as useRef4, useState as useState11 } from "react";
|
|
2779
3030
|
function isTurnQueueEvent(event) {
|
|
2780
3031
|
return event.type.startsWith("turn.");
|
|
2781
3032
|
}
|
|
@@ -2819,8 +3070,8 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
2819
3070
|
const [loading, setLoading] = useState11(enabled);
|
|
2820
3071
|
const [error, setError] = useState11(null);
|
|
2821
3072
|
const mutation = useMutationRunner();
|
|
2822
|
-
const generation =
|
|
2823
|
-
const targetKeyRef =
|
|
3073
|
+
const generation = useRef4(0);
|
|
3074
|
+
const targetKeyRef = useRef4(null);
|
|
2824
3075
|
const load = useCallback5(async () => {
|
|
2825
3076
|
if (!sessionId) {
|
|
2826
3077
|
return;
|
|
@@ -2939,7 +3190,7 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
2939
3190
|
|
|
2940
3191
|
// src/hooks/use-goal.ts
|
|
2941
3192
|
import { OpenGeniApiError } from "@opengeni/sdk";
|
|
2942
|
-
import { useCallback as useCallback6, useEffect as useEffect6, useRef as
|
|
3193
|
+
import { useCallback as useCallback6, useEffect as useEffect6, useRef as useRef5, useState as useState12 } from "react";
|
|
2943
3194
|
function isGoalEvent(event) {
|
|
2944
3195
|
return event.type.startsWith("goal.");
|
|
2945
3196
|
}
|
|
@@ -2952,8 +3203,8 @@ function useGoal(sessionId, options = {}) {
|
|
|
2952
3203
|
const [loading, setLoading] = useState12(enabled);
|
|
2953
3204
|
const [error, setError] = useState12(null);
|
|
2954
3205
|
const mutation = useMutationRunner();
|
|
2955
|
-
const generation =
|
|
2956
|
-
const targetKeyRef =
|
|
3206
|
+
const generation = useRef5(0);
|
|
3207
|
+
const targetKeyRef = useRef5(null);
|
|
2957
3208
|
const load = useCallback6(async () => {
|
|
2958
3209
|
if (!sessionId) {
|
|
2959
3210
|
return;
|
|
@@ -3358,7 +3609,7 @@ import {
|
|
|
3358
3609
|
OpenGeniApiError as OpenGeniApiError2,
|
|
3359
3610
|
applyUrlRotation
|
|
3360
3611
|
} from "@opengeni/sdk";
|
|
3361
|
-
import { useCallback as useCallback15, useEffect as useEffect7, useRef as
|
|
3612
|
+
import { useCallback as useCallback15, useEffect as useEffect7, useRef as useRef6, useState as useState13 } from "react";
|
|
3362
3613
|
function desktopAttachable(cell) {
|
|
3363
3614
|
if (cell.transport !== null) return true;
|
|
3364
3615
|
return cell.reason === "lease_cold" || cell.reason === "not_provisioned" || cell.reason === null;
|
|
@@ -3393,8 +3644,8 @@ function useSessionCapabilities(sessionId, options = {}) {
|
|
|
3393
3644
|
const [viewerCapReached, setViewerCapReached] = useState13(false);
|
|
3394
3645
|
const [viewerId, setViewerId] = useState13(null);
|
|
3395
3646
|
const [nonce, setNonce] = useState13(0);
|
|
3396
|
-
const epochRef =
|
|
3397
|
-
const viewerIdRef =
|
|
3647
|
+
const epochRef = useRef6(0);
|
|
3648
|
+
const viewerIdRef = useRef6(null);
|
|
3398
3649
|
const renegotiate = useCallback15(() => {
|
|
3399
3650
|
setNonce((n) => n + 1);
|
|
3400
3651
|
}, []);
|
|
@@ -3593,7 +3844,7 @@ import {
|
|
|
3593
3844
|
desktopSocketUrl,
|
|
3594
3845
|
nextDesktopState
|
|
3595
3846
|
} from "@opengeni/sdk";
|
|
3596
|
-
import { useEffect as useEffect9, useRef as
|
|
3847
|
+
import { useEffect as useEffect9, useRef as useRef8, useState as useState15 } from "react";
|
|
3597
3848
|
|
|
3598
3849
|
// src/lib/relay-wire.ts
|
|
3599
3850
|
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
|
|
@@ -3666,7 +3917,7 @@ function decodeStreamFrame(bytes) {
|
|
|
3666
3917
|
}
|
|
3667
3918
|
|
|
3668
3919
|
// src/hooks/use-relay-frame-stream.ts
|
|
3669
|
-
import { useEffect as useEffect8, useRef as
|
|
3920
|
+
import { useEffect as useEffect8, useRef as useRef7, useState as useState14 } from "react";
|
|
3670
3921
|
var TAG_OPEN = 1;
|
|
3671
3922
|
var TAG_OPENACK = 2;
|
|
3672
3923
|
var TAG_FRAME = 3;
|
|
@@ -3684,7 +3935,7 @@ function useRelayFrameStream(options) {
|
|
|
3684
3935
|
const [state, setState] = useState14("idle");
|
|
3685
3936
|
const [error, setError] = useState14(null);
|
|
3686
3937
|
const [nonce, setNonce] = useState14(0);
|
|
3687
|
-
const stateRef =
|
|
3938
|
+
const stateRef = useRef7("idle");
|
|
3688
3939
|
const setBoth = (next) => {
|
|
3689
3940
|
stateRef.current = next;
|
|
3690
3941
|
setState(next);
|
|
@@ -3693,7 +3944,7 @@ function useRelayFrameStream(options) {
|
|
|
3693
3944
|
const transport = capability?.transport ?? null;
|
|
3694
3945
|
const url = capability?.url ?? null;
|
|
3695
3946
|
const token = capability?.token ?? null;
|
|
3696
|
-
const factoryRef =
|
|
3947
|
+
const factoryRef = useRef7(webSocketFactory);
|
|
3697
3948
|
factoryRef.current = webSocketFactory;
|
|
3698
3949
|
useEffect8(() => {
|
|
3699
3950
|
if (typeof window === "undefined") return;
|
|
@@ -3887,7 +4138,7 @@ function useDesktopStream(options) {
|
|
|
3887
4138
|
const [state, setState] = useState15("idle");
|
|
3888
4139
|
const [error, setError] = useState15(null);
|
|
3889
4140
|
const [nonce, setNonce] = useState15(0);
|
|
3890
|
-
const stateRef =
|
|
4141
|
+
const stateRef = useRef8("idle");
|
|
3891
4142
|
const setBoth = (next) => {
|
|
3892
4143
|
stateRef.current = next;
|
|
3893
4144
|
setState(next);
|
|
@@ -3897,11 +4148,11 @@ function useDesktopStream(options) {
|
|
|
3897
4148
|
const token = capability?.token ?? null;
|
|
3898
4149
|
const transport = capability?.transport ?? null;
|
|
3899
4150
|
const mode = capability?.mode ?? "read-only";
|
|
3900
|
-
const rfbRef =
|
|
3901
|
-
const interactiveRef =
|
|
3902
|
-
const scaleViewportRef =
|
|
3903
|
-
const modeRef =
|
|
3904
|
-
const rfbFactoryRef =
|
|
4151
|
+
const rfbRef = useRef8(null);
|
|
4152
|
+
const interactiveRef = useRef8(interactive);
|
|
4153
|
+
const scaleViewportRef = useRef8(scaleViewport);
|
|
4154
|
+
const modeRef = useRef8(mode);
|
|
4155
|
+
const rfbFactoryRef = useRef8(rfbFactory);
|
|
3905
4156
|
interactiveRef.current = interactive;
|
|
3906
4157
|
scaleViewportRef.current = scaleViewport;
|
|
3907
4158
|
modeRef.current = mode;
|
|
@@ -3994,7 +4245,7 @@ import {
|
|
|
3994
4245
|
ttydResizeFrame,
|
|
3995
4246
|
TtydServerCommand
|
|
3996
4247
|
} from "@opengeni/sdk";
|
|
3997
|
-
import { useEffect as useEffect10, useMemo as useMemo3, useRef as
|
|
4248
|
+
import { useEffect as useEffect10, useMemo as useMemo3, useRef as useRef9, useState as useState16 } from "react";
|
|
3998
4249
|
function decodeFrame(data) {
|
|
3999
4250
|
if (typeof data === "string") {
|
|
4000
4251
|
return { command: data.charAt(0), payload: data.slice(1) };
|
|
@@ -4007,13 +4258,13 @@ function decodeFrame(data) {
|
|
|
4007
4258
|
function useTerminalStream(options) {
|
|
4008
4259
|
const { capability, onOutput, onTitle, initialCols, initialRows } = options;
|
|
4009
4260
|
const [status, setStatus] = useState16("closed");
|
|
4010
|
-
const wsRef =
|
|
4011
|
-
const sizeRef =
|
|
4261
|
+
const wsRef = useRef9(null);
|
|
4262
|
+
const sizeRef = useRef9({
|
|
4012
4263
|
cols: initialCols ?? 80,
|
|
4013
4264
|
rows: initialRows ?? 24
|
|
4014
4265
|
});
|
|
4015
|
-
const onOutputRef =
|
|
4016
|
-
const onTitleRef =
|
|
4266
|
+
const onOutputRef = useRef9(onOutput);
|
|
4267
|
+
const onTitleRef = useRef9(onTitle);
|
|
4017
4268
|
onOutputRef.current = onOutput;
|
|
4018
4269
|
onTitleRef.current = onTitle;
|
|
4019
4270
|
const transport = capability?.transport ?? null;
|
|
@@ -4116,7 +4367,7 @@ function useTerminalStream(options) {
|
|
|
4116
4367
|
|
|
4117
4368
|
// src/hooks/use-sandbox-terminal.ts
|
|
4118
4369
|
import { OpenGeniApiError as OpenGeniApiError3 } from "@opengeni/sdk";
|
|
4119
|
-
import { useCallback as useCallback16, useEffect as useEffect11, useMemo as useMemo4, useRef as
|
|
4370
|
+
import { useCallback as useCallback16, useEffect as useEffect11, useMemo as useMemo4, useRef as useRef10, useState as useState17 } from "react";
|
|
4120
4371
|
function useSandboxTerminal(sessionId, options) {
|
|
4121
4372
|
const { client, workspaceId } = useOpenGeni(options);
|
|
4122
4373
|
const includeAgentFirehose = options.includeAgentFirehose ?? true;
|
|
@@ -4126,7 +4377,7 @@ function useSandboxTerminal(sessionId, options) {
|
|
|
4126
4377
|
const [openedPtyId, setOpenedPtyId] = useState17(null);
|
|
4127
4378
|
const [openError, setOpenError] = useState17(null);
|
|
4128
4379
|
const [reopenNonce, setReopenNonce] = useState17(0);
|
|
4129
|
-
const openInFlight =
|
|
4380
|
+
const openInFlight = useRef10(false);
|
|
4130
4381
|
const boxWarm = liveness === void 0 || liveness === "warm" || liveness === "draining";
|
|
4131
4382
|
useEffect11(() => {
|
|
4132
4383
|
if (!interactive || !sessionId || ptyFilter || !boxWarm) return;
|
|
@@ -4232,7 +4483,7 @@ function useSandboxTerminal(sessionId, options) {
|
|
|
4232
4483
|
}
|
|
4233
4484
|
|
|
4234
4485
|
// src/hooks/use-sandbox-files.ts
|
|
4235
|
-
import { useCallback as useCallback17, useEffect as useEffect12, useRef as
|
|
4486
|
+
import { useCallback as useCallback17, useEffect as useEffect12, useRef as useRef11, useState as useState18 } from "react";
|
|
4236
4487
|
function parentOf(path) {
|
|
4237
4488
|
const i = path.lastIndexOf("/");
|
|
4238
4489
|
return i <= 0 ? "" : path.slice(0, i);
|
|
@@ -4352,12 +4603,12 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4352
4603
|
const enabled = (options.enabled ?? true) && Boolean(sessionId);
|
|
4353
4604
|
const rootPath = options.rootPath ?? "";
|
|
4354
4605
|
const [tree, setTree] = useState18([]);
|
|
4355
|
-
const treeRef =
|
|
4606
|
+
const treeRef = useRef11([]);
|
|
4356
4607
|
const [loading, setLoading] = useState18(false);
|
|
4357
4608
|
const [expandingPaths, setExpandingPaths] = useState18(/* @__PURE__ */ new Set());
|
|
4358
4609
|
const [error, setError] = useState18(null);
|
|
4359
|
-
const statusRef =
|
|
4360
|
-
const ownRevisionsRef =
|
|
4610
|
+
const statusRef = useRef11(/* @__PURE__ */ new Map());
|
|
4611
|
+
const ownRevisionsRef = useRef11(/* @__PURE__ */ new Set());
|
|
4361
4612
|
const onMutationError = options.onMutationError;
|
|
4362
4613
|
treeRef.current = tree;
|
|
4363
4614
|
const applyStatus = useCallback17((nodes) => {
|
|
@@ -4572,10 +4823,10 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4572
4823
|
}
|
|
4573
4824
|
}, [client, workspaceId, sessionId, rootPath, applyStatus]);
|
|
4574
4825
|
const events = options.events;
|
|
4575
|
-
const lastSeqRef =
|
|
4576
|
-
const pendingParentsRef =
|
|
4577
|
-
const pendingGitRef =
|
|
4578
|
-
const debounceRef =
|
|
4826
|
+
const lastSeqRef = useRef11(0);
|
|
4827
|
+
const pendingParentsRef = useRef11(/* @__PURE__ */ new Set());
|
|
4828
|
+
const pendingGitRef = useRef11(false);
|
|
4829
|
+
const debounceRef = useRef11(null);
|
|
4579
4830
|
useEffect12(() => {
|
|
4580
4831
|
if (!enabled || !events) return;
|
|
4581
4832
|
let sawNew = false;
|
|
@@ -4619,7 +4870,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4619
4870
|
},
|
|
4620
4871
|
[]
|
|
4621
4872
|
);
|
|
4622
|
-
const wasLiveRef =
|
|
4873
|
+
const wasLiveRef = useRef11(false);
|
|
4623
4874
|
const liveness = options.liveness;
|
|
4624
4875
|
useEffect12(() => {
|
|
4625
4876
|
const live = liveness === "warm" || liveness === "draining";
|
|
@@ -4647,7 +4898,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
4647
4898
|
}
|
|
4648
4899
|
|
|
4649
4900
|
// src/hooks/use-sandbox-git.ts
|
|
4650
|
-
import { useCallback as useCallback18, useEffect as useEffect13, useRef as
|
|
4901
|
+
import { useCallback as useCallback18, useEffect as useEffect13, useRef as useRef12, useState as useState19 } from "react";
|
|
4651
4902
|
function useSandboxGit(sessionId, options = {}) {
|
|
4652
4903
|
const { client, workspaceId } = useOpenGeni(options);
|
|
4653
4904
|
const enabled = (options.enabled ?? true) && Boolean(sessionId);
|
|
@@ -4692,7 +4943,7 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
4692
4943
|
void refresh();
|
|
4693
4944
|
}, [enabled, refresh]);
|
|
4694
4945
|
const events = options.events;
|
|
4695
|
-
const lastChangeRef =
|
|
4946
|
+
const lastChangeRef = useRef12(0);
|
|
4696
4947
|
useEffect13(() => {
|
|
4697
4948
|
if (!enabled || !events) return;
|
|
4698
4949
|
let latest = lastChangeRef.current;
|
|
@@ -4941,14 +5192,14 @@ function clearErrorMessage(cause) {
|
|
|
4941
5192
|
}
|
|
4942
5193
|
|
|
4943
5194
|
// src/hooks/use-slash-commands.ts
|
|
4944
|
-
import { useCallback as useCallback19, useMemo as useMemo5, useRef as
|
|
5195
|
+
import { useCallback as useCallback19, useMemo as useMemo5, useRef as useRef13, useState as useState20 } from "react";
|
|
4945
5196
|
function useSlashCommands(options) {
|
|
4946
5197
|
const { commands, context, handlers, value, setValue } = options;
|
|
4947
5198
|
const [highlight, setHighlight] = useState20(0);
|
|
4948
5199
|
const [dismissedValue, setDismissedValue] = useState20(null);
|
|
4949
5200
|
const dismissed = dismissedValue !== null && dismissedValue === value;
|
|
4950
|
-
const navigatedRef =
|
|
4951
|
-
const navTokenRef =
|
|
5201
|
+
const navigatedRef = useRef13(false);
|
|
5202
|
+
const navTokenRef = useRef13(value);
|
|
4952
5203
|
if (navTokenRef.current !== value) {
|
|
4953
5204
|
navTokenRef.current = value;
|
|
4954
5205
|
navigatedRef.current = false;
|
|
@@ -5075,7 +5326,7 @@ function useSlashCommands(options) {
|
|
|
5075
5326
|
},
|
|
5076
5327
|
[items, runResolved]
|
|
5077
5328
|
);
|
|
5078
|
-
const runningRef =
|
|
5329
|
+
const runningRef = useRef13(false);
|
|
5079
5330
|
const onKeyDown = useCallback19(
|
|
5080
5331
|
(event) => {
|
|
5081
5332
|
if (!open) {
|
|
@@ -5216,9 +5467,9 @@ function CommandPalette({ open, items, highlight, onHighlight, onRun, argHintTex
|
|
|
5216
5467
|
}
|
|
5217
5468
|
|
|
5218
5469
|
// src/components/chat-composer.tsx
|
|
5219
|
-
import { ArrowUpIcon, FileIcon, ImageIcon as ImageIcon2, LoaderCircleIcon, PaperclipIcon, SquareIcon, XIcon as XIcon2 } from "lucide-react";
|
|
5470
|
+
import { ArrowUpIcon, FileIcon, ImageIcon as ImageIcon2, LoaderCircleIcon, PaperclipIcon, RotateCwIcon, SquareIcon, XIcon as XIcon2 } from "lucide-react";
|
|
5220
5471
|
import { AnimatePresence as AnimatePresence3, motion as motion3 } from "motion/react";
|
|
5221
|
-
import { useCallback as useCallback20, useEffect as useEffect14, useId as useId2, useMemo as useMemo7, useRef as
|
|
5472
|
+
import { useCallback as useCallback20, useEffect as useEffect14, useId as useId2, useMemo as useMemo7, useRef as useRef14, useState as useState21 } from "react";
|
|
5222
5473
|
|
|
5223
5474
|
// src/components/model-picker.tsx
|
|
5224
5475
|
import { ChevronDownIcon } from "lucide-react";
|
|
@@ -5295,8 +5546,8 @@ function ChatComposer({
|
|
|
5295
5546
|
commandContext,
|
|
5296
5547
|
onClearView
|
|
5297
5548
|
}) {
|
|
5298
|
-
const textareaRef =
|
|
5299
|
-
const fileInputRef =
|
|
5549
|
+
const textareaRef = useRef14(null);
|
|
5550
|
+
const fileInputRef = useRef14(null);
|
|
5300
5551
|
const active = status != null && ACTIVE_STATUSES.has(status);
|
|
5301
5552
|
const blockedByUpload = attachments?.uploading === true;
|
|
5302
5553
|
const hasReadyAttachment = (attachments?.readyResources.length ?? 0) > 0;
|
|
@@ -5438,217 +5689,258 @@ function ChatComposer({
|
|
|
5438
5689
|
[commands, commandContext]
|
|
5439
5690
|
);
|
|
5440
5691
|
const activeNotice = notice ?? (composer.error ? { tone: "error", message: composer.error.message || "Sending failed \u2014 your draft is still here. Try again." } : null);
|
|
5441
|
-
return
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
palette.
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
"div",
|
|
5475
|
-
{
|
|
5476
|
-
"aria-hidden": true,
|
|
5477
|
-
className: cn(
|
|
5478
|
-
"pointer-events-none absolute inset-0 z-10 flex items-center justify-center",
|
|
5479
|
-
"rounded-og-lg bg-og-surface-1/85 text-sm font-medium text-og-accent backdrop-blur-[1px]"
|
|
5480
|
-
),
|
|
5481
|
-
children: /* @__PURE__ */ jsxs10("span", { className: "inline-flex items-center gap-2", children: [
|
|
5482
|
-
/* @__PURE__ */ jsx12(PaperclipIcon, { className: "size-4" }),
|
|
5483
|
-
"Drop files to attach"
|
|
5484
|
-
] })
|
|
5485
|
-
}
|
|
5486
|
-
) : null,
|
|
5487
|
-
attachments && attachments.attachments.length > 0 ? /* @__PURE__ */ jsx12(AttachmentChips, { attachments: attachments.attachments, onRemove: attachments.remove }) : null,
|
|
5488
|
-
header,
|
|
5489
|
-
/* @__PURE__ */ jsx12(
|
|
5490
|
-
"textarea",
|
|
5491
|
-
{
|
|
5492
|
-
ref: textareaRef,
|
|
5493
|
-
rows: 1,
|
|
5494
|
-
value: composer.value,
|
|
5495
|
-
onChange: (event) => composer.setValue(event.target.value),
|
|
5496
|
-
onKeyDown,
|
|
5497
|
-
onPaste: handlePaste,
|
|
5498
|
-
placeholder: placeholder ?? "Message the agent\u2026",
|
|
5499
|
-
disabled,
|
|
5500
|
-
autoFocus,
|
|
5501
|
-
"aria-label": "Message the agent",
|
|
5502
|
-
role: paletteEnabled && palette.open ? "combobox" : void 0,
|
|
5503
|
-
"aria-expanded": paletteEnabled ? palette.open : void 0,
|
|
5504
|
-
"aria-controls": paletteEnabled && palette.open ? listboxId : void 0,
|
|
5505
|
-
"aria-activedescendant": paletteEnabled && palette.open ? `${listboxId}-option-${palette.highlight}` : void 0,
|
|
5506
|
-
className: cn(
|
|
5507
|
-
"block w-full resize-none bg-transparent px-4 pt-3.5 pb-1 text-[15px] leading-6",
|
|
5508
|
-
// The wrapper owns the whole-composer focus affordance (focus-within
|
|
5509
|
-
// border + soft glow). Suppress any self-scoped focus outline on the
|
|
5510
|
-
// textarea itself: `focus:outline-none` alone only sets outline-style
|
|
5511
|
-
// on `:focus`, which a host app's zero-specificity
|
|
5512
|
-
// `:where(...):focus-visible { outline: ... }` base rule re-applies as
|
|
5513
|
-
// the full shorthand. `focus-visible:outline-none` matches the same
|
|
5514
|
-
// state at class specificity and wins, so no second highlight (the
|
|
5515
|
-
// top-half rectangle bounded to the textarea box) ever paints.
|
|
5516
|
-
"text-og-fg placeholder:text-og-fg-subtle focus:outline-none focus-visible:outline-none",
|
|
5517
|
-
"disabled:cursor-not-allowed disabled:opacity-60"
|
|
5518
|
-
)
|
|
5519
|
-
}
|
|
5692
|
+
return (
|
|
5693
|
+
// Respect the iOS home-indicator inset so the sticky composer never sits
|
|
5694
|
+
// under it (0 on non-notch devices and desktop, so it's inert there).
|
|
5695
|
+
/* @__PURE__ */ jsxs10("div", { className: cn("og-root", className), style: { paddingBottom: "env(safe-area-inset-bottom)" }, children: [
|
|
5696
|
+
/* @__PURE__ */ jsxs10("div", { className: "relative", children: [
|
|
5697
|
+
paletteEnabled ? /* @__PURE__ */ jsx12(
|
|
5698
|
+
CommandPalette,
|
|
5699
|
+
{
|
|
5700
|
+
open: palette.open && confirmState === null,
|
|
5701
|
+
items: palette.items,
|
|
5702
|
+
highlight: palette.highlight,
|
|
5703
|
+
onHighlight: palette.setHighlight,
|
|
5704
|
+
onRun: (index) => {
|
|
5705
|
+
palette.setHighlight(index);
|
|
5706
|
+
void palette.runAt(index);
|
|
5707
|
+
},
|
|
5708
|
+
argHintText: palette.activeArgHint,
|
|
5709
|
+
listboxId
|
|
5710
|
+
}
|
|
5711
|
+
) : null,
|
|
5712
|
+
/* @__PURE__ */ jsxs10(
|
|
5713
|
+
"div",
|
|
5714
|
+
{
|
|
5715
|
+
onDragOver: attachments ? handleDragOver : void 0,
|
|
5716
|
+
onDragLeave: attachments ? handleDragLeave : void 0,
|
|
5717
|
+
onDrop: attachments ? handleDrop : void 0,
|
|
5718
|
+
className: cn(
|
|
5719
|
+
"relative rounded-og-lg border border-og-border bg-og-surface-1 shadow-og-sm",
|
|
5720
|
+
"transition-[border-color,box-shadow] duration-200",
|
|
5721
|
+
"focus-within:border-og-accent/60 focus-within:shadow-og-glow",
|
|
5722
|
+
// While files are dragged over, swap to a dashed accent border to
|
|
5723
|
+
// signal a live drop target (the overlay carries the label).
|
|
5724
|
+
dragging && "border-dashed border-og-accent"
|
|
5520
5725
|
),
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
attachments || models || controlsStart ? /* @__PURE__ */ jsxs10("span", { className: "flex min-w-0 items-center gap-1.5", children: [
|
|
5530
|
-
attachments ? /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
5531
|
-
/* @__PURE__ */ jsx12(
|
|
5532
|
-
"input",
|
|
5533
|
-
{
|
|
5534
|
-
ref: fileInputRef,
|
|
5535
|
-
type: "file",
|
|
5536
|
-
multiple: true,
|
|
5537
|
-
className: "hidden",
|
|
5538
|
-
onChange: handleFileChange
|
|
5539
|
-
}
|
|
5726
|
+
children: [
|
|
5727
|
+
dragging ? /* @__PURE__ */ jsx12(
|
|
5728
|
+
"div",
|
|
5729
|
+
{
|
|
5730
|
+
"aria-hidden": true,
|
|
5731
|
+
className: cn(
|
|
5732
|
+
"pointer-events-none absolute inset-0 z-10 flex items-center justify-center",
|
|
5733
|
+
"rounded-og-lg bg-og-surface-1/85 text-sm font-medium text-og-accent backdrop-blur-[1px]"
|
|
5540
5734
|
),
|
|
5735
|
+
children: /* @__PURE__ */ jsxs10("span", { className: "inline-flex items-center gap-2", children: [
|
|
5736
|
+
/* @__PURE__ */ jsx12(PaperclipIcon, { className: "size-4" }),
|
|
5737
|
+
"Drop files to attach"
|
|
5738
|
+
] })
|
|
5739
|
+
}
|
|
5740
|
+
) : null,
|
|
5741
|
+
attachments && attachments.attachments.length > 0 ? /* @__PURE__ */ jsx12(
|
|
5742
|
+
AttachmentChips,
|
|
5743
|
+
{
|
|
5744
|
+
attachments: attachments.attachments,
|
|
5745
|
+
onRemove: attachments.remove,
|
|
5746
|
+
onRetry: attachments.retry
|
|
5747
|
+
}
|
|
5748
|
+
) : null,
|
|
5749
|
+
header,
|
|
5750
|
+
/* @__PURE__ */ jsx12(
|
|
5751
|
+
"textarea",
|
|
5752
|
+
{
|
|
5753
|
+
ref: textareaRef,
|
|
5754
|
+
rows: 1,
|
|
5755
|
+
value: composer.value,
|
|
5756
|
+
onChange: (event) => composer.setValue(event.target.value),
|
|
5757
|
+
onKeyDown,
|
|
5758
|
+
onPaste: handlePaste,
|
|
5759
|
+
placeholder: placeholder ?? "Message the agent\u2026",
|
|
5760
|
+
disabled,
|
|
5761
|
+
autoFocus,
|
|
5762
|
+
"aria-label": "Message the agent",
|
|
5763
|
+
role: paletteEnabled && palette.open ? "combobox" : void 0,
|
|
5764
|
+
"aria-expanded": paletteEnabled ? palette.open : void 0,
|
|
5765
|
+
"aria-controls": paletteEnabled && palette.open ? listboxId : void 0,
|
|
5766
|
+
"aria-activedescendant": paletteEnabled && palette.open ? `${listboxId}-option-${palette.highlight}` : void 0,
|
|
5767
|
+
className: cn(
|
|
5768
|
+
// Font size steps up to 16px below `md` so iOS never zooms the
|
|
5769
|
+
// viewport on focus; desktop keeps the 15px og-md rhythm.
|
|
5770
|
+
"block w-full resize-none bg-transparent px-4 pt-3.5 pb-1 text-base leading-6 md:text-og-md",
|
|
5771
|
+
// The wrapper owns the whole-composer focus affordance (focus-within
|
|
5772
|
+
// border + soft glow). Suppress any self-scoped focus outline on the
|
|
5773
|
+
// textarea itself: `focus:outline-none` alone only sets outline-style
|
|
5774
|
+
// on `:focus`, which a host app's zero-specificity
|
|
5775
|
+
// `:where(...):focus-visible { outline: ... }` base rule re-applies as
|
|
5776
|
+
// the full shorthand. `focus-visible:outline-none` matches the same
|
|
5777
|
+
// state at class specificity and wins, so no second highlight (the
|
|
5778
|
+
// top-half rectangle bounded to the textarea box) ever paints.
|
|
5779
|
+
"text-og-fg placeholder:text-og-fg-subtle focus:outline-none focus-visible:outline-none",
|
|
5780
|
+
"disabled:cursor-not-allowed disabled:opacity-60"
|
|
5781
|
+
)
|
|
5782
|
+
}
|
|
5783
|
+
),
|
|
5784
|
+
confirmState && pendingDangerCommand ? /* @__PURE__ */ jsx12(
|
|
5785
|
+
ConfirmBar,
|
|
5786
|
+
{
|
|
5787
|
+
command: pendingDangerCommand,
|
|
5788
|
+
onCancel: () => confirmState.resolve(false),
|
|
5789
|
+
onConfirm: () => confirmState.resolve(true),
|
|
5790
|
+
returnFocusRef: textareaRef
|
|
5791
|
+
}
|
|
5792
|
+
) : /* @__PURE__ */ jsxs10("div", { className: "flex items-end gap-2 px-2.5 pb-2.5 pt-1", children: [
|
|
5793
|
+
attachments || models || controlsStart ? (
|
|
5794
|
+
// The control group wraps onto extra rows when it can't fit
|
|
5795
|
+
// (narrow viewports) instead of clipping under the rounded
|
|
5796
|
+
// corner; send/stop stays anchored bottom-right (shrink-0).
|
|
5797
|
+
/* @__PURE__ */ jsxs10("span", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-1.5", children: [
|
|
5798
|
+
attachments ? /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
5799
|
+
/* @__PURE__ */ jsx12(
|
|
5800
|
+
"input",
|
|
5801
|
+
{
|
|
5802
|
+
ref: fileInputRef,
|
|
5803
|
+
type: "file",
|
|
5804
|
+
multiple: true,
|
|
5805
|
+
className: "hidden",
|
|
5806
|
+
onChange: handleFileChange
|
|
5807
|
+
}
|
|
5808
|
+
),
|
|
5809
|
+
/* @__PURE__ */ jsx12(
|
|
5810
|
+
"button",
|
|
5811
|
+
{
|
|
5812
|
+
type: "button",
|
|
5813
|
+
disabled: disabled === true,
|
|
5814
|
+
onClick: () => fileInputRef.current?.click(),
|
|
5815
|
+
"aria-label": "Attach files",
|
|
5816
|
+
title: "Attach files",
|
|
5817
|
+
className: cn(
|
|
5818
|
+
"inline-flex size-8 items-center justify-center rounded-og-md",
|
|
5819
|
+
"text-og-fg-muted transition-colors duration-150 hover:bg-og-surface-2 hover:text-og-fg",
|
|
5820
|
+
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
5821
|
+
),
|
|
5822
|
+
children: /* @__PURE__ */ jsx12(PaperclipIcon, { className: "size-4" })
|
|
5823
|
+
}
|
|
5824
|
+
)
|
|
5825
|
+
] }) : null,
|
|
5826
|
+
models ? /* @__PURE__ */ jsx12(
|
|
5827
|
+
ModelPicker,
|
|
5828
|
+
{
|
|
5829
|
+
models,
|
|
5830
|
+
value: selectedModel,
|
|
5831
|
+
onChange: (modelId) => onSelectModel?.(modelId),
|
|
5832
|
+
disabled: disabled === true
|
|
5833
|
+
}
|
|
5834
|
+
) : null,
|
|
5835
|
+
controlsStart
|
|
5836
|
+
] })
|
|
5837
|
+
) : /* @__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" }),
|
|
5838
|
+
/* @__PURE__ */ jsxs10("span", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: [
|
|
5839
|
+
/* @__PURE__ */ jsx12(AnimatePresence3, { initial: false, children: active ? /* @__PURE__ */ jsx12(
|
|
5840
|
+
motion3.button,
|
|
5841
|
+
{
|
|
5842
|
+
type: "button",
|
|
5843
|
+
initial: { opacity: 0, scale: 0.8 },
|
|
5844
|
+
animate: { opacity: 1, scale: 1 },
|
|
5845
|
+
exit: { opacity: 0, scale: 0.8 },
|
|
5846
|
+
transition: { duration: 0.15, ease: "easeOut" },
|
|
5847
|
+
onClick: () => void composer.interrupt(),
|
|
5848
|
+
disabled: composer.interrupting,
|
|
5849
|
+
"aria-label": "Stop the current turn",
|
|
5850
|
+
title: "Stop the current turn",
|
|
5851
|
+
className: cn(
|
|
5852
|
+
"inline-flex size-8 items-center justify-center rounded-og-md border border-og-border pointer-coarse:size-11",
|
|
5853
|
+
"bg-og-surface-2 text-og-fg-muted transition-colors duration-150",
|
|
5854
|
+
"hover:border-og-status-failed/50 hover:text-og-status-failed",
|
|
5855
|
+
"disabled:opacity-50"
|
|
5856
|
+
),
|
|
5857
|
+
children: composer.interrupting ? /* @__PURE__ */ jsx12(LoaderCircleIcon, { className: "size-3.5 animate-og-spin" }) : /* @__PURE__ */ jsx12(SquareIcon, { className: "size-3 fill-current" })
|
|
5858
|
+
},
|
|
5859
|
+
"stop"
|
|
5860
|
+
) : null }),
|
|
5541
5861
|
/* @__PURE__ */ jsx12(
|
|
5542
5862
|
"button",
|
|
5543
5863
|
{
|
|
5544
5864
|
type: "button",
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
5865
|
+
onClick: () => {
|
|
5866
|
+
if (blockedByUpload) {
|
|
5867
|
+
return;
|
|
5868
|
+
}
|
|
5869
|
+
void composer.send();
|
|
5870
|
+
},
|
|
5871
|
+
disabled: !canSend || disabled === true || commandDraftBlocked,
|
|
5872
|
+
"aria-label": "Send message",
|
|
5549
5873
|
className: cn(
|
|
5550
|
-
"inline-flex size-8 items-center justify-center rounded-og-md",
|
|
5551
|
-
"
|
|
5552
|
-
"
|
|
5874
|
+
"inline-flex size-8 items-center justify-center rounded-og-md pointer-coarse:size-11",
|
|
5875
|
+
"bg-og-accent text-og-accent-fg shadow-og-sm",
|
|
5876
|
+
"transition-[background-color,transform,opacity] duration-150 ease-og-spring",
|
|
5877
|
+
"hover:bg-og-accent-strong active:scale-95",
|
|
5878
|
+
"disabled:cursor-not-allowed disabled:bg-og-surface-3 disabled:text-og-fg-subtle disabled:shadow-none"
|
|
5553
5879
|
),
|
|
5554
|
-
children: /* @__PURE__ */ jsx12(
|
|
5880
|
+
children: composer.sending ? /* @__PURE__ */ jsx12(LoaderCircleIcon, { className: "size-4 animate-og-spin" }) : /* @__PURE__ */ jsx12(ArrowUpIcon, { className: "size-4" })
|
|
5555
5881
|
}
|
|
5556
5882
|
)
|
|
5557
|
-
] })
|
|
5558
|
-
models ? /* @__PURE__ */ jsx12(
|
|
5559
|
-
ModelPicker,
|
|
5560
|
-
{
|
|
5561
|
-
models,
|
|
5562
|
-
value: selectedModel,
|
|
5563
|
-
onChange: (modelId) => onSelectModel?.(modelId),
|
|
5564
|
-
disabled: disabled === true
|
|
5565
|
-
}
|
|
5566
|
-
) : null,
|
|
5567
|
-
controlsStart
|
|
5568
|
-
] }) : /* @__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" }),
|
|
5569
|
-
/* @__PURE__ */ jsxs10("span", { className: "flex items-center gap-1.5", children: [
|
|
5570
|
-
/* @__PURE__ */ jsx12(AnimatePresence3, { initial: false, children: active ? /* @__PURE__ */ jsx12(
|
|
5571
|
-
motion3.button,
|
|
5572
|
-
{
|
|
5573
|
-
type: "button",
|
|
5574
|
-
initial: { opacity: 0, scale: 0.8 },
|
|
5575
|
-
animate: { opacity: 1, scale: 1 },
|
|
5576
|
-
exit: { opacity: 0, scale: 0.8 },
|
|
5577
|
-
transition: { duration: 0.15, ease: "easeOut" },
|
|
5578
|
-
onClick: () => void composer.interrupt(),
|
|
5579
|
-
disabled: composer.interrupting,
|
|
5580
|
-
"aria-label": "Stop the current turn",
|
|
5581
|
-
title: "Stop the current turn",
|
|
5582
|
-
className: cn(
|
|
5583
|
-
"inline-flex size-8 items-center justify-center rounded-og-md border border-og-border",
|
|
5584
|
-
"bg-og-surface-2 text-og-fg-muted transition-colors duration-150",
|
|
5585
|
-
"hover:border-og-status-failed/50 hover:text-og-status-failed",
|
|
5586
|
-
"disabled:opacity-50"
|
|
5587
|
-
),
|
|
5588
|
-
children: composer.interrupting ? /* @__PURE__ */ jsx12(LoaderCircleIcon, { className: "size-3.5 animate-og-spin" }) : /* @__PURE__ */ jsx12(SquareIcon, { className: "size-3 fill-current" })
|
|
5589
|
-
},
|
|
5590
|
-
"stop"
|
|
5591
|
-
) : null }),
|
|
5592
|
-
/* @__PURE__ */ jsx12(
|
|
5593
|
-
"button",
|
|
5594
|
-
{
|
|
5595
|
-
type: "button",
|
|
5596
|
-
onClick: () => {
|
|
5597
|
-
if (blockedByUpload) {
|
|
5598
|
-
return;
|
|
5599
|
-
}
|
|
5600
|
-
void composer.send();
|
|
5601
|
-
},
|
|
5602
|
-
disabled: !canSend || disabled === true || commandDraftBlocked,
|
|
5603
|
-
"aria-label": "Send message",
|
|
5604
|
-
className: cn(
|
|
5605
|
-
"inline-flex size-8 items-center justify-center rounded-og-md",
|
|
5606
|
-
"bg-og-accent text-og-accent-fg shadow-og-sm",
|
|
5607
|
-
"transition-[background-color,transform,opacity] duration-150 ease-og-spring",
|
|
5608
|
-
"hover:bg-og-accent-strong active:scale-95",
|
|
5609
|
-
"disabled:cursor-not-allowed disabled:bg-og-surface-3 disabled:text-og-fg-subtle disabled:shadow-none"
|
|
5610
|
-
),
|
|
5611
|
-
children: composer.sending ? /* @__PURE__ */ jsx12(LoaderCircleIcon, { className: "size-4 animate-og-spin" }) : /* @__PURE__ */ jsx12(ArrowUpIcon, { className: "size-4" })
|
|
5612
|
-
}
|
|
5613
|
-
)
|
|
5883
|
+
] })
|
|
5614
5884
|
] })
|
|
5615
|
-
]
|
|
5616
|
-
]
|
|
5617
|
-
}
|
|
5618
|
-
)
|
|
5619
|
-
] }),
|
|
5620
|
-
/* @__PURE__ */ jsx12(AnimatePresence3, { children: helpOpen ? /* @__PURE__ */ jsx12(HelpPanel, { commands: helpCommands, onClose: () => setHelpOpen(false) }) : null }),
|
|
5621
|
-
/* @__PURE__ */ jsx12(AnimatePresence3, { children: activeNotice ? /* @__PURE__ */ jsx12(
|
|
5622
|
-
motion3.p,
|
|
5623
|
-
{
|
|
5624
|
-
initial: { opacity: 0, height: 0 },
|
|
5625
|
-
animate: { opacity: 1, height: "auto" },
|
|
5626
|
-
exit: { opacity: 0, height: 0 },
|
|
5627
|
-
className: cn(
|
|
5628
|
-
"overflow-hidden px-1 pt-1.5 text-xs",
|
|
5629
|
-
activeNotice.tone === "ok" ? "text-og-fg-muted" : "text-og-status-failed"
|
|
5630
|
-
),
|
|
5631
|
-
role: activeNotice.tone === "error" ? "alert" : "status",
|
|
5632
|
-
onAnimationComplete: () => {
|
|
5633
|
-
if (activeNotice.tone === "ok") {
|
|
5634
|
-
window.setTimeout(() => setNotice((current) => current === activeNotice ? null : current), 2400);
|
|
5885
|
+
]
|
|
5635
5886
|
}
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
}
|
|
5639
|
-
|
|
5640
|
-
|
|
5887
|
+
)
|
|
5888
|
+
] }),
|
|
5889
|
+
/* @__PURE__ */ jsx12(AnimatePresence3, { children: helpOpen ? /* @__PURE__ */ jsx12(HelpPanel, { commands: helpCommands, onClose: () => setHelpOpen(false) }) : null }),
|
|
5890
|
+
/* @__PURE__ */ jsx12(AnimatePresence3, { children: activeNotice ? /* @__PURE__ */ jsx12(
|
|
5891
|
+
motion3.p,
|
|
5892
|
+
{
|
|
5893
|
+
initial: { opacity: 0, height: 0 },
|
|
5894
|
+
animate: { opacity: 1, height: "auto" },
|
|
5895
|
+
exit: { opacity: 0, height: 0 },
|
|
5896
|
+
className: cn(
|
|
5897
|
+
"overflow-hidden px-1 pt-1.5 text-xs",
|
|
5898
|
+
activeNotice.tone === "ok" ? "text-og-fg-muted" : "text-og-status-failed"
|
|
5899
|
+
),
|
|
5900
|
+
role: activeNotice.tone === "error" ? "alert" : "status",
|
|
5901
|
+
onAnimationComplete: () => {
|
|
5902
|
+
if (activeNotice.tone === "ok") {
|
|
5903
|
+
window.setTimeout(() => setNotice((current) => current === activeNotice ? null : current), 2400);
|
|
5904
|
+
}
|
|
5905
|
+
},
|
|
5906
|
+
children: activeNotice.message
|
|
5907
|
+
}
|
|
5908
|
+
) : null })
|
|
5909
|
+
] })
|
|
5910
|
+
);
|
|
5641
5911
|
}
|
|
5642
|
-
function ConfirmBar({
|
|
5912
|
+
function ConfirmBar({
|
|
5913
|
+
command,
|
|
5914
|
+
onCancel,
|
|
5915
|
+
onConfirm,
|
|
5916
|
+
returnFocusRef
|
|
5917
|
+
}) {
|
|
5918
|
+
const confirmRef = useRef14(null);
|
|
5919
|
+
const descriptionId = useId2();
|
|
5920
|
+
useEffect14(() => {
|
|
5921
|
+
const returnTo = returnFocusRef?.current ?? null;
|
|
5922
|
+
confirmRef.current?.focus();
|
|
5923
|
+
return () => {
|
|
5924
|
+
returnTo?.focus();
|
|
5925
|
+
};
|
|
5926
|
+
}, [returnFocusRef]);
|
|
5643
5927
|
return /* @__PURE__ */ jsxs10(
|
|
5644
5928
|
"div",
|
|
5645
5929
|
{
|
|
5646
5930
|
role: "alertdialog",
|
|
5647
5931
|
"aria-label": `Confirm /${command.name}`,
|
|
5932
|
+
"aria-describedby": descriptionId,
|
|
5648
5933
|
"data-testid": "danger-confirm",
|
|
5649
|
-
|
|
5934
|
+
onKeyDown: (event) => {
|
|
5935
|
+
if (event.key === "Escape") {
|
|
5936
|
+
event.preventDefault();
|
|
5937
|
+
event.stopPropagation();
|
|
5938
|
+
onCancel();
|
|
5939
|
+
}
|
|
5940
|
+
},
|
|
5941
|
+
className: "flex items-end justify-between gap-2 px-2.5 pb-2.5 pt-1",
|
|
5650
5942
|
children: [
|
|
5651
|
-
/* @__PURE__ */ jsxs10("span", { className: "px-1.5 text-
|
|
5943
|
+
/* @__PURE__ */ jsxs10("span", { id: descriptionId, className: "min-w-0 flex-1 px-1.5 text-og-sm text-og-status-failed", children: [
|
|
5652
5944
|
"Run ",
|
|
5653
5945
|
/* @__PURE__ */ jsxs10("span", { className: "font-mono", children: [
|
|
5654
5946
|
"/",
|
|
@@ -5657,24 +5949,27 @@ function ConfirmBar({ command, onCancel, onConfirm }) {
|
|
|
5657
5949
|
"? ",
|
|
5658
5950
|
command.description
|
|
5659
5951
|
] }),
|
|
5660
|
-
/* @__PURE__ */ jsxs10("span", { className: "flex items-center gap-1.5", children: [
|
|
5952
|
+
/* @__PURE__ */ jsxs10("span", { className: "flex shrink-0 items-center gap-1.5", children: [
|
|
5661
5953
|
/* @__PURE__ */ jsx12(
|
|
5662
5954
|
"button",
|
|
5663
5955
|
{
|
|
5664
5956
|
type: "button",
|
|
5665
5957
|
onClick: onCancel,
|
|
5666
|
-
className: "rounded-og-md border border-og-border bg-og-surface-2 px-2.5 py-1 text-
|
|
5958
|
+
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",
|
|
5667
5959
|
children: "Cancel"
|
|
5668
5960
|
}
|
|
5669
5961
|
),
|
|
5670
|
-
/* @__PURE__ */
|
|
5962
|
+
/* @__PURE__ */ jsxs10(
|
|
5671
5963
|
"button",
|
|
5672
5964
|
{
|
|
5965
|
+
ref: confirmRef,
|
|
5673
5966
|
type: "button",
|
|
5674
|
-
autoFocus: true,
|
|
5675
5967
|
onClick: onConfirm,
|
|
5676
|
-
className: "rounded-og-md border border-og-status-failed/50 bg-og-status-failed/15 px-2.5 py-1 text-
|
|
5677
|
-
children:
|
|
5968
|
+
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",
|
|
5969
|
+
children: [
|
|
5970
|
+
"Run /",
|
|
5971
|
+
command.name
|
|
5972
|
+
]
|
|
5678
5973
|
}
|
|
5679
5974
|
)
|
|
5680
5975
|
] })
|
|
@@ -5682,44 +5977,57 @@ function ConfirmBar({ command, onCancel, onConfirm }) {
|
|
|
5682
5977
|
}
|
|
5683
5978
|
);
|
|
5684
5979
|
}
|
|
5685
|
-
function AttachmentChips({ attachments, onRemove }) {
|
|
5686
|
-
return /* @__PURE__ */ jsx12("div", { className: "flex flex-wrap gap-2 border-b border-og-border px-3 py-2", children: attachments.map((attachment) =>
|
|
5687
|
-
"
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5980
|
+
function AttachmentChips({ attachments, onRemove, onRetry }) {
|
|
5981
|
+
return /* @__PURE__ */ jsx12("div", { className: "flex flex-wrap gap-2 border-b border-og-border px-3 py-2", children: attachments.map((attachment) => {
|
|
5982
|
+
const failed = attachment.status === "failed";
|
|
5983
|
+
const statusText = attachment.status === "uploading" ? "Uploading" : failed ? attachment.error || "Upload failed" : formatBytes(attachment.sizeBytes);
|
|
5984
|
+
return /* @__PURE__ */ jsxs10(
|
|
5985
|
+
"div",
|
|
5986
|
+
{
|
|
5987
|
+
className: cn(
|
|
5988
|
+
"flex min-w-0 max-w-[240px] items-center gap-2 rounded-og-md border px-2 py-1.5 text-og-sm",
|
|
5989
|
+
failed ? "border-og-status-failed/40 bg-og-status-failed/10" : "border-og-border bg-og-surface-2"
|
|
5990
|
+
),
|
|
5991
|
+
children: [
|
|
5992
|
+
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" }),
|
|
5993
|
+
/* @__PURE__ */ jsxs10("div", { className: "min-w-0 flex-1", children: [
|
|
5994
|
+
/* @__PURE__ */ jsx12("div", { className: "truncate font-medium text-og-fg", children: attachment.name }),
|
|
5995
|
+
/* @__PURE__ */ jsx12(
|
|
5996
|
+
"div",
|
|
5997
|
+
{
|
|
5998
|
+
className: cn("truncate text-og-xs", failed ? "text-og-status-failed" : "text-og-fg-subtle"),
|
|
5999
|
+
title: failed ? statusText : void 0,
|
|
6000
|
+
children: statusText
|
|
6001
|
+
}
|
|
6002
|
+
)
|
|
6003
|
+
] }),
|
|
6004
|
+
attachment.status === "uploading" ? /* @__PURE__ */ jsx12(LoaderCircleIcon, { className: "size-3.5 shrink-0 animate-og-spin" }) : null,
|
|
6005
|
+
failed && onRetry ? /* @__PURE__ */ jsx12(
|
|
6006
|
+
"button",
|
|
6007
|
+
{
|
|
6008
|
+
type: "button",
|
|
6009
|
+
onClick: () => onRetry(attachment.id),
|
|
6010
|
+
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",
|
|
6011
|
+
"aria-label": `Retry ${attachment.name}`,
|
|
6012
|
+
title: "Retry upload",
|
|
6013
|
+
children: /* @__PURE__ */ jsx12(RotateCwIcon, { className: "size-3.5" })
|
|
6014
|
+
}
|
|
6015
|
+
) : null,
|
|
5697
6016
|
/* @__PURE__ */ jsx12(
|
|
5698
|
-
"
|
|
6017
|
+
"button",
|
|
5699
6018
|
{
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
children:
|
|
6019
|
+
type: "button",
|
|
6020
|
+
onClick: () => onRemove(attachment.id),
|
|
6021
|
+
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",
|
|
6022
|
+
"aria-label": `Remove ${attachment.name}`,
|
|
6023
|
+
children: /* @__PURE__ */ jsx12(XIcon2, { className: "size-3.5" })
|
|
5705
6024
|
}
|
|
5706
6025
|
)
|
|
5707
|
-
]
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
type: "button",
|
|
5713
|
-
onClick: () => onRemove(attachment.id),
|
|
5714
|
-
className: "shrink-0 rounded-og-xs p-1 text-og-fg-muted hover:bg-og-surface-1 hover:text-og-fg",
|
|
5715
|
-
"aria-label": `Remove ${attachment.name}`,
|
|
5716
|
-
children: /* @__PURE__ */ jsx12(XIcon2, { className: "size-3.5" })
|
|
5717
|
-
}
|
|
5718
|
-
)
|
|
5719
|
-
]
|
|
5720
|
-
},
|
|
5721
|
-
attachment.id
|
|
5722
|
-
)) });
|
|
6026
|
+
]
|
|
6027
|
+
},
|
|
6028
|
+
attachment.id
|
|
6029
|
+
);
|
|
6030
|
+
}) });
|
|
5723
6031
|
}
|
|
5724
6032
|
function HelpPanel({ commands, onClose }) {
|
|
5725
6033
|
return /* @__PURE__ */ jsxs10(
|
|
@@ -5731,19 +6039,19 @@ function HelpPanel({ commands, onClose }) {
|
|
|
5731
6039
|
className: "mt-2 overflow-hidden rounded-og-lg border border-og-border bg-og-surface-2",
|
|
5732
6040
|
children: [
|
|
5733
6041
|
/* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between border-b border-og-border px-3 py-1.5", children: [
|
|
5734
|
-
/* @__PURE__ */ jsx12("span", { className: "text-
|
|
5735
|
-
/* @__PURE__ */ jsx12("button", { type: "button", onClick: onClose, className: "text-
|
|
6042
|
+
/* @__PURE__ */ jsx12("span", { className: "text-og-sm font-medium text-og-fg", children: "Commands" }),
|
|
6043
|
+
/* @__PURE__ */ jsx12("button", { type: "button", onClick: onClose, className: "text-og-xs text-og-fg-subtle hover:text-og-fg", children: "Close" })
|
|
5736
6044
|
] }),
|
|
5737
6045
|
/* @__PURE__ */ jsx12("ul", { className: "py-1", children: commands.map((command) => {
|
|
5738
6046
|
const hint = argHint(command.args);
|
|
5739
6047
|
return /* @__PURE__ */ jsxs10("li", { className: "flex items-baseline gap-2 px-3 py-1", children: [
|
|
5740
|
-
/* @__PURE__ */ jsxs10("span", { className: "font-mono text-
|
|
6048
|
+
/* @__PURE__ */ jsxs10("span", { className: "font-mono text-og-sm text-og-accent", children: [
|
|
5741
6049
|
"/",
|
|
5742
6050
|
command.name,
|
|
5743
6051
|
hint ? /* @__PURE__ */ jsx12("span", { className: "ml-1 text-og-fg-subtle", children: hint }) : null
|
|
5744
6052
|
] }),
|
|
5745
|
-
/* @__PURE__ */ jsx12("span", { className: "text-
|
|
5746
|
-
command.danger ? /* @__PURE__ */ jsx12("span", { className: "ml-auto rounded-og-xs bg-og-status-failed/15 px-1 text-
|
|
6053
|
+
/* @__PURE__ */ jsx12("span", { className: "text-og-sm text-og-fg-muted", children: command.description }),
|
|
6054
|
+
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
|
|
5747
6055
|
] }, command.name);
|
|
5748
6056
|
}) })
|
|
5749
6057
|
]
|
|
@@ -5763,7 +6071,7 @@ import {
|
|
|
5763
6071
|
TriangleAlertIcon as TriangleAlertIcon2
|
|
5764
6072
|
} from "lucide-react";
|
|
5765
6073
|
import { AnimatePresence as AnimatePresence4, motion as motion4 } from "motion/react";
|
|
5766
|
-
import { useEffect as useEffect15, useMemo as useMemo8, useRef as
|
|
6074
|
+
import { useCallback as useCallback21, useEffect as useEffect15, useMemo as useMemo8, useRef as useRef15, useState as useState22 } from "react";
|
|
5767
6075
|
|
|
5768
6076
|
// src/components/markdown.tsx
|
|
5769
6077
|
import { memo } from "react";
|
|
@@ -5773,8 +6081,8 @@ import { jsx as jsx13 } from "react/jsx-runtime";
|
|
|
5773
6081
|
var components = {
|
|
5774
6082
|
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 }),
|
|
5775
6083
|
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 }),
|
|
5776
|
-
h3: ({ children, ...props }) => /* @__PURE__ */ jsx13("h3", { className: "mt-4 mb-1.5 text-
|
|
5777
|
-
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 }),
|
|
6084
|
+
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 }),
|
|
6085
|
+
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 }),
|
|
5778
6086
|
p: ({ children, ...props }) => /* @__PURE__ */ jsx13("p", { className: "my-2.5 leading-7 first:mt-0 last:mb-0", ...props, children }),
|
|
5779
6087
|
strong: ({ children, ...props }) => /* @__PURE__ */ jsx13("strong", { className: "font-semibold text-og-fg", ...props, children }),
|
|
5780
6088
|
em: ({ children, ...props }) => /* @__PURE__ */ jsx13("em", { className: "italic", ...props, children }),
|
|
@@ -5800,7 +6108,7 @@ var components = {
|
|
|
5800
6108
|
...props,
|
|
5801
6109
|
type: "checkbox",
|
|
5802
6110
|
disabled: true,
|
|
5803
|
-
className: "mr-2 size-3.5 translate-y-[2px] cursor-default
|
|
6111
|
+
className: "mr-2 size-3.5 translate-y-[2px] cursor-default accent-og-accent align-baseline"
|
|
5804
6112
|
}
|
|
5805
6113
|
) : /* @__PURE__ */ jsx13("input", { type, ...props }),
|
|
5806
6114
|
blockquote: ({ children, ...props }) => /* @__PURE__ */ jsx13(
|
|
@@ -5818,7 +6126,7 @@ var components = {
|
|
|
5818
6126
|
code: ({ children, className: _className, ...props }) => /* @__PURE__ */ jsx13(
|
|
5819
6127
|
"code",
|
|
5820
6128
|
{
|
|
5821
|
-
className: "rounded-og-xs border border-og-border bg-og-surface-1 px-1 py-0.5 font-og-mono text-
|
|
6129
|
+
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",
|
|
5822
6130
|
...props,
|
|
5823
6131
|
children
|
|
5824
6132
|
}
|
|
@@ -5828,12 +6136,12 @@ var components = {
|
|
|
5828
6136
|
pre: ({ children, ...props }) => /* @__PURE__ */ jsx13(
|
|
5829
6137
|
"pre",
|
|
5830
6138
|
{
|
|
5831
|
-
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-
|
|
6139
|
+
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",
|
|
5832
6140
|
...props,
|
|
5833
6141
|
children
|
|
5834
6142
|
}
|
|
5835
6143
|
),
|
|
5836
|
-
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-
|
|
6144
|
+
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 }) }),
|
|
5837
6145
|
thead: ({ children, ...props }) => /* @__PURE__ */ jsx13("thead", { className: "bg-og-surface-1", ...props, children }),
|
|
5838
6146
|
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 }),
|
|
5839
6147
|
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 }),
|
|
@@ -5870,7 +6178,7 @@ var SESSION_STATUS_META = {
|
|
|
5870
6178
|
pulse: false
|
|
5871
6179
|
},
|
|
5872
6180
|
requires_action: {
|
|
5873
|
-
label: "
|
|
6181
|
+
label: "Waiting on you",
|
|
5874
6182
|
dotClassName: "bg-og-status-waiting",
|
|
5875
6183
|
badgeClassName: "text-og-status-waiting border-og-status-waiting/35 bg-og-status-waiting/10",
|
|
5876
6184
|
pulse: true
|
|
@@ -5896,7 +6204,7 @@ function SessionStatus({ status, label, size = "md", className }) {
|
|
|
5896
6204
|
"data-status": status,
|
|
5897
6205
|
className: cn(
|
|
5898
6206
|
"og-root inline-flex shrink-0 items-center rounded-full border font-medium",
|
|
5899
|
-
size === "sm" ? "gap-1 px-1.5 py-px text-
|
|
6207
|
+
size === "sm" ? "gap-1 px-1.5 py-px text-og-xs" : "gap-1.5 px-2 py-0.5 text-xs",
|
|
5900
6208
|
meta.badgeClassName,
|
|
5901
6209
|
className
|
|
5902
6210
|
),
|
|
@@ -5927,23 +6235,74 @@ function MessageTimeline({
|
|
|
5927
6235
|
}) {
|
|
5928
6236
|
const resolvedItems = useMemo8(() => items ?? buildTimeline(events ?? []), [items, events]);
|
|
5929
6237
|
const groups = useMemo8(() => groupTimeline(resolvedItems), [resolvedItems]);
|
|
5930
|
-
const scrollRef =
|
|
6238
|
+
const scrollRef = useRef15(null);
|
|
5931
6239
|
const [pinned, setPinned] = useState22(true);
|
|
6240
|
+
const pinnedRef = useRef15(true);
|
|
6241
|
+
const anchorRef = useRef15(null);
|
|
5932
6242
|
const lastItem = resolvedItems[resolvedItems.length - 1];
|
|
5933
6243
|
const streaming = lastItem !== void 0 && (lastItem.kind === "agent-message" || lastItem.kind === "reasoning") && lastItem.streaming;
|
|
5934
6244
|
const working = status === "running" && !streaming;
|
|
6245
|
+
const captureAnchor = useCallback21(() => {
|
|
6246
|
+
const node = scrollRef.current;
|
|
6247
|
+
const inner = node?.firstElementChild;
|
|
6248
|
+
if (!node || !inner) {
|
|
6249
|
+
anchorRef.current = null;
|
|
6250
|
+
return;
|
|
6251
|
+
}
|
|
6252
|
+
const containerTop = node.getBoundingClientRect().top;
|
|
6253
|
+
for (const child of Array.from(inner.children)) {
|
|
6254
|
+
const rect = child.getBoundingClientRect();
|
|
6255
|
+
if (rect.bottom > containerTop + 1) {
|
|
6256
|
+
anchorRef.current = { el: child, top: rect.top - containerTop };
|
|
6257
|
+
return;
|
|
6258
|
+
}
|
|
6259
|
+
}
|
|
6260
|
+
anchorRef.current = null;
|
|
6261
|
+
}, []);
|
|
5935
6262
|
useEffect15(() => {
|
|
5936
6263
|
const node = scrollRef.current;
|
|
5937
6264
|
if (node && autoFollow && pinned) {
|
|
5938
6265
|
node.scrollTop = node.scrollHeight;
|
|
5939
6266
|
}
|
|
5940
6267
|
}, [resolvedItems, working, autoFollow, pinned]);
|
|
6268
|
+
useEffect15(() => {
|
|
6269
|
+
const node = scrollRef.current;
|
|
6270
|
+
const inner = node?.firstElementChild;
|
|
6271
|
+
if (!node || !inner || typeof ResizeObserver === "undefined") {
|
|
6272
|
+
return;
|
|
6273
|
+
}
|
|
6274
|
+
const observer = new ResizeObserver(() => {
|
|
6275
|
+
const current = scrollRef.current;
|
|
6276
|
+
if (!current) {
|
|
6277
|
+
return;
|
|
6278
|
+
}
|
|
6279
|
+
if (autoFollow && pinnedRef.current) {
|
|
6280
|
+
current.scrollTop = current.scrollHeight;
|
|
6281
|
+
} else {
|
|
6282
|
+
const anchor = anchorRef.current;
|
|
6283
|
+
if (anchor && anchor.el.isConnected) {
|
|
6284
|
+
const containerTop = current.getBoundingClientRect().top;
|
|
6285
|
+
const now = anchor.el.getBoundingClientRect().top - containerTop;
|
|
6286
|
+
const diff = now - anchor.top;
|
|
6287
|
+
if (diff !== 0) {
|
|
6288
|
+
current.scrollTop += diff;
|
|
6289
|
+
}
|
|
6290
|
+
}
|
|
6291
|
+
}
|
|
6292
|
+
captureAnchor();
|
|
6293
|
+
});
|
|
6294
|
+
observer.observe(inner);
|
|
6295
|
+
return () => observer.disconnect();
|
|
6296
|
+
}, [autoFollow, captureAnchor]);
|
|
5941
6297
|
const onScroll = () => {
|
|
5942
6298
|
const node = scrollRef.current;
|
|
5943
6299
|
if (!node) {
|
|
5944
6300
|
return;
|
|
5945
6301
|
}
|
|
5946
|
-
|
|
6302
|
+
const nextPinned = node.scrollHeight - node.scrollTop - node.clientHeight < 48;
|
|
6303
|
+
pinnedRef.current = nextPinned;
|
|
6304
|
+
setPinned(nextPinned);
|
|
6305
|
+
captureAnchor();
|
|
5947
6306
|
};
|
|
5948
6307
|
return /* @__PURE__ */ jsx15(LightboxProvider, { children: /* @__PURE__ */ jsxs12("div", { className: cn("og-root relative flex min-h-0 flex-col", className), children: [
|
|
5949
6308
|
/* @__PURE__ */ jsx15("div", { ref: scrollRef, onScroll, className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-6 sm:px-6", children: /* @__PURE__ */ jsxs12("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: [
|
|
@@ -5973,6 +6332,7 @@ function MessageTimeline({
|
|
|
5973
6332
|
if (node) {
|
|
5974
6333
|
node.scrollTo({ top: node.scrollHeight, behavior: "smooth" });
|
|
5975
6334
|
}
|
|
6335
|
+
pinnedRef.current = true;
|
|
5976
6336
|
setPinned(true);
|
|
5977
6337
|
},
|
|
5978
6338
|
className: cn(
|
|
@@ -6088,7 +6448,10 @@ function UserMessageRow({
|
|
|
6088
6448
|
item,
|
|
6089
6449
|
renderMessageText
|
|
6090
6450
|
}) {
|
|
6091
|
-
return /* @__PURE__ */ jsx15("div", { className: "animate-og-enter flex justify-end", children: /* @__PURE__ */
|
|
6451
|
+
return /* @__PURE__ */ jsx15("div", { className: "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: [
|
|
6452
|
+
item.pending ? /* @__PURE__ */ jsx15("span", { className: "px-1 text-og-xs text-og-fg-subtle", children: "queued" }) : null,
|
|
6453
|
+
/* @__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 }) })
|
|
6454
|
+
] }) });
|
|
6092
6455
|
}
|
|
6093
6456
|
function AgentMessageRow({
|
|
6094
6457
|
item,
|
|
@@ -6192,11 +6555,11 @@ function FleetTile({ session, title, subtitle, onOpen, className }) {
|
|
|
6192
6555
|
}
|
|
6193
6556
|
),
|
|
6194
6557
|
/* @__PURE__ */ jsxs13("span", { className: "flex w-full items-start justify-between gap-3", children: [
|
|
6195
|
-
/* @__PURE__ */ jsx16("span", { className: "line-clamp-2 min-w-0 text-
|
|
6558
|
+
/* @__PURE__ */ jsx16("span", { className: "line-clamp-2 min-w-0 text-og-base font-medium leading-snug text-og-fg", children: title ?? sessionDisplayTitle(session) }),
|
|
6196
6559
|
/* @__PURE__ */ jsx16(SessionStatus, { status: session.status, size: "sm", className: "mt-px" })
|
|
6197
6560
|
] }),
|
|
6198
|
-
subtitle ? /* @__PURE__ */ jsx16("span", { className: "line-clamp-1 text-
|
|
6199
|
-
/* @__PURE__ */ jsxs13("span", { className: "mt-auto flex w-full items-center gap-2 text-
|
|
6561
|
+
subtitle ? /* @__PURE__ */ jsx16("span", { className: "line-clamp-1 text-og-sm text-og-fg-muted", children: subtitle }) : null,
|
|
6562
|
+
/* @__PURE__ */ jsxs13("span", { className: "mt-auto flex w-full items-center gap-2 text-og-xs text-og-fg-subtle", children: [
|
|
6200
6563
|
/* @__PURE__ */ jsx16("span", { className: "font-og-mono", children: session.id.slice(0, 8) }),
|
|
6201
6564
|
/* @__PURE__ */ jsx16("span", { "aria-hidden": true, children: "\xB7" }),
|
|
6202
6565
|
/* @__PURE__ */ jsx16("span", { className: "truncate", children: session.model }),
|
|
@@ -6208,7 +6571,7 @@ function FleetTile({ session, title, subtitle, onOpen, className }) {
|
|
|
6208
6571
|
}
|
|
6209
6572
|
|
|
6210
6573
|
// src/components/sandbox-terminal.tsx
|
|
6211
|
-
import { useEffect as useEffect16, useRef as
|
|
6574
|
+
import { useEffect as useEffect16, useRef as useRef16, useState as useState23 } from "react";
|
|
6212
6575
|
import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
6213
6576
|
function SandboxTerminal({
|
|
6214
6577
|
result,
|
|
@@ -6223,13 +6586,13 @@ function SandboxTerminal({
|
|
|
6223
6586
|
onActivate,
|
|
6224
6587
|
className
|
|
6225
6588
|
}) {
|
|
6226
|
-
const containerRef =
|
|
6227
|
-
const termRef =
|
|
6228
|
-
const fitRef =
|
|
6229
|
-
const writtenRef =
|
|
6589
|
+
const containerRef = useRef16(null);
|
|
6590
|
+
const termRef = useRef16(null);
|
|
6591
|
+
const fitRef = useRef16(null);
|
|
6592
|
+
const writtenRef = useRef16(/* @__PURE__ */ new Set());
|
|
6230
6593
|
const [ready, setReady] = useState23(false);
|
|
6231
6594
|
const ptyWs = terminalCapability?.transport === "pty-ws" && Boolean(terminalCapability?.url);
|
|
6232
|
-
const ptyOutputQueueRef =
|
|
6595
|
+
const ptyOutputQueueRef = useRef16([]);
|
|
6233
6596
|
const ptyStream = useTerminalStream({
|
|
6234
6597
|
capability: ptyWs ? {
|
|
6235
6598
|
transport: terminalCapability.transport,
|
|
@@ -6277,7 +6640,7 @@ function SandboxTerminal({
|
|
|
6277
6640
|
convertEol: true,
|
|
6278
6641
|
disableStdin: !interactive,
|
|
6279
6642
|
cursorBlink: interactive,
|
|
6280
|
-
fontFamily: fontFamily ?? "var(--og-font-mono
|
|
6643
|
+
fontFamily: fontFamily ?? "var(--og-font-mono)",
|
|
6281
6644
|
fontSize: fontSize ?? 13,
|
|
6282
6645
|
lineHeight: 1.25,
|
|
6283
6646
|
// A little breathing room from the panel edge so output isn't flush to
|
|
@@ -6324,7 +6687,7 @@ function SandboxTerminal({
|
|
|
6324
6687
|
if (!ready || !term || !theme) return;
|
|
6325
6688
|
term.options.theme = theme;
|
|
6326
6689
|
}, [ready, theme]);
|
|
6327
|
-
const enteredPtyRef =
|
|
6690
|
+
const enteredPtyRef = useRef16(false);
|
|
6328
6691
|
useEffect16(() => {
|
|
6329
6692
|
const term = termRef.current;
|
|
6330
6693
|
if (!ready || !term) return;
|
|
@@ -6380,24 +6743,24 @@ function SandboxTerminal({
|
|
|
6380
6743
|
};
|
|
6381
6744
|
}, [ready]);
|
|
6382
6745
|
return /* @__PURE__ */ jsxs14("div", { className: cn("relative flex h-full w-full flex-col overflow-hidden", className), children: [
|
|
6383
|
-
showHeader && /* @__PURE__ */ jsxs14("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-
|
|
6746
|
+
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: [
|
|
6384
6747
|
/* @__PURE__ */ jsxs14("span", { className: "flex min-w-0 items-center gap-1.5", children: [
|
|
6385
6748
|
/* @__PURE__ */ jsx17(
|
|
6386
6749
|
"span",
|
|
6387
6750
|
{
|
|
6388
6751
|
className: cn(
|
|
6389
6752
|
"size-1.5 shrink-0 rounded-full",
|
|
6390
|
-
result.running ? "bg-
|
|
6753
|
+
result.running ? "bg-og-status-running" : "bg-og-fg-subtle"
|
|
6391
6754
|
)
|
|
6392
6755
|
}
|
|
6393
6756
|
),
|
|
6394
|
-
/* @__PURE__ */ jsxs14("span", { className: "truncate font-
|
|
6757
|
+
/* @__PURE__ */ jsxs14("span", { className: "truncate font-og-mono", children: [
|
|
6395
6758
|
"pty: ",
|
|
6396
6759
|
shell ?? "shell"
|
|
6397
6760
|
] })
|
|
6398
6761
|
] }),
|
|
6399
6762
|
/* @__PURE__ */ jsxs14("span", { className: "flex shrink-0 items-center gap-2", children: [
|
|
6400
|
-
!interactive && /* @__PURE__ */ jsx17("span", { className: "rounded-
|
|
6763
|
+
!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" }),
|
|
6401
6764
|
/* @__PURE__ */ jsx17(
|
|
6402
6765
|
"button",
|
|
6403
6766
|
{
|
|
@@ -6406,7 +6769,7 @@ function SandboxTerminal({
|
|
|
6406
6769
|
termRef.current?.clear();
|
|
6407
6770
|
writtenRef.current = /* @__PURE__ */ new Set();
|
|
6408
6771
|
},
|
|
6409
|
-
className: "rounded-
|
|
6772
|
+
className: "rounded-og-sm px-1.5 py-0.5 text-og-xs hover:text-og-fg pointer-coarse:min-h-10",
|
|
6410
6773
|
children: "Clear"
|
|
6411
6774
|
}
|
|
6412
6775
|
)
|
|
@@ -6415,7 +6778,7 @@ function SandboxTerminal({
|
|
|
6415
6778
|
/* @__PURE__ */ jsxs14(
|
|
6416
6779
|
"div",
|
|
6417
6780
|
{
|
|
6418
|
-
className: "relative min-h-0 flex-1 bg-
|
|
6781
|
+
className: "relative min-h-0 flex-1 bg-og-bg px-2 py-1.5",
|
|
6419
6782
|
onPointerDownCapture: onActivate,
|
|
6420
6783
|
onFocusCapture: onActivate,
|
|
6421
6784
|
children: [
|
|
@@ -6432,7 +6795,7 @@ var XTERM_BASE_CSS = `
|
|
|
6432
6795
|
.xterm.focus,.xterm:focus{outline:none}
|
|
6433
6796
|
.xterm .xterm-helpers{position:absolute;top:0;z-index:5}
|
|
6434
6797
|
.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}
|
|
6435
|
-
.xterm .composition-view{background
|
|
6798
|
+
.xterm .composition-view{background:var(--og-color-bg);color:var(--og-color-fg);display:none;position:absolute;white-space:nowrap;z-index:1}
|
|
6436
6799
|
.xterm .composition-view.active{display:block}
|
|
6437
6800
|
.xterm .xterm-viewport{background-color:transparent;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}
|
|
6438
6801
|
.xterm .xterm-screen{position:relative}
|
|
@@ -6468,7 +6831,7 @@ function ensureXtermBaseCss() {
|
|
|
6468
6831
|
document.head.appendChild(style);
|
|
6469
6832
|
}
|
|
6470
6833
|
function TerminalPlaceholder() {
|
|
6471
|
-
return /* @__PURE__ */ jsx17("div", { className: "absolute inset-0 flex items-center justify-center text-
|
|
6834
|
+
return /* @__PURE__ */ jsx17("div", { className: "absolute inset-0 flex items-center justify-center text-og-sm text-og-fg-subtle", children: "Loading terminal\u2026" });
|
|
6472
6835
|
}
|
|
6473
6836
|
|
|
6474
6837
|
// src/components/file-browser.tsx
|
|
@@ -6484,19 +6847,19 @@ import {
|
|
|
6484
6847
|
Trash2Icon
|
|
6485
6848
|
} from "lucide-react";
|
|
6486
6849
|
import {
|
|
6487
|
-
useCallback as
|
|
6850
|
+
useCallback as useCallback22,
|
|
6488
6851
|
useEffect as useEffect17,
|
|
6489
6852
|
useMemo as useMemo9,
|
|
6490
|
-
useRef as
|
|
6853
|
+
useRef as useRef17,
|
|
6491
6854
|
useState as useState24
|
|
6492
6855
|
} from "react";
|
|
6493
6856
|
import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
6494
6857
|
var STATUS_TINT = {
|
|
6495
|
-
added: "text-
|
|
6496
|
-
modified: "text-
|
|
6497
|
-
deleted: "text-
|
|
6498
|
-
renamed: "text-
|
|
6499
|
-
untracked: "text-
|
|
6858
|
+
added: "text-og-status-idle",
|
|
6859
|
+
modified: "text-og-status-running",
|
|
6860
|
+
deleted: "text-og-status-failed line-through",
|
|
6861
|
+
renamed: "text-og-accent",
|
|
6862
|
+
untracked: "text-og-fg-subtle"
|
|
6500
6863
|
};
|
|
6501
6864
|
function parentOf2(path) {
|
|
6502
6865
|
const i = path.lastIndexOf("/");
|
|
@@ -6534,9 +6897,9 @@ function FileBrowser({
|
|
|
6534
6897
|
const [dragOver, setDragOver] = useState24(null);
|
|
6535
6898
|
const [menu, setMenu] = useState24(null);
|
|
6536
6899
|
const [busy, setBusy] = useState24(false);
|
|
6537
|
-
const containerRef =
|
|
6900
|
+
const containerRef = useRef17(null);
|
|
6538
6901
|
const cursor = active ?? selectedPath ?? null;
|
|
6539
|
-
const expand =
|
|
6902
|
+
const expand = useCallback22(
|
|
6540
6903
|
async (path) => {
|
|
6541
6904
|
const node = findNode(result.tree, path);
|
|
6542
6905
|
if (node && node.kind === "dir" && node.children === void 0) {
|
|
@@ -6554,14 +6917,14 @@ function FileBrowser({
|
|
|
6554
6917
|
},
|
|
6555
6918
|
[result]
|
|
6556
6919
|
);
|
|
6557
|
-
const open =
|
|
6920
|
+
const open = useCallback22(
|
|
6558
6921
|
(path) => {
|
|
6559
6922
|
setExpanded((prev) => new Set(prev).add(path));
|
|
6560
6923
|
void expand(path);
|
|
6561
6924
|
},
|
|
6562
6925
|
[expand]
|
|
6563
6926
|
);
|
|
6564
|
-
const toggle =
|
|
6927
|
+
const toggle = useCallback22(
|
|
6565
6928
|
async (node) => {
|
|
6566
6929
|
if (node.kind !== "dir") return;
|
|
6567
6930
|
const isOpen = expanded.has(node.path);
|
|
@@ -6589,7 +6952,7 @@ function FileBrowser({
|
|
|
6589
6952
|
return rows;
|
|
6590
6953
|
}, [result.tree, expanded]);
|
|
6591
6954
|
const supportsMutation = editable;
|
|
6592
|
-
const runDelete =
|
|
6955
|
+
const runDelete = useCallback22(
|
|
6593
6956
|
async (node) => {
|
|
6594
6957
|
if (!supportsMutation) return;
|
|
6595
6958
|
const recursive = node.kind === "dir";
|
|
@@ -6608,7 +6971,7 @@ function FileBrowser({
|
|
|
6608
6971
|
},
|
|
6609
6972
|
[supportsMutation, confirmDelete, result]
|
|
6610
6973
|
);
|
|
6611
|
-
const commitCreate =
|
|
6974
|
+
const commitCreate = useCallback22(
|
|
6612
6975
|
async (name) => {
|
|
6613
6976
|
const draft = draftCreate;
|
|
6614
6977
|
setDraftCreate(null);
|
|
@@ -6633,7 +6996,7 @@ function FileBrowser({
|
|
|
6633
6996
|
},
|
|
6634
6997
|
[draftCreate, supportsMutation, result, open, onSelectFile]
|
|
6635
6998
|
);
|
|
6636
|
-
const commitRename =
|
|
6999
|
+
const commitRename = useCallback22(
|
|
6637
7000
|
async (name) => {
|
|
6638
7001
|
const draft = draftRename;
|
|
6639
7002
|
setDraftRename(null);
|
|
@@ -6656,7 +7019,7 @@ function FileBrowser({
|
|
|
6656
7019
|
},
|
|
6657
7020
|
[draftRename, supportsMutation, result, selectedPath, active, onSelectFile]
|
|
6658
7021
|
);
|
|
6659
|
-
const startCreate =
|
|
7022
|
+
const startCreate = useCallback22(
|
|
6660
7023
|
(kind) => {
|
|
6661
7024
|
if (!supportsMutation) return;
|
|
6662
7025
|
const anchor = cursor ? findNode(result.tree, cursor) : void 0;
|
|
@@ -6668,7 +7031,7 @@ function FileBrowser({
|
|
|
6668
7031
|
},
|
|
6669
7032
|
[supportsMutation, cursor, result.tree, open]
|
|
6670
7033
|
);
|
|
6671
|
-
const startRename =
|
|
7034
|
+
const startRename = useCallback22(
|
|
6672
7035
|
(node) => {
|
|
6673
7036
|
if (!supportsMutation) return;
|
|
6674
7037
|
setDraftCreate(null);
|
|
@@ -6677,7 +7040,7 @@ function FileBrowser({
|
|
|
6677
7040
|
},
|
|
6678
7041
|
[supportsMutation]
|
|
6679
7042
|
);
|
|
6680
|
-
const onDropOnto =
|
|
7043
|
+
const onDropOnto = useCallback22(
|
|
6681
7044
|
async (targetDir, sourcePath) => {
|
|
6682
7045
|
setDragOver(null);
|
|
6683
7046
|
if (!supportsMutation || !sourcePath) return;
|
|
@@ -6701,7 +7064,7 @@ function FileBrowser({
|
|
|
6701
7064
|
},
|
|
6702
7065
|
[supportsMutation, result, selectedPath, active, onSelectFile]
|
|
6703
7066
|
);
|
|
6704
|
-
const onKeyDown =
|
|
7067
|
+
const onKeyDown = useCallback22(
|
|
6705
7068
|
(e) => {
|
|
6706
7069
|
if (draftCreate || draftRename) return;
|
|
6707
7070
|
if (flatRows.length === 0) return;
|
|
@@ -6778,10 +7141,9 @@ function FileBrowser({
|
|
|
6778
7141
|
window.removeEventListener("resize", close);
|
|
6779
7142
|
};
|
|
6780
7143
|
}, [menu]);
|
|
6781
|
-
|
|
6782
|
-
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}` });
|
|
6783
|
-
}
|
|
7144
|
+
const showErrorEmpty = result.error && result.tree.length === 0 && !draftCreate;
|
|
6784
7145
|
const showEmpty = !result.loading && result.tree.length === 0 && !draftCreate;
|
|
7146
|
+
const showToolbar = supportsMutation || Boolean(result.error) || result.loading;
|
|
6785
7147
|
const renderRow = (node, depth) => {
|
|
6786
7148
|
const isOpen = expanded.has(node.path);
|
|
6787
7149
|
if (renderNode) {
|
|
@@ -6849,11 +7211,11 @@ function FileBrowser({
|
|
|
6849
7211
|
setMenu({ node, x: e.clientX, y: e.clientY });
|
|
6850
7212
|
},
|
|
6851
7213
|
className: cn(
|
|
6852
|
-
"group flex w-full items-center gap-1 truncate rounded px-1 py-0.5 text-left text-
|
|
6853
|
-
"hover:bg-
|
|
6854
|
-
isSelected && "bg-
|
|
6855
|
-
isCursor && "outline outline-1 -outline-offset-1 outline-
|
|
6856
|
-
isDropTarget && "ring-1 ring-inset ring-
|
|
7214
|
+
"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",
|
|
7215
|
+
"hover:bg-og-surface-2",
|
|
7216
|
+
isSelected && "bg-og-surface-2",
|
|
7217
|
+
isCursor && "outline outline-1 -outline-offset-1 outline-og-accent",
|
|
7218
|
+
isDropTarget && "bg-og-accent-soft ring-1 ring-inset ring-og-accent",
|
|
6857
7219
|
node.status ? STATUS_TINT[node.status] : void 0
|
|
6858
7220
|
),
|
|
6859
7221
|
style: { paddingLeft: `${depth * 12 + 4}px` },
|
|
@@ -6861,7 +7223,7 @@ function FileBrowser({
|
|
|
6861
7223
|
isDir ? isLoading ? /* @__PURE__ */ jsx18(
|
|
6862
7224
|
Loader2Icon,
|
|
6863
7225
|
{
|
|
6864
|
-
className: "size-3 shrink-0 animate-spin text-
|
|
7226
|
+
className: "size-3 shrink-0 animate-spin text-og-fg-subtle",
|
|
6865
7227
|
"aria-label": "Loading"
|
|
6866
7228
|
}
|
|
6867
7229
|
) : /* @__PURE__ */ jsx18(ChevronRightIcon3, { className: cn("size-3 shrink-0 transition-transform", isOpen && "rotate-90") }) : /* @__PURE__ */ jsx18("span", { className: "inline-block w-3 shrink-0" }),
|
|
@@ -6880,7 +7242,7 @@ function FileBrowser({
|
|
|
6880
7242
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
6881
7243
|
setMenu({ node, x: rect.right, y: rect.bottom });
|
|
6882
7244
|
},
|
|
6883
|
-
className: "ml-auto hidden shrink-0 px-1 text-
|
|
7245
|
+
className: "ml-auto hidden shrink-0 px-1 text-og-fg-subtle hover:text-og-fg group-hover:inline",
|
|
6884
7246
|
children: "\u22EF"
|
|
6885
7247
|
}
|
|
6886
7248
|
)
|
|
@@ -6907,7 +7269,7 @@ function FileBrowser({
|
|
|
6907
7269
|
children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx18(
|
|
6908
7270
|
"div",
|
|
6909
7271
|
{
|
|
6910
|
-
className: "h-2.5 animate-pulse rounded bg-
|
|
7272
|
+
className: "h-2.5 animate-pulse rounded-og-sm bg-og-surface-2",
|
|
6911
7273
|
style: { width: `${70 - i * 12}%` }
|
|
6912
7274
|
},
|
|
6913
7275
|
i
|
|
@@ -6921,33 +7283,35 @@ function FileBrowser({
|
|
|
6921
7283
|
);
|
|
6922
7284
|
};
|
|
6923
7285
|
return /* @__PURE__ */ jsxs15("div", { className: cn("flex min-w-0 flex-col", className), children: [
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
7286
|
+
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: [
|
|
7287
|
+
supportsMutation ? /* @__PURE__ */ jsxs15(Fragment5, { children: [
|
|
7288
|
+
/* @__PURE__ */ jsx18(ToolbarButton, { label: "New file", onClick: () => startCreate("file"), disabled: busy, children: /* @__PURE__ */ jsx18(FilePlusIcon, { className: "size-3.5" }) }),
|
|
7289
|
+
/* @__PURE__ */ jsx18(ToolbarButton, { label: "New folder", onClick: () => startCreate("dir"), disabled: busy, children: /* @__PURE__ */ jsx18(FolderPlusIcon, { className: "size-3.5" }) }),
|
|
7290
|
+
/* @__PURE__ */ jsx18(
|
|
7291
|
+
ToolbarButton,
|
|
7292
|
+
{
|
|
7293
|
+
label: "Rename",
|
|
7294
|
+
onClick: () => {
|
|
7295
|
+
const node = cursor ? findNode(result.tree, cursor) : void 0;
|
|
7296
|
+
if (node) startRename(node);
|
|
7297
|
+
},
|
|
7298
|
+
disabled: busy || !cursor,
|
|
7299
|
+
children: /* @__PURE__ */ jsx18(PencilIcon, { className: "size-3.5" })
|
|
7300
|
+
}
|
|
7301
|
+
),
|
|
7302
|
+
/* @__PURE__ */ jsx18(
|
|
7303
|
+
ToolbarButton,
|
|
7304
|
+
{
|
|
7305
|
+
label: "Delete",
|
|
7306
|
+
onClick: () => {
|
|
7307
|
+
const node = cursor ? findNode(result.tree, cursor) : void 0;
|
|
7308
|
+
if (node) void runDelete(node);
|
|
7309
|
+
},
|
|
7310
|
+
disabled: busy || !cursor,
|
|
7311
|
+
children: /* @__PURE__ */ jsx18(Trash2Icon, { className: "size-3.5" })
|
|
7312
|
+
}
|
|
7313
|
+
)
|
|
7314
|
+
] }) : null,
|
|
6951
7315
|
/* @__PURE__ */ jsx18("span", { className: "ml-auto" }),
|
|
6952
7316
|
/* @__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") }) })
|
|
6953
7317
|
] }),
|
|
@@ -6971,7 +7335,7 @@ function FileBrowser({
|
|
|
6971
7335
|
} : void 0,
|
|
6972
7336
|
className: cn(
|
|
6973
7337
|
"min-w-0 flex-1 overflow-auto p-1 outline-none",
|
|
6974
|
-
dragOver === "" && "ring-1 ring-inset ring-
|
|
7338
|
+
dragOver === "" && "ring-1 ring-inset ring-og-accent"
|
|
6975
7339
|
),
|
|
6976
7340
|
"data-opengeni-file-tree": true,
|
|
6977
7341
|
children: [
|
|
@@ -6985,7 +7349,22 @@ function FileBrowser({
|
|
|
6985
7349
|
onCancel: () => setDraftCreate(null)
|
|
6986
7350
|
}
|
|
6987
7351
|
),
|
|
6988
|
-
|
|
7352
|
+
showErrorEmpty ? /* @__PURE__ */ jsxs15("div", { className: "flex flex-col items-start gap-2 p-2 text-og-sm text-og-fg-subtle", children: [
|
|
7353
|
+
/* @__PURE__ */ jsx18("div", { children: fallback ?? `Could not load files: ${result.error?.message ?? "refresh the file list to try again"}` }),
|
|
7354
|
+
/* @__PURE__ */ jsxs15(
|
|
7355
|
+
"button",
|
|
7356
|
+
{
|
|
7357
|
+
type: "button",
|
|
7358
|
+
onClick: () => void result.refresh(),
|
|
7359
|
+
disabled: result.loading,
|
|
7360
|
+
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",
|
|
7361
|
+
children: [
|
|
7362
|
+
/* @__PURE__ */ jsx18(RefreshCwIcon, { className: cn("size-3.5", result.loading && "animate-spin"), "aria-hidden": true }),
|
|
7363
|
+
"Retry"
|
|
7364
|
+
]
|
|
7365
|
+
}
|
|
7366
|
+
)
|
|
7367
|
+
] }) : 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))
|
|
6989
7368
|
]
|
|
6990
7369
|
}
|
|
6991
7370
|
),
|
|
@@ -7018,8 +7397,8 @@ function ToolbarButton({
|
|
|
7018
7397
|
onClick,
|
|
7019
7398
|
disabled,
|
|
7020
7399
|
className: cn(
|
|
7021
|
-
"inline-flex items-center justify-center rounded p-1 text-
|
|
7022
|
-
"hover:bg-
|
|
7400
|
+
"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",
|
|
7401
|
+
"hover:bg-og-surface-2 hover:text-og-fg",
|
|
7023
7402
|
"disabled:cursor-not-allowed disabled:opacity-40"
|
|
7024
7403
|
),
|
|
7025
7404
|
children
|
|
@@ -7034,8 +7413,8 @@ function InlineInput({
|
|
|
7034
7413
|
onCancel
|
|
7035
7414
|
}) {
|
|
7036
7415
|
const [value, setValue] = useState24(initialValue);
|
|
7037
|
-
const ref =
|
|
7038
|
-
const doneRef =
|
|
7416
|
+
const ref = useRef17(null);
|
|
7417
|
+
const doneRef = useRef17(false);
|
|
7039
7418
|
useEffect17(() => {
|
|
7040
7419
|
const el = ref.current;
|
|
7041
7420
|
if (!el) return;
|
|
@@ -7074,8 +7453,8 @@ function InlineInput({
|
|
|
7074
7453
|
e.stopPropagation();
|
|
7075
7454
|
},
|
|
7076
7455
|
className: cn(
|
|
7077
|
-
"min-w-0 flex-1 rounded border bg-
|
|
7078
|
-
"border-
|
|
7456
|
+
"min-w-0 flex-1 rounded-og-sm border bg-og-bg px-1 py-0 text-og-sm",
|
|
7457
|
+
"border-og-accent text-og-fg",
|
|
7079
7458
|
"outline-none"
|
|
7080
7459
|
)
|
|
7081
7460
|
}
|
|
@@ -7105,9 +7484,9 @@ function ContextMenu({
|
|
|
7105
7484
|
onClick();
|
|
7106
7485
|
},
|
|
7107
7486
|
className: cn(
|
|
7108
|
-
"flex w-full items-center gap-2 px-2.5 py-1 text-left text-
|
|
7109
|
-
"hover:bg-
|
|
7110
|
-
danger ? "text-
|
|
7487
|
+
"flex w-full items-center gap-2 px-2.5 py-1 text-left text-og-sm pointer-coarse:min-h-10",
|
|
7488
|
+
"hover:bg-og-surface-2",
|
|
7489
|
+
danger ? "text-og-status-failed" : "text-og-fg"
|
|
7111
7490
|
),
|
|
7112
7491
|
children: [
|
|
7113
7492
|
icon,
|
|
@@ -7123,14 +7502,14 @@ function ContextMenu({
|
|
|
7123
7502
|
style: { left, top },
|
|
7124
7503
|
className: cn(
|
|
7125
7504
|
"fixed z-50 min-w-[160px] overflow-hidden rounded-md border py-1 shadow-lg",
|
|
7126
|
-
"border-
|
|
7127
|
-
"bg-
|
|
7505
|
+
"border-og-border",
|
|
7506
|
+
"bg-og-surface-1"
|
|
7128
7507
|
),
|
|
7129
7508
|
children: [
|
|
7130
7509
|
isDir && /* @__PURE__ */ jsxs15(Fragment5, { children: [
|
|
7131
7510
|
item("New file", /* @__PURE__ */ jsx18(FilePlusIcon, { className: "size-3.5" }), onNewFile),
|
|
7132
7511
|
item("New folder", /* @__PURE__ */ jsx18(FolderPlusIcon, { className: "size-3.5" }), onNewFolder),
|
|
7133
|
-
/* @__PURE__ */ jsx18("div", { className: "my-1 h-px bg-
|
|
7512
|
+
/* @__PURE__ */ jsx18("div", { className: "my-1 h-px bg-og-border" })
|
|
7134
7513
|
] }),
|
|
7135
7514
|
item("Rename", /* @__PURE__ */ jsx18(PencilIcon, { className: "size-3.5" }), onRename),
|
|
7136
7515
|
item("Delete", /* @__PURE__ */ jsx18(Trash2Icon, { className: "size-3.5" }), onDelete, true)
|
|
@@ -7183,12 +7562,12 @@ function PierreFile({
|
|
|
7183
7562
|
themeType: themeType ?? "dark"
|
|
7184
7563
|
};
|
|
7185
7564
|
const pierreVars = {
|
|
7186
|
-
"--diffs-dark-bg": "var(--og-color-bg
|
|
7187
|
-
"--diffs-light-bg": "var(--og-color-bg
|
|
7188
|
-
"--diffs-bg-buffer-override": "var(--og-color-surface-1
|
|
7189
|
-
"--diffs-bg-separator-override": "var(--og-color-surface-1
|
|
7190
|
-
"--diffs-font-size": "
|
|
7191
|
-
"--diffs-line-height": "
|
|
7565
|
+
"--diffs-dark-bg": "var(--og-color-bg)",
|
|
7566
|
+
"--diffs-light-bg": "var(--og-color-bg)",
|
|
7567
|
+
"--diffs-bg-buffer-override": "var(--og-color-surface-1)",
|
|
7568
|
+
"--diffs-bg-separator-override": "var(--og-color-surface-1)",
|
|
7569
|
+
"--diffs-font-size": "var(--og-code-font-size)",
|
|
7570
|
+
"--diffs-line-height": "var(--og-code-line-height)"
|
|
7192
7571
|
};
|
|
7193
7572
|
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(
|
|
7194
7573
|
LazyFile,
|
|
@@ -7203,14 +7582,14 @@ function PlainFile({ name, contents }) {
|
|
|
7203
7582
|
return /* @__PURE__ */ jsx19(
|
|
7204
7583
|
"pre",
|
|
7205
7584
|
{
|
|
7206
|
-
className: "overflow-auto whitespace-pre p-2 font-
|
|
7585
|
+
className: "overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg",
|
|
7207
7586
|
"data-file": name,
|
|
7208
7587
|
children: contents
|
|
7209
7588
|
}
|
|
7210
7589
|
);
|
|
7211
7590
|
}
|
|
7212
7591
|
function FileSkeleton() {
|
|
7213
|
-
return /* @__PURE__ */ jsx19("div", { className: "p-3 text-
|
|
7592
|
+
return /* @__PURE__ */ jsx19("div", { className: "p-3 text-og-sm text-og-fg-subtle", children: "Loading file\u2026" });
|
|
7214
7593
|
}
|
|
7215
7594
|
|
|
7216
7595
|
// src/components/code-editor.tsx
|
|
@@ -7218,10 +7597,10 @@ import { Loader2Icon as Loader2Icon2, SaveIcon } from "lucide-react";
|
|
|
7218
7597
|
import {
|
|
7219
7598
|
lazy as lazy3,
|
|
7220
7599
|
Suspense as Suspense3,
|
|
7221
|
-
useCallback as
|
|
7600
|
+
useCallback as useCallback23,
|
|
7222
7601
|
useEffect as useEffect19,
|
|
7223
7602
|
useMemo as useMemo10,
|
|
7224
|
-
useRef as
|
|
7603
|
+
useRef as useRef18,
|
|
7225
7604
|
useState as useState26
|
|
7226
7605
|
} from "react";
|
|
7227
7606
|
import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
@@ -7290,7 +7669,7 @@ function CodeEditor({
|
|
|
7290
7669
|
const [saveError, setSaveError] = useState26(null);
|
|
7291
7670
|
const [savedTick, setSavedTick] = useState26(false);
|
|
7292
7671
|
const dirty = value !== baseline;
|
|
7293
|
-
const lastSeed =
|
|
7672
|
+
const lastSeed = useRef18({ path, contents: initialContents });
|
|
7294
7673
|
useEffect19(() => {
|
|
7295
7674
|
const seedChanged = lastSeed.current.path !== path || lastSeed.current.contents !== initialContents;
|
|
7296
7675
|
if (!seedChanged) return;
|
|
@@ -7333,9 +7712,9 @@ function CodeEditor({
|
|
|
7333
7712
|
cancelled = true;
|
|
7334
7713
|
};
|
|
7335
7714
|
}, [langKey]);
|
|
7336
|
-
const saveRef =
|
|
7715
|
+
const saveRef = useRef18(() => {
|
|
7337
7716
|
});
|
|
7338
|
-
const save =
|
|
7717
|
+
const save = useCallback23(async () => {
|
|
7339
7718
|
if (readOnly) return;
|
|
7340
7719
|
const snapshot = value;
|
|
7341
7720
|
if (snapshot === baseline) return;
|
|
@@ -7388,18 +7767,18 @@ function CodeEditor({
|
|
|
7388
7767
|
"data-opengeni-code-editor": true,
|
|
7389
7768
|
style: editorVars,
|
|
7390
7769
|
children: [
|
|
7391
|
-
/* @__PURE__ */ jsxs16("div", { className: "flex shrink-0 items-center gap-2 border-b border-
|
|
7770
|
+
/* @__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: [
|
|
7392
7771
|
/* @__PURE__ */ jsx20(
|
|
7393
7772
|
"span",
|
|
7394
7773
|
{
|
|
7395
7774
|
className: cn(
|
|
7396
7775
|
"size-1.5 shrink-0 rounded-full transition-colors",
|
|
7397
|
-
readOnly ? "bg-transparent" : dirty ? "bg-
|
|
7776
|
+
readOnly ? "bg-transparent" : dirty ? "bg-og-status-running" : "bg-og-status-idle"
|
|
7398
7777
|
),
|
|
7399
7778
|
title: readOnly ? "read-only" : dirty ? "unsaved changes" : "saved"
|
|
7400
7779
|
}
|
|
7401
7780
|
),
|
|
7402
|
-
/* @__PURE__ */ jsxs16("span", { className: "truncate font-
|
|
7781
|
+
/* @__PURE__ */ jsxs16("span", { className: "truncate font-og-mono text-og-xs text-og-fg-muted", children: [
|
|
7403
7782
|
fileName,
|
|
7404
7783
|
dirty && !readOnly ? " \u2022" : ""
|
|
7405
7784
|
] }),
|
|
@@ -7407,21 +7786,21 @@ function CodeEditor({
|
|
|
7407
7786
|
saveError && /* @__PURE__ */ jsx20(
|
|
7408
7787
|
"span",
|
|
7409
7788
|
{
|
|
7410
|
-
className: "max-w-[220px] truncate text-
|
|
7789
|
+
className: "max-w-[220px] truncate text-og-xs text-og-status-failed",
|
|
7411
7790
|
title: saveError.message,
|
|
7412
7791
|
children: saveError.message
|
|
7413
7792
|
}
|
|
7414
7793
|
),
|
|
7415
|
-
!saveError && savedTick && /* @__PURE__ */ jsx20("span", { className: "text-
|
|
7416
|
-
readOnly ? /* @__PURE__ */ jsx20("span", { className: "text-
|
|
7794
|
+
!saveError && savedTick && /* @__PURE__ */ jsx20("span", { className: "text-og-xs text-og-status-idle", children: "Saved" }),
|
|
7795
|
+
readOnly ? /* @__PURE__ */ jsx20("span", { className: "text-og-xs uppercase tracking-wide text-og-fg-subtle", children: "Read-only" }) : /* @__PURE__ */ jsxs16(
|
|
7417
7796
|
"button",
|
|
7418
7797
|
{
|
|
7419
7798
|
type: "button",
|
|
7420
7799
|
onClick: () => void save(),
|
|
7421
7800
|
disabled: saving || !dirty,
|
|
7422
7801
|
className: cn(
|
|
7423
|
-
"flex items-center gap-1 rounded-
|
|
7424
|
-
saving || !dirty ? "cursor-default text-
|
|
7802
|
+
"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",
|
|
7803
|
+
saving || !dirty ? "cursor-default text-og-fg-subtle opacity-60" : "text-og-fg hover:bg-og-accent-soft"
|
|
7425
7804
|
),
|
|
7426
7805
|
title: "Save (\u2318/Ctrl+S)",
|
|
7427
7806
|
children: [
|
|
@@ -7442,7 +7821,7 @@ function CodeEditor({
|
|
|
7442
7821
|
basicSetup: true,
|
|
7443
7822
|
extensions: cmExtensions,
|
|
7444
7823
|
height: "100%",
|
|
7445
|
-
className: "og-cm-editor min-h-full text-
|
|
7824
|
+
className: "og-cm-editor min-h-full text-og-sm",
|
|
7446
7825
|
onChange: readOnly ? void 0 : (next) => {
|
|
7447
7826
|
setValue(next);
|
|
7448
7827
|
setSavedTick(false);
|
|
@@ -7454,8 +7833,8 @@ function CodeEditor({
|
|
|
7454
7833
|
);
|
|
7455
7834
|
}
|
|
7456
7835
|
var editorVars = {
|
|
7457
|
-
"--og-cm-bg": "var(--og-color-bg
|
|
7458
|
-
fontFamily: "var(--og-font-mono
|
|
7836
|
+
"--og-cm-bg": "var(--og-color-bg)",
|
|
7837
|
+
fontFamily: "var(--og-font-mono)"
|
|
7459
7838
|
};
|
|
7460
7839
|
function PlainTextarea({
|
|
7461
7840
|
value,
|
|
@@ -7469,28 +7848,28 @@ function PlainTextarea({
|
|
|
7469
7848
|
readOnly,
|
|
7470
7849
|
spellCheck: false,
|
|
7471
7850
|
onChange: (e) => onChange(e.target.value),
|
|
7472
|
-
className: "h-full w-full resize-none bg-transparent p-2 font-
|
|
7851
|
+
className: "h-full w-full resize-none bg-transparent p-2 font-og-mono text-og-sm text-og-fg outline-none"
|
|
7473
7852
|
}
|
|
7474
7853
|
);
|
|
7475
7854
|
}
|
|
7476
7855
|
function EditorSkeleton() {
|
|
7477
|
-
return /* @__PURE__ */ jsx20("div", { className: "p-3 text-
|
|
7856
|
+
return /* @__PURE__ */ jsx20("div", { className: "p-3 text-og-sm text-og-fg-subtle", children: "Loading editor\u2026" });
|
|
7478
7857
|
}
|
|
7479
7858
|
|
|
7480
7859
|
// src/components/sandbox-files.tsx
|
|
7481
7860
|
import { FileIcon as FileIcon3 } from "lucide-react";
|
|
7482
|
-
import { useCallback as
|
|
7861
|
+
import { useCallback as useCallback24, useEffect as useEffect20, useMemo as useMemo11, useRef as useRef19, useState as useState27 } from "react";
|
|
7483
7862
|
import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
7484
7863
|
var STATUS_TINT2 = {
|
|
7485
|
-
added: "text-
|
|
7486
|
-
modified: "text-
|
|
7487
|
-
deleted: "text-
|
|
7488
|
-
renamed: "text-
|
|
7489
|
-
copied: "text-
|
|
7490
|
-
untracked: "text-
|
|
7491
|
-
ignored: "text-
|
|
7492
|
-
conflicted: "text-
|
|
7493
|
-
typechange: "text-
|
|
7864
|
+
added: "text-og-status-idle",
|
|
7865
|
+
modified: "text-og-status-running",
|
|
7866
|
+
deleted: "text-og-status-failed",
|
|
7867
|
+
renamed: "text-og-accent",
|
|
7868
|
+
copied: "text-og-accent",
|
|
7869
|
+
untracked: "text-og-fg-subtle",
|
|
7870
|
+
ignored: "text-og-fg-subtle",
|
|
7871
|
+
conflicted: "text-og-status-failed",
|
|
7872
|
+
typechange: "text-og-status-running"
|
|
7494
7873
|
};
|
|
7495
7874
|
var STATUS_LETTER = {
|
|
7496
7875
|
added: "A",
|
|
@@ -7517,7 +7896,7 @@ function SandboxFiles({
|
|
|
7517
7896
|
const [staged, setStaged] = useState27(false);
|
|
7518
7897
|
const [layout, setLayout] = useState27("unified");
|
|
7519
7898
|
const [editMode, setEditMode] = useState27(false);
|
|
7520
|
-
const rootRef =
|
|
7899
|
+
const rootRef = useRef19(null);
|
|
7521
7900
|
const [wide, setWide] = useState27(false);
|
|
7522
7901
|
useEffect20(() => {
|
|
7523
7902
|
const el = rootRef.current;
|
|
@@ -7537,7 +7916,7 @@ function SandboxFiles({
|
|
|
7537
7916
|
const selectedDiff = changed.find((f) => f.path === effectiveSelected) ?? null;
|
|
7538
7917
|
const viewPath = effectiveSelected && !selectedDiff ? effectiveSelected : null;
|
|
7539
7918
|
const fileView = useFileView(viewPath, files.readFile);
|
|
7540
|
-
const selectFile =
|
|
7919
|
+
const selectFile = useCallback24((path) => {
|
|
7541
7920
|
setSelected(path);
|
|
7542
7921
|
setEditMode(false);
|
|
7543
7922
|
}, []);
|
|
@@ -7554,11 +7933,11 @@ function SandboxFiles({
|
|
|
7554
7933
|
{
|
|
7555
7934
|
className: cn(
|
|
7556
7935
|
"min-h-0 overflow-auto",
|
|
7557
|
-
wide ? "w-[280px] shrink-0 border-r border-
|
|
7936
|
+
wide ? "w-[280px] shrink-0 border-r border-og-border" : "flex-1"
|
|
7558
7937
|
),
|
|
7559
7938
|
children: [
|
|
7560
|
-
changed.length > 0 && /* @__PURE__ */ jsxs17("div", { className: "border-b border-
|
|
7561
|
-
/* @__PURE__ */ jsxs17("div", { className: "px-2 py-1 text-
|
|
7939
|
+
changed.length > 0 && /* @__PURE__ */ jsxs17("div", { className: "border-b border-og-border", children: [
|
|
7940
|
+
/* @__PURE__ */ jsxs17("div", { className: "px-2 py-1 text-og-xs font-medium uppercase tracking-wide text-og-fg-subtle", children: [
|
|
7562
7941
|
"Changes \xB7 ",
|
|
7563
7942
|
changed.length
|
|
7564
7943
|
] }),
|
|
@@ -7568,15 +7947,15 @@ function SandboxFiles({
|
|
|
7568
7947
|
type: "button",
|
|
7569
7948
|
onClick: () => selectFile(file.path),
|
|
7570
7949
|
className: cn(
|
|
7571
|
-
"flex w-full items-center gap-1.5 truncate px-2 py-0.5 text-left text-
|
|
7572
|
-
file.path === effectiveSelected && "bg-
|
|
7950
|
+
"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",
|
|
7951
|
+
file.path === effectiveSelected && "bg-og-surface-2"
|
|
7573
7952
|
),
|
|
7574
7953
|
children: [
|
|
7575
7954
|
/* @__PURE__ */ jsx21(
|
|
7576
7955
|
"span",
|
|
7577
7956
|
{
|
|
7578
7957
|
className: cn(
|
|
7579
|
-
"w-3 shrink-0 text-center font-
|
|
7958
|
+
"w-3 shrink-0 text-center font-og-mono text-og-xs",
|
|
7580
7959
|
STATUS_TINT2[file.status]
|
|
7581
7960
|
),
|
|
7582
7961
|
children: STATUS_LETTER[file.status]
|
|
@@ -7584,12 +7963,12 @@ function SandboxFiles({
|
|
|
7584
7963
|
),
|
|
7585
7964
|
/* @__PURE__ */ jsx21(FileIcon3, { className: "size-3.5 shrink-0 opacity-70" }),
|
|
7586
7965
|
/* @__PURE__ */ jsx21("span", { className: "truncate", children: file.path }),
|
|
7587
|
-
/* @__PURE__ */ jsxs17("span", { className: "ml-auto flex shrink-0 items-center gap-1.5 pl-2 text-
|
|
7588
|
-
/* @__PURE__ */ jsxs17("span", { className: "text-
|
|
7966
|
+
/* @__PURE__ */ jsxs17("span", { className: "ml-auto flex shrink-0 items-center gap-1.5 pl-2 text-og-xs", children: [
|
|
7967
|
+
/* @__PURE__ */ jsxs17("span", { className: "text-og-status-idle", children: [
|
|
7589
7968
|
"+",
|
|
7590
7969
|
file.additions
|
|
7591
7970
|
] }),
|
|
7592
|
-
/* @__PURE__ */ jsxs17("span", { className: "text-
|
|
7971
|
+
/* @__PURE__ */ jsxs17("span", { className: "text-og-status-failed", children: [
|
|
7593
7972
|
"\u2212",
|
|
7594
7973
|
file.deletions
|
|
7595
7974
|
] })
|
|
@@ -7598,14 +7977,14 @@ function SandboxFiles({
|
|
|
7598
7977
|
}
|
|
7599
7978
|
) }, file.path)) })
|
|
7600
7979
|
] }),
|
|
7601
|
-
/* @__PURE__ */ jsx21("div", { className: "px-2 py-1 text-
|
|
7980
|
+
/* @__PURE__ */ jsx21("div", { className: "px-2 py-1 text-og-xs font-medium uppercase tracking-wide text-og-fg-subtle", children: "Files" }),
|
|
7602
7981
|
/* @__PURE__ */ jsx21(
|
|
7603
7982
|
FileBrowser,
|
|
7604
7983
|
{
|
|
7605
7984
|
result: files,
|
|
7606
7985
|
selectedPath: effectiveSelected ?? void 0,
|
|
7607
7986
|
onSelectFile: selectFile,
|
|
7608
|
-
emptyState: "
|
|
7987
|
+
emptyState: "This directory is empty",
|
|
7609
7988
|
className: "min-w-0"
|
|
7610
7989
|
}
|
|
7611
7990
|
)
|
|
@@ -7617,12 +7996,12 @@ function SandboxFiles({
|
|
|
7617
7996
|
{
|
|
7618
7997
|
className: cn(
|
|
7619
7998
|
"flex min-h-0 min-w-0 flex-col",
|
|
7620
|
-
wide ? "flex-1" : "flex-[1.4] border-t border-
|
|
7999
|
+
wide ? "flex-1" : "flex-[1.4] border-t border-og-border"
|
|
7621
8000
|
),
|
|
7622
8001
|
children: [
|
|
7623
|
-
/* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-
|
|
7624
|
-
/* @__PURE__ */ jsx21("span", { className: "truncate font-
|
|
7625
|
-
/* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
8002
|
+
/* @__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: [
|
|
8003
|
+
/* @__PURE__ */ jsx21("span", { className: "min-w-0 truncate font-og-mono text-og-xs text-og-fg-muted", children: effectiveSelected ?? "No file selected" }),
|
|
8004
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex min-w-0 shrink-0 flex-wrap items-center justify-end gap-1", children: [
|
|
7626
8005
|
selectedDiff && stagedGit && /* @__PURE__ */ jsx21(
|
|
7627
8006
|
Segmented,
|
|
7628
8007
|
{
|
|
@@ -7699,7 +8078,7 @@ function SandboxFiles({
|
|
|
7699
8078
|
fileView.sizeBytes ?? 0,
|
|
7700
8079
|
" bytes)."
|
|
7701
8080
|
] }) : fileView.content !== null ? /* @__PURE__ */ jsxs17(Fragment6, { children: [
|
|
7702
|
-
fileView.truncated && /* @__PURE__ */ jsxs17("div", { className: "border-b border-
|
|
8081
|
+
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: [
|
|
7703
8082
|
"Large file \u2014 showing a truncated preview (",
|
|
7704
8083
|
fileView.sizeBytes ?? 0,
|
|
7705
8084
|
" bytes loaded). Editing is disabled to avoid corrupting the file."
|
|
@@ -7710,10 +8089,10 @@ function SandboxFiles({
|
|
|
7710
8089
|
path: viewPath,
|
|
7711
8090
|
contents: fileView.content,
|
|
7712
8091
|
themeType: resolvedTheme,
|
|
7713
|
-
fallback: /* @__PURE__ */ jsx21("pre", { className: "overflow-auto whitespace-pre p-2 font-
|
|
8092
|
+
fallback: /* @__PURE__ */ jsx21("pre", { className: "overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg", children: fileView.content }),
|
|
7714
8093
|
className: "p-1"
|
|
7715
8094
|
}
|
|
7716
|
-
) : /* @__PURE__ */ jsx21("pre", { className: "overflow-auto whitespace-pre p-2 font-
|
|
8095
|
+
) : /* @__PURE__ */ jsx21("pre", { className: "overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg", children: fileView.content })
|
|
7717
8096
|
] }) : /* @__PURE__ */ jsxs17(Notice, { children: [
|
|
7718
8097
|
"Loading ",
|
|
7719
8098
|
viewPath,
|
|
@@ -7732,19 +8111,19 @@ function SandboxFiles({
|
|
|
7732
8111
|
}
|
|
7733
8112
|
function GitHeader({ git, dirtyCount }) {
|
|
7734
8113
|
const dirty = dirtyCount > 0;
|
|
7735
|
-
return /* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center gap-2 border-b border-
|
|
8114
|
+
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: [
|
|
7736
8115
|
/* @__PURE__ */ jsx21(
|
|
7737
8116
|
"span",
|
|
7738
8117
|
{
|
|
7739
8118
|
className: cn(
|
|
7740
8119
|
"size-2 shrink-0 rounded-full",
|
|
7741
|
-
dirty ? "bg-
|
|
8120
|
+
dirty ? "bg-og-status-running" : "bg-og-status-idle"
|
|
7742
8121
|
),
|
|
7743
8122
|
title: dirty ? `${dirtyCount} changed` : "clean"
|
|
7744
8123
|
}
|
|
7745
8124
|
),
|
|
7746
|
-
/* @__PURE__ */ jsx21("span", { className: "truncate font-
|
|
7747
|
-
(git.ahead > 0 || git.behind > 0) && /* @__PURE__ */ jsxs17("span", { className: "flex shrink-0 items-center gap-1.5 text-
|
|
8125
|
+
/* @__PURE__ */ jsx21("span", { className: "truncate font-og-mono text-og-fg", children: git.branch ?? (git.isRepo ? "(detached)" : "no repo") }),
|
|
8126
|
+
(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: [
|
|
7748
8127
|
git.ahead > 0 && /* @__PURE__ */ jsxs17("span", { children: [
|
|
7749
8128
|
"\u2191",
|
|
7750
8129
|
git.ahead
|
|
@@ -7754,7 +8133,7 @@ function GitHeader({ git, dirtyCount }) {
|
|
|
7754
8133
|
git.behind
|
|
7755
8134
|
] })
|
|
7756
8135
|
] }),
|
|
7757
|
-
dirty && /* @__PURE__ */ jsxs17("span", { className: "ml-auto shrink-0 text-
|
|
8136
|
+
dirty && /* @__PURE__ */ jsxs17("span", { className: "ml-auto shrink-0 text-og-xs text-og-fg-subtle", children: [
|
|
7758
8137
|
dirtyCount,
|
|
7759
8138
|
" changed"
|
|
7760
8139
|
] })
|
|
@@ -7765,14 +8144,14 @@ function Segmented({
|
|
|
7765
8144
|
value,
|
|
7766
8145
|
onChange
|
|
7767
8146
|
}) {
|
|
7768
|
-
return /* @__PURE__ */ jsx21("div", { className: "flex items-center rounded-
|
|
8147
|
+
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(
|
|
7769
8148
|
"button",
|
|
7770
8149
|
{
|
|
7771
8150
|
type: "button",
|
|
7772
8151
|
onClick: () => onChange(opt.value),
|
|
7773
8152
|
className: cn(
|
|
7774
|
-
"rounded-
|
|
7775
|
-
opt.value === value ? "bg-
|
|
8153
|
+
"rounded-og-xs px-1.5 py-0.5 text-og-xs pointer-coarse:min-h-10",
|
|
8154
|
+
opt.value === value ? "bg-og-accent-soft text-og-fg" : "text-og-fg-subtle hover:text-og-fg"
|
|
7776
8155
|
),
|
|
7777
8156
|
children: opt.label
|
|
7778
8157
|
},
|
|
@@ -7840,7 +8219,7 @@ function Notice({ children, className }) {
|
|
|
7840
8219
|
"div",
|
|
7841
8220
|
{
|
|
7842
8221
|
className: cn(
|
|
7843
|
-
"flex h-full items-center justify-center p-4 text-center text-
|
|
8222
|
+
"flex h-full items-center justify-center p-4 text-center text-og-sm text-og-fg-subtle",
|
|
7844
8223
|
className
|
|
7845
8224
|
),
|
|
7846
8225
|
children
|
|
@@ -7850,8 +8229,9 @@ function Notice({ children, className }) {
|
|
|
7850
8229
|
|
|
7851
8230
|
// src/components/desktop-viewer.tsx
|
|
7852
8231
|
import { LoaderCircleIcon as LoaderCircleIcon2, MonitorIcon, MousePointerClickIcon, WifiOffIcon } from "lucide-react";
|
|
7853
|
-
import { useEffect as useEffect21, useRef as
|
|
8232
|
+
import { useEffect as useEffect21, useRef as useRef20, useState as useState28 } from "react";
|
|
7854
8233
|
import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
8234
|
+
var DESKTOP_MEDIA_BACKGROUND = "#000";
|
|
7855
8235
|
function isHardUnavailable(reason) {
|
|
7856
8236
|
switch (reason) {
|
|
7857
8237
|
case "backend_unsupported":
|
|
@@ -7882,7 +8262,7 @@ function DesktopViewer({
|
|
|
7882
8262
|
connectTimeoutMs = 13e3,
|
|
7883
8263
|
className
|
|
7884
8264
|
}) {
|
|
7885
|
-
const containerRef =
|
|
8265
|
+
const containerRef = useRef20(null);
|
|
7886
8266
|
const [consented, setConsented] = useState28(false);
|
|
7887
8267
|
const [takeControl, setTakeControl] = useState28(interactive ?? false);
|
|
7888
8268
|
const externallyControlled = interactive !== void 0;
|
|
@@ -7924,9 +8304,9 @@ function DesktopViewer({
|
|
|
7924
8304
|
});
|
|
7925
8305
|
const connected = stream.state === "connected";
|
|
7926
8306
|
const hasLiveUrl = Boolean(connectCapability?.url);
|
|
7927
|
-
const streamStateRef =
|
|
8307
|
+
const streamStateRef = useRef20(stream.state);
|
|
7928
8308
|
streamStateRef.current = stream.state;
|
|
7929
|
-
const warmKeyRef =
|
|
8309
|
+
const warmKeyRef = useRef20(null);
|
|
7930
8310
|
useEffect21(() => {
|
|
7931
8311
|
if (!isWatching || !coldWarmable || needsAck || viewerCapReached) {
|
|
7932
8312
|
if (!coldWarmable) warmKeyRef.current = null;
|
|
@@ -8005,10 +8385,11 @@ function DesktopViewer({
|
|
|
8005
8385
|
"div",
|
|
8006
8386
|
{
|
|
8007
8387
|
className: cn(
|
|
8008
|
-
"relative h-full w-full overflow-hidden
|
|
8009
|
-
inControl && "ring-2 ring-inset ring-
|
|
8388
|
+
"relative h-full w-full overflow-hidden",
|
|
8389
|
+
inControl && "ring-2 ring-inset ring-og-accent",
|
|
8010
8390
|
className
|
|
8011
8391
|
),
|
|
8392
|
+
style: { backgroundColor: DESKTOP_MEDIA_BACKGROUND },
|
|
8012
8393
|
"data-opengeni-desktop": true,
|
|
8013
8394
|
"data-state": stream.state,
|
|
8014
8395
|
"data-ui-state": uiState,
|
|
@@ -8023,18 +8404,18 @@ function DesktopViewer({
|
|
|
8023
8404
|
"data-state": stream.state
|
|
8024
8405
|
}
|
|
8025
8406
|
),
|
|
8026
|
-
uiState === "connecting" && /* @__PURE__ */ jsxs18("div", { className: "pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-3 text-
|
|
8407
|
+
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: [
|
|
8027
8408
|
/* @__PURE__ */ jsxs18("span", { className: "relative flex items-center justify-center", children: [
|
|
8028
8409
|
/* @__PURE__ */ jsx22(MonitorIcon, { className: "size-8 opacity-30", strokeWidth: 1.5 }),
|
|
8029
8410
|
/* @__PURE__ */ jsx22(
|
|
8030
8411
|
LoaderCircleIcon2,
|
|
8031
8412
|
{
|
|
8032
|
-
className: "absolute size-12 animate-og-spin text-
|
|
8413
|
+
className: "absolute size-12 animate-og-spin text-og-accent opacity-70",
|
|
8033
8414
|
strokeWidth: 1.25
|
|
8034
8415
|
}
|
|
8035
8416
|
)
|
|
8036
8417
|
] }),
|
|
8037
|
-
/* @__PURE__ */ jsx22("span", { className: "text-
|
|
8418
|
+
/* @__PURE__ */ jsx22("span", { className: "text-og-sm", children: "Connecting to the desktop\u2026" })
|
|
8038
8419
|
] }),
|
|
8039
8420
|
showToggle && !externallyControlled && inControl && /* @__PURE__ */ jsx22(
|
|
8040
8421
|
InControlBar,
|
|
@@ -8047,7 +8428,7 @@ function DesktopViewer({
|
|
|
8047
8428
|
TakeControlCallToAction,
|
|
8048
8429
|
{
|
|
8049
8430
|
disabled: !serverAllowsControl,
|
|
8050
|
-
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,
|
|
8431
|
+
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,
|
|
8051
8432
|
onTakeControl: () => setTakeControl(true)
|
|
8052
8433
|
}
|
|
8053
8434
|
),
|
|
@@ -8073,16 +8454,16 @@ function TakeControlCallToAction({
|
|
|
8073
8454
|
title: disabled ? disabledReason : "Take control of the desktop",
|
|
8074
8455
|
onClick: onTakeControl,
|
|
8075
8456
|
className: cn(
|
|
8076
|
-
"group pointer-events-auto flex items-center gap-3 rounded-
|
|
8077
|
-
"border-
|
|
8078
|
-
"bg-
|
|
8079
|
-
"shadow-
|
|
8457
|
+
"group pointer-events-auto flex items-center gap-3 rounded-og-lg border px-5 py-3",
|
|
8458
|
+
"border-og-border",
|
|
8459
|
+
"bg-og-bg/85 backdrop-blur-md",
|
|
8460
|
+
"shadow-og-lg",
|
|
8080
8461
|
"outline-none transition-all duration-150 ease-out",
|
|
8081
|
-
"focus-visible:ring-2 focus-visible:ring-
|
|
8462
|
+
"focus-visible:ring-2 focus-visible:ring-og-accent focus-visible:ring-offset-2 focus-visible:ring-offset-og-bg",
|
|
8082
8463
|
disabled ? "cursor-not-allowed opacity-60" : cn(
|
|
8083
8464
|
"cursor-pointer opacity-90 hover:-translate-y-0.5 hover:opacity-100",
|
|
8084
|
-
"hover:border-
|
|
8085
|
-
"hover:bg-
|
|
8465
|
+
"hover:border-og-accent",
|
|
8466
|
+
"hover:bg-og-accent/10"
|
|
8086
8467
|
)
|
|
8087
8468
|
),
|
|
8088
8469
|
children: [
|
|
@@ -8091,16 +8472,16 @@ function TakeControlCallToAction({
|
|
|
8091
8472
|
{
|
|
8092
8473
|
className: cn(
|
|
8093
8474
|
"flex size-9 shrink-0 items-center justify-center rounded-full transition-colors",
|
|
8094
|
-
"bg-
|
|
8095
|
-
"text-
|
|
8475
|
+
"bg-og-accent",
|
|
8476
|
+
"text-og-accent-fg",
|
|
8096
8477
|
disabled ? "" : "group-hover:scale-105"
|
|
8097
8478
|
),
|
|
8098
8479
|
children: /* @__PURE__ */ jsx22(MousePointerClickIcon, { className: "size-5", strokeWidth: 2 })
|
|
8099
8480
|
}
|
|
8100
8481
|
),
|
|
8101
8482
|
/* @__PURE__ */ jsxs18("span", { className: "flex flex-col items-start leading-tight", children: [
|
|
8102
|
-
/* @__PURE__ */ jsx22("span", { className: "text-
|
|
8103
|
-
/* @__PURE__ */ jsx22("span", { className: "text-
|
|
8483
|
+
/* @__PURE__ */ jsx22("span", { className: "text-og-base font-semibold text-og-fg", children: "Take control" }),
|
|
8484
|
+
/* @__PURE__ */ jsx22("span", { className: "text-og-xs text-og-fg-subtle", children: disabled && disabledReason ? disabledReason : "Drive the mouse & keyboard" })
|
|
8104
8485
|
] })
|
|
8105
8486
|
]
|
|
8106
8487
|
}
|
|
@@ -8109,13 +8490,13 @@ function TakeControlCallToAction({
|
|
|
8109
8490
|
}
|
|
8110
8491
|
function InControlBar({ shared, onRelease }) {
|
|
8111
8492
|
return /* @__PURE__ */ jsxs18("div", { className: "pointer-events-none absolute inset-x-0 top-0 flex items-center justify-between gap-2 p-2", children: [
|
|
8112
|
-
/* @__PURE__ */ jsxs18("span", { className: "pointer-events-auto inline-flex items-center gap-2 rounded-
|
|
8493
|
+
/* @__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: [
|
|
8113
8494
|
/* @__PURE__ */ jsx22("span", { className: "size-1.5 animate-pulse rounded-full bg-current", "aria-hidden": true }),
|
|
8114
8495
|
"You're in control",
|
|
8115
8496
|
/* @__PURE__ */ jsx22("span", { className: "opacity-75", children: "\xB7 click Return control (or Ctrl+Alt+Shift)" })
|
|
8116
8497
|
] }),
|
|
8117
8498
|
/* @__PURE__ */ jsxs18("div", { className: "pointer-events-auto flex items-center gap-1.5", children: [
|
|
8118
|
-
shared && /* @__PURE__ */ jsx22("span", { className: "rounded-
|
|
8499
|
+
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" }),
|
|
8119
8500
|
/* @__PURE__ */ jsxs18(
|
|
8120
8501
|
"button",
|
|
8121
8502
|
{
|
|
@@ -8123,9 +8504,9 @@ function InControlBar({ shared, onRelease }) {
|
|
|
8123
8504
|
onClick: onRelease,
|
|
8124
8505
|
title: "Return control (or press Ctrl+Alt+Shift)",
|
|
8125
8506
|
className: cn(
|
|
8126
|
-
"inline-flex items-center gap-1.5 rounded-
|
|
8127
|
-
"border-
|
|
8128
|
-
"outline-none hover:bg-
|
|
8507
|
+
"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",
|
|
8508
|
+
"border-og-accent bg-og-bg/90 text-og-fg backdrop-blur-sm",
|
|
8509
|
+
"outline-none hover:bg-og-accent hover:text-og-accent-fg focus-visible:ring-2 focus-visible:ring-og-accent"
|
|
8129
8510
|
),
|
|
8130
8511
|
children: [
|
|
8131
8512
|
/* @__PURE__ */ jsx22(MonitorIcon, { className: "size-3.5", strokeWidth: 2, "aria-hidden": true }),
|
|
@@ -8145,7 +8526,7 @@ function unavailableCopy(reason) {
|
|
|
8145
8526
|
case "os_unsupported":
|
|
8146
8527
|
return "The sandbox OS does not support a desktop stream.";
|
|
8147
8528
|
case "not_provisioned":
|
|
8148
|
-
return "
|
|
8529
|
+
return "This sandbox doesn't have a desktop yet.";
|
|
8149
8530
|
case "disabled_by_policy":
|
|
8150
8531
|
return "Desktop streaming is disabled on this deployment.";
|
|
8151
8532
|
case "lease_cold":
|
|
@@ -8155,62 +8536,62 @@ function unavailableCopy(reason) {
|
|
|
8155
8536
|
}
|
|
8156
8537
|
}
|
|
8157
8538
|
function WarmingNotice({ onRetry }) {
|
|
8158
|
-
return /* @__PURE__ */ jsxs18("div", { className: "flex max-w-sm flex-col items-center gap-3 rounded-lg border border-
|
|
8539
|
+
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: [
|
|
8159
8540
|
/* @__PURE__ */ jsx22(
|
|
8160
8541
|
LoaderCircleIcon2,
|
|
8161
8542
|
{
|
|
8162
|
-
className: "size-7 animate-og-spin text-
|
|
8543
|
+
className: "size-7 animate-og-spin text-og-accent",
|
|
8163
8544
|
strokeWidth: 1.5
|
|
8164
8545
|
}
|
|
8165
8546
|
),
|
|
8166
8547
|
/* @__PURE__ */ jsxs18("div", { className: "space-y-1", children: [
|
|
8167
8548
|
/* @__PURE__ */ jsx22("div", { className: "font-medium", children: "Warming the sandbox\u2026" }),
|
|
8168
|
-
/* @__PURE__ */ jsx22("p", { className: "text-
|
|
8549
|
+
/* @__PURE__ */ jsx22("p", { className: "text-og-sm text-og-fg-subtle", children: "Spinning up the desktop \u2014 this takes a few seconds." })
|
|
8169
8550
|
] }),
|
|
8170
8551
|
onRetry && /* @__PURE__ */ jsx22(
|
|
8171
8552
|
"button",
|
|
8172
8553
|
{
|
|
8173
8554
|
type: "button",
|
|
8174
8555
|
onClick: onRetry,
|
|
8175
|
-
className: "rounded border border-
|
|
8556
|
+
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",
|
|
8176
8557
|
children: "Taking too long? Retry"
|
|
8177
8558
|
}
|
|
8178
8559
|
)
|
|
8179
8560
|
] });
|
|
8180
8561
|
}
|
|
8181
8562
|
function DefaultConsentGate({ shared, onAccept }) {
|
|
8182
|
-
return /* @__PURE__ */ jsxs18("div", { className: "max-w-sm rounded-lg border border-
|
|
8563
|
+
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: [
|
|
8183
8564
|
/* @__PURE__ */ jsx22("div", { className: "mb-1 font-medium", children: "Watch the live desktop?" }),
|
|
8184
|
-
/* @__PURE__ */ jsxs18("p", { className: "mb-3 text-
|
|
8565
|
+
/* @__PURE__ */ jsxs18("p", { className: "mb-3 text-og-sm text-og-fg-subtle", children: [
|
|
8185
8566
|
"The desktop pixel stream is ",
|
|
8186
8567
|
/* @__PURE__ */ jsx22("strong", { children: "un-redacted" }),
|
|
8187
8568
|
" \u2014 it can show secrets the agent prints on screen.",
|
|
8188
|
-
shared ? " This
|
|
8569
|
+
shared ? " This sandbox is shared: you'll also see other sessions' agents on the same screen." : ""
|
|
8189
8570
|
] }),
|
|
8190
8571
|
/* @__PURE__ */ jsx22(
|
|
8191
8572
|
"button",
|
|
8192
8573
|
{
|
|
8193
8574
|
type: "button",
|
|
8194
8575
|
onClick: onAccept,
|
|
8195
|
-
className: "rounded bg-
|
|
8576
|
+
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",
|
|
8196
8577
|
children: "I understand \u2014 show the desktop"
|
|
8197
8578
|
}
|
|
8198
8579
|
)
|
|
8199
8580
|
] });
|
|
8200
8581
|
}
|
|
8201
8582
|
function defaultNotice(title, body, onRetry) {
|
|
8202
|
-
return /* @__PURE__ */ jsxs18("div", { className: "max-w-sm rounded-lg border border-
|
|
8583
|
+
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: [
|
|
8203
8584
|
/* @__PURE__ */ jsxs18("div", { className: "mb-1 flex items-center justify-center gap-1.5 font-medium", children: [
|
|
8204
8585
|
onRetry && /* @__PURE__ */ jsx22(WifiOffIcon, { className: "size-4 opacity-70", strokeWidth: 1.75 }),
|
|
8205
8586
|
title
|
|
8206
8587
|
] }),
|
|
8207
|
-
/* @__PURE__ */ jsx22("p", { className: "text-
|
|
8588
|
+
/* @__PURE__ */ jsx22("p", { className: "text-og-sm text-og-fg-subtle", children: body }),
|
|
8208
8589
|
onRetry && /* @__PURE__ */ jsx22(
|
|
8209
8590
|
"button",
|
|
8210
8591
|
{
|
|
8211
8592
|
type: "button",
|
|
8212
8593
|
onClick: onRetry,
|
|
8213
|
-
className: "mt-3 rounded border border-
|
|
8594
|
+
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",
|
|
8214
8595
|
children: "Reconnect"
|
|
8215
8596
|
}
|
|
8216
8597
|
)
|
|
@@ -8218,12 +8599,13 @@ function defaultNotice(title, body, onRetry) {
|
|
|
8218
8599
|
}
|
|
8219
8600
|
|
|
8220
8601
|
// src/components/workspace-dock.tsx
|
|
8221
|
-
import { useCallback as
|
|
8602
|
+
import { useCallback as useCallback25, useEffect as useEffect22, useLayoutEffect, useState as useState29 } from "react";
|
|
8222
8603
|
import {
|
|
8223
8604
|
ChevronsLeftRightIcon,
|
|
8224
8605
|
Maximize2Icon,
|
|
8225
8606
|
Minimize2Icon,
|
|
8226
|
-
PanelRightCloseIcon
|
|
8607
|
+
PanelRightCloseIcon,
|
|
8608
|
+
XIcon as XIcon3
|
|
8227
8609
|
} from "lucide-react";
|
|
8228
8610
|
import {
|
|
8229
8611
|
Group,
|
|
@@ -8234,6 +8616,25 @@ import {
|
|
|
8234
8616
|
} from "react-resizable-panels";
|
|
8235
8617
|
import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
8236
8618
|
var useDockLayoutEffect = typeof window === "undefined" ? useEffect22 : useLayoutEffect;
|
|
8619
|
+
var DOCK_OVERLAY_BREAKPOINT = 1024;
|
|
8620
|
+
function useIsNarrow(maxWidth) {
|
|
8621
|
+
const [narrow, setNarrow] = useState29(false);
|
|
8622
|
+
useDockLayoutEffect(() => {
|
|
8623
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
8624
|
+
return;
|
|
8625
|
+
}
|
|
8626
|
+
const mql = window.matchMedia(`(max-width: ${maxWidth - 1}px)`);
|
|
8627
|
+
const update = () => setNarrow(mql.matches);
|
|
8628
|
+
update();
|
|
8629
|
+
if (typeof mql.addEventListener === "function") {
|
|
8630
|
+
mql.addEventListener("change", update);
|
|
8631
|
+
return () => mql.removeEventListener("change", update);
|
|
8632
|
+
}
|
|
8633
|
+
mql.addListener(update);
|
|
8634
|
+
return () => mql.removeListener(update);
|
|
8635
|
+
}, [maxWidth]);
|
|
8636
|
+
return narrow;
|
|
8637
|
+
}
|
|
8237
8638
|
function WorkspaceDock({
|
|
8238
8639
|
primary,
|
|
8239
8640
|
tabs,
|
|
@@ -8247,11 +8648,13 @@ function WorkspaceDock({
|
|
|
8247
8648
|
maxSize = 70,
|
|
8248
8649
|
className
|
|
8249
8650
|
}) {
|
|
8651
|
+
const narrow = useIsNarrow(DOCK_OVERLAY_BREAKPOINT);
|
|
8250
8652
|
const dockPanelRef = usePanelRef();
|
|
8251
8653
|
const [internalCollapsed, setInternalCollapsed] = useState29(false);
|
|
8252
8654
|
const [maximized, setMaximized] = useState29(false);
|
|
8253
8655
|
const [internalTab, setInternalTab] = useState29(tabs[0]?.id ?? "");
|
|
8254
8656
|
const collapsed = collapsedProp ?? internalCollapsed;
|
|
8657
|
+
const hostControlled = collapsedProp !== void 0;
|
|
8255
8658
|
const { defaultLayout, onLayoutChanged } = useDefaultLayout({
|
|
8256
8659
|
panelIds: ["primary", "dock"],
|
|
8257
8660
|
storage: typeof window !== "undefined" ? window.localStorage : void 0,
|
|
@@ -8260,14 +8663,14 @@ function WorkspaceDock({
|
|
|
8260
8663
|
const current = activeTab ?? internalTab;
|
|
8261
8664
|
const tabIds = tabs.map((tab) => tab.id).join("\0");
|
|
8262
8665
|
const firstTabId = tabs[0]?.id ?? "";
|
|
8263
|
-
const setTab =
|
|
8666
|
+
const setTab = useCallback25(
|
|
8264
8667
|
(id) => {
|
|
8265
8668
|
setInternalTab(id);
|
|
8266
8669
|
onActiveTabChange?.(id);
|
|
8267
8670
|
},
|
|
8268
8671
|
[onActiveTabChange]
|
|
8269
8672
|
);
|
|
8270
|
-
const setCollapsed =
|
|
8673
|
+
const setCollapsed = useCallback25(
|
|
8271
8674
|
(next) => {
|
|
8272
8675
|
setInternalCollapsed((previous) => previous === next ? previous : next);
|
|
8273
8676
|
onCollapsedChange?.(next);
|
|
@@ -8290,31 +8693,70 @@ function WorkspaceDock({
|
|
|
8290
8693
|
setTab(firstTabId);
|
|
8291
8694
|
}
|
|
8292
8695
|
}, [tabIds, firstTabId, current, setTab]);
|
|
8293
|
-
|
|
8294
|
-
if (!maximized) return;
|
|
8295
|
-
const onKey = (event) => {
|
|
8296
|
-
if (event.key === "Escape") setMaximized(false);
|
|
8297
|
-
};
|
|
8298
|
-
window.addEventListener("keydown", onKey);
|
|
8299
|
-
return () => window.removeEventListener("keydown", onKey);
|
|
8300
|
-
}, [maximized]);
|
|
8301
|
-
const collapse = useCallback24(() => {
|
|
8696
|
+
const collapse = useCallback25(() => {
|
|
8302
8697
|
dockPanelRef.current?.collapse();
|
|
8303
8698
|
setCollapsed(true);
|
|
8304
8699
|
}, [dockPanelRef, setCollapsed]);
|
|
8305
|
-
const expand =
|
|
8700
|
+
const expand = useCallback25(() => {
|
|
8306
8701
|
dockPanelRef.current?.expand();
|
|
8307
8702
|
setCollapsed(false);
|
|
8308
8703
|
}, [dockPanelRef, setCollapsed]);
|
|
8704
|
+
useEffect22(() => {
|
|
8705
|
+
const overlayOpen = maximized || narrow && !collapsed;
|
|
8706
|
+
if (!overlayOpen) return;
|
|
8707
|
+
const onKey = (event) => {
|
|
8708
|
+
if (event.key !== "Escape") return;
|
|
8709
|
+
if (maximized) setMaximized(false);
|
|
8710
|
+
else collapse();
|
|
8711
|
+
};
|
|
8712
|
+
window.addEventListener("keydown", onKey);
|
|
8713
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
8714
|
+
}, [maximized, narrow, collapsed, collapse]);
|
|
8715
|
+
if (narrow) {
|
|
8716
|
+
return /* @__PURE__ */ jsxs19("div", { className: cn("relative flex h-full min-h-0 w-full min-w-0", className), children: [
|
|
8717
|
+
/* @__PURE__ */ jsx23("div", { className: "min-h-0 min-w-0 flex-1", children: primary }),
|
|
8718
|
+
!collapsed && /* @__PURE__ */ jsx23(
|
|
8719
|
+
"div",
|
|
8720
|
+
{
|
|
8721
|
+
role: "dialog",
|
|
8722
|
+
"aria-modal": "true",
|
|
8723
|
+
"aria-label": "Workspace",
|
|
8724
|
+
className: "fixed inset-0 z-40 flex flex-col bg-og-bg",
|
|
8725
|
+
style: {
|
|
8726
|
+
paddingTop: "env(safe-area-inset-top)",
|
|
8727
|
+
paddingBottom: "env(safe-area-inset-bottom)"
|
|
8728
|
+
},
|
|
8729
|
+
children: /* @__PURE__ */ jsx23(
|
|
8730
|
+
DockChrome,
|
|
8731
|
+
{
|
|
8732
|
+
tabs,
|
|
8733
|
+
current,
|
|
8734
|
+
onTab: setTab,
|
|
8735
|
+
controls: /* @__PURE__ */ jsx23(ChromeButton, { onClick: collapse, title: "Close workspace", label: "Close workspace", children: /* @__PURE__ */ jsx23(XIcon3, { className: "size-4" }) })
|
|
8736
|
+
}
|
|
8737
|
+
)
|
|
8738
|
+
}
|
|
8739
|
+
)
|
|
8740
|
+
] });
|
|
8741
|
+
}
|
|
8309
8742
|
const dockChrome = /* @__PURE__ */ jsx23(
|
|
8310
8743
|
DockChrome,
|
|
8311
8744
|
{
|
|
8312
8745
|
tabs,
|
|
8313
8746
|
current,
|
|
8314
8747
|
onTab: setTab,
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8748
|
+
controls: /* @__PURE__ */ jsxs19(Fragment7, { children: [
|
|
8749
|
+
/* @__PURE__ */ jsx23(
|
|
8750
|
+
ChromeButton,
|
|
8751
|
+
{
|
|
8752
|
+
onClick: () => setMaximized((m) => !m),
|
|
8753
|
+
title: maximized ? "Restore (Esc)" : "Maximize",
|
|
8754
|
+
label: maximized ? "Restore dock" : "Maximize dock",
|
|
8755
|
+
children: maximized ? /* @__PURE__ */ jsx23(Minimize2Icon, { className: "size-3.5" }) : /* @__PURE__ */ jsx23(Maximize2Icon, { className: "size-3.5" })
|
|
8756
|
+
}
|
|
8757
|
+
),
|
|
8758
|
+
hostControlled ? null : /* @__PURE__ */ jsx23(ChromeButton, { onClick: collapse, title: "Collapse", label: "Collapse dock", children: /* @__PURE__ */ jsx23(PanelRightCloseIcon, { className: "size-3.5" }) })
|
|
8759
|
+
] })
|
|
8318
8760
|
}
|
|
8319
8761
|
);
|
|
8320
8762
|
return /* @__PURE__ */ jsxs19("div", { className: cn("relative flex h-full min-h-0 w-full min-w-0", className), children: [
|
|
@@ -8327,7 +8769,7 @@ function WorkspaceDock({
|
|
|
8327
8769
|
onLayoutChanged,
|
|
8328
8770
|
children: [
|
|
8329
8771
|
/* @__PURE__ */ jsx23(Panel, { id: "primary", minSize: "30%", className: "min-h-0 min-w-0", children: primary }),
|
|
8330
|
-
!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-
|
|
8772
|
+
!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" }) }),
|
|
8331
8773
|
/* @__PURE__ */ jsx23(
|
|
8332
8774
|
Panel,
|
|
8333
8775
|
{
|
|
@@ -8346,83 +8788,85 @@ function WorkspaceDock({
|
|
|
8346
8788
|
}
|
|
8347
8789
|
},
|
|
8348
8790
|
className: "min-h-0 min-w-0",
|
|
8349
|
-
children: !collapsed && !maximized && /* @__PURE__ */ jsx23("div", { className: "flex h-full min-h-0 min-w-0 flex-col border-l border-
|
|
8791
|
+
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 })
|
|
8350
8792
|
}
|
|
8351
8793
|
)
|
|
8352
8794
|
]
|
|
8353
8795
|
}
|
|
8354
8796
|
),
|
|
8355
|
-
collapsed && !maximized && /* @__PURE__ */ jsx23(
|
|
8797
|
+
collapsed && !maximized && !hostControlled && /* @__PURE__ */ jsx23(
|
|
8356
8798
|
"button",
|
|
8357
8799
|
{
|
|
8358
8800
|
type: "button",
|
|
8359
8801
|
onClick: expand,
|
|
8360
8802
|
title: "Open workspace",
|
|
8361
|
-
className: "absolute inset-y-0 right-0 flex w-6 shrink-0 items-center justify-center border-l border-
|
|
8803
|
+
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",
|
|
8362
8804
|
children: /* @__PURE__ */ jsx23(ChevronsLeftRightIcon, { className: "size-3.5" })
|
|
8363
8805
|
}
|
|
8364
8806
|
),
|
|
8365
|
-
maximized && /* @__PURE__ */ jsx23("div", { className: "fixed inset-0 z-40 flex flex-col bg-
|
|
8807
|
+
maximized && /* @__PURE__ */ jsx23("div", { className: "fixed inset-0 z-40 flex flex-col bg-og-bg", children: dockChrome })
|
|
8366
8808
|
] });
|
|
8367
8809
|
}
|
|
8810
|
+
function ChromeButton({
|
|
8811
|
+
onClick,
|
|
8812
|
+
title,
|
|
8813
|
+
label,
|
|
8814
|
+
children
|
|
8815
|
+
}) {
|
|
8816
|
+
return /* @__PURE__ */ jsx23(
|
|
8817
|
+
"button",
|
|
8818
|
+
{
|
|
8819
|
+
type: "button",
|
|
8820
|
+
onClick,
|
|
8821
|
+
title,
|
|
8822
|
+
"aria-label": label,
|
|
8823
|
+
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",
|
|
8824
|
+
children
|
|
8825
|
+
}
|
|
8826
|
+
);
|
|
8827
|
+
}
|
|
8368
8828
|
function DockChrome({
|
|
8369
8829
|
tabs,
|
|
8370
8830
|
current,
|
|
8371
8831
|
onTab,
|
|
8372
|
-
|
|
8373
|
-
onToggleMaximize,
|
|
8374
|
-
onCollapse
|
|
8832
|
+
controls
|
|
8375
8833
|
}) {
|
|
8376
8834
|
const active = tabs.find((t) => t.id === current) ?? tabs[0];
|
|
8377
8835
|
return /* @__PURE__ */ jsxs19(Fragment7, { children: [
|
|
8378
|
-
/* @__PURE__ */ jsxs19("div", { className: "flex shrink-0 items-center
|
|
8379
|
-
/* @__PURE__ */ jsx23(
|
|
8380
|
-
"
|
|
8836
|
+
/* @__PURE__ */ jsxs19("div", { className: "flex shrink-0 items-center gap-2 border-b border-og-border px-1.5 py-1", children: [
|
|
8837
|
+
/* @__PURE__ */ jsx23(
|
|
8838
|
+
"div",
|
|
8381
8839
|
{
|
|
8382
|
-
|
|
8383
|
-
role: "
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
children: maximized ? /* @__PURE__ */ jsx23(Minimize2Icon, { className: "size-3.5" }) : /* @__PURE__ */ jsx23(Maximize2Icon, { className: "size-3.5" })
|
|
8406
|
-
}
|
|
8407
|
-
),
|
|
8408
|
-
/* @__PURE__ */ jsx23(
|
|
8409
|
-
"button",
|
|
8410
|
-
{
|
|
8411
|
-
type: "button",
|
|
8412
|
-
onClick: onCollapse,
|
|
8413
|
-
title: maximized ? "Restore" : "Collapse",
|
|
8414
|
-
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))]",
|
|
8415
|
-
children: /* @__PURE__ */ jsx23(PanelRightCloseIcon, { className: "size-3.5" })
|
|
8416
|
-
}
|
|
8417
|
-
)
|
|
8418
|
-
] })
|
|
8840
|
+
className: "flex min-w-0 flex-1 items-center gap-0.5 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
8841
|
+
role: "tablist",
|
|
8842
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsxs19(
|
|
8843
|
+
"button",
|
|
8844
|
+
{
|
|
8845
|
+
type: "button",
|
|
8846
|
+
role: "tab",
|
|
8847
|
+
"aria-selected": tab.id === current,
|
|
8848
|
+
onClick: () => onTab(tab.id),
|
|
8849
|
+
className: cn(
|
|
8850
|
+
"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",
|
|
8851
|
+
tab.id === current ? "bg-og-accent-soft text-og-fg" : "text-og-fg-subtle hover:text-og-fg"
|
|
8852
|
+
),
|
|
8853
|
+
children: [
|
|
8854
|
+
/* @__PURE__ */ jsx23("span", { children: tab.label }),
|
|
8855
|
+
tab.badge
|
|
8856
|
+
]
|
|
8857
|
+
},
|
|
8858
|
+
tab.id
|
|
8859
|
+
))
|
|
8860
|
+
}
|
|
8861
|
+
),
|
|
8862
|
+
/* @__PURE__ */ jsx23("div", { className: "flex shrink-0 items-center gap-0.5 text-og-fg-subtle", children: controls })
|
|
8419
8863
|
] }),
|
|
8420
8864
|
/* @__PURE__ */ jsx23("div", { className: "min-h-0 min-w-0 flex-1 overflow-hidden", role: "tabpanel", children: active?.content })
|
|
8421
8865
|
] });
|
|
8422
8866
|
}
|
|
8423
8867
|
|
|
8424
8868
|
// src/hooks/use-codex-accounts.ts
|
|
8425
|
-
import { useCallback as
|
|
8869
|
+
import { useCallback as useCallback26, useState as useState30 } from "react";
|
|
8426
8870
|
function isCodexAccountEvent(event) {
|
|
8427
8871
|
return event.type === "codex.account.switched" || event.type === "turn.started";
|
|
8428
8872
|
}
|
|
@@ -8439,7 +8883,7 @@ function useCodexAccounts(options = {}) {
|
|
|
8439
8883
|
const codexClient = options.codexClient ?? client;
|
|
8440
8884
|
const sessionId = options.sessionId;
|
|
8441
8885
|
const sharedEvents = options.events;
|
|
8442
|
-
const load =
|
|
8886
|
+
const load = useCallback26(async () => {
|
|
8443
8887
|
const accountsP = codexClient.listCodexAccounts(workspaceId);
|
|
8444
8888
|
const sessionP = sessionId && codexClient.getSession ? codexClient.getSession(workspaceId, sessionId).catch(() => null) : Promise.resolve(null);
|
|
8445
8889
|
const [acc, session] = await Promise.all([accountsP, sessionP]);
|
|
@@ -8463,7 +8907,7 @@ function useCodexAccounts(options = {}) {
|
|
|
8463
8907
|
() => void state.refresh(),
|
|
8464
8908
|
{ enabled: options.enabled ?? true, ...sharedEvents !== void 0 ? { events: sharedEvents } : {} }
|
|
8465
8909
|
);
|
|
8466
|
-
const pin =
|
|
8910
|
+
const pin = useCallback26(
|
|
8467
8911
|
async (target) => {
|
|
8468
8912
|
if (!sessionId || !codexClient.pinSessionCodexAccount) {
|
|
8469
8913
|
return false;
|
|
@@ -8479,7 +8923,7 @@ function useCodexAccounts(options = {}) {
|
|
|
8479
8923
|
},
|
|
8480
8924
|
[codexClient, workspaceId, sessionId, mutation.run, state.refresh]
|
|
8481
8925
|
);
|
|
8482
|
-
const refreshUsage =
|
|
8926
|
+
const refreshUsage = useCallback26(
|
|
8483
8927
|
async () => {
|
|
8484
8928
|
if (!codexClient.refreshCodexUsage) {
|
|
8485
8929
|
return false;
|
|
@@ -8518,16 +8962,13 @@ function xtermThemeFromTokens(root) {
|
|
|
8518
8962
|
if (typeof window === "undefined" || typeof getComputedStyle === "undefined") return void 0;
|
|
8519
8963
|
const el = root ?? document.documentElement;
|
|
8520
8964
|
const style = getComputedStyle(el);
|
|
8521
|
-
const read = (
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
if (value) return value;
|
|
8525
|
-
}
|
|
8526
|
-
return void 0;
|
|
8965
|
+
const read = (name) => {
|
|
8966
|
+
const value = style.getPropertyValue(name).trim();
|
|
8967
|
+
return value || void 0;
|
|
8527
8968
|
};
|
|
8528
|
-
const bg = read(
|
|
8529
|
-
const fg = read(
|
|
8530
|
-
const accent = read(
|
|
8969
|
+
const bg = read("--og-color-bg");
|
|
8970
|
+
const fg = read("--og-color-fg");
|
|
8971
|
+
const accent = read("--og-color-accent");
|
|
8531
8972
|
const theme = {};
|
|
8532
8973
|
if (bg) theme.background = bg;
|
|
8533
8974
|
if (fg) theme.foreground = fg;
|
|
@@ -8553,6 +8994,7 @@ export {
|
|
|
8553
8994
|
DisclosureDefaultsProvider,
|
|
8554
8995
|
EnrollmentConsent,
|
|
8555
8996
|
EnrollmentDeviceFlow,
|
|
8997
|
+
FILE_ONLY_MESSAGE_TEXT,
|
|
8556
8998
|
FileBrowser,
|
|
8557
8999
|
FleetTile,
|
|
8558
9000
|
LightboxProvider,
|
|
@@ -8608,6 +9050,7 @@ export {
|
|
|
8608
9050
|
gitFileDiffToPatch,
|
|
8609
9051
|
groupTimeline,
|
|
8610
9052
|
hasPermission,
|
|
9053
|
+
humanizeFailureReason,
|
|
8611
9054
|
isApplyPatch,
|
|
8612
9055
|
isCodexAccountEvent,
|
|
8613
9056
|
isExecSessionLostBanner,
|