@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.
Files changed (96) hide show
  1. package/dist/cli/ui/components/App.d.ts.map +1 -1
  2. package/dist/cli/ui/components/App.js +5 -47
  3. package/dist/cli/ui/components/App.js.map +1 -1
  4. package/dist/cli/ui/components/common/Input.d.ts +1 -1
  5. package/dist/cli/ui/components/screens/BranchListScreen.d.ts +1 -2
  6. package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +1 -1
  7. package/dist/cli/ui/components/screens/BranchListScreen.js +19 -14
  8. package/dist/cli/ui/components/screens/BranchListScreen.js.map +1 -1
  9. package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts.map +1 -1
  10. package/dist/cli/ui/components/screens/ModelSelectorScreen.js +6 -6
  11. package/dist/cli/ui/components/screens/ModelSelectorScreen.js.map +1 -1
  12. package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts.map +1 -1
  13. package/dist/cli/ui/components/screens/PRCleanupScreen.js +0 -3
  14. package/dist/cli/ui/components/screens/PRCleanupScreen.js.map +1 -1
  15. package/dist/cli/ui/hooks/useGitData.d.ts.map +1 -1
  16. package/dist/cli/ui/hooks/useGitData.js +43 -2
  17. package/dist/cli/ui/hooks/useGitData.js.map +1 -1
  18. package/dist/cli/ui/types.d.ts +16 -4
  19. package/dist/cli/ui/types.d.ts.map +1 -1
  20. package/dist/cli/ui/utils/branchFormatter.d.ts.map +1 -1
  21. package/dist/cli/ui/utils/branchFormatter.js +124 -15
  22. package/dist/cli/ui/utils/branchFormatter.js.map +1 -1
  23. package/dist/cli/ui/utils/modelOptions.d.ts.map +1 -1
  24. package/dist/cli/ui/utils/modelOptions.js.map +1 -1
  25. package/dist/client/assets/{index-CNWntAlF.js → index-Dl798X5w.js} +1 -1
  26. package/dist/client/index.html +1 -1
  27. package/dist/config/index.d.ts.map +1 -1
  28. package/dist/config/index.js.map +1 -1
  29. package/dist/git.d.ts +6 -0
  30. package/dist/git.d.ts.map +1 -1
  31. package/dist/git.js +40 -5
  32. package/dist/git.js.map +1 -1
  33. package/dist/web/client/src/components/BranchGraph.js +1 -1
  34. package/dist/web/client/src/components/BranchGraph.js.map +1 -1
  35. package/dist/web/client/src/pages/BranchDetailPage.d.ts.map +1 -1
  36. package/dist/web/client/src/pages/BranchDetailPage.js +8 -3
  37. package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
  38. package/dist/web/server/routes/sessions.d.ts.map +1 -1
  39. package/dist/web/server/routes/sessions.js +4 -2
  40. package/dist/web/server/routes/sessions.js.map +1 -1
  41. package/dist/worktree.d.ts.map +1 -1
  42. package/dist/worktree.js +31 -44
  43. package/dist/worktree.js.map +1 -1
  44. package/package.json +1 -1
  45. package/src/cli/ui/__tests__/acceptance/navigation.acceptance.test.tsx +9 -17
  46. package/src/cli/ui/__tests__/components/App.protected-branch.test.tsx +14 -20
  47. package/src/cli/ui/__tests__/components/App.shortcuts.test.tsx +14 -44
  48. package/src/cli/ui/__tests__/components/App.test.tsx +8 -15
  49. package/src/cli/ui/__tests__/components/ModelSelectorScreen.initial.test.tsx +12 -5
  50. package/src/cli/ui/__tests__/components/common/Confirm.test.tsx +3 -2
  51. package/src/cli/ui/__tests__/components/common/ErrorBoundary.test.tsx +3 -2
  52. package/src/cli/ui/__tests__/components/common/Input.test.tsx +3 -2
  53. package/src/cli/ui/__tests__/components/common/LoadingIndicator.test.tsx +15 -14
  54. package/src/cli/ui/__tests__/components/common/Select.memo.test.tsx +3 -3
  55. package/src/cli/ui/__tests__/components/common/Select.test.tsx +1 -4
  56. package/src/cli/ui/__tests__/components/parts/Footer.test.tsx +3 -2
  57. package/src/cli/ui/__tests__/components/parts/Header.test.tsx +3 -2
  58. package/src/cli/ui/__tests__/components/parts/ScrollableList.test.tsx +3 -2
  59. package/src/cli/ui/__tests__/components/parts/Stats.test.tsx +3 -2
  60. package/src/cli/ui/__tests__/components/screens/AIToolSelectorScreen.test.tsx +3 -2
  61. package/src/cli/ui/__tests__/components/screens/BranchCreatorScreen.test.tsx +3 -2
  62. package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +31 -41
  63. package/src/cli/ui/__tests__/components/screens/ExecutionModeSelectorScreen.test.tsx +3 -2
  64. package/src/cli/ui/__tests__/components/screens/PRCleanupScreen.test.tsx +3 -2
  65. package/src/cli/ui/__tests__/components/screens/SessionSelectorScreen.test.tsx +3 -2
  66. package/src/cli/ui/__tests__/hooks/useScreenState.test.ts +18 -17
  67. package/src/cli/ui/__tests__/hooks/useTerminalSize.test.ts +3 -2
  68. package/src/cli/ui/__tests__/integration/edgeCases.test.tsx +5 -12
  69. package/src/cli/ui/__tests__/integration/navigation.test.tsx +15 -10
  70. package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx +3 -2
  71. package/src/cli/ui/__tests__/performance/branchList.performance.test.tsx +0 -4
  72. package/src/cli/ui/__tests__/performance/useMemoOptimization.test.tsx +3 -5
  73. package/src/cli/ui/__tests__/utils/branchFormatter.test.ts +24 -22
  74. package/src/cli/ui/components/App.tsx +3 -74
  75. package/src/cli/ui/components/common/Input.tsx +1 -1
  76. package/src/cli/ui/components/screens/BranchListScreen.tsx +32 -22
  77. package/src/cli/ui/components/screens/ModelSelectorScreen.tsx +46 -49
  78. package/src/cli/ui/components/screens/PRCleanupScreen.tsx +0 -3
  79. package/src/cli/ui/hooks/useGitData.ts +59 -1
  80. package/src/cli/ui/screens/__tests__/BranchActionSelectorScreen.test.tsx +3 -2
  81. package/src/cli/ui/types.ts +24 -5
  82. package/src/cli/ui/utils/branchFormatter.ts +123 -15
  83. package/src/cli/ui/utils/modelOptions.test.ts +4 -6
  84. package/src/cli/ui/utils/modelOptions.ts +1 -2
  85. package/src/config/index.ts +2 -1
  86. package/src/git.ts +56 -16
  87. package/src/web/client/src/components/BranchGraph.tsx +1 -1
  88. package/src/web/client/src/pages/BranchDetailPage.tsx +8 -3
  89. package/src/web/server/routes/sessions.ts +12 -5
  90. package/src/worktree.ts +31 -59
  91. package/dist/cli/ui/components/screens/WorktreeManagerScreen.d.ts +0 -20
  92. package/dist/cli/ui/components/screens/WorktreeManagerScreen.d.ts.map +0 -1
  93. package/dist/cli/ui/components/screens/WorktreeManagerScreen.js +0 -65
  94. package/dist/cli/ui/components/screens/WorktreeManagerScreen.js.map +0 -1
  95. package/src/cli/ui/__tests__/components/screens/WorktreeManagerScreen.test.tsx +0 -151
  96. 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
- }