replicas-computer 0.3.9 → 0.3.10

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.
@@ -11,9 +11,8 @@
11
11
  </head>
12
12
  <body>
13
13
  <div id="screen"></div>
14
- <div id="status" class="visible" role="status" aria-live="polite">
15
- <img src="./viewer-icon.svg" alt="">
16
- <span id="status-title" aria-hidden="true">Replicas</span>
14
+ <div id="status" class="visible pending" role="status" aria-live="polite">
15
+ <span id="status-spinner" aria-hidden="true"></span>
17
16
  <span id="status-text">connecting…</span>
18
17
  </div>
19
18
  <div id="hint">This desktop runs Linux — ⌘ shortcuts won't work here. Use Ctrl instead (e.g. Ctrl+C / Ctrl+V).</div>
@@ -11,9 +11,8 @@
11
11
  </head>
12
12
  <body>
13
13
  <video id="screen" tabindex="0" aria-label="Replicas desktop" autoplay muted playsinline></video>
14
- <div id="status" class="visible" role="status" aria-live="polite">
15
- <img src="./viewer-icon.svg" alt="">
16
- <span id="status-title" aria-hidden="true">Replicas</span>
14
+ <div id="status" class="visible pending" role="status" aria-live="polite">
15
+ <span id="status-spinner" aria-hidden="true"></span>
17
16
  <span id="status-text">connecting…</span>
18
17
  </div>
19
18
  <button id="audio-prompt" type="button">Enable audio</button>
@@ -11,8 +11,6 @@ html[data-view="native"] body, html[data-view="pixel"] body { width: max-content
11
11
  touch-action: none;
12
12
  }
13
13
 
14
- #status { background: var(--replicas-grid); }
15
-
16
14
  #audio-prompt {
17
15
  position: fixed;
18
16
  right: 16px;
@@ -6,14 +6,6 @@
6
6
  src: url("./geist-mono-400.woff2") format("woff2");
7
7
  }
8
8
 
9
- @font-face {
10
- font-family: "Geist Mono";
11
- font-style: normal;
12
- font-weight: 600;
13
- font-display: swap;
14
- src: url("./geist-mono-600.woff2") format("woff2");
15
- }
16
-
17
9
  @font-face {
18
10
  font-family: "Geist Mono";
19
11
  font-style: normal;
@@ -22,21 +14,10 @@
22
14
  src: url("./geist-mono-700.woff2") format("woff2");
23
15
  }
24
16
 
