claude-remote-cli 2.4.5 → 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.
@@ -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-DOfplZTg.js"></script>
15
- <link rel="stylesheet" crossorigin href="/assets/index-D_vlhnTU.css">
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>
@@ -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
- for (const dir of WORKTREE_DIRS) {
401
- const worktreeDir = path.join(repo.path, dir);
402
- let entries;
403
- try {
404
- entries = fs.readdirSync(worktreeDir, { withFileTypes: true });
405
- }
406
- catch (_) {
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: entry.name,
416
- path: wtPath,
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 ? meta.displayName : '',
421
- lastActivity: meta ? meta.lastActivity : '',
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, '.worktrees');
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
- ensureGitignore(repoPath, '.worktrees/');
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,
@@ -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,
@@ -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,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-remote-cli",
3
- "version": "2.4.5",
3
+ "version": "2.4.6",
4
4
  "description": "Remote web interface for Claude Code CLI sessions",
5
5
  "type": "module",
6
6
  "main": "dist/server/index.js",
@@ -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-wrapper.drag-over.svelte-5qgfij{outline:2px dashed var(--accent);outline-offset:-2px}.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;padding-bottom:calc(4px + env(safe-area-inset-bottom,0px));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}.mobile-input.svelte-us0qpd::-webkit-search-cancel-button,.mobile-input.svelte-us0qpd::-webkit-search-decoration{-webkit-appearance:none;-moz-appearance:none;appearance:none}.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:40vh;height:40dvh;overflow-y:scroll;-webkit-overflow-scrolling:touch;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;overscroll-behavior:contain}.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}