@agent-native/core 0.77.11 → 0.77.13

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.
@@ -103,6 +103,7 @@ interface PendingNativeUpload {
103
103
  lastAttemptAt?: string | null;
104
104
  lastError?: string | null;
105
105
  retryCount: number;
106
+ corrupt?: boolean;
106
107
  }
107
108
 
108
109
  type PendingDesktopUpload = PendingNativeUpload | PendingBrowserRecordingUpload;
@@ -2474,25 +2475,40 @@ function PendingUploadBanner({
2474
2475
  <IconDownload size={14} stroke={2} />
2475
2476
  </button>
2476
2477
  ) : null}
2477
- <button
2478
- type="button"
2479
- className="pending-upload-retry"
2480
- disabled={actionsDisabled}
2481
- onClick={() => onRetry(latest)}
2482
- >
2483
- <IconRefresh size={14} stroke={2} />
2484
- {retrying ? "Retrying" : "Retry"}
2485
- </button>
2486
- <button
2487
- type="button"
2488
- className="pending-upload-discard"
2489
- disabled={actionsDisabled}
2490
- onClick={() => onDiscard(latest)}
2491
- aria-label="Discard saved local clip"
2492
- title="Discard saved local clip"
2493
- >
2494
- <IconTrash size={14} stroke={2} />
2495
- </button>
2478
+ {latest.kind === "native" && latest.corrupt ? (
2479
+ <button
2480
+ type="button"
2481
+ className="pending-upload-discard"
2482
+ disabled={actionsDisabled}
2483
+ onClick={() => onDiscard(latest)}
2484
+ aria-label="Discard corrupted clip"
2485
+ title="This clip is corrupted and cannot be recovered. Discard it and record again."
2486
+ >
2487
+ <IconTrash size={14} stroke={2} />
2488
+ </button>
2489
+ ) : (
2490
+ <>
2491
+ <button
2492
+ type="button"
2493
+ className="pending-upload-retry"
2494
+ disabled={actionsDisabled}
2495
+ onClick={() => onRetry(latest)}
2496
+ >
2497
+ <IconRefresh size={14} stroke={2} />
2498
+ {retrying ? "Retrying" : "Retry"}
2499
+ </button>
2500
+ <button
2501
+ type="button"
2502
+ className="pending-upload-discard"
2503
+ disabled={actionsDisabled}
2504
+ onClick={() => onDiscard(latest)}
2505
+ aria-label="Discard saved local clip"
2506
+ title="Discard saved local clip"
2507
+ >
2508
+ <IconTrash size={14} stroke={2} />
2509
+ </button>
2510
+ </>
2511
+ )}
2496
2512
  </div>
2497
2513
  </div>
2498
2514
  );
