@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.
Files changed (149) hide show
  1. package/README.ja.md +4 -4
  2. package/README.md +4 -4
  3. package/dist/cli/ui/components/App.d.ts +4 -4
  4. package/dist/cli/ui/components/App.d.ts.map +1 -1
  5. package/dist/cli/ui/components/App.js +144 -105
  6. package/dist/cli/ui/components/App.js.map +1 -1
  7. package/dist/cli/ui/components/common/Confirm.d.ts +1 -1
  8. package/dist/cli/ui/components/common/Confirm.d.ts.map +1 -1
  9. package/dist/cli/ui/components/common/Confirm.js +7 -7
  10. package/dist/cli/ui/components/common/Confirm.js.map +1 -1
  11. package/dist/cli/ui/components/common/ErrorBoundary.d.ts +1 -1
  12. package/dist/cli/ui/components/common/ErrorBoundary.d.ts.map +1 -1
  13. package/dist/cli/ui/components/common/ErrorBoundary.js +4 -4
  14. package/dist/cli/ui/components/common/ErrorBoundary.js.map +1 -1
  15. package/dist/cli/ui/components/common/Input.d.ts +2 -2
  16. package/dist/cli/ui/components/common/Input.d.ts.map +1 -1
  17. package/dist/cli/ui/components/common/Input.js +4 -4
  18. package/dist/cli/ui/components/common/Input.js.map +1 -1
  19. package/dist/cli/ui/components/common/LoadingIndicator.d.ts +1 -1
  20. package/dist/cli/ui/components/common/LoadingIndicator.d.ts.map +1 -1
  21. package/dist/cli/ui/components/common/LoadingIndicator.js +4 -4
  22. package/dist/cli/ui/components/common/LoadingIndicator.js.map +1 -1
  23. package/dist/cli/ui/components/common/Select.d.ts +1 -1
  24. package/dist/cli/ui/components/common/Select.d.ts.map +1 -1
  25. package/dist/cli/ui/components/common/Select.js +11 -12
  26. package/dist/cli/ui/components/common/Select.js.map +1 -1
  27. package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts +2 -2
  28. package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts.map +1 -1
  29. package/dist/cli/ui/components/screens/AIToolSelectorScreen.js +11 -11
  30. package/dist/cli/ui/components/screens/AIToolSelectorScreen.js.map +1 -1
  31. package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts +1 -1
  32. package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts.map +1 -1
  33. package/dist/cli/ui/components/screens/BranchCreatorScreen.js +39 -36
  34. package/dist/cli/ui/components/screens/BranchCreatorScreen.js.map +1 -1
  35. package/dist/cli/ui/components/screens/BranchListScreen.d.ts +3 -3
  36. package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +1 -1
  37. package/dist/cli/ui/components/screens/BranchListScreen.js +55 -50
  38. package/dist/cli/ui/components/screens/BranchListScreen.js.map +1 -1
  39. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts +2 -2
  40. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts.map +1 -1
  41. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js +25 -25
  42. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js.map +1 -1
  43. package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts +2 -2
  44. package/dist/cli/ui/components/screens/PRCleanupScreen.js +21 -21
  45. package/dist/cli/ui/components/screens/SessionSelectorScreen.d.ts +1 -1
  46. package/dist/cli/ui/components/screens/SessionSelectorScreen.js +8 -8
  47. package/dist/cli/ui/components/screens/WorktreeManagerScreen.d.ts +1 -1
  48. package/dist/cli/ui/components/screens/WorktreeManagerScreen.js +8 -8
  49. package/dist/cli/ui/screens/BranchActionSelectorScreen.d.ts.map +1 -1
  50. package/dist/cli/ui/screens/BranchActionSelectorScreen.js +7 -4
  51. package/dist/cli/ui/screens/BranchActionSelectorScreen.js.map +1 -1
  52. package/dist/cli/ui/types.d.ts.map +1 -1
  53. package/dist/client/assets/{index-V6hDu9KS.js → index-Difv1Hwu.js} +2 -2
  54. package/dist/client/index.html +1 -1
  55. package/dist/config/builtin-tools.d.ts +10 -2
  56. package/dist/config/builtin-tools.d.ts.map +1 -1
  57. package/dist/config/builtin-tools.js +40 -4
  58. package/dist/config/builtin-tools.js.map +1 -1
  59. package/dist/config/index.d.ts.map +1 -1
  60. package/dist/config/index.js.map +1 -1
  61. package/dist/config/tools.d.ts.map +1 -1
  62. package/dist/config/tools.js +4 -3
  63. package/dist/config/tools.js.map +1 -1
  64. package/dist/gemini.d.ts +12 -0
  65. package/dist/gemini.d.ts.map +1 -0
  66. package/dist/gemini.js +154 -0
  67. package/dist/gemini.js.map +1 -0
  68. package/dist/git.d.ts.map +1 -1
  69. package/dist/git.js.map +1 -1
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +30 -0
  72. package/dist/index.js.map +1 -1
  73. package/dist/qwen.d.ts +12 -0
  74. package/dist/qwen.d.ts.map +1 -0
  75. package/dist/qwen.js +154 -0
  76. package/dist/qwen.js.map +1 -0
  77. package/dist/services/git.service.d.ts.map +1 -1
  78. package/dist/services/git.service.js.map +1 -1
  79. package/dist/web/client/src/components/BranchGraph.d.ts.map +1 -1
  80. package/dist/web/client/src/components/BranchGraph.js +1 -1
  81. package/dist/web/client/src/components/BranchGraph.js.map +1 -1
  82. package/dist/web/client/src/components/EnvEditor.d.ts.map +1 -1
  83. package/dist/web/client/src/components/EnvEditor.js +7 -4
  84. package/dist/web/client/src/components/EnvEditor.js.map +1 -1
  85. package/dist/web/client/src/pages/BranchDetailPage.d.ts.map +1 -1
  86. package/dist/web/client/src/pages/BranchDetailPage.js +55 -18
  87. package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
  88. package/dist/web/client/src/pages/BranchListPage.d.ts.map +1 -1
  89. package/dist/web/client/src/pages/BranchListPage.js +10 -4
  90. package/dist/web/client/src/pages/BranchListPage.js.map +1 -1
  91. package/dist/web/client/src/pages/ConfigManagementPage.d.ts.map +1 -1
  92. package/dist/web/client/src/pages/ConfigManagementPage.js +4 -2
  93. package/dist/web/client/src/pages/ConfigManagementPage.js.map +1 -1
  94. package/package.json +2 -1
  95. package/src/cli/ui/__tests__/acceptance/navigation.acceptance.test.tsx +69 -50
  96. package/src/cli/ui/__tests__/components/App.protected-branch.test.tsx +67 -45
  97. package/src/cli/ui/__tests__/components/App.shortcuts.test.tsx +117 -75
  98. package/src/cli/ui/__tests__/components/App.test.tsx +45 -37
  99. package/src/cli/ui/__tests__/components/common/Confirm.test.tsx +35 -22
  100. package/src/cli/ui/__tests__/components/common/ErrorBoundary.test.tsx +22 -22
  101. package/src/cli/ui/__tests__/components/common/Input.test.tsx +29 -22
  102. package/src/cli/ui/__tests__/components/common/LoadingIndicator.test.tsx +40 -34
  103. package/src/cli/ui/__tests__/components/common/Select.memo.test.tsx +57 -66
  104. package/src/cli/ui/__tests__/components/common/Select.test.tsx +121 -91
  105. package/src/cli/ui/__tests__/components/parts/Footer.test.tsx +18 -16
  106. package/src/cli/ui/__tests__/components/parts/Header.test.tsx +13 -13
  107. package/src/cli/ui/__tests__/components/parts/ScrollableList.test.tsx +20 -20
  108. package/src/cli/ui/__tests__/components/parts/Stats.test.tsx +38 -26
  109. package/src/cli/ui/__tests__/components/screens/AIToolSelectorScreen.test.tsx +31 -31
  110. package/src/cli/ui/__tests__/components/screens/BranchCreatorScreen.test.tsx +73 -37
  111. package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +261 -153
  112. package/src/cli/ui/__tests__/components/screens/ExecutionModeSelectorScreen.test.tsx +38 -32
  113. package/src/cli/ui/__tests__/components/screens/PRCleanupScreen.test.tsx +39 -39
  114. package/src/cli/ui/__tests__/components/screens/SessionSelectorScreen.test.tsx +49 -21
  115. package/src/cli/ui/__tests__/components/screens/WorktreeManagerScreen.test.tsx +52 -28
  116. package/src/cli/ui/__tests__/integration/edgeCases.test.tsx +84 -48
  117. package/src/cli/ui/__tests__/integration/navigation.test.tsx +111 -83
  118. package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx +111 -108
  119. package/src/cli/ui/__tests__/performance/branchList.performance.test.tsx +50 -37
  120. package/src/cli/ui/__tests__/performance/useMemoOptimization.test.tsx +75 -76
  121. package/src/cli/ui/components/App.tsx +247 -150
  122. package/src/cli/ui/components/common/Confirm.tsx +13 -9
  123. package/src/cli/ui/components/common/ErrorBoundary.tsx +8 -5
  124. package/src/cli/ui/components/common/Input.tsx +12 -4
  125. package/src/cli/ui/components/common/LoadingIndicator.tsx +8 -5
  126. package/src/cli/ui/components/common/Select.tsx +28 -17
  127. package/src/cli/ui/components/parts/Header.test.tsx +5 -15
  128. package/src/cli/ui/components/screens/AIToolSelectorScreen.tsx +19 -13
  129. package/src/cli/ui/components/screens/BranchCreatorScreen.tsx +74 -54
  130. package/src/cli/ui/components/screens/BranchListScreen.tsx +92 -75
  131. package/src/cli/ui/components/screens/ExecutionModeSelectorScreen.tsx +35 -28
  132. package/src/cli/ui/components/screens/PRCleanupScreen.tsx +22 -22
  133. package/src/cli/ui/components/screens/SessionSelectorScreen.tsx +8 -8
  134. package/src/cli/ui/components/screens/WorktreeManagerScreen.tsx +8 -8
  135. package/src/cli/ui/screens/BranchActionSelectorScreen.tsx +9 -4
  136. package/src/cli/ui/types.ts +8 -1
  137. package/src/config/builtin-tools.ts +42 -4
  138. package/src/config/index.ts +2 -12
  139. package/src/config/tools.ts +16 -6
  140. package/src/gemini.ts +202 -0
  141. package/src/git.ts +2 -1
  142. package/src/index.ts +30 -0
  143. package/src/qwen.ts +208 -0
  144. package/src/services/git.service.ts +2 -1
  145. package/src/web/client/src/components/BranchGraph.tsx +3 -2
  146. package/src/web/client/src/components/EnvEditor.tsx +44 -11
  147. package/src/web/client/src/pages/BranchDetailPage.tsx +165 -54
  148. package/src/web/client/src/pages/BranchListPage.tsx +37 -13
  149. package/src/web/client/src/pages/ConfigManagementPage.tsx +28 -9
