@akiojin/gwt 2.9.1 → 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 (98) hide show
  1. package/README.md +6 -0
  2. package/dist/cli/ui/components/App.d.ts.map +1 -1
  3. package/dist/cli/ui/components/App.js +4 -37
  4. package/dist/cli/ui/components/App.js.map +1 -1
  5. package/dist/cli/ui/components/common/Input.d.ts +1 -1
  6. package/dist/cli/ui/components/screens/BranchListScreen.d.ts +1 -2
  7. package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +1 -1
  8. package/dist/cli/ui/components/screens/BranchListScreen.js +19 -14
  9. package/dist/cli/ui/components/screens/BranchListScreen.js.map +1 -1
  10. package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts.map +1 -1
  11. package/dist/cli/ui/components/screens/ModelSelectorScreen.js +6 -6
  12. package/dist/cli/ui/components/screens/ModelSelectorScreen.js.map +1 -1
  13. package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts.map +1 -1
  14. package/dist/cli/ui/components/screens/PRCleanupScreen.js +0 -3
  15. package/dist/cli/ui/components/screens/PRCleanupScreen.js.map +1 -1
  16. package/dist/cli/ui/hooks/useGitData.d.ts.map +1 -1
  17. package/dist/cli/ui/hooks/useGitData.js +43 -2
  18. package/dist/cli/ui/hooks/useGitData.js.map +1 -1
  19. package/dist/cli/ui/types.d.ts +16 -4
  20. package/dist/cli/ui/types.d.ts.map +1 -1
  21. package/dist/cli/ui/utils/branchFormatter.d.ts.map +1 -1
  22. package/dist/cli/ui/utils/branchFormatter.js +124 -15
  23. package/dist/cli/ui/utils/branchFormatter.js.map +1 -1
  24. package/dist/cli/ui/utils/modelOptions.d.ts.map +1 -1
  25. package/dist/cli/ui/utils/modelOptions.js.map +1 -1
  26. package/dist/client/assets/{index-CNWntAlF.js → index-Dl798X5w.js} +1 -1
  27. package/dist/client/index.html +1 -1
  28. package/dist/config/index.d.ts.map +1 -1
  29. package/dist/config/index.js.map +1 -1
  30. package/dist/git.d.ts +6 -0
  31. package/dist/git.d.ts.map +1 -1
  32. package/dist/git.js +40 -5
  33. package/dist/git.js.map +1 -1
  34. package/dist/web/client/src/components/BranchGraph.js +1 -1
  35. package/dist/web/client/src/components/BranchGraph.js.map +1 -1
  36. package/dist/web/client/src/pages/BranchDetailPage.d.ts.map +1 -1
  37. package/dist/web/client/src/pages/BranchDetailPage.js +8 -3
  38. package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
  39. package/dist/web/server/routes/sessions.d.ts.map +1 -1
  40. package/dist/web/server/routes/sessions.js +4 -2
  41. package/dist/web/server/routes/sessions.js.map +1 -1
  42. package/dist/worktree.d.ts.map +1 -1
  43. package/dist/worktree.js +69 -62
  44. package/dist/worktree.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/cli/ui/__tests__/acceptance/navigation.acceptance.test.tsx +9 -17
  47. package/src/cli/ui/__tests__/components/App.protected-branch.test.tsx +77 -83
  48. package/src/cli/ui/__tests__/components/App.shortcuts.test.tsx +107 -160
  49. package/src/cli/ui/__tests__/components/App.test.tsx +108 -84
  50. package/src/cli/ui/__tests__/components/ModelSelectorScreen.initial.test.tsx +12 -5
  51. package/src/cli/ui/__tests__/components/common/Confirm.test.tsx +3 -2
  52. package/src/cli/ui/__tests__/components/common/ErrorBoundary.test.tsx +3 -2
  53. package/src/cli/ui/__tests__/components/common/Input.test.tsx +3 -2
  54. package/src/cli/ui/__tests__/components/common/LoadingIndicator.test.tsx +15 -14
  55. package/src/cli/ui/__tests__/components/common/Select.memo.test.tsx +3 -3
  56. package/src/cli/ui/__tests__/components/common/Select.test.tsx +1 -4
  57. package/src/cli/ui/__tests__/components/parts/Footer.test.tsx +3 -2
  58. package/src/cli/ui/__tests__/components/parts/Header.test.tsx +3 -2
  59. package/src/cli/ui/__tests__/components/parts/ScrollableList.test.tsx +3 -2
  60. package/src/cli/ui/__tests__/components/parts/Stats.test.tsx +3 -2
  61. package/src/cli/ui/__tests__/components/screens/AIToolSelectorScreen.test.tsx +3 -2
  62. package/src/cli/ui/__tests__/components/screens/BranchCreatorScreen.test.tsx +3 -2
  63. package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +31 -41
  64. package/src/cli/ui/__tests__/components/screens/ExecutionModeSelectorScreen.test.tsx +3 -2
  65. package/src/cli/ui/__tests__/components/screens/PRCleanupScreen.test.tsx +3 -2
  66. package/src/cli/ui/__tests__/components/screens/SessionSelectorScreen.test.tsx +3 -2
  67. package/src/cli/ui/__tests__/hooks/useScreenState.test.ts +18 -17
  68. package/src/cli/ui/__tests__/hooks/useTerminalSize.test.ts +3 -2
  69. package/src/cli/ui/__tests__/integration/edgeCases.test.tsx +61 -41
  70. package/src/cli/ui/__tests__/integration/navigation.test.tsx +15 -10
  71. package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx +3 -2
  72. package/src/cli/ui/__tests__/performance/branchList.performance.test.tsx +0 -4
  73. package/src/cli/ui/__tests__/performance/useMemoOptimization.test.tsx +3 -5
  74. package/src/cli/ui/__tests__/utils/branchFormatter.test.ts +24 -22
  75. package/src/cli/ui/components/App.tsx +5 -63
  76. package/src/cli/ui/components/common/Input.tsx +1 -1
  77. package/src/cli/ui/components/screens/BranchListScreen.tsx +32 -22
  78. package/src/cli/ui/components/screens/ModelSelectorScreen.tsx +46 -49
  79. package/src/cli/ui/components/screens/PRCleanupScreen.tsx +0 -3
  80. package/src/cli/ui/hooks/useGitData.ts +59 -1
  81. package/src/cli/ui/screens/__tests__/BranchActionSelectorScreen.test.tsx +3 -2
  82. package/src/cli/ui/types.ts +24 -5
  83. package/src/cli/ui/utils/branchFormatter.ts +123 -15
  84. package/src/cli/ui/utils/modelOptions.test.ts +4 -6
  85. package/src/cli/ui/utils/modelOptions.ts +1 -2
  86. package/src/config/index.ts +2 -1
  87. package/src/git.ts +56 -16
  88. package/src/index.test.ts +1 -1
  89. package/src/web/client/src/components/BranchGraph.tsx +1 -1
  90. package/src/web/client/src/pages/BranchDetailPage.tsx +8 -3
  91. package/src/web/server/routes/sessions.ts +12 -5
  92. package/src/worktree.ts +80 -91
  93. package/dist/cli/ui/components/screens/WorktreeManagerScreen.d.ts +0 -20
  94. package/dist/cli/ui/components/screens/WorktreeManagerScreen.d.ts.map +0 -1
  95. package/dist/cli/ui/components/screens/WorktreeManagerScreen.js +0 -65
  96. package/dist/cli/ui/components/screens/WorktreeManagerScreen.js.map +0 -1
  97. package/src/cli/ui/__tests__/components/screens/WorktreeManagerScreen.test.tsx +0 -151
  98. package/src/cli/ui/components/screens/WorktreeManagerScreen.tsx +0 -117