25
- @font-face {
26
- font-family: "General Sans";
27
- font-style: normal;
28
- font-weight: 300;
29
- font-display: swap;
30
- src: url("./general-sans-300.woff2") format("woff2");
31
- }
32
-
33
17
  :root {
34
18
  --replicas-green: #3cba85;
35
- --replicas-mark-glow: rgb(60 186 133 / 15%);
36
- --replicas-mark-filter: brightness(0.85);
37
19
  --replicas-surface: #121212;
38
20
  --replicas-ink: #ededed;
39
- --replicas-title: #ffffff;
40
21
  --replicas-ink-muted: rgb(255 255 255 / 60%);
41
22
  --replicas-hairline: rgb(255 255 255 / 16%);
42
23
  --replicas-hairline-strong: rgb(255 255 255 / 50%);
@@ -50,11 +31,8 @@
50
31
 
51
32
  :root[data-theme="light"] {
52
33
  --replicas-green: #2fc487;
53
- --replicas-mark-glow: rgb(47 196 135 / 40%);
54
- --replicas-mark-filter: brightness(0.84);
55
34
  --replicas-surface: #f4f5f1;
56
35
  --replicas-ink: #162118;
57
- --replicas-title: #162118;
58
36
  --replicas-ink-muted: rgb(22 33 24 / 60%);
59
37
  --replicas-hairline: rgb(22 33 24 / 14%);
60
38
  --replicas-hairline-strong: rgb(22 33 24 / 45%);
@@ -74,51 +52,52 @@ html, body {
74
52
  #status {
75
53
  position: fixed;
76
54
  inset: 0;
77
- display: flex;
78
- flex-direction: column;
79
- gap: 18px;
80
- align-items: center;
81
- justify-content: center;
55
+ display: grid;
56
+ place-items: center;
82
57
  pointer-events: none;
58
+ background: var(--replicas-surface);
83
59
  opacity: 0;
84
60
  transition: opacity 180ms ease-out;
85
61
  }
86
62
 
87
63
  #status.visible { opacity: 1; }
88
64
 
89
- #status img {
90
- width: 56px;
91
- height: 56px;
92
- filter: var(--replicas-mark-filter) drop-shadow(0 0 18px var(--replicas-mark-glow));
93
- animation: status-pulse 2.4s ease-in-out infinite;
65
+ #status-spinner {
66
+ width: 20px;
67
+ height: 20px;
68
+ box-sizing: border-box;
69
+ border: 2px solid var(--replicas-hairline);
70
+ border-top-color: var(--replicas-ink-muted);
71
+ border-radius: 50%;
72
+ animation: status-spin 0.8s linear infinite;
94
73
  }
95
74
 
96
- @keyframes status-pulse {
97
- 0%, 100% { opacity: 1; }
98
- 50% { opacity: 0.55; }
75
+ @keyframes status-spin {
76
+ to { transform: rotate(360deg); }
99
77
  }
100
78
 
101
79
  @media (prefers-reduced-motion: reduce) {
102
- #status img { animation: none; }
80
+ #status-spinner { animation-duration: 2.4s; }
103
81
  }
104
82
 
105
- #status-title {
106
- color: var(--replicas-title);
107
- font-family: "General Sans", system-ui, sans-serif;
108
- font-size: 30px;
109
- font-weight: 300;
110
- letter-spacing: -0.04em;
111
- line-height: 1;
112
- }
83
+ #status:not(.pending) #status-spinner { display: none; }
113
84
 
114
85
  #status-text {
115
86
  max-width: 72ch;
116
87
  padding: 0 24px;
117
88
  color: var(--replicas-ink-muted);
118
- font-size: 11px;
119
- font-weight: 600;
120
- letter-spacing: 0.12em;
89
+ font-size: 12px;
121
90
  line-height: 1.5;
122
91
  text-align: center;
123
- text-transform: uppercase;
92
+ }
93
+
94
+ /* Progress messages stay readable to screen readers and capture scripts behind the spinner. */
95
+ #status.pending #status-text {
96
+ position: absolute;
97
+ width: 1px;
98
+ height: 1px;
99
+ padding: 0;
100
+ overflow: hidden;
101
+ clip-path: inset(50%);
102
+ white-space: nowrap;
124
103
  }
package/dist/index.js CHANGED
@@ -2937,7 +2937,7 @@ async function computerStatusCommand() {
2937
2937
  }
2938
2938
 
2939
2939
  // src/version.ts
2940
- var COMPUTER_USE_VERSION = "0.3.9";
2940
+ var COMPUTER_USE_VERSION = "0.3.10";
2941
2941
  var COMPUTER_USE_PROTOCOL_VERSION = 1;
2942
2942
 
2943
2943
  // src/program.ts