@@ -1,19 +1,27 @@
1
1
  /**
2
2
  * @vitest-environment happy-dom
3
3
  */
4
- import { describe, it, expect, beforeEach, afterEach, afterAll, vi } from 'vitest';
5
- import { act, render } from '@testing-library/react';
6
- import React from 'react';
7
- import { Window } from 'happy-dom';
8
- import { App } from '../../components/App.js';
9
- import type { BranchInfo, BranchItem } from '../../types.js';
10
- import * as useGitDataModule from '../../hooks/useGitData.js';
11
- import * as useScreenStateModule from '../../hooks/useScreenState.js';
12
- import * as BranchListScreenModule from '../../components/screens/BranchListScreen.js';
13
- import * as BranchActionSelectorScreenModule from '../../screens/BranchActionSelectorScreen.js';
14
- import * as worktreeModule from '../../../../worktree.ts';
15
- import * as gitModule from '../../../../git.ts';
16
- import type { ScreenType } from '../../types.js';
4
+ import {
5
+ describe,
6
+ it,
7
+ expect,
8
+ beforeEach,
9
+ afterEach,
10
+ afterAll,
11
+ vi,
12
+ } from "vitest";
13
+ import { act, render } from "@testing-library/react";
14
+ import React from "react";
15
+ import { Window } from "happy-dom";
16
+ import { App } from "../../components/App.js";
17
+ import type { BranchInfo, BranchItem } from "../../types.js";
18
+ import * as useGitDataModule from "../../hooks/useGitData.js";
19
+ import * as useScreenStateModule from "../../hooks/useScreenState.js";
20
+ import * as BranchListScreenModule from "../../components/screens/BranchListScreen.js";
21
+ import * as BranchActionSelectorScreenModule from "../../screens/BranchActionSelectorScreen.js";
22
+ import * as worktreeModule from "../../../../worktree.ts";
23
+ import * as gitModule from "../../../../git.ts";
24
+ import type { ScreenType } from "../../types.js";
17
25
 
