@akiojin/gwt 2.10.0 → 2.11.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/dist/cli/ui/components/App.d.ts.map +1 -1
- package/dist/cli/ui/components/App.js +5 -47
- package/dist/cli/ui/components/App.js.map +1 -1
- package/dist/cli/ui/components/common/Input.d.ts +1 -1
- package/dist/cli/ui/components/screens/BranchListScreen.d.ts +1 -2
- package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/BranchListScreen.js +19 -14
- package/dist/cli/ui/components/screens/BranchListScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/ModelSelectorScreen.js +6 -6
- package/dist/cli/ui/components/screens/ModelSelectorScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/PRCleanupScreen.js +0 -3
- package/dist/cli/ui/components/screens/PRCleanupScreen.js.map +1 -1
- package/dist/cli/ui/hooks/useGitData.d.ts.map +1 -1
- package/dist/cli/ui/hooks/useGitData.js +43 -2
- package/dist/cli/ui/hooks/useGitData.js.map +1 -1
- package/dist/cli/ui/types.d.ts +16 -4
- package/dist/cli/ui/types.d.ts.map +1 -1
- package/dist/cli/ui/utils/branchFormatter.d.ts.map +1 -1
- package/dist/cli/ui/utils/branchFormatter.js +124 -15
- package/dist/cli/ui/utils/branchFormatter.js.map +1 -1
- package/dist/cli/ui/utils/modelOptions.d.ts.map +1 -1
- package/dist/cli/ui/utils/modelOptions.js.map +1 -1
- package/dist/client/assets/{index-CNWntAlF.js → index-Dl798X5w.js} +1 -1
- package/dist/client/index.html +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/git.d.ts +6 -0
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +40 -5
- package/dist/git.js.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/pages/BranchDetailPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/BranchDetailPage.js +8 -3
- package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
- package/dist/web/server/routes/sessions.d.ts.map +1 -1
- package/dist/web/server/routes/sessions.js +4 -2
- package/dist/web/server/routes/sessions.js.map +1 -1
- package/dist/worktree.d.ts.map +1 -1
- package/dist/worktree.js +31 -44
- package/dist/worktree.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/ui/__tests__/acceptance/navigation.acceptance.test.tsx +9 -17
- package/src/cli/ui/__tests__/components/App.protected-branch.test.tsx +14 -20
- package/src/cli/ui/__tests__/components/App.shortcuts.test.tsx +14 -44
- package/src/cli/ui/__tests__/components/App.test.tsx +8 -15
- package/src/cli/ui/__tests__/components/ModelSelectorScreen.initial.test.tsx +12 -5
- package/src/cli/ui/__tests__/components/common/Confirm.test.tsx +3 -2
- package/src/cli/ui/__tests__/components/common/ErrorBoundary.test.tsx +3 -2
- package/src/cli/ui/__tests__/components/common/Input.test.tsx +3 -2
- package/src/cli/ui/__tests__/components/common/LoadingIndicator.test.tsx +15 -14
- package/src/cli/ui/__tests__/components/common/Select.memo.test.tsx +3 -3
- package/src/cli/ui/__tests__/components/common/Select.test.tsx +1 -4
- package/src/cli/ui/__tests__/components/parts/Footer.test.tsx +3 -2
- package/src/cli/ui/__tests__/components/parts/Header.test.tsx +3 -2
- package/src/cli/ui/__tests__/components/parts/ScrollableList.test.tsx +3 -2
- package/src/cli/ui/__tests__/components/parts/Stats.test.tsx +3 -2
- package/src/cli/ui/__tests__/components/screens/AIToolSelectorScreen.test.tsx +3 -2
- package/src/cli/ui/__tests__/components/screens/BranchCreatorScreen.test.tsx +3 -2
- package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +31 -41
- package/src/cli/ui/__tests__/components/screens/ExecutionModeSelectorScreen.test.tsx +3 -2
- package/src/cli/ui/__tests__/components/screens/PRCleanupScreen.test.tsx +3 -2
- package/src/cli/ui/__tests__/components/screens/SessionSelectorScreen.test.tsx +3 -2
- package/src/cli/ui/__tests__/hooks/useScreenState.test.ts +18 -17
- package/src/cli/ui/__tests__/hooks/useTerminalSize.test.ts +3 -2
- package/src/cli/ui/__tests__/integration/edgeCases.test.tsx +5 -12
- package/src/cli/ui/__tests__/integration/navigation.test.tsx +15 -10
- package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx +3 -2
- package/src/cli/ui/__tests__/performance/branchList.performance.test.tsx +0 -4
- package/src/cli/ui/__tests__/performance/useMemoOptimization.test.tsx +3 -5
- package/src/cli/ui/__tests__/utils/branchFormatter.test.ts +24 -22
- package/src/cli/ui/components/App.tsx +3 -74
- package/src/cli/ui/components/common/Input.tsx +1 -1
- package/src/cli/ui/components/screens/BranchListScreen.tsx +32 -22
- package/src/cli/ui/components/screens/ModelSelectorScreen.tsx +46 -49
- package/src/cli/ui/components/screens/PRCleanupScreen.tsx +0 -3
- package/src/cli/ui/hooks/useGitData.ts +59 -1
- package/src/cli/ui/screens/__tests__/BranchActionSelectorScreen.test.tsx +3 -2
- package/src/cli/ui/types.ts +24 -5
- package/src/cli/ui/utils/branchFormatter.ts +123 -15
- package/src/cli/ui/utils/modelOptions.test.ts +4 -6
- package/src/cli/ui/utils/modelOptions.ts +1 -2
- package/src/config/index.ts +2 -1
- package/src/git.ts +56 -16
- package/src/web/client/src/components/BranchGraph.tsx +1 -1
- package/src/web/client/src/pages/BranchDetailPage.tsx +8 -3
- package/src/web/server/routes/sessions.ts +12 -5
- package/src/worktree.ts +31 -59
- package/dist/cli/ui/components/screens/WorktreeManagerScreen.d.ts +0 -20
- package/dist/cli/ui/components/screens/WorktreeManagerScreen.d.ts.map +0 -1
- package/dist/cli/ui/components/screens/WorktreeManagerScreen.js +0 -65
- package/dist/cli/ui/components/screens/WorktreeManagerScreen.js.map +0 -1
- package/src/cli/ui/__tests__/components/screens/WorktreeManagerScreen.test.tsx +0 -151
- package/src/cli/ui/components/screens/WorktreeManagerScreen.tsx +0 -117
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
export interface WorktreeItem {
|
|
3
|
-
branch: string;
|
|
4
|
-
path: string;
|
|
5
|
-
isAccessible: boolean;
|
|
6
|
-
label?: string;
|
|
7
|
-
value?: string;
|
|
8
|
-
}
|
|
9
|
-
export interface WorktreeManagerScreenProps {
|
|
10
|
-
worktrees: WorktreeItem[];
|
|
11
|
-
onBack: () => void;
|
|
12
|
-
onSelect: (worktree: WorktreeItem) => void;
|
|
13
|
-
version?: string | null;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* WorktreeManagerScreen - Screen for managing worktrees
|
|
17
|
-
* Layout: Header + Stats + Worktree List + Footer
|
|
18
|
-
*/
|
|
19
|
-
export declare function WorktreeManagerScreen({ worktrees, onBack, onSelect, version, }: WorktreeManagerScreenProps): React.JSX.Element;
|
|
20
|
-
//# sourceMappingURL=WorktreeManagerScreen.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WorktreeManagerScreen.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ui/components/screens/WorktreeManagerScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;IAC3C,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,MAAM,EACN,QAAQ,EACR,OAAO,GACR,EAAE,0BAA0B,qBAqF5B"}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Box, Text, useInput } from "ink";
|
|
3
|
-
import { Header } from "../parts/Header.js";
|
|
4
|
-
import { Footer } from "../parts/Footer.js";
|
|
5
|
-
import { Select } from "../common/Select.js";
|
|
6
|
-
import { useTerminalSize } from "../../hooks/useTerminalSize.js";
|
|
7
|
-
/**
|
|
8
|
-
* WorktreeManagerScreen - Screen for managing worktrees
|
|
9
|
-
* Layout: Header + Stats + Worktree List + Footer
|
|
10
|
-
*/
|
|
11
|
-
export function WorktreeManagerScreen({ worktrees, onBack, onSelect, version, }) {
|
|
12
|
-
const { rows } = useTerminalSize();
|
|
13
|
-
// Handle keyboard input
|
|
14
|
-
// Note: Select component handles Enter and arrow keys
|
|
15
|
-
useInput((input, key) => {
|
|
16
|
-
if (key.escape) {
|
|
17
|
-
onBack();
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
// Calculate accessible and inaccessible counts
|
|
21
|
-
const accessibleCount = worktrees.filter((w) => w.isAccessible).length;
|
|
22
|
-
const inaccessibleCount = worktrees.filter((w) => !w.isAccessible).length;
|
|
23
|
-
// Format worktrees for Select component
|
|
24
|
-
const worktreeItems = worktrees.map((wt) => ({
|
|
25
|
-
...wt,
|
|
26
|
-
label: wt.isAccessible
|
|
27
|
-
? `${wt.branch} (${wt.path})`
|
|
28
|
-
: `${wt.branch} (${wt.path}) [Inaccessible]`,
|
|
29
|
-
value: wt.branch,
|
|
30
|
-
}));
|
|
31
|
-
// Calculate available space for worktree list
|
|
32
|
-
const headerLines = 2;
|
|
33
|
-
const statsLines = 1;
|
|
34
|
-
const emptyLine = 1;
|
|
35
|
-
const footerLines = 1;
|
|
36
|
-
const fixedLines = headerLines + statsLines + emptyLine + footerLines;
|
|
37
|
-
const contentHeight = rows - fixedLines;
|
|
38
|
-
const limit = Math.max(5, contentHeight);
|
|
39
|
-
// Footer actions
|
|
40
|
-
const footerActions = [
|
|
41
|
-
{ key: "enter", description: "Select" },
|
|
42
|
-
{ key: "esc", description: "Back" },
|
|
43
|
-
];
|
|
44
|
-
return (React.createElement(Box, { flexDirection: "column", height: rows },
|
|
45
|
-
React.createElement(Header, { title: "Worktree Manager", titleColor: "magenta", version: version }),
|
|
46
|
-
React.createElement(Box, { marginTop: 1 },
|
|
47
|
-
React.createElement(Box, { flexDirection: "row" },
|
|
48
|
-
React.createElement(Box, { marginRight: 2 },
|
|
49
|
-
React.createElement(Text, null,
|
|
50
|
-
"Total: ",
|
|
51
|
-
React.createElement(Text, { bold: true }, worktrees.length))),
|
|
52
|
-
React.createElement(Box, { marginRight: 2 },
|
|
53
|
-
React.createElement(Text, { color: "green" },
|
|
54
|
-
"Accessible: ",
|
|
55
|
-
React.createElement(Text, { bold: true }, accessibleCount))),
|
|
56
|
-
inaccessibleCount > 0 && (React.createElement(Box, null,
|
|
57
|
-
React.createElement(Text, { color: "red" },
|
|
58
|
-
"Inaccessible: ",
|
|
59
|
-
React.createElement(Text, { bold: true }, inaccessibleCount)))))),
|
|
60
|
-
React.createElement(Box, { height: 1 }),
|
|
61
|
-
React.createElement(Box, { flexDirection: "column", flexGrow: 1 }, worktrees.length === 0 ? (React.createElement(Box, null,
|
|
62
|
-
React.createElement(Text, { dimColor: true }, "No worktrees found"))) : (React.createElement(Select, { items: worktreeItems, onSelect: onSelect, limit: limit }))),
|
|
63
|
-
React.createElement(Footer, { actions: footerActions })));
|
|
64
|
-
}
|
|
65
|
-
//# sourceMappingURL=WorktreeManagerScreen.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WorktreeManagerScreen.js","sourceRoot":"","sources":["../../../../../src/cli/ui/components/screens/WorktreeManagerScreen.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @vitest-environment happy-dom
|
|
3
|
-
*/
|
|
4
|
-
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
5
|
-
import { render } from "@testing-library/react";
|
|
6
|
-
import React from "react";
|
|
7
|
-
import { WorktreeManagerScreen } from "../../../components/screens/WorktreeManagerScreen.js";
|
|
8
|
-
import { Window } from "happy-dom";
|
|
9
|
-
|
|
10
|
-
describe("WorktreeManagerScreen", () => {
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
// Setup happy-dom
|
|
13
|
-
const window = new Window();
|
|
14
|
-
globalThis.window = window as any;
|
|
15
|
-
globalThis.document = window.document as any;
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
const mockWorktrees = [
|
|
19
|
-
{
|
|
20
|
-
branch: "feature/test-1",
|
|
21
|
-
path: "/path/to/worktree-1",
|
|
22
|
-
isAccessible: true,
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
branch: "feature/test-2",
|
|
26
|
-
path: "/path/to/worktree-2",
|
|
27
|
-
isAccessible: true,
|
|
28
|
-
},
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
it("should render header with title", () => {
|
|
32
|
-
const onBack = vi.fn();
|
|
33
|
-
const onSelect = vi.fn();
|
|
34
|
-
const { getByText } = render(
|
|
35
|
-
<WorktreeManagerScreen
|
|
36
|
-
worktrees={mockWorktrees}
|
|
37
|
-
onBack={onBack}
|
|
38
|
-
onSelect={onSelect}
|
|
39
|
-
/>,
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
expect(getByText(/Worktree Manager/i)).toBeDefined();
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it("should render worktree list", () => {
|
|
46
|
-
const onBack = vi.fn();
|
|
47
|
-
const onSelect = vi.fn();
|
|
48
|
-
const { getByText } = render(
|
|
49
|
-
<WorktreeManagerScreen
|
|
50
|
-
worktrees={mockWorktrees}
|
|
51
|
-
onBack={onBack}
|
|
52
|
-
onSelect={onSelect}
|
|
53
|
-
/>,
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
expect(getByText(/feature\/test-1/)).toBeDefined();
|
|
57
|
-
expect(getByText(/feature\/test-2/)).toBeDefined();
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it("should render footer with actions", () => {
|
|
61
|
-
const onBack = vi.fn();
|
|
62
|
-
const onSelect = vi.fn();
|
|
63
|
-
const { getAllByText } = render(
|
|
64
|
-
<WorktreeManagerScreen
|
|
65
|
-
worktrees={mockWorktrees}
|
|
66
|
-
onBack={onBack}
|
|
67
|
-
onSelect={onSelect}
|
|
68
|
-
/>,
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
expect(getAllByText(/enter/i).length).toBeGreaterThan(0);
|
|
72
|
-
expect(getAllByText(/esc/i).length).toBeGreaterThan(0);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it("should handle empty worktree list", () => {
|
|
76
|
-
const onBack = vi.fn();
|
|
77
|
-
const onSelect = vi.fn();
|
|
78
|
-
const { getByText } = render(
|
|
79
|
-
<WorktreeManagerScreen
|
|
80
|
-
worktrees={[]}
|
|
81
|
-
onBack={onBack}
|
|
82
|
-
onSelect={onSelect}
|
|
83
|
-
/>,
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
expect(getByText(/No worktrees found/i)).toBeDefined();
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it("should display inaccessible worktrees differently", () => {
|
|
90
|
-
const worktreesWithInaccessible = [
|
|
91
|
-
{
|
|
92
|
-
branch: "feature/accessible",
|
|
93
|
-
path: "/path/accessible",
|
|
94
|
-
isAccessible: true,
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
branch: "feature/inaccessible",
|
|
98
|
-
path: "/path/inaccessible",
|
|
99
|
-
isAccessible: false,
|
|
100
|
-
},
|
|
101
|
-
];
|
|
102
|
-
|
|
103
|
-
const onBack = vi.fn();
|
|
104
|
-
const onSelect = vi.fn();
|
|
105
|
-
const { getByText } = render(
|
|
106
|
-
<WorktreeManagerScreen
|
|
107
|
-
worktrees={worktreesWithInaccessible}
|
|
108
|
-
onBack={onBack}
|
|
109
|
-
onSelect={onSelect}
|
|
110
|
-
/>,
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
expect(getByText(/feature\/accessible/)).toBeDefined();
|
|
114
|
-
expect(getByText(/feature\/inaccessible/)).toBeDefined();
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it("should use terminal height for layout calculation", () => {
|
|
118
|
-
const originalRows = process.stdout.rows;
|
|
119
|
-
process.stdout.rows = 30;
|
|
120
|
-
|
|
121
|
-
const onBack = vi.fn();
|
|
122
|
-
const onSelect = vi.fn();
|
|
123
|
-
const { container } = render(
|
|
124
|
-
<WorktreeManagerScreen
|
|
125
|
-
worktrees={mockWorktrees}
|
|
126
|
-
onBack={onBack}
|
|
127
|
-
onSelect={onSelect}
|
|
128
|
-
/>,
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
expect(container).toBeDefined();
|
|
132
|
-
|
|
133
|
-
process.stdout.rows = originalRows;
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it("should display worktree count in stats", () => {
|
|
137
|
-
const onBack = vi.fn();
|
|
138
|
-
const onSelect = vi.fn();
|
|
139
|
-
const { getByText, getAllByText } = render(
|
|
140
|
-
<WorktreeManagerScreen
|
|
141
|
-
worktrees={mockWorktrees}
|
|
142
|
-
onBack={onBack}
|
|
143
|
-
onSelect={onSelect}
|
|
144
|
-
/>,
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
// Check for worktree count
|
|
148
|
-
expect(getByText(/Total:/i)).toBeDefined();
|
|
149
|
-
expect(getAllByText(/2/).length).toBeGreaterThan(0);
|
|
150
|
-
});
|
|
151
|
-
});
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Box, Text, useInput } from "ink";
|
|
3
|
-
import { Header } from "../parts/Header.js";
|
|
4
|
-
import { Footer } from "../parts/Footer.js";
|
|
5
|
-
import { Select } from "../common/Select.js";
|
|
6
|
-
import { useTerminalSize } from "../../hooks/useTerminalSize.js";
|
|
7
|
-
|
|
8
|
-
export interface WorktreeItem {
|
|
9
|
-
branch: string;
|
|
10
|
-
path: string;
|
|
11
|
-
isAccessible: boolean;
|
|
12
|
-
label?: string;
|
|
13
|
-
value?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface WorktreeManagerScreenProps {
|
|
17
|
-
worktrees: WorktreeItem[];
|
|
18
|
-
onBack: () => void;
|
|
19
|
-
onSelect: (worktree: WorktreeItem) => void;
|
|
20
|
-
version?: string | null;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* WorktreeManagerScreen - Screen for managing worktrees
|
|
25
|
-
* Layout: Header + Stats + Worktree List + Footer
|
|
26
|
-
*/
|
|
27
|
-
export function WorktreeManagerScreen({
|
|
28
|
-
worktrees,
|
|
29
|
-
onBack,
|
|
30
|
-
onSelect,
|
|
31
|
-
version,
|
|
32
|
-
}: WorktreeManagerScreenProps) {
|
|
33
|
-
const { rows } = useTerminalSize();
|
|
34
|
-
|
|
35
|
-
// Handle keyboard input
|
|
36
|
-
// Note: Select component handles Enter and arrow keys
|
|
37
|
-
useInput((input, key) => {
|
|
38
|
-
if (key.escape) {
|
|
39
|
-
onBack();
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
// Calculate accessible and inaccessible counts
|
|
44
|
-
const accessibleCount = worktrees.filter((w) => w.isAccessible).length;
|
|
45
|
-
const inaccessibleCount = worktrees.filter((w) => !w.isAccessible).length;
|
|
46
|
-
|
|
47
|
-
// Format worktrees for Select component
|
|
48
|
-
const worktreeItems = worktrees.map((wt) => ({
|
|
49
|
-
...wt,
|
|
50
|
-
label: wt.isAccessible
|
|
51
|
-
? `${wt.branch} (${wt.path})`
|
|
52
|
-
: `${wt.branch} (${wt.path}) [Inaccessible]`,
|
|
53
|
-
value: wt.branch,
|
|
54
|
-
}));
|
|
55
|
-
|
|
56
|
-
// Calculate available space for worktree list
|
|
57
|
-
const headerLines = 2;
|
|
58
|
-
const statsLines = 1;
|
|
59
|
-
const emptyLine = 1;
|
|
60
|
-
const footerLines = 1;
|
|
61
|
-
const fixedLines = headerLines + statsLines + emptyLine + footerLines;
|
|
62
|
-
const contentHeight = rows - fixedLines;
|
|
63
|
-
const limit = Math.max(5, contentHeight);
|
|
64
|
-
|
|
65
|
-
// Footer actions
|
|
66
|
-
const footerActions = [
|
|
67
|
-
{ key: "enter", description: "Select" },
|
|
68
|
-
{ key: "esc", description: "Back" },
|
|
69
|
-
];
|
|
70
|
-
|
|
71
|
-
return (
|
|
72
|
-
<Box flexDirection="column" height={rows}>
|
|
73
|
-
{/* Header */}
|
|
74
|
-
<Header title="Worktree Manager" titleColor="magenta" version={version} />
|
|
75
|
-
|
|
76
|
-
{/* Stats */}
|
|
77
|
-
<Box marginTop={1}>
|
|
78
|
-
<Box flexDirection="row">
|
|
79
|
-
<Box marginRight={2}>
|
|
80
|
-
<Text>
|
|
81
|
-
Total: <Text bold>{worktrees.length}</Text>
|
|
82
|
-
</Text>
|
|
83
|
-
</Box>
|
|
84
|
-
<Box marginRight={2}>
|
|
85
|
-
<Text color="green">
|
|
86
|
-
Accessible: <Text bold>{accessibleCount}</Text>
|
|
87
|
-
</Text>
|
|
88
|
-
</Box>
|
|
89
|
-
{inaccessibleCount > 0 && (
|
|
90
|
-
<Box>
|
|
91
|
-
<Text color="red">
|
|
92
|
-
Inaccessible: <Text bold>{inaccessibleCount}</Text>
|
|
93
|
-
</Text>
|
|
94
|
-
</Box>
|
|
95
|
-
)}
|
|
96
|
-
</Box>
|
|
97
|
-
</Box>
|
|
98
|
-
|
|
99
|
-
{/* Empty line */}
|
|
100
|
-
<Box height={1} />
|
|
101
|
-
|
|
102
|
-
{/* Content */}
|
|
103
|
-
<Box flexDirection="column" flexGrow={1}>
|
|
104
|
-
{worktrees.length === 0 ? (
|
|
105
|
-
<Box>
|
|
106
|
-
<Text dimColor>No worktrees found</Text>
|
|
107
|
-
</Box>
|
|
108
|
-
) : (
|
|
109
|
-
<Select items={worktreeItems} onSelect={onSelect} limit={limit} />
|
|
110
|
-
)}
|
|
111
|
-
</Box>
|
|
112
|
-
|
|
113
|
-
{/* Footer */}
|
|
114
|
-
<Footer actions={footerActions} />
|
|
115
|
-
</Box>
|
|
116
|
-
);
|
|
117
|
-
}
|