claude-remote-cli 2.4.4 → 2.4.6
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/dist/frontend/assets/index-BYzn7owE.css +32 -0
- package/dist/frontend/assets/{index-D5L5xi4X.js → index-Bqy4cyeJ.js} +16 -16
- package/dist/frontend/index.html +2 -2
- package/dist/server/index.js +48 -22
- package/dist/server/sessions.js +5 -3
- package/dist/server/watcher.js +27 -0
- package/dist/test/sessions.test.js +50 -0
- package/dist/test/worktrees.test.js +115 -1
- package/package.json +1 -1
- package/dist/frontend/assets/index-BV4uKxaj.css +0 -32
package/dist/frontend/index.html
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
12
12
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
13
13
|
<meta name="theme-color" content="#1a1a1a" />
|
|
14
|
-
<script type="module" crossorigin src="/assets/index-
|
|
15
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
14
|
+
<script type="module" crossorigin src="/assets/index-Bqy4cyeJ.js"></script>
|
|
15
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BYzn7owE.css">
|
|
16
16
|
</head>
|
|
17
17
|
<body>
|
|
18
18
|
<div id="app"></div>
|
package/dist/server/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import { loadConfig, saveConfig, DEFAULTS, readMeta, writeMeta, deleteMeta, ensu
|
|
|
12
12
|
import * as auth from './auth.js';
|
|
13
13
|
import * as sessions from './sessions.js';
|
|
14
14
|
import { setupWebSocket } from './ws.js';
|
|
15
|
-
import { WorktreeWatcher, WORKTREE_DIRS, isValidWorktreePath } from './watcher.js';
|
|
15
|
+
import { WorktreeWatcher, WORKTREE_DIRS, isValidWorktreePath, parseWorktreeListPorcelain } from './watcher.js';
|
|
16
16
|
import { isInstalled as serviceIsInstalled } from './service.js';
|
|
17
17
|
import { extensionForMime, setClipboardImage } from './clipboard.js';
|
|
18
18
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -384,7 +384,7 @@ async function main() {
|
|
|
384
384
|
res.json(response);
|
|
385
385
|
});
|
|
386
386
|
// GET /worktrees?repo=<path> — list worktrees; omit repo to scan all repos in all rootDirs
|
|
387
|
-
app.get('/worktrees', requireAuth, (req, res) => {
|
|
387
|
+
app.get('/worktrees', requireAuth, async (req, res) => {
|
|
388
388
|
const repoParam = typeof req.query.repo === 'string' ? req.query.repo : undefined;
|
|
389
389
|
const roots = config.rootDirs || [];
|
|
390
390
|
const worktrees = [];
|
|
@@ -397,31 +397,54 @@ async function main() {
|
|
|
397
397
|
reposToScan = scanAllRepos(roots);
|
|
398
398
|
}
|
|
399
399
|
for (const repo of reposToScan) {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
continue;
|
|
408
|
-
}
|
|
409
|
-
for (const entry of entries) {
|
|
410
|
-
if (!entry.isDirectory())
|
|
411
|
-
continue;
|
|
412
|
-
const wtPath = path.join(worktreeDir, entry.name);
|
|
413
|
-
const meta = readMeta(CONFIG_PATH, wtPath);
|
|
400
|
+
// Use git worktree list to discover all worktrees (including those at arbitrary paths)
|
|
401
|
+
try {
|
|
402
|
+
const { stdout } = await execFileAsync('git', ['worktree', 'list', '--porcelain'], { cwd: repo.path });
|
|
403
|
+
const parsed = parseWorktreeListPorcelain(stdout, repo.path);
|
|
404
|
+
for (const wt of parsed) {
|
|
405
|
+
const dirName = wt.path.split('/').pop() || '';
|
|
406
|
+
const meta = readMeta(CONFIG_PATH, wt.path);
|
|
414
407
|
worktrees.push({
|
|
415
|
-
name:
|
|
416
|
-
path:
|
|
408
|
+
name: dirName,
|
|
409
|
+
path: wt.path,
|
|
417
410
|
repoName: repo.name,
|
|
418
411
|
repoPath: repo.path,
|
|
419
412
|
root: repo.root,
|
|
420
|
-
displayName: meta
|
|
421
|
-
lastActivity: meta
|
|
413
|
+
displayName: meta?.displayName || wt.branch || dirName,
|
|
414
|
+
lastActivity: meta?.lastActivity || '',
|
|
415
|
+
branchName: wt.branch || meta?.branchName || dirName,
|
|
422
416
|
});
|
|
423
417
|
}
|
|
424
418
|
}
|
|
419
|
+
catch {
|
|
420
|
+
// git worktree list failed — fall back to directory scanning
|
|
421
|
+
for (const dir of WORKTREE_DIRS) {
|
|
422
|
+
const worktreeDir = path.join(repo.path, dir);
|
|
423
|
+
let entries;
|
|
424
|
+
try {
|
|
425
|
+
entries = fs.readdirSync(worktreeDir, { withFileTypes: true });
|
|
426
|
+
}
|
|
427
|
+
catch (_) {
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
for (const entry of entries) {
|
|
431
|
+
if (!entry.isDirectory())
|
|
432
|
+
continue;
|
|
433
|
+
const wtPath = path.join(worktreeDir, entry.name);
|
|
434
|
+
const meta = readMeta(CONFIG_PATH, wtPath);
|
|
435
|
+
worktrees.push({
|
|
436
|
+
name: entry.name,
|
|
437
|
+
path: wtPath,
|
|
438
|
+
repoName: repo.name,
|
|
439
|
+
repoPath: repo.path,
|
|
440
|
+
root: repo.root,
|
|
441
|
+
displayName: meta?.displayName || '',
|
|
442
|
+
lastActivity: meta?.lastActivity || '',
|
|
443
|
+
branchName: meta?.branchName || entry.name,
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
425
448
|
}
|
|
426
449
|
res.json(worktrees);
|
|
427
450
|
});
|
|
@@ -555,13 +578,15 @@ async function main() {
|
|
|
555
578
|
dirName = 'mobile-' + name + '-' + Date.now().toString(36);
|
|
556
579
|
resolvedBranch = dirName;
|
|
557
580
|
}
|
|
558
|
-
const worktreeDir = path.join(repoPath,
|
|
581
|
+
const worktreeDir = path.join(repoPath, WORKTREE_DIRS[0]);
|
|
559
582
|
let targetDir = path.join(worktreeDir, dirName);
|
|
560
583
|
if (fs.existsSync(targetDir)) {
|
|
561
584
|
targetDir = targetDir + '-' + Date.now().toString(36);
|
|
562
585
|
dirName = path.basename(targetDir);
|
|
563
586
|
}
|
|
564
|
-
|
|
587
|
+
for (const dir of WORKTREE_DIRS) {
|
|
588
|
+
ensureGitignore(repoPath, dir + '/');
|
|
589
|
+
}
|
|
565
590
|
try {
|
|
566
591
|
// Check if branch exists locally or on a remote
|
|
567
592
|
let branchExists = false;
|
|
@@ -605,6 +630,7 @@ async function main() {
|
|
|
605
630
|
cwd,
|
|
606
631
|
root,
|
|
607
632
|
worktreeName,
|
|
633
|
+
branchName: branchName || worktreeName,
|
|
608
634
|
displayName,
|
|
609
635
|
command: config.claudeCommand,
|
|
610
636
|
args,
|
package/dist/server/sessions.js
CHANGED
|
@@ -11,7 +11,7 @@ let idleChangeCallback = null;
|
|
|
11
11
|
function onIdleChange(cb) {
|
|
12
12
|
idleChangeCallback = cb;
|
|
13
13
|
}
|
|
14
|
-
function create({ type, repoName, repoPath, cwd, root, worktreeName, displayName, command, args = [], cols = 80, rows = 24, configPath }) {
|
|
14
|
+
function create({ type, repoName, repoPath, cwd, root, worktreeName, branchName, displayName, command, args = [], cols = 80, rows = 24, configPath }) {
|
|
15
15
|
const id = crypto.randomBytes(8).toString('hex');
|
|
16
16
|
const createdAt = new Date().toISOString();
|
|
17
17
|
// Strip CLAUDECODE env var to allow spawning claude inside a claude-managed server
|
|
@@ -35,6 +35,7 @@ function create({ type, repoName, repoPath, cwd, root, worktreeName, displayName
|
|
|
35
35
|
repoName: repoName || '',
|
|
36
36
|
repoPath,
|
|
37
37
|
worktreeName: worktreeName || '',
|
|
38
|
+
branchName: branchName || worktreeName || '',
|
|
38
39
|
displayName: displayName || worktreeName || repoName || '',
|
|
39
40
|
pty: ptyProcess,
|
|
40
41
|
createdAt,
|
|
@@ -97,20 +98,21 @@ function create({ type, repoName, repoPath, cwd, root, worktreeName, displayName
|
|
|
97
98
|
const tmpDir = path.join(os.tmpdir(), 'claude-remote-cli', id);
|
|
98
99
|
fs.rm(tmpDir, { recursive: true, force: true }, () => { });
|
|
99
100
|
});
|
|
100
|
-
return { id, type: session.type, root: session.root, repoName: session.repoName, repoPath, worktreeName: session.worktreeName, displayName: session.displayName, pid: ptyProcess.pid, createdAt, lastActivity: createdAt, idle: false };
|
|
101
|
+
return { id, type: session.type, root: session.root, repoName: session.repoName, repoPath, worktreeName: session.worktreeName, branchName: session.branchName, displayName: session.displayName, pid: ptyProcess.pid, createdAt, lastActivity: createdAt, idle: false };
|
|
101
102
|
}
|
|
102
103
|
function get(id) {
|
|
103
104
|
return sessions.get(id);
|
|
104
105
|
}
|
|
105
106
|
function list() {
|
|
106
107
|
return Array.from(sessions.values())
|
|
107
|
-
.map(({ id, type, root, repoName, repoPath, worktreeName, displayName, createdAt, lastActivity, idle }) => ({
|
|
108
|
+
.map(({ id, type, root, repoName, repoPath, worktreeName, branchName, displayName, createdAt, lastActivity, idle }) => ({
|
|
108
109
|
id,
|
|
109
110
|
type,
|
|
110
111
|
root,
|
|
111
112
|
repoName,
|
|
112
113
|
repoPath,
|
|
113
114
|
worktreeName,
|
|
115
|
+
branchName,
|
|
114
116
|
displayName,
|
|
115
117
|
createdAt,
|
|
116
118
|
lastActivity,
|
package/dist/server/watcher.js
CHANGED
|
@@ -8,6 +8,33 @@ export function isValidWorktreePath(worktreePath) {
|
|
|
8
8
|
return resolved.includes(path.sep + dir + path.sep);
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Parse `git worktree list --porcelain` output into structured entries.
|
|
13
|
+
* Skips the main worktree (matching repoPath) and bare/detached entries.
|
|
14
|
+
*/
|
|
15
|
+
export function parseWorktreeListPorcelain(stdout, repoPath) {
|
|
16
|
+
const results = [];
|
|
17
|
+
const blocks = stdout.split('\n\n').filter(Boolean);
|
|
18
|
+
for (const block of blocks) {
|
|
19
|
+
const lines = block.split('\n');
|
|
20
|
+
let wtPath = '';
|
|
21
|
+
let branch = '';
|
|
22
|
+
let bare = false;
|
|
23
|
+
for (const line of lines) {
|
|
24
|
+
if (line.startsWith('worktree '))
|
|
25
|
+
wtPath = line.slice(9);
|
|
26
|
+
if (line.startsWith('branch refs/heads/'))
|
|
27
|
+
branch = line.slice(18);
|
|
28
|
+
if (line === 'bare')
|
|
29
|
+
bare = true;
|
|
30
|
+
}
|
|
31
|
+
// Skip the main worktree (repo root), bare repos, and detached HEAD
|
|
32
|
+
if (!wtPath || wtPath === repoPath || bare || !branch)
|
|
33
|
+
continue;
|
|
34
|
+
results.push({ path: wtPath, branch });
|
|
35
|
+
}
|
|
36
|
+
return results;
|
|
37
|
+
}
|
|
11
38
|
export class WorktreeWatcher extends EventEmitter {
|
|
12
39
|
_watchers;
|
|
13
40
|
_debounceTimer;
|
|
@@ -214,4 +214,54 @@ describe('sessions', () => {
|
|
|
214
214
|
const found = sessions.findRepoSession('/tmp/my-repo');
|
|
215
215
|
assert.strictEqual(found, undefined, 'should not match worktree sessions');
|
|
216
216
|
});
|
|
217
|
+
it('branchName defaults to worktreeName when not specified', () => {
|
|
218
|
+
const result = sessions.create({
|
|
219
|
+
repoName: 'test-repo',
|
|
220
|
+
repoPath: '/tmp',
|
|
221
|
+
worktreeName: 'dy-feat-my-feature',
|
|
222
|
+
command: '/bin/echo',
|
|
223
|
+
args: ['hello'],
|
|
224
|
+
});
|
|
225
|
+
createdIds.push(result.id);
|
|
226
|
+
assert.strictEqual(result.branchName, 'dy-feat-my-feature');
|
|
227
|
+
});
|
|
228
|
+
it('branchName is set independently from worktreeName', () => {
|
|
229
|
+
const result = sessions.create({
|
|
230
|
+
repoName: 'test-repo',
|
|
231
|
+
repoPath: '/tmp',
|
|
232
|
+
worktreeName: 'dy-feat-my-feature',
|
|
233
|
+
branchName: 'dy/feat/my-feature',
|
|
234
|
+
command: '/bin/echo',
|
|
235
|
+
args: ['hello'],
|
|
236
|
+
});
|
|
237
|
+
createdIds.push(result.id);
|
|
238
|
+
assert.strictEqual(result.worktreeName, 'dy-feat-my-feature');
|
|
239
|
+
assert.strictEqual(result.branchName, 'dy/feat/my-feature');
|
|
240
|
+
});
|
|
241
|
+
it('list includes branchName field', () => {
|
|
242
|
+
const result = sessions.create({
|
|
243
|
+
repoName: 'test-repo',
|
|
244
|
+
repoPath: '/tmp',
|
|
245
|
+
worktreeName: 'my-wt',
|
|
246
|
+
branchName: 'feat/my-branch',
|
|
247
|
+
command: '/bin/echo',
|
|
248
|
+
args: ['hello'],
|
|
249
|
+
});
|
|
250
|
+
createdIds.push(result.id);
|
|
251
|
+
const list = sessions.list();
|
|
252
|
+
const session = list.find(s => s.id === result.id);
|
|
253
|
+
assert.ok(session);
|
|
254
|
+
assert.strictEqual(session.branchName, 'feat/my-branch');
|
|
255
|
+
});
|
|
256
|
+
it('branchName defaults to empty string when neither branchName nor worktreeName provided', () => {
|
|
257
|
+
const result = sessions.create({
|
|
258
|
+
type: 'repo',
|
|
259
|
+
repoName: 'test-repo',
|
|
260
|
+
repoPath: '/tmp',
|
|
261
|
+
command: '/bin/echo',
|
|
262
|
+
args: ['hello'],
|
|
263
|
+
});
|
|
264
|
+
createdIds.push(result.id);
|
|
265
|
+
assert.strictEqual(result.branchName, '');
|
|
266
|
+
});
|
|
217
267
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it } from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
|
-
import { WORKTREE_DIRS, isValidWorktreePath } from '../server/watcher.js';
|
|
3
|
+
import { WORKTREE_DIRS, isValidWorktreePath, parseWorktreeListPorcelain } from '../server/watcher.js';
|
|
4
4
|
describe('worktree directories constant', () => {
|
|
5
5
|
it('should include both .worktrees and .claude/worktrees', () => {
|
|
6
6
|
assert.deepEqual(WORKTREE_DIRS, ['.worktrees', '.claude/worktrees']);
|
|
@@ -32,6 +32,120 @@ describe('branch name to directory name', () => {
|
|
|
32
32
|
assert.equal(dirName, 'my-feature');
|
|
33
33
|
});
|
|
34
34
|
});
|
|
35
|
+
describe('parseWorktreeListPorcelain', () => {
|
|
36
|
+
const repoPath = '/Users/me/code/my-repo';
|
|
37
|
+
it('should parse a single worktree entry', () => {
|
|
38
|
+
const stdout = [
|
|
39
|
+
`worktree ${repoPath}`,
|
|
40
|
+
'HEAD abc123',
|
|
41
|
+
'branch refs/heads/main',
|
|
42
|
+
'',
|
|
43
|
+
'worktree /Users/me/code/my-repo/.worktrees/feat-branch',
|
|
44
|
+
'HEAD def456',
|
|
45
|
+
'branch refs/heads/feat/branch',
|
|
46
|
+
'',
|
|
47
|
+
].join('\n');
|
|
48
|
+
const result = parseWorktreeListPorcelain(stdout, repoPath);
|
|
49
|
+
assert.equal(result.length, 1);
|
|
50
|
+
assert.equal(result[0].path, '/Users/me/code/my-repo/.worktrees/feat-branch');
|
|
51
|
+
assert.equal(result[0].branch, 'feat/branch');
|
|
52
|
+
});
|
|
53
|
+
it('should parse multiple worktree entries', () => {
|
|
54
|
+
const stdout = [
|
|
55
|
+
`worktree ${repoPath}`,
|
|
56
|
+
'HEAD abc123',
|
|
57
|
+
'branch refs/heads/main',
|
|
58
|
+
'',
|
|
59
|
+
'worktree /Users/me/code/my-repo/.worktrees/feat-a',
|
|
60
|
+
'HEAD def456',
|
|
61
|
+
'branch refs/heads/feat/a',
|
|
62
|
+
'',
|
|
63
|
+
'worktree /Users/me/other-path/extend-cli',
|
|
64
|
+
'HEAD 789abc',
|
|
65
|
+
'branch refs/heads/dy/feat/worktree-isolation',
|
|
66
|
+
'',
|
|
67
|
+
].join('\n');
|
|
68
|
+
const result = parseWorktreeListPorcelain(stdout, repoPath);
|
|
69
|
+
assert.equal(result.length, 2);
|
|
70
|
+
assert.equal(result[0].path, '/Users/me/code/my-repo/.worktrees/feat-a');
|
|
71
|
+
assert.equal(result[0].branch, 'feat/a');
|
|
72
|
+
assert.equal(result[1].path, '/Users/me/other-path/extend-cli');
|
|
73
|
+
assert.equal(result[1].branch, 'dy/feat/worktree-isolation');
|
|
74
|
+
});
|
|
75
|
+
it('should skip the main worktree (repo root)', () => {
|
|
76
|
+
const stdout = [
|
|
77
|
+
`worktree ${repoPath}`,
|
|
78
|
+
'HEAD abc123',
|
|
79
|
+
'branch refs/heads/main',
|
|
80
|
+
'',
|
|
81
|
+
].join('\n');
|
|
82
|
+
const result = parseWorktreeListPorcelain(stdout, repoPath);
|
|
83
|
+
assert.equal(result.length, 0);
|
|
84
|
+
});
|
|
85
|
+
it('should skip bare entries', () => {
|
|
86
|
+
const stdout = [
|
|
87
|
+
`worktree ${repoPath}`,
|
|
88
|
+
'HEAD abc123',
|
|
89
|
+
'branch refs/heads/main',
|
|
90
|
+
'',
|
|
91
|
+
'worktree /some/bare/repo',
|
|
92
|
+
'HEAD def456',
|
|
93
|
+
'bare',
|
|
94
|
+
'',
|
|
95
|
+
].join('\n');
|
|
96
|
+
const result = parseWorktreeListPorcelain(stdout, repoPath);
|
|
97
|
+
assert.equal(result.length, 0);
|
|
98
|
+
});
|
|
99
|
+
it('should skip detached HEAD worktrees (no branch line)', () => {
|
|
100
|
+
const stdout = [
|
|
101
|
+
`worktree ${repoPath}`,
|
|
102
|
+
'HEAD abc123',
|
|
103
|
+
'branch refs/heads/main',
|
|
104
|
+
'',
|
|
105
|
+
'worktree /Users/me/code/my-repo/.worktrees/detached',
|
|
106
|
+
'HEAD def456',
|
|
107
|
+
'detached',
|
|
108
|
+
'',
|
|
109
|
+
].join('\n');
|
|
110
|
+
const result = parseWorktreeListPorcelain(stdout, repoPath);
|
|
111
|
+
assert.equal(result.length, 0);
|
|
112
|
+
});
|
|
113
|
+
it('should handle empty output', () => {
|
|
114
|
+
const result = parseWorktreeListPorcelain('', repoPath);
|
|
115
|
+
assert.equal(result.length, 0);
|
|
116
|
+
});
|
|
117
|
+
it('should discover worktrees at arbitrary paths outside .worktrees/', () => {
|
|
118
|
+
const stdout = [
|
|
119
|
+
`worktree ${repoPath}`,
|
|
120
|
+
'HEAD abc123',
|
|
121
|
+
'branch refs/heads/main',
|
|
122
|
+
'',
|
|
123
|
+
'worktree /completely/different/path/project-checkout',
|
|
124
|
+
'HEAD def456',
|
|
125
|
+
'branch refs/heads/feature/my-feature',
|
|
126
|
+
'',
|
|
127
|
+
].join('\n');
|
|
128
|
+
const result = parseWorktreeListPorcelain(stdout, repoPath);
|
|
129
|
+
assert.equal(result.length, 1);
|
|
130
|
+
assert.equal(result[0].path, '/completely/different/path/project-checkout');
|
|
131
|
+
assert.equal(result[0].branch, 'feature/my-feature');
|
|
132
|
+
});
|
|
133
|
+
it('should handle deeply nested branch names', () => {
|
|
134
|
+
const stdout = [
|
|
135
|
+
`worktree ${repoPath}`,
|
|
136
|
+
'HEAD abc123',
|
|
137
|
+
'branch refs/heads/main',
|
|
138
|
+
'',
|
|
139
|
+
'worktree /Users/me/code/my-repo/.worktrees/dy-feat-deep-nesting',
|
|
140
|
+
'HEAD def456',
|
|
141
|
+
'branch refs/heads/dy/feat/deep/nesting/here',
|
|
142
|
+
'',
|
|
143
|
+
].join('\n');
|
|
144
|
+
const result = parseWorktreeListPorcelain(stdout, repoPath);
|
|
145
|
+
assert.equal(result.length, 1);
|
|
146
|
+
assert.equal(result[0].branch, 'dy/feat/deep/nesting/here');
|
|
147
|
+
});
|
|
148
|
+
});
|
|
35
149
|
describe('CLI worktree arg parsing', () => {
|
|
36
150
|
it('should extract --yolo and leave other args intact', () => {
|
|
37
151
|
const args = ['add', './.worktrees/my-feature', '-b', 'my-feature', '--yolo'];
|
package/package.json
CHANGED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
.pin-gate.svelte-1qp96yb{display:flex;align-items:center;justify-content:center;height:100vh;background:var(--bg);padding:1rem}.pin-container.svelte-1qp96yb{display:flex;flex-direction:column;align-items:center;gap:1rem;width:100%;max-width:320px;text-align:center}.pin-container.svelte-1qp96yb h1:where(.svelte-1qp96yb){font-size:1.5rem;color:var(--text)}.pin-container.svelte-1qp96yb p:where(.svelte-1qp96yb){color:var(--text-muted);font-size:.95rem}input.svelte-1qp96yb{width:100%;padding:14px 16px;background:var(--surface);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:1.2rem;text-align:center;outline:none;-webkit-appearance:none}input.svelte-1qp96yb:focus{border-color:var(--accent)}button.svelte-1qp96yb{width:100%;padding:14px;background:var(--accent);color:#fff;border:none;border-radius:8px;font-size:1rem;font-weight:600;cursor:pointer;touch-action:manipulation}button.svelte-1qp96yb:active{opacity:.8}.error.svelte-1qp96yb{color:var(--accent);font-size:.9rem}li.svelte-ix4pl2{position:relative;display:flex;align-items:flex-start;padding:8px 10px;cursor:pointer;border-radius:6px;margin:2px 6px;font-size:.8rem;color:var(--text-muted);touch-action:manipulation;transition:background .15s,border-color .15s}li.active-session.svelte-ix4pl2{background:var(--bg)}li.active-session.svelte-ix4pl2:hover,li.active-session.svelte-ix4pl2.longpress{background:var(--border)}li.active-session.selected.svelte-ix4pl2{background:var(--accent);color:#fff}li.active-session.selected.svelte-ix4pl2 .session-sub:where(.svelte-ix4pl2),li.active-session.selected.svelte-ix4pl2 .session-time:where(.svelte-ix4pl2){color:#ffffffb3}li.inactive-worktree.svelte-ix4pl2{background:transparent;border:1px solid var(--border);color:var(--text-muted);opacity:.7}li.inactive-worktree.svelte-ix4pl2:hover,li.inactive-worktree.svelte-ix4pl2.longpress{opacity:1;border-color:var(--accent)}.session-info.svelte-ix4pl2{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}.session-row-1.svelte-ix4pl2{display:flex;align-items:center;min-width:0}.status-dot.svelte-ix4pl2{display:inline-block;width:8px;height:8px;border-radius:50%;flex-shrink:0;margin-right:8px}.status-dot--running.svelte-ix4pl2{background:#4ade80}.status-dot--idle.svelte-ix4pl2{background:#60a5fa}.status-dot--attention.svelte-ix4pl2{background:#f59e0b;box-shadow:0 0 6px 2px #f59e0b80;animation:svelte-ix4pl2-attention-glow 2s ease-in-out infinite}.status-dot--inactive.svelte-ix4pl2{background:#6b7280}@keyframes svelte-ix4pl2-attention-glow{0%,to{box-shadow:0 0 4px 1px #f59e0b4d}50%{box-shadow:0 0 8px 3px #f59e0b99}}.session-name.svelte-ix4pl2{flex:1;min-width:0;overflow:hidden;white-space:nowrap;font-weight:500;color:var(--text)}.session-name-text.svelte-ix4pl2{display:inline-block;white-space:nowrap;will-change:transform}.session-name.has-overflow.svelte-ix4pl2{mask-image:linear-gradient(to right,black calc(100% - 32px),transparent);-webkit-mask-image:linear-gradient(to right,black calc(100% - 32px),transparent)}li.svelte-ix4pl2:hover .session-name.has-overflow:where(.svelte-ix4pl2),li.svelte-ix4pl2.longpress .session-name.has-overflow:where(.svelte-ix4pl2){mask-image:none;-webkit-mask-image:none}li.active-session.selected.svelte-ix4pl2 .session-name:where(.svelte-ix4pl2){color:#fff}li.active-session.selected.svelte-ix4pl2 .session-name.has-overflow:where(.svelte-ix4pl2){mask-image:linear-gradient(to right,white calc(100% - 32px),transparent);-webkit-mask-image:linear-gradient(to right,white calc(100% - 32px),transparent)}li.active-session.selected.svelte-ix4pl2:hover .session-name.has-overflow:where(.svelte-ix4pl2),li.active-session.selected.svelte-ix4pl2.longpress .session-name.has-overflow:where(.svelte-ix4pl2){mask-image:none;-webkit-mask-image:none}.action-pill.svelte-ix4pl2{background:#ffffff1a;border:none;color:var(--text);font-size:.75rem;cursor:pointer;padding:2px 8px;border-radius:12px;touch-action:manipulation;flex-shrink:0;min-height:24px;display:inline-flex;align-items:center;transition:background .15s,color .15s;line-height:1}.action-pill.svelte-ix4pl2:hover{background:#fff3}.action-pill--mono.svelte-ix4pl2{font-family:monospace;font-size:.65rem;letter-spacing:.02em}.action-pill--danger.svelte-ix4pl2:hover{background:#e74c3c26;color:#e74c3c}li.active-session.selected.svelte-ix4pl2 .action-pill:where(.svelte-ix4pl2){background:#fff3;color:#fff}li.active-session.selected.svelte-ix4pl2 .action-pill:where(.svelte-ix4pl2):hover{background:#ffffff4d}li.active-session.selected.svelte-ix4pl2 .action-pill--danger:where(.svelte-ix4pl2):hover{background:#e74c3c40;color:#fca5a5}.session-actions.svelte-ix4pl2{position:absolute;right:10px;top:50%;transform:translateY(-50%);display:flex;align-items:center;gap:4px;opacity:0;visibility:hidden;transition:opacity .15s .1s,visibility .15s .1s}li.svelte-ix4pl2:hover .session-actions:where(.svelte-ix4pl2),li.svelte-ix4pl2:focus-within .session-actions:where(.svelte-ix4pl2),li.svelte-ix4pl2.longpress .session-actions:where(.svelte-ix4pl2){opacity:1;visibility:visible}.session-row-2.svelte-ix4pl2{display:flex;align-items:center;gap:4px;min-width:0;padding-left:16px}.pr-icon.svelte-ix4pl2{font-size:.65rem;flex-shrink:0}.pr-open.svelte-ix4pl2{color:#4ade80}.pr-merged.svelte-ix4pl2{color:#a78bfa}.pr-closed.svelte-ix4pl2{color:#f87171}.session-sub.svelte-ix4pl2{font-size:.7rem;color:var(--text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.session-row-3.svelte-ix4pl2{display:flex;align-items:center;gap:6px;min-width:0;padding-left:16px}.session-time.svelte-ix4pl2{font-size:.65rem;color:var(--text-muted);opacity:.6}.git-diff.svelte-ix4pl2{display:flex;gap:4px;font-size:.65rem;font-family:monospace}.diff-add.svelte-ix4pl2{color:#4ade80}.diff-del.svelte-ix4pl2{color:#f87171}.sidebar-filters.svelte-1o5d4l8{display:flex;flex-direction:column;gap:4px;padding:6px 8px;flex-shrink:0}select.svelte-1o5d4l8{padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:.75rem;outline:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23aaa' fill='none' stroke-width='1.5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 8px center;cursor:pointer;transition:border-color .15s,box-shadow .3s}select.svelte-1o5d4l8:focus{border-color:var(--accent)}select.highlight.svelte-1o5d4l8{border-color:var(--accent);animation:svelte-1o5d4l8-pulse-border 2s ease-in-out infinite}@keyframes svelte-1o5d4l8-pulse-border{0%,to{border-color:var(--accent);box-shadow:0 0 #d9775700}50%{border-color:var(--accent);box-shadow:0 0 6px 2px #d977574d}}input.svelte-1o5d4l8{padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:.75rem;outline:none;-webkit-appearance:none}input.svelte-1o5d4l8:focus{border-color:var(--accent)}.role-filter.svelte-1o5d4l8{display:flex;gap:0;border:1px solid var(--border);border-radius:6px;overflow:hidden}.role-btn.svelte-1o5d4l8{flex:1;padding:5px 8px;background:var(--bg);border:none;border-right:1px solid var(--border);color:var(--text-muted);font-size:.7rem;cursor:pointer;transition:background .15s,color .15s}.role-btn.svelte-1o5d4l8:last-child{border-right:none}.role-btn.svelte-1o5d4l8:hover{color:var(--text)}.role-btn.active.svelte-1o5d4l8{background:var(--accent);color:#fff}li.pr-item.svelte-jhsg4e{position:relative;display:flex;align-items:flex-start;padding:8px 10px;cursor:pointer;border-radius:6px;margin:2px 6px;font-size:.8rem;color:var(--text-muted);touch-action:manipulation;transition:background .15s,border-color .15s;background:transparent;border:1px solid var(--border);opacity:.8}li.pr-item.svelte-jhsg4e:hover,li.pr-item.svelte-jhsg4e.longpress{opacity:1;border-color:var(--accent)}li.pr-item.active-session.svelte-jhsg4e{background:var(--bg);border-color:var(--accent);opacity:1}.pr-info.svelte-jhsg4e{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}.pr-row-1.svelte-jhsg4e{display:flex;align-items:center;min-width:0}.pr-state{font-size:.65rem;flex-shrink:0;width:16px;text-align:center;margin-right:4px}.pr-open{color:#4ade80}.pr-merged{color:#a78bfa}.pr-closed{color:#f87171}.pr-title.svelte-jhsg4e{flex:1;min-width:0;overflow:hidden;white-space:nowrap;font-weight:500;color:var(--text)}.pr-title-text.svelte-jhsg4e{display:inline-block;white-space:nowrap;will-change:transform}.pr-title.has-overflow.svelte-jhsg4e{mask-image:linear-gradient(to right,black calc(100% - 32px),transparent);-webkit-mask-image:linear-gradient(to right,black calc(100% - 32px),transparent)}li.svelte-jhsg4e:hover .pr-title.has-overflow:where(.svelte-jhsg4e),li.svelte-jhsg4e.longpress .pr-title.has-overflow:where(.svelte-jhsg4e){mask-image:none;-webkit-mask-image:none}.pr-actions.svelte-jhsg4e{position:absolute;right:10px;top:50%;transform:translateY(-50%);display:flex;align-items:center;gap:2px;opacity:0;visibility:hidden;transition:opacity .15s .1s,visibility .15s .1s}li.svelte-jhsg4e:hover .pr-actions:where(.svelte-jhsg4e),li.svelte-jhsg4e:focus-within .pr-actions:where(.svelte-jhsg4e),li.svelte-jhsg4e.longpress .pr-actions:where(.svelte-jhsg4e){opacity:1;visibility:visible}.external-link-btn.svelte-jhsg4e{background:none;border:none;color:var(--text-muted);font-size:.85rem;cursor:pointer;padding:2px 4px;border-radius:4px;touch-action:manipulation;flex-shrink:0;transition:color .15s,transform .15s}.external-link-btn.svelte-jhsg4e:hover{color:var(--accent);transform:scale(1.1)}.review-badge.svelte-jhsg4e{font-size:.7rem;padding:0 3px}.review-approved.svelte-jhsg4e{color:#4ade80}.review-changes.svelte-jhsg4e{color:#f87171}.review-pending.svelte-jhsg4e{color:#f59e0b}.pr-row-2.svelte-jhsg4e{display:flex;align-items:center;gap:4px;min-width:0;padding-left:20px}.pr-meta.svelte-jhsg4e{font-size:.7rem;color:var(--text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.role-badge.svelte-jhsg4e{font-size:.6rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;padding:1px 5px;border-radius:3px;flex-shrink:0}.role-author.svelte-jhsg4e{background:#60a5fa26;color:#60a5fa}.role-reviewer.svelte-jhsg4e{background:#a78bfa26;color:#a78bfa}.pr-row-3.svelte-jhsg4e{display:flex;align-items:center;gap:6px;min-width:0;padding-left:20px}.pr-time.svelte-jhsg4e{font-size:.65rem;color:var(--text-muted);opacity:.6}.git-diff.svelte-jhsg4e{display:flex;gap:4px;font-size:.65rem;font-family:monospace}.diff-add.svelte-jhsg4e{color:#4ade80}.diff-del.svelte-jhsg4e{color:#f87171}.session-list-tabs.svelte-ynafm7{display:flex;padding:0 8px;border-bottom:1px solid var(--border)}.sidebar-tab.svelte-ynafm7{flex:1;background:none;border:none;border-bottom:2px solid transparent;color:var(--text-muted);font-size:.7rem;padding:6px 4px;cursor:pointer;transition:color .15s,border-color .15s;text-align:center}.sidebar-tab.svelte-ynafm7:hover{color:var(--text)}.sidebar-tab.active.svelte-ynafm7{color:var(--accent);border-bottom-color:var(--accent)}.tab-count.svelte-ynafm7{opacity:.7}.session-list.svelte-ynafm7{list-style:none;flex:1;overflow-y:auto;padding:8px 0}.session-divider{font-size:.65rem;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.05em;padding:8px 12px 4px;opacity:.6;list-style:none}.pr-toolbar.svelte-ynafm7{display:flex;justify-content:flex-end;padding:4px 10px 0}.refresh-btn.svelte-ynafm7{background:none;border:1px solid var(--border);border-radius:4px;color:var(--text-muted);font-size:.85rem;cursor:pointer;padding:2px 6px;transition:color .15s,border-color .15s}.refresh-btn.svelte-ynafm7:hover{color:var(--accent);border-color:var(--accent)}.refresh-btn.svelte-ynafm7:disabled{opacity:.5;cursor:not-allowed}.spinning.svelte-ynafm7{display:inline-block;animation:svelte-ynafm7-spin 1s linear infinite}@keyframes svelte-ynafm7-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.pr-hint{font-size:.75rem;color:var(--text-muted);text-align:center;padding:20px 12px;opacity:.6;list-style:none}.pr-hint-sub{font-size:.65rem;opacity:.8;display:block;margin-top:4px}.pr-hint code{background:var(--bg);padding:1px 4px;border-radius:3px;font-size:.65rem}.sidebar.svelte-owj5vn{position:relative;display:flex;flex-direction:column;background:var(--surface);border-right:1px solid var(--border);overflow:hidden;transition:transform .25s ease,width .2s ease,min-width .2s ease;z-index:100}.resize-handle.svelte-owj5vn{position:absolute;top:0;right:0;width:4px;height:100%;cursor:col-resize;z-index:10;transition:background .15s}.resize-handle.svelte-owj5vn:hover{background:var(--accent)}.sidebar-header.svelte-owj5vn{display:flex;align-items:center;justify-content:space-between;padding:12px 10px;border-bottom:1px solid var(--border);flex-shrink:0}.sidebar-label.svelte-owj5vn{flex:1;font-size:.85rem;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.05em}.collapse-btn.svelte-owj5vn{background:none;border:none;color:var(--text-muted);font-size:1.1rem;cursor:pointer;padding:4px 8px;border-radius:4px;flex-shrink:0;line-height:1}.collapse-btn.svelte-owj5vn:hover{color:var(--text);background:var(--border)}.sidebar.collapsed.svelte-owj5vn .sidebar-header:where(.svelte-owj5vn){justify-content:center;padding:12px 4px}.icon-btn.svelte-owj5vn{background:none;border:none;color:var(--text);font-size:1.2rem;cursor:pointer;padding:4px 6px;border-radius:4px;touch-action:manipulation;display:none}.icon-btn.svelte-owj5vn:active{background:var(--border)}.new-session-btn.svelte-owj5vn{margin:8px;padding:10px 12px;background:none;border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:.875rem;cursor:pointer;touch-action:manipulation;text-align:center;flex-shrink:0}.new-session-btn.svelte-owj5vn:active{background:var(--border)}.settings-btn.svelte-owj5vn{margin:0 8px 8px;padding:10px 12px;background:none;border:1px solid var(--border);border-radius:6px;color:var(--text-muted);font-size:.8rem;cursor:pointer;touch-action:manipulation;text-align:center;flex-shrink:0}.settings-btn.svelte-owj5vn:active{background:var(--border)}@media(max-width:600px){.sidebar.svelte-owj5vn{position:fixed;top:0;left:0;height:100%;transform:translate(-100%);box-shadow:2px 0 12px #00000080;transition:transform .25s ease}.sidebar.open.svelte-owj5vn{transform:translate(0)}.collapse-btn.svelte-owj5vn{display:none}.icon-btn.svelte-owj5vn{display:block;font-size:1.4rem;padding:4px 8px}.resize-handle.svelte-owj5vn{display:none}}/**
|
|
2
|
-
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
|
3
|
-
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
|
4
|
-
* https://github.com/chjj/term.js
|
|
5
|
-
* @license MIT
|
|
6
|
-
*
|
|
7
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
9
|
-
* in the Software without restriction, including without limitation the rights
|
|
10
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
12
|
-
* furnished to do so, subject to the following conditions:
|
|
13
|
-
*
|
|
14
|
-
* The above copyright notice and this permission notice shall be included in
|
|
15
|
-
* all copies or substantial portions of the Software.
|
|
16
|
-
*
|
|
17
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
23
|
-
* THE SOFTWARE.
|
|
24
|
-
*
|
|
25
|
-
* Originally forked from (with the author's permission):
|
|
26
|
-
* Fabrice Bellard's javascript vt100 for jslinux:
|
|
27
|
-
* http://bellard.org/jslinux/
|
|
28
|
-
* Copyright (c) 2011 Fabrice Bellard
|
|
29
|
-
* The original design remains. The terminal itself
|
|
30
|
-
* has been extended to include xterm CSI codes, among
|
|
31
|
-
* other features.
|
|
32
|
-
*/.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.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}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{font-family:monospace;-webkit-user-select:text;user-select:text;white-space:pre}.xterm .xterm-accessibility-tree>div{transform-origin:left;width:fit-content}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;background:#0000;transition:opacity .1s linear;z-index:11}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{position:absolute;display:none}.xterm .xterm-scrollable-element>.shadow.top{display:block;top:0;left:3px;height:3px;width:100%;box-shadow:var(--vscode-scrollbar-shadow, #000) 0 6px 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.left{display:block;top:3px;left:0;height:100%;width:3px;box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.top-left-corner{display:block;top:0;left:0;height:3px;width:3px}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.terminal-wrapper.svelte-5qgfij{display:flex;flex:1;min-height:0;position:relative;overflow:hidden}.terminal-container.svelte-5qgfij{flex:1;min-width:0;min-height:0;overflow:hidden;padding:4px}.terminal-scrollbar.svelte-5qgfij{width:8px;background:transparent;position:relative;flex-shrink:0}.terminal-scrollbar-thumb.svelte-5qgfij{position:absolute;right:0;width:6px;background:var(--border);border-radius:3px;cursor:pointer}@media(hover:none){.terminal-scrollbar.svelte-5qgfij{width:12px}.terminal-scrollbar-thumb.svelte-5qgfij{width:8px;min-height:44px}}.toolbar.svelte-k7we1m{background:var(--surface);border-top:1px solid var(--border);padding:4px;flex-shrink:0}.toolbar-grid.svelte-k7we1m{display:grid;grid-template-columns:repeat(6,1fr);gap:4px}.tb-btn.svelte-k7we1m{background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:.85rem;padding:8px 4px;cursor:pointer;touch-action:manipulation;min-height:40px;display:flex;align-items:center;justify-content:center;user-select:none;-webkit-user-select:none}.tb-btn.svelte-k7we1m:active{background:var(--border)}.tb-enter.svelte-k7we1m{background:var(--accent);border-color:var(--accent);color:#fff}.tb-enter.svelte-k7we1m:active{opacity:.8}.mobile-header.svelte-wp0i5g{display:none;align-items:center;gap:8px;padding:8px 12px;background:var(--surface);border-bottom:1px solid var(--border);min-height:44px;flex-shrink:0}@media(max-width:768px){.mobile-header.svelte-wp0i5g{display:flex}.mobile-header.hidden.svelte-wp0i5g{display:none}}.mobile-title.svelte-wp0i5g{font-size:.95rem;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.icon-btn.svelte-wp0i5g{background:none;border:none;color:var(--text);font-size:1.2rem;cursor:pointer;padding:6px;min-width:36px;min-height:36px;display:flex;align-items:center;justify-content:center;border-radius:6px;touch-action:manipulation}.icon-btn.svelte-wp0i5g:hover{background:var(--border)}.mobile-input-form.svelte-us0qpd{position:fixed;left:-9999px;top:0;width:1px;height:1px;opacity:0;pointer-events:none}.mobile-input.svelte-us0qpd{width:100%;height:100%;background:transparent;border:none;outline:none;color:transparent;caret-color:transparent;font-size:16px}.debug-toggle.svelte-us0qpd{position:fixed;bottom:60px;right:8px;z-index:10000;background:#333;color:#0f0;border:1px solid #0f0;border-radius:6px;font:12px monospace;padding:6px 10px;min-width:44px;min-height:44px;touch-action:manipulation}.debug-panel.svelte-us0qpd{position:fixed;top:0;left:0;right:0;height:30vh;overflow-y:auto;background:#000000eb;color:#0f0;font:11px/1.4 monospace;padding:6px 6px 6px 40px;z-index:9999;white-space:pre-wrap;word-break:break-all}.update-toast.svelte-1trivgv{position:fixed;bottom:0;left:0;right:0;z-index:150;display:flex;justify-content:center;padding:12px 12px calc(12px + env(safe-area-inset-bottom));pointer-events:none;animation:svelte-1trivgv-toast-slide-up .25s ease-out}@keyframes svelte-1trivgv-toast-slide-up{0%{transform:translateY(100%);opacity:0}to{transform:translateY(0);opacity:1}}.update-toast-content.svelte-1trivgv{display:flex;flex-direction:row;align-items:center;gap:12px;background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:12px 16px;max-width:500px;box-shadow:0 4px 16px #0000004d;pointer-events:auto}.update-toast-text.svelte-1trivgv{flex:1;font-size:.85rem;color:var(--text)}.update-toast-actions.svelte-1trivgv{display:flex;gap:8px;flex-shrink:0}.update-toast-btn.svelte-1trivgv{padding:8px 14px;border-radius:6px;font-size:.8rem;border:none;background:var(--accent);color:#fff;cursor:pointer;white-space:nowrap}.update-toast-btn.svelte-1trivgv:disabled{opacity:.6;cursor:not-allowed}.update-toast-dismiss.svelte-1trivgv{background:none;border:none;color:var(--text-muted);font-size:1.2rem;padding:4px 6px;cursor:pointer}.update-toast-dismiss.svelte-1trivgv:hover{color:var(--text)}.image-toast.svelte-1y8sviv{position:fixed;bottom:60px;left:50%;transform:translate(-50%);z-index:1000;background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:8px 14px;color:var(--text);font-size:13px;max-width:90vw;box-shadow:0 4px 12px #0006}.image-toast-content.svelte-1y8sviv{display:flex;align-items:center;gap:10px}.image-toast-text.svelte-1y8sviv{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:60vw}.image-toast-actions.svelte-1y8sviv{display:flex;gap:6px;align-items:center;flex-shrink:0}.image-toast-insert.svelte-1y8sviv{background:var(--accent);color:#fff;border:none;border-radius:4px;padding:4px 10px;font-size:12px;cursor:pointer}.image-toast-insert.svelte-1y8sviv:active{opacity:.8}.image-toast-dismiss.svelte-1y8sviv{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:16px;padding:2px 6px}.image-toast-dismiss.svelte-1y8sviv:hover{color:var(--text)}.dialog.svelte-thtd9b{background:var(--surface);color:var(--text);border:1px solid var(--border);border-radius:10px;padding:0;width:min(480px,95vw);max-height:90vh;overflow:hidden}.dialog.svelte-thtd9b::backdrop{background:#0009}.dialog-content.svelte-thtd9b{display:flex;flex-direction:column;max-height:90vh;overflow:hidden}.dialog-title.svelte-thtd9b{font-size:1.1rem;font-weight:600;padding:16px 20px 12px;margin:0;border-bottom:1px solid var(--border);flex-shrink:0}.dialog-tabs.svelte-thtd9b{display:flex;border-bottom:1px solid var(--border);flex-shrink:0}.dialog-tab.svelte-thtd9b{flex:1;padding:10px;background:none;border:none;color:var(--text-muted);font-size:.9rem;cursor:pointer;border-bottom:2px solid transparent;transition:color .15s,border-color .15s}.dialog-tab.active.svelte-thtd9b{color:var(--accent);border-bottom-color:var(--accent)}.dialog-tab.svelte-thtd9b:hover:not(.active){color:var(--text)}.dialog-body.svelte-thtd9b{padding:16px 20px;overflow-y:auto;flex:1;display:flex;flex-direction:column;gap:14px}.dialog-field.svelte-thtd9b{display:flex;flex-direction:column;gap:5px}.dialog-field--inline.svelte-thtd9b{flex-direction:row;align-items:center;gap:8px}.dialog-label.svelte-thtd9b{font-size:.85rem;color:var(--text-muted)}.dialog-label-inline.svelte-thtd9b{font-size:.9rem;cursor:pointer}.dialog-select.svelte-thtd9b,.dialog-input.svelte-thtd9b{background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:.9rem;padding:7px 10px;width:100%;box-sizing:border-box}.dialog-select.svelte-thtd9b:disabled{opacity:.5;cursor:not-allowed}.dialog-checkbox.svelte-thtd9b{width:16px;height:16px;accent-color:var(--accent);cursor:pointer;flex-shrink:0}.branch-input-wrap.svelte-thtd9b{position:relative}.branch-dropdown.svelte-thtd9b{position:absolute;top:calc(100% + 2px);left:0;right:0;background:var(--surface);border:1px solid var(--border);border-radius:6px;list-style:none;margin:0;padding:4px 0;z-index:100;max-height:180px;overflow-y:auto}.branch-dropdown.svelte-thtd9b li:where(.svelte-thtd9b){padding:7px 12px;font-size:.9rem;cursor:pointer}.branch-dropdown.svelte-thtd9b li:where(.svelte-thtd9b):hover{background:var(--border)}.branch-create-new.svelte-thtd9b{color:var(--accent);border-bottom:1px solid var(--border)}.dialog-footer.svelte-thtd9b{display:flex;justify-content:flex-end;gap:10px;padding:12px 20px 16px;border-top:1px solid var(--border);flex-shrink:0}.btn.svelte-thtd9b{padding:8px 18px;border-radius:6px;font-size:.9rem;cursor:pointer;border:1px solid transparent;font-weight:500;transition:opacity .15s}.btn.svelte-thtd9b:disabled{opacity:.4;cursor:not-allowed}.btn-primary.svelte-thtd9b{background:var(--accent);color:#fff}.btn-primary.svelte-thtd9b:hover:not(:disabled){opacity:.9}.btn-ghost.svelte-thtd9b{background:transparent;color:var(--text-muted);border-color:var(--border)}.btn-ghost.svelte-thtd9b:hover{background:var(--border);color:var(--text)}.dialog.svelte-fdtoa4{background:var(--surface);color:var(--text);border:1px solid var(--border);border-radius:10px;padding:0;width:min(460px,95vw);max-height:90vh;overflow:hidden}.dialog.svelte-fdtoa4::backdrop{background:#0009}.dialog-content.svelte-fdtoa4{display:flex;flex-direction:column;max-height:90vh;overflow:hidden}.dialog-header.svelte-fdtoa4{display:flex;align-items:center;justify-content:space-between;padding:16px 20px 12px;border-bottom:1px solid var(--border);flex-shrink:0}.dialog-title.svelte-fdtoa4{font-size:1.1rem;font-weight:600;margin:0}.close-btn.svelte-fdtoa4{background:none;border:none;color:var(--text-muted);font-size:1rem;cursor:pointer;padding:4px 6px;border-radius:4px}.close-btn.svelte-fdtoa4:hover{background:var(--border);color:var(--text)}.dialog-body.svelte-fdtoa4{padding:16px 20px;overflow-y:auto;flex:1;display:flex;flex-direction:column;gap:20px}.settings-section.svelte-fdtoa4{display:flex;flex-direction:column;gap:10px}.section-title.svelte-fdtoa4{font-size:.9rem;font-weight:600;color:var(--text);margin:0}.section-desc.svelte-fdtoa4{font-size:.82rem;color:var(--text-muted);margin:0}.empty-msg.svelte-fdtoa4{font-size:.85rem;color:var(--text-muted);font-style:italic;margin:0}.roots-list.svelte-fdtoa4{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.root-item.svelte-fdtoa4{display:flex;align-items:center;justify-content:space-between;gap:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;padding:7px 10px}.root-path.svelte-fdtoa4{font-size:.85rem;font-family:monospace;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.remove-btn.svelte-fdtoa4{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:.9rem;padding:2px 5px;border-radius:4px;flex-shrink:0;line-height:1}.remove-btn.svelte-fdtoa4:hover{background:var(--border);color:var(--text)}.add-root-row.svelte-fdtoa4{display:flex;gap:8px}.add-root-input.svelte-fdtoa4{flex:1;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:.9rem;padding:7px 10px}.error-msg.svelte-fdtoa4{font-size:.82rem;color:#e74c3c;margin:0}.devtools-row.svelte-fdtoa4{display:flex;align-items:center;gap:8px}.dialog-checkbox.svelte-fdtoa4{width:16px;height:16px;accent-color:var(--accent);cursor:pointer;flex-shrink:0}.devtools-label.svelte-fdtoa4{font-size:.9rem;cursor:pointer}.dialog-footer.svelte-fdtoa4{display:flex;justify-content:flex-end;gap:10px;padding:12px 20px 16px;border-top:1px solid var(--border);flex-shrink:0}.btn.svelte-fdtoa4{padding:8px 18px;border-radius:6px;font-size:.9rem;cursor:pointer;border:1px solid transparent;font-weight:500}.btn-primary.svelte-fdtoa4{background:var(--accent);color:#fff;flex-shrink:0}.btn-primary.svelte-fdtoa4:hover{opacity:.9}.btn-ghost.svelte-fdtoa4{background:transparent;color:var(--text-muted);border-color:var(--border)}.btn-ghost.svelte-fdtoa4:hover{background:var(--border);color:var(--text)}.dialog.svelte-15sco2n{background:var(--surface);color:var(--text);border:1px solid var(--border);border-radius:10px;padding:0;width:min(400px,95vw);overflow:hidden}.dialog.svelte-15sco2n::backdrop{background:#0009}.dialog-content.svelte-15sco2n{display:flex;flex-direction:column}.dialog-title.svelte-15sco2n{font-size:1.1rem;font-weight:600;padding:16px 20px 12px;margin:0;border-bottom:1px solid var(--border)}.dialog-body.svelte-15sco2n{padding:16px 20px;display:flex;flex-direction:column;gap:8px}.confirm-msg.svelte-15sco2n{font-size:.95rem;margin:0;line-height:1.5}.wt-name.svelte-15sco2n{color:var(--text)}.wt-path.svelte-15sco2n{font-size:.82rem;color:var(--text-muted);font-family:monospace;margin:0;word-break:break-all}.warning-msg.svelte-15sco2n{font-size:.82rem;color:#e74c3c;margin:0}.error-msg.svelte-15sco2n{font-size:.85rem;color:#e74c3c;margin:0;padding:8px 10px;background:#e74c3c1a;border-radius:6px;border:1px solid rgba(231,76,60,.3)}.dialog-footer.svelte-15sco2n{display:flex;justify-content:flex-end;gap:10px;padding:12px 20px 16px;border-top:1px solid var(--border)}.btn.svelte-15sco2n{padding:8px 18px;border-radius:6px;font-size:.9rem;cursor:pointer;border:1px solid transparent;font-weight:500}.btn.svelte-15sco2n:disabled{opacity:.4;cursor:not-allowed}.btn-danger.svelte-15sco2n{background:#e74c3c;color:#fff}.btn-danger.svelte-15sco2n:hover:not(:disabled){opacity:.9}.btn-ghost.svelte-15sco2n{background:transparent;color:var(--text-muted);border-color:var(--border)}.btn-ghost.svelte-15sco2n:hover:not(:disabled){background:var(--border);color:var(--text)}.main-app.svelte-13zv0lp{display:flex;flex-direction:row;width:100%;height:100vh;height:100dvh;overflow:hidden}.sidebar-overlay.svelte-13zv0lp{display:none}.terminal-area.svelte-13zv0lp{flex:1;display:flex;flex-direction:column;min-width:0;overflow:hidden;position:relative}.no-session-msg.svelte-13zv0lp{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:var(--text-muted);font-size:.95rem;text-align:center;pointer-events:none}@media(max-width:600px){.main-app.svelte-13zv0lp{position:fixed;top:0;right:0;bottom:0;left:0;width:100%}.sidebar-overlay.svelte-13zv0lp{display:block;position:fixed;top:0;right:0;bottom:0;left:0;background:#00000080;z-index:99}.terminal-area.svelte-13zv0lp{width:100%}}:root{--bg: #1a1a1a;--surface: #2b2b2b;--accent: #d97757;--text: #ececec;--text-muted: #9b9b9b;--border: #3d3d3d;--sidebar-width: 240px;--toolbar-height: auto}[hidden]{display:none!important}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}dialog{margin:auto}html,body{height:100%;overflow:hidden;background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:15px}::-webkit-scrollbar{width:4px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:4px}
|