@opengeni/react 0.6.2 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/{chunk-DEW2ZNF2.js → chunk-5C7RGAWA.js} +70 -37
  2. package/dist/chunk-5C7RGAWA.js.map +1 -0
  3. package/dist/index.d.ts +27 -5
  4. package/dist/index.js +949 -616
  5. package/dist/index.js.map +1 -1
  6. package/dist/{machines-BD6h9P_s.d.ts → machines-Bv9tG7qZ.d.ts} +1 -1
  7. package/dist/machines.d.ts +1 -1
  8. package/dist/machines.js +1 -1
  9. package/package.json +2 -2
  10. package/src/components/chat-composer.tsx +127 -60
  11. package/src/components/code-editor.tsx +15 -15
  12. package/src/components/desktop-viewer.tsx +40 -36
  13. package/src/components/diff-view.tsx +22 -22
  14. package/src/components/enrollment-consent.tsx +13 -13
  15. package/src/components/file-browser.tsx +74 -67
  16. package/src/components/fleet-tile.tsx +3 -3
  17. package/src/components/machine-card.tsx +6 -6
  18. package/src/components/machine-status-pill.tsx +3 -3
  19. package/src/components/machines-dashboard.tsx +28 -14
  20. package/src/components/markdown.tsx +6 -6
  21. package/src/components/message-timeline.tsx +70 -2
  22. package/src/components/pierre-diff.tsx +9 -10
  23. package/src/components/pierre-file.tsx +8 -8
  24. package/src/components/sandbox-files.tsx +37 -40
  25. package/src/components/sandbox-terminal.tsx +9 -11
  26. package/src/components/session-status.tsx +2 -2
  27. package/src/components/workspace-dock.tsx +153 -49
  28. package/src/hooks/use-file-attachments.ts +45 -15
  29. package/src/index.ts +2 -2
  30. package/src/lib/format.ts +32 -0
  31. package/src/lib/xterm-theme.ts +8 -11
  32. package/src/timeline/activity-rail.tsx +1 -1
  33. package/src/timeline/parsers.ts +104 -0
  34. package/src/timeline/projection.ts +4 -2
  35. package/src/timeline/screenshot-lightbox.tsx +1 -1
  36. package/src/timeline/shared.tsx +4 -1
  37. package/src/timeline/tool-diff.tsx +1 -1
  38. package/src/timeline/tool-renderers.tsx +46 -7
  39. package/src/timeline/turn-summary.tsx +21 -3
  40. package/styles/tokens.css +8 -0
  41. 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";
@@ -732,7 +733,7 @@ function failureMessage(payload) {
732
733
  for (const key of ["error", "message"]) {
733
734
  const value = payload[key];
734
735
  if (typeof value === "string" && value.trim().length > 0) {
735
- return value;
736
+ return humanizeFailureReason(value);
736
737
  }
737
738
  }
738
739
  return null;
@@ -1028,6 +1029,88 @@ function unwrapMcpOutput(output) {
1028
1029
  }
1029
1030
  return { text: typeof output === "string" ? output : output == null ? "" : JSON.stringify(output), isError: false };
1030
1031
  }
1032
+ function screenshotDataUrl(out) {
1033
+ if (typeof out === "string") {
1034
+ if (out.startsWith("data:image")) {
1035
+ return out;
1036
+ }
1037
+ if (out.startsWith("{") || out.startsWith("[")) {
1038
+ const parsed = tryParseJson(out);
1039
+ if (parsed !== void 0 && parsed !== out) {
1040
+ return screenshotDataUrl(parsed);
1041
+ }
1042
+ }
1043
+ return null;
1044
+ }
1045
+ if (Array.isArray(out)) {
1046
+ for (const entry of out) {
1047
+ const url = screenshotDataUrl(entry);
1048
+ if (url) {
1049
+ return url;
1050
+ }
1051
+ }
1052
+ return null;
1053
+ }
1054
+ if (out === null || typeof out !== "object") {
1055
+ return null;
1056
+ }
1057
+ const record = out;
1058
+ const imageUrl = record.image_url ?? record.imageUrl;
1059
+ if (typeof imageUrl === "string" && imageUrl.startsWith("data:image")) {
1060
+ return imageUrl;
1061
+ }
1062
+ if (imageUrl && typeof imageUrl === "object") {
1063
+ const url = imageUrl.url;
1064
+ if (typeof url === "string" && url.startsWith("data:image")) {
1065
+ return url;
1066
+ }
1067
+ }
1068
+ const image = record.image;
1069
+ if (image && typeof image === "object") {
1070
+ const mediaType = typeof image.mediaType === "string" ? image.mediaType : "image/png";
1071
+ const base64 = bytesToBase64(image.data);
1072
+ if (base64) {
1073
+ return `data:${mediaType};base64,${base64}`;
1074
+ }
1075
+ if (typeof image.data === "string" && image.data.length > 0) {
1076
+ return `data:${mediaType};base64,${image.data}`;
1077
+ }
1078
+ }
1079
+ return null;
1080
+ }
1081
+ function bytesToBase64(data) {
1082
+ const isByte = (n) => typeof n === "number" && Number.isInteger(n) && n >= 0 && n <= 255;
1083
+ let bytes = null;
1084
+ if (Array.isArray(data) && data.every(isByte)) {
1085
+ bytes = data;
1086
+ } else if (data && typeof data === "object") {
1087
+ const record = data;
1088
+ if (record.type === "Buffer" && Array.isArray(record.data) && record.data.every(isByte)) {
1089
+ bytes = record.data;
1090
+ } else {
1091
+ const keys = Object.keys(record);
1092
+ if (keys.length > 0 && keys.every((key) => /^\d+$/.test(key))) {
1093
+ const values = keys.sort((a, b) => Number(a) - Number(b)).map((key) => record[key]);
1094
+ if (values.every(isByte)) {
1095
+ bytes = values;
1096
+ }
1097
+ }
1098
+ }
1099
+ }
1100
+ if (!bytes || bytes.length === 0) {
1101
+ return null;
1102
+ }
1103
+ try {
1104
+ let binary = "";
1105
+ const CHUNK = 32768;
1106
+ for (let i = 0; i < bytes.length; i += CHUNK) {
1107
+ binary += String.fromCharCode(...bytes.slice(i, i + CHUNK));
1108
+ }
1109
+ return typeof btoa === "function" ? btoa(binary) : Buffer.from(binary, "binary").toString("base64");
1110
+ } catch {
1111
+ return null;
1112
+ }
1113
+ }
1031
1114
 
1032
1115
  // src/timeline/shared.tsx
1033
1116
  import { CameraIcon, CameraOffIcon, ChevronRightIcon } from "lucide-react";
@@ -1131,7 +1214,7 @@ function LightboxRoot({ children }) {
1131
1214
  }
1132
1215
  )
1133
1216
  ] }),
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" })
1217
+ state.caption ? /* @__PURE__ */ jsx2("figcaption", { className: "max-w-2xl text-center font-og-mono text-og-xs text-white/55", children: state.caption }) : /* @__PURE__ */ jsx2("figcaption", { className: "font-og-mono text-og-xs uppercase tracking-[0.1em] text-white/35", children: "Esc or click outside to close" })
1135
1218
  ] })
1136
1219
  ]
1137
1220
  }
