@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
@@ -84,6 +84,10 @@ type DesktopUiState =
84
84
  | "error" // RFB error / securityfailure after a connect.
85
85
  | "connected"; // live framebuffer painting.
86
86
 
87
+ // Media-inspection exception: the framebuffer sits on true black so screenshots
88
+ // and desktop pixels are not tinted by the product chrome palette.
89
+ const DESKTOP_MEDIA_BACKGROUND = "#000";
90
+
87
91
  /** Reasons that are genuinely-unavailable (never warmable from the viewer). A
88
92
  * `lease_cold` is deliberately EXCLUDED — that's the warmable cold state. */
89
93
  function isHardUnavailable(reason: CapabilityUnavailableReason | null): boolean {
@@ -369,11 +373,11 @@ export function DesktopViewer({
369
373
  return (
370
374
  <div
371
375
  className={cn(
372
- "relative h-full w-full overflow-hidden bg-black",
373
- inControl &&
374
- "ring-2 ring-inset ring-[color:var(--og-color-accent,var(--color-brand,#3b82f6))]",
376
+ "relative h-full w-full overflow-hidden",
377
+ inControl && "ring-2 ring-inset ring-og-accent",
375
378
  className,
376
379
  )}
380
+ style={{ backgroundColor: DESKTOP_MEDIA_BACKGROUND }}
377
381
  data-opengeni-desktop
378
382
  data-state={stream.state}
379
383
  data-ui-state={uiState}
@@ -399,15 +403,15 @@ export function DesktopViewer({
399
403
  `connecting` UI-state (every other non-connected state has an explicit
400
404
  overlay). A spinner + transitional copy makes it feel live. */}
401
405
  {uiState === "connecting" && (
402
- <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))]">
406
+ <div className="pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-3 text-og-fg-subtle">
403
407
  <span className="relative flex items-center justify-center">
404
408
  <MonitorIcon className="size-8 opacity-30" strokeWidth={1.5} />
405
409
  <LoaderCircleIcon
406
- className="absolute size-12 animate-og-spin text-[color:var(--og-color-accent,var(--color-brand,#3b82f6))] opacity-70"
410
+ className="absolute size-12 animate-og-spin text-og-accent opacity-70"
407
411
  strokeWidth={1.25}
408
412
  />
409
413
  </span>
410
- <span className="text-xs">Connecting to the desktop…</span>
414
+ <span className="text-og-sm">Connecting to the desktop…</span>
411
415
  </div>
412
416
  )}
413
417
 
@@ -438,7 +442,7 @@ export function DesktopViewer({
438
442
  !serverAllowsControl
439
443
  ? capability?.client === "frames"
440
444
  ? "View-only — live control isn't available for this machine yet."
441
- : "This deployment streams the desktop read-only"
445
+ : "This deployment streams the desktop read-only."
442
446
  : undefined
443
447
  }
444
448
  onTakeControl={() => setTakeControl(true)}
@@ -481,36 +485,36 @@ function TakeControlCallToAction({
481
485
  title={disabled ? disabledReason : "Take control of the desktop"}
482
486
  onClick={onTakeControl}
483
487
  className={cn(
484
- "group pointer-events-auto flex items-center gap-3 rounded-[var(--og-radius-lg,12px)] border px-5 py-3",
485
- "border-[color:var(--og-color-border,var(--color-border,#2a2a2a))]",
486
- "bg-[color:var(--og-color-bg,#0d0d0d)]/85 backdrop-blur-md",
487
- "shadow-[var(--og-shadow-lg,0_10px_30px_-10px_rgba(0,0,0,0.6))]",
488
+ "group pointer-events-auto flex items-center gap-3 rounded-og-lg border px-5 py-3",
489
+ "border-og-border",
490
+ "bg-og-bg/85 backdrop-blur-md",
491
+ "shadow-og-lg",
488
492
  "outline-none transition-all duration-150 ease-out",
489
- "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",
493
+ "focus-visible:ring-2 focus-visible:ring-og-accent focus-visible:ring-offset-2 focus-visible:ring-offset-og-bg",
490
494
  disabled
491
495
  ? "cursor-not-allowed opacity-60"
492
496
  : cn(
493
497
  "cursor-pointer opacity-90 hover:-translate-y-0.5 hover:opacity-100",
494
- "hover:border-[color:var(--og-color-accent,var(--color-brand,#3b82f6))]",
495
- "hover:bg-[color:var(--og-color-accent,var(--color-brand,#3b82f6))]/10",
498
+ "hover:border-og-accent",
499
+ "hover:bg-og-accent/10",
496
500
  ),
497
501
  )}
498
502
  >
499
503
  <span
500
504
  className={cn(
501
505
  "flex size-9 shrink-0 items-center justify-center rounded-full transition-colors",
502
- "bg-[color:var(--og-color-accent,var(--color-brand,#3b82f6))]",
503
- "text-[color:var(--og-color-accent-fg,#fff)]",
506
+ "bg-og-accent",
507
+ "text-og-accent-fg",
504
508
  disabled ? "" : "group-hover:scale-105",
505
509
  )}
506
510
  >
507
511
  <MousePointerClickIcon className="size-5" strokeWidth={2} />
508
512
  </span>
509
513
  <span className="flex flex-col items-start leading-tight">
510
- <span className="text-sm font-semibold text-[color:var(--og-color-fg,#e6e6e6)]">
514
+ <span className="text-og-base font-semibold text-og-fg">
511
515
  Take control
512
516
  </span>
513
- <span className="text-[11px] text-[color:var(--og-color-fg-subtle,var(--color-fg-subtle,#888))]">
517
+ <span className="text-og-xs text-og-fg-subtle">
514
518
  {disabled && disabledReason ? disabledReason : "Drive the mouse & keyboard"}
515
519
  </span>
516
520
  </span>
@@ -530,15 +534,15 @@ function TakeControlCallToAction({
530
534
  function InControlBar({ shared, onRelease }: { shared: boolean; onRelease: () => void }) {
531
535
  return (
532
536
  <div className="pointer-events-none absolute inset-x-0 top-0 flex items-center justify-between gap-2 p-2">
533
- <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)]">
537
+ <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">
534
538
  <span className="size-1.5 animate-pulse rounded-full bg-current" aria-hidden />
535
539
  You&apos;re in control
536
540
  <span className="opacity-75">· click Return control (or Ctrl+Alt+Shift)</span>
537
541
  </span>
538
542
  <div className="pointer-events-auto flex items-center gap-1.5">
539
543
  {shared && (
540
- <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">
541
- Shared box — others are watching
544
+ <span className="rounded-og-sm bg-og-status-failed/85 px-2 py-0.5 text-og-xs text-og-accent-fg">
545
+ Shared sandbox — others are watching
542
546
  </span>
543
547
  )}
544
548
  <button
@@ -546,9 +550,9 @@ function InControlBar({ shared, onRelease }: { shared: boolean; onRelease: () =>
546
550
  onClick={onRelease}
547
551
  title="Return control (or press Ctrl+Alt+Shift)"
548
552
  className={cn(
549
- "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",
550
- "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",
551
- "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))]",
553
+ "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",
554
+ "border-og-accent bg-og-bg/90 text-og-fg backdrop-blur-sm",
555
+ "outline-none hover:bg-og-accent hover:text-og-accent-fg focus-visible:ring-2 focus-visible:ring-og-accent",
552
556
  )}
553
557
  >
554
558
  <MonitorIcon className="size-3.5" strokeWidth={2} aria-hidden />
@@ -568,7 +572,7 @@ function unavailableCopy(reason: CapabilityUnavailableReason | null): string {
568
572
  case "os_unsupported":
569
573
  return "The sandbox OS does not support a desktop stream.";
570
574
  case "not_provisioned":
571
- return "No display stack is provisioned on this box yet.";
575
+ return "This sandbox doesn't have a desktop yet.";
572
576
  case "disabled_by_policy":
573
577
  return "Desktop streaming is disabled on this deployment.";
574
578
  case "lease_cold":
@@ -589,14 +593,14 @@ function unavailableCopy(reason: CapabilityUnavailableReason | null): string {
589
593
  */
590
594
  function WarmingNotice({ onRetry }: { onRetry?: (() => void) | undefined }) {
591
595
  return (
592
- <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">
596
+ <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">
593
597
  <LoaderCircleIcon
594
- className="size-7 animate-og-spin text-[color:var(--og-color-accent,var(--color-brand,#3b82f6))]"
598
+ className="size-7 animate-og-spin text-og-accent"
595
599
  strokeWidth={1.5}
596
600
  />
597
601
  <div className="space-y-1">
598
602
  <div className="font-medium">Warming the sandbox…</div>
599
- <p className="text-xs text-[color:var(--color-fg-subtle,#888)]">
603
+ <p className="text-og-sm text-og-fg-subtle">
600
604
  Spinning up the desktop — this takes a few seconds.
601
605
  </p>
602
606
  </div>
@@ -604,7 +608,7 @@ function WarmingNotice({ onRetry }: { onRetry?: (() => void) | undefined }) {
604
608
  <button
605
609
  type="button"
606
610
  onClick={onRetry}
607
- 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)]"
611
+ 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"
608
612
  >
609
613
  Taking too long? Retry
610
614
  </button>
@@ -615,19 +619,19 @@ function WarmingNotice({ onRetry }: { onRetry?: (() => void) | undefined }) {
615
619
 
616
620
  function DefaultConsentGate({ shared, onAccept }: { shared: boolean; onAccept: () => void }) {
617
621
  return (
618
- <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)]">
622
+ <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">
619
623
  <div className="mb-1 font-medium">Watch the live desktop?</div>
620
- <p className="mb-3 text-xs text-[color:var(--color-fg-subtle,#888)]">
624
+ <p className="mb-3 text-og-sm text-og-fg-subtle">
621
625
  The desktop pixel stream is <strong>un-redacted</strong> — it can show secrets the agent prints
622
626
  on screen.
623
627
  {shared
624
- ? " This box is shared: you will also see sibling sessions' agents on the same screen."
628
+ ? " This sandbox is shared: you'll also see other sessions' agents on the same screen."
625
629
  : ""}
626
630
  </p>
627
631
  <button
628
632
  type="button"
629
633
  onClick={onAccept}
630
- className="rounded bg-[color:var(--color-brand,#3b82f6)] px-3 py-1.5 text-xs font-medium text-white"
634
+ 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"
631
635
  >
632
636
  I understand — show the desktop
633
637
  </button>
@@ -637,17 +641,17 @@ function DefaultConsentGate({ shared, onAccept }: { shared: boolean; onAccept: (
637
641
 
638
642
  function defaultNotice(title: string, body: string, onRetry?: () => void): ReactNode {
639
643
  return (
640
- <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)]">
644
+ <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">
641
645
  <div className="mb-1 flex items-center justify-center gap-1.5 font-medium">
642
646
  {onRetry && <WifiOffIcon className="size-4 opacity-70" strokeWidth={1.75} />}
643
647
  {title}
644
648
  </div>
645
- <p className="text-xs text-[color:var(--color-fg-subtle,#888)]">{body}</p>
649
+ <p className="text-og-sm text-og-fg-subtle">{body}</p>
646
650
  {onRetry && (
647
651
  <button
648
652
  type="button"
649
653
  onClick={onRetry}
650
- 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))]"
654
+ 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"
651
655
  >
652
656
  Reconnect
653
657
  </button>
@@ -60,8 +60,8 @@ export function DiffView({
60
60
 
61
61
  if (diff.length === 0) {
62
62
  return (
63
- <div className={cn("p-3 text-xs text-[color:var(--color-fg-subtle,#888)]", className)}>
64
- {emptyState ?? (isRepo ? "No changes." : "No repository mounted.")}
63
+ <div className={cn("p-3 text-og-sm text-og-fg-subtle", className)}>
64
+ {emptyState ?? (isRepo ? "No changes" : "No repository mounted")}
65
65
  </div>
66
66
  );
67
67
  }
@@ -93,29 +93,29 @@ function FileDiffBlock({
93
93
  onSelect?: (() => void) | undefined;
94
94
  }) {
95
95
  return (
96
- <section className="mb-2 overflow-hidden rounded border border-[color:var(--color-border,#2a2a2a)]">
96
+ <section className="mb-2 overflow-hidden rounded-og-sm border border-og-border">
97
97
  <header
98
98
  className={cn(
99
- "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",
99
+ "flex items-center justify-between gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-sm",
100
100
  onSelect && "cursor-pointer",
101
101
  )}
102
102
  onClick={onSelect}
103
103
  >
104
- <span className="truncate font-mono">
104
+ <span className="truncate font-og-mono">
105
105
  {file.oldPath && file.oldPath !== file.path ? `${file.oldPath} → ${file.path}` : file.path}
106
106
  </span>
107
107
  <span className="flex shrink-0 items-center gap-2">
108
- <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)]">
108
+ <span className="rounded-og-xs bg-og-bg px-1 py-0.5 text-og-xs text-og-fg-subtle">
109
109
  {STATUS_LABEL[file.status]}
110
110
  </span>
111
- <span className="text-[color:var(--color-success,#3fb950)]">+{file.additions}</span>
112
- <span className="text-[color:var(--color-danger,#f85149)]">−{file.deletions}</span>
111
+ <span className="text-og-status-idle">+{file.additions}</span>
112
+ <span className="text-og-status-failed">−{file.deletions}</span>
113
113
  </span>
114
114
  </header>
115
115
  {file.isBinary ? (
116
- <div className="px-2 py-3 text-xs text-[color:var(--color-fg-subtle,#888)]">Binary file not shown.</div>
116
+ <div className="px-2 py-3 text-og-sm text-og-fg-subtle">Binary file not shown</div>
117
117
  ) : file.truncated ? (
118
- <div className="px-2 py-3 text-xs text-[color:var(--color-fg-subtle,#888)]">Diff too large — truncated.</div>
118
+ <div className="px-2 py-3 text-og-sm text-og-fg-subtle">Diff too large — truncated</div>
119
119
  ) : layout === "split" ? (
120
120
  <SplitHunks file={file} theme={theme} />
121
121
  ) : (
@@ -126,8 +126,8 @@ function FileDiffBlock({
126
126
  }
127
127
 
128
128
  function lineBg(type: GitDiffLine["type"], theme: DiffTheme | undefined): string | undefined {
129
- if (type === "add") return theme?.addBackground ?? "var(--color-diff-add, rgba(63,185,80,0.15))";
130
- if (type === "del") return theme?.delBackground ?? "var(--color-diff-del, rgba(248,81,73,0.15))";
129
+ if (type === "add") return theme?.addBackground ?? "var(--og-color-diff-add-bg)";
130
+ if (type === "del") return theme?.delBackground ?? "var(--og-color-diff-del-bg)";
131
131
  if (type === "meta") return undefined;
132
132
  return theme?.contextBackground;
133
133
  }
@@ -140,11 +140,11 @@ function marker(type: GitDiffLine["type"]): string {
140
140
 
141
141
  function UnifiedHunks({ file, theme }: { file: GitFileDiff; theme: DiffTheme | undefined }) {
142
142
  return (
143
- <div className="font-mono text-[11px] leading-tight">
143
+ <div className="font-og-mono text-og-xs">
144
144
  {file.hunks.map((hunk, hi) => (
145
145
  <div key={`${file.path}-h${hi}`}>
146
146
  <div
147
- className="px-2 py-0.5 text-[color:var(--color-info,#58a6ff)]"
147
+ className="px-2 py-0.5 text-og-accent"
148
148
  style={{ color: theme?.metaForeground }}
149
149
  >
150
150
  {hunk.header}
@@ -155,13 +155,13 @@ function UnifiedHunks({ file, theme }: { file: GitFileDiff; theme: DiffTheme | u
155
155
  className="flex"
156
156
  style={{ backgroundColor: lineBg(line.type, theme) }}
157
157
  >
158
- <span className="w-10 shrink-0 select-none px-1 text-right text-[color:var(--color-fg-subtle,#666)]">
158
+ <span className="w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle">
159
159
  {line.oldNo ?? ""}
160
160
  </span>
161
- <span className="w-10 shrink-0 select-none px-1 text-right text-[color:var(--color-fg-subtle,#666)]">
161
+ <span className="w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle">
162
162
  {line.newNo ?? ""}
163
163
  </span>
164
- <span className="w-4 shrink-0 select-none text-center text-[color:var(--color-fg-subtle,#888)]">
164
+ <span className="w-4 shrink-0 select-none text-center text-og-fg-subtle">
165
165
  {marker(line.type)}
166
166
  </span>
167
167
  <span className="whitespace-pre-wrap break-all px-1">{line.text}</span>
@@ -175,7 +175,7 @@ function UnifiedHunks({ file, theme }: { file: GitFileDiff; theme: DiffTheme | u
175
175
 
176
176
  function SplitHunks({ file, theme }: { file: GitFileDiff; theme: DiffTheme | undefined }) {
177
177
  return (
178
- <div className="font-mono text-[11px] leading-tight">
178
+ <div className="font-og-mono text-og-xs">
179
179
  {file.hunks.map((hunk, hi) => {
180
180
  // Pair del/add lines side-by-side; context spans both columns.
181
181
  const left: (GitDiffLine | null)[] = [];
@@ -193,7 +193,7 @@ function SplitHunks({ file, theme }: { file: GitFileDiff; theme: DiffTheme | und
193
193
  const rows = Math.max(left.length, right.length);
194
194
  return (
195
195
  <div key={`${file.path}-h${hi}`}>
196
- <div className="px-2 py-0.5 text-[color:var(--color-info,#58a6ff)]" style={{ color: theme?.metaForeground }}>
196
+ <div className="px-2 py-0.5 text-og-accent" style={{ color: theme?.metaForeground }}>
197
197
  {hunk.header}
198
198
  </div>
199
199
  {Array.from({ length: rows }).map((_, ri) => {
@@ -205,16 +205,16 @@ function SplitHunks({ file, theme }: { file: GitFileDiff; theme: DiffTheme | und
205
205
  className="flex w-1/2 min-w-0"
206
206
  style={{ backgroundColor: l ? lineBg(l.type, theme) : undefined }}
207
207
  >
208
- <span className="w-10 shrink-0 select-none px-1 text-right text-[color:var(--color-fg-subtle,#666)]">
208
+ <span className="w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle">
209
209
  {l?.oldNo ?? ""}
210
210
  </span>
211
211
  <span className="whitespace-pre-wrap break-all px-1">{l?.text ?? ""}</span>
212
212
  </span>
213
213
  <span
214
- className="flex w-1/2 min-w-0 border-l border-[color:var(--color-border,#2a2a2a)]"
214
+ className="flex w-1/2 min-w-0 border-l border-og-border"
215
215
  style={{ backgroundColor: r ? lineBg(r.type, theme) : undefined }}
216
216
  >
217
- <span className="w-10 shrink-0 select-none px-1 text-right text-[color:var(--color-fg-subtle,#666)]">
217
+ <span className="w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle">
218
218
  {r?.newNo ?? ""}
219
219
  </span>
220
220
  <span className="whitespace-pre-wrap break-all px-1">{r?.text ?? ""}</span>
@@ -43,8 +43,8 @@ function Capability({ icon, title, body }: { icon: ReactNode; title: string; bod
43
43
  <li className="flex items-start gap-2.5">
44
44
  <span className="mt-0.5 shrink-0 text-og-status-failed">{icon}</span>
45
45
  <span className="min-w-0">
46
- <span className="block text-[13px] font-medium text-og-fg">{title}</span>
47
- <span className="block text-[12px] text-og-fg-muted">{body}</span>
46
+ <span className="block text-og-base font-medium text-og-fg">{title}</span>
47
+ <span className="block text-og-sm text-og-fg-muted">{body}</span>
48
48
  </span>
49
49
  </li>
50
50
  );
@@ -113,15 +113,15 @@ export function EnrollmentConsent({
113
113
  <ShieldAlertIcon className="size-5" aria-hidden />
114
114
  </span>
115
115
  <div className="min-w-0">
116
- <h1 className="text-base font-semibold text-og-fg">Give the agent your whole machine?</h1>
117
- <p className="mt-1 text-[13px] text-og-fg-muted">
116
+ <h1 className="text-og-md font-semibold text-og-fg">Give the agent your whole machine?</h1>
117
+ <p className="mt-1 text-og-base text-og-fg-muted">
118
118
  Approving lets the OpenGeni agent run on <span className="font-medium text-og-fg">{machine.machineName}</span> with
119
119
  full access. This is your real computer — not a sandbox.
120
120
  </p>
121
121
  </div>
122
122
  </div>
123
123
 
124
- <div className="flex flex-wrap items-center gap-2 rounded-og-md border border-og-border bg-og-surface-2 px-3 py-2 text-[12px]">
124
+ <div className="flex flex-wrap items-center gap-2 rounded-og-md border border-og-border bg-og-surface-2 px-3 py-2 text-og-sm">
125
125
  <LaptopIcon className="size-4 text-og-fg-subtle" aria-hidden />
126
126
  <span className="font-medium text-og-fg">{machine.machineName}</span>
127
127
  <span className="font-og-mono text-og-fg-subtle">
@@ -163,21 +163,21 @@ export function EnrollmentConsent({
163
163
  checked={allowScreenControl}
164
164
  disabled={busy}
165
165
  onChange={(e) => setAllowScreenControl(e.target.checked)}
166
- className="mt-0.5 size-4 accent-[var(--og-color-accent)]"
166
+ className="mt-0.5 size-4 accent-og-accent"
167
167
  />
168
168
  <span className="min-w-0">
169
- <span className="flex items-center gap-1.5 text-[13px] font-medium text-og-fg">
169
+ <span className="flex items-center gap-1.5 text-og-base font-medium text-og-fg">
170
170
  <ScreenShareIcon className="size-3.5 text-og-fg-muted" aria-hidden />
171
171
  Also let the agent control my mouse & keyboard
172
172
  </span>
173
- <span className="mt-0.5 block text-[12px] text-og-fg-muted">
173
+ <span className="mt-0.5 block text-og-sm text-og-fg-muted">
174
174
  Optional. Enables computer-use — the agent can move the pointer, type, and click on this machine's desktop. Leave
175
175
  off to let it only watch.
176
176
  </span>
177
177
  </span>
178
178
  </label>
179
179
  ) : (
180
- <p className="flex items-start gap-2 rounded-og-md border border-og-border bg-og-bg px-3 py-2 text-[12px] text-og-fg-muted">
180
+ <p className="flex items-start gap-2 rounded-og-md border border-og-border bg-og-bg px-3 py-2 text-og-sm text-og-fg-muted">
181
181
  <CircleAlertIcon className="mt-px size-3.5 shrink-0 text-og-fg-subtle" aria-hidden />
182
182
  This machine has no display, so screen control isn't available — files, terminal, and git only.
183
183
  </p>
@@ -189,7 +189,7 @@ export function EnrollmentConsent({
189
189
  data-deny
190
190
  disabled={busy}
191
191
  onClick={() => onDeny?.()}
192
- className="flex-1 rounded-og-sm border border-og-border px-3 py-2 text-sm font-medium text-og-fg-muted transition-colors hover:border-og-border-strong hover:text-og-fg disabled:opacity-50"
192
+ className="flex-1 rounded-og-sm border border-og-border px-3 py-2 text-og-sm font-medium text-og-fg-muted transition-colors hover:border-og-border-strong hover:text-og-fg disabled:opacity-50 pointer-coarse:min-h-10"
193
193
  >
194
194
  Cancel
195
195
  </button>
@@ -198,7 +198,7 @@ export function EnrollmentConsent({
198
198
  data-approve
199
199
  disabled={busy}
200
200
  onClick={() => onApprove?.(allowScreenControl)}
201
- className="flex-1 rounded-og-sm bg-og-status-failed px-3 py-2 text-sm font-semibold text-white transition-colors hover:opacity-90 disabled:opacity-50"
201
+ className="flex-1 rounded-og-sm bg-og-status-failed px-3 py-2 text-og-sm font-semibold text-og-accent-fg transition-colors hover:opacity-90 disabled:opacity-50 pointer-coarse:min-h-10"
202
202
  >
203
203
  {busy ? "Connecting…" : "Grant full access"}
204
204
  </button>
@@ -238,8 +238,8 @@ function ConsentResult({
238
238
  <span className={cn("flex size-10 items-center justify-center rounded-full bg-og-surface-2", iconClass)}>
239
239
  <LaptopIcon className="size-5" aria-hidden />
240
240
  </span>
241
- <h1 className="text-base font-semibold text-og-fg">{title}</h1>
242
- <p className="max-w-sm text-[13px] text-og-fg-muted">{body}</p>
241
+ <h1 className="text-og-md font-semibold text-og-fg">{title}</h1>
242
+ <p className="max-w-sm text-og-base text-og-fg-muted">{body}</p>
243
243
  </div>
244
244
  );
245
245
  }