@opengeni/react 0.6.2 → 0.8.0

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