@@ -1172,7 +1255,10 @@ function ActivityDisclosure({
1172
1255
  const previewVisible = preview != null && !open;
1173
1256
  const rowClass = cn(
1174
1257
  "group/disclosure flex w-full min-w-0 items-center gap-2 rounded-og-sm px-1.5 py-1.5 text-left text-og-base",
1175
- "text-og-fg-muted transition-colors duration-150"
1258
+ "text-og-fg-muted transition-colors duration-150",
1259
+ // A tool row is a touch target on coarse pointers: grow its padding so the
1260
+ // hit area clears the 40px minimum without loosening the dense desktop rail.
1261
+ "pointer-coarse:py-2.5"
1176
1262
  );
1177
1263
  const inner = /* @__PURE__ */ jsxs2(Fragment2, { children: [
1178
1264
  hasBody ? /* @__PURE__ */ jsx3(ChevronRightIcon, { className: "size-3.5 shrink-0 text-og-fg-subtle transition-transform duration-150 ease-og-in-out group-data-[state=open]/disclosure:rotate-90" }) : /* @__PURE__ */ jsx3("span", { className: "size-3.5 shrink-0" }),
@@ -1247,7 +1333,7 @@ function TermBlock({
1247
1333
  const shown = full || !big ? output : lines.slice(-tailLines).join("\n");
1248
1334
  const showMore = big && !full;
1249
1335
  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: [
1336
+ return /* @__PURE__ */ jsxs2("div", { className: "min-w-0 overflow-hidden rounded-og-sm border border-og-border bg-og-bg/70", children: [
1251
1337
  showHeader ? /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 border-b border-og-border/70 px-2.5 py-1.5", children: [
1252
1338
  /* @__PURE__ */ jsx3("span", { className: "select-none text-og-status-idle", children: "$" }),
1253
1339
  command != null ? /* @__PURE__ */ jsx3("span", { className: "min-w-0 flex-1 truncate font-og-mono text-og-sm text-og-fg-muted", children: command }) : /* @__PURE__ */ jsx3("span", { className: "flex-1" }),
@@ -1412,7 +1498,7 @@ function DiffView({
1412
1498
  return /* @__PURE__ */ jsx4("div", { className, children: fallback });
1413
1499
  }
1414
1500
  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.") });
1501
+ return /* @__PURE__ */ jsx4("div", { className: cn("p-3 text-og-sm text-og-fg-subtle", className), children: emptyState ?? (isRepo ? "No changes" : "No repository mounted") });
1416
1502
  }
1417
1503
  return /* @__PURE__ */ jsx4("div", { className: cn("min-w-0 overflow-auto", className), "data-opengeni-diff": true, children: diff.map((file) => /* @__PURE__ */ jsx4(
1418
1504
  FileDiffBlock,
@@ -1431,24 +1517,24 @@ function FileDiffBlock({
1431
1517
  theme,
1432
1518
  onSelect
1433
1519
  }) {
1434
- return /* @__PURE__ */ jsxs3("section", { className: "mb-2 overflow-hidden rounded border border-[color:var(--color-border,#2a2a2a)]", children: [
1520
+ return /* @__PURE__ */ jsxs3("section", { className: "mb-2 overflow-hidden rounded-og-sm border border-og-border", children: [
1435
1521
  /* @__PURE__ */ jsxs3(
1436
1522
  "header",
1437
1523
  {
1438
1524
  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",
1525
+ "flex items-center justify-between gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-sm",
1440
1526
  onSelect && "cursor-pointer"
1441
1527
  ),
1442
1528
  onClick: onSelect,
1443
1529
  children: [
1444
- /* @__PURE__ */ jsx4("span", { className: "truncate font-mono", children: file.oldPath && file.oldPath !== file.path ? `${file.oldPath} \u2192 ${file.path}` : file.path }),
1530
+ /* @__PURE__ */ jsx4("span", { className: "truncate font-og-mono", children: file.oldPath && file.oldPath !== file.path ? `${file.oldPath} \u2192 ${file.path}` : file.path }),
1445
1531
  /* @__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: [
1532
+ /* @__PURE__ */ jsx4("span", { className: "rounded-og-xs bg-og-bg px-1 py-0.5 text-og-xs text-og-fg-subtle", children: STATUS_LABEL[file.status] }),
1533
+ /* @__PURE__ */ jsxs3("span", { className: "text-og-status-idle", children: [
1448
1534
  "+",
1449
1535
  file.additions
1450
1536
  ] }),
1451
- /* @__PURE__ */ jsxs3("span", { className: "text-[color:var(--color-danger,#f85149)]", children: [
1537
+ /* @__PURE__ */ jsxs3("span", { className: "text-og-status-failed", children: [
1452
1538
  "\u2212",
1453
1539
  file.deletions
1454
1540
  ] })
@@ -1456,12 +1542,12 @@ function FileDiffBlock({
1456
1542
  ]
1457
1543
  }
1458
1544
  ),
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 })
1545
+ file.isBinary ? /* @__PURE__ */ jsx4("div", { className: "px-2 py-3 text-og-sm text-og-fg-subtle", children: "Binary file not shown" }) : file.truncated ? /* @__PURE__ */ jsx4("div", { className: "px-2 py-3 text-og-sm text-og-fg-subtle", children: "Diff too large \u2014 truncated" }) : layout === "split" ? /* @__PURE__ */ jsx4(SplitHunks, { file, theme }) : /* @__PURE__ */ jsx4(UnifiedHunks, { file, theme })
1460
1546
  ] });
1461
1547
  }
1462
1548
  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))";
1549
+ if (type === "add") return theme?.addBackground ?? "var(--og-color-diff-add-bg)";
1550
+ if (type === "del") return theme?.delBackground ?? "var(--og-color-diff-del-bg)";
1465
1551
  if (type === "meta") return void 0;
1466
1552
  return theme?.contextBackground;
1467
1553
  }
@@ -1471,11 +1557,11 @@ function marker(type) {
1471
1557
  return " ";
1472
1558
  }
1473
1559
  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: [
1560
+ return /* @__PURE__ */ jsx4("div", { className: "font-og-mono text-og-xs", children: file.hunks.map((hunk, hi) => /* @__PURE__ */ jsxs3("div", { children: [
1475
1561
  /* @__PURE__ */ jsx4(
1476
1562
  "div",
1477
1563
  {
1478
- className: "px-2 py-0.5 text-[color:var(--color-info,#58a6ff)]",
1564
+ className: "px-2 py-0.5 text-og-accent",
1479
1565
  style: { color: theme?.metaForeground },
1480
1566
  children: hunk.header
1481
1567
  }
@@ -1486,9 +1572,9 @@ function UnifiedHunks({ file, theme }) {
1486
1572
  className: "flex",
1487
1573
  style: { backgroundColor: lineBg(line.type, theme) },
1488
1574
  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) }),
1575
+ /* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle", children: line.oldNo ?? "" }),
1576
+ /* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle", children: line.newNo ?? "" }),
1577
+ /* @__PURE__ */ jsx4("span", { className: "w-4 shrink-0 select-none text-center text-og-fg-subtle", children: marker(line.type) }),
1492
1578
  /* @__PURE__ */ jsx4("span", { className: "whitespace-pre-wrap break-all px-1", children: line.text })
1493
1579
  ]
1494
1580
  },
@@ -1497,7 +1583,7 @@ function UnifiedHunks({ file, theme }) {
1497
1583
  ] }, `${file.path}-h${hi}`)) });
1498
1584
  }
1499
1585
  function SplitHunks({ file, theme }) {
1500
- return /* @__PURE__ */ jsx4("div", { className: "font-mono text-[11px] leading-tight", children: file.hunks.map((hunk, hi) => {
1586
+ return /* @__PURE__ */ jsx4("div", { className: "font-og-mono text-og-xs", children: file.hunks.map((hunk, hi) => {
1501
1587
  const left = [];
1502
1588
  const right = [];
1503
1589
  for (const line of hunk.lines) {
@@ -1512,7 +1598,7 @@ function SplitHunks({ file, theme }) {
1512
1598
  }
1513
1599
  const rows = Math.max(left.length, right.length);
1514
1600
  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 }),
1601
+ /* @__PURE__ */ jsx4("div", { className: "px-2 py-0.5 text-og-accent", style: { color: theme?.metaForeground }, children: hunk.header }),
1516
1602
  Array.from({ length: rows }).map((_, ri) => {
1517
1603
  const l = left[ri] ?? null;
1518
1604
  const r = right[ri] ?? null;
@@ -1523,7 +1609,7 @@ function SplitHunks({ file, theme }) {
1523
1609
  className: "flex w-1/2 min-w-0",
1524
1610
  style: { backgroundColor: l ? lineBg(l.type, theme) : void 0 },
1525
1611
  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 ?? "" }),
1612
+ /* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle", children: l?.oldNo ?? "" }),
1527
1613
  /* @__PURE__ */ jsx4("span", { className: "whitespace-pre-wrap break-all px-1", children: l?.text ?? "" })
1528
1614
  ]
1529
1615
  }
@@ -1531,10 +1617,10 @@ function SplitHunks({ file, theme }) {
1531
1617
  /* @__PURE__ */ jsxs3(
1532
1618
  "span",
1533
1619
  {
1534
- className: "flex w-1/2 min-w-0 border-l border-[color:var(--color-border,#2a2a2a)]",
1620
+ className: "flex w-1/2 min-w-0 border-l border-og-border",
1535
1621
  style: { backgroundColor: r ? lineBg(r.type, theme) : void 0 },
1536
1622
  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 ?? "" }),
1623
+ /* @__PURE__ */ jsx4("span", { className: "w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle", children: r?.newNo ?? "" }),
1538
1624
  /* @__PURE__ */ jsx4("span", { className: "whitespace-pre-wrap break-all px-1", children: r?.text ?? "" })
1539
1625
  ]
1540
1626
  }
@@ -1619,12 +1705,12 @@ function PierreDiff({
1619
1705
  themeType: themeType ?? "dark"
1620
1706
  };
1621
1707
  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"
1708
+ "--diffs-dark-bg": "var(--og-color-bg)",
1709
+ "--diffs-light-bg": "var(--og-color-bg)",
1710
+ "--diffs-bg-buffer-override": "var(--og-color-surface-1)",
1711
+ "--diffs-bg-separator-override": "var(--og-color-surface-1)",
1712
+ "--diffs-font-size": "var(--og-code-font-size)",
1713
+ "--diffs-line-height": "var(--og-code-line-height)"
1628
1714
  };
1629
1715
  return /* @__PURE__ */ jsx5(
1630
1716
  "div",
@@ -1644,7 +1730,7 @@ function PierreDiff({
1644
1730
  );
1645
1731
  }
1646
1732
  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" });
1733
+ return /* @__PURE__ */ jsx5("div", { className: "p-3 text-og-sm text-og-fg-subtle", children: "Loading diff\u2026" });
1648
1734
  }
1649
1735
 
1650
1736
  // src/timeline/tool-diff.tsx
@@ -1672,7 +1758,7 @@ function LayoutToggle({ layout, onChange }) {
1672
1758
  type: "button",
1673
1759
  onClick: () => onChange(value),
1674
1760
  className: cn(
1675
- "rounded-[5px] px-2 py-[3px] text-[11px] font-medium capitalize transition-colors",
1761
+ "rounded-og-xs px-2 py-[3px] text-og-xs font-medium capitalize transition-colors",
1676
1762
  layout === value ? "bg-og-surface-2 text-og-fg" : "text-og-fg-subtle hover:text-og-fg-muted"
1677
1763
  ),
1678
1764
  children: value
@@ -2024,16 +2110,34 @@ function computerVerb(action) {
2024
2110
  return action.type;
2025
2111
  }
2026
2112
  }
2113
+ function asComputerArgs(args) {
2114
+ if (!args) {
2115
+ return {};
2116
+ }
2117
+ const parsed = typeof args === "string" ? tryParseJson(args) : args;
2118
+ if (!parsed || typeof parsed !== "object") {
2119
+ return {};
2120
+ }
2121
+ const record = parsed;
2122
+ return {
2123
+ ...typeof record.x === "number" ? { x: record.x } : {},
2124
+ ...typeof record.y === "number" ? { y: record.y } : {},
2125
+ ...typeof record.text === "string" ? { text: record.text } : {},
2126
+ ...Array.isArray(record.keys) ? { keys: record.keys } : {},
2127
+ ...typeof record.button === "string" ? { button: record.button } : {}
2128
+ };
2129
+ }
2027
2130
  function ComputerCallRenderer({ item }) {
2028
2131
  const raw = item.raw ?? {};
2029
- const action = raw.action;
2132
+ const functionAction = !raw.action && item.name.startsWith("computer_") && item.name !== "computer_call" ? { type: item.name.slice("computer_".length), ...asComputerArgs(item.arguments) } : void 0;
2133
+ const action = raw.action ?? functionAction;
2030
2134
  const actions = raw.actions ?? (action ? [action] : []);
2031
2135
  const verb = computerVerb(action);
2032
2136
  const out = item.output;
2033
2137
  const running = item.status === "running";
2034
2138
  const rejected = raw.providerData?.approvalStatus === "rejected";
2035
2139
  const readOnly = typeof out === "string" && out.includes("read-only");
2036
- const isImage2 = typeof out === "string" && out.startsWith("data:image");
2140
+ const shotUrl = screenshotDataUrl(out);
2037
2141
  const empty = out === "" || out == null;
2038
2142
  const batched = actions.length > 1 ? actions.map((a) => computerVerb(a)).join(" \xB7 ") : null;
2039
2143
  const countSuffix = actions.length > 1 ? ` \xB7${actions.length}` : "";
@@ -2078,8 +2182,8 @@ function ComputerCallRenderer({ item }) {
2078
2182
  }
2079
2183
  const isFailed = item.status === "failed";
2080
2184
  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)` : ""}`;
2185
+ if (shotUrl) {
2186
+ const caption = `${verb}${actions.length > 1 ? ` (+${actions.length - 1} more)` : ""}`;
2083
2187
  return /* @__PURE__ */ jsxs5(
2084
2188
  ActivityDisclosure,
2085
2189
  {
@@ -2088,9 +2192,9 @@ function ComputerCallRenderer({ item }) {
2088
2192
  title: `${verb}${countSuffix}`,
2089
2193
  failed: isFailed,
2090
2194
  cancelled: isCancelled,
2091
- media: /* @__PURE__ */ jsx7(Thumbnail, { src: out, caption }),
2195
+ media: /* @__PURE__ */ jsx7(Thumbnail, { src: shotUrl, caption }),
2092
2196
  children: [
2093
- /* @__PURE__ */ jsx7(ScreenshotFigure, { src: out, caption }),
2197
+ /* @__PURE__ */ jsx7(ScreenshotFigure, { src: shotUrl, caption }),
2094
2198
  batched ? /* @__PURE__ */ jsxs5(BodyNote, { children: [
2095
2199
  "batched: ",
2096
2200
  batched
@@ -2368,6 +2472,15 @@ var BASE_ENTRIES = [
2368
2472
  { match: "name", name: "write_stdin", render: WriteStdinRenderer },
2369
2473
  { match: "name", name: "apply_patch_call", render: ApplyPatchRenderer },
2370
2474
  { match: "name", name: "computer_call", render: ComputerCallRenderer },
2475
+ // Function-mode computer tools (codex / chat-wire transports).
2476
+ { match: "name", name: "computer_screenshot", render: ComputerCallRenderer },
2477
+ { match: "name", name: "computer_click", render: ComputerCallRenderer },
2478
+ { match: "name", name: "computer_double_click", render: ComputerCallRenderer },
2479
+ { match: "name", name: "computer_move", render: ComputerCallRenderer },
2480
+ { match: "name", name: "computer_scroll", render: ComputerCallRenderer },
2481
+ { match: "name", name: "computer_type", render: ComputerCallRenderer },
2482
+ { match: "name", name: "computer_keypress", render: ComputerCallRenderer },
2483
+ { match: "name", name: "computer_drag", render: ComputerCallRenderer },
2371
2484
  { match: "name", name: "web_search_call", render: WebSearchRenderer },
2372
2485
  { match: "name", name: "view_image", render: ViewImageRenderer },
2373
2486
  { match: "name", name: "environment_set_variable", render: SecretSetRenderer }
@@ -2497,7 +2610,7 @@ function WorkerRow({ item, onOpenSession }) {
2497
2610
  type: "button",
2498
2611
  onClick: () => item.workerSessionId && onOpenSession(item.workerSessionId),
2499
2612
  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",
2613
+ "shrink-0 self-center rounded-og-sm border border-og-border px-2.5 py-1 text-og-sm font-medium text-og-fg-muted pointer-coarse:py-2",
2501
2614
  "outline-none transition-colors duration-150 hover:border-og-border-strong hover:text-og-fg",
2502
2615
  "focus-visible:ring-2 focus-visible:ring-og-accent"
2503
2616
  ),
@@ -2524,6 +2637,9 @@ function TurnSummary({ items, outcome, failureText, durationMs, defaultOpen, chi
2524
2637
  {
2525
2638
  className: cn(
2526
2639
  "group flex w-full items-center gap-2.5 rounded-og-md border px-3 py-2 text-left text-og-base transition-colors",
2640
+ // A folded turn is a touch target on coarse pointers: grow the row so
2641
+ // it clears the 40px minimum without disturbing the calm desktop rhythm.
2642
+ "pointer-coarse:py-2.5",
2527
2643
  // Only a failed turn earns the one filled/tinted card in the timeline;
2528
2644
  // complete and cancelled stay flat and calm.
2529
2645
  outcome === "failed" ? "border-og-status-failed/30 bg-og-status-failed/[0.06] hover:border-og-status-failed/50" : "border-og-border bg-og-surface-1/50 hover:border-og-border-strong"
@@ -2547,7 +2663,19 @@ function TurnSummary({ items, outcome, failureText, durationMs, defaultOpen, chi
2547
2663
  failureText
2548
2664
  ] }) : null,
2549
2665
  outcome === "cancelled" ? /* @__PURE__ */ jsx9("span", { className: "text-og-fg-subtle", children: " \xB7 interrupted" }) : null
2550
- ] })
2666
+ ] }),
2667
+ /* @__PURE__ */ jsx9(
2668
+ "span",
2669
+ {
2670
+ "aria-hidden": true,
2671
+ className: cn(
2672
+ "ml-auto shrink-0 pl-2 text-og-xs text-og-fg-subtle transition-opacity duration-150",
2673
+ "opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100",
2674
+ "pointer-coarse:opacity-100"
2675
+ ),
2676
+ children: open ? "hide steps" : "show steps"
2677
+ }
2678
+ )
2551
2679
  ]
2552
2680
  }
2553
2681
  ),
@@ -2566,8 +2694,8 @@ function summarizeTurn(items, durationMs) {
2566
2694
  files += applyPatchOps(item.raw).length;
2567
2695
  } else if (item.name === "exec_command") {
2568
2696
  commands += 1;
2569
- } else if (rawTypeOf(item) === "computer_call" || item.name === "computer_call") {
2570
- if (typeof item.output === "string" && item.output.startsWith("data:image")) {
2697
+ } else if (rawTypeOf(item) === "computer_call" || item.name === "computer_call" || item.name === "computer_screenshot") {
2698
+ if (screenshotDataUrl(item.output) !== null) {
2571
2699
  screenshots += 1;
2572
2700
  }
2573
2701
  }
@@ -2812,15 +2940,28 @@ function generateClientEventId() {
2812
2940
  }
2813
2941
 
2814
2942
  // src/hooks/use-file-attachments.ts
2815
- import { useCallback as useCallback4, useState as useState10 } from "react";
2943
+ import { useCallback as useCallback4, useRef as useRef3, useState as useState10 } from "react";
2816
2944
  var isImage = (file) => file.type.startsWith("image/");
2817
2945
  function useFileAttachments(options = {}) {
2818
2946
  const { client, workspaceId } = useOpenGeni(options);
2819
2947
  const pasteFilter = options.pasteFilter ?? isImage;
2820
2948
  const [attachments, setAttachments] = useState10([]);
2949
+ const sources = useRef3(/* @__PURE__ */ new Map());
2950
+ const startUpload = useCallback4((id, file) => {
2951
+ void client.uploadFile(workspaceId, {
2952
+ filename: file.name || "file",
2953
+ contentType: file.type || "application/octet-stream",
2954
+ data: file
2955
+ }).then((asset) => {
2956
+ setAttachments((current) => current.map((attachment) => attachment.id === id ? { ...attachment, status: "ready", file: asset, name: asset.filename, contentType: asset.contentType, sizeBytes: asset.sizeBytes, error: void 0 } : attachment));
2957
+ }).catch((error) => {
2958
+ setAttachments((current) => current.map((attachment) => attachment.id === id ? { ...attachment, status: "failed", error: error instanceof Error ? error.message : String(error) } : attachment));
2959
+ });
2960
+ }, [client, workspaceId]);
2821
2961
  const addFiles = useCallback4((files) => {
2822
2962
  for (const file of files) {
2823
2963
  const id = crypto.randomUUID();
2964
+ sources.current.set(id, file);
2824
2965
  const previewUrl = isImage(file) ? URL.createObjectURL(file) : void 0;
2825
2966
  setAttachments((current) => [...current, {
2826
2967
  id,
@@ -2830,17 +2971,17 @@ function useFileAttachments(options = {}) {
2830
2971
  status: "uploading",
2831
2972
  ...previewUrl ? { previewUrl } : {}
2832
2973
  }]);
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
- });
2974
+ startUpload(id, file);
2842
2975
  }
2843
- }, [client, workspaceId]);
2976
+ }, [startUpload]);
2977
+ const retry = useCallback4((id) => {
2978
+ const file = sources.current.get(id);
2979
+ if (!file) {
2980
+ return;
2981
+ }
2982
+ setAttachments((current) => current.map((attachment) => attachment.id === id ? { ...attachment, status: "uploading", error: void 0 } : attachment));
2983
+ startUpload(id, file);
2984
+ }, [startUpload]);
2844
2985
  const addFromPaste = useCallback4((event) => {
2845
2986
  const clipboardFiles = event.clipboardData?.files;
2846
2987
  if (!clipboardFiles) {
@@ -2852,6 +2993,7 @@ function useFileAttachments(options = {}) {
2852
2993
  }
2853
2994
  }, [addFiles, pasteFilter]);
2854
2995
  const remove = useCallback4((id) => {
2996
+ sources.current.delete(id);
2855
2997
  setAttachments((current) => {
2856
2998
  const removed = current.find((attachment) => attachment.id === id);
2857
2999
  if (removed?.previewUrl) {
@@ -2861,6 +3003,7 @@ function useFileAttachments(options = {}) {
2861
3003
  });
2862
3004
  }, []);
2863
3005
  const clear = useCallback4(() => {
3006
+ sources.current.clear();
2864
3007
  setAttachments((current) => {
2865
3008
  for (const attachment of current) {
2866
3009
  if (attachment.previewUrl) {
@@ -2876,13 +3019,14 @@ function useFileAttachments(options = {}) {
2876
3019
  uploading: attachments.some((attachment) => attachment.status === "uploading"),
2877
3020
  addFiles,
2878
3021
  addFromPaste,
3022
+ retry,
2879
3023
  remove,
2880
3024
  clear
2881
3025
  };
2882
3026
  }
2883
3027
 
2884
3028
  // src/hooks/use-turn-queue.ts
2885
- import { useCallback as useCallback5, useEffect as useEffect5, useRef as useRef3, useState as useState11 } from "react";
3029
+ import { useCallback as useCallback5, useEffect as useEffect5, useRef as useRef4, useState as useState11 } from "react";
2886
3030
  function isTurnQueueEvent(event) {
2887
3031
  return event.type.startsWith("turn.");
2888
3032
  }
@@ -2926,8 +3070,8 @@ function useTurnQueue(sessionId, options = {}) {
2926
3070
  const [loading, setLoading] = useState11(enabled);
2927
3071
  const [error, setError] = useState11(null);
2928
3072
  const mutation = useMutationRunner();
2929
- const generation = useRef3(0);
2930
- const targetKeyRef = useRef3(null);
3073
+ const generation = useRef4(0);
3074
+ const targetKeyRef = useRef4(null);
2931
3075
  const load = useCallback5(async () => {
2932
3076
  if (!sessionId) {
2933
3077
  return;
@@ -3046,7 +3190,7 @@ function useTurnQueue(sessionId, options = {}) {
3046
3190
 
3047
3191
  // src/hooks/use-goal.ts
3048
3192
  import { OpenGeniApiError } from "@opengeni/sdk";
3049
- import { useCallback as useCallback6, useEffect as useEffect6, useRef as useRef4, useState as useState12 } from "react";
3193
+ import { useCallback as useCallback6, useEffect as useEffect6, useRef as useRef5, useState as useState12 } from "react";
3050
3194
  function isGoalEvent(event) {
3051
3195
  return event.type.startsWith("goal.");
3052
3196
  }
@@ -3059,8 +3203,8 @@ function useGoal(sessionId, options = {}) {
3059
3203
  const [loading, setLoading] = useState12(enabled);
3060
3204
  const [error, setError] = useState12(null);
3061
3205
  const mutation = useMutationRunner();
3062
- const generation = useRef4(0);
3063
- const targetKeyRef = useRef4(null);
3206
+ const generation = useRef5(0);
3207
+ const targetKeyRef = useRef5(null);
3064
3208
  const load = useCallback6(async () => {
3065
3209
  if (!sessionId) {
3066
3210
  return;
@@ -3465,7 +3609,7 @@ import {
3465
3609
  OpenGeniApiError as OpenGeniApiError2,
3466
3610
  applyUrlRotation
3467
3611
  } from "@opengeni/sdk";
3468
- import { useCallback as useCallback15, useEffect as useEffect7, useRef as useRef5, useState as useState13 } from "react";
3612
+ import { useCallback as useCallback15, useEffect as useEffect7, useRef as useRef6, useState as useState13 } from "react";
3469
3613
  function desktopAttachable(cell) {
3470
3614
  if (cell.transport !== null) return true;
3471
3615
  return cell.reason === "lease_cold" || cell.reason === "not_provisioned" || cell.reason === null;
@@ -3500,8 +3644,8 @@ function useSessionCapabilities(sessionId, options = {}) {
3500
3644
  const [viewerCapReached, setViewerCapReached] = useState13(false);
3501
3645
  const [viewerId, setViewerId] = useState13(null);
3502
3646
  const [nonce, setNonce] = useState13(0);
3503
- const epochRef = useRef5(0);
3504
- const viewerIdRef = useRef5(null);
3647
+ const epochRef = useRef6(0);
3648
+ const viewerIdRef = useRef6(null);
3505
3649
  const renegotiate = useCallback15(() => {
3506
3650
  setNonce((n) => n + 1);
3507
3651
  }, []);
@@ -3700,7 +3844,7 @@ import {
3700
3844
  desktopSocketUrl,
3701
3845
  nextDesktopState
3702
3846
  } from "@opengeni/sdk";
3703
- import { useEffect as useEffect9, useRef as useRef7, useState as useState15 } from "react";
3847
+ import { useEffect as useEffect9, useRef as useRef8, useState as useState15 } from "react";
3704
3848
 
3705
3849
  // src/lib/relay-wire.ts
3706
3850
  import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
@@ -3773,7 +3917,7 @@ function decodeStreamFrame(bytes) {
3773
3917
  }
3774
3918
 
3775
3919
  // src/hooks/use-relay-frame-stream.ts
3776
- import { useEffect as useEffect8, useRef as useRef6, useState as useState14 } from "react";
3920
+ import { useEffect as useEffect8, useRef as useRef7, useState as useState14 } from "react";
3777
3921
  var TAG_OPEN = 1;
3778
3922
  var TAG_OPENACK = 2;
3779
3923
  var TAG_FRAME = 3;
@@ -3791,7 +3935,7 @@ function useRelayFrameStream(options) {
3791
3935
  const [state, setState] = useState14("idle");
3792
3936
  const [error, setError] = useState14(null);
3793
3937
  const [nonce, setNonce] = useState14(0);
3794
- const stateRef = useRef6("idle");
3938
+ const stateRef = useRef7("idle");
3795
3939
  const setBoth = (next) => {
3796
3940
  stateRef.current = next;
3797
3941
  setState(next);
@@ -3800,7 +3944,7 @@ function useRelayFrameStream(options) {
3800
3944
  const transport = capability?.transport ?? null;
3801
3945
  const url = capability?.url ?? null;
3802
3946
  const token = capability?.token ?? null;
3803
- const factoryRef = useRef6(webSocketFactory);
3947
+ const factoryRef = useRef7(webSocketFactory);
3804
3948
  factoryRef.current = webSocketFactory;
3805
3949
  useEffect8(() => {
3806
3950
  if (typeof window === "undefined") return;
@@ -3994,7 +4138,7 @@ function useDesktopStream(options) {
3994
4138
  const [state, setState] = useState15("idle");
3995
4139
  const [error, setError] = useState15(null);
3996
4140
  const [nonce, setNonce] = useState15(0);
3997
- const stateRef = useRef7("idle");
4141
+ const stateRef = useRef8("idle");
3998
4142
  const setBoth = (next) => {
3999
4143
  stateRef.current = next;
4000
4144
  setState(next);
@@ -4004,11 +4148,11 @@ function useDesktopStream(options) {
4004
4148
  const token = capability?.token ?? null;
4005
4149
  const transport = capability?.transport ?? null;
4006
4150
  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);
4151
+ const rfbRef = useRef8(null);
4152
+ const interactiveRef = useRef8(interactive);
4153
+ const scaleViewportRef = useRef8(scaleViewport);
4154
+ const modeRef = useRef8(mode);
4155
+ const rfbFactoryRef = useRef8(rfbFactory);
4012
4156
  interactiveRef.current = interactive;
4013
4157
  scaleViewportRef.current = scaleViewport;
4014
4158
  modeRef.current = mode;
@@ -4101,7 +4245,7 @@ import {
4101
4245
  ttydResizeFrame,
4102
4246
  TtydServerCommand
4103
4247
  } from "@opengeni/sdk";
4104
- import { useEffect as useEffect10, useMemo as useMemo3, useRef as useRef8, useState as useState16 } from "react";
4248
+ import { useEffect as useEffect10, useMemo as useMemo3, useRef as useRef9, useState as useState16 } from "react";
4105
4249
  function decodeFrame(data) {
4106
4250
  if (typeof data === "string") {
4107
4251
  return { command: data.charAt(0), payload: data.slice(1) };
@@ -4114,13 +4258,13 @@ function decodeFrame(data) {
4114
4258
  function useTerminalStream(options) {
4115
4259
  const { capability, onOutput, onTitle, initialCols, initialRows } = options;
4116
4260
  const [status, setStatus] = useState16("closed");
4117
- const wsRef = useRef8(null);
4118
- const sizeRef = useRef8({
4261
+ const wsRef = useRef9(null);
4262
+ const sizeRef = useRef9({
4119
4263
  cols: initialCols ?? 80,
4120
4264
  rows: initialRows ?? 24
4121
4265
  });
4122
- const onOutputRef = useRef8(onOutput);
4123
- const onTitleRef = useRef8(onTitle);
4266
+ const onOutputRef = useRef9(onOutput);
4267
+ const onTitleRef = useRef9(onTitle);
4124
4268
  onOutputRef.current = onOutput;
4125
4269
  onTitleRef.current = onTitle;
4126
4270
  const transport = capability?.transport ?? null;
@@ -4223,7 +4367,7 @@ function useTerminalStream(options) {
4223
4367
 
4224
4368
  // src/hooks/use-sandbox-terminal.ts
4225
4369
  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";
4370
+ import { useCallback as useCallback16, useEffect as useEffect11, useMemo as useMemo4, useRef as useRef10, useState as useState17 } from "react";
4227
4371
  function useSandboxTerminal(sessionId, options) {
4228
4372
  const { client, workspaceId } = useOpenGeni(options);
4229
4373
  const includeAgentFirehose = options.includeAgentFirehose ?? true;
@@ -4233,7 +4377,7 @@ function useSandboxTerminal(sessionId, options) {
4233
4377
  const [openedPtyId, setOpenedPtyId] = useState17(null);
4234
4378
  const [openError, setOpenError] = useState17(null);
4235
4379
  const [reopenNonce, setReopenNonce] = useState17(0);
4236
- const openInFlight = useRef9(false);
4380
+ const openInFlight = useRef10(false);
4237
4381
  const boxWarm = liveness === void 0 || liveness === "warm" || liveness === "draining";
4238
4382
  useEffect11(() => {
4239
4383
  if (!interactive || !sessionId || ptyFilter || !boxWarm) return;
@@ -4339,7 +4483,7 @@ function useSandboxTerminal(sessionId, options) {
4339
4483
  }
4340
4484
 
4341
4485
  // src/hooks/use-sandbox-files.ts
4342
- import { useCallback as useCallback17, useEffect as useEffect12, useRef as useRef10, useState as useState18 } from "react";
4486
+ import { useCallback as useCallback17, useEffect as useEffect12, useRef as useRef11, useState as useState18 } from "react";
4343
4487
  function parentOf(path) {
4344
4488
  const i = path.lastIndexOf("/");
4345
4489
  return i <= 0 ? "" : path.slice(0, i);
@@ -4459,12 +4603,12 @@ function useSandboxFiles(sessionId, options = {}) {
4459
4603
  const enabled = (options.enabled ?? true) && Boolean(sessionId);
4460
4604
  const rootPath = options.rootPath ?? "";
4461
4605
  const [tree, setTree] = useState18([]);
4462
- const treeRef = useRef10([]);
4606
+ const treeRef = useRef11([]);
4463
4607
  const [loading, setLoading] = useState18(false);
4464
4608
  const [expandingPaths, setExpandingPaths] = useState18(/* @__PURE__ */ new Set());
4465
4609
  const [error, setError] = useState18(null);
4466
- const statusRef = useRef10(/* @__PURE__ */ new Map());
4467
- const ownRevisionsRef = useRef10(/* @__PURE__ */ new Set());
4610
+ const statusRef = useRef11(/* @__PURE__ */ new Map());
4611
+ const ownRevisionsRef = useRef11(/* @__PURE__ */ new Set());
4468
4612
  const onMutationError = options.onMutationError;
4469
4613
  treeRef.current = tree;
4470
4614
  const applyStatus = useCallback17((nodes) => {
@@ -4679,10 +4823,10 @@ function useSandboxFiles(sessionId, options = {}) {
4679
4823
  }
4680
4824
  }, [client, workspaceId, sessionId, rootPath, applyStatus]);
4681
4825
  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);
4826
+ const lastSeqRef = useRef11(0);
4827
+ const pendingParentsRef = useRef11(/* @__PURE__ */ new Set());
4828
+ const pendingGitRef = useRef11(false);
4829
+ const debounceRef = useRef11(null);
4686
4830
  useEffect12(() => {
4687
4831
  if (!enabled || !events) return;
4688
4832
  let sawNew = false;
@@ -4726,7 +4870,7 @@ function useSandboxFiles(sessionId, options = {}) {
4726
4870
  },
4727
4871
  []
4728
4872
  );
4729
- const wasLiveRef = useRef10(false);
4873
+ const wasLiveRef = useRef11(false);
4730
4874
  const liveness = options.liveness;
4731
4875
  useEffect12(() => {
4732
4876
  const live = liveness === "warm" || liveness === "draining";
@@ -4754,7 +4898,7 @@ function useSandboxFiles(sessionId, options = {}) {
4754
4898
  }
4755
4899
 
4756
4900
  // src/hooks/use-sandbox-git.ts
4757
- import { useCallback as useCallback18, useEffect as useEffect13, useRef as useRef11, useState as useState19 } from "react";
4901
+ import { useCallback as useCallback18, useEffect as useEffect13, useRef as useRef12, useState as useState19 } from "react";
4758
4902
  function useSandboxGit(sessionId, options = {}) {
4759
4903
  const { client, workspaceId } = useOpenGeni(options);
4760
4904
  const enabled = (options.enabled ?? true) && Boolean(sessionId);
@@ -4799,7 +4943,7 @@ function useSandboxGit(sessionId, options = {}) {
4799
4943
  void refresh();
4800
4944
  }, [enabled, refresh]);
4801
4945
  const events = options.events;
4802
- const lastChangeRef = useRef11(0);
4946
+ const lastChangeRef = useRef12(0);
4803
4947
  useEffect13(() => {
4804
4948
  if (!enabled || !events) return;
4805
4949
  let latest = lastChangeRef.current;
@@ -5048,14 +5192,14 @@ function clearErrorMessage(cause) {
5048
5192
  }
5049
5193
 
5050
5194
  // src/hooks/use-slash-commands.ts
5051
- import { useCallback as useCallback19, useMemo as useMemo5, useRef as useRef12, useState as useState20 } from "react";
5195
+ import { useCallback as useCallback19, useMemo as useMemo5, useRef as useRef13, useState as useState20 } from "react";
5052
5196
  function useSlashCommands(options) {
5053
5197
  const { commands, context, handlers, value, setValue } = options;
5054
5198
  const [highlight, setHighlight] = useState20(0);
5055
5199
  const [dismissedValue, setDismissedValue] = useState20(null);
5056
5200
  const dismissed = dismissedValue !== null && dismissedValue === value;
5057
- const navigatedRef = useRef12(false);
5058
- const navTokenRef = useRef12(value);
5201
+ const navigatedRef = useRef13(false);
5202
+ const navTokenRef = useRef13(value);
5059
5203
  if (navTokenRef.current !== value) {
5060
5204
  navTokenRef.current = value;
5061
5205
  navigatedRef.current = false;
@@ -5182,7 +5326,7 @@ function useSlashCommands(options) {
5182
5326
  },
5183
5327
  [items, runResolved]
5184
5328
  );
5185
- const runningRef = useRef12(false);
5329
+ const runningRef = useRef13(false);
5186
5330
  const onKeyDown = useCallback19(
5187
5331
  (event) => {
5188
5332
  if (!open) {
@@ -5323,9 +5467,9 @@ function CommandPalette({ open, items, highlight, onHighlight, onRun, argHintTex
5323
5467
  }
5324
5468
 
5325
5469
  // src/components/chat-composer.tsx
5326
- import { ArrowUpIcon, FileIcon, ImageIcon as ImageIcon2, LoaderCircleIcon, PaperclipIcon, SquareIcon, XIcon as XIcon2 } from "lucide-react";
5470
+ import { ArrowUpIcon, FileIcon, ImageIcon as ImageIcon2, LoaderCircleIcon, PaperclipIcon, RotateCwIcon, SquareIcon, XIcon as XIcon2 } from "lucide-react";
5327
5471
  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";
5472
+ import { useCallback as useCallback20, useEffect as useEffect14, useId as useId2, useMemo as useMemo7, useRef as useRef14, useState as useState21 } from "react";
5329
5473
 
5330
5474
  // src/components/model-picker.tsx
5331
5475
  import { ChevronDownIcon } from "lucide-react";
@@ -5402,8 +5546,8 @@ function ChatComposer({
5402
5546
  commandContext,
5403
5547
  onClearView
5404
5548
  }) {
5405
- const textareaRef = useRef13(null);
5406
- const fileInputRef = useRef13(null);
5549
+ const textareaRef = useRef14(null);
5550
+ const fileInputRef = useRef14(null);
5407
5551
  const active = status != null && ACTIVE_STATUSES.has(status);
5408
5552
  const blockedByUpload = attachments?.uploading === true;
5409
5553
  const hasReadyAttachment = (attachments?.readyResources.length ?? 0) > 0;
@@ -5545,217 +5689,258 @@ function ChatComposer({
5545
5689
  [commands, commandContext]
5546
5690
  );
5547
5691
  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
- }
5692
+ return (
5693
+ // Respect the iOS home-indicator inset so the sticky composer never sits
5694
+ // under it (0 on non-notch devices and desktop, so it's inert there).
5695
+ /* @__PURE__ */ jsxs10("div", { className: cn("og-root", className), style: { paddingBottom: "env(safe-area-inset-bottom)" }, children: [
5696
+ /* @__PURE__ */ jsxs10("div", { className: "relative", children: [
5697
+ paletteEnabled ? /* @__PURE__ */ jsx12(
5698
+ CommandPalette,
5699
+ {
5700
+ open: palette.open && confirmState === null,
5701
+ items: palette.items,
5702
+ highlight: palette.highlight,
5703
+ onHighlight: palette.setHighlight,
5704
+ onRun: (index) => {
5705
+ palette.setHighlight(index);
5706
+ void palette.runAt(index);
5707
+ },
5708
+ argHintText: palette.activeArgHint,
5709
+ listboxId
5710
+ }
5711
+ ) : null,
5712
+ /* @__PURE__ */ jsxs10(
5713
+ "div",
5714
+ {
5715
+ onDragOver: attachments ? handleDragOver : void 0,
5716
+ onDragLeave: attachments ? handleDragLeave : void 0,
5717
+ onDrop: attachments ? handleDrop : void 0,
5718
+ className: cn(
5719
+ "relative rounded-og-lg border border-og-border bg-og-surface-1 shadow-og-sm",
5720
+ "transition-[border-color,box-shadow] duration-200",
5721
+ "focus-within:border-og-accent/60 focus-within:shadow-og-glow",
5722
+ // While files are dragged over, swap to a dashed accent border to
5723
+ // signal a live drop target (the overlay carries the label).
5724
+ dragging && "border-dashed border-og-accent"
5627
5725
  ),
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
- }
5726
+ children: [
5727
+ dragging ? /* @__PURE__ */ jsx12(
5728
+ "div",
5729
+ {
5730
+ "aria-hidden": true,
5731
+ className: cn(
5732
+ "pointer-events-none absolute inset-0 z-10 flex items-center justify-center",
5733
+ "rounded-og-lg bg-og-surface-1/85 text-sm font-medium text-og-accent backdrop-blur-[1px]"
5647
5734
  ),
5735
+ children: /* @__PURE__ */ jsxs10("span", { className: "inline-flex items-center gap-2", children: [
5736
+ /* @__PURE__ */ jsx12(PaperclipIcon, { className: "size-4" }),
5737
+ "Drop files to attach"
5738
+ ] })
5739
+ }
5740
+ ) : null,
5741
+ attachments && attachments.attachments.length > 0 ? /* @__PURE__ */ jsx12(
5742
+ AttachmentChips,
5743
+ {
5744
+ attachments: attachments.attachments,
5745
+ onRemove: attachments.remove,
5746
+ onRetry: attachments.retry
5747
+ }
5748
+ ) : null,
5749
+ header,
5750
+ /* @__PURE__ */ jsx12(
5751
+ "textarea",
5752
+ {
5753
+ ref: textareaRef,
5754
+ rows: 1,
5755
+ value: composer.value,
5756
+ onChange: (event) => composer.setValue(event.target.value),
5757
+ onKeyDown,
5758
+ onPaste: handlePaste,
5759
+ placeholder: placeholder ?? "Message the agent\u2026",
5760
+ disabled,
5761
+ autoFocus,
5762
+ "aria-label": "Message the agent",
5763
+ role: paletteEnabled && palette.open ? "combobox" : void 0,
5764
+ "aria-expanded": paletteEnabled ? palette.open : void 0,
5765
+ "aria-controls": paletteEnabled && palette.open ? listboxId : void 0,
5766
+ "aria-activedescendant": paletteEnabled && palette.open ? `${listboxId}-option-${palette.highlight}` : void 0,
5767
+ className: cn(
5768
+ // Font size steps up to 16px below `md` so iOS never zooms the
5769
+ // viewport on focus; desktop keeps the 15px og-md rhythm.
5770
+ "block w-full resize-none bg-transparent px-4 pt-3.5 pb-1 text-base leading-6 md:text-og-md",
5771
+ // The wrapper owns the whole-composer focus affordance (focus-within
5772
+ // border + soft glow). Suppress any self-scoped focus outline on the
5773
+ // textarea itself: `focus:outline-none` alone only sets outline-style
5774
+ // on `:focus`, which a host app's zero-specificity
5775
+ // `:where(...):focus-visible { outline: ... }` base rule re-applies as
5776
+ // the full shorthand. `focus-visible:outline-none` matches the same
5777
+ // state at class specificity and wins, so no second highlight (the
5778
+ // top-half rectangle bounded to the textarea box) ever paints.
5779
+ "text-og-fg placeholder:text-og-fg-subtle focus:outline-none focus-visible:outline-none",
5780
+ "disabled:cursor-not-allowed disabled:opacity-60"
5781
+ )
5782
+ }
5783
+ ),
5784
+ confirmState && pendingDangerCommand ? /* @__PURE__ */ jsx12(
5785
+ ConfirmBar,
5786
+ {
5787
+ command: pendingDangerCommand,
5788
+ onCancel: () => confirmState.resolve(false),
5789
+ onConfirm: () => confirmState.resolve(true),
5790
+ returnFocusRef: textareaRef
5791
+ }
5792
+ ) : /* @__PURE__ */ jsxs10("div", { className: "flex items-end gap-2 px-2.5 pb-2.5 pt-1", children: [
5793
+ attachments || models || controlsStart ? (
5794
+ // The control group wraps onto extra rows when it can't fit
5795
+ // (narrow viewports) instead of clipping under the rounded
5796
+ // corner; send/stop stays anchored bottom-right (shrink-0).
5797
+ /* @__PURE__ */ jsxs10("span", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-1.5", children: [
5798
+ attachments ? /* @__PURE__ */ jsxs10(Fragment3, { children: [
5799
+ /* @__PURE__ */ jsx12(
5800
+ "input",
5801
+ {
5802
+ ref: fileInputRef,
5803
+ type: "file",
5804
+ multiple: true,
5805
+ className: "hidden",
5806
+ onChange: handleFileChange
5807
+ }
5808
+ ),
5809
+ /* @__PURE__ */ jsx12(
5810
+ "button",
5811
+ {
5812
+ type: "button",
5813
+ disabled: disabled === true,
5814
+ onClick: () => fileInputRef.current?.click(),
5815
+ "aria-label": "Attach files",
5816
+ title: "Attach files",
5817
+ className: cn(
5818
+ "inline-flex size-8 items-center justify-center rounded-og-md",
5819
+ "text-og-fg-muted transition-colors duration-150 hover:bg-og-surface-2 hover:text-og-fg",
5820
+ "disabled:cursor-not-allowed disabled:opacity-50"
5821
+ ),
5822
+ children: /* @__PURE__ */ jsx12(PaperclipIcon, { className: "size-4" })
5823
+ }
5824
+ )
5825
+ ] }) : null,
5826
+ models ? /* @__PURE__ */ jsx12(
5827
+ ModelPicker,
5828
+ {
5829
+ models,
5830
+ value: selectedModel,
5831
+ onChange: (modelId) => onSelectModel?.(modelId),
5832
+ disabled: disabled === true
5833
+ }
5834
+ ) : null,
5835
+ controlsStart
5836
+ ] })
5837
+ ) : /* @__PURE__ */ jsx12("span", { className: "min-w-0 flex-1 px-1.5 text-og-xs text-og-fg-subtle max-sm:hidden", children: hint ?? "Enter to send \xB7 Shift+Enter for a new line \xB7 / for commands" }),
5838
+ /* @__PURE__ */ jsxs10("span", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: [
5839
+ /* @__PURE__ */ jsx12(AnimatePresence3, { initial: false, children: active ? /* @__PURE__ */ jsx12(
5840
+ motion3.button,
5841
+ {
5842
+ type: "button",
5843
+ initial: { opacity: 0, scale: 0.8 },
5844
+ animate: { opacity: 1, scale: 1 },
5845
+ exit: { opacity: 0, scale: 0.8 },
5846
+ transition: { duration: 0.15, ease: "easeOut" },
5847
+ onClick: () => void composer.interrupt(),
5848
+ disabled: composer.interrupting,
5849
+ "aria-label": "Stop the current turn",
5850
+ title: "Stop the current turn",
5851
+ className: cn(
5852
+ "inline-flex size-8 items-center justify-center rounded-og-md border border-og-border pointer-coarse:size-11",
5853
+ "bg-og-surface-2 text-og-fg-muted transition-colors duration-150",
5854
+ "hover:border-og-status-failed/50 hover:text-og-status-failed",
5855
+ "disabled:opacity-50"
5856
+ ),
5857
+ children: composer.interrupting ? /* @__PURE__ */ jsx12(LoaderCircleIcon, { className: "size-3.5 animate-og-spin" }) : /* @__PURE__ */ jsx12(SquareIcon, { className: "size-3 fill-current" })
5858
+ },
5859
+ "stop"
5860
+ ) : null }),
5648
5861
  /* @__PURE__ */ jsx12(
5649
5862
  "button",
5650
5863
  {
5651
5864
  type: "button",
5652
- disabled: disabled === true,
5653
- onClick: () => fileInputRef.current?.click(),
5654
- "aria-label": "Attach files",
5655
- title: "Attach files",
5865
+ onClick: () => {
5866
+ if (blockedByUpload) {
5867
+ return;
5868
+ }
5869
+ void composer.send();
5870
+ },
5871
+ disabled: !canSend || disabled === true || commandDraftBlocked,
5872
+ "aria-label": "Send message",
5656
5873
  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"
5874
+ "inline-flex size-8 items-center justify-center rounded-og-md pointer-coarse:size-11",
5875
+ "bg-og-accent text-og-accent-fg shadow-og-sm",
5876
+ "transition-[background-color,transform,opacity] duration-150 ease-og-spring",
5877
+ "hover:bg-og-accent-strong active:scale-95",
5878
+ "disabled:cursor-not-allowed disabled:bg-og-surface-3 disabled:text-og-fg-subtle disabled:shadow-none"
5660
5879
  ),
5661
- children: /* @__PURE__ */ jsx12(PaperclipIcon, { className: "size-4" })
5880
+ children: composer.sending ? /* @__PURE__ */ jsx12(LoaderCircleIcon, { className: "size-4 animate-og-spin" }) : /* @__PURE__ */ jsx12(ArrowUpIcon, { className: "size-4" })
5662
5881
  }
5663
5882
  )
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
- )
5883
+ ] })
5721
5884
  ] })
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);
5885
+ ]
5742
5886
  }
5743
- },
5744
- children: activeNotice.message
5745
- }
5746
- ) : null })
5747
- ] });
5887
+ )
5888
+ ] }),
5889
+ /* @__PURE__ */ jsx12(AnimatePresence3, { children: helpOpen ? /* @__PURE__ */ jsx12(HelpPanel, { commands: helpCommands, onClose: () => setHelpOpen(false) }) : null }),
5890
+ /* @__PURE__ */ jsx12(AnimatePresence3, { children: activeNotice ? /* @__PURE__ */ jsx12(
5891
+ motion3.p,
5892
+ {
5893
+ initial: { opacity: 0, height: 0 },
5894
+ animate: { opacity: 1, height: "auto" },
5895
+ exit: { opacity: 0, height: 0 },
5896
+ className: cn(
5897
+ "overflow-hidden px-1 pt-1.5 text-xs",
5898
+ activeNotice.tone === "ok" ? "text-og-fg-muted" : "text-og-status-failed"
5899
+ ),
5900
+ role: activeNotice.tone === "error" ? "alert" : "status",
5901
+ onAnimationComplete: () => {
5902
+ if (activeNotice.tone === "ok") {
5903
+ window.setTimeout(() => setNotice((current) => current === activeNotice ? null : current), 2400);
5904
+ }
5905
+ },
5906
+ children: activeNotice.message
5907
+ }
5908
+ ) : null })
5909
+ ] })
5910
+ );
5748
5911
  }
5749
- function ConfirmBar({ command, onCancel, onConfirm }) {
5912
+ function ConfirmBar({
5913
+ command,
5914
+ onCancel,
5915
+ onConfirm,
5916
+ returnFocusRef
5917
+ }) {
5918
+ const confirmRef = useRef14(null);
5919
+ const descriptionId = useId2();
5920
+ useEffect14(() => {
5921
+ const returnTo = returnFocusRef?.current ?? null;
5922
+ confirmRef.current?.focus();
5923
+ return () => {
5924
+ returnTo?.focus();
5925
+ };
5926
+ }, [returnFocusRef]);
5750
5927
  return /* @__PURE__ */ jsxs10(
5751
5928
  "div",
5752
5929
  {
5753
5930
  role: "alertdialog",
5754
5931
  "aria-label": `Confirm /${command.name}`,
5932
+ "aria-describedby": descriptionId,
5755
5933
  "data-testid": "danger-confirm",
5756
- className: "flex items-center justify-between gap-2 px-2.5 pb-2.5 pt-1",
5934
+ onKeyDown: (event) => {
5935
+ if (event.key === "Escape") {
5936
+ event.preventDefault();
5937
+ event.stopPropagation();
5938
+ onCancel();
5939
+ }
5940
+ },
5941
+ className: "flex items-end justify-between gap-2 px-2.5 pb-2.5 pt-1",
5757
5942
  children: [
5758
- /* @__PURE__ */ jsxs10("span", { className: "px-1.5 text-[12px] text-og-status-failed", children: [
5943
+ /* @__PURE__ */ jsxs10("span", { id: descriptionId, className: "min-w-0 flex-1 px-1.5 text-og-sm text-og-status-failed", children: [
5759
5944
  "Run ",
5760
5945
  /* @__PURE__ */ jsxs10("span", { className: "font-mono", children: [
5761
5946
  "/",
@@ -5764,24 +5949,27 @@ function ConfirmBar({ command, onCancel, onConfirm }) {
5764
5949
  "? ",
5765
5950
  command.description
5766
5951
  ] }),
5767
- /* @__PURE__ */ jsxs10("span", { className: "flex items-center gap-1.5", children: [
5952
+ /* @__PURE__ */ jsxs10("span", { className: "flex shrink-0 items-center gap-1.5", children: [
5768
5953
  /* @__PURE__ */ jsx12(
5769
5954
  "button",
5770
5955
  {
5771
5956
  type: "button",
5772
5957
  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",
5958
+ className: "rounded-og-md border border-og-border bg-og-surface-2 px-2.5 py-1 text-og-sm text-og-fg-muted hover:bg-og-surface-3 pointer-coarse:min-h-10",
5774
5959
  children: "Cancel"
5775
5960
  }
5776
5961
  ),
5777
- /* @__PURE__ */ jsx12(
5962
+ /* @__PURE__ */ jsxs10(
5778
5963
  "button",
5779
5964
  {
5965
+ ref: confirmRef,
5780
5966
  type: "button",
5781
- autoFocus: true,
5782
5967
  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"
5968
+ className: "rounded-og-md border border-og-status-failed/50 bg-og-status-failed/15 px-2.5 py-1 text-og-sm text-og-status-failed hover:bg-og-status-failed/25 pointer-coarse:min-h-10",
5969
+ children: [
5970
+ "Run /",
5971
+ command.name
5972
+ ]
5785
5973
  }
5786
5974
  )
5787
5975
  ] })
@@ -5789,44 +5977,57 @@ function ConfirmBar({ command, onCancel, onConfirm }) {
5789
5977
  }
5790
5978
  );
5791
5979
  }
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 }),
5980
+ function AttachmentChips({ attachments, onRemove, onRetry }) {
5981
+ return /* @__PURE__ */ jsx12("div", { className: "flex flex-wrap gap-2 border-b border-og-border px-3 py-2", children: attachments.map((attachment) => {
5982
+ const failed = attachment.status === "failed";
5983
+ const statusText = attachment.status === "uploading" ? "Uploading" : failed ? attachment.error || "Upload failed" : formatBytes(attachment.sizeBytes);
5984
+ return /* @__PURE__ */ jsxs10(
5985
+ "div",
5986
+ {
5987
+ className: cn(
5988
+ "flex min-w-0 max-w-[240px] items-center gap-2 rounded-og-md border px-2 py-1.5 text-og-sm",
5989
+ failed ? "border-og-status-failed/40 bg-og-status-failed/10" : "border-og-border bg-og-surface-2"
5990
+ ),
5991
+ children: [
5992
+ attachment.previewUrl ? /* @__PURE__ */ jsx12("img", { src: attachment.previewUrl, alt: "", className: "size-8 shrink-0 rounded object-cover" }) : attachment.contentType.startsWith("image/") ? /* @__PURE__ */ jsx12(ImageIcon2, { className: "size-4 shrink-0 text-og-fg-muted" }) : /* @__PURE__ */ jsx12(FileIcon, { className: "size-4 shrink-0 text-og-fg-muted" }),
5993
+ /* @__PURE__ */ jsxs10("div", { className: "min-w-0 flex-1", children: [
5994
+ /* @__PURE__ */ jsx12("div", { className: "truncate font-medium text-og-fg", children: attachment.name }),
5995
+ /* @__PURE__ */ jsx12(
5996
+ "div",
5997
+ {
5998
+ className: cn("truncate text-og-xs", failed ? "text-og-status-failed" : "text-og-fg-subtle"),
5999
+ title: failed ? statusText : void 0,
6000
+ children: statusText
6001
+ }
6002
+ )
6003
+ ] }),
6004
+ attachment.status === "uploading" ? /* @__PURE__ */ jsx12(LoaderCircleIcon, { className: "size-3.5 shrink-0 animate-og-spin" }) : null,
6005
+ failed && onRetry ? /* @__PURE__ */ jsx12(
6006
+ "button",
6007
+ {
6008
+ type: "button",
6009
+ onClick: () => onRetry(attachment.id),
6010
+ className: "shrink-0 rounded-og-xs p-1 text-og-fg-muted hover:bg-og-surface-1 hover:text-og-fg pointer-coarse:size-8",
6011
+ "aria-label": `Retry ${attachment.name}`,
6012
+ title: "Retry upload",
6013
+ children: /* @__PURE__ */ jsx12(RotateCwIcon, { className: "size-3.5" })
6014
+ }
6015
+ ) : null,
5804
6016
  /* @__PURE__ */ jsx12(
5805
- "div",
6017
+ "button",
5806
6018
  {
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)
6019
+ type: "button",
6020
+ onClick: () => onRemove(attachment.id),
6021
+ className: "shrink-0 rounded-og-xs p-1 text-og-fg-muted hover:bg-og-surface-1 hover:text-og-fg pointer-coarse:size-8",
6022
+ "aria-label": `Remove ${attachment.name}`,
6023
+ children: /* @__PURE__ */ jsx12(XIcon2, { className: "size-3.5" })
5812
6024
  }
5813
6025
  )
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
- )) });
6026
+ ]
6027
+ },
6028
+ attachment.id
6029
+ );
6030
+ }) });
5830
6031
  }
5831
6032
  function HelpPanel({ commands, onClose }) {
5832
6033
  return /* @__PURE__ */ jsxs10(
@@ -5838,19 +6039,19 @@ function HelpPanel({ commands, onClose }) {
5838
6039
  className: "mt-2 overflow-hidden rounded-og-lg border border-og-border bg-og-surface-2",
5839
6040
  children: [
5840
6041
  /* @__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" })
6042
+ /* @__PURE__ */ jsx12("span", { className: "text-og-sm font-medium text-og-fg", children: "Commands" }),
6043
+ /* @__PURE__ */ jsx12("button", { type: "button", onClick: onClose, className: "text-og-xs text-og-fg-subtle hover:text-og-fg", children: "Close" })
5843
6044
  ] }),
5844
6045
  /* @__PURE__ */ jsx12("ul", { className: "py-1", children: commands.map((command) => {
5845
6046
  const hint = argHint(command.args);
5846
6047
  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: [
6048
+ /* @__PURE__ */ jsxs10("span", { className: "font-mono text-og-sm text-og-accent", children: [
5848
6049
  "/",
5849
6050
  command.name,
5850
6051
  hint ? /* @__PURE__ */ jsx12("span", { className: "ml-1 text-og-fg-subtle", children: hint }) : null
5851
6052
  ] }),
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
6053
+ /* @__PURE__ */ jsx12("span", { className: "text-og-sm text-og-fg-muted", children: command.description }),
6054
+ command.danger ? /* @__PURE__ */ jsx12("span", { className: "ml-auto rounded-og-xs bg-og-status-failed/15 px-1 text-og-xs uppercase tracking-wide text-og-status-failed", children: "danger" }) : null
5854
6055
  ] }, command.name);
5855
6056
  }) })
5856
6057
  ]
@@ -5870,7 +6071,7 @@ import {
5870
6071
  TriangleAlertIcon as TriangleAlertIcon2
5871
6072
  } from "lucide-react";
5872
6073
  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";
6074
+ import { useCallback as useCallback21, useEffect as useEffect15, useMemo as useMemo8, useRef as useRef15, useState as useState22 } from "react";
5874
6075
 
5875
6076
  // src/components/markdown.tsx
5876
6077
  import { memo } from "react";
@@ -5880,8 +6081,8 @@ import { jsx as jsx13 } from "react/jsx-runtime";
5880
6081
  var components = {
5881
6082
  h1: ({ children, ...props }) => /* @__PURE__ */ jsx13("h1", { className: "mt-5 mb-2.5 text-xl font-semibold tracking-tight text-og-fg first:mt-0", ...props, children }),
5882
6083
  h2: ({ children, ...props }) => /* @__PURE__ */ jsx13("h2", { className: "mt-5 mb-2 text-lg font-semibold tracking-tight text-og-fg first:mt-0", ...props, children }),
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 }),
6084
+ h3: ({ children, ...props }) => /* @__PURE__ */ jsx13("h3", { className: "mt-4 mb-1.5 text-og-md font-semibold tracking-tight text-og-fg first:mt-0", ...props, children }),
6085
+ h4: ({ children, ...props }) => /* @__PURE__ */ jsx13("h4", { className: "mt-4 mb-1.5 text-og-sm font-semibold uppercase tracking-[0.04em] text-og-fg-muted first:mt-0", ...props, children }),
5885
6086
  p: ({ children, ...props }) => /* @__PURE__ */ jsx13("p", { className: "my-2.5 leading-7 first:mt-0 last:mb-0", ...props, children }),
5886
6087
  strong: ({ children, ...props }) => /* @__PURE__ */ jsx13("strong", { className: "font-semibold text-og-fg", ...props, children }),
5887
6088
  em: ({ children, ...props }) => /* @__PURE__ */ jsx13("em", { className: "italic", ...props, children }),
@@ -5907,7 +6108,7 @@ var components = {
5907
6108
  ...props,
5908
6109
  type: "checkbox",
5909
6110
  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"
6111
+ className: "mr-2 size-3.5 translate-y-[2px] cursor-default accent-og-accent align-baseline"
5911
6112
  }
5912
6113
  ) : /* @__PURE__ */ jsx13("input", { type, ...props }),
5913
6114
  blockquote: ({ children, ...props }) => /* @__PURE__ */ jsx13(
@@ -5925,7 +6126,7 @@ var components = {
5925
6126
  code: ({ children, className: _className, ...props }) => /* @__PURE__ */ jsx13(
5926
6127
  "code",
5927
6128
  {
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",
6129
+ className: "rounded-og-xs border border-og-border bg-og-surface-1 px-1 py-0.5 font-og-mono text-og-sm text-og-fg",
5929
6130
  ...props,
5930
6131
  children
5931
6132
  }
@@ -5935,12 +6136,12 @@ var components = {
5935
6136
  pre: ({ children, ...props }) => /* @__PURE__ */ jsx13(
5936
6137
  "pre",
5937
6138
  {
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",
6139
+ className: "my-3 max-h-96 overflow-auto rounded-og-md border border-og-border bg-og-bg/60 p-3 font-og-mono text-og-sm text-og-fg-muted [&>code]:border-0 [&>code]:bg-transparent [&>code]:p-0 [&>code]:text-inherit first:mt-0 last:mb-0",
5939
6140
  ...props,
5940
6141
  children
5941
6142
  }
5942
6143
  ),
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 }) }),
6144
+ table: ({ children, ...props }) => /* @__PURE__ */ jsx13("div", { className: "my-3 max-w-full overflow-x-auto rounded-og-md border border-og-border first:mt-0 last:mb-0", children: /* @__PURE__ */ jsx13("table", { className: "w-full border-collapse text-og-base", ...props, children }) }),
5944
6145
  thead: ({ children, ...props }) => /* @__PURE__ */ jsx13("thead", { className: "bg-og-surface-1", ...props, children }),
5945
6146
  th: ({ children, ...props }) => /* @__PURE__ */ jsx13("th", { className: "border-b border-og-border px-3 py-1.5 text-left font-medium text-og-fg", ...props, children }),
5946
6147
  td: ({ children, ...props }) => /* @__PURE__ */ jsx13("td", { className: "border-b border-og-border px-3 py-1.5 align-top text-og-fg-muted [tr:last-child>&]:border-b-0", ...props, children }),
@@ -5977,7 +6178,7 @@ var SESSION_STATUS_META = {
5977
6178
  pulse: false
5978
6179
  },
5979
6180
  requires_action: {
5980
- label: "Needs you",
6181
+ label: "Waiting on you",
5981
6182
  dotClassName: "bg-og-status-waiting",
5982
6183
  badgeClassName: "text-og-status-waiting border-og-status-waiting/35 bg-og-status-waiting/10",
5983
6184
  pulse: true
@@ -6003,7 +6204,7 @@ function SessionStatus({ status, label, size = "md", className }) {
6003
6204
  "data-status": status,
6004
6205
  className: cn(
6005
6206
  "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",
6207
+ size === "sm" ? "gap-1 px-1.5 py-px text-og-xs" : "gap-1.5 px-2 py-0.5 text-xs",
6007
6208
  meta.badgeClassName,
6008
6209
  className
6009
6210
  ),
@@ -6034,23 +6235,74 @@ function MessageTimeline({
6034
6235
  }) {
6035
6236
  const resolvedItems = useMemo8(() => items ?? buildTimeline(events ?? []), [items, events]);
6036
6237
  const groups = useMemo8(() => groupTimeline(resolvedItems), [resolvedItems]);
6037
- const scrollRef = useRef14(null);
6238
+ const scrollRef = useRef15(null);
6038
6239
  const [pinned, setPinned] = useState22(true);
6240
+ const pinnedRef = useRef15(true);
6241
+ const anchorRef = useRef15(null);
6039
6242
  const lastItem = resolvedItems[resolvedItems.length - 1];
6040
6243
  const streaming = lastItem !== void 0 && (lastItem.kind === "agent-message" || lastItem.kind === "reasoning") && lastItem.streaming;
6041
6244
  const working = status === "running" && !streaming;
6245
+ const captureAnchor = useCallback21(() => {
6246
+ const node = scrollRef.current;
6247
+ const inner = node?.firstElementChild;
6248
+ if (!node || !inner) {
6249
+ anchorRef.current = null;
6250
+ return;
6251
+ }
6252
+ const containerTop = node.getBoundingClientRect().top;
6253
+ for (const child of Array.from(inner.children)) {
6254
+ const rect = child.getBoundingClientRect();
6255
+ if (rect.bottom > containerTop + 1) {
6256
+ anchorRef.current = { el: child, top: rect.top - containerTop };
6257
+ return;
6258
+ }
6259
+ }
6260
+ anchorRef.current = null;
6261
+ }, []);
6042
6262
  useEffect15(() => {
6043
6263
  const node = scrollRef.current;
6044
6264
  if (node && autoFollow && pinned) {
6045
6265
  node.scrollTop = node.scrollHeight;
6046
6266
  }
6047
6267
  }, [resolvedItems, working, autoFollow, pinned]);
6268
+ useEffect15(() => {
6269
+ const node = scrollRef.current;
6270
+ const inner = node?.firstElementChild;
6271
+ if (!node || !inner || typeof ResizeObserver === "undefined") {
6272
+ return;
6273
+ }
6274
+ const observer = new ResizeObserver(() => {
6275
+ const current = scrollRef.current;
6276
+ if (!current) {
6277
+ return;
6278
+ }
6279
+ if (autoFollow && pinnedRef.current) {
6280
+ current.scrollTop = current.scrollHeight;
6281
+ } else {
6282
+ const anchor = anchorRef.current;
6283
+ if (anchor && anchor.el.isConnected) {
6284
+ const containerTop = current.getBoundingClientRect().top;
6285
+ const now = anchor.el.getBoundingClientRect().top - containerTop;
6286
+ const diff = now - anchor.top;
6287
+ if (diff !== 0) {
6288
+ current.scrollTop += diff;
6289
+ }
6290
+ }
6291
+ }
6292
+ captureAnchor();
6293
+ });
6294
+ observer.observe(inner);
6295
+ return () => observer.disconnect();
6296
+ }, [autoFollow, captureAnchor]);
6048
6297
  const onScroll = () => {
6049
6298
  const node = scrollRef.current;
6050
6299
  if (!node) {
6051
6300
  return;
6052
6301
  }
6053
- setPinned(node.scrollHeight - node.scrollTop - node.clientHeight < 48);
6302
+ const nextPinned = node.scrollHeight - node.scrollTop - node.clientHeight < 48;
6303
+ pinnedRef.current = nextPinned;
6304
+ setPinned(nextPinned);
6305
+ captureAnchor();
6054
6306
  };
6055
6307
  return /* @__PURE__ */ jsx15(LightboxProvider, { children: /* @__PURE__ */ jsxs12("div", { className: cn("og-root relative flex min-h-0 flex-col", className), children: [
6056
6308
  /* @__PURE__ */ jsx15("div", { ref: scrollRef, onScroll, className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-6 sm:px-6", children: /* @__PURE__ */ jsxs12("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: [
@@ -6080,6 +6332,7 @@ function MessageTimeline({
6080
6332
  if (node) {
6081
6333
  node.scrollTo({ top: node.scrollHeight, behavior: "smooth" });
6082
6334
  }
6335
+ pinnedRef.current = true;
6083
6336
  setPinned(true);
6084
6337
  },
6085
6338
  className: cn(
@@ -6302,11 +6555,11 @@ function FleetTile({ session, title, subtitle, onOpen, className }) {
6302
6555
  }
6303
6556
  ),
6304
6557
  /* @__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) }),
6558
+ /* @__PURE__ */ jsx16("span", { className: "line-clamp-2 min-w-0 text-og-base font-medium leading-snug text-og-fg", children: title ?? sessionDisplayTitle(session) }),
6306
6559
  /* @__PURE__ */ jsx16(SessionStatus, { status: session.status, size: "sm", className: "mt-px" })
6307
6560
  ] }),
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: [
6561
+ subtitle ? /* @__PURE__ */ jsx16("span", { className: "line-clamp-1 text-og-sm text-og-fg-muted", children: subtitle }) : null,
6562
+ /* @__PURE__ */ jsxs13("span", { className: "mt-auto flex w-full items-center gap-2 text-og-xs text-og-fg-subtle", children: [
6310
6563
  /* @__PURE__ */ jsx16("span", { className: "font-og-mono", children: session.id.slice(0, 8) }),
6311
6564
  /* @__PURE__ */ jsx16("span", { "aria-hidden": true, children: "\xB7" }),
6312
6565
  /* @__PURE__ */ jsx16("span", { className: "truncate", children: session.model }),
@@ -6318,7 +6571,7 @@ function FleetTile({ session, title, subtitle, onOpen, className }) {
6318
6571
  }
6319
6572
 
6320
6573
  // src/components/sandbox-terminal.tsx
6321
- import { useEffect as useEffect16, useRef as useRef15, useState as useState23 } from "react";
6574
+ import { useEffect as useEffect16, useRef as useRef16, useState as useState23 } from "react";
6322
6575
  import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
6323
6576
  function SandboxTerminal({
6324
6577
  result,
@@ -6333,13 +6586,13 @@ function SandboxTerminal({
6333
6586
  onActivate,
6334
6587
  className
6335
6588
  }) {
6336
- const containerRef = useRef15(null);
6337
- const termRef = useRef15(null);
6338
- const fitRef = useRef15(null);
6339
- const writtenRef = useRef15(/* @__PURE__ */ new Set());
6589
+ const containerRef = useRef16(null);
6590
+ const termRef = useRef16(null);
6591
+ const fitRef = useRef16(null);
6592
+ const writtenRef = useRef16(/* @__PURE__ */ new Set());
6340
6593
  const [ready, setReady] = useState23(false);
6341
6594
  const ptyWs = terminalCapability?.transport === "pty-ws" && Boolean(terminalCapability?.url);
6342
- const ptyOutputQueueRef = useRef15([]);
6595
+ const ptyOutputQueueRef = useRef16([]);
6343
6596
  const ptyStream = useTerminalStream({
6344
6597
  capability: ptyWs ? {
6345
6598
  transport: terminalCapability.transport,
@@ -6387,7 +6640,7 @@ function SandboxTerminal({
6387
6640
  convertEol: true,
6388
6641
  disableStdin: !interactive,
6389
6642
  cursorBlink: interactive,
6390
- fontFamily: fontFamily ?? "var(--og-font-mono, var(--font-mono, monospace))",
6643
+ fontFamily: fontFamily ?? "var(--og-font-mono)",
6391
6644
  fontSize: fontSize ?? 13,
6392
6645
  lineHeight: 1.25,
6393
6646
  // A little breathing room from the panel edge so output isn't flush to
@@ -6434,7 +6687,7 @@ function SandboxTerminal({
6434
6687
  if (!ready || !term || !theme) return;
6435
6688
  term.options.theme = theme;
6436
6689
  }, [ready, theme]);
6437
- const enteredPtyRef = useRef15(false);
6690
+ const enteredPtyRef = useRef16(false);
6438
6691
  useEffect16(() => {
6439
6692
  const term = termRef.current;
6440
6693
  if (!ready || !term) return;
@@ -6490,24 +6743,24 @@ function SandboxTerminal({
6490
6743
  };
6491
6744
  }, [ready]);
6492
6745
  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: [
6746
+ showHeader && /* @__PURE__ */ jsxs14("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-og-border px-2 py-1 text-og-xs text-og-fg-subtle", children: [
6494
6747
  /* @__PURE__ */ jsxs14("span", { className: "flex min-w-0 items-center gap-1.5", children: [
6495
6748
  /* @__PURE__ */ jsx17(
6496
6749
  "span",
6497
6750
  {
6498
6751
  className: cn(
6499
6752
  "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))]"
6753
+ result.running ? "bg-og-status-running" : "bg-og-fg-subtle"
6501
6754
  )
6502
6755
  }
6503
6756
  ),
6504
- /* @__PURE__ */ jsxs14("span", { className: "truncate font-[family-name:var(--og-font-mono,var(--font-mono,monospace))]", children: [
6757
+ /* @__PURE__ */ jsxs14("span", { className: "truncate font-og-mono", children: [
6505
6758
  "pty: ",
6506
6759
  shell ?? "shell"
6507
6760
  ] })
6508
6761
  ] }),
6509
6762
  /* @__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" }),
6763
+ !interactive && /* @__PURE__ */ jsx17("span", { className: "rounded-og-sm bg-og-surface-2 px-1.5 py-0.5 text-og-xs uppercase tracking-wide", children: "read-only" }),
6511
6764
  /* @__PURE__ */ jsx17(
6512
6765
  "button",
6513
6766
  {
@@ -6516,7 +6769,7 @@ function SandboxTerminal({
6516
6769
  termRef.current?.clear();
6517
6770
  writtenRef.current = /* @__PURE__ */ new Set();
6518
6771
  },
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))]",
6772
+ className: "rounded-og-sm px-1.5 py-0.5 text-og-xs hover:text-og-fg pointer-coarse:min-h-10",
6520
6773
  children: "Clear"
6521
6774
  }
6522
6775
  )
@@ -6525,7 +6778,7 @@ function SandboxTerminal({
6525
6778
  /* @__PURE__ */ jsxs14(
6526
6779
  "div",
6527
6780
  {
6528
- className: "relative min-h-0 flex-1 bg-[color:var(--og-color-bg,var(--color-bg,#0d0d0d))] px-2 py-1.5",
6781
+ className: "relative min-h-0 flex-1 bg-og-bg px-2 py-1.5",
6529
6782
  onPointerDownCapture: onActivate,
6530
6783
  onFocusCapture: onActivate,
6531
6784
  children: [
@@ -6542,7 +6795,7 @@ var XTERM_BASE_CSS = `
6542
6795
  .xterm.focus,.xterm:focus{outline:none}
6543
6796
  .xterm .xterm-helpers{position:absolute;top:0;z-index:5}
6544
6797
  .xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}
6545
- .xterm .composition-view{background:#000;color:#FFF;display:none;position:absolute;white-space:nowrap;z-index:1}
6798
+ .xterm .composition-view{background:var(--og-color-bg);color:var(--og-color-fg);display:none;position:absolute;white-space:nowrap;z-index:1}
6546
6799
  .xterm .composition-view.active{display:block}
6547
6800
  .xterm .xterm-viewport{background-color:transparent;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}
6548
6801
  .xterm .xterm-screen{position:relative}
@@ -6578,7 +6831,7 @@ function ensureXtermBaseCss() {
6578
6831
  document.head.appendChild(style);
6579
6832
  }
6580
6833
  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" });
6834
+ return /* @__PURE__ */ jsx17("div", { className: "absolute inset-0 flex items-center justify-center text-og-sm text-og-fg-subtle", children: "Loading terminal\u2026" });
6582
6835
  }
6583
6836
 
6584
6837
  // src/components/file-browser.tsx
@@ -6594,19 +6847,19 @@ import {
6594
6847
  Trash2Icon
6595
6848
  } from "lucide-react";
6596
6849
  import {
6597
- useCallback as useCallback21,
6850
+ useCallback as useCallback22,
6598
6851
  useEffect as useEffect17,
6599
6852
  useMemo as useMemo9,
6600
- useRef as useRef16,
6853
+ useRef as useRef17,
6601
6854
  useState as useState24
6602
6855
  } from "react";
6603
6856
  import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
6604
6857
  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))]"
6858
+ added: "text-og-status-idle",
6859
+ modified: "text-og-status-running",
6860
+ deleted: "text-og-status-failed line-through",
6861
+ renamed: "text-og-accent",
6862
+ untracked: "text-og-fg-subtle"
6610
6863
  };
6611
6864
  function parentOf2(path) {
6612
6865
  const i = path.lastIndexOf("/");
@@ -6644,9 +6897,9 @@ function FileBrowser({
6644
6897
  const [dragOver, setDragOver] = useState24(null);
6645
6898
  const [menu, setMenu] = useState24(null);
6646
6899
  const [busy, setBusy] = useState24(false);
6647
- const containerRef = useRef16(null);
6900
+ const containerRef = useRef17(null);
6648
6901
  const cursor = active ?? selectedPath ?? null;
6649
- const expand = useCallback21(
6902
+ const expand = useCallback22(
6650
6903
  async (path) => {
6651
6904
  const node = findNode(result.tree, path);
6652
6905
  if (node && node.kind === "dir" && node.children === void 0) {
@@ -6664,14 +6917,14 @@ function FileBrowser({
6664
6917
  },
6665
6918
  [result]
6666
6919
  );
6667
- const open = useCallback21(
6920
+ const open = useCallback22(
6668
6921
  (path) => {
6669
6922
  setExpanded((prev) => new Set(prev).add(path));
6670
6923
  void expand(path);
6671
6924
  },
6672
6925
  [expand]
6673
6926
  );
6674
- const toggle = useCallback21(
6927
+ const toggle = useCallback22(
6675
6928
  async (node) => {
6676
6929
  if (node.kind !== "dir") return;
6677
6930
  const isOpen = expanded.has(node.path);
@@ -6699,7 +6952,7 @@ function FileBrowser({
6699
6952
  return rows;
6700
6953
  }, [result.tree, expanded]);
6701
6954
  const supportsMutation = editable;
6702
- const runDelete = useCallback21(
6955
+ const runDelete = useCallback22(
6703
6956
  async (node) => {
6704
6957
  if (!supportsMutation) return;
6705
6958
  const recursive = node.kind === "dir";
@@ -6718,7 +6971,7 @@ function FileBrowser({
6718
6971
  },
6719
6972
  [supportsMutation, confirmDelete, result]
6720
6973
  );
6721
- const commitCreate = useCallback21(
6974
+ const commitCreate = useCallback22(
6722
6975
  async (name) => {
6723
6976
  const draft = draftCreate;
6724
6977
  setDraftCreate(null);
@@ -6743,7 +6996,7 @@ function FileBrowser({
6743
6996
  },
6744
6997
  [draftCreate, supportsMutation, result, open, onSelectFile]
6745
6998
  );
6746
- const commitRename = useCallback21(
6999
+ const commitRename = useCallback22(
6747
7000
  async (name) => {
6748
7001
  const draft = draftRename;
6749
7002
  setDraftRename(null);
@@ -6766,7 +7019,7 @@ function FileBrowser({
6766
7019
  },
6767
7020
  [draftRename, supportsMutation, result, selectedPath, active, onSelectFile]
6768
7021
  );
6769
- const startCreate = useCallback21(
7022
+ const startCreate = useCallback22(
6770
7023
  (kind) => {
6771
7024
  if (!supportsMutation) return;
6772
7025
  const anchor = cursor ? findNode(result.tree, cursor) : void 0;
@@ -6778,7 +7031,7 @@ function FileBrowser({
6778
7031
  },
6779
7032
  [supportsMutation, cursor, result.tree, open]
6780
7033
  );
6781
- const startRename = useCallback21(
7034
+ const startRename = useCallback22(
6782
7035
  (node) => {
6783
7036
  if (!supportsMutation) return;
6784
7037
  setDraftCreate(null);
@@ -6787,7 +7040,7 @@ function FileBrowser({
6787
7040
  },
6788
7041
  [supportsMutation]
6789
7042
  );
6790
- const onDropOnto = useCallback21(
7043
+ const onDropOnto = useCallback22(
6791
7044
  async (targetDir, sourcePath) => {
6792
7045
  setDragOver(null);
6793
7046
  if (!supportsMutation || !sourcePath) return;
@@ -6811,7 +7064,7 @@ function FileBrowser({
6811
7064
  },
6812
7065
  [supportsMutation, result, selectedPath, active, onSelectFile]
6813
7066
  );
6814
- const onKeyDown = useCallback21(
7067
+ const onKeyDown = useCallback22(
6815
7068
  (e) => {
6816
7069
  if (draftCreate || draftRename) return;
6817
7070
  if (flatRows.length === 0) return;
@@ -6888,10 +7141,9 @@ function FileBrowser({
6888
7141
  window.removeEventListener("resize", close);
6889
7142
  };
6890
7143
  }, [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
- }
7144
+ const showErrorEmpty = result.error && result.tree.length === 0 && !draftCreate;
6894
7145
  const showEmpty = !result.loading && result.tree.length === 0 && !draftCreate;
7146
+ const showToolbar = supportsMutation || Boolean(result.error) || result.loading;
6895
7147
  const renderRow = (node, depth) => {
6896
7148
  const isOpen = expanded.has(node.path);
6897
7149
  if (renderNode) {
@@ -6959,11 +7211,11 @@ function FileBrowser({
6959
7211
  setMenu({ node, x: e.clientX, y: e.clientY });
6960
7212
  },
6961
7213
  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))]",
7214
+ "group flex w-full items-center gap-1 truncate rounded-og-sm px-1 py-0.5 text-left text-og-sm pointer-coarse:min-h-10",
7215
+ "hover:bg-og-surface-2",
7216
+ isSelected && "bg-og-surface-2",
7217
+ isCursor && "outline outline-1 -outline-offset-1 outline-og-accent",
7218
+ isDropTarget && "bg-og-accent-soft ring-1 ring-inset ring-og-accent",
6967
7219
  node.status ? STATUS_TINT[node.status] : void 0
6968
7220
  ),
6969
7221
  style: { paddingLeft: `${depth * 12 + 4}px` },
@@ -6971,7 +7223,7 @@ function FileBrowser({
6971
7223
  isDir ? isLoading ? /* @__PURE__ */ jsx18(
6972
7224
  Loader2Icon,
6973
7225
  {
6974
- className: "size-3 shrink-0 animate-spin text-[color:var(--og-color-fg-subtle,var(--color-fg-subtle,#888))]",
7226
+ className: "size-3 shrink-0 animate-spin text-og-fg-subtle",
6975
7227
  "aria-label": "Loading"
6976
7228
  }
6977
7229
  ) : /* @__PURE__ */ jsx18(ChevronRightIcon3, { className: cn("size-3 shrink-0 transition-transform", isOpen && "rotate-90") }) : /* @__PURE__ */ jsx18("span", { className: "inline-block w-3 shrink-0" }),
@@ -6990,7 +7242,7 @@ function FileBrowser({
6990
7242
  const rect = e.currentTarget.getBoundingClientRect();
6991
7243
  setMenu({ node, x: rect.right, y: rect.bottom });
6992
7244
  },
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",
7245
+ className: "ml-auto hidden shrink-0 px-1 text-og-fg-subtle hover:text-og-fg group-hover:inline",
6994
7246
  children: "\u22EF"
6995
7247
  }
6996
7248
  )
@@ -7017,7 +7269,7 @@ function FileBrowser({
7017
7269
  children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx18(
7018
7270
  "div",
7019
7271
  {
7020
- className: "h-2.5 animate-pulse rounded bg-[color:var(--og-color-surface-2,var(--color-bg-subtle,#1c1c1c))]",
7272
+ className: "h-2.5 animate-pulse rounded-og-sm bg-og-surface-2",
7021
7273
  style: { width: `${70 - i * 12}%` }
7022
7274
  },
7023
7275
  i
@@ -7031,33 +7283,35 @@ function FileBrowser({
7031
7283
  );
7032
7284
  };
7033
7285
  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
- ),
7286
+ showToolbar && /* @__PURE__ */ jsxs15("div", { className: "flex shrink-0 flex-wrap items-center gap-0.5 border-b border-og-border px-1 py-1", children: [
7287
+ supportsMutation ? /* @__PURE__ */ jsxs15(Fragment5, { children: [
7288
+ /* @__PURE__ */ jsx18(ToolbarButton, { label: "New file", onClick: () => startCreate("file"), disabled: busy, children: /* @__PURE__ */ jsx18(FilePlusIcon, { className: "size-3.5" }) }),
7289
+ /* @__PURE__ */ jsx18(ToolbarButton, { label: "New folder", onClick: () => startCreate("dir"), disabled: busy, children: /* @__PURE__ */ jsx18(FolderPlusIcon, { className: "size-3.5" }) }),
7290
+ /* @__PURE__ */ jsx18(
7291
+ ToolbarButton,
7292
+ {
7293
+ label: "Rename",
7294
+ onClick: () => {
7295
+ const node = cursor ? findNode(result.tree, cursor) : void 0;
7296
+ if (node) startRename(node);
7297
+ },
7298
+ disabled: busy || !cursor,
7299
+ children: /* @__PURE__ */ jsx18(PencilIcon, { className: "size-3.5" })
7300
+ }
7301
+ ),
7302
+ /* @__PURE__ */ jsx18(
7303
+ ToolbarButton,
7304
+ {
7305
+ label: "Delete",
7306
+ onClick: () => {
7307
+ const node = cursor ? findNode(result.tree, cursor) : void 0;
7308
+ if (node) void runDelete(node);
7309
+ },
7310
+ disabled: busy || !cursor,
7311
+ children: /* @__PURE__ */ jsx18(Trash2Icon, { className: "size-3.5" })
7312
+ }
7313
+ )
7314
+ ] }) : null,
7061
7315
  /* @__PURE__ */ jsx18("span", { className: "ml-auto" }),
7062
7316
  /* @__PURE__ */ jsx18(ToolbarButton, { label: "Refresh", onClick: () => void result.refresh(), disabled: busy || result.loading, children: /* @__PURE__ */ jsx18(RefreshCwIcon, { className: cn("size-3.5", result.loading && "animate-spin") }) })
7063
7317
  ] }),
@@ -7081,7 +7335,7 @@ function FileBrowser({
7081
7335
  } : void 0,
7082
7336
  className: cn(
7083
7337
  "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))]"
7338
+ dragOver === "" && "ring-1 ring-inset ring-og-accent"
7085
7339
  ),
7086
7340
  "data-opengeni-file-tree": true,
7087
7341
  children: [
@@ -7095,7 +7349,22 @@ function FileBrowser({
7095
7349
  onCancel: () => setDraftCreate(null)
7096
7350
  }
7097
7351
  ),
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))
7352
+ showErrorEmpty ? /* @__PURE__ */ jsxs15("div", { className: "flex flex-col items-start gap-2 p-2 text-og-sm text-og-fg-subtle", children: [
7353
+ /* @__PURE__ */ jsx18("div", { children: fallback ?? `Could not load files: ${result.error?.message ?? "refresh the file list to try again"}` }),
7354
+ /* @__PURE__ */ jsxs15(
7355
+ "button",
7356
+ {
7357
+ type: "button",
7358
+ onClick: () => void result.refresh(),
7359
+ disabled: result.loading,
7360
+ className: "inline-flex items-center gap-1.5 rounded-og-sm border border-og-border px-2 py-1 text-og-xs font-medium text-og-fg-muted transition-colors hover:border-og-border-strong hover:text-og-fg disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:min-h-10",
7361
+ children: [
7362
+ /* @__PURE__ */ jsx18(RefreshCwIcon, { className: cn("size-3.5", result.loading && "animate-spin"), "aria-hidden": true }),
7363
+ "Retry"
7364
+ ]
7365
+ }
7366
+ )
7367
+ ] }) : showEmpty ? /* @__PURE__ */ jsx18("div", { className: "p-2 text-og-sm text-og-fg-subtle", children: emptyState ?? "This directory is empty" }) : result.tree.map((node) => renderRow(node, 0))
7099
7368
  ]
7100
7369
  }
7101
7370
  ),
@@ -7128,8 +7397,8 @@ function ToolbarButton({
7128
7397
  onClick,
7129
7398
  disabled,
7130
7399
  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))]",
7400
+ "inline-flex items-center justify-center rounded-og-sm p-1 text-og-fg-muted pointer-coarse:min-h-10 pointer-coarse:min-w-10",
7401
+ "hover:bg-og-surface-2 hover:text-og-fg",
7133
7402
  "disabled:cursor-not-allowed disabled:opacity-40"
7134
7403
  ),
7135
7404
  children
@@ -7144,8 +7413,8 @@ function InlineInput({
7144
7413
  onCancel
7145
7414
  }) {
7146
7415
  const [value, setValue] = useState24(initialValue);
7147
- const ref = useRef16(null);
7148
- const doneRef = useRef16(false);
7416
+ const ref = useRef17(null);
7417
+ const doneRef = useRef17(false);
7149
7418
  useEffect17(() => {
7150
7419
  const el = ref.current;
7151
7420
  if (!el) return;
@@ -7184,8 +7453,8 @@ function InlineInput({
7184
7453
  e.stopPropagation();
7185
7454
  },
7186
7455
  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))]",
7456
+ "min-w-0 flex-1 rounded-og-sm border bg-og-bg px-1 py-0 text-og-sm",
7457
+ "border-og-accent text-og-fg",
7189
7458
  "outline-none"
7190
7459
  )
7191
7460
  }
@@ -7215,9 +7484,9 @@ function ContextMenu({
7215
7484
  onClick();
7216
7485
  },
7217
7486
  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))]"
7487
+ "flex w-full items-center gap-2 px-2.5 py-1 text-left text-og-sm pointer-coarse:min-h-10",
7488
+ "hover:bg-og-surface-2",
7489
+ danger ? "text-og-status-failed" : "text-og-fg"
7221
7490
  ),
7222
7491
  children: [
7223
7492
  icon,
@@ -7233,14 +7502,14 @@ function ContextMenu({
7233
7502
  style: { left, top },
7234
7503
  className: cn(
7235
7504
  "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))]"
7505
+ "border-og-border",
7506
+ "bg-og-surface-1"
7238
7507
  ),
7239
7508
  children: [
7240
7509
  isDir && /* @__PURE__ */ jsxs15(Fragment5, { children: [
7241
7510
  item("New file", /* @__PURE__ */ jsx18(FilePlusIcon, { className: "size-3.5" }), onNewFile),
7242
7511
  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))]" })
7512
+ /* @__PURE__ */ jsx18("div", { className: "my-1 h-px bg-og-border" })
7244
7513
  ] }),
7245
7514
  item("Rename", /* @__PURE__ */ jsx18(PencilIcon, { className: "size-3.5" }), onRename),
7246
7515
  item("Delete", /* @__PURE__ */ jsx18(Trash2Icon, { className: "size-3.5" }), onDelete, true)
@@ -7293,12 +7562,12 @@ function PierreFile({
7293
7562
  themeType: themeType ?? "dark"
7294
7563
  };
7295
7564
  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"
7565
+ "--diffs-dark-bg": "var(--og-color-bg)",
7566
+ "--diffs-light-bg": "var(--og-color-bg)",
7567
+ "--diffs-bg-buffer-override": "var(--og-color-surface-1)",
7568
+ "--diffs-bg-separator-override": "var(--og-color-surface-1)",
7569
+ "--diffs-font-size": "var(--og-code-font-size)",
7570
+ "--diffs-line-height": "var(--og-code-line-height)"
7302
7571
  };
7303
7572
  return /* @__PURE__ */ jsx19("div", { className: cn("min-w-0", className), "data-opengeni-pierre-file": true, style: pierreVars, children: /* @__PURE__ */ jsx19(Suspense2, { fallback: loading ?? /* @__PURE__ */ jsx19(FileSkeleton, {}), children: /* @__PURE__ */ jsx19(
7304
7573
  LazyFile,
@@ -7313,14 +7582,14 @@ function PlainFile({ name, contents }) {
7313
7582
  return /* @__PURE__ */ jsx19(
7314
7583
  "pre",
7315
7584
  {
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))]",
7585
+ className: "overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg",
7317
7586
  "data-file": name,
7318
7587
  children: contents
7319
7588
  }
7320
7589
  );
7321
7590
  }
7322
7591
  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" });
7592
+ return /* @__PURE__ */ jsx19("div", { className: "p-3 text-og-sm text-og-fg-subtle", children: "Loading file\u2026" });
7324
7593
  }
7325
7594
 
7326
7595
  // src/components/code-editor.tsx
@@ -7328,10 +7597,10 @@ import { Loader2Icon as Loader2Icon2, SaveIcon } from "lucide-react";
7328
7597
  import {
7329
7598
  lazy as lazy3,
7330
7599
  Suspense as Suspense3,
7331
- useCallback as useCallback22,
7600
+ useCallback as useCallback23,
7332
7601
  useEffect as useEffect19,
7333
7602
  useMemo as useMemo10,
7334
- useRef as useRef17,
7603
+ useRef as useRef18,
7335
7604
  useState as useState26
7336
7605
  } from "react";
7337
7606
  import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
@@ -7400,7 +7669,7 @@ function CodeEditor({
7400
7669
  const [saveError, setSaveError] = useState26(null);
7401
7670
  const [savedTick, setSavedTick] = useState26(false);
7402
7671
  const dirty = value !== baseline;
7403
- const lastSeed = useRef17({ path, contents: initialContents });
7672
+ const lastSeed = useRef18({ path, contents: initialContents });
7404
7673
  useEffect19(() => {
7405
7674
  const seedChanged = lastSeed.current.path !== path || lastSeed.current.contents !== initialContents;
7406
7675
  if (!seedChanged) return;
@@ -7443,9 +7712,9 @@ function CodeEditor({
7443
7712
  cancelled = true;
7444
7713
  };
7445
7714
  }, [langKey]);
7446
- const saveRef = useRef17(() => {
7715
+ const saveRef = useRef18(() => {
7447
7716
  });
7448
- const save = useCallback22(async () => {
7717
+ const save = useCallback23(async () => {
7449
7718
  if (readOnly) return;
7450
7719
  const snapshot = value;
7451
7720
  if (snapshot === baseline) return;
@@ -7498,18 +7767,18 @@ function CodeEditor({
7498
7767
  "data-opengeni-code-editor": true,
7499
7768
  style: editorVars,
7500
7769
  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: [
7770
+ /* @__PURE__ */ jsxs16("div", { className: "flex shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1", children: [
7502
7771
  /* @__PURE__ */ jsx20(
7503
7772
  "span",
7504
7773
  {
7505
7774
  className: cn(
7506
7775
  "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))]"
7776
+ readOnly ? "bg-transparent" : dirty ? "bg-og-status-running" : "bg-og-status-idle"
7508
7777
  ),
7509
7778
  title: readOnly ? "read-only" : dirty ? "unsaved changes" : "saved"
7510
7779
  }
7511
7780
  ),
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: [
7781
+ /* @__PURE__ */ jsxs16("span", { className: "truncate font-og-mono text-og-xs text-og-fg-muted", children: [
7513
7782
  fileName,
7514
7783
  dirty && !readOnly ? " \u2022" : ""
7515
7784
  ] }),
@@ -7517,21 +7786,21 @@ function CodeEditor({
7517
7786
  saveError && /* @__PURE__ */ jsx20(
7518
7787
  "span",
7519
7788
  {
7520
- className: "max-w-[220px] truncate text-[10px] text-[color:var(--og-color-danger,var(--color-danger,#f85149))]",
7789
+ className: "max-w-[220px] truncate text-og-xs text-og-status-failed",
7521
7790
  title: saveError.message,
7522
7791
  children: saveError.message
7523
7792
  }
7524
7793
  ),
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(
7794
+ !saveError && savedTick && /* @__PURE__ */ jsx20("span", { className: "text-og-xs text-og-status-idle", children: "Saved" }),
7795
+ readOnly ? /* @__PURE__ */ jsx20("span", { className: "text-og-xs uppercase tracking-wide text-og-fg-subtle", children: "Read-only" }) : /* @__PURE__ */ jsxs16(
7527
7796
  "button",
7528
7797
  {
7529
7798
  type: "button",
7530
7799
  onClick: () => void save(),
7531
7800
  disabled: saving || !dirty,
7532
7801
  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))]"
7802
+ "flex items-center gap-1 rounded-og-sm border border-og-border px-1.5 py-0.5 text-og-xs pointer-coarse:min-h-10",
7803
+ saving || !dirty ? "cursor-default text-og-fg-subtle opacity-60" : "text-og-fg hover:bg-og-accent-soft"
7535
7804
  ),
7536
7805
  title: "Save (\u2318/Ctrl+S)",
7537
7806
  children: [
@@ -7552,7 +7821,7 @@ function CodeEditor({
7552
7821
  basicSetup: true,
7553
7822
  extensions: cmExtensions,
7554
7823
  height: "100%",
7555
- className: "og-cm-editor min-h-full text-[12.5px]",
7824
+ className: "og-cm-editor min-h-full text-og-sm",
7556
7825
  onChange: readOnly ? void 0 : (next) => {
7557
7826
  setValue(next);
7558
7827
  setSavedTick(false);
@@ -7564,8 +7833,8 @@ function CodeEditor({
7564
7833
  );
7565
7834
  }
7566
7835
  var editorVars = {
7567
- "--og-cm-bg": "var(--og-color-bg, #0d0d0d)",
7568
- fontFamily: "var(--og-font-mono, var(--font-mono, monospace))"
7836
+ "--og-cm-bg": "var(--og-color-bg)",
7837
+ fontFamily: "var(--og-font-mono)"
7569
7838
  };
7570
7839
  function PlainTextarea({
7571
7840
  value,
@@ -7579,28 +7848,28 @@ function PlainTextarea({
7579
7848
  readOnly,
7580
7849
  spellCheck: false,
7581
7850
  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"
7851
+ className: "h-full w-full resize-none bg-transparent p-2 font-og-mono text-og-sm text-og-fg outline-none"
7583
7852
  }
7584
7853
  );
7585
7854
  }
7586
7855
  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" });
7856
+ return /* @__PURE__ */ jsx20("div", { className: "p-3 text-og-sm text-og-fg-subtle", children: "Loading editor\u2026" });
7588
7857
  }
7589
7858
 
7590
7859
  // src/components/sandbox-files.tsx
7591
7860
  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";
7861
+ import { useCallback as useCallback24, useEffect as useEffect20, useMemo as useMemo11, useRef as useRef19, useState as useState27 } from "react";
7593
7862
  import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
7594
7863
  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))]"
7864
+ added: "text-og-status-idle",
7865
+ modified: "text-og-status-running",
7866
+ deleted: "text-og-status-failed",
7867
+ renamed: "text-og-accent",
7868
+ copied: "text-og-accent",
7869
+ untracked: "text-og-fg-subtle",
7870
+ ignored: "text-og-fg-subtle",
7871
+ conflicted: "text-og-status-failed",
7872
+ typechange: "text-og-status-running"
7604
7873
  };
7605
7874
  var STATUS_LETTER = {
7606
7875
  added: "A",
@@ -7627,7 +7896,7 @@ function SandboxFiles({
7627
7896
  const [staged, setStaged] = useState27(false);
7628
7897
  const [layout, setLayout] = useState27("unified");
7629
7898
  const [editMode, setEditMode] = useState27(false);
7630
- const rootRef = useRef18(null);
7899
+ const rootRef = useRef19(null);
7631
7900
  const [wide, setWide] = useState27(false);
7632
7901
  useEffect20(() => {
7633
7902
  const el = rootRef.current;
@@ -7647,7 +7916,7 @@ function SandboxFiles({
7647
7916
  const selectedDiff = changed.find((f) => f.path === effectiveSelected) ?? null;
7648
7917
  const viewPath = effectiveSelected && !selectedDiff ? effectiveSelected : null;
7649
7918
  const fileView = useFileView(viewPath, files.readFile);
7650
- const selectFile = useCallback23((path) => {
7919
+ const selectFile = useCallback24((path) => {
7651
7920
  setSelected(path);
7652
7921
  setEditMode(false);
7653
7922
  }, []);
@@ -7664,11 +7933,11 @@ function SandboxFiles({
7664
7933
  {
7665
7934
  className: cn(
7666
7935
  "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"
7936
+ wide ? "w-[280px] shrink-0 border-r border-og-border" : "flex-1"
7668
7937
  ),
7669
7938
  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: [
7939
+ changed.length > 0 && /* @__PURE__ */ jsxs17("div", { className: "border-b border-og-border", children: [
7940
+ /* @__PURE__ */ jsxs17("div", { className: "px-2 py-1 text-og-xs font-medium uppercase tracking-wide text-og-fg-subtle", children: [
7672
7941
  "Changes \xB7 ",
7673
7942
  changed.length
7674
7943
  ] }),
@@ -7678,15 +7947,15 @@ function SandboxFiles({
7678
7947
  type: "button",
7679
7948
  onClick: () => selectFile(file.path),
7680
7949
  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))]"
7950
+ "flex w-full items-center gap-1.5 truncate px-2 py-0.5 text-left text-og-sm hover:bg-og-surface-2 pointer-coarse:min-h-10",
7951
+ file.path === effectiveSelected && "bg-og-surface-2"
7683
7952
  ),
7684
7953
  children: [
7685
7954
  /* @__PURE__ */ jsx21(
7686
7955
  "span",
7687
7956
  {
7688
7957
  className: cn(
7689
- "w-3 shrink-0 text-center font-[family-name:var(--og-font-mono,var(--font-mono,monospace))] text-[10px]",
7958
+ "w-3 shrink-0 text-center font-og-mono text-og-xs",
7690
7959
  STATUS_TINT2[file.status]
7691
7960
  ),
7692
7961
  children: STATUS_LETTER[file.status]
@@ -7694,12 +7963,12 @@ function SandboxFiles({
7694
7963
  ),
7695
7964
  /* @__PURE__ */ jsx21(FileIcon3, { className: "size-3.5 shrink-0 opacity-70" }),
7696
7965
  /* @__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: [
7966
+ /* @__PURE__ */ jsxs17("span", { className: "ml-auto flex shrink-0 items-center gap-1.5 pl-2 text-og-xs", children: [
7967
+ /* @__PURE__ */ jsxs17("span", { className: "text-og-status-idle", children: [
7699
7968
  "+",
7700
7969
  file.additions
7701
7970
  ] }),
7702
- /* @__PURE__ */ jsxs17("span", { className: "text-[color:var(--og-color-danger,var(--color-danger,#f85149))]", children: [
7971
+ /* @__PURE__ */ jsxs17("span", { className: "text-og-status-failed", children: [
7703
7972
  "\u2212",
7704
7973
  file.deletions
7705
7974
  ] })
@@ -7708,14 +7977,14 @@ function SandboxFiles({
7708
7977
  }
7709
7978
  ) }, file.path)) })
7710
7979
  ] }),
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" }),
7980
+ /* @__PURE__ */ jsx21("div", { className: "px-2 py-1 text-og-xs font-medium uppercase tracking-wide text-og-fg-subtle", children: "Files" }),
7712
7981
  /* @__PURE__ */ jsx21(
7713
7982
  FileBrowser,
7714
7983
  {
7715
7984
  result: files,
7716
7985
  selectedPath: effectiveSelected ?? void 0,
7717
7986
  onSelectFile: selectFile,
7718
- emptyState: "No files.",
7987
+ emptyState: "This directory is empty",
7719
7988
  className: "min-w-0"
7720
7989
  }
7721
7990
  )
@@ -7727,12 +7996,12 @@ function SandboxFiles({
7727
7996
  {
7728
7997
  className: cn(
7729
7998
  "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))]"
7999
+ wide ? "flex-1" : "flex-[1.4] border-t border-og-border"
7731
8000
  ),
7732
8001
  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: [
8002
+ /* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1", children: [
8003
+ /* @__PURE__ */ jsx21("span", { className: "min-w-0 truncate font-og-mono text-og-xs text-og-fg-muted", children: effectiveSelected ?? "No file selected" }),
8004
+ /* @__PURE__ */ jsxs17("div", { className: "flex min-w-0 shrink-0 flex-wrap items-center justify-end gap-1", children: [
7736
8005
  selectedDiff && stagedGit && /* @__PURE__ */ jsx21(
7737
8006
  Segmented,
7738
8007
  {
@@ -7809,7 +8078,7 @@ function SandboxFiles({
7809
8078
  fileView.sizeBytes ?? 0,
7810
8079
  " bytes)."
7811
8080
  ] }) : 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: [
8081
+ fileView.truncated && /* @__PURE__ */ jsxs17("div", { className: "border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-xs text-og-status-running", children: [
7813
8082
  "Large file \u2014 showing a truncated preview (",
7814
8083
  fileView.sizeBytes ?? 0,
7815
8084
  " bytes loaded). Editing is disabled to avoid corrupting the file."
@@ -7820,10 +8089,10 @@ function SandboxFiles({
7820
8089
  path: viewPath,
7821
8090
  contents: fileView.content,
7822
8091
  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 }),
8092
+ fallback: /* @__PURE__ */ jsx21("pre", { className: "overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg", children: fileView.content }),
7824
8093
  className: "p-1"
7825
8094
  }
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 })
8095
+ ) : /* @__PURE__ */ jsx21("pre", { className: "overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg", children: fileView.content })
7827
8096
  ] }) : /* @__PURE__ */ jsxs17(Notice, { children: [
7828
8097
  "Loading ",
7829
8098
  viewPath,
@@ -7842,19 +8111,19 @@ function SandboxFiles({
7842
8111
  }
7843
8112
  function GitHeader({ git, dirtyCount }) {
7844
8113
  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: [
8114
+ return /* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-sm", children: [
7846
8115
  /* @__PURE__ */ jsx21(
7847
8116
  "span",
7848
8117
  {
7849
8118
  className: cn(
7850
8119
  "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))]"
8120
+ dirty ? "bg-og-status-running" : "bg-og-status-idle"
7852
8121
  ),
7853
8122
  title: dirty ? `${dirtyCount} changed` : "clean"
7854
8123
  }
7855
8124
  ),
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: [
8125
+ /* @__PURE__ */ jsx21("span", { className: "truncate font-og-mono text-og-fg", children: git.branch ?? (git.isRepo ? "(detached)" : "no repo") }),
8126
+ (git.ahead > 0 || git.behind > 0) && /* @__PURE__ */ jsxs17("span", { className: "flex shrink-0 items-center gap-1.5 text-og-xs text-og-fg-subtle", children: [
7858
8127
  git.ahead > 0 && /* @__PURE__ */ jsxs17("span", { children: [
7859
8128
  "\u2191",
7860
8129
  git.ahead
@@ -7864,7 +8133,7 @@ function GitHeader({ git, dirtyCount }) {
7864
8133
  git.behind
7865
8134
  ] })
7866
8135
  ] }),
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: [
8136
+ dirty && /* @__PURE__ */ jsxs17("span", { className: "ml-auto shrink-0 text-og-xs text-og-fg-subtle", children: [
7868
8137
  dirtyCount,
7869
8138
  " changed"
7870
8139
  ] })
@@ -7875,14 +8144,14 @@ function Segmented({
7875
8144
  value,
7876
8145
  onChange
7877
8146
  }) {
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(
8147
+ return /* @__PURE__ */ jsx21("div", { className: "flex flex-wrap items-center rounded-og-sm border border-og-border p-0.5", children: options.map((opt) => /* @__PURE__ */ jsx21(
7879
8148
  "button",
7880
8149
  {
7881
8150
  type: "button",
7882
8151
  onClick: () => onChange(opt.value),
7883
8152
  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))]"
8153
+ "rounded-og-xs px-1.5 py-0.5 text-og-xs pointer-coarse:min-h-10",
8154
+ opt.value === value ? "bg-og-accent-soft text-og-fg" : "text-og-fg-subtle hover:text-og-fg"
7886
8155
  ),
7887
8156
  children: opt.label
7888
8157
  },
@@ -7950,7 +8219,7 @@ function Notice({ children, className }) {
7950
8219
  "div",
7951
8220
  {
7952
8221
  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))]",
8222
+ "flex h-full items-center justify-center p-4 text-center text-og-sm text-og-fg-subtle",
7954
8223
  className
7955
8224
  ),
7956
8225
  children
@@ -7960,8 +8229,9 @@ function Notice({ children, className }) {
7960
8229
 
7961
8230
  // src/components/desktop-viewer.tsx
7962
8231
  import { LoaderCircleIcon as LoaderCircleIcon2, MonitorIcon, MousePointerClickIcon, WifiOffIcon } from "lucide-react";
7963
- import { useEffect as useEffect21, useRef as useRef19, useState as useState28 } from "react";
8232
+ import { useEffect as useEffect21, useRef as useRef20, useState as useState28 } from "react";
7964
8233
  import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
8234
+ var DESKTOP_MEDIA_BACKGROUND = "#000";
7965
8235
  function isHardUnavailable(reason) {
7966
8236
  switch (reason) {
7967
8237
  case "backend_unsupported":
@@ -7992,7 +8262,7 @@ function DesktopViewer({
7992
8262
  connectTimeoutMs = 13e3,
7993
8263
  className
7994
8264
  }) {
7995
- const containerRef = useRef19(null);
8265
+ const containerRef = useRef20(null);
7996
8266
  const [consented, setConsented] = useState28(false);
7997
8267
  const [takeControl, setTakeControl] = useState28(interactive ?? false);
7998
8268
  const externallyControlled = interactive !== void 0;
@@ -8034,9 +8304,9 @@ function DesktopViewer({
8034
8304
  });
8035
8305
  const connected = stream.state === "connected";
8036
8306
  const hasLiveUrl = Boolean(connectCapability?.url);
8037
- const streamStateRef = useRef19(stream.state);
8307
+ const streamStateRef = useRef20(stream.state);
8038
8308
  streamStateRef.current = stream.state;
8039
- const warmKeyRef = useRef19(null);
8309
+ const warmKeyRef = useRef20(null);
8040
8310
  useEffect21(() => {
8041
8311
  if (!isWatching || !coldWarmable || needsAck || viewerCapReached) {
8042
8312
  if (!coldWarmable) warmKeyRef.current = null;
@@ -8115,10 +8385,11 @@ function DesktopViewer({
8115
8385
  "div",
8116
8386
  {
8117
8387
  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))]",
8388
+ "relative h-full w-full overflow-hidden",
8389
+ inControl && "ring-2 ring-inset ring-og-accent",
8120
8390
  className
8121
8391
  ),
8392
+ style: { backgroundColor: DESKTOP_MEDIA_BACKGROUND },
8122
8393
  "data-opengeni-desktop": true,
8123
8394
  "data-state": stream.state,
8124
8395
  "data-ui-state": uiState,
@@ -8133,18 +8404,18 @@ function DesktopViewer({
8133
8404
  "data-state": stream.state
8134
8405
  }
8135
8406
  ),
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: [
8407
+ uiState === "connecting" && /* @__PURE__ */ jsxs18("div", { className: "pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-3 text-og-fg-subtle", children: [
8137
8408
  /* @__PURE__ */ jsxs18("span", { className: "relative flex items-center justify-center", children: [
8138
8409
  /* @__PURE__ */ jsx22(MonitorIcon, { className: "size-8 opacity-30", strokeWidth: 1.5 }),
8139
8410
  /* @__PURE__ */ jsx22(
8140
8411
  LoaderCircleIcon2,
8141
8412
  {
8142
- className: "absolute size-12 animate-og-spin text-[color:var(--og-color-accent,var(--color-brand,#3b82f6))] opacity-70",
8413
+ className: "absolute size-12 animate-og-spin text-og-accent opacity-70",
8143
8414
  strokeWidth: 1.25
8144
8415
  }
8145
8416
  )
8146
8417
  ] }),
8147
- /* @__PURE__ */ jsx22("span", { className: "text-xs", children: "Connecting to the desktop\u2026" })
8418
+ /* @__PURE__ */ jsx22("span", { className: "text-og-sm", children: "Connecting to the desktop\u2026" })
8148
8419
  ] }),
8149
8420
  showToggle && !externallyControlled && inControl && /* @__PURE__ */ jsx22(
8150
8421
  InControlBar,
@@ -8157,7 +8428,7 @@ function DesktopViewer({
8157
8428
  TakeControlCallToAction,
8158
8429
  {
8159
8430
  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,
8431
+ disabledReason: !serverAllowsControl ? capability?.client === "frames" ? "View-only \u2014 live control isn't available for this machine yet." : "This deployment streams the desktop read-only." : void 0,
8161
8432
  onTakeControl: () => setTakeControl(true)
8162
8433
  }
8163
8434
  ),
@@ -8183,16 +8454,16 @@ function TakeControlCallToAction({
8183
8454
  title: disabled ? disabledReason : "Take control of the desktop",
8184
8455
  onClick: onTakeControl,
8185
8456
  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))]",
8457
+ "group pointer-events-auto flex items-center gap-3 rounded-og-lg border px-5 py-3",
8458
+ "border-og-border",
8459
+ "bg-og-bg/85 backdrop-blur-md",
8460
+ "shadow-og-lg",
8190
8461
  "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",
8462
+ "focus-visible:ring-2 focus-visible:ring-og-accent focus-visible:ring-offset-2 focus-visible:ring-offset-og-bg",
8192
8463
  disabled ? "cursor-not-allowed opacity-60" : cn(
8193
8464
  "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"
8465
+ "hover:border-og-accent",
8466
+ "hover:bg-og-accent/10"
8196
8467
  )
8197
8468
  ),
8198
8469
  children: [
@@ -8201,16 +8472,16 @@ function TakeControlCallToAction({
8201
8472
  {
8202
8473
  className: cn(
8203
8474
  "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)]",
8475
+ "bg-og-accent",
8476
+ "text-og-accent-fg",
8206
8477
  disabled ? "" : "group-hover:scale-105"
8207
8478
  ),
8208
8479
  children: /* @__PURE__ */ jsx22(MousePointerClickIcon, { className: "size-5", strokeWidth: 2 })
8209
8480
  }
8210
8481
  ),
8211
8482
  /* @__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" })
8483
+ /* @__PURE__ */ jsx22("span", { className: "text-og-base font-semibold text-og-fg", children: "Take control" }),
8484
+ /* @__PURE__ */ jsx22("span", { className: "text-og-xs text-og-fg-subtle", children: disabled && disabledReason ? disabledReason : "Drive the mouse & keyboard" })
8214
8485
  ] })
8215
8486
  ]
8216
8487
  }
@@ -8219,13 +8490,13 @@ function TakeControlCallToAction({
8219
8490
  }
8220
8491
  function InControlBar({ shared, onRelease }) {
8221
8492
  return /* @__PURE__ */ jsxs18("div", { className: "pointer-events-none absolute inset-x-0 top-0 flex items-center justify-between gap-2 p-2", children: [
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: [
8493
+ /* @__PURE__ */ jsxs18("span", { className: "pointer-events-auto inline-flex items-center gap-2 rounded-og-sm bg-og-accent px-2.5 py-1 text-og-xs font-medium text-og-accent-fg shadow-og-md", children: [
8223
8494
  /* @__PURE__ */ jsx22("span", { className: "size-1.5 animate-pulse rounded-full bg-current", "aria-hidden": true }),
8224
8495
  "You're in control",
8225
8496
  /* @__PURE__ */ jsx22("span", { className: "opacity-75", children: "\xB7 click Return control (or Ctrl+Alt+Shift)" })
8226
8497
  ] }),
8227
8498
  /* @__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" }),
8499
+ shared && /* @__PURE__ */ jsx22("span", { className: "rounded-og-sm bg-og-status-failed/85 px-2 py-0.5 text-og-xs text-og-accent-fg", children: "Shared sandbox \u2014 others are watching" }),
8229
8500
  /* @__PURE__ */ jsxs18(
8230
8501
  "button",
8231
8502
  {
@@ -8233,9 +8504,9 @@ function InControlBar({ shared, onRelease }) {
8233
8504
  onClick: onRelease,
8234
8505
  title: "Return control (or press Ctrl+Alt+Shift)",
8235
8506
  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))]"
8507
+ "inline-flex items-center gap-1.5 rounded-og-sm border px-2.5 py-1 text-og-xs font-semibold shadow-og-md transition-colors",
8508
+ "border-og-accent bg-og-bg/90 text-og-fg backdrop-blur-sm",
8509
+ "outline-none hover:bg-og-accent hover:text-og-accent-fg focus-visible:ring-2 focus-visible:ring-og-accent"
8239
8510
  ),
8240
8511
  children: [
8241
8512
  /* @__PURE__ */ jsx22(MonitorIcon, { className: "size-3.5", strokeWidth: 2, "aria-hidden": true }),
@@ -8255,7 +8526,7 @@ function unavailableCopy(reason) {
8255
8526
  case "os_unsupported":
8256
8527
  return "The sandbox OS does not support a desktop stream.";
8257
8528
  case "not_provisioned":
8258
- return "No display stack is provisioned on this box yet.";
8529
+ return "This sandbox doesn't have a desktop yet.";
8259
8530
  case "disabled_by_policy":
8260
8531
  return "Desktop streaming is disabled on this deployment.";
8261
8532
  case "lease_cold":
@@ -8265,62 +8536,62 @@ function unavailableCopy(reason) {
8265
8536
  }
8266
8537
  }
8267
8538
  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: [
8539
+ return /* @__PURE__ */ jsxs18("div", { className: "flex max-w-sm flex-col items-center gap-3 rounded-og-lg border border-og-border bg-og-bg/90 p-5 text-center text-og-base text-og-fg backdrop-blur-sm", children: [
8269
8540
  /* @__PURE__ */ jsx22(
8270
8541
  LoaderCircleIcon2,
8271
8542
  {
8272
- className: "size-7 animate-og-spin text-[color:var(--og-color-accent,var(--color-brand,#3b82f6))]",
8543
+ className: "size-7 animate-og-spin text-og-accent",
8273
8544
  strokeWidth: 1.5
8274
8545
  }
8275
8546
  ),
8276
8547
  /* @__PURE__ */ jsxs18("div", { className: "space-y-1", children: [
8277
8548
  /* @__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." })
8549
+ /* @__PURE__ */ jsx22("p", { className: "text-og-sm text-og-fg-subtle", children: "Spinning up the desktop \u2014 this takes a few seconds." })
8279
8550
  ] }),
8280
8551
  onRetry && /* @__PURE__ */ jsx22(
8281
8552
  "button",
8282
8553
  {
8283
8554
  type: "button",
8284
8555
  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)]",
8556
+ className: "rounded-og-sm border border-og-border px-3 py-1.5 text-og-sm text-og-fg-muted transition-colors hover:text-og-fg pointer-coarse:min-h-10",
8286
8557
  children: "Taking too long? Retry"
8287
8558
  }
8288
8559
  )
8289
8560
  ] });
8290
8561
  }
8291
8562
  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: [
8563
+ return /* @__PURE__ */ jsxs18("div", { className: "max-w-sm rounded-og-lg border border-og-border bg-og-bg p-4 text-center text-og-base text-og-fg", children: [
8293
8564
  /* @__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: [
8565
+ /* @__PURE__ */ jsxs18("p", { className: "mb-3 text-og-sm text-og-fg-subtle", children: [
8295
8566
  "The desktop pixel stream is ",
8296
8567
  /* @__PURE__ */ jsx22("strong", { children: "un-redacted" }),
8297
8568
  " \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." : ""
8569
+ shared ? " This sandbox is shared: you'll also see other sessions' agents on the same screen." : ""
8299
8570
  ] }),
8300
8571
  /* @__PURE__ */ jsx22(
8301
8572
  "button",
8302
8573
  {
8303
8574
  type: "button",
8304
8575
  onClick: onAccept,
8305
- className: "rounded bg-[color:var(--color-brand,#3b82f6)] px-3 py-1.5 text-xs font-medium text-white",
8576
+ className: "rounded-og-sm bg-og-accent px-3 py-1.5 text-og-sm font-medium text-og-accent-fg pointer-coarse:min-h-10",
8306
8577
  children: "I understand \u2014 show the desktop"
8307
8578
  }
8308
8579
  )
8309
8580
  ] });
8310
8581
  }
8311
8582
  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: [
8583
+ return /* @__PURE__ */ jsxs18("div", { className: "max-w-sm rounded-og-lg border border-og-border bg-og-bg p-4 text-center text-og-base text-og-fg", children: [
8313
8584
  /* @__PURE__ */ jsxs18("div", { className: "mb-1 flex items-center justify-center gap-1.5 font-medium", children: [
8314
8585
  onRetry && /* @__PURE__ */ jsx22(WifiOffIcon, { className: "size-4 opacity-70", strokeWidth: 1.75 }),
8315
8586
  title
8316
8587
  ] }),
8317
- /* @__PURE__ */ jsx22("p", { className: "text-xs text-[color:var(--color-fg-subtle,#888)]", children: body }),
8588
+ /* @__PURE__ */ jsx22("p", { className: "text-og-sm text-og-fg-subtle", children: body }),
8318
8589
  onRetry && /* @__PURE__ */ jsx22(
8319
8590
  "button",
8320
8591
  {
8321
8592
  type: "button",
8322
8593
  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))]",
8594
+ className: "mt-3 rounded-og-sm border border-og-border px-3 py-1.5 text-og-sm transition-colors hover:border-og-accent pointer-coarse:min-h-10",
8324
8595
  children: "Reconnect"
8325
8596
  }
8326
8597
  )
@@ -8328,12 +8599,13 @@ function defaultNotice(title, body, onRetry) {
8328
8599
  }
8329
8600
 
8330
8601
  // src/components/workspace-dock.tsx
8331
- import { useCallback as useCallback24, useEffect as useEffect22, useLayoutEffect, useState as useState29 } from "react";
8602
+ import { useCallback as useCallback25, useEffect as useEffect22, useLayoutEffect, useState as useState29 } from "react";
8332
8603
  import {
8333
8604
  ChevronsLeftRightIcon,
8334
8605
  Maximize2Icon,
8335
8606
  Minimize2Icon,
8336
- PanelRightCloseIcon
8607
+ PanelRightCloseIcon,
8608
+ XIcon as XIcon3
8337
8609
  } from "lucide-react";
8338
8610
  import {
8339
8611
  Group,
@@ -8344,6 +8616,25 @@ import {
8344
8616
  } from "react-resizable-panels";
8345
8617
  import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
8346
8618
  var useDockLayoutEffect = typeof window === "undefined" ? useEffect22 : useLayoutEffect;
8619
+ var DOCK_OVERLAY_BREAKPOINT = 1024;
8620
+ function useIsNarrow(maxWidth) {
8621
+ const [narrow, setNarrow] = useState29(false);
8622
+ useDockLayoutEffect(() => {
8623
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
8624
+ return;
8625
+ }
8626
+ const mql = window.matchMedia(`(max-width: ${maxWidth - 1}px)`);
8627
+ const update = () => setNarrow(mql.matches);
8628
+ update();
8629
+ if (typeof mql.addEventListener === "function") {
8630
+ mql.addEventListener("change", update);
8631
+ return () => mql.removeEventListener("change", update);
8632
+ }
8633
+ mql.addListener(update);
8634
+ return () => mql.removeListener(update);
8635
+ }, [maxWidth]);
8636
+ return narrow;
8637
+ }
8347
8638
  function WorkspaceDock({
8348
8639
  primary,
8349
8640
  tabs,
@@ -8357,11 +8648,13 @@ function WorkspaceDock({
8357
8648
  maxSize = 70,
8358
8649
  className
8359
8650
  }) {
8651
+ const narrow = useIsNarrow(DOCK_OVERLAY_BREAKPOINT);
8360
8652
  const dockPanelRef = usePanelRef();
8361
8653
  const [internalCollapsed, setInternalCollapsed] = useState29(false);
8362
8654
  const [maximized, setMaximized] = useState29(false);
8363
8655
  const [internalTab, setInternalTab] = useState29(tabs[0]?.id ?? "");
8364
8656
  const collapsed = collapsedProp ?? internalCollapsed;
8657
+ const hostControlled = collapsedProp !== void 0;
8365
8658
  const { defaultLayout, onLayoutChanged } = useDefaultLayout({
8366
8659
  panelIds: ["primary", "dock"],
8367
8660
  storage: typeof window !== "undefined" ? window.localStorage : void 0,
@@ -8370,14 +8663,14 @@ function WorkspaceDock({
8370
8663
  const current = activeTab ?? internalTab;
8371
8664
  const tabIds = tabs.map((tab) => tab.id).join("\0");
8372
8665
  const firstTabId = tabs[0]?.id ?? "";
8373
- const setTab = useCallback24(
8666
+ const setTab = useCallback25(
8374
8667
  (id) => {
8375
8668
  setInternalTab(id);
8376
8669
  onActiveTabChange?.(id);
8377
8670
  },
8378
8671
  [onActiveTabChange]
8379
8672
  );
8380
- const setCollapsed = useCallback24(
8673
+ const setCollapsed = useCallback25(
8381
8674
  (next) => {
8382
8675
  setInternalCollapsed((previous) => previous === next ? previous : next);
8383
8676
  onCollapsedChange?.(next);
@@ -8400,31 +8693,70 @@ function WorkspaceDock({
8400
8693
  setTab(firstTabId);
8401
8694
  }
8402
8695
  }, [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(() => {
8696
+ const collapse = useCallback25(() => {
8412
8697
  dockPanelRef.current?.collapse();
8413
8698
  setCollapsed(true);
8414
8699
  }, [dockPanelRef, setCollapsed]);
8415
- const expand = useCallback24(() => {
8700
+ const expand = useCallback25(() => {
8416
8701
  dockPanelRef.current?.expand();
8417
8702
  setCollapsed(false);
8418
8703
  }, [dockPanelRef, setCollapsed]);
8704
+ useEffect22(() => {
8705
+ const overlayOpen = maximized || narrow && !collapsed;
8706
+ if (!overlayOpen) return;
8707
+ const onKey = (event) => {
8708
+ if (event.key !== "Escape") return;
8709
+ if (maximized) setMaximized(false);
8710
+ else collapse();
8711
+ };
8712
+ window.addEventListener("keydown", onKey);
8713
+ return () => window.removeEventListener("keydown", onKey);
8714
+ }, [maximized, narrow, collapsed, collapse]);
8715
+ if (narrow) {
8716
+ return /* @__PURE__ */ jsxs19("div", { className: cn("relative flex h-full min-h-0 w-full min-w-0", className), children: [
8717
+ /* @__PURE__ */ jsx23("div", { className: "min-h-0 min-w-0 flex-1", children: primary }),
8718
+ !collapsed && /* @__PURE__ */ jsx23(
8719
+ "div",
8720
+ {
8721
+ role: "dialog",
8722
+ "aria-modal": "true",
8723
+ "aria-label": "Workspace",
8724
+ className: "fixed inset-0 z-40 flex flex-col bg-og-bg",
8725
+ style: {
8726
+ paddingTop: "env(safe-area-inset-top)",
8727
+ paddingBottom: "env(safe-area-inset-bottom)"
8728
+ },
8729
+ children: /* @__PURE__ */ jsx23(
8730
+ DockChrome,
8731
+ {
8732
+ tabs,
8733
+ current,
8734
+ onTab: setTab,
8735
+ controls: /* @__PURE__ */ jsx23(ChromeButton, { onClick: collapse, title: "Close workspace", label: "Close workspace", children: /* @__PURE__ */ jsx23(XIcon3, { className: "size-4" }) })
8736
+ }
8737
+ )
8738
+ }
8739
+ )
8740
+ ] });
8741
+ }
8419
8742
  const dockChrome = /* @__PURE__ */ jsx23(
8420
8743
  DockChrome,
8421
8744
  {
8422
8745
  tabs,
8423
8746
  current,
8424
8747
  onTab: setTab,
8425
- maximized,
8426
- onToggleMaximize: () => setMaximized((m) => !m),
8427
- onCollapse: maximized ? () => setMaximized(false) : collapse
8748
+ controls: /* @__PURE__ */ jsxs19(Fragment7, { children: [
8749
+ /* @__PURE__ */ jsx23(
8750
+ ChromeButton,
8751
+ {
8752
+ onClick: () => setMaximized((m) => !m),
8753
+ title: maximized ? "Restore (Esc)" : "Maximize",
8754
+ label: maximized ? "Restore dock" : "Maximize dock",
8755
+ children: maximized ? /* @__PURE__ */ jsx23(Minimize2Icon, { className: "size-3.5" }) : /* @__PURE__ */ jsx23(Maximize2Icon, { className: "size-3.5" })
8756
+ }
8757
+ ),
8758
+ hostControlled ? null : /* @__PURE__ */ jsx23(ChromeButton, { onClick: collapse, title: "Collapse", label: "Collapse dock", children: /* @__PURE__ */ jsx23(PanelRightCloseIcon, { className: "size-3.5" }) })
8759
+ ] })
8428
8760
  }
8429
8761
  );
8430
8762
  return /* @__PURE__ */ jsxs19("div", { className: cn("relative flex h-full min-h-0 w-full min-w-0", className), children: [
@@ -8437,7 +8769,7 @@ function WorkspaceDock({
8437
8769
  onLayoutChanged,
8438
8770
  children: [
8439
8771
  /* @__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))]" }) }),
8772
+ !collapsed && /* @__PURE__ */ jsx23(Separator, { className: "group relative w-1.5 shrink-0 outline-none", children: /* @__PURE__ */ jsx23("span", { className: "absolute inset-y-0 left-1/2 w-px -translate-x-1/2 bg-og-border transition-colors group-hover:bg-og-accent group-data-[separator-state=dragging]:bg-og-accent" }) }),
8441
8773
  /* @__PURE__ */ jsx23(
8442
8774
  Panel,
8443
8775
  {
@@ -8456,83 +8788,85 @@ function WorkspaceDock({
8456
8788
  }
8457
8789
  },
8458
8790
  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 })
8791
+ children: !collapsed && !maximized && /* @__PURE__ */ jsx23("div", { className: "flex h-full min-h-0 min-w-0 flex-col border-l border-og-border bg-og-bg", children: dockChrome })
8460
8792
  }
8461
8793
  )
8462
8794
  ]
8463
8795
  }
8464
8796
  ),
8465
- collapsed && !maximized && /* @__PURE__ */ jsx23(
8797
+ collapsed && !maximized && !hostControlled && /* @__PURE__ */ jsx23(
8466
8798
  "button",
8467
8799
  {
8468
8800
  type: "button",
8469
8801
  onClick: expand,
8470
8802
  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))]",
8803
+ className: "absolute inset-y-0 right-0 flex w-6 shrink-0 items-center justify-center border-l border-og-border bg-og-surface-1 text-og-fg-subtle hover:text-og-fg",
8472
8804
  children: /* @__PURE__ */ jsx23(ChevronsLeftRightIcon, { className: "size-3.5" })
8473
8805
  }
8474
8806
  ),
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 })
8807
+ maximized && /* @__PURE__ */ jsx23("div", { className: "fixed inset-0 z-40 flex flex-col bg-og-bg", children: dockChrome })
8476
8808
  ] });
8477
8809
  }
8810
+ function ChromeButton({
8811
+ onClick,
8812
+ title,
8813
+ label,
8814
+ children
8815
+ }) {
8816
+ return /* @__PURE__ */ jsx23(
8817
+ "button",
8818
+ {
8819
+ type: "button",
8820
+ onClick,
8821
+ title,
8822
+ "aria-label": label,
8823
+ className: "inline-flex items-center justify-center rounded-og-sm p-1 transition-colors hover:bg-og-surface-2 hover:text-og-fg pointer-coarse:size-10",
8824
+ children
8825
+ }
8826
+ );
8827
+ }
8478
8828
  function DockChrome({
8479
8829
  tabs,
8480
8830
  current,
8481
8831
  onTab,
8482
- maximized,
8483
- onToggleMaximize,
8484
- onCollapse
8832
+ controls
8485
8833
  }) {
8486
8834
  const active = tabs.find((t) => t.id === current) ?? tabs[0];
8487
8835
  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",
8836
+ /* @__PURE__ */ jsxs19("div", { className: "flex shrink-0 items-center gap-2 border-b border-og-border px-1.5 py-1", children: [
8837
+ /* @__PURE__ */ jsx23(
8838
+ "div",
8491
8839
  {
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
- ] })
8840
+ className: "flex min-w-0 flex-1 items-center gap-0.5 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
8841
+ role: "tablist",
8842
+ children: tabs.map((tab) => /* @__PURE__ */ jsxs19(
8843
+ "button",
8844
+ {
8845
+ type: "button",
8846
+ role: "tab",
8847
+ "aria-selected": tab.id === current,
8848
+ onClick: () => onTab(tab.id),
8849
+ className: cn(
8850
+ "flex shrink-0 items-center gap-1 rounded-og-sm px-2 py-1 text-og-xs font-medium transition-colors pointer-coarse:min-h-10",
8851
+ tab.id === current ? "bg-og-accent-soft text-og-fg" : "text-og-fg-subtle hover:text-og-fg"
8852
+ ),
8853
+ children: [
8854
+ /* @__PURE__ */ jsx23("span", { children: tab.label }),
8855
+ tab.badge
8856
+ ]
8857
+ },
8858
+ tab.id
8859
+ ))
8860
+ }
8861
+ ),
8862
+ /* @__PURE__ */ jsx23("div", { className: "flex shrink-0 items-center gap-0.5 text-og-fg-subtle", children: controls })
8529
8863
  ] }),
8530
8864
  /* @__PURE__ */ jsx23("div", { className: "min-h-0 min-w-0 flex-1 overflow-hidden", role: "tabpanel", children: active?.content })
8531
8865
  ] });
8532
8866
  }
8533
8867
 
8534
8868
  // src/hooks/use-codex-accounts.ts
8535
- import { useCallback as useCallback25, useState as useState30 } from "react";
8869
+ import { useCallback as useCallback26, useState as useState30 } from "react";
8536
8870
  function isCodexAccountEvent(event) {
8537
8871
  return event.type === "codex.account.switched" || event.type === "turn.started";
8538
8872
  }
@@ -8549,7 +8883,7 @@ function useCodexAccounts(options = {}) {
8549
8883
  const codexClient = options.codexClient ?? client;
8550
8884
  const sessionId = options.sessionId;
8551
8885
  const sharedEvents = options.events;
8552
- const load = useCallback25(async () => {
8886
+ const load = useCallback26(async () => {
8553
8887
  const accountsP = codexClient.listCodexAccounts(workspaceId);
8554
8888
  const sessionP = sessionId && codexClient.getSession ? codexClient.getSession(workspaceId, sessionId).catch(() => null) : Promise.resolve(null);
8555
8889
  const [acc, session] = await Promise.all([accountsP, sessionP]);
@@ -8573,7 +8907,7 @@ function useCodexAccounts(options = {}) {
8573
8907
  () => void state.refresh(),
8574
8908
  { enabled: options.enabled ?? true, ...sharedEvents !== void 0 ? { events: sharedEvents } : {} }
8575
8909
  );
8576
- const pin = useCallback25(
8910
+ const pin = useCallback26(
8577
8911
  async (target) => {
8578
8912
  if (!sessionId || !codexClient.pinSessionCodexAccount) {
8579
8913
  return false;
@@ -8589,7 +8923,7 @@ function useCodexAccounts(options = {}) {
8589
8923
  },
8590
8924
  [codexClient, workspaceId, sessionId, mutation.run, state.refresh]
8591
8925
  );
8592
- const refreshUsage = useCallback25(
8926
+ const refreshUsage = useCallback26(
8593
8927
  async () => {
8594
8928
  if (!codexClient.refreshCodexUsage) {
8595
8929
  return false;
@@ -8628,16 +8962,13 @@ function xtermThemeFromTokens(root) {
8628
8962
  if (typeof window === "undefined" || typeof getComputedStyle === "undefined") return void 0;
8629
8963
  const el = root ?? document.documentElement;
8630
8964
  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;
8965
+ const read = (name) => {
8966
+ const value = style.getPropertyValue(name).trim();
8967
+ return value || void 0;
8637
8968
  };
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"]);
8969
+ const bg = read("--og-color-bg");
8970
+ const fg = read("--og-color-fg");
8971
+ const accent = read("--og-color-accent");
8641
8972
  const theme = {};
8642
8973
  if (bg) theme.background = bg;
8643
8974
  if (fg) theme.foreground = fg;
@@ -8663,6 +8994,7 @@ export {
8663
8994
  DisclosureDefaultsProvider,
8664
8995
  EnrollmentConsent,
8665
8996
  EnrollmentDeviceFlow,
8997
+ FILE_ONLY_MESSAGE_TEXT,
8666
8998
  FileBrowser,
8667
8999
  FleetTile,
8668
9000
  LightboxProvider,
@@ -8718,6 +9050,7 @@ export {
8718
9050
  gitFileDiffToPatch,
8719
9051
  groupTimeline,
8720
9052
  hasPermission,
9053
+ humanizeFailureReason,
8721
9054
  isApplyPatch,
8722
9055
  isCodexAccountEvent,
8723
9056
  isExecSessionLostBanner,