@@ -5494,13 +5494,13 @@ async function setupComputer(options = {}) {
5494
5494
  mkdirSync6(viewerRoot, { recursive: true });
5495
5495
  cpSync(noVncCore, resolve4(viewerRoot, "core"), { recursive: true, force: true });
5496
5496
  cpSync(noVncVendor, resolve4(viewerRoot, "vendor"), { recursive: true, force: true });
5497
- for (const file of ["novnc-index.html", "viewer.css", "viewer-theme.css", "viewer-theme.js", "viewer-icon.svg", "geist-mono-400.ttf", "geist-mono-600.ttf", "geist-mono-700.ttf", "general-sans-300.ttf"]) {
5497
+ for (const file of ["novnc-index.html", "viewer.css", "viewer-theme.css", "viewer-theme.js", "viewer-icon.svg", "geist-mono-400.ttf", "geist-mono-700.ttf"]) {
5498
5498
  cpSync(resolve4(assets, file), resolve4(viewerRoot, file === "novnc-index.html" ? "index.html" : file), { force: true });
5499
5499
  }
5500
5500
  cpSync(resolve4(packageRoot2, "dist", "viewer.js"), resolve4(viewerRoot, "viewer.js"), { force: true });
5501
5501
  const streamRoot = "/usr/local/share/replicas/desktop/stream";
5502
5502
  mkdirSync6(streamRoot, { recursive: true });
5503
- for (const file of ["stream-index.html", "stream-viewer.css", "viewer-theme.css", "viewer-theme.js", "viewer-icon.svg", "geist-mono-400.ttf", "geist-mono-600.ttf", "geist-mono-700.ttf", "general-sans-300.ttf"]) {
5503
+ for (const file of ["stream-index.html", "stream-viewer.css", "viewer-theme.css", "viewer-theme.js", "viewer-icon.svg", "geist-mono-400.ttf", "geist-mono-700.ttf"]) {
5504
5504
  cpSync(resolve4(assets, file), resolve4(streamRoot, file), { force: true });
5505
5505
  }
5506
5506
  cpSync(resolve4(packageRoot2, "dist", "stream-viewer.js"), resolve4(streamRoot, "stream-viewer.js"), { force: true });
@@ -159,8 +159,9 @@ var note = (event, detail) => {
159
159
  if (viewerEvents.push({ at: Date.now(), event, detail }) > 50) viewerEvents.shift();
160
160
  };
161
161
  var describeEvents = (list) => list.map((entry) => `${new Date(entry.at).toLocaleTimeString([], { hour12: false })} ${entry.event}${entry.detail ? ` (${entry.detail})` : ""}`).join(" \xB7 ");
162
- var showStatus = (message) => {
162
+ var showStatus = (message, pending = false) => {
163
163
  statusText.textContent = message;
164
+ status.classList.toggle("pending", pending);
164
165
  status.classList.add("visible");
165
166
  };
166
167
  var describe = (error) => error instanceof Error ? error.message : String(error);
@@ -298,7 +299,7 @@ var configureVideo = async (next, preferHardware = true) => {
298
299
  videoDecoder = void 0;
299
300
  waitingForKeyframe = true;
300
301
  note("decoder error", error.message);
301
- showStatus(`recovering video: ${error.message}`);
302
+ showStatus(`recovering video: ${error.message}`, true);
302
303
  if (config) void configureVideo(config, false).catch((reason) => showStatus(describe(reason)));
303
304
  }
304
305
  });
@@ -571,7 +572,7 @@ var handleServerMessage = (message, viaSocket) => {
571
572
  webrtcSkips -= 1;
572
573
  useFallback("recent_failure");
573
574
  } else if (!transport) {
574
- showStatus("Establishing connection\u2026");
575
+ showStatus("Establishing connection\u2026", true);
575
576
  webrtcDeadline ??= setTimeout(() => useFallback("video_timeout", true), webrtcFrameTimeoutMs);
576
577
  }
577
578
  };
@@ -603,7 +604,7 @@ var connect = () => {
603
604
  route = { path: "", codec: "", decoded: "", kbps: 0, displayedFps: 0 };
604
605
  announceTransport();
605
606
  socket?.close();
606
- showStatus(reconnectAttempt ? "reconnecting\u2026" : "connecting\u2026");
607
+ showStatus(reconnectAttempt ? "reconnecting\u2026" : "connecting\u2026", true);
607
608
  const query = new URLSearchParams([...params].filter(([key]) => ["transport", "profile", "adapt", "ice"].includes(key)));
608
609
  const nextSocket = new WebSocket(`${location.protocol === "https:" ? "wss" : "ws"}://${location.host}/stream?${query}`);
609
610
  nextSocket.binaryType = "arraybuffer";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-computer",
3
- "version": "0.3.9",
3
+ "version": "0.3.10",
4
4
  "description": "Replicas workspace computer-use runtime",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
Binary file