18
26
  const navigateToMock = vi.fn();
19
27
  const goBackMock = vi.fn();
@@ -22,37 +30,47 @@ const resetMock = vi.fn();
22
30
  const originalUseGitData = useGitDataModule.useGitData;
23
31
  const originalUseScreenState = useScreenStateModule.useScreenState;
24
32
  const originalBranchListScreen = BranchListScreenModule.BranchListScreen;
25
- const originalBranchActionSelector = BranchActionSelectorScreenModule.BranchActionSelectorScreen;
33
+ const originalBranchActionSelector =
34
+ BranchActionSelectorScreenModule.BranchActionSelectorScreen;
26
35
  const originalGetRepositoryRoot = gitModule.getRepositoryRoot;
27
36
 
28
- const useGitDataSpy = vi.spyOn(useGitDataModule, 'useGitData');
29
- const useScreenStateSpy = vi.spyOn(useScreenStateModule, 'useScreenState');
30
- const branchListScreenSpy = vi.spyOn(BranchListScreenModule, 'BranchListScreen');
31
- const branchActionSelectorSpy = vi.spyOn(BranchActionSelectorScreenModule, 'BranchActionSelectorScreen');
32
- const switchToProtectedBranchSpy = vi.spyOn(worktreeModule, 'switchToProtectedBranch');
33
- const getRepositoryRootSpy = vi.spyOn(gitModule, 'getRepositoryRoot');
37
+ const useGitDataSpy = vi.spyOn(useGitDataModule, "useGitData");
38
+ const useScreenStateSpy = vi.spyOn(useScreenStateModule, "useScreenState");
39
+ const branchListScreenSpy = vi.spyOn(
40
+ BranchListScreenModule,
41
+ "BranchListScreen",
42
+ );
43
+ const branchActionSelectorSpy = vi.spyOn(
44
+ BranchActionSelectorScreenModule,
45
+ "BranchActionSelectorScreen",
46
+ );
47
+ const switchToProtectedBranchSpy = vi.spyOn(
48
+ worktreeModule,
49
+ "switchToProtectedBranch",
50
+ );
51
+ const getRepositoryRootSpy = vi.spyOn(gitModule, "getRepositoryRoot");
34
52
 