@@ -1,92 +1,97 @@
1
1
  /**
2
2
  * @vitest-environment happy-dom
3
3
  */
4
- import {
5
- describe,
6
- it,
7
- expect,
8
- beforeEach,
9
- afterEach,
10
- afterAll,
11
- vi,
12
- } from "vitest";
4
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
13
5
  import type { Mock } from "vitest";
14
- import { render, act, waitFor } from "@testing-library/react";
6
+ import { render, act } from "@testing-library/react";
15
7
  import React from "react";
16
8
  import type { BranchItem, CleanupTarget } from "../../types.js";
9
+ import type { BranchCreatorScreenProps } from "../../components/screens/BranchCreatorScreen.js";
10
+ import type { BranchListScreenProps } from "../../components/screens/BranchListScreen.js";
17
11
  import { Window } from "happy-dom";
18
- import * as useGitDataModule from "../../hooks/useGitData.js";
19
- import * as useScreenStateModule from "../../hooks/useScreenState.js";
20
- import * as WorktreeManagerScreenModule from "../../components/screens/WorktreeManagerScreen.js";
21
- import * as BranchCreatorScreenModule from "../../components/screens/BranchCreatorScreen.js";
22
- import * as BranchListScreenModule from "../../components/screens/BranchListScreen.js";
23
- import * as worktreeModule from "../../../../worktree.ts";
24
- import * as gitModule from "../../../../git.ts";
25
- import { App } from "../../components/App.js";
12
+ let App: typeof import("../../components/App.js").App;
26
13
 
