@opengeni/react 0.6.1 → 0.6.3

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