@akiojin/gwt 2.2.0 → 2.3.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/README.ja.md +4 -4
- package/README.md +4 -4
- package/dist/cli/ui/components/App.d.ts +4 -4
- package/dist/cli/ui/components/App.d.ts.map +1 -1
- package/dist/cli/ui/components/App.js +144 -105
- package/dist/cli/ui/components/App.js.map +1 -1
- package/dist/cli/ui/components/common/Confirm.d.ts +1 -1
- package/dist/cli/ui/components/common/Confirm.d.ts.map +1 -1
- package/dist/cli/ui/components/common/Confirm.js +7 -7
- package/dist/cli/ui/components/common/Confirm.js.map +1 -1
- package/dist/cli/ui/components/common/ErrorBoundary.d.ts +1 -1
- package/dist/cli/ui/components/common/ErrorBoundary.d.ts.map +1 -1
- package/dist/cli/ui/components/common/ErrorBoundary.js +4 -4
- package/dist/cli/ui/components/common/ErrorBoundary.js.map +1 -1
- package/dist/cli/ui/components/common/Input.d.ts +2 -2
- package/dist/cli/ui/components/common/Input.d.ts.map +1 -1
- package/dist/cli/ui/components/common/Input.js +4 -4
- package/dist/cli/ui/components/common/Input.js.map +1 -1
- package/dist/cli/ui/components/common/LoadingIndicator.d.ts +1 -1
- package/dist/cli/ui/components/common/LoadingIndicator.d.ts.map +1 -1
- package/dist/cli/ui/components/common/LoadingIndicator.js +4 -4
- package/dist/cli/ui/components/common/LoadingIndicator.js.map +1 -1
- package/dist/cli/ui/components/common/Select.d.ts +1 -1
- package/dist/cli/ui/components/common/Select.d.ts.map +1 -1
- package/dist/cli/ui/components/common/Select.js +11 -12
- package/dist/cli/ui/components/common/Select.js.map +1 -1
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts +2 -2
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.js +11 -11
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts +1 -1
- package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/BranchCreatorScreen.js +39 -36
- package/dist/cli/ui/components/screens/BranchCreatorScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/BranchListScreen.d.ts +3 -3
- package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/BranchListScreen.js +55 -50
- package/dist/cli/ui/components/screens/BranchListScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts +2 -2
- package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js +25 -25
- package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts +2 -2
- package/dist/cli/ui/components/screens/PRCleanupScreen.js +21 -21
- package/dist/cli/ui/components/screens/SessionSelectorScreen.d.ts +1 -1
- package/dist/cli/ui/components/screens/SessionSelectorScreen.js +8 -8
- package/dist/cli/ui/components/screens/WorktreeManagerScreen.d.ts +1 -1
- package/dist/cli/ui/components/screens/WorktreeManagerScreen.js +8 -8
- package/dist/cli/ui/screens/BranchActionSelectorScreen.d.ts.map +1 -1
- package/dist/cli/ui/screens/BranchActionSelectorScreen.js +7 -4
- package/dist/cli/ui/screens/BranchActionSelectorScreen.js.map +1 -1
- package/dist/cli/ui/types.d.ts.map +1 -1
- package/dist/client/assets/{index-V6hDu9KS.js → index-Difv1Hwu.js} +2 -2
- package/dist/client/index.html +1 -1
- package/dist/config/builtin-tools.d.ts +10 -2
- package/dist/config/builtin-tools.d.ts.map +1 -1
- package/dist/config/builtin-tools.js +40 -4
- package/dist/config/builtin-tools.js.map +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/tools.d.ts.map +1 -1
- package/dist/config/tools.js +4 -3
- package/dist/config/tools.js.map +1 -1
- package/dist/gemini.d.ts +12 -0
- package/dist/gemini.d.ts.map +1 -0
- package/dist/gemini.js +154 -0
- package/dist/gemini.js.map +1 -0
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -1
- package/dist/qwen.d.ts +12 -0
- package/dist/qwen.d.ts.map +1 -0
- package/dist/qwen.js +154 -0
- package/dist/qwen.js.map +1 -0
- package/dist/services/git.service.d.ts.map +1 -1
- package/dist/services/git.service.js.map +1 -1
- package/dist/web/client/src/components/BranchGraph.d.ts.map +1 -1
- package/dist/web/client/src/components/BranchGraph.js +1 -1
- package/dist/web/client/src/components/BranchGraph.js.map +1 -1
- package/dist/web/client/src/components/EnvEditor.d.ts.map +1 -1
- package/dist/web/client/src/components/EnvEditor.js +7 -4
- package/dist/web/client/src/components/EnvEditor.js.map +1 -1
- package/dist/web/client/src/pages/BranchDetailPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/BranchDetailPage.js +55 -18
- package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
- package/dist/web/client/src/pages/BranchListPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/BranchListPage.js +10 -4
- package/dist/web/client/src/pages/BranchListPage.js.map +1 -1
- package/dist/web/client/src/pages/ConfigManagementPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/ConfigManagementPage.js +4 -2
- package/dist/web/client/src/pages/ConfigManagementPage.js.map +1 -1
- package/package.json +2 -1
- package/src/cli/ui/__tests__/acceptance/navigation.acceptance.test.tsx +69 -50
- package/src/cli/ui/__tests__/components/App.protected-branch.test.tsx +67 -45
- package/src/cli/ui/__tests__/components/App.shortcuts.test.tsx +117 -75
- package/src/cli/ui/__tests__/components/App.test.tsx +45 -37
- package/src/cli/ui/__tests__/components/common/Confirm.test.tsx +35 -22
- package/src/cli/ui/__tests__/components/common/ErrorBoundary.test.tsx +22 -22
- package/src/cli/ui/__tests__/components/common/Input.test.tsx +29 -22
- package/src/cli/ui/__tests__/components/common/LoadingIndicator.test.tsx +40 -34
- package/src/cli/ui/__tests__/components/common/Select.memo.test.tsx +57 -66
- package/src/cli/ui/__tests__/components/common/Select.test.tsx +121 -91
- package/src/cli/ui/__tests__/components/parts/Footer.test.tsx +18 -16
- package/src/cli/ui/__tests__/components/parts/Header.test.tsx +13 -13
- package/src/cli/ui/__tests__/components/parts/ScrollableList.test.tsx +20 -20
- package/src/cli/ui/__tests__/components/parts/Stats.test.tsx +38 -26
- package/src/cli/ui/__tests__/components/screens/AIToolSelectorScreen.test.tsx +31 -31
- package/src/cli/ui/__tests__/components/screens/BranchCreatorScreen.test.tsx +73 -37
- package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +261 -153
- package/src/cli/ui/__tests__/components/screens/ExecutionModeSelectorScreen.test.tsx +38 -32
- package/src/cli/ui/__tests__/components/screens/PRCleanupScreen.test.tsx +39 -39
- package/src/cli/ui/__tests__/components/screens/SessionSelectorScreen.test.tsx +49 -21
- package/src/cli/ui/__tests__/components/screens/WorktreeManagerScreen.test.tsx +52 -28
- package/src/cli/ui/__tests__/integration/edgeCases.test.tsx +84 -48
- package/src/cli/ui/__tests__/integration/navigation.test.tsx +111 -83
- package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx +111 -108
- package/src/cli/ui/__tests__/performance/branchList.performance.test.tsx +50 -37
- package/src/cli/ui/__tests__/performance/useMemoOptimization.test.tsx +75 -76
- package/src/cli/ui/components/App.tsx +247 -150
- package/src/cli/ui/components/common/Confirm.tsx +13 -9
- package/src/cli/ui/components/common/ErrorBoundary.tsx +8 -5
- package/src/cli/ui/components/common/Input.tsx +12 -4
- package/src/cli/ui/components/common/LoadingIndicator.tsx +8 -5
- package/src/cli/ui/components/common/Select.tsx +28 -17
- package/src/cli/ui/components/parts/Header.test.tsx +5 -15
- package/src/cli/ui/components/screens/AIToolSelectorScreen.tsx +19 -13
- package/src/cli/ui/components/screens/BranchCreatorScreen.tsx +74 -54
- package/src/cli/ui/components/screens/BranchListScreen.tsx +92 -75
- package/src/cli/ui/components/screens/ExecutionModeSelectorScreen.tsx +35 -28
- package/src/cli/ui/components/screens/PRCleanupScreen.tsx +22 -22
- package/src/cli/ui/components/screens/SessionSelectorScreen.tsx +8 -8
- package/src/cli/ui/components/screens/WorktreeManagerScreen.tsx +8 -8
- package/src/cli/ui/screens/BranchActionSelectorScreen.tsx +9 -4
- package/src/cli/ui/types.ts +8 -1
- package/src/config/builtin-tools.ts +42 -4
- package/src/config/index.ts +2 -12
- package/src/config/tools.ts +16 -6
- package/src/gemini.ts +202 -0
- package/src/git.ts +2 -1
- package/src/index.ts +30 -0
- package/src/qwen.ts +208 -0
- package/src/services/git.service.ts +2 -1
- package/src/web/client/src/components/BranchGraph.tsx +3 -2
- package/src/web/client/src/components/EnvEditor.tsx +44 -11
- package/src/web/client/src/pages/BranchDetailPage.tsx +165 -54
- package/src/web/client/src/pages/BranchListPage.tsx +37 -13
- package/src/web/client/src/pages/ConfigManagementPage.tsx +28 -9
|
@@ -1,22 +1,28 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import type {
|
|
19
|
-
import {
|
|
1
|
+
import React, {
|
|
2
|
+
useCallback,
|
|
3
|
+
useEffect,
|
|
4
|
+
useMemo,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
} from "react";
|
|
8
|
+
import { useApp } from "ink";
|
|
9
|
+
import { ErrorBoundary } from "./common/ErrorBoundary.js";
|
|
10
|
+
import { BranchListScreen } from "./screens/BranchListScreen.js";
|
|
11
|
+
import { WorktreeManagerScreen } from "./screens/WorktreeManagerScreen.js";
|
|
12
|
+
import { BranchCreatorScreen } from "./screens/BranchCreatorScreen.js";
|
|
13
|
+
import { BranchActionSelectorScreen } from "../screens/BranchActionSelectorScreen.js";
|
|
14
|
+
import { AIToolSelectorScreen } from "./screens/AIToolSelectorScreen.js";
|
|
15
|
+
import { SessionSelectorScreen } from "./screens/SessionSelectorScreen.js";
|
|
16
|
+
import { ExecutionModeSelectorScreen } from "./screens/ExecutionModeSelectorScreen.js";
|
|
17
|
+
import type { AITool } from "./screens/AIToolSelectorScreen.js";
|
|
18
|
+
import type { ExecutionMode } from "./screens/ExecutionModeSelectorScreen.js";
|
|
19
|
+
import type { WorktreeItem } from "./screens/WorktreeManagerScreen.js";
|
|
20
|
+
import { useGitData } from "../hooks/useGitData.js";
|
|
21
|
+
import { useScreenState } from "../hooks/useScreenState.js";
|
|
22
|
+
import { formatBranchItems } from "../utils/branchFormatter.js";
|
|
23
|
+
import { calculateStatistics } from "../utils/statisticsCalculator.js";
|
|
24
|
+
import type { BranchInfo, BranchItem, SelectedBranchState } from "../types.js";
|
|
25
|
+
import { getRepositoryRoot, deleteBranch } from "../../../git.js";
|
|
20
26
|
import {
|
|
21
27
|
createWorktree,
|
|
22
28
|
generateWorktreePath,
|
|
@@ -24,30 +30,30 @@ import {
|
|
|
24
30
|
isProtectedBranchName,
|
|
25
31
|
removeWorktree,
|
|
26
32
|
switchToProtectedBranch,
|
|
27
|
-
} from
|
|
28
|
-
import { getPackageVersion } from
|
|
33
|
+
} from "../../../worktree.js";
|
|
34
|
+
import { getPackageVersion } from "../../../utils.js";
|
|
29
35
|
import {
|
|
30
36
|
resolveBaseBranchLabel,
|
|
31
37
|
resolveBaseBranchRef,
|
|
32
|
-
} from
|
|
38
|
+
} from "../utils/baseBranch.js";
|
|
33
39
|
|
|
34
|
-
const SPINNER_FRAMES = [
|
|
40
|
+
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧"];
|
|
35
41
|
const COMPLETION_HOLD_DURATION_MS = 3000;
|
|
36
42
|
const PROTECTED_BRANCH_WARNING =
|
|
37
|
-
|
|
43
|
+
"Root branches operate directly in the repository root. Create a new branch if you need a dedicated worktree.";
|
|
38
44
|
|
|
39
45
|
const getSpinnerFrame = (index: number): string => {
|
|
40
46
|
const frame = SPINNER_FRAMES[index];
|
|
41
|
-
if (typeof frame ===
|
|
47
|
+
if (typeof frame === "string") {
|
|
42
48
|
return frame;
|
|
43
49
|
}
|
|
44
|
-
return SPINNER_FRAMES[0] ??
|
|
50
|
+
return SPINNER_FRAMES[0] ?? "⠋";
|
|
45
51
|
};
|
|
46
52
|
|
|
47
53
|
export interface SelectionResult {
|
|
48
54
|
branch: string; // Local branch name (without remote prefix)
|
|
49
55
|
displayName: string; // Name that was selected in the UI (may include remote prefix)
|
|
50
|
-
branchType:
|
|
56
|
+
branchType: "local" | "remote";
|
|
51
57
|
remoteBranch?: string; // Full remote ref when branchType === 'remote'
|
|
52
58
|
tool: AITool;
|
|
53
59
|
mode: ExecutionMode;
|
|
@@ -69,24 +75,37 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
69
75
|
// 起動ディレクトリの取得
|
|
70
76
|
const workingDirectory = process.cwd();
|
|
71
77
|
|
|
72
|
-
const { branches, worktrees, loading, error, refresh, lastUpdated } =
|
|
73
|
-
|
|
74
|
-
|
|
78
|
+
const { branches, worktrees, loading, error, refresh, lastUpdated } =
|
|
79
|
+
useGitData({
|
|
80
|
+
enableAutoRefresh: false, // Manual refresh with 'r' key
|
|
81
|
+
});
|
|
75
82
|
const { currentScreen, navigateTo, goBack } = useScreenState();
|
|
76
83
|
|
|
77
84
|
// Version state
|
|
78
85
|
const [version, setVersion] = useState<string | null>(null);
|
|
79
86
|
|
|
80
87
|
// Selection state (for branch → tool → mode flow)
|
|
81
|
-
const [selectedBranch, setSelectedBranch] =
|
|
82
|
-
|
|
88
|
+
const [selectedBranch, setSelectedBranch] =
|
|
89
|
+
useState<SelectedBranchState | null>(null);
|
|
90
|
+
const [creationSourceBranch, setCreationSourceBranch] =
|
|
91
|
+
useState<SelectedBranchState | null>(null);
|
|
83
92
|
const [selectedTool, setSelectedTool] = useState<AITool | null>(null);
|
|
84
93
|
|
|
85
94
|
// PR cleanup feedback
|
|
86
|
-
const [cleanupIndicators, setCleanupIndicators] = useState<
|
|
87
|
-
|
|
95
|
+
const [cleanupIndicators, setCleanupIndicators] = useState<
|
|
96
|
+
Record<
|
|
97
|
+
string,
|
|
98
|
+
{ icon: string; color?: "cyan" | "green" | "yellow" | "red" }
|
|
99
|
+
>
|
|
100
|
+
>({});
|
|
101
|
+
const [cleanupProcessingBranch, setCleanupProcessingBranch] = useState<
|
|
102
|
+
string | null
|
|
103
|
+
>(null);
|
|
88
104
|
const [cleanupInputLocked, setCleanupInputLocked] = useState(false);
|
|
89
|
-
const [cleanupFooterMessage, setCleanupFooterMessage] = useState<{
|
|
105
|
+
const [cleanupFooterMessage, setCleanupFooterMessage] = useState<{
|
|
106
|
+
text: string;
|
|
107
|
+
color?: "cyan" | "green" | "yellow" | "red";
|
|
108
|
+
} | null>(null);
|
|
90
109
|
const [hiddenBranches, setHiddenBranches] = useState<string[]>([]);
|
|
91
110
|
const spinnerFrameIndexRef = useRef(0);
|
|
92
111
|
const [spinnerFrameIndex, setSpinnerFrameIndex] = useState(0);
|
|
@@ -107,7 +126,8 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
107
126
|
}
|
|
108
127
|
|
|
109
128
|
const interval = setInterval(() => {
|
|
110
|
-
spinnerFrameIndexRef.current =
|
|
129
|
+
spinnerFrameIndexRef.current =
|
|
130
|
+
(spinnerFrameIndexRef.current + 1) % SPINNER_FRAMES.length;
|
|
111
131
|
setSpinnerFrameIndex(spinnerFrameIndexRef.current);
|
|
112
132
|
}, 120);
|
|
113
133
|
|
|
@@ -128,20 +148,23 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
128
148
|
if (cleanupProcessingBranch) {
|
|
129
149
|
setCleanupIndicators((prev) => {
|
|
130
150
|
const current = prev[cleanupProcessingBranch];
|
|
131
|
-
if (current && current.icon === frame && current.color ===
|
|
151
|
+
if (current && current.icon === frame && current.color === "cyan") {
|
|
132
152
|
return prev;
|
|
133
153
|
}
|
|
134
154
|
|
|
135
|
-
const next: Record<
|
|
155
|
+
const next: Record<
|
|
156
|
+
string,
|
|
157
|
+
{ icon: string; color?: "cyan" | "green" | "yellow" | "red" }
|
|
158
|
+
> = {
|
|
136
159
|
...prev,
|
|
137
|
-
[cleanupProcessingBranch]: { icon: frame, color:
|
|
160
|
+
[cleanupProcessingBranch]: { icon: frame, color: "cyan" },
|
|
138
161
|
};
|
|
139
162
|
|
|
140
163
|
return next;
|
|
141
164
|
});
|
|
142
165
|
}
|
|
143
166
|
|
|
144
|
-
setCleanupFooterMessage({ text: `Processing... ${frame}`, color:
|
|
167
|
+
setCleanupFooterMessage({ text: `Processing... ${frame}`, color: "cyan" });
|
|
145
168
|
}, [cleanupInputLocked, cleanupProcessingBranch, spinnerFrameIndex]);
|
|
146
169
|
|
|
147
170
|
useEffect(() => {
|
|
@@ -157,28 +180,34 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
157
180
|
}
|
|
158
181
|
}, [branches, hiddenBranches]);
|
|
159
182
|
|
|
160
|
-
useEffect(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
183
|
+
useEffect(
|
|
184
|
+
() => () => {
|
|
185
|
+
if (completionTimerRef.current) {
|
|
186
|
+
clearTimeout(completionTimerRef.current);
|
|
187
|
+
completionTimerRef.current = null;
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
[],
|
|
191
|
+
);
|
|
166
192
|
|
|
167
193
|
const visibleBranches = useMemo(
|
|
168
194
|
() => branches.filter((branch) => !hiddenBranches.includes(branch.name)),
|
|
169
|
-
[branches, hiddenBranches]
|
|
195
|
+
[branches, hiddenBranches],
|
|
170
196
|
);
|
|
171
197
|
|
|
172
198
|
// Helper function to create content-based hash for branches
|
|
173
199
|
const branchHash = useMemo(
|
|
174
|
-
() =>
|
|
175
|
-
|
|
200
|
+
() =>
|
|
201
|
+
visibleBranches
|
|
202
|
+
.map((b) => `${b.name}-${b.type}-${b.isCurrent}`)
|
|
203
|
+
.join(","),
|
|
204
|
+
[visibleBranches],
|
|
176
205
|
);
|
|
177
206
|
|
|
178
207
|
// Helper function to create content-based hash for worktrees
|
|
179
208
|
const worktreeHash = useMemo(
|
|
180
|
-
() => worktrees.map((w) => `${w.branch}-${w.path}`).join(
|
|
181
|
-
[worktrees]
|
|
209
|
+
() => worktrees.map((w) => `${w.branch}-${w.path}`).join(","),
|
|
210
|
+
[worktrees],
|
|
182
211
|
);
|
|
183
212
|
|
|
184
213
|
// Format branches to BranchItems (memoized for performance with content-based dependencies)
|
|
@@ -197,76 +226,89 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
197
226
|
}, [branchHash, worktreeHash, visibleBranches, worktrees]);
|
|
198
227
|
|
|
199
228
|
// Calculate statistics (memoized for performance)
|
|
200
|
-
const stats = useMemo(
|
|
229
|
+
const stats = useMemo(
|
|
230
|
+
() => calculateStatistics(visibleBranches),
|
|
231
|
+
[visibleBranches],
|
|
232
|
+
);
|
|
201
233
|
|
|
202
234
|
// Format worktrees to WorktreeItems
|
|
203
235
|
const worktreeItems: WorktreeItem[] = useMemo(
|
|
204
236
|
() =>
|
|
205
|
-
worktrees.map(
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
237
|
+
worktrees.map(
|
|
238
|
+
(wt): WorktreeItem => ({
|
|
239
|
+
branch: wt.branch,
|
|
240
|
+
path: wt.path,
|
|
241
|
+
isAccessible: wt.isAccessible ?? true,
|
|
242
|
+
}),
|
|
243
|
+
),
|
|
244
|
+
[worktrees],
|
|
211
245
|
);
|
|
212
246
|
|
|
213
247
|
const resolveBaseBranch = useCallback(() => {
|
|
214
248
|
const localMain = branches.find(
|
|
215
249
|
(branch) =>
|
|
216
|
-
branch.type ===
|
|
250
|
+
branch.type === "local" &&
|
|
251
|
+
(branch.name === "main" || branch.name === "master"),
|
|
217
252
|
);
|
|
218
253
|
if (localMain) {
|
|
219
254
|
return localMain.name;
|
|
220
255
|
}
|
|
221
256
|
|
|
222
257
|
const develop = branches.find(
|
|
223
|
-
(branch) =>
|
|
258
|
+
(branch) =>
|
|
259
|
+
branch.type === "local" &&
|
|
260
|
+
(branch.name === "develop" || branch.name === "dev"),
|
|
224
261
|
);
|
|
225
262
|
if (develop) {
|
|
226
263
|
return develop.name;
|
|
227
264
|
}
|
|
228
265
|
|
|
229
|
-
return
|
|
266
|
+
return "main";
|
|
230
267
|
}, [branches]);
|
|
231
268
|
|
|
232
269
|
const baseBranchLabel = useMemo(
|
|
233
|
-
() =>
|
|
234
|
-
|
|
270
|
+
() =>
|
|
271
|
+
resolveBaseBranchLabel(
|
|
272
|
+
creationSourceBranch,
|
|
273
|
+
selectedBranch,
|
|
274
|
+
resolveBaseBranch,
|
|
275
|
+
),
|
|
276
|
+
[creationSourceBranch, resolveBaseBranch, selectedBranch],
|
|
235
277
|
);
|
|
236
278
|
|
|
237
279
|
// Handle branch selection
|
|
238
280
|
const toLocalBranchName = useCallback((remoteName: string) => {
|
|
239
|
-
const segments = remoteName.split(
|
|
281
|
+
const segments = remoteName.split("/");
|
|
240
282
|
if (segments.length <= 1) {
|
|
241
283
|
return remoteName;
|
|
242
284
|
}
|
|
243
|
-
return segments.slice(1).join(
|
|
285
|
+
return segments.slice(1).join("/");
|
|
244
286
|
}, []);
|
|
245
287
|
|
|
246
288
|
const inferBranchCategory = useCallback(
|
|
247
|
-
(branchName: string): BranchInfo[
|
|
289
|
+
(branchName: string): BranchInfo["branchType"] => {
|
|
248
290
|
const matched = branches.find((branch) => branch.name === branchName);
|
|
249
291
|
if (matched) {
|
|
250
292
|
return matched.branchType;
|
|
251
293
|
}
|
|
252
|
-
if (branchName ===
|
|
253
|
-
return
|
|
294
|
+
if (branchName === "main" || branchName === "master") {
|
|
295
|
+
return "main";
|
|
254
296
|
}
|
|
255
|
-
if (branchName ===
|
|
256
|
-
return
|
|
297
|
+
if (branchName === "develop" || branchName === "dev") {
|
|
298
|
+
return "develop";
|
|
257
299
|
}
|
|
258
|
-
if (branchName.startsWith(
|
|
259
|
-
return
|
|
300
|
+
if (branchName.startsWith("feature/")) {
|
|
301
|
+
return "feature";
|
|
260
302
|
}
|
|
261
|
-
if (branchName.startsWith(
|
|
262
|
-
return
|
|
303
|
+
if (branchName.startsWith("hotfix/")) {
|
|
304
|
+
return "hotfix";
|
|
263
305
|
}
|
|
264
|
-
if (branchName.startsWith(
|
|
265
|
-
return
|
|
306
|
+
if (branchName.startsWith("release/")) {
|
|
307
|
+
return "release";
|
|
266
308
|
}
|
|
267
|
-
return
|
|
309
|
+
return "other";
|
|
268
310
|
},
|
|
269
|
-
[branches]
|
|
311
|
+
[branches],
|
|
270
312
|
);
|
|
271
313
|
|
|
272
314
|
const isProtectedSelection = useCallback(
|
|
@@ -277,12 +319,14 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
277
319
|
return (
|
|
278
320
|
isProtectedBranchName(branch.name) ||
|
|
279
321
|
isProtectedBranchName(branch.displayName) ||
|
|
280
|
-
(branch.remoteBranch
|
|
281
|
-
|
|
282
|
-
|
|
322
|
+
(branch.remoteBranch
|
|
323
|
+
? isProtectedBranchName(branch.remoteBranch)
|
|
324
|
+
: false) ||
|
|
325
|
+
branch.branchCategory === "main" ||
|
|
326
|
+
branch.branchCategory === "develop"
|
|
283
327
|
);
|
|
284
328
|
},
|
|
285
|
-
[isProtectedBranchName]
|
|
329
|
+
[isProtectedBranchName],
|
|
286
330
|
);
|
|
287
331
|
|
|
288
332
|
const protectedBranchInfo = useMemo(() => {
|
|
@@ -302,18 +346,18 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
302
346
|
const handleSelect = useCallback(
|
|
303
347
|
(item: BranchItem) => {
|
|
304
348
|
const selection: SelectedBranchState =
|
|
305
|
-
item.type ===
|
|
349
|
+
item.type === "remote"
|
|
306
350
|
? {
|
|
307
351
|
name: toLocalBranchName(item.name),
|
|
308
352
|
displayName: item.name,
|
|
309
|
-
branchType:
|
|
353
|
+
branchType: "remote",
|
|
310
354
|
branchCategory: item.branchType,
|
|
311
355
|
remoteBranch: item.name,
|
|
312
356
|
}
|
|
313
357
|
: {
|
|
314
358
|
name: item.name,
|
|
315
359
|
displayName: item.name,
|
|
316
|
-
branchType:
|
|
360
|
+
branchType: "local",
|
|
317
361
|
branchCategory: item.branchType,
|
|
318
362
|
};
|
|
319
363
|
|
|
@@ -326,15 +370,22 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
326
370
|
if (protectedSelected) {
|
|
327
371
|
setCleanupFooterMessage({
|
|
328
372
|
text: PROTECTED_BRANCH_WARNING,
|
|
329
|
-
color:
|
|
373
|
+
color: "yellow",
|
|
330
374
|
});
|
|
331
375
|
} else {
|
|
332
376
|
setCleanupFooterMessage(null);
|
|
333
377
|
}
|
|
334
378
|
|
|
335
|
-
navigateTo(
|
|
379
|
+
navigateTo("branch-action-selector");
|
|
336
380
|
},
|
|
337
|
-
[
|
|
381
|
+
[
|
|
382
|
+
isProtectedSelection,
|
|
383
|
+
navigateTo,
|
|
384
|
+
setCleanupFooterMessage,
|
|
385
|
+
setCreationSourceBranch,
|
|
386
|
+
setSelectedTool,
|
|
387
|
+
toLocalBranchName,
|
|
388
|
+
],
|
|
338
389
|
);
|
|
339
390
|
|
|
340
391
|
// Handle navigation
|
|
@@ -342,7 +393,7 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
342
393
|
(screen: string) => {
|
|
343
394
|
navigateTo(screen as any);
|
|
344
395
|
},
|
|
345
|
-
[navigateTo]
|
|
396
|
+
[navigateTo],
|
|
346
397
|
);
|
|
347
398
|
|
|
348
399
|
const handleWorktreeSelect = useCallback(
|
|
@@ -350,15 +401,20 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
350
401
|
setSelectedBranch({
|
|
351
402
|
name: worktree.branch,
|
|
352
403
|
displayName: worktree.branch,
|
|
353
|
-
branchType:
|
|
404
|
+
branchType: "local",
|
|
354
405
|
branchCategory: inferBranchCategory(worktree.branch),
|
|
355
406
|
});
|
|
356
407
|
setSelectedTool(null);
|
|
357
408
|
setCreationSourceBranch(null);
|
|
358
409
|
setCleanupFooterMessage(null);
|
|
359
|
-
navigateTo(
|
|
410
|
+
navigateTo("ai-tool-selector");
|
|
360
411
|
},
|
|
361
|
-
[
|
|
412
|
+
[
|
|
413
|
+
inferBranchCategory,
|
|
414
|
+
navigateTo,
|
|
415
|
+
setCleanupFooterMessage,
|
|
416
|
+
setCreationSourceBranch,
|
|
417
|
+
],
|
|
362
418
|
);
|
|
363
419
|
|
|
364
420
|
// Handle branch action selection
|
|
@@ -370,13 +426,13 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
370
426
|
try {
|
|
371
427
|
setCleanupFooterMessage({
|
|
372
428
|
text: `Preparing root branch '${selectedBranch.displayName ?? selectedBranch.name}'...`,
|
|
373
|
-
color:
|
|
429
|
+
color: "cyan",
|
|
374
430
|
});
|
|
375
431
|
const repoRoot = await getRepositoryRoot();
|
|
376
432
|
const remoteRef =
|
|
377
433
|
selectedBranch.remoteBranch ??
|
|
378
|
-
(selectedBranch.branchType ===
|
|
379
|
-
? selectedBranch.displayName ?? selectedBranch.name
|
|
434
|
+
(selectedBranch.branchType === "remote"
|
|
435
|
+
? (selectedBranch.displayName ?? selectedBranch.name)
|
|
380
436
|
: null);
|
|
381
437
|
|
|
382
438
|
const result = await switchToProtectedBranch({
|
|
@@ -386,45 +442,44 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
386
442
|
});
|
|
387
443
|
|
|
388
444
|
let successMessage = `'${selectedBranch.displayName ?? selectedBranch.name}' will use the repository root.`;
|
|
389
|
-
if (result ===
|
|
445
|
+
if (result === "remote") {
|
|
390
446
|
successMessage = `Created a local tracking branch for '${selectedBranch.displayName ?? selectedBranch.name}' and switched to the protected branch.`;
|
|
391
|
-
} else if (result ===
|
|
447
|
+
} else if (result === "local") {
|
|
392
448
|
successMessage = `Checked out '${selectedBranch.displayName ?? selectedBranch.name}' in the repository root.`;
|
|
393
449
|
}
|
|
394
450
|
|
|
395
451
|
setCleanupFooterMessage({
|
|
396
452
|
text: successMessage,
|
|
397
|
-
color:
|
|
453
|
+
color: "green",
|
|
398
454
|
});
|
|
399
455
|
refresh();
|
|
400
|
-
navigateTo(
|
|
456
|
+
navigateTo("ai-tool-selector");
|
|
401
457
|
} catch (error) {
|
|
402
|
-
const message =
|
|
403
|
-
error instanceof Error ? error.message : String(error);
|
|
458
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
404
459
|
setCleanupFooterMessage({
|
|
405
460
|
text: `Failed to switch root branch: ${message}`,
|
|
406
|
-
color:
|
|
461
|
+
color: "red",
|
|
407
462
|
});
|
|
408
|
-
console.error(
|
|
463
|
+
console.error("Failed to switch protected branch:", error);
|
|
409
464
|
}
|
|
410
|
-
}, [
|
|
411
|
-
navigateTo,
|
|
412
|
-
refresh,
|
|
413
|
-
selectedBranch,
|
|
414
|
-
setCleanupFooterMessage,
|
|
415
|
-
]);
|
|
465
|
+
}, [navigateTo, refresh, selectedBranch, setCleanupFooterMessage]);
|
|
416
466
|
|
|
417
467
|
const handleUseExistingBranch = useCallback(() => {
|
|
418
468
|
if (selectedBranch && isProtectedSelection(selectedBranch)) {
|
|
419
469
|
void handleProtectedBranchSwitch();
|
|
420
470
|
return;
|
|
421
471
|
}
|
|
422
|
-
navigateTo(
|
|
423
|
-
}, [
|
|
472
|
+
navigateTo("ai-tool-selector");
|
|
473
|
+
}, [
|
|
474
|
+
handleProtectedBranchSwitch,
|
|
475
|
+
isProtectedSelection,
|
|
476
|
+
navigateTo,
|
|
477
|
+
selectedBranch,
|
|
478
|
+
]);
|
|
424
479
|
|
|
425
480
|
const handleCreateNewBranch = useCallback(() => {
|
|
426
481
|
setCreationSourceBranch(selectedBranch);
|
|
427
|
-
navigateTo(
|
|
482
|
+
navigateTo("branch-creator");
|
|
428
483
|
}, [navigateTo, selectedBranch]);
|
|
429
484
|
|
|
430
485
|
// Handle quit
|
|
@@ -459,16 +514,16 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
459
514
|
setSelectedBranch({
|
|
460
515
|
name: branchName,
|
|
461
516
|
displayName: branchName,
|
|
462
|
-
branchType:
|
|
517
|
+
branchType: "local",
|
|
463
518
|
branchCategory: inferBranchCategory(branchName),
|
|
464
519
|
});
|
|
465
520
|
setSelectedTool(null);
|
|
466
521
|
setCleanupFooterMessage(null);
|
|
467
522
|
|
|
468
|
-
navigateTo(
|
|
523
|
+
navigateTo("ai-tool-selector");
|
|
469
524
|
} catch (error) {
|
|
470
525
|
// On error, go back to branch list
|
|
471
|
-
console.error(
|
|
526
|
+
console.error("Failed to create branch:", error);
|
|
472
527
|
goBack();
|
|
473
528
|
refresh();
|
|
474
529
|
}
|
|
@@ -482,7 +537,7 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
482
537
|
creationSourceBranch,
|
|
483
538
|
inferBranchCategory,
|
|
484
539
|
setCleanupFooterMessage,
|
|
485
|
-
]
|
|
540
|
+
],
|
|
486
541
|
);
|
|
487
542
|
|
|
488
543
|
const handleCleanupCommand = useCallback(async () => {
|
|
@@ -516,7 +571,10 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
516
571
|
setCleanupInputLocked(true);
|
|
517
572
|
setCleanupIndicators({});
|
|
518
573
|
const initialFrame = getSpinnerFrame(0);
|
|
519
|
-
setCleanupFooterMessage({
|
|
574
|
+
setCleanupFooterMessage({
|
|
575
|
+
text: `Processing... ${initialFrame}`,
|
|
576
|
+
color: "cyan",
|
|
577
|
+
});
|
|
520
578
|
setCleanupProcessingBranch(null);
|
|
521
579
|
spinnerFrameIndexRef.current = 0;
|
|
522
580
|
setSpinnerFrameIndex(0);
|
|
@@ -527,7 +585,7 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
527
585
|
} catch (error) {
|
|
528
586
|
const message = error instanceof Error ? error.message : String(error);
|
|
529
587
|
setCleanupIndicators({});
|
|
530
|
-
setCleanupFooterMessage({ text: `❌ ${message}`, color:
|
|
588
|
+
setCleanupFooterMessage({ text: `❌ ${message}`, color: "red" });
|
|
531
589
|
setCleanupInputLocked(false);
|
|
532
590
|
completionTimerRef.current = setTimeout(() => {
|
|
533
591
|
setCleanupFooterMessage(null);
|
|
@@ -538,7 +596,10 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
538
596
|
|
|
539
597
|
if (targets.length === 0) {
|
|
540
598
|
setCleanupIndicators({});
|
|
541
|
-
setCleanupFooterMessage({
|
|
599
|
+
setCleanupFooterMessage({
|
|
600
|
+
text: "✅ Nothing to clean up.",
|
|
601
|
+
color: "green",
|
|
602
|
+
});
|
|
542
603
|
setCleanupInputLocked(false);
|
|
543
604
|
completionTimerRef.current = setTimeout(() => {
|
|
544
605
|
setCleanupFooterMessage(null);
|
|
@@ -548,11 +609,21 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
548
609
|
}
|
|
549
610
|
|
|
550
611
|
// Reset hidden branches that may already be gone
|
|
551
|
-
setHiddenBranches((prev) =>
|
|
612
|
+
setHiddenBranches((prev) =>
|
|
613
|
+
prev.filter(
|
|
614
|
+
(name) => targets.find((t) => t.branch === name) === undefined,
|
|
615
|
+
),
|
|
616
|
+
);
|
|
552
617
|
|
|
553
|
-
const initialIndicators = targets.reduce<
|
|
554
|
-
|
|
555
|
-
|
|
618
|
+
const initialIndicators = targets.reduce<
|
|
619
|
+
Record<
|
|
620
|
+
string,
|
|
621
|
+
{ icon: string; color?: "cyan" | "green" | "yellow" | "red" }
|
|
622
|
+
>
|
|
623
|
+
>((acc, target, index) => {
|
|
624
|
+
const icon = index === 0 ? getSpinnerFrame(0) : "⏳";
|
|
625
|
+
const color: "cyan" | "green" | "yellow" | "red" =
|
|
626
|
+
index === 0 ? "cyan" : "yellow";
|
|
556
627
|
acc[target.branch] = { icon, color };
|
|
557
628
|
return acc;
|
|
558
629
|
}, {});
|
|
@@ -562,7 +633,10 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
562
633
|
setCleanupProcessingBranch(firstTarget ? firstTarget.branch : null);
|
|
563
634
|
spinnerFrameIndexRef.current = 0;
|
|
564
635
|
setSpinnerFrameIndex(0);
|
|
565
|
-
setCleanupFooterMessage({
|
|
636
|
+
setCleanupFooterMessage({
|
|
637
|
+
text: `Processing... ${getSpinnerFrame(0)}`,
|
|
638
|
+
color: "cyan",
|
|
639
|
+
});
|
|
566
640
|
|
|
567
641
|
for (let index = 0; index < targets.length; index += 1) {
|
|
568
642
|
const currentTarget = targets[index];
|
|
@@ -577,11 +651,11 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
577
651
|
|
|
578
652
|
setCleanupIndicators((prev) => {
|
|
579
653
|
const updated = { ...prev };
|
|
580
|
-
updated[target.branch] = { icon: getSpinnerFrame(0), color:
|
|
654
|
+
updated[target.branch] = { icon: getSpinnerFrame(0), color: "cyan" };
|
|
581
655
|
for (const pending of targets.slice(index + 1)) {
|
|
582
656
|
const current = updated[pending.branch];
|
|
583
|
-
if (!current || current.icon !==
|
|
584
|
-
updated[pending.branch] = { icon:
|
|
657
|
+
if (!current || current.icon !== "⏳") {
|
|
658
|
+
updated[pending.branch] = { icon: "⏳", color: "yellow" };
|
|
585
659
|
}
|
|
586
660
|
}
|
|
587
661
|
return updated;
|
|
@@ -590,19 +664,23 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
590
664
|
const shouldSkip =
|
|
591
665
|
target.hasUncommittedChanges ||
|
|
592
666
|
target.hasUnpushedCommits ||
|
|
593
|
-
(target.cleanupType ===
|
|
667
|
+
(target.cleanupType === "worktree-and-branch" &&
|
|
668
|
+
(!target.worktreePath || target.isAccessible === false));
|
|
594
669
|
|
|
595
670
|
if (shouldSkip) {
|
|
596
671
|
setCleanupIndicators((prev) => ({
|
|
597
672
|
...prev,
|
|
598
|
-
[target.branch]: { icon:
|
|
673
|
+
[target.branch]: { icon: "⏭️", color: "yellow" },
|
|
599
674
|
}));
|
|
600
675
|
setCleanupProcessingBranch(null);
|
|
601
676
|
continue;
|
|
602
677
|
}
|
|
603
678
|
|
|
604
679
|
try {
|
|
605
|
-
if (
|
|
680
|
+
if (
|
|
681
|
+
target.cleanupType === "worktree-and-branch" &&
|
|
682
|
+
target.worktreePath
|
|
683
|
+
) {
|
|
606
684
|
await removeWorktree(target.worktreePath, true);
|
|
607
685
|
}
|
|
608
686
|
|
|
@@ -610,13 +688,13 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
610
688
|
succeededBranches.push(target.branch);
|
|
611
689
|
setCleanupIndicators((prev) => ({
|
|
612
690
|
...prev,
|
|
613
|
-
[target.branch]: { icon:
|
|
691
|
+
[target.branch]: { icon: "✅", color: "green" },
|
|
614
692
|
}));
|
|
615
693
|
} catch {
|
|
616
|
-
const icon =
|
|
694
|
+
const icon = "❌";
|
|
617
695
|
setCleanupIndicators((prev) => ({
|
|
618
696
|
...prev,
|
|
619
|
-
[target.branch]: { icon, color:
|
|
697
|
+
[target.branch]: { icon, color: "red" },
|
|
620
698
|
}));
|
|
621
699
|
}
|
|
622
700
|
|
|
@@ -625,23 +703,32 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
625
703
|
|
|
626
704
|
setCleanupProcessingBranch(null);
|
|
627
705
|
setCleanupInputLocked(false);
|
|
628
|
-
setCleanupFooterMessage({
|
|
706
|
+
setCleanupFooterMessage({
|
|
707
|
+
text: "Cleanup completed. Finalizing...",
|
|
708
|
+
color: "green",
|
|
709
|
+
});
|
|
629
710
|
|
|
630
711
|
const holdDuration =
|
|
631
|
-
typeof process !==
|
|
712
|
+
typeof process !== "undefined" && process.env?.NODE_ENV === "test"
|
|
632
713
|
? 0
|
|
633
714
|
: COMPLETION_HOLD_DURATION_MS;
|
|
634
715
|
|
|
635
716
|
completionTimerRef.current = setTimeout(resetAfterWait, holdDuration);
|
|
636
|
-
}, [
|
|
717
|
+
}, [
|
|
718
|
+
cleanupInputLocked,
|
|
719
|
+
deleteBranch,
|
|
720
|
+
getMergedPRWorktrees,
|
|
721
|
+
refresh,
|
|
722
|
+
removeWorktree,
|
|
723
|
+
]);
|
|
637
724
|
|
|
638
725
|
// Handle AI tool selection
|
|
639
726
|
const handleToolSelect = useCallback(
|
|
640
727
|
(tool: AITool) => {
|
|
641
728
|
setSelectedTool(tool);
|
|
642
|
-
navigateTo(
|
|
729
|
+
navigateTo("execution-mode-selector");
|
|
643
730
|
},
|
|
644
|
-
[navigateTo]
|
|
731
|
+
[navigateTo],
|
|
645
732
|
);
|
|
646
733
|
|
|
647
734
|
// Handle session selection
|
|
@@ -651,7 +738,7 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
651
738
|
// For now, just go back to branch list
|
|
652
739
|
goBack();
|
|
653
740
|
},
|
|
654
|
-
[goBack]
|
|
741
|
+
[goBack],
|
|
655
742
|
);
|
|
656
743
|
|
|
657
744
|
// Handle execution mode and skipPermissions selection
|
|
@@ -675,13 +762,13 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
675
762
|
exit();
|
|
676
763
|
}
|
|
677
764
|
},
|
|
678
|
-
[selectedBranch, selectedTool, onExit, exit]
|
|
765
|
+
[selectedBranch, selectedTool, onExit, exit],
|
|
679
766
|
);
|
|
680
767
|
|
|
681
768
|
// Render screen based on currentScreen
|
|
682
769
|
const renderScreen = () => {
|
|
683
770
|
switch (currentScreen) {
|
|
684
|
-
case
|
|
771
|
+
case "branch-list":
|
|
685
772
|
return (
|
|
686
773
|
<BranchListScreen
|
|
687
774
|
branches={branchItems}
|
|
@@ -705,7 +792,7 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
705
792
|
/>
|
|
706
793
|
);
|
|
707
794
|
|
|
708
|
-
case
|
|
795
|
+
case "worktree-manager":
|
|
709
796
|
return (
|
|
710
797
|
<WorktreeManagerScreen
|
|
711
798
|
worktrees={worktreeItems}
|
|
@@ -715,7 +802,7 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
715
802
|
/>
|
|
716
803
|
);
|
|
717
804
|
|
|
718
|
-
case
|
|
805
|
+
case "branch-creator":
|
|
719
806
|
return (
|
|
720
807
|
<BranchCreatorScreen
|
|
721
808
|
onBack={goBack}
|
|
@@ -725,10 +812,10 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
725
812
|
/>
|
|
726
813
|
);
|
|
727
814
|
|
|
728
|
-
case
|
|
815
|
+
case "branch-action-selector": {
|
|
729
816
|
const isProtected = Boolean(protectedBranchInfo);
|
|
730
817
|
const baseProps = {
|
|
731
|
-
selectedBranch: selectedBranch?.displayName ??
|
|
818
|
+
selectedBranch: selectedBranch?.displayName ?? "",
|
|
732
819
|
onUseExisting: handleUseExistingBranch,
|
|
733
820
|
onCreateNew: handleCreateNewBranch,
|
|
734
821
|
onBack: goBack,
|
|
@@ -750,10 +837,16 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
750
837
|
return <BranchActionSelectorScreen {...baseProps} />;
|
|
751
838
|
}
|
|
752
839
|
|
|
753
|
-
case
|
|
754
|
-
return
|
|
840
|
+
case "ai-tool-selector":
|
|
841
|
+
return (
|
|
842
|
+
<AIToolSelectorScreen
|
|
843
|
+
onBack={goBack}
|
|
844
|
+
onSelect={handleToolSelect}
|
|
845
|
+
version={version}
|
|
846
|
+
/>
|
|
847
|
+
);
|
|
755
848
|
|
|
756
|
-
case
|
|
849
|
+
case "session-selector":
|
|
757
850
|
// TODO: Implement session data fetching
|
|
758
851
|
return (
|
|
759
852
|
<SessionSelectorScreen
|
|
@@ -764,9 +857,13 @@ export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
|
|
|
764
857
|
/>
|
|
765
858
|
);
|
|
766
859
|
|
|
767
|
-
case
|
|
860
|
+
case "execution-mode-selector":
|
|
768
861
|
return (
|
|
769
|
-
<ExecutionModeSelectorScreen
|
|
862
|
+
<ExecutionModeSelectorScreen
|
|
863
|
+
onBack={goBack}
|
|
864
|
+
onSelect={handleModeSelect}
|
|
865
|
+
version={version}
|
|
866
|
+
/>
|
|
770
867
|
);
|
|
771
868
|
|
|
772
869
|
default:
|