claude-remote-cli 1.9.0 → 1.9.2
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.
- package/README.md +47 -19
- package/package.json +1 -1
- package/public/app.js +115 -67
- package/public/icon-192.png +0 -0
- package/public/icon-512.png +0 -0
- package/public/icon.svg +6 -0
- package/public/index.html +4 -1
- package/public/manifest.json +18 -1
- package/public/style.css +19 -2
- package/public/sw.js +5 -0
package/README.md
CHANGED
|
@@ -2,30 +2,66 @@
|
|
|
2
2
|
|
|
3
3
|
Remote web interface for interacting with Claude Code CLI sessions from any device.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Getting Started
|
|
6
6
|
|
|
7
|
-
### Install
|
|
7
|
+
### 1. Install
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
npm install -g claude-remote-cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Requires **Node.js 24+** and **[Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code)** installed and available in your PATH.
|
|
14
|
+
|
|
15
|
+
### 2. Start the server
|
|
16
|
+
|
|
17
|
+
```bash
|
|
11
18
|
claude-remote-cli
|
|
12
19
|
```
|
|
13
20
|
|
|
14
|
-
|
|
21
|
+
On first launch you'll be prompted to set a PIN. This PIN protects access to your Claude sessions.
|
|
22
|
+
|
|
23
|
+
Open `http://localhost:3456` in your browser and enter your PIN.
|
|
24
|
+
|
|
25
|
+
### 3. Add your project directories
|
|
26
|
+
|
|
27
|
+
Click **Settings** in the app to add root directories — these are parent folders that contain your git repos (scanned one level deep).
|
|
28
|
+
|
|
29
|
+
You can also edit `~/.config/claude-remote-cli/config.json` directly:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"rootDirs": ["/home/you/projects", "/home/you/work"]
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 4. Run as a background service (recommended)
|
|
38
|
+
|
|
39
|
+
To keep the server running after you close your terminal and auto-start on login:
|
|
15
40
|
|
|
16
41
|
```bash
|
|
17
|
-
|
|
18
|
-
cd claude-remote-cli
|
|
19
|
-
npm install
|
|
20
|
-
npm start
|
|
42
|
+
claude-remote-cli --bg
|
|
21
43
|
```
|
|
22
44
|
|
|
23
|
-
|
|
45
|
+
This installs a persistent service (launchd on macOS, systemd on Linux) that restarts on crash. See [Background Service](#background-service) for more options.
|
|
46
|
+
|
|
47
|
+
### 5. Access from your phone with Tailscale
|
|
48
|
+
|
|
49
|
+
claude-remote-cli binds to `0.0.0.0` by default, but you should **not** expose it to the public internet. Use [Tailscale](https://tailscale.com/) to create a private encrypted network between your devices.
|
|
50
|
+
|
|
51
|
+
1. **Install Tailscale** on your computer (the one running claude-remote-cli) and on your phone/tablet
|
|
52
|
+
- macOS: `brew install tailscale` or download from [tailscale.com/download](https://tailscale.com/download)
|
|
53
|
+
- Linux: follow the [install guide](https://tailscale.com/download/linux)
|
|
54
|
+
- iOS/Android: install the Tailscale app from your app store
|
|
55
|
+
|
|
56
|
+
2. **Sign in** to the same Tailscale account on both devices
|
|
24
57
|
|
|
25
|
-
|
|
58
|
+
3. **Find your computer's Tailscale IP** — run `tailscale ip` on your computer, or check the Tailscale admin console. It will look like `100.x.y.z`.
|
|
26
59
|
|
|
27
|
-
|
|
28
|
-
|
|
60
|
+
4. **Open the app** on your phone at `http://100.x.y.z:3456`
|
|
61
|
+
|
|
62
|
+
That's it. Your traffic is encrypted end-to-end via WireGuard, no ports are exposed to the internet, and only devices on your Tailscale network can reach the server.
|
|
63
|
+
|
|
64
|
+
> **Alternatives:** You can also use [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) (`cloudflared tunnel --url http://localhost:3456`) or [ngrok](https://ngrok.com/) (`ngrok http 3456`), but these expose your server to the public internet and rely on the PIN as your only layer of defense. Tailscale keeps everything private.
|
|
29
65
|
|
|
30
66
|
## Platform Support
|
|
31
67
|
|
|
@@ -150,14 +186,6 @@ claude-remote-cli/
|
|
|
150
186
|
└── package.json
|
|
151
187
|
```
|
|
152
188
|
|
|
153
|
-
## Remote Access
|
|
154
|
-
|
|
155
|
-
To access from your phone or another device, expose the server via a tunnel or VPN:
|
|
156
|
-
|
|
157
|
-
- **Tailscale** (recommended): Install on both devices, access via Tailscale IP
|
|
158
|
-
- **Cloudflare Tunnel**: `cloudflared tunnel --url http://localhost:3456`
|
|
159
|
-
- **ngrok**: `ngrok http 3456`
|
|
160
|
-
|
|
161
189
|
## License
|
|
162
190
|
|
|
163
191
|
MIT
|
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -162,65 +162,59 @@
|
|
|
162
162
|
term.onScroll(updateScrollbar);
|
|
163
163
|
term.onWriteParsed(updateScrollbar);
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
165
|
+
var isMac = /Mac|iPhone|iPad|iPod/.test(navigator.platform || '');
|
|
166
|
+
term.attachCustomKeyEventHandler(function (e) {
|
|
167
|
+
if (isMobileDevice) {
|
|
168
|
+
return false;
|
|
168
169
|
}
|
|
169
|
-
});
|
|
170
170
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
for (var i = 0; i < clipboardItems.length; i++) {
|
|
187
|
-
var types = clipboardItems[i].types;
|
|
188
|
-
for (var j = 0; j < types.length; j++) {
|
|
189
|
-
if (types[j].indexOf('image/') === 0) {
|
|
190
|
-
imageType = types[j];
|
|
191
|
-
imageBlob = clipboardItems[i];
|
|
192
|
-
break;
|
|
193
|
-
}
|
|
171
|
+
if (!isMac && e.type === 'keydown' && e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey &&
|
|
172
|
+
(e.key === 'v' || e.key === 'V')) {
|
|
173
|
+
if (navigator.clipboard && navigator.clipboard.read) {
|
|
174
|
+
navigator.clipboard.read().then(function (clipboardItems) {
|
|
175
|
+
var imageBlob = null;
|
|
176
|
+
var imageType = null;
|
|
177
|
+
|
|
178
|
+
for (var i = 0; i < clipboardItems.length; i++) {
|
|
179
|
+
var types = clipboardItems[i].types;
|
|
180
|
+
for (var j = 0; j < types.length; j++) {
|
|
181
|
+
if (types[j].indexOf('image/') === 0) {
|
|
182
|
+
imageType = types[j];
|
|
183
|
+
imageBlob = clipboardItems[i];
|
|
184
|
+
break;
|
|
194
185
|
}
|
|
195
|
-
if (imageBlob) break;
|
|
196
186
|
}
|
|
187
|
+
if (imageBlob) break;
|
|
188
|
+
}
|
|
197
189
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}).catch(function () {});
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
return false; // Prevent xterm from handling Ctrl+V
|
|
219
|
-
}
|
|
190
|
+
if (imageBlob) {
|
|
191
|
+
imageBlob.getType(imageType).then(function (blob) {
|
|
192
|
+
uploadImage(blob, imageType);
|
|
193
|
+
});
|
|
194
|
+
} else {
|
|
195
|
+
navigator.clipboard.readText().then(function (text) {
|
|
196
|
+
if (text) term.paste(text);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}).catch(function () {
|
|
200
|
+
if (navigator.clipboard.readText) {
|
|
201
|
+
navigator.clipboard.readText().then(function (text) {
|
|
202
|
+
if (text) term.paste(text);
|
|
203
|
+
}).catch(function () {});
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
return false;
|
|
220
207
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return true;
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
term.onData(function (data) {
|
|
214
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
215
|
+
ws.send(data);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
224
218
|
|
|
225
219
|
var resizeObserver = new ResizeObserver(function () {
|
|
226
220
|
fitAddon.fit();
|
|
@@ -255,7 +249,7 @@
|
|
|
255
249
|
}
|
|
256
250
|
|
|
257
251
|
terminalScrollbarThumb.style.display = 'block';
|
|
258
|
-
var thumbHeight = Math.max(20, (term.rows / totalLines) * trackHeight);
|
|
252
|
+
var thumbHeight = Math.max(isMobileDevice ? 44 : 20, (term.rows / totalLines) * trackHeight);
|
|
259
253
|
var thumbTop = (viewportTop / (totalLines - term.rows)) * (trackHeight - thumbHeight);
|
|
260
254
|
|
|
261
255
|
terminalScrollbarThumb.style.height = thumbHeight + 'px';
|
|
@@ -268,7 +262,7 @@
|
|
|
268
262
|
var totalLines = buf.baseY + term.rows;
|
|
269
263
|
if (totalLines <= term.rows) return;
|
|
270
264
|
|
|
271
|
-
var thumbHeight = Math.max(20, (term.rows / totalLines) * terminalScrollbar.clientHeight);
|
|
265
|
+
var thumbHeight = Math.max(isMobileDevice ? 44 : 20, (term.rows / totalLines) * terminalScrollbar.clientHeight);
|
|
272
266
|
var trackUsable = terminalScrollbar.clientHeight - thumbHeight;
|
|
273
267
|
var relativeY = clientY - rect.top - thumbHeight / 2;
|
|
274
268
|
var ratio = Math.max(0, Math.min(1, relativeY / trackUsable));
|
|
@@ -293,7 +287,7 @@
|
|
|
293
287
|
var totalLines = buf.baseY + term.rows;
|
|
294
288
|
if (totalLines <= term.rows) return;
|
|
295
289
|
|
|
296
|
-
var thumbHeight = Math.max(20, (term.rows / totalLines) * terminalScrollbar.clientHeight);
|
|
290
|
+
var thumbHeight = Math.max(isMobileDevice ? 44 : 20, (term.rows / totalLines) * terminalScrollbar.clientHeight);
|
|
297
291
|
var trackUsable = terminalScrollbar.clientHeight - thumbHeight;
|
|
298
292
|
var newTop = Math.max(0, Math.min(trackUsable, scrollbarDragStartTop + deltaY));
|
|
299
293
|
var ratio = newTop / trackUsable;
|
|
@@ -331,7 +325,13 @@
|
|
|
331
325
|
delete attentionSessions[sessionId];
|
|
332
326
|
noSessionMsg.hidden = true;
|
|
333
327
|
term.clear();
|
|
334
|
-
|
|
328
|
+
if (isMobileDevice) {
|
|
329
|
+
mobileInput.value = '';
|
|
330
|
+
mobileInput.dispatchEvent(new Event('sessionchange'));
|
|
331
|
+
mobileInput.focus();
|
|
332
|
+
} else {
|
|
333
|
+
term.focus();
|
|
334
|
+
}
|
|
335
335
|
closeSidebar();
|
|
336
336
|
updateSessionTitle();
|
|
337
337
|
highlightActiveSession();
|
|
@@ -1108,12 +1108,22 @@
|
|
|
1108
1108
|
var text = btn.dataset.text;
|
|
1109
1109
|
var key = btn.dataset.key;
|
|
1110
1110
|
|
|
1111
|
+
// Flush composed text before sending Enter so pending input isn't lost
|
|
1112
|
+
if (key === '\r' && mobileInput.flushComposedText) {
|
|
1113
|
+
mobileInput.flushComposedText();
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1111
1116
|
if (text !== undefined) {
|
|
1112
1117
|
ws.send(text);
|
|
1113
1118
|
} else if (key !== undefined) {
|
|
1114
1119
|
ws.send(key);
|
|
1115
1120
|
}
|
|
1116
1121
|
|
|
1122
|
+
// Clear input after Enter to reset state
|
|
1123
|
+
if (key === '\r' && mobileInput.clearInput) {
|
|
1124
|
+
mobileInput.clearInput();
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1117
1127
|
// Re-focus the mobile input to keep keyboard open
|
|
1118
1128
|
if (isMobileDevice) {
|
|
1119
1129
|
mobileInput.focus();
|
|
@@ -1277,6 +1287,7 @@
|
|
|
1277
1287
|
if (!isMobileDevice) return;
|
|
1278
1288
|
|
|
1279
1289
|
var lastInputValue = '';
|
|
1290
|
+
var isComposing = false;
|
|
1280
1291
|
|
|
1281
1292
|
function focusMobileInput() {
|
|
1282
1293
|
if (document.activeElement !== mobileInput) {
|
|
@@ -1336,6 +1347,50 @@
|
|
|
1336
1347
|
}
|
|
1337
1348
|
}
|
|
1338
1349
|
|
|
1350
|
+
mobileInput.addEventListener('compositionstart', function () {
|
|
1351
|
+
isComposing = true;
|
|
1352
|
+
});
|
|
1353
|
+
|
|
1354
|
+
mobileInput.addEventListener('compositionend', function () {
|
|
1355
|
+
isComposing = false;
|
|
1356
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
1357
|
+
var currentValue = mobileInput.value;
|
|
1358
|
+
sendInputDiff(currentValue);
|
|
1359
|
+
lastInputValue = currentValue;
|
|
1360
|
+
}
|
|
1361
|
+
});
|
|
1362
|
+
|
|
1363
|
+
mobileInput.addEventListener('blur', function () {
|
|
1364
|
+
if (isComposing) {
|
|
1365
|
+
isComposing = false;
|
|
1366
|
+
lastInputValue = mobileInput.value;
|
|
1367
|
+
}
|
|
1368
|
+
});
|
|
1369
|
+
|
|
1370
|
+
mobileInput.addEventListener('sessionchange', function () {
|
|
1371
|
+
isComposing = false;
|
|
1372
|
+
lastInputValue = '';
|
|
1373
|
+
});
|
|
1374
|
+
|
|
1375
|
+
// Flush any pending composed text to the terminal.
|
|
1376
|
+
// Safe to call even if compositionend already ran: sendInputDiff
|
|
1377
|
+
// is a no-op when lastInputValue === mobileInput.value.
|
|
1378
|
+
function flushComposedText() {
|
|
1379
|
+
isComposing = false;
|
|
1380
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
1381
|
+
var currentValue = mobileInput.value;
|
|
1382
|
+
sendInputDiff(currentValue);
|
|
1383
|
+
lastInputValue = currentValue;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
function clearInput() {
|
|
1387
|
+
mobileInput.value = '';
|
|
1388
|
+
lastInputValue = '';
|
|
1389
|
+
}
|
|
1390
|
+
// Expose for toolbar handler
|
|
1391
|
+
mobileInput.flushComposedText = flushComposedText;
|
|
1392
|
+
mobileInput.clearInput = clearInput;
|
|
1393
|
+
|
|
1339
1394
|
// Handle text input with autocorrect
|
|
1340
1395
|
var clearTimer = null;
|
|
1341
1396
|
mobileInput.addEventListener('input', function () {
|
|
@@ -1348,6 +1403,8 @@
|
|
|
1348
1403
|
|
|
1349
1404
|
if (!ws || ws.readyState !== WebSocket.OPEN) return;
|
|
1350
1405
|
|
|
1406
|
+
if (isComposing) return;
|
|
1407
|
+
|
|
1351
1408
|
var currentValue = mobileInput.value;
|
|
1352
1409
|
sendInputDiff(currentValue);
|
|
1353
1410
|
lastInputValue = currentValue;
|
|
@@ -1361,6 +1418,7 @@
|
|
|
1361
1418
|
|
|
1362
1419
|
switch (e.key) {
|
|
1363
1420
|
case 'Enter':
|
|
1421
|
+
flushComposedText();
|
|
1364
1422
|
ws.send('\r');
|
|
1365
1423
|
mobileInput.value = '';
|
|
1366
1424
|
lastInputValue = '';
|
|
@@ -1379,24 +1437,14 @@
|
|
|
1379
1437
|
lastInputValue = '';
|
|
1380
1438
|
break;
|
|
1381
1439
|
case 'Tab':
|
|
1382
|
-
e.preventDefault();
|
|
1383
1440
|
ws.send('\t');
|
|
1384
1441
|
break;
|
|
1385
1442
|
case 'ArrowUp':
|
|
1386
|
-
e.preventDefault();
|
|
1387
1443
|
ws.send('\x1b[A');
|
|
1388
1444
|
break;
|
|
1389
1445
|
case 'ArrowDown':
|
|
1390
|
-
e.preventDefault();
|
|
1391
1446
|
ws.send('\x1b[B');
|
|
1392
1447
|
break;
|
|
1393
|
-
case 'ArrowLeft':
|
|
1394
|
-
// Let input handle cursor movement for autocorrect
|
|
1395
|
-
handled = false;
|
|
1396
|
-
break;
|
|
1397
|
-
case 'ArrowRight':
|
|
1398
|
-
handled = false;
|
|
1399
|
-
break;
|
|
1400
1448
|
default:
|
|
1401
1449
|
handled = false;
|
|
1402
1450
|
}
|
|
Binary file
|
|
Binary file
|
package/public/icon.svg
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
2
|
+
<rect width="512" height="512" rx="64" fill="#1a1a1a"/>
|
|
3
|
+
<text x="256" y="200" text-anchor="middle" font-family="monospace" font-size="72" font-weight="bold" fill="#d97757">>_</text>
|
|
4
|
+
<text x="256" y="320" text-anchor="middle" font-family="-apple-system,sans-serif" font-size="56" font-weight="600" fill="#ececec">Claude</text>
|
|
5
|
+
<text x="256" y="390" text-anchor="middle" font-family="-apple-system,sans-serif" font-size="40" fill="#9b9b9b">Remote CLI</text>
|
|
6
|
+
</svg>
|
package/public/index.html
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
|
|
6
6
|
<title>Claude Remote CLI</title>
|
|
7
7
|
<link rel="manifest" href="/manifest.json" />
|
|
8
|
+
<link rel="icon" href="/icon.svg" type="image/svg+xml" />
|
|
9
|
+
<link rel="apple-touch-icon" href="/icon-192.png" />
|
|
8
10
|
<meta name="mobile-web-app-capable" content="yes" />
|
|
9
11
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
10
12
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
@@ -64,7 +66,7 @@
|
|
|
64
66
|
<button id="menu-btn" class="icon-btn" aria-label="Open sessions menu">☰</button>
|
|
65
67
|
<span id="session-title" class="mobile-title">No session</span>
|
|
66
68
|
</div>
|
|
67
|
-
<input type="text" id="mobile-input" autocomplete="
|
|
69
|
+
<input type="text" id="mobile-input" dir="ltr" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" aria-label="Terminal input" />
|
|
68
70
|
<div id="terminal-container"></div>
|
|
69
71
|
<div id="terminal-scrollbar"><div id="terminal-scrollbar-thumb"></div></div>
|
|
70
72
|
<div id="no-session-msg">No active session. Create or select a session to begin.</div>
|
|
@@ -182,5 +184,6 @@
|
|
|
182
184
|
<script src="/vendor/xterm.js"></script>
|
|
183
185
|
<script src="/vendor/addon-fit.js"></script>
|
|
184
186
|
<script src="/app.js"></script>
|
|
187
|
+
<script>if ('serviceWorker' in navigator) navigator.serviceWorker.register('/sw.js');</script>
|
|
185
188
|
</body>
|
|
186
189
|
</html>
|
package/public/manifest.json
CHANGED
|
@@ -4,5 +4,22 @@
|
|
|
4
4
|
"display": "standalone",
|
|
5
5
|
"start_url": "/",
|
|
6
6
|
"background_color": "#1a1a1a",
|
|
7
|
-
"theme_color": "#1a1a1a"
|
|
7
|
+
"theme_color": "#1a1a1a",
|
|
8
|
+
"icons": [
|
|
9
|
+
{
|
|
10
|
+
"src": "/icon-192.png",
|
|
11
|
+
"sizes": "192x192",
|
|
12
|
+
"type": "image/png"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"src": "/icon-512.png",
|
|
16
|
+
"sizes": "512x512",
|
|
17
|
+
"type": "image/png"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"src": "/icon.svg",
|
|
21
|
+
"sizes": "any",
|
|
22
|
+
"type": "image/svg+xml"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
8
25
|
}
|
package/public/style.css
CHANGED
|
@@ -470,13 +470,20 @@ html, body {
|
|
|
470
470
|
|
|
471
471
|
#mobile-input {
|
|
472
472
|
position: absolute;
|
|
473
|
-
|
|
474
|
-
|
|
473
|
+
left: 0;
|
|
474
|
+
top: 0;
|
|
475
475
|
width: 1px;
|
|
476
476
|
height: 1px;
|
|
477
477
|
opacity: 0;
|
|
478
478
|
font-size: 16px; /* prevents iOS zoom on focus */
|
|
479
479
|
z-index: -1;
|
|
480
|
+
border: 0;
|
|
481
|
+
padding: 0;
|
|
482
|
+
margin: 0;
|
|
483
|
+
outline: none;
|
|
484
|
+
color: transparent;
|
|
485
|
+
caret-color: transparent;
|
|
486
|
+
background: transparent;
|
|
480
487
|
}
|
|
481
488
|
|
|
482
489
|
/* ===== Terminal Scrollbar ===== */
|
|
@@ -1082,6 +1089,16 @@ dialog#delete-worktree-dialog h2 {
|
|
|
1082
1089
|
|
|
1083
1090
|
#terminal-scrollbar {
|
|
1084
1091
|
display: block;
|
|
1092
|
+
width: 24px;
|
|
1093
|
+
right: 0;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
#terminal-scrollbar-thumb {
|
|
1097
|
+
width: 24px;
|
|
1098
|
+
min-height: 44px;
|
|
1099
|
+
border-radius: 12px;
|
|
1100
|
+
background: var(--text-muted);
|
|
1101
|
+
opacity: 0.5;
|
|
1085
1102
|
}
|
|
1086
1103
|
}
|
|
1087
1104
|
|