35
53
  const branchListProps: any[] = [];
36
54
  const branchActionProps: any[] = [];
37
55
  const aiToolProps: any[] = [];
38
56
  let currentScreenState: ScreenType;
39
57
 
40
- vi.mock('../../components/screens/AIToolSelectorScreen.js', () => {
58
+ vi.mock("../../components/screens/AIToolSelectorScreen.js", () => {
41
59
  return {
42
60
  AIToolSelectorScreen: (props: unknown) => {
43
61
  aiToolProps.push(props);
44
- return React.createElement('div');
62
+ return React.createElement("div");
45
63
  },
46
64
  };
47
65
  });
48
66
 
49
- describe('App protected branch handling', () => {
67
+ describe("App protected branch handling", () => {
50
68
  beforeEach(() => {
51
69
  const window = new Window();
52
70
  globalThis.window = window as any;
53
71
  globalThis.document = window.document as any;
54
72
 
55
- currentScreenState = 'branch-list';
73
+ currentScreenState = "branch-list";
56
74
  navigateToMock.mockReset();
57
75
  goBackMock.mockReset();
58
76
  resetMock.mockReset();
@@ -73,7 +91,7 @@ describe('App protected branch handling', () => {
73
91
  goBack: goBackMock,
74
92
  reset: () => {
75
93
  resetMock();
76
- currentScreenState = 'branch-list';
94
+ currentScreenState = "branch-list";
77
95
  },
78
96
  }));
79
97
 
@@ -85,8 +103,8 @@ describe('App protected branch handling', () => {
85
103
  branchActionProps.push(props);
86
104
  return React.createElement(originalBranchActionSelector, props);
87
105
  });
88
- switchToProtectedBranchSpy.mockResolvedValue('local');
89
- getRepositoryRootSpy.mockResolvedValue('/repo');
106
+ switchToProtectedBranchSpy.mockResolvedValue("local");
107
+ getRepositoryRootSpy.mockResolvedValue("/repo");
90
108
  });
91
109
 
92
110
  afterEach(() => {
@@ -95,7 +113,9 @@ describe('App protected branch handling', () => {
95
113
  useScreenStateSpy.mockReset();
96
114
  useScreenStateSpy.mockImplementation(originalUseScreenState);
97
115
  branchListScreenSpy.mockImplementation(originalBranchListScreen as any);
98
- branchActionSelectorSpy.mockImplementation(originalBranchActionSelector as any);
116
+ branchActionSelectorSpy.mockImplementation(
117
+ originalBranchActionSelector as any,
118
+ );
99
119
  switchToProtectedBranchSpy.mockReset();
100
120
  getRepositoryRootSpy.mockReset();
101
121
  branchActionProps.length = 0;
@@ -110,18 +130,18 @@ describe('App protected branch handling', () => {
110
130
  getRepositoryRootSpy.mockRestore();
111
131
  });
112
132
 
113
- it('shows protected branch warning and switches root without launching AI tool', async () => {
133
+ it("shows protected branch warning and switches root without launching AI tool", async () => {
114
134
  const branches: BranchInfo[] = [
115
135
  {
116
- name: 'main',
117
- type: 'local',
118
- branchType: 'main',
136
+ name: "main",
137
+ type: "local",
138
+ branchType: "main",
119
139
  isCurrent: false,
120
140
  },
121
141
  {
122
- name: 'feature/example',
123
- type: 'local',
124
- branchType: 'feature',
142
+ name: "feature/example",
143
+ type: "local",
144
+ branchType: "feature",
125
145
  isCurrent: true,
126
146
  },
127
147
  ];
@@ -141,15 +161,15 @@ describe('App protected branch handling', () => {
141
161
  const latestProps = branchListProps.at(-1);
142
162
  expect(latestProps).toBeDefined();
143
163
  if (!latestProps) {
144
- throw new Error('BranchListScreen props missing');
164
+ throw new Error("BranchListScreen props missing");
145
165
  }
146
166
 
147
167
  const protectedBranch = (latestProps.branches as BranchItem[]).find(
148
- (item) => item.name === 'main'
168
+ (item) => item.name === "main",
149
169
  );
150
170
  expect(protectedBranch).toBeDefined();
151
171
  if (!protectedBranch) {
152
- throw new Error('Protected branch item not found');
172
+ throw new Error("Protected branch item not found");
153
173
  }
154
174
 
155
175
  await act(async () => {
@@ -157,13 +177,15 @@ describe('App protected branch handling', () => {
157
177
  await Promise.resolve();
158
178
  });
159
179
 
160
- expect(navigateToMock).toHaveBeenCalledWith('branch-action-selector');
180
+ expect(navigateToMock).toHaveBeenCalledWith("branch-action-selector");
161
181
  expect(branchActionProps).not.toHaveLength(0);
162
182
  const actionProps = branchActionProps.at(-1);
163
- expect(actionProps?.mode).toBe('protected');
164
- expect(actionProps?.infoMessage).toContain('is a root branch');
165
- expect(actionProps?.primaryLabel).toBe('Use root branch (no worktree)');
166
- expect(actionProps?.secondaryLabel).toBe('Create new branch from this branch');
183
+ expect(actionProps?.mode).toBe("protected");
184
+ expect(actionProps?.infoMessage).toContain("is a root branch");
185
+ expect(actionProps?.primaryLabel).toBe("Use root branch (no worktree)");
186
+ expect(actionProps?.secondaryLabel).toBe(
187
+ "Create new branch from this branch",
188
+ );
167
189
 
168
190
  await act(async () => {
169
191
  actionProps?.onUseExisting();
@@ -172,12 +194,12 @@ describe('App protected branch handling', () => {
172
194
  });
173
195
 
174
196
  expect(switchToProtectedBranchSpy).toHaveBeenCalledWith({
175
- branchName: 'main',
197
+ branchName: "main",
176
198
  repoRoot: expect.any(String),
177
199
  remoteRef: null,
178
200
  });
179
201
 
180
- expect(navigateToMock).toHaveBeenCalledWith('ai-tool-selector');
202
+ expect(navigateToMock).toHaveBeenCalledWith("ai-tool-selector");
181
203
  expect(aiToolProps).not.toHaveLength(0);
182
204
  });
183
205
  });
@@ -1,20 +1,28 @@
1
1
  /**
2
2
  * @vitest-environment happy-dom
3
3
  */
4
- import { describe, it, expect, beforeEach, afterEach, afterAll, vi } from 'vitest';
5
- import type { Mock } from 'vitest';
6
- import { render, act, waitFor } from '@testing-library/react';
7
- import React from 'react';
8
- import type { BranchItem, CleanupTarget } from '../../types.js';
9
- import { Window } from 'happy-dom';
10
- import * as useGitDataModule from '../../hooks/useGitData.js';
11
- import * as useScreenStateModule from '../../hooks/useScreenState.js';
12
- import * as WorktreeManagerScreenModule from '../../components/screens/WorktreeManagerScreen.js';
13
- import * as BranchCreatorScreenModule from '../../components/screens/BranchCreatorScreen.js';
14
- import * as BranchListScreenModule from '../../components/screens/BranchListScreen.js';
15
- import * as worktreeModule from '../../../../worktree.ts';
16
- import * as gitModule from '../../../../git.ts';
17
- import { App } from '../../components/App.js';
4
+ import {
5
+ describe,
6
+ it,
7
+ expect,
8
+ beforeEach,
9
+ afterEach,
10
+ afterAll,
11
+ vi,
12
+ } from "vitest";
13
+ import type { Mock } from "vitest";
14
+ import { render, act, waitFor } from "@testing-library/react";
15
+ import React from "react";
16
+ import type { BranchItem, CleanupTarget } from "../../types.js";
17
+ 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";
18
26
 
19
27
  const navigateToMock = vi.fn();
20
28
  const goBackMock = vi.fn();
@@ -26,8 +34,10 @@ const branchListProps: any[] = [];
26
34
 
27
35
  const originalUseGitData = useGitDataModule.useGitData;
28
36
  const originalUseScreenState = useScreenStateModule.useScreenState;
29
- const originalWorktreeManagerScreen = WorktreeManagerScreenModule.WorktreeManagerScreen;
30
- const originalBranchCreatorScreen = BranchCreatorScreenModule.BranchCreatorScreen;
37
+ const originalWorktreeManagerScreen =
38
+ WorktreeManagerScreenModule.WorktreeManagerScreen;
39
+ const originalBranchCreatorScreen =
40
+ BranchCreatorScreenModule.BranchCreatorScreen;
31
41
  const originalBranchListScreen = BranchListScreenModule.BranchListScreen;
32
42
  const originalGetMergedPRWorktrees = worktreeModule.getMergedPRWorktrees;
33
43
  const originalGenerateWorktreePath = worktreeModule.generateWorktreePath;
@@ -36,21 +46,36 @@ const originalRemoveWorktree = worktreeModule.removeWorktree;
36
46
  const originalGetRepositoryRoot = gitModule.getRepositoryRoot;
37
47
  const originalDeleteBranch = gitModule.deleteBranch;
38
48
 
39
- const useGitDataSpy = vi.spyOn(useGitDataModule, 'useGitData');
40
- const useScreenStateSpy = vi.spyOn(useScreenStateModule, 'useScreenState');
41
- const worktreeManagerScreenSpy = vi.spyOn(WorktreeManagerScreenModule, 'WorktreeManagerScreen');
42
- const branchCreatorScreenSpy = vi.spyOn(BranchCreatorScreenModule, 'BranchCreatorScreen');
43
- const branchListScreenSpy = vi.spyOn(BranchListScreenModule, 'BranchListScreen');
44
- const getMergedPRWorktreesSpy = vi.spyOn(worktreeModule, 'getMergedPRWorktrees');
45
- const generateWorktreePathSpy = vi.spyOn(worktreeModule, 'generateWorktreePath');
46
- const createWorktreeSpy = vi.spyOn(worktreeModule, 'createWorktree');
47
- const removeWorktreeSpy = vi.spyOn(worktreeModule, 'removeWorktree');
48
- const getRepositoryRootSpy = vi.spyOn(gitModule, 'getRepositoryRoot');
49
- const deleteBranchSpy = vi.spyOn(gitModule, 'deleteBranch');
50
-
51
- describe('App shortcuts integration', () => {
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");
75
+
76
+ describe("App shortcuts integration", () => {
52
77
  beforeEach(() => {
53
- if (typeof globalThis.document === 'undefined') {
78
+ if (typeof globalThis.document === "undefined") {
54
79
  const window = new Window();
55
80
  globalThis.window = window as any;
56
81
  globalThis.document = window.document as any;
@@ -65,8 +90,8 @@ describe('App shortcuts integration', () => {
65
90
  branches: [],
66
91
  worktrees: [
67
92
  {
68
- branch: 'feature/existing',
69
- path: '/worktrees/feature-existing',
93
+ branch: "feature/existing",
94
+ path: "/worktrees/feature-existing",
70
95
  isAccessible: true,
71
96
  },
72
97
  ],
@@ -76,7 +101,7 @@ describe('App shortcuts integration', () => {
76
101
  lastUpdated: null,
77
102
  }));
78
103
  useScreenStateSpy.mockImplementation(() => ({
79
- currentScreen: 'worktree-manager',
104
+ currentScreen: "worktree-manager",
80
105
  navigateTo: navigateToMock as _Mock,
81
106
  goBack: goBackMock as _Mock,
82
107
  reset: resetMock as _Mock,
@@ -95,42 +120,42 @@ describe('App shortcuts integration', () => {
95
120
  });
96
121
  getMergedPRWorktreesSpy.mockResolvedValue([
97
122
  {
98
- branch: 'feature/add-new-feature',
99
- cleanupType: 'worktree-and-branch',
123
+ branch: "feature/add-new-feature",
124
+ cleanupType: "worktree-and-branch",
100
125
  pullRequest: {
101
126
  number: 123,
102
- title: 'Add new feature',
103
- branch: 'feature/add-new-feature',
104
- mergedAt: '2025-01-20T10:00:00Z',
105
- author: 'user1',
127
+ title: "Add new feature",
128
+ branch: "feature/add-new-feature",
129
+ mergedAt: "2025-01-20T10:00:00Z",
130
+ author: "user1",
106
131
  },
107
- worktreePath: '/worktrees/feature-add-new-feature',
132
+ worktreePath: "/worktrees/feature-add-new-feature",
108
133
  hasUncommittedChanges: false,
109
134
  hasUnpushedCommits: false,
110
135
  hasRemoteBranch: true,
111
136
  isAccessible: true,
112
137
  },
113
138
  {
114
- branch: 'hotfix/urgent-fix',
115
- cleanupType: 'worktree-and-branch',
139
+ branch: "hotfix/urgent-fix",
140
+ cleanupType: "worktree-and-branch",
116
141
  pullRequest: {
117
142
  number: 456,
118
- title: 'Urgent fix',
119
- branch: 'hotfix/urgent-fix',
120
- mergedAt: '2025-01-21T09:00:00Z',
121
- author: 'user2',
143
+ title: "Urgent fix",
144
+ branch: "hotfix/urgent-fix",
145
+ mergedAt: "2025-01-21T09:00:00Z",
146
+ author: "user2",
122
147
  },
123
- worktreePath: '/worktrees/hotfix-urgent-fix',
148
+ worktreePath: "/worktrees/hotfix-urgent-fix",
124
149
  hasUncommittedChanges: true,
125
150
  hasUnpushedCommits: false,
126
151
  hasRemoteBranch: true,
127
152
  isAccessible: true,
128
153
  },
129
154
  ] as CleanupTarget[]);
130
- generateWorktreePathSpy.mockResolvedValue('/worktrees/new-branch');
155
+ generateWorktreePathSpy.mockResolvedValue("/worktrees/new-branch");
131
156
  createWorktreeSpy.mockResolvedValue(undefined);
132
157
  removeWorktreeSpy.mockResolvedValue(undefined);
133
- getRepositoryRootSpy.mockResolvedValue('/repo');
158
+ getRepositoryRootSpy.mockResolvedValue("/repo");
134
159
  deleteBranchSpy.mockResolvedValue(undefined);
135
160
  });
136
161
 
@@ -148,18 +173,26 @@ describe('App shortcuts integration', () => {
148
173
  deleteBranchSpy.mockReset();
149
174
  useGitDataSpy.mockImplementation(originalUseGitData);
150
175
  useScreenStateSpy.mockImplementation(originalUseScreenState);
151
- worktreeManagerScreenSpy.mockImplementation(originalWorktreeManagerScreen as any);
152
- branchCreatorScreenSpy.mockImplementation(originalBranchCreatorScreen as any);
176
+ worktreeManagerScreenSpy.mockImplementation(
177
+ originalWorktreeManagerScreen as any,
178
+ );
179
+ branchCreatorScreenSpy.mockImplementation(
180
+ originalBranchCreatorScreen as any,
181
+ );
153
182
  branchListScreenSpy.mockImplementation(originalBranchListScreen as any);
154
- getMergedPRWorktreesSpy.mockImplementation(originalGetMergedPRWorktrees as any);
155
- generateWorktreePathSpy.mockImplementation(originalGenerateWorktreePath as any);
183
+ getMergedPRWorktreesSpy.mockImplementation(
184
+ originalGetMergedPRWorktrees as any,
185
+ );
186
+ generateWorktreePathSpy.mockImplementation(
187
+ originalGenerateWorktreePath as any,
188
+ );
156
189
  createWorktreeSpy.mockImplementation(originalCreateWorktree as any);
157
190
  removeWorktreeSpy.mockImplementation(originalRemoveWorktree as any);
158
191
  getRepositoryRootSpy.mockImplementation(originalGetRepositoryRoot as any);
159
192
  deleteBranchSpy.mockImplementation(originalDeleteBranch as any);
160
193
  });
161
194
 
162
- it('navigates to AI tool selector when worktree is selected', () => {
195
+ it("navigates to AI tool selector when worktree is selected", () => {
163
196
  const onExit = vi.fn();
164
197
  render(<App onExit={onExit} />);
165
198
 
@@ -169,15 +202,15 @@ describe('App shortcuts integration', () => {
169
202
 
170
203
  onSelect(worktrees[0]);
171
204
 
172
- expect(navigateToMock).toHaveBeenCalledWith('ai-tool-selector');
205
+ expect(navigateToMock).toHaveBeenCalledWith("ai-tool-selector");
173
206
  });
174
207
 
175
- it('creates new worktree when branch creator submits', async () => {
208
+ it("creates new worktree when branch creator submits", async () => {
176
209
  const onExit = vi.fn();
177
210
 
178
211
  // Update screen state mock to branch-creator for this test
179
212
  useScreenStateSpy.mockReturnValue({
180
- currentScreen: 'branch-creator',
213
+ currentScreen: "branch-creator",
181
214
  navigateTo: navigateToMock as _Mock,
182
215
  goBack: goBackMock as _Mock,
183
216
  reset: resetMock as _Mock,
@@ -189,19 +222,19 @@ describe('App shortcuts integration', () => {
189
222
  const { onCreate } = branchCreatorProps[0];
190
223
 
191
224
  await act(async () => {
192
- await onCreate('feature/new-branch');
225
+ await onCreate("feature/new-branch");
193
226
  });
194
227
 
195
228
  expect(createWorktreeSpy).toHaveBeenCalledWith(
196
229
  expect.objectContaining({
197
- branchName: 'feature/new-branch',
230
+ branchName: "feature/new-branch",
198
231
  isNewBranch: true,
199
- })
232
+ }),
200
233
  );
201
- expect(navigateToMock).toHaveBeenCalledWith('ai-tool-selector');
234
+ expect(navigateToMock).toHaveBeenCalledWith("ai-tool-selector");
202
235
  });
203
236
 
204
- it('displays per-branch cleanup indicators and waits before clearing results', async () => {
237
+ it("displays per-branch cleanup indicators and waits before clearing results", async () => {
205
238
  vi.useFakeTimers();
206
239
 
207
240
  try {
@@ -214,18 +247,18 @@ describe('App shortcuts integration', () => {
214
247
  () =>
215
248
  new Promise<void>((resolve) => {
216
249
  resolveRemoveWorktree = resolve;
217
- })
250
+ }),
218
251
  );
219
252
 
220
253
  deleteBranchSpy.mockImplementationOnce(
221
254
  () =>
222
255
  new Promise<void>((resolve) => {
223
256
  resolveDeleteBranch = resolve;
224
- })
257
+ }),
225
258
  );
226
259
 
227
260
  useScreenStateSpy.mockReturnValue({
228
- currentScreen: 'branch-list',
261
+ currentScreen: "branch-list",
229
262
  navigateTo: navigateToMock as _Mock,
230
263
  goBack: goBackMock as _Mock,
231
264
  reset: resetMock as _Mock,
@@ -237,7 +270,7 @@ describe('App shortcuts integration', () => {
237
270
  const initialProps = branchListProps.at(-1);
238
271
  expect(initialProps).toBeDefined();
239
272
  if (!initialProps) {
240
- throw new Error('BranchListScreen props missing');
273
+ throw new Error("BranchListScreen props missing");
241
274
  }
242
275
 
243
276
  act(() => {
@@ -252,8 +285,10 @@ describe('App shortcuts integration', () => {
252
285
  expect(latestProps?.cleanupUI?.inputLocked).toBe(true);
253
286
  expect(latestProps?.cleanupUI?.footerMessage?.text).toBeTruthy();
254
287
  expect(latestProps?.cleanupUI?.indicators).toMatchObject({
255
- 'feature/add-new-feature': expect.objectContaining({ icon: expect.stringMatching(/⠋|⠙|⠹|⠸|⠼|⠴|⠦|⠧/) }),
256
- 'hotfix/urgent-fix': expect.objectContaining({ icon: '⏳' }),
288
+ "feature/add-new-feature": expect.objectContaining({
289
+ icon: expect.stringMatching(/⠋|⠙|⠹|⠸|⠼|⠴|⠦|⠧/),
290
+ }),
291
+ "hotfix/urgent-fix": expect.objectContaining({ icon: "⏳" }),
257
292
  });
258
293
 
259
294
  resolveRemoveWorktree?.();
@@ -265,10 +300,13 @@ describe('App shortcuts integration', () => {
265
300
  resolveDeleteBranch?.();
266
301
 
267
302
  expect(removeWorktreeSpy).toHaveBeenCalledWith(
268
- '/worktrees/feature-add-new-feature',
269
- true
303
+ "/worktrees/feature-add-new-feature",
304
+ true,
305
+ );
306
+ expect(deleteBranchSpy).toHaveBeenCalledWith(
307
+ "feature/add-new-feature",
308
+ true,
270
309
  );
271
- expect(deleteBranchSpy).toHaveBeenCalledWith('feature/add-new-feature', true);
272
310
 
273
311
  // Flush state updates after processing first target
274
312
  await act(async () => {
@@ -277,8 +315,8 @@ describe('App shortcuts integration', () => {
277
315
 
278
316
  latestProps = branchListProps.at(-1);
279
317
  expect(latestProps?.cleanupUI?.indicators).toMatchObject({
280
- 'feature/add-new-feature': { icon: '' },
281
- 'hotfix/urgent-fix': { icon: '⏭️' },
318
+ "feature/add-new-feature": { icon: "" },
319
+ "hotfix/urgent-fix": { icon: "⏭️" },
282
320
  });
283
321
  expect(latestProps?.cleanupUI?.inputLocked).toBe(false);
284
322
 
@@ -291,7 +329,11 @@ describe('App shortcuts integration', () => {
291
329
  latestProps = branchListProps.at(-1);
292
330
  expect(latestProps?.cleanupUI?.indicators).toEqual({});
293
331
  expect(latestProps?.cleanupUI?.inputLocked).toBe(false);
294
- expect(latestProps?.branches?.some((branch: BranchItem) => branch.name === 'feature/add-new-feature')).toBe(false);
332
+ expect(
333
+ latestProps?.branches?.some(
334
+ (branch: BranchItem) => branch.name === "feature/add-new-feature",
335
+ ),
336
+ ).toBe(false);
295
337
  } finally {
296
338
  vi.useRealTimers();
297
339
  }
@@ -303,7 +345,7 @@ afterAll(() => {
303
345
  useScreenStateSpy.mockRestore();
304
346
  worktreeManagerScreenSpy.mockRestore();
305
347
  branchCreatorScreenSpy.mockRestore();
306
- branchListScreenSpy.mockRestore();
348
+ branchListScreenSpy.mockRestore();
307
349
  getMergedPRWorktreesSpy.mockRestore();
308
350
  generateWorktreePathSpy.mockRestore();
309
351
  createWorktreeSpy.mockRestore();