27
14
  const navigateToMock = vi.fn();
28
15
  const goBackMock = vi.fn();
29
16
  const resetMock = vi.fn();
30
17
 
31
- const worktreeScreenProps: any[] = [];
32
- const branchCreatorProps: any[] = [];
33
- const branchListProps: any[] = [];
34
-
35
- const originalUseGitData = useGitDataModule.useGitData;
36
- const originalUseScreenState = useScreenStateModule.useScreenState;
37
- const originalWorktreeManagerScreen =
38
- WorktreeManagerScreenModule.WorktreeManagerScreen;
39
- const originalBranchCreatorScreen =
40
- BranchCreatorScreenModule.BranchCreatorScreen;
41
- const originalBranchListScreen = BranchListScreenModule.BranchListScreen;
42
- const originalGetMergedPRWorktrees = worktreeModule.getMergedPRWorktrees;
43
- const originalGenerateWorktreePath = worktreeModule.generateWorktreePath;
44
- const originalCreateWorktree = worktreeModule.createWorktree;
45
- const originalRemoveWorktree = worktreeModule.removeWorktree;
46
- const originalGetRepositoryRoot = gitModule.getRepositoryRoot;
47
- const originalDeleteBranch = gitModule.deleteBranch;
48
-
49
- const useGitDataSpy = vi.spyOn(useGitDataModule, "useGitData");
50
- const useScreenStateSpy = vi.spyOn(useScreenStateModule, "useScreenState");
51
- const worktreeManagerScreenSpy = vi.spyOn(
52
- WorktreeManagerScreenModule,
53
- "WorktreeManagerScreen",
54
- );
55
- const branchCreatorScreenSpy = vi.spyOn(
56
- BranchCreatorScreenModule,
57
- "BranchCreatorScreen",
58
- );
59
- const branchListScreenSpy = vi.spyOn(
60
- BranchListScreenModule,
61
- "BranchListScreen",
62
- );
63
- const getMergedPRWorktreesSpy = vi.spyOn(
64
- worktreeModule,
65
- "getMergedPRWorktrees",
66
- );
67
- const generateWorktreePathSpy = vi.spyOn(
68
- worktreeModule,
69
- "generateWorktreePath",
70
- );
71
- const createWorktreeSpy = vi.spyOn(worktreeModule, "createWorktree");
72
- const removeWorktreeSpy = vi.spyOn(worktreeModule, "removeWorktree");
73
- const getRepositoryRootSpy = vi.spyOn(gitModule, "getRepositoryRoot");
74
- const deleteBranchSpy = vi.spyOn(gitModule, "deleteBranch");
18
+ const branchCreatorProps: BranchCreatorScreenProps[] = [];
19
+ const branchListProps: BranchListScreenProps[] = [];
20
+
21
+ const useGitDataMock = vi.fn();
22
+ const useScreenStateMock = vi.fn();
23
+ const getMergedPRWorktreesMock = vi.fn();
24
+ const generateWorktreePathMock = vi.fn();
25
+ const createWorktreeMock = vi.fn();
26
+ const removeWorktreeMock = vi.fn();
27
+ const getRepositoryRootMock = vi.fn();
28
+ const deleteBranchMock = vi.fn();
29
+
30
+ vi.mock("../../hooks/useGitData.js", () => ({
31
+ useGitData: (...args: unknown[]) => useGitDataMock(...args),
32
+ }));
33
+
34
+ vi.mock("../../hooks/useScreenState.js", () => ({
35
+ useScreenState: (...args: unknown[]) => useScreenStateMock(...args),
36
+ }));
37
+
38
+ vi.mock("../../../../worktree.js", async () => {
39
+ const actual = await vi.importActual<
40
+ typeof import("../../../../worktree.js")
41
+ >("../../../../worktree.js");
42
+ return {
43
+ ...actual,
44
+ getMergedPRWorktrees: getMergedPRWorktreesMock,
45
+ generateWorktreePath: generateWorktreePathMock,
46
+ createWorktree: createWorktreeMock,
47
+ removeWorktree: removeWorktreeMock,
48
+ };
49
+ });
50
+
51
+ vi.mock("../../../../git.js", async () => {
52
+ const actual =
53
+ await vi.importActual<typeof import("../../../../git.js")>(
54
+ "../../../../git.js",
55
+ );
56
+ return {
57
+ ...actual,
58
+ getRepositoryRoot: getRepositoryRootMock,
59
+ deleteBranch: deleteBranchMock,
60
+ };
61
+ });
62
+
63
+ vi.mock("../../components/screens/BranchCreatorScreen.js", () => {
64
+ return {
65
+ BranchCreatorScreen: (props: BranchCreatorScreenProps) => {
66
+ branchCreatorProps.push(props);
67
+ return React.createElement("div", null, "BranchCreatorScreenMock");
68
+ },
69
+ };
70
+ });
71
+
72
+ vi.mock("../../components/screens/BranchListScreen.js", () => {
73
+ return {
74
+ BranchListScreen: (props: BranchListScreenProps) => {
75
+ branchListProps.push(props);
76
+ return React.createElement("div", null, "BranchListScreenMock");
77
+ },
78
+ };
79
+ });
75
80
 
