hjworktree-cli 2.3.0 → 2.5.0
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/.context-snapshots/context-snapshot-20250107-221530.md +95 -0
- package/.context-snapshots/context-snapshot-20260106-211500.md +85 -0
- package/README.md +39 -10
- package/bin/cli.js +64 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +10 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/socketHandlers.d.ts.map +1 -1
- package/dist/server/socketHandlers.js +19 -18
- package/dist/server/socketHandlers.js.map +1 -1
- package/dist/shared/constants.d.ts +2 -3
- package/dist/shared/constants.d.ts.map +1 -1
- package/dist/shared/constants.js +2 -24
- package/dist/shared/constants.js.map +1 -1
- package/dist/shared/types/index.d.ts +3 -15
- package/dist/shared/types/index.d.ts.map +1 -1
- package/dist/shared/types/index.js +1 -1
- package/dist/shared/types/index.js.map +1 -1
- package/dist/web/assets/index-Dgl6wRHk.css +32 -0
- package/dist/web/assets/index-Jm7djWxU.js +53 -0
- package/dist/web/assets/index-Jm7djWxU.js.map +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +2 -1
- package/server/index.ts +11 -0
- package/server/socketHandlers.ts +24 -23
- package/shared/constants.ts +2 -27
- package/shared/types/index.ts +6 -21
- package/web/src/App.tsx +8 -6
- package/web/src/components/Layout/LeftNavBar.tsx +6 -17
- package/web/src/components/Modals/AddWorktreeModal.tsx +1 -21
- package/web/src/components/Steps/WorktreeStep.tsx +1 -8
- package/web/src/components/Terminal/SplitTerminalView.tsx +64 -0
- package/web/src/components/Terminal/TerminalPanel.tsx +3 -69
- package/web/src/components/Terminal/XTerminal.tsx +4 -6
- package/web/src/stores/useAppStore.ts +77 -35
- package/web/src/styles/global.css +127 -77
- package/dist/web/assets/index-CsixHL-D.css +0 -32
- package/dist/web/assets/index-De6xm4hO.js +0 -53
- package/dist/web/assets/index-De6xm4hO.js.map +0 -1
- package/web/src/components/Setup/AgentSelector.tsx +0 -27
- package/web/src/components/Steps/AgentStep.tsx +0 -20
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { create } from 'zustand';
|
|
2
|
-
import type { Branch, TerminalInfo,
|
|
2
|
+
import type { Branch, TerminalInfo, TerminalStatus, NavigationStep, StepStatus, ModalType, SessionGroup } from '../../../shared/types/index.js';
|
|
3
3
|
import { STEP_ORDER } from '../../../shared/types/index.js';
|
|
4
4
|
import { DEFAULT_PARALLEL_COUNT, MIN_PARALLEL_COUNT, MAX_PARALLEL_COUNT } from '../../../shared/constants.js';
|
|
5
5
|
|
|
@@ -21,9 +21,6 @@ interface AppState {
|
|
|
21
21
|
branches: Branch[];
|
|
22
22
|
selectedBranch: string | null;
|
|
23
23
|
|
|
24
|
-
// Agent selection
|
|
25
|
-
selectedAgent: AgentId;
|
|
26
|
-
|
|
27
24
|
// Worktree count
|
|
28
25
|
worktreeCount: number;
|
|
29
26
|
|
|
@@ -31,15 +28,15 @@ interface AppState {
|
|
|
31
28
|
terminals: TerminalInfo[];
|
|
32
29
|
activeTerminalIndex: number;
|
|
33
30
|
|
|
34
|
-
// Session management
|
|
31
|
+
// Session management
|
|
35
32
|
activeSessionId: string | null;
|
|
36
33
|
selectedSessionIds: string[];
|
|
37
34
|
|
|
38
|
-
// LNB state
|
|
35
|
+
// LNB state
|
|
39
36
|
isSetupCollapsed: boolean;
|
|
40
37
|
collapsedBranches: string[];
|
|
41
38
|
|
|
42
|
-
// Modal state
|
|
39
|
+
// Modal state
|
|
43
40
|
modalType: ModalType;
|
|
44
41
|
modalData: { sessionIds?: string[]; branchName?: string } | null;
|
|
45
42
|
|
|
@@ -70,9 +67,6 @@ interface AppActions {
|
|
|
70
67
|
setSelectedBranch: (branch: string | null) => void;
|
|
71
68
|
fetchBranches: () => Promise<void>;
|
|
72
69
|
|
|
73
|
-
// Agent selection
|
|
74
|
-
setSelectedAgent: (agent: AgentId) => void;
|
|
75
|
-
|
|
76
70
|
// Worktree count
|
|
77
71
|
setWorktreeCount: (count: number) => void;
|
|
78
72
|
incrementWorktreeCount: () => void;
|
|
@@ -80,12 +74,12 @@ interface AppActions {
|
|
|
80
74
|
|
|
81
75
|
// Terminals
|
|
82
76
|
addTerminal: (terminal: TerminalInfo) => void;
|
|
83
|
-
updateTerminalStatus: (sessionId: string, status:
|
|
77
|
+
updateTerminalStatus: (sessionId: string, status: TerminalStatus) => void;
|
|
84
78
|
removeTerminal: (sessionId: string) => void;
|
|
85
79
|
setActiveTerminal: (index: number) => void;
|
|
86
80
|
clearAllTerminals: () => void;
|
|
87
81
|
|
|
88
|
-
// Session management
|
|
82
|
+
// Session management
|
|
89
83
|
setActiveSession: (sessionId: string | null) => void;
|
|
90
84
|
toggleSessionSelection: (sessionId: string) => void;
|
|
91
85
|
selectAllSessions: () => void;
|
|
@@ -93,16 +87,19 @@ interface AppActions {
|
|
|
93
87
|
removeSelectedSessions: () => Promise<void>;
|
|
94
88
|
getSessionGroups: () => SessionGroup[];
|
|
95
89
|
|
|
96
|
-
// LNB state
|
|
90
|
+
// LNB state
|
|
97
91
|
toggleSetupCollapse: () => void;
|
|
98
92
|
toggleBranchCollapse: (branchName: string) => void;
|
|
99
93
|
|
|
100
|
-
// Modal
|
|
94
|
+
// Modal
|
|
101
95
|
openModal: (type: ModalType, data?: { sessionIds?: string[]; branchName?: string }) => void;
|
|
102
96
|
closeModal: () => void;
|
|
103
97
|
|
|
104
|
-
// Single worktree creation
|
|
105
|
-
createSingleWorktree: (branch: string
|
|
98
|
+
// Single worktree creation
|
|
99
|
+
createSingleWorktree: (branch: string) => Promise<void>;
|
|
100
|
+
|
|
101
|
+
// Restore existing worktrees on page load
|
|
102
|
+
restoreExistingWorktrees: () => Promise<void>;
|
|
106
103
|
|
|
107
104
|
// Execute
|
|
108
105
|
execute: () => Promise<void>;
|
|
@@ -125,7 +122,6 @@ const initialState: AppState = {
|
|
|
125
122
|
projectInfo: null,
|
|
126
123
|
branches: [],
|
|
127
124
|
selectedBranch: null,
|
|
128
|
-
selectedAgent: 'claude',
|
|
129
125
|
worktreeCount: DEFAULT_PARALLEL_COUNT,
|
|
130
126
|
terminals: [],
|
|
131
127
|
activeTerminalIndex: 0,
|
|
@@ -206,13 +202,11 @@ export const useAppStore = create<AppStore>((set, get) => ({
|
|
|
206
202
|
},
|
|
207
203
|
|
|
208
204
|
isStepComplete: (checkStep) => {
|
|
209
|
-
const { selectedBranch,
|
|
205
|
+
const { selectedBranch, worktreeCount, terminals } = get();
|
|
210
206
|
|
|
211
207
|
switch (checkStep) {
|
|
212
208
|
case 'branch':
|
|
213
209
|
return selectedBranch !== null;
|
|
214
|
-
case 'agent':
|
|
215
|
-
return selectedAgent !== null;
|
|
216
210
|
case 'worktree':
|
|
217
211
|
return worktreeCount >= MIN_PARALLEL_COUNT;
|
|
218
212
|
case 'running':
|
|
@@ -268,9 +262,6 @@ export const useAppStore = create<AppStore>((set, get) => ({
|
|
|
268
262
|
}
|
|
269
263
|
},
|
|
270
264
|
|
|
271
|
-
// Agent selection
|
|
272
|
-
setSelectedAgent: (agent) => set({ selectedAgent: agent }),
|
|
273
|
-
|
|
274
265
|
// Worktree count
|
|
275
266
|
setWorktreeCount: (count) => set({
|
|
276
267
|
worktreeCount: Math.max(MIN_PARALLEL_COUNT, Math.min(MAX_PARALLEL_COUNT, count))
|
|
@@ -291,9 +282,13 @@ export const useAppStore = create<AppStore>((set, get) => ({
|
|
|
291
282
|
},
|
|
292
283
|
|
|
293
284
|
// Terminals
|
|
294
|
-
addTerminal: (terminal) => set((state) =>
|
|
295
|
-
|
|
296
|
-
|
|
285
|
+
addTerminal: (terminal) => set((state) => {
|
|
286
|
+
// 이미 같은 sessionId가 있으면 무시
|
|
287
|
+
if (state.terminals.some(t => t.sessionId === terminal.sessionId)) {
|
|
288
|
+
return state;
|
|
289
|
+
}
|
|
290
|
+
return { terminals: [...state.terminals, terminal] };
|
|
291
|
+
}),
|
|
297
292
|
|
|
298
293
|
updateTerminalStatus: (sessionId, status) => set((state) => ({
|
|
299
294
|
terminals: state.terminals.map((t) =>
|
|
@@ -426,7 +421,7 @@ export const useAppStore = create<AppStore>((set, get) => ({
|
|
|
426
421
|
closeModal: () => set({ modalType: null, modalData: null }),
|
|
427
422
|
|
|
428
423
|
// Single worktree creation
|
|
429
|
-
createSingleWorktree: async (branch
|
|
424
|
+
createSingleWorktree: async (branch) => {
|
|
430
425
|
const { setLoading, setError, addTerminal, setActiveSession } = get();
|
|
431
426
|
|
|
432
427
|
setLoading(true, 'Creating worktree...');
|
|
@@ -436,7 +431,7 @@ export const useAppStore = create<AppStore>((set, get) => ({
|
|
|
436
431
|
const response = await fetch('/api/worktrees/single', {
|
|
437
432
|
method: 'POST',
|
|
438
433
|
headers: { 'Content-Type': 'application/json' },
|
|
439
|
-
body: JSON.stringify({ branch
|
|
434
|
+
body: JSON.stringify({ branch }),
|
|
440
435
|
});
|
|
441
436
|
|
|
442
437
|
if (!response.ok) {
|
|
@@ -445,14 +440,13 @@ export const useAppStore = create<AppStore>((set, get) => ({
|
|
|
445
440
|
}
|
|
446
441
|
|
|
447
442
|
const { worktree } = await response.json();
|
|
448
|
-
const sessionId =
|
|
443
|
+
const sessionId = worktree.name;
|
|
449
444
|
|
|
450
445
|
addTerminal({
|
|
451
446
|
sessionId,
|
|
452
447
|
worktreePath: worktree.path,
|
|
453
448
|
worktreeName: worktree.name,
|
|
454
449
|
branchName: worktree.branch,
|
|
455
|
-
agentType,
|
|
456
450
|
status: 'initializing',
|
|
457
451
|
});
|
|
458
452
|
|
|
@@ -473,9 +467,59 @@ export const useAppStore = create<AppStore>((set, get) => ({
|
|
|
473
467
|
}
|
|
474
468
|
},
|
|
475
469
|
|
|
470
|
+
// Restore existing worktrees on page load
|
|
471
|
+
restoreExistingWorktrees: async () => {
|
|
472
|
+
const { terminals } = get();
|
|
473
|
+
|
|
474
|
+
// 이미 터미널이 복구되어 있으면 실행하지 않음
|
|
475
|
+
if (terminals.length > 0) {
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
try {
|
|
480
|
+
const response = await fetch('/api/worktrees');
|
|
481
|
+
if (!response.ok) return;
|
|
482
|
+
|
|
483
|
+
const worktrees = await response.json();
|
|
484
|
+
|
|
485
|
+
// Filter to only project worktrees (exclude main worktree)
|
|
486
|
+
const projectWorktrees = worktrees.filter(
|
|
487
|
+
(wt: { isMainWorktree: boolean; name: string }) =>
|
|
488
|
+
!wt.isMainWorktree && wt.name.includes('-project-')
|
|
489
|
+
);
|
|
490
|
+
|
|
491
|
+
if (projectWorktrees.length === 0) return;
|
|
492
|
+
|
|
493
|
+
const { addTerminal } = get();
|
|
494
|
+
|
|
495
|
+
// Restore terminals for each project worktree
|
|
496
|
+
for (const wt of projectWorktrees) {
|
|
497
|
+
addTerminal({
|
|
498
|
+
sessionId: wt.name,
|
|
499
|
+
worktreePath: wt.path,
|
|
500
|
+
worktreeName: wt.name,
|
|
501
|
+
branchName: wt.branch,
|
|
502
|
+
status: 'running',
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// Transition to running state
|
|
507
|
+
set({
|
|
508
|
+
step: 'running',
|
|
509
|
+
completedSteps: ['branch', 'worktree'],
|
|
510
|
+
isSetupCollapsed: true,
|
|
511
|
+
activeSessionId: projectWorktrees[0].name,
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
console.log(`Restored ${projectWorktrees.length} worktree sessions`);
|
|
515
|
+
} catch (error) {
|
|
516
|
+
console.error('Failed to restore worktrees:', error);
|
|
517
|
+
}
|
|
518
|
+
},
|
|
519
|
+
|
|
476
520
|
// Execute
|
|
477
521
|
execute: async () => {
|
|
478
|
-
const { selectedBranch, worktreeCount,
|
|
522
|
+
const { selectedBranch, worktreeCount, setLoading, setError, addTerminal } = get();
|
|
479
523
|
|
|
480
524
|
if (!selectedBranch) {
|
|
481
525
|
setError('Please select a branch');
|
|
@@ -492,7 +536,6 @@ export const useAppStore = create<AppStore>((set, get) => ({
|
|
|
492
536
|
body: JSON.stringify({
|
|
493
537
|
branch: selectedBranch,
|
|
494
538
|
count: worktreeCount,
|
|
495
|
-
agentType: selectedAgent,
|
|
496
539
|
}),
|
|
497
540
|
});
|
|
498
541
|
|
|
@@ -505,13 +548,12 @@ export const useAppStore = create<AppStore>((set, get) => ({
|
|
|
505
548
|
|
|
506
549
|
// Create terminal info for each worktree
|
|
507
550
|
for (const worktree of worktrees) {
|
|
508
|
-
const sessionId =
|
|
551
|
+
const sessionId = worktree.name;
|
|
509
552
|
addTerminal({
|
|
510
553
|
sessionId,
|
|
511
554
|
worktreePath: worktree.path,
|
|
512
555
|
worktreeName: worktree.name,
|
|
513
556
|
branchName: worktree.branch,
|
|
514
|
-
agentType: selectedAgent,
|
|
515
557
|
status: 'initializing',
|
|
516
558
|
});
|
|
517
559
|
}
|
|
@@ -520,7 +562,7 @@ export const useAppStore = create<AppStore>((set, get) => ({
|
|
|
520
562
|
const { terminals: updatedTerminals } = get();
|
|
521
563
|
set({
|
|
522
564
|
step: 'running',
|
|
523
|
-
completedSteps: ['branch', '
|
|
565
|
+
completedSteps: ['branch', 'worktree'],
|
|
524
566
|
isSetupCollapsed: true,
|
|
525
567
|
activeSessionId: updatedTerminals.length > 0 ? updatedTerminals[0].sessionId : null,
|
|
526
568
|
});
|
|
@@ -169,42 +169,6 @@ body {
|
|
|
169
169
|
text-align: center;
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
/* Agent cards */
|
|
173
|
-
.agent-cards {
|
|
174
|
-
display: grid;
|
|
175
|
-
grid-template-columns: repeat(3, 1fr);
|
|
176
|
-
gap: 12px;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
.agent-card {
|
|
180
|
-
padding: 16px;
|
|
181
|
-
border: 2px solid var(--border-color);
|
|
182
|
-
border-radius: 8px;
|
|
183
|
-
background-color: var(--bg-tertiary);
|
|
184
|
-
cursor: pointer;
|
|
185
|
-
transition: all 0.2s;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
.agent-card:hover {
|
|
189
|
-
border-color: var(--accent-blue);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
.agent-card.selected {
|
|
193
|
-
border-color: var(--accent-blue);
|
|
194
|
-
background-color: rgba(88, 166, 255, 0.1);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
.agent-card h4 {
|
|
198
|
-
font-size: 14px;
|
|
199
|
-
font-weight: 600;
|
|
200
|
-
margin-bottom: 4px;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
.agent-card p {
|
|
204
|
-
font-size: 12px;
|
|
205
|
-
color: var(--text-muted);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
172
|
/* Execute button */
|
|
209
173
|
.execute-button {
|
|
210
174
|
padding: 14px 48px;
|
|
@@ -852,15 +816,6 @@ body {
|
|
|
852
816
|
white-space: nowrap;
|
|
853
817
|
}
|
|
854
818
|
|
|
855
|
-
.session-agent {
|
|
856
|
-
font-size: 10px;
|
|
857
|
-
font-weight: 600;
|
|
858
|
-
color: var(--text-muted);
|
|
859
|
-
background-color: var(--bg-tertiary);
|
|
860
|
-
padding: 2px 6px;
|
|
861
|
-
border-radius: 4px;
|
|
862
|
-
}
|
|
863
|
-
|
|
864
819
|
.session-close {
|
|
865
820
|
padding: 2px 6px;
|
|
866
821
|
background: transparent;
|
|
@@ -1059,38 +1014,6 @@ body {
|
|
|
1059
1014
|
border-color: var(--accent-blue);
|
|
1060
1015
|
}
|
|
1061
1016
|
|
|
1062
|
-
/* Agent Options in Modal */
|
|
1063
|
-
.agent-options {
|
|
1064
|
-
display: flex;
|
|
1065
|
-
gap: 8px;
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
.agent-option {
|
|
1069
|
-
flex: 1;
|
|
1070
|
-
padding: 12px;
|
|
1071
|
-
background-color: var(--bg-tertiary);
|
|
1072
|
-
border: 2px solid var(--border-color);
|
|
1073
|
-
border-radius: 6px;
|
|
1074
|
-
cursor: pointer;
|
|
1075
|
-
transition: all 0.2s;
|
|
1076
|
-
text-align: center;
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
.agent-option:hover {
|
|
1080
|
-
border-color: var(--accent-blue);
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
.agent-option.selected {
|
|
1084
|
-
border-color: var(--accent-blue);
|
|
1085
|
-
background-color: rgba(88, 166, 255, 0.1);
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
.agent-option .agent-name {
|
|
1089
|
-
font-size: 12px;
|
|
1090
|
-
font-weight: 500;
|
|
1091
|
-
color: var(--text-primary);
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
1017
|
/* Modal Buttons */
|
|
1095
1018
|
.btn-primary {
|
|
1096
1019
|
padding: 10px 20px;
|
|
@@ -1215,3 +1138,130 @@ body {
|
|
|
1215
1138
|
font-size: 16px;
|
|
1216
1139
|
color: var(--text-secondary);
|
|
1217
1140
|
}
|
|
1141
|
+
|
|
1142
|
+
/* ========================================
|
|
1143
|
+
Split Terminal View Styles
|
|
1144
|
+
======================================== */
|
|
1145
|
+
|
|
1146
|
+
/* Terminal Header for Split View */
|
|
1147
|
+
.terminal-header {
|
|
1148
|
+
display: flex;
|
|
1149
|
+
align-items: center;
|
|
1150
|
+
gap: 12px;
|
|
1151
|
+
padding: 8px 16px;
|
|
1152
|
+
background-color: var(--bg-secondary);
|
|
1153
|
+
border-bottom: 1px solid var(--border-color);
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
/* Split Terminal Grid Container */
|
|
1157
|
+
.terminal-grid-container {
|
|
1158
|
+
flex: 1;
|
|
1159
|
+
display: flex;
|
|
1160
|
+
flex-direction: column;
|
|
1161
|
+
overflow: hidden;
|
|
1162
|
+
padding: 8px;
|
|
1163
|
+
background-color: var(--bg-primary);
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
.terminal-grid-container.scrollable {
|
|
1167
|
+
overflow-y: auto;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
/* Terminal Grid */
|
|
1171
|
+
.terminal-grid {
|
|
1172
|
+
flex: 1;
|
|
1173
|
+
display: grid;
|
|
1174
|
+
gap: 8px;
|
|
1175
|
+
min-height: 0;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
/* Grid layout - fixed 2 columns */
|
|
1179
|
+
.terminal-grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
|
|
1180
|
+
|
|
1181
|
+
/* Scrollable grid for many sessions */
|
|
1182
|
+
.terminal-grid-container.scrollable .terminal-grid {
|
|
1183
|
+
grid-auto-rows: minmax(350px, 1fr);
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
/* Terminal Pane */
|
|
1187
|
+
.terminal-pane {
|
|
1188
|
+
position: relative;
|
|
1189
|
+
display: flex;
|
|
1190
|
+
flex-direction: column;
|
|
1191
|
+
border: 2px solid var(--border-color);
|
|
1192
|
+
border-radius: 8px;
|
|
1193
|
+
overflow: hidden;
|
|
1194
|
+
background-color: var(--bg-primary);
|
|
1195
|
+
min-height: 300px;
|
|
1196
|
+
transition: border-color 0.2s, box-shadow 0.2s;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
.terminal-pane:hover {
|
|
1200
|
+
border-color: var(--text-muted);
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
.terminal-pane.active {
|
|
1204
|
+
border-color: var(--accent-green);
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
|
|
1208
|
+
/* Pane Header */
|
|
1209
|
+
.pane-header {
|
|
1210
|
+
display: flex;
|
|
1211
|
+
align-items: center;
|
|
1212
|
+
gap: 8px;
|
|
1213
|
+
padding: 6px 10px;
|
|
1214
|
+
background-color: var(--bg-secondary);
|
|
1215
|
+
border-bottom: 1px solid var(--border-color);
|
|
1216
|
+
min-height: 32px;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
.pane-status {
|
|
1220
|
+
width: 8px;
|
|
1221
|
+
height: 8px;
|
|
1222
|
+
border-radius: 50%;
|
|
1223
|
+
flex-shrink: 0;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
.pane-status.running { background-color: var(--accent-green); }
|
|
1227
|
+
.pane-status.initializing { background-color: var(--accent-yellow); }
|
|
1228
|
+
.pane-status.stopped { background-color: var(--text-muted); }
|
|
1229
|
+
.pane-status.error { background-color: var(--accent-red); }
|
|
1230
|
+
|
|
1231
|
+
.pane-title {
|
|
1232
|
+
flex: 1;
|
|
1233
|
+
font-size: 11px;
|
|
1234
|
+
font-weight: 500;
|
|
1235
|
+
color: var(--text-primary);
|
|
1236
|
+
white-space: nowrap;
|
|
1237
|
+
overflow: hidden;
|
|
1238
|
+
text-overflow: ellipsis;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
/* Pane Terminal Container */
|
|
1242
|
+
.pane-terminal {
|
|
1243
|
+
flex: 1;
|
|
1244
|
+
position: relative;
|
|
1245
|
+
overflow: hidden;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
.pane-terminal .terminal {
|
|
1249
|
+
height: 100%;
|
|
1250
|
+
width: 100%;
|
|
1251
|
+
padding: 4px;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
/* Empty Grid Message */
|
|
1255
|
+
.empty-grid-message {
|
|
1256
|
+
display: flex;
|
|
1257
|
+
flex-direction: column;
|
|
1258
|
+
align-items: center;
|
|
1259
|
+
justify-content: center;
|
|
1260
|
+
height: 100%;
|
|
1261
|
+
color: var(--text-muted);
|
|
1262
|
+
gap: 16px;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
.empty-grid-message p {
|
|
1266
|
+
font-size: 14px;
|
|
1267
|
+
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
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 .xterm-scroll-area{visibility:hidden}.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{-webkit-user-select:text;user-select:text;white-space:pre}.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}*{margin:0;padding:0;box-sizing:border-box}:root{--bg-primary: #0d1117;--bg-secondary: #161b22;--bg-tertiary: #21262d;--border-color: #30363d;--text-primary: #c9d1d9;--text-secondary: #8b949e;--text-muted: #6e7681;--accent-blue: #58a6ff;--accent-green: #3fb950;--accent-yellow: #d29922;--accent-red: #f85149;--accent-purple: #a371f7}html,body,#root{height:100%;width:100%}body{font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;background-color:var(--bg-primary);color:var(--text-primary);line-height:1.5}.app{display:flex;flex-direction:column;height:100vh;overflow:hidden}.header{display:flex;align-items:center;justify-content:space-between;padding:12px 24px;background-color:var(--bg-secondary);border-bottom:1px solid var(--border-color)}.header h1{font-size:18px;font-weight:600;color:var(--text-primary)}.header .project-info{display:flex;align-items:center;gap:12px;color:var(--text-secondary);font-size:13px}.header .project-info .branch{display:flex;align-items:center;gap:4px;color:var(--accent-green)}.main-content{flex:1;display:flex;flex-direction:column;overflow:hidden}.setup-panel{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;gap:32px}.setup-panel h2{font-size:24px;font-weight:600;margin-bottom:8px}.setup-panel p{color:var(--text-secondary);font-size:14px}.setup-section{width:100%;max-width:500px;background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:8px;padding:20px}.setup-section label{display:block;font-size:14px;font-weight:500;margin-bottom:8px;color:var(--text-primary)}.setup-section select,.setup-section input{width:100%;padding:10px 12px;border:1px solid var(--border-color);border-radius:6px;background-color:var(--bg-tertiary);color:var(--text-primary);font-size:14px;font-family:inherit}.setup-section select:focus,.setup-section input:focus{outline:none;border-color:var(--accent-blue)}.setup-section .counter{display:flex;align-items:center;gap:16px}.setup-section .counter button{width:40px;height:40px;border:1px solid var(--border-color);border-radius:6px;background-color:var(--bg-tertiary);color:var(--text-primary);font-size:20px;cursor:pointer;transition:all .2s}.setup-section .counter button:hover{background-color:var(--bg-primary);border-color:var(--accent-blue)}.setup-section .counter button:disabled{opacity:.5;cursor:not-allowed}.setup-section .counter span{font-size:24px;font-weight:600;min-width:60px;text-align:center}.agent-cards{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}.agent-card{padding:16px;border:2px solid var(--border-color);border-radius:8px;background-color:var(--bg-tertiary);cursor:pointer;transition:all .2s}.agent-card:hover{border-color:var(--accent-blue)}.agent-card.selected{border-color:var(--accent-blue);background-color:#58a6ff1a}.agent-card h4{font-size:14px;font-weight:600;margin-bottom:4px}.agent-card p{font-size:12px;color:var(--text-muted)}.execute-button{padding:14px 48px;background-color:var(--accent-green);color:var(--bg-primary);border:none;border-radius:8px;font-size:16px;font-weight:600;cursor:pointer;transition:all .2s}.execute-button:hover{filter:brightness(1.1)}.execute-button:disabled{background-color:var(--bg-tertiary);color:var(--text-muted);cursor:not-allowed}.terminal-panel{display:flex;flex-direction:column;height:100%;overflow:hidden}.terminal-tabs{display:flex;align-items:center;gap:4px;padding:8px 16px;background-color:var(--bg-secondary);border-bottom:1px solid var(--border-color);overflow-x:auto}.terminal-tab{display:flex;align-items:center;gap:8px;padding:8px 16px;background-color:transparent;border:1px solid transparent;border-radius:6px;color:var(--text-secondary);font-size:13px;cursor:pointer;transition:all .2s;white-space:nowrap}.terminal-tab:hover{background-color:var(--bg-tertiary)}.terminal-tab.active{background-color:var(--bg-tertiary);border-color:var(--border-color);color:var(--text-primary)}.terminal-tab .status{width:8px;height:8px;border-radius:50%}.terminal-tab .status.running{background-color:var(--accent-green)}.terminal-tab .status.initializing{background-color:var(--accent-yellow)}.terminal-tab .status.stopped{background-color:var(--text-muted)}.terminal-tab .status.error{background-color:var(--accent-red)}.terminal-tab .close-btn{padding:2px 4px;background:transparent;border:none;color:var(--text-muted);cursor:pointer;border-radius:4px;line-height:1}.terminal-tab .close-btn:hover{background-color:var(--bg-primary);color:var(--accent-red)}.terminal-actions{display:flex;align-items:center;gap:8px;margin-left:auto;padding-left:16px}.terminal-actions button{padding:6px 12px;background-color:transparent;border:1px solid var(--border-color);border-radius:6px;color:var(--text-secondary);font-size:12px;cursor:pointer;transition:all .2s}.terminal-actions button:hover{background-color:var(--bg-tertiary);color:var(--text-primary)}.terminal-actions button.danger:hover{border-color:var(--accent-red);color:var(--accent-red)}.terminal-container{flex:1;position:relative;overflow:hidden}.terminal-wrapper{position:absolute;top:0;left:0;right:0;bottom:0;padding:8px}.terminal-wrapper.hidden{visibility:hidden}.terminal{height:100%;width:100%}.loading-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background-color:#0d1117e6;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;z-index:1000}.loading-spinner{width:48px;height:48px;border:3px solid var(--border-color);border-top-color:var(--accent-blue);border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.loading-overlay p{color:var(--text-secondary);font-size:14px}.connection-status{position:fixed;bottom:16px;right:16px;display:flex;align-items:center;gap:8px;padding:8px 12px;background-color:var(--bg-secondary);border:1px solid var(--border-color);border-radius:6px;font-size:12px;color:var(--text-secondary)}.connection-status .dot{width:8px;height:8px;border-radius:50%}.connection-status .dot.connected{background-color:var(--accent-green)}.connection-status .dot.disconnected{background-color:var(--accent-red)}.error-banner{padding:12px 16px;background-color:#f851491a;border:1px solid var(--accent-red);border-radius:6px;color:var(--accent-red);font-size:14px;text-align:center}.main-layout{display:flex;flex:1;overflow:hidden}.main-content-area{flex:1;display:flex;flex-direction:column;overflow:hidden}.main-content-area.with-lnb{margin-left:0}.main-content-area.full-width{width:100%}.left-nav-bar{width:260px;background-color:var(--bg-secondary);border-right:1px solid var(--border-color);display:flex;flex-direction:column;flex-shrink:0}.lnb-header{padding:20px;border-bottom:1px solid var(--border-color);font-size:14px;font-weight:600;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.5px}.lnb-steps{padding:16px;display:flex;flex-direction:column;gap:8px}.lnb-step{display:flex;align-items:center;gap:12px;padding:14px 16px;background:transparent;border:1px solid transparent;border-radius:8px;text-align:left;cursor:pointer;transition:all .2s ease;width:100%;font-family:inherit}.lnb-step:hover:not(:disabled){background-color:var(--bg-tertiary)}.lnb-step:disabled{cursor:not-allowed;opacity:.5}.step-number{width:28px;height:28px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex-shrink:0;transition:all .2s ease}.lnb-step.pending .step-number{background-color:var(--bg-tertiary);color:var(--text-muted);border:2px solid var(--border-color)}.lnb-step.pending .step-label{color:var(--text-muted)}.lnb-step.current{background-color:#58a6ff1a;border-color:var(--accent-blue)}.lnb-step.current .step-number{background-color:var(--accent-blue);color:var(--bg-primary)}.lnb-step.current .step-label{color:var(--text-primary);font-weight:500}.lnb-step.completed .step-number{background-color:var(--accent-green);color:var(--bg-primary)}.lnb-step.completed .step-label{color:var(--text-primary)}.step-label{font-size:14px;flex:1}.step-container{flex:1;display:flex;flex-direction:column;padding:40px;max-width:600px;margin:0 auto;width:100%}.step-header{text-align:center;margin-bottom:32px}.step-header h2{font-size:24px;font-weight:600;margin-bottom:8px;color:var(--text-primary)}.step-header p{color:var(--text-secondary);font-size:14px}.step-content{flex:1;display:flex;flex-direction:column;gap:24px}.step-navigation{display:flex;justify-content:space-between;padding-top:32px;margin-top:auto;border-top:1px solid var(--border-color)}.nav-button{padding:12px 32px;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s ease;font-family:inherit}.nav-button.prev{background:transparent;border:1px solid var(--border-color);color:var(--text-secondary)}.nav-button.prev:hover:not(:disabled){background-color:var(--bg-tertiary);color:var(--text-primary)}.nav-button.prev:disabled{opacity:.3;cursor:not-allowed}.nav-button.next{background-color:var(--accent-blue);border:none;color:#fff}.nav-button.next:hover:not(:disabled){filter:brightness(1.1)}.nav-button.next:disabled{background-color:var(--bg-tertiary);color:var(--text-muted);cursor:not-allowed}.execution-summary{background-color:var(--bg-secondary);border:1px solid var(--border-color);border-radius:8px;padding:20px}.execution-summary h4{font-size:14px;font-weight:600;margin-bottom:16px;color:var(--text-primary);padding-bottom:12px;border-bottom:1px solid var(--border-color)}.summary-item{display:flex;justify-content:space-between;align-items:center;padding:8px 0}.summary-label{font-size:13px;color:var(--text-secondary)}.summary-value{font-size:13px;font-weight:500;color:var(--text-primary)}.left-nav-bar{width:280px;background-color:var(--bg-secondary);border-right:1px solid var(--border-color);display:flex;flex-direction:column;flex-shrink:0;overflow-y:auto}.lnb-section{border-bottom:1px solid var(--border-color)}.lnb-section-header{display:flex;align-items:center;justify-content:space-between;padding:16px;cursor:pointer;-webkit-user-select:none;user-select:none;transition:background-color .2s}.lnb-section-header:hover{background-color:var(--bg-tertiary)}.section-title{font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px}.collapse-icon{font-size:14px;color:var(--text-muted)}.sessions-section{flex:1;display:flex;flex-direction:column;min-height:0}.session-count{font-size:11px;background-color:var(--bg-tertiary);color:var(--text-secondary);padding:2px 8px;border-radius:10px;margin-left:8px}.session-list{flex:1;overflow-y:auto;padding:8px}.session-group{margin-bottom:8px}.session-group-header{display:flex;align-items:center;gap:8px;padding:8px 12px;cursor:pointer;border-radius:6px;transition:background-color .2s}.session-group-header:hover{background-color:var(--bg-tertiary)}.group-collapse-icon{font-size:10px;color:var(--text-muted)}.group-name{font-size:12px;font-weight:500;color:var(--text-secondary);flex:1}.group-count{font-size:11px;color:var(--text-muted)}.session-group-items{padding-left:12px}.session-item{display:flex;align-items:center;gap:8px;padding:8px 12px;cursor:pointer;border-radius:6px;margin:2px 0;border:1px solid transparent;transition:all .2s}.session-item:hover{background-color:var(--bg-tertiary)}.session-item.active{background-color:#58a6ff1a;border-color:var(--accent-blue)}.session-item.selected{background-color:#58a6ff0d}.session-checkbox{width:14px;height:14px;cursor:pointer;accent-color:var(--accent-blue)}.status-indicator{width:8px;height:8px;border-radius:50%;flex-shrink:0}.session-name{flex:1;font-size:12px;color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.session-agent{font-size:10px;font-weight:600;color:var(--text-muted);background-color:var(--bg-tertiary);padding:2px 6px;border-radius:4px}.session-close{padding:2px 6px;background:transparent;border:none;color:var(--text-muted);cursor:pointer;border-radius:4px;font-size:14px;line-height:1;opacity:0;transition:all .2s}.session-item:hover .session-close{opacity:1}.session-close:hover{background-color:var(--bg-primary);color:var(--accent-red)}.add-session-btn{margin:8px 16px 16px;padding:10px;background-color:transparent;border:1px dashed var(--border-color);border-radius:6px;color:var(--text-secondary);font-size:12px;cursor:pointer;transition:all .2s}.add-session-btn:hover{border-color:var(--accent-blue);color:var(--accent-blue);background-color:#58a6ff0d}.bulk-actions-bar{display:flex;align-items:center;gap:12px;padding:12px 16px;background-color:var(--bg-tertiary);border-top:1px solid var(--border-color)}.selected-count{font-size:12px;color:var(--text-secondary);flex:1}.bulk-delete-btn{padding:6px 12px;background-color:var(--accent-red);border:none;border-radius:4px;color:#fff;font-size:11px;font-weight:500;cursor:pointer;transition:filter .2s}.bulk-delete-btn:hover{filter:brightness(1.1)}.bulk-cancel-btn{padding:6px 12px;background-color:transparent;border:1px solid var(--border-color);border-radius:4px;color:var(--text-secondary);font-size:11px;cursor:pointer;transition:all .2s}.bulk-cancel-btn:hover{background-color:var(--bg-primary);color:var(--text-primary)}.modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background-color:#000000b3;display:flex;align-items:center;justify-content:center;z-index:1000}.modal-content{background-color:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;width:100%;max-width:440px;max-height:90vh;overflow:hidden;display:flex;flex-direction:column}.modal-confirm{max-width:400px}.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px;border-bottom:1px solid var(--border-color)}.modal-header h2{font-size:16px;font-weight:600;color:var(--text-primary)}.modal-close{padding:4px 8px;background:transparent;border:none;color:var(--text-muted);font-size:20px;cursor:pointer;border-radius:4px;line-height:1}.modal-close:hover{background-color:var(--bg-tertiary);color:var(--text-primary)}.modal-body{padding:24px;overflow-y:auto}.modal-footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid var(--border-color)}.form-group{margin-bottom:20px}.form-group:last-child{margin-bottom:0}.form-group label{display:block;font-size:13px;font-weight:500;color:var(--text-primary);margin-bottom:8px}.form-group select{width:100%;padding:10px 12px;background-color:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:6px;color:var(--text-primary);font-size:14px;font-family:inherit}.form-group select:focus{outline:none;border-color:var(--accent-blue)}.agent-options{display:flex;gap:8px}.agent-option{flex:1;padding:12px;background-color:var(--bg-tertiary);border:2px solid var(--border-color);border-radius:6px;cursor:pointer;transition:all .2s;text-align:center}.agent-option:hover{border-color:var(--accent-blue)}.agent-option.selected{border-color:var(--accent-blue);background-color:#58a6ff1a}.agent-option .agent-name{font-size:12px;font-weight:500;color:var(--text-primary)}.btn-primary{padding:10px 20px;background-color:var(--accent-blue);border:none;border-radius:6px;color:#fff;font-size:13px;font-weight:500;cursor:pointer;transition:filter .2s;font-family:inherit}.btn-primary:hover:not(:disabled){filter:brightness(1.1)}.btn-primary:disabled{background-color:var(--bg-tertiary);color:var(--text-muted);cursor:not-allowed}.btn-secondary{padding:10px 20px;background-color:transparent;border:1px solid var(--border-color);border-radius:6px;color:var(--text-secondary);font-size:13px;font-weight:500;cursor:pointer;transition:all .2s;font-family:inherit}.btn-secondary:hover:not(:disabled){background-color:var(--bg-tertiary);color:var(--text-primary)}.btn-danger{padding:10px 20px;background-color:var(--accent-red);border:none;border-radius:6px;color:#fff;font-size:13px;font-weight:500;cursor:pointer;transition:filter .2s;font-family:inherit}.btn-danger:hover:not(:disabled){filter:brightness(1.1)}.btn-danger:disabled{opacity:.5;cursor:not-allowed}.confirm-message{font-size:14px;color:var(--text-primary);margin-bottom:16px}.delete-list{list-style:none;padding:12px;background-color:var(--bg-tertiary);border-radius:6px;margin-bottom:16px;max-height:150px;overflow-y:auto}.delete-list li{display:flex;align-items:center;gap:8px;padding:6px 0;font-size:13px;color:var(--text-secondary)}.delete-list .status{width:6px;height:6px;border-radius:50%}.warning-text{font-size:12px;color:var(--accent-yellow);padding:12px;background-color:#d299221a;border-radius:6px}.terminal-panel.empty{display:flex;align-items:center;justify-content:center}.empty-message{text-align:center;color:var(--text-muted)}.empty-message p{margin:8px 0}.empty-message p:first-child{font-size:16px;color:var(--text-secondary)}
|