hjworktree-cli 2.0.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-20260106-110353.md +66 -0
- package/.context-snapshots/context-snapshot-20260106-110441.md +66 -0
- package/.context-snapshots/context-snapshot-20260106-220000.md +99 -0
- package/AGENTS.md +29 -0
- package/CLAUDE.md +88 -0
- package/bin/cli.js +85 -0
- package/dist/server/index.d.ts +6 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +64 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/routes/api.d.ts +3 -0
- package/dist/server/routes/api.d.ts.map +1 -0
- package/dist/server/routes/api.js +101 -0
- package/dist/server/routes/api.js.map +1 -0
- package/dist/server/services/gitService.d.ts +13 -0
- package/dist/server/services/gitService.d.ts.map +1 -0
- package/dist/server/services/gitService.js +84 -0
- package/dist/server/services/gitService.js.map +1 -0
- package/dist/server/services/worktreeService.d.ts +17 -0
- package/dist/server/services/worktreeService.d.ts.map +1 -0
- package/dist/server/services/worktreeService.js +161 -0
- package/dist/server/services/worktreeService.js.map +1 -0
- package/dist/server/socketHandlers.d.ts +4 -0
- package/dist/server/socketHandlers.d.ts.map +1 -0
- package/dist/server/socketHandlers.js +118 -0
- package/dist/server/socketHandlers.js.map +1 -0
- package/dist/shared/constants.d.ts +10 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +31 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/types/index.d.ts +67 -0
- package/dist/shared/types/index.d.ts.map +1 -0
- package/dist/shared/types/index.js +3 -0
- package/dist/shared/types/index.js.map +1 -0
- package/dist/web/assets/index-C61yAbey.css +32 -0
- package/dist/web/assets/index-WEdVUKxb.js +53 -0
- package/dist/web/assets/index-WEdVUKxb.js.map +1 -0
- package/dist/web/index.html +16 -0
- package/package.json +63 -0
- package/server/index.ts +75 -0
- package/server/routes/api.ts +108 -0
- package/server/services/gitService.ts +91 -0
- package/server/services/worktreeService.ts +181 -0
- package/server/socketHandlers.ts +157 -0
- package/shared/constants.ts +35 -0
- package/shared/types/index.ts +92 -0
- package/tsconfig.json +20 -0
- package/web/index.html +15 -0
- package/web/src/App.tsx +65 -0
- package/web/src/components/Layout/Header.tsx +29 -0
- package/web/src/components/Layout/LeftNavBar.tsx +67 -0
- package/web/src/components/Layout/MainLayout.tsx +23 -0
- package/web/src/components/Layout/StepContainer.tsx +71 -0
- package/web/src/components/Setup/AgentSelector.tsx +27 -0
- package/web/src/components/Setup/BranchSelector.tsx +28 -0
- package/web/src/components/Setup/SetupPanel.tsx +32 -0
- package/web/src/components/Setup/WorktreeCountSelector.tsx +30 -0
- package/web/src/components/Steps/AgentStep.tsx +20 -0
- package/web/src/components/Steps/BranchStep.tsx +20 -0
- package/web/src/components/Steps/WorktreeStep.tsx +41 -0
- package/web/src/components/Terminal/TerminalPanel.tsx +113 -0
- package/web/src/components/Terminal/XTerminal.tsx +203 -0
- package/web/src/hooks/useSocket.ts +80 -0
- package/web/src/main.tsx +10 -0
- package/web/src/stores/useAppStore.ts +348 -0
- package/web/src/styles/global.css +695 -0
- package/web/tsconfig.json +23 -0
- package/web/vite.config.ts +32 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { simpleGit } from 'simple-git';
|
|
2
|
+
export class GitService {
|
|
3
|
+
git;
|
|
4
|
+
cwd;
|
|
5
|
+
constructor(cwd = process.cwd()) {
|
|
6
|
+
this.cwd = cwd;
|
|
7
|
+
this.git = simpleGit(cwd);
|
|
8
|
+
}
|
|
9
|
+
async isGitRepository() {
|
|
10
|
+
try {
|
|
11
|
+
await this.git.status();
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async getBranches() {
|
|
19
|
+
const branchSummary = await this.git.branch(['-a']);
|
|
20
|
+
const branches = [];
|
|
21
|
+
const localBranchNames = new Set();
|
|
22
|
+
// First pass: collect local branches
|
|
23
|
+
for (const [name, data] of Object.entries(branchSummary.branches)) {
|
|
24
|
+
if (!name.startsWith('remotes/')) {
|
|
25
|
+
localBranchNames.add(name);
|
|
26
|
+
branches.push({
|
|
27
|
+
name,
|
|
28
|
+
isCurrent: data.current,
|
|
29
|
+
isRemote: false,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Second pass: add remote branches that don't have local counterparts
|
|
34
|
+
for (const [name] of Object.entries(branchSummary.branches)) {
|
|
35
|
+
if (name.startsWith('remotes/origin/')) {
|
|
36
|
+
const localName = name.replace('remotes/origin/', '');
|
|
37
|
+
// Skip HEAD reference and branches that exist locally
|
|
38
|
+
if (localName !== 'HEAD' && !localBranchNames.has(localName)) {
|
|
39
|
+
branches.push({
|
|
40
|
+
name: localName,
|
|
41
|
+
isCurrent: false,
|
|
42
|
+
isRemote: true,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Sort: current first, then local, then remote, alphabetically within each group
|
|
48
|
+
return branches.sort((a, b) => {
|
|
49
|
+
if (a.isCurrent)
|
|
50
|
+
return -1;
|
|
51
|
+
if (b.isCurrent)
|
|
52
|
+
return 1;
|
|
53
|
+
if (!a.isRemote && b.isRemote)
|
|
54
|
+
return -1;
|
|
55
|
+
if (a.isRemote && !b.isRemote)
|
|
56
|
+
return 1;
|
|
57
|
+
return a.name.localeCompare(b.name);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
async getCurrentBranch() {
|
|
61
|
+
const status = await this.git.status();
|
|
62
|
+
return status.current || 'HEAD';
|
|
63
|
+
}
|
|
64
|
+
async fetch() {
|
|
65
|
+
try {
|
|
66
|
+
await this.git.fetch(['--prune']);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Silently fail fetch - might not have remote configured
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
getCwd() {
|
|
73
|
+
return this.cwd;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Singleton instance
|
|
77
|
+
let gitServiceInstance = null;
|
|
78
|
+
export function getGitService(cwd) {
|
|
79
|
+
if (!gitServiceInstance || (cwd && gitServiceInstance.getCwd() !== cwd)) {
|
|
80
|
+
gitServiceInstance = new GitService(cwd);
|
|
81
|
+
}
|
|
82
|
+
return gitServiceInstance;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=gitService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitService.js","sourceRoot":"","sources":["../../../server/services/gitService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Worktree } from '../../shared/types/index.js';
|
|
2
|
+
export declare class WorktreeService {
|
|
3
|
+
private git;
|
|
4
|
+
private rootDir;
|
|
5
|
+
private createdWorktrees;
|
|
6
|
+
constructor(cwd?: string);
|
|
7
|
+
listWorktrees(): Promise<Worktree[]>;
|
|
8
|
+
createWorktree(baseBranch: string, index: number): Promise<Worktree>;
|
|
9
|
+
createMultipleWorktrees(baseBranch: string, count: number): Promise<Worktree[]>;
|
|
10
|
+
removeWorktree(worktreePath: string): Promise<void>;
|
|
11
|
+
removeAllWorktrees(): Promise<void>;
|
|
12
|
+
cleanup(): Promise<void>;
|
|
13
|
+
getCreatedWorktrees(): string[];
|
|
14
|
+
getRootDir(): string;
|
|
15
|
+
}
|
|
16
|
+
export declare function getWorktreeService(cwd?: string): WorktreeService;
|
|
17
|
+
//# sourceMappingURL=worktreeService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktreeService.d.ts","sourceRoot":"","sources":["../../../server/services/worktreeService.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE5D,qBAAa,eAAe;IAC1B,OAAO,CAAC,GAAG,CAAY;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,gBAAgB,CAA0B;gBAEtC,GAAG,GAAE,MAAsB;IAKjC,aAAa,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAwBpC,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAsCpE,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IA2B/E,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCnD,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAenC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAY9B,mBAAmB,IAAI,MAAM,EAAE;IAI/B,UAAU,IAAI,MAAM;CAGrB;AAKD,wBAAgB,kBAAkB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,eAAe,CAKhE"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { simpleGit } from 'simple-git';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs/promises';
|
|
4
|
+
export class WorktreeService {
|
|
5
|
+
git;
|
|
6
|
+
rootDir;
|
|
7
|
+
createdWorktrees = new Set();
|
|
8
|
+
constructor(cwd = process.cwd()) {
|
|
9
|
+
this.rootDir = cwd;
|
|
10
|
+
this.git = simpleGit(cwd);
|
|
11
|
+
}
|
|
12
|
+
async listWorktrees() {
|
|
13
|
+
const result = await this.git.raw(['worktree', 'list', '--porcelain']);
|
|
14
|
+
const worktrees = [];
|
|
15
|
+
const entries = result.trim().split('\n\n').filter(Boolean);
|
|
16
|
+
for (const entry of entries) {
|
|
17
|
+
const lines = entry.split('\n');
|
|
18
|
+
const worktreePath = lines.find((l) => l.startsWith('worktree '))?.replace('worktree ', '');
|
|
19
|
+
const branchLine = lines.find((l) => l.startsWith('branch '));
|
|
20
|
+
const branch = branchLine?.replace('branch refs/heads/', '');
|
|
21
|
+
if (worktreePath) {
|
|
22
|
+
worktrees.push({
|
|
23
|
+
path: worktreePath,
|
|
24
|
+
branch: branch || 'detached',
|
|
25
|
+
name: path.basename(worktreePath),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return worktrees;
|
|
30
|
+
}
|
|
31
|
+
async createWorktree(baseBranch, index) {
|
|
32
|
+
const worktreeName = `${baseBranch}-project-${index}`;
|
|
33
|
+
// Create worktree in parent directory of the main repo
|
|
34
|
+
const worktreePath = path.join(path.dirname(this.rootDir), worktreeName);
|
|
35
|
+
const newBranchName = worktreeName;
|
|
36
|
+
// Check if directory already exists
|
|
37
|
+
try {
|
|
38
|
+
await fs.access(worktreePath);
|
|
39
|
+
// Directory exists, try to remove it first
|
|
40
|
+
await this.removeWorktree(worktreePath);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Directory doesn't exist, which is good
|
|
44
|
+
}
|
|
45
|
+
// Check if branch already exists
|
|
46
|
+
try {
|
|
47
|
+
const branches = await this.git.branch();
|
|
48
|
+
if (branches.all.includes(newBranchName)) {
|
|
49
|
+
// Branch exists, delete it first
|
|
50
|
+
await this.git.branch(['-D', newBranchName]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Branch doesn't exist, which is good
|
|
55
|
+
}
|
|
56
|
+
// Create worktree with new branch based on the selected branch
|
|
57
|
+
await this.git.raw(['worktree', 'add', '-b', newBranchName, worktreePath, baseBranch]);
|
|
58
|
+
this.createdWorktrees.add(worktreePath);
|
|
59
|
+
return {
|
|
60
|
+
path: worktreePath,
|
|
61
|
+
branch: newBranchName,
|
|
62
|
+
name: worktreeName,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
async createMultipleWorktrees(baseBranch, count) {
|
|
66
|
+
const worktrees = [];
|
|
67
|
+
const createdPaths = [];
|
|
68
|
+
try {
|
|
69
|
+
for (let i = 1; i <= count; i++) {
|
|
70
|
+
const worktree = await this.createWorktree(baseBranch, i);
|
|
71
|
+
worktrees.push(worktree);
|
|
72
|
+
createdPaths.push(worktree.path);
|
|
73
|
+
}
|
|
74
|
+
return worktrees;
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
// Rollback: remove already created worktrees
|
|
78
|
+
console.error(`Failed to create worktree ${createdPaths.length + 1}, rolling back...`);
|
|
79
|
+
for (const worktreePath of createdPaths) {
|
|
80
|
+
try {
|
|
81
|
+
await this.removeWorktree(worktreePath);
|
|
82
|
+
}
|
|
83
|
+
catch (rollbackError) {
|
|
84
|
+
console.error(`Failed to rollback worktree: ${worktreePath}`, rollbackError);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async removeWorktree(worktreePath) {
|
|
91
|
+
const branchName = path.basename(worktreePath);
|
|
92
|
+
try {
|
|
93
|
+
// 1. Force remove worktree
|
|
94
|
+
await this.git.raw(['worktree', 'remove', worktreePath, '--force']);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// 2. If worktree remove fails, try to remove directory manually
|
|
98
|
+
try {
|
|
99
|
+
await fs.rm(worktreePath, { recursive: true, force: true });
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// Ignore errors
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// 3. CRITICAL: Prune orphan worktree references
|
|
106
|
+
try {
|
|
107
|
+
await this.git.raw(['worktree', 'prune']);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// Ignore prune errors
|
|
111
|
+
}
|
|
112
|
+
// 4. Now we can safely delete the branch
|
|
113
|
+
try {
|
|
114
|
+
await this.git.branch(['-D', branchName]);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Branch deletion failure is acceptable
|
|
118
|
+
}
|
|
119
|
+
this.createdWorktrees.delete(worktreePath);
|
|
120
|
+
}
|
|
121
|
+
async removeAllWorktrees() {
|
|
122
|
+
const worktrees = await this.listWorktrees();
|
|
123
|
+
// Filter out the main worktree (usually the first one / the main repo)
|
|
124
|
+
const additionalWorktrees = worktrees.filter(wt => wt.path !== this.rootDir);
|
|
125
|
+
for (const worktree of additionalWorktrees) {
|
|
126
|
+
try {
|
|
127
|
+
await this.removeWorktree(worktree.path);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
console.error(`Failed to remove worktree: ${worktree.path}`, error);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async cleanup() {
|
|
135
|
+
// Remove all worktrees created in this session
|
|
136
|
+
for (const worktreePath of this.createdWorktrees) {
|
|
137
|
+
try {
|
|
138
|
+
await this.removeWorktree(worktreePath);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
console.error(`Failed to cleanup worktree: ${worktreePath}`, error);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
this.createdWorktrees.clear();
|
|
145
|
+
}
|
|
146
|
+
getCreatedWorktrees() {
|
|
147
|
+
return Array.from(this.createdWorktrees);
|
|
148
|
+
}
|
|
149
|
+
getRootDir() {
|
|
150
|
+
return this.rootDir;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Singleton instance
|
|
154
|
+
let worktreeServiceInstance = null;
|
|
155
|
+
export function getWorktreeService(cwd) {
|
|
156
|
+
if (!worktreeServiceInstance || (cwd && worktreeServiceInstance.getRootDir() !== cwd)) {
|
|
157
|
+
worktreeServiceInstance = new WorktreeService(cwd);
|
|
158
|
+
}
|
|
159
|
+
return worktreeServiceInstance;
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=worktreeService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktreeService.js","sourceRoot":"","sources":["../../../server/services/worktreeService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socketHandlers.d.ts","sourceRoot":"","sources":["../../server/socketHandlers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAU,MAAM,WAAW,CAAC;AA8B3C,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,QAsH1D;AAED,wBAAgB,eAAe,IAAI,IAAI,CAMtC"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import * as pty from 'node-pty';
|
|
2
|
+
import { AI_AGENTS } from '../shared/constants.js';
|
|
3
|
+
const sessions = new Map();
|
|
4
|
+
function getAgentCommand(agentType) {
|
|
5
|
+
const agent = AI_AGENTS.find(a => a.id === agentType);
|
|
6
|
+
return agent?.command || 'bash';
|
|
7
|
+
}
|
|
8
|
+
function getShell() {
|
|
9
|
+
return process.platform === 'win32' ? 'powershell.exe' : process.env.SHELL || '/bin/bash';
|
|
10
|
+
}
|
|
11
|
+
export function setupSocketHandlers(io, cwd) {
|
|
12
|
+
io.on('connection', (socket) => {
|
|
13
|
+
console.log(`Client connected: ${socket.id}`);
|
|
14
|
+
// Terminal create
|
|
15
|
+
socket.on('terminal:create', async (data) => {
|
|
16
|
+
const { sessionId, worktreePath, agentType } = data;
|
|
17
|
+
console.log(`Creating terminal session: ${sessionId} at ${worktreePath} with ${agentType}`);
|
|
18
|
+
try {
|
|
19
|
+
const shell = getShell();
|
|
20
|
+
const agentCommand = getAgentCommand(agentType);
|
|
21
|
+
const ptyProcess = pty.spawn(shell, [], {
|
|
22
|
+
name: 'xterm-256color',
|
|
23
|
+
cols: 120,
|
|
24
|
+
rows: 30,
|
|
25
|
+
cwd: worktreePath,
|
|
26
|
+
env: {
|
|
27
|
+
...process.env,
|
|
28
|
+
TERM: 'xterm-256color',
|
|
29
|
+
FORCE_COLOR: '1',
|
|
30
|
+
COLORTERM: 'truecolor',
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
sessions.set(sessionId, {
|
|
34
|
+
pty: ptyProcess,
|
|
35
|
+
worktreePath,
|
|
36
|
+
agentType,
|
|
37
|
+
socketId: socket.id,
|
|
38
|
+
});
|
|
39
|
+
// Send output to client
|
|
40
|
+
ptyProcess.onData((output) => {
|
|
41
|
+
socket.emit('terminal:output', { sessionId, data: output });
|
|
42
|
+
});
|
|
43
|
+
// Handle PTY exit
|
|
44
|
+
ptyProcess.onExit(({ exitCode }) => {
|
|
45
|
+
console.log(`Terminal session ${sessionId} exited with code ${exitCode}`);
|
|
46
|
+
socket.emit('terminal:exit', { sessionId, exitCode });
|
|
47
|
+
sessions.delete(sessionId);
|
|
48
|
+
});
|
|
49
|
+
// Start the AI agent after a short delay
|
|
50
|
+
setTimeout(() => {
|
|
51
|
+
ptyProcess.write(`${agentCommand}\r`);
|
|
52
|
+
}, 500);
|
|
53
|
+
socket.emit('terminal:created', { sessionId });
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
console.error(`Failed to create terminal session: ${sessionId}`, error);
|
|
57
|
+
socket.emit('terminal:error', {
|
|
58
|
+
sessionId,
|
|
59
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
// Terminal input
|
|
64
|
+
socket.on('terminal:input', (data) => {
|
|
65
|
+
const { sessionId, data: input } = data;
|
|
66
|
+
const session = sessions.get(sessionId);
|
|
67
|
+
if (session) {
|
|
68
|
+
session.pty.write(input);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
// Terminal resize
|
|
72
|
+
socket.on('terminal:resize', (data) => {
|
|
73
|
+
const { sessionId, cols, rows } = data;
|
|
74
|
+
const session = sessions.get(sessionId);
|
|
75
|
+
if (session) {
|
|
76
|
+
session.pty.resize(cols, rows);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
// Terminal kill
|
|
80
|
+
socket.on('terminal:kill', (data) => {
|
|
81
|
+
const { sessionId } = data;
|
|
82
|
+
const session = sessions.get(sessionId);
|
|
83
|
+
if (session) {
|
|
84
|
+
console.log(`Killing terminal session: ${sessionId}`);
|
|
85
|
+
session.pty.kill();
|
|
86
|
+
sessions.delete(sessionId);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
// Broadcast input to all terminals
|
|
90
|
+
socket.on('terminal:broadcast', (data) => {
|
|
91
|
+
const socketSessions = Array.from(sessions.entries())
|
|
92
|
+
.filter(([, session]) => session.socketId === socket.id);
|
|
93
|
+
for (const [sessionId, session] of socketSessions) {
|
|
94
|
+
session.pty.write(data.data);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
// Disconnect handling
|
|
98
|
+
socket.on('disconnect', () => {
|
|
99
|
+
console.log(`Client disconnected: ${socket.id}`);
|
|
100
|
+
// Kill all sessions owned by this socket
|
|
101
|
+
const socketSessions = Array.from(sessions.entries())
|
|
102
|
+
.filter(([, session]) => session.socketId === socket.id);
|
|
103
|
+
for (const [sessionId, session] of socketSessions) {
|
|
104
|
+
console.log(`Killing orphaned terminal session: ${sessionId}`);
|
|
105
|
+
session.pty.kill();
|
|
106
|
+
sessions.delete(sessionId);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
export function killAllSessions() {
|
|
112
|
+
for (const [sessionId, session] of sessions) {
|
|
113
|
+
console.log(`Killing terminal session: ${sessionId}`);
|
|
114
|
+
session.pty.kill();
|
|
115
|
+
}
|
|
116
|
+
sessions.clear();
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=socketHandlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socketHandlers.js","sourceRoot":"","sources":["../../server/socketHandlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AgentType } from './types/index.js';
|
|
2
|
+
export declare const AI_AGENTS: AgentType[];
|
|
3
|
+
export declare const MAX_PARALLEL_COUNT = 10;
|
|
4
|
+
export declare const MIN_PARALLEL_COUNT = 1;
|
|
5
|
+
export declare const DEFAULT_PARALLEL_COUNT = 3;
|
|
6
|
+
export declare const BRANCH_POLL_INTERVAL = 5000;
|
|
7
|
+
export declare const APP_NAME = "hjWorktree CLI";
|
|
8
|
+
export declare const APP_VERSION = "2.0.0";
|
|
9
|
+
export declare const DEFAULT_PORT = 3847;
|
|
10
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../shared/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,eAAO,MAAM,SAAS,EAAE,SAAS,EAsBhC,CAAC;AAEF,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAEzC,eAAO,MAAM,QAAQ,mBAAmB,CAAC;AACzC,eAAO,MAAM,WAAW,UAAU,CAAC;AACnC,eAAO,MAAM,YAAY,OAAO,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export const AI_AGENTS = [
|
|
2
|
+
{
|
|
3
|
+
id: 'codex',
|
|
4
|
+
name: 'Codex CLI',
|
|
5
|
+
command: 'codex',
|
|
6
|
+
installCommand: 'npm install -g @openai/codex',
|
|
7
|
+
description: 'OpenAI Codex CLI - AI-powered coding assistant'
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
id: 'claude',
|
|
11
|
+
name: 'Claude Code',
|
|
12
|
+
command: 'claude',
|
|
13
|
+
installCommand: 'npm install -g @anthropic-ai/claude-code',
|
|
14
|
+
description: 'Anthropic Claude Code - Advanced AI coding assistant'
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: 'gemini',
|
|
18
|
+
name: 'Gemini CLI',
|
|
19
|
+
command: 'gemini',
|
|
20
|
+
installCommand: 'npm install -g @google/gemini-cli',
|
|
21
|
+
description: 'Google Gemini CLI - Multi-modal AI assistant'
|
|
22
|
+
}
|
|
23
|
+
];
|
|
24
|
+
export const MAX_PARALLEL_COUNT = 10;
|
|
25
|
+
export const MIN_PARALLEL_COUNT = 1;
|
|
26
|
+
export const DEFAULT_PARALLEL_COUNT = 3;
|
|
27
|
+
export const BRANCH_POLL_INTERVAL = 5000; // 5 seconds
|
|
28
|
+
export const APP_NAME = 'hjWorktree CLI';
|
|
29
|
+
export const APP_VERSION = '2.0.0';
|
|
30
|
+
export const DEFAULT_PORT = 3847;
|
|
31
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../shared/constants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,SAAS,GAAgB;IACpC;QACE,EAAE,EAAE,OAAO;QACX,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,OAAO;QAChB,cAAc,EAAE,8BAA8B;QAC9C,WAAW,EAAE,gDAAgD;KAC9D;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,QAAQ;QACjB,cAAc,EAAE,0CAA0C;QAC1D,WAAW,EAAE,sDAAsD;KACpE;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,QAAQ;QACjB,cAAc,EAAE,mCAAmC;QACnD,WAAW,EAAE,8CAA8C;KAC5D;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC;AACrC,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAExC,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC,CAAC,YAAY;AAEtD,MAAM,CAAC,MAAM,QAAQ,GAAG,gBAAgB,CAAC;AACzC,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC;AACnC,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export type NavigationStep = 'branch' | 'agent' | 'worktree' | 'running';
|
|
2
|
+
export type StepStatus = 'pending' | 'current' | 'completed';
|
|
3
|
+
export interface StepConfig {
|
|
4
|
+
id: NavigationStep;
|
|
5
|
+
number: number;
|
|
6
|
+
label: string;
|
|
7
|
+
description: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const STEP_ORDER: NavigationStep[];
|
|
10
|
+
export type AgentId = 'codex' | 'claude' | 'gemini';
|
|
11
|
+
export interface AgentType {
|
|
12
|
+
id: AgentId;
|
|
13
|
+
name: string;
|
|
14
|
+
command: string;
|
|
15
|
+
installCommand: string;
|
|
16
|
+
description: string;
|
|
17
|
+
}
|
|
18
|
+
export interface Branch {
|
|
19
|
+
name: string;
|
|
20
|
+
isCurrent: boolean;
|
|
21
|
+
isRemote: boolean;
|
|
22
|
+
lastCommit?: string;
|
|
23
|
+
}
|
|
24
|
+
export type AgentStatus = 'initializing' | 'installing' | 'running' | 'stopped' | 'error';
|
|
25
|
+
export interface TerminalInfo {
|
|
26
|
+
sessionId: string;
|
|
27
|
+
worktreePath: string;
|
|
28
|
+
worktreeName: string;
|
|
29
|
+
branchName: string;
|
|
30
|
+
agentType: AgentId;
|
|
31
|
+
status: AgentStatus;
|
|
32
|
+
}
|
|
33
|
+
export interface Worktree {
|
|
34
|
+
path: string;
|
|
35
|
+
branch: string;
|
|
36
|
+
name: string;
|
|
37
|
+
}
|
|
38
|
+
export interface TerminalCreateData {
|
|
39
|
+
sessionId: string;
|
|
40
|
+
worktreePath: string;
|
|
41
|
+
agentType: AgentId;
|
|
42
|
+
}
|
|
43
|
+
export interface TerminalOutputData {
|
|
44
|
+
sessionId: string;
|
|
45
|
+
data: string;
|
|
46
|
+
}
|
|
47
|
+
export interface TerminalInputData {
|
|
48
|
+
sessionId: string;
|
|
49
|
+
data: string;
|
|
50
|
+
}
|
|
51
|
+
export interface TerminalResizeData {
|
|
52
|
+
sessionId: string;
|
|
53
|
+
cols: number;
|
|
54
|
+
rows: number;
|
|
55
|
+
}
|
|
56
|
+
export interface TerminalKillData {
|
|
57
|
+
sessionId: string;
|
|
58
|
+
}
|
|
59
|
+
export interface CreateWorktreesRequest {
|
|
60
|
+
branch: string;
|
|
61
|
+
count: number;
|
|
62
|
+
agentType: AgentId;
|
|
63
|
+
}
|
|
64
|
+
export interface CreateWorktreesResponse {
|
|
65
|
+
worktrees: Worktree[];
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../shared/types/index.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;AAGzE,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;AAG7D,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,cAAc,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAGD,eAAO,MAAM,UAAU,EAAE,cAAc,EAA+C,CAAC;AAGvF,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEpD,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;CACrB;AAGD,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAGD,MAAM,MAAM,WAAW,GAAG,cAAc,GAAG,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE1F,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,WAAW,CAAC;CACrB;AAGD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../shared/types/index.ts"],"names":[],"mappings":"AAcA,sBAAsB;AACtB,MAAM,CAAC,MAAM,UAAU,GAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
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)}
|