76
81
  describe("App shortcuts integration", () => {
77
- beforeEach(() => {
82
+ beforeEach(async () => {
78
83
  if (typeof globalThis.document === "undefined") {
79
84
  const window = new Window();
80
- globalThis.window = window as any;
81
- globalThis.document = window.document as any;
85
+ globalThis.window = window as unknown as typeof globalThis.window;
86
+ globalThis.document =
87
+ window.document as unknown as typeof globalThis.document;
82
88
  }
83
- worktreeScreenProps.length = 0;
84
89
  branchCreatorProps.length = 0;
85
90
  branchListProps.length = 0;
86
91
  navigateToMock.mockClear();
87
92
  goBackMock.mockClear();
88
93
  resetMock.mockClear();
89
- useGitDataSpy.mockImplementation(() => ({
94
+ useGitDataMock.mockReturnValue({
90
95
  branches: [],
91
96
  worktrees: [
92
97
  {
@@ -99,26 +104,14 @@ describe("App shortcuts integration", () => {
99
104
  error: null,
100
105
  refresh: vi.fn(),
101
106
  lastUpdated: null,
102
- }));
103
- useScreenStateSpy.mockImplementation(() => ({
104
- currentScreen: "worktree-manager",
105
- navigateTo: navigateToMock as _Mock,
106
- goBack: goBackMock as _Mock,
107
- reset: resetMock as _Mock,
108
- }));
109
- worktreeManagerScreenSpy.mockImplementation((props: any) => {
110
- worktreeScreenProps.push(props);
111
- return React.createElement(originalWorktreeManagerScreen, props);
112
107
  });
113
- branchCreatorScreenSpy.mockImplementation((props: any) => {
114
- branchCreatorProps.push(props);
115
- return React.createElement(originalBranchCreatorScreen, props);
108
+ useScreenStateMock.mockReturnValue({
109
+ currentScreen: "branch-list",
110
+ navigateTo: navigateToMock as Mock,
111
+ goBack: goBackMock as Mock,
112
+ reset: resetMock as Mock,
116
113
  });
117
- branchListScreenSpy.mockImplementation((props: any) => {
118
- branchListProps.push(props);
119
- return React.createElement(originalBranchListScreen, props);
120
- });
121
- getMergedPRWorktreesSpy.mockResolvedValue([
114
+ getMergedPRWorktreesMock.mockResolvedValue([
122
115
  {
123
116
  branch: "feature/add-new-feature",
124
117
  cleanupType: "worktree-and-branch",
@@ -152,68 +145,36 @@ describe("App shortcuts integration", () => {
152
145
  isAccessible: true,
153
146
  },
154
147
  ] as CleanupTarget[]);
155
- generateWorktreePathSpy.mockResolvedValue("/worktrees/new-branch");
156
- createWorktreeSpy.mockResolvedValue(undefined);
157
- removeWorktreeSpy.mockResolvedValue(undefined);
158
- getRepositoryRootSpy.mockResolvedValue("/repo");
159
- deleteBranchSpy.mockResolvedValue(undefined);
148
+ generateWorktreePathMock.mockResolvedValue("/worktrees/new-branch");
149
+ createWorktreeMock.mockResolvedValue(undefined);
150
+ removeWorktreeMock.mockResolvedValue(undefined);
151
+ getRepositoryRootMock.mockResolvedValue("/repo");
152
+ deleteBranchMock.mockResolvedValue(undefined);
153
+ App = (await import("../../components/App.js")).App;
160
154
  });
161
155
 
162
156
  afterEach(() => {
163
- useGitDataSpy.mockReset();
164
- useScreenStateSpy.mockReset();
165
- worktreeManagerScreenSpy.mockReset();
166
- branchCreatorScreenSpy.mockReset();
167
- branchListScreenSpy.mockReset();
168
- getMergedPRWorktreesSpy.mockReset();
169
- generateWorktreePathSpy.mockReset();
170
- createWorktreeSpy.mockReset();
171
- removeWorktreeSpy.mockReset();
172
- getRepositoryRootSpy.mockReset();
173
- deleteBranchSpy.mockReset();
174
- useGitDataSpy.mockImplementation(originalUseGitData);
175
- useScreenStateSpy.mockImplementation(originalUseScreenState);
176
- worktreeManagerScreenSpy.mockImplementation(
177
- originalWorktreeManagerScreen as any,
178
- );
179
- branchCreatorScreenSpy.mockImplementation(
180
- originalBranchCreatorScreen as any,
181
- );
182
- branchListScreenSpy.mockImplementation(originalBranchListScreen as any);
183
- getMergedPRWorktreesSpy.mockImplementation(
184
- originalGetMergedPRWorktrees as any,
185
- );
186
- generateWorktreePathSpy.mockImplementation(
187
- originalGenerateWorktreePath as any,
188
- );
189
- createWorktreeSpy.mockImplementation(originalCreateWorktree as any);
190
- removeWorktreeSpy.mockImplementation(originalRemoveWorktree as any);
191
- getRepositoryRootSpy.mockImplementation(originalGetRepositoryRoot as any);
192
- deleteBranchSpy.mockImplementation(originalDeleteBranch as any);
193
- });
194
-
195
- it("navigates to AI tool selector when worktree is selected", () => {
196
- const onExit = vi.fn();
197
- render(<App onExit={onExit} />);
198
-
199
- expect(worktreeScreenProps).not.toHaveLength(0);
200
- const { onSelect, worktrees } = worktreeScreenProps[0];
201
- expect(worktrees).toHaveLength(1);
202
-
203
- onSelect(worktrees[0]);
204
-
205
- expect(navigateToMock).toHaveBeenCalledWith("ai-tool-selector");
157
+ useGitDataMock.mockReset();
158
+ useScreenStateMock.mockReset();
159
+ getMergedPRWorktreesMock.mockReset();
160
+ generateWorktreePathMock.mockReset();
161
+ createWorktreeMock.mockReset();
162
+ removeWorktreeMock.mockReset();
163
+ getRepositoryRootMock.mockReset();
164
+ deleteBranchMock.mockReset();
165
+ branchCreatorProps.length = 0;
166
+ branchListProps.length = 0;
206
167
  });
207
168
 
208
169
  it("creates new worktree when branch creator submits", async () => {
209
170
  const onExit = vi.fn();
210
171
 
211
172
  // Update screen state mock to branch-creator for this test
212
- useScreenStateSpy.mockReturnValue({
173
+ useScreenStateMock.mockReturnValue({
213
174
  currentScreen: "branch-creator",
214
- navigateTo: navigateToMock as _Mock,
215
- goBack: goBackMock as _Mock,
216
- reset: resetMock as _Mock,
175
+ navigateTo: navigateToMock as Mock,
176
+ goBack: goBackMock as Mock,
177
+ reset: resetMock as Mock,
217
178
  });
218
179
 
219
180
  render(<App onExit={onExit} />);
@@ -225,7 +186,7 @@ describe("App shortcuts integration", () => {
225
186
  await onCreate("feature/new-branch");
226
187
  });
227
188
 
228
- expect(createWorktreeSpy).toHaveBeenCalledWith(
189
+ expect(createWorktreeMock).toHaveBeenCalledWith(
229
190
  expect.objectContaining({
230
191
  branchName: "feature/new-branch",
231
192
  isNewBranch: true,
@@ -243,25 +204,25 @@ describe("App shortcuts integration", () => {
243
204
  let resolveRemoveWorktree: (() => void) | undefined;
244
205
  let resolveDeleteBranch: (() => void) | undefined;
245
206
 
246
- removeWorktreeSpy.mockImplementationOnce(
207
+ removeWorktreeMock.mockImplementationOnce(
247
208
  () =>
248
209
  new Promise<void>((resolve) => {
249
210
  resolveRemoveWorktree = resolve;
250
211
  }),
251
212
  );
252
213
 
253
- deleteBranchSpy.mockImplementationOnce(
214
+ deleteBranchMock.mockImplementationOnce(
254
215
  () =>
255
216
  new Promise<void>((resolve) => {
256
217
  resolveDeleteBranch = resolve;
257
218
  }),
258
219
  );
259
220
 
260
- useScreenStateSpy.mockReturnValue({
221
+ useScreenStateMock.mockReturnValue({
261
222
  currentScreen: "branch-list",
262
- navigateTo: navigateToMock as _Mock,
263
- goBack: goBackMock as _Mock,
264
- reset: resetMock as _Mock,
223
+ navigateTo: navigateToMock as Mock,
224
+ goBack: goBackMock as Mock,
225
+ reset: resetMock as Mock,
265
226
  });
266
227
 
267
228
  render(<App onExit={onExit} />);
@@ -299,11 +260,11 @@ describe("App shortcuts integration", () => {
299
260
 
300
261
  resolveDeleteBranch?.();
301
262
 
302
- expect(removeWorktreeSpy).toHaveBeenCalledWith(
263
+ expect(removeWorktreeMock).toHaveBeenCalledWith(
303
264
  "/worktrees/feature-add-new-feature",
304
265
  true,
305
266
  );
306
- expect(deleteBranchSpy).toHaveBeenCalledWith(
267
+ expect(deleteBranchMock).toHaveBeenCalledWith(
307
268
  "feature/add-new-feature",
308
269
  true,
309
270
  );
@@ -339,17 +300,3 @@ describe("App shortcuts integration", () => {
339
300
  }
340
301
  });
341
302
  });
342
-
343
- afterAll(() => {
344
- useGitDataSpy.mockRestore();
345
- useScreenStateSpy.mockRestore();
346
- worktreeManagerScreenSpy.mockRestore();
347
- branchCreatorScreenSpy.mockRestore();
348
- branchListScreenSpy.mockRestore();
349
- getMergedPRWorktreesSpy.mockRestore();
350
- generateWorktreePathSpy.mockRestore();
351
- createWorktreeSpy.mockRestore();
352
- removeWorktreeSpy.mockRestore();
353
- getRepositoryRootSpy.mockRestore();
354
- deleteBranchSpy.mockRestore();
355
- });