@@ -1,4 +1,5 @@
1
1
  import {
2
+ IconAlertTriangle,
2
3
  IconLoader2,
3
4
  IconPlayerPauseFilled,
4
5
  IconPlayerPlayFilled,
@@ -57,6 +58,9 @@ export function Toolbar() {
57
58
  // Stop / Pause are disabled until the recorder actually begins, at which
58
59
  // point `clips:toolbar-enabled` fires with `true` from the recorder.
59
60
  const [enabled, setEnabled] = useState(false);
61
+ const [diskSpaceLevel, setDiskSpaceLevel] = useState<
62
+ "ok" | "warning" | "critical"
63
+ >("ok");
60
64
  const fallbackTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
61
65
  const expandedRef = useRef(false);
62
66
 
@@ -94,6 +98,26 @@ export function Toolbar() {
94
98
  trackListen(
95
99
  listen<boolean>("clips:toolbar-enabled", (ev) => {
96
100
  setEnabled(!!ev.payload);
101
+ if (!ev.payload) {
102
+ setDiskSpaceLevel("ok");
103
+ }
104
+ }),
105
+ );
106
+ trackListen(
107
+ listen<{ freeMb: number }>("clips:disk-space-warning", () => {
108
+ setDiskSpaceLevel((prev) =>
109
+ prev === "critical" ? "critical" : "warning",
110
+ );
111
+ }),
112
+ );
113
+ trackListen(
114
+ listen<{ freeMb: number }>("clips:disk-space-critical", () => {
115
+ setDiskSpaceLevel("critical");
116
+ }),
117
+ );
118
+ trackListen(
119
+ listen<{ freeMb: number }>("clips:disk-space-ok", () => {
120
+ setDiskSpaceLevel("ok");
97
121
  }),
98
122
  );
99
123
  return () => {
@@ -221,7 +245,7 @@ export function Toolbar() {
221
245
 
222
246
  return (
223
247
  <div
224
- className={`toolbar-v ${paused ? "toolbar-v-paused" : ""} ${enabled ? "" : "toolbar-v-disabled"}`}
248
+ className={`toolbar-v ${paused ? "toolbar-v-paused" : ""} ${enabled ? "" : "toolbar-v-disabled"} ${diskSpaceLevel !== "ok" ? `toolbar-v-disk-${diskSpaceLevel}` : ""}`}
225
249
  onMouseDown={handleToolbarMouseDown}
226
250
  onMouseEnter={() => resizeToolbarWindow(true)}
227
251
  onMouseLeave={() => resizeToolbarWindow(false)}
@@ -257,6 +281,19 @@ export function Toolbar() {
257
281
  )}
258
282
  </button>
259
283
  <div className="toolbar-v-time">{formatTime(elapsed)}</div>
284
+ {diskSpaceLevel !== "ok" && (
285
+ <div
286
+ className={`toolbar-v-disk-indicator toolbar-v-disk-indicator-${diskSpaceLevel}`}
287
+ title={
288
+ diskSpaceLevel === "critical"
289
+ ? "Disk almost full — stop recording now to avoid losing your clip"
290
+ : "Low disk space — save your recording soon"
291
+ }
292
+ data-no-drag
293
+ >
294
+ <IconAlertTriangle size={12} />
295
+ </div>
296
+ )}
260
297
  <button
261
298
  className="toolbar-v-pause"
262
299
  onClick={togglePause}
@@ -2676,12 +2676,47 @@ body[data-clips-route="recording-pill"] #root {
2676
2676
  cursor: not-allowed;
2677
2677
  }
2678
2678
 
2679
+ .toolbar-v-disk-indicator {
2680
+ display: flex;
2681
+ align-items: center;
2682
+ justify-content: center;
2683
+ color: #f59e0b;
2684
+ opacity: 0.9;
2685
+ flex-shrink: 0;
2686
+ }
2687
+
2688
+ .toolbar-v-disk-indicator-critical {
2689
+ color: #ef4444;
2690
+ animation: toolbar-v-disk-pulse 1.4s ease-in-out infinite;
2691
+ }
2692
+
2693
+ @keyframes toolbar-v-disk-pulse {
2694
+ 0%,
2695
+ 100% {
2696
+ opacity: 0.7;
2697
+ }
2698
+ 50% {
2699
+ opacity: 1;
2700
+ }
2701
+ }
2702
+
2703
+ .toolbar-v-disk-warning {
2704
+ border-color: rgba(245, 158, 11, 0.45);
2705
+ }
2706
+
2707
+ .toolbar-v-disk-critical {
2708
+ border-color: rgba(239, 68, 68, 0.5);
2709
+ }
2710
+
2679
2711
  @media (prefers-reduced-motion: reduce) {
2680
2712
  .toolbar-v,
2681
2713
  .toolbar-v-hover-actions,
2682
2714
  .toolbar-v-action {
2683
2715
  transition: none;
2684
2716
  }
2717
+ .toolbar-v-disk-indicator-critical {
2718
+ animation: none;
2719
+ }
2685
2720
  }
2686
2721
 
2687
2722
  /* ------------------------------------------------------------------------- */