@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,19 @@
1
- import React, { useCallback, useState, useMemo } from 'react';
2
- import { Box, Text, useInput } from 'ink';
3
- import { Header } from '../parts/Header.js';
4
- import { Stats } from '../parts/Stats.js';
5
- import { Footer } from '../parts/Footer.js';
6
- import { Select } from '../common/Select.js';
7
- import { Input } from '../common/Input.js';
8
- import { LoadingIndicator } from '../common/LoadingIndicator.js';
9
- import { useTerminalSize } from '../../hooks/useTerminalSize.js';
10
- import type { BranchItem, Statistics } from '../../types.js';
11
- import stringWidth from 'string-width';
12
- import chalk from 'chalk';
1
+ import React, { useCallback, useState, useMemo } from "react";
2
+ import { Box, Text, useInput } from "ink";
3
+ import { Header } from "../parts/Header.js";
4
+ import { Stats } from "../parts/Stats.js";
5
+ import { Footer } from "../parts/Footer.js";
6
+ import { Select } from "../common/Select.js";
7
+ import { Input } from "../common/Input.js";
8
+ import { LoadingIndicator } from "../common/LoadingIndicator.js";
9
+ import { useTerminalSize } from "../../hooks/useTerminalSize.js";
10
+ import type { BranchItem, Statistics } from "../../types.js";
11
+ import stringWidth from "string-width";
12
+ import chalk from "chalk";
13
13
 
14
14
  const WIDTH_OVERRIDES: Record<string, number> = {
15
- '': 1,
16
- '': 1,
15
+ "": 1,
16
+ "": 1,
17
17
  };
18
18
 
19
19
  const measureDisplayWidth = (value: string): number => {
@@ -29,7 +29,7 @@ const measureDisplayWidth = (value: string): number => {
29
29
  return width;
30
30
  };
31
31
 
32
- type IndicatorColor = 'cyan' | 'green' | 'yellow' | 'red';
32
+ type IndicatorColor = "cyan" | "green" | "yellow" | "red";
33
33
 
34
34
  interface CleanupIndicator {
35
35
  icon: string;
@@ -95,26 +95,28 @@ export function BranchListScreen({
95
95
  const { rows } = useTerminalSize();
96
96
 
97
97
  // Filter state - allow test control via props
98
- const [internalFilterQuery, setInternalFilterQuery] = useState('');
99
- const filterQuery = testFilterQuery !== undefined ? testFilterQuery : internalFilterQuery;
98
+ const [internalFilterQuery, setInternalFilterQuery] = useState("");
99
+ const filterQuery =
100
+ testFilterQuery !== undefined ? testFilterQuery : internalFilterQuery;
100
101
  const setFilterQuery = useCallback(
101
102
  (query: string) => {
102
103
  setInternalFilterQuery(query);
103
104
  testOnFilterQueryChange?.(query);
104
105
  },
105
- [testOnFilterQueryChange]
106
+ [testOnFilterQueryChange],
106
107
  );
107
108
 
108
109
  // Focus management: true = filter mode, false = branch selection mode
109
110
  // Allow test control via props
110
111
  const [internalFilterMode, setInternalFilterMode] = useState(false);
111
- const filterMode = testFilterMode !== undefined ? testFilterMode : internalFilterMode;
112
+ const filterMode =
113
+ testFilterMode !== undefined ? testFilterMode : internalFilterMode;
112
114
  const setFilterMode = useCallback(
113
115
  (mode: boolean) => {
114
116
  setInternalFilterMode(mode);
115
117
  testOnFilterModeChange?.(mode);
116
118
  },
117
- [testOnFilterModeChange]
119
+ [testOnFilterModeChange],
118
120
  );
119
121
 
120
122
  // Handle keyboard input
@@ -129,7 +131,7 @@ export function BranchListScreen({
129
131
  if (key.escape) {
130
132
  if (filterQuery) {
131
133
  // Clear filter query first
132
- setFilterQuery('');
134
+ setFilterQuery("");
133
135
  return;
134
136
  }
135
137
  if (filterMode) {
@@ -140,17 +142,17 @@ export function BranchListScreen({
140
142
  }
141
143
 
142
144
  // Enter filter mode with 'f' key (only in branch selection mode)
143
- if (input === 'f' && !filterMode) {
145
+ if (input === "f" && !filterMode) {
144
146
  setFilterMode(true);
145
147
  return;
146
148
  }
147
149
 
148
150
  // Global shortcuts (blocked by Input component when typing in filter mode)
149
- if (input === 'm' && onNavigate) {
150
- onNavigate('worktree-manager');
151
- } else if (input === 'c') {
151
+ if (input === "m" && onNavigate) {
152
+ onNavigate("worktree-manager");
153
+ } else if (input === "c") {
152
154
  onCleanupCommand?.();
153
- } else if (input === 'r' && onRefresh) {
155
+ } else if (input === "r" && onRefresh) {
154
156
  onRefresh();
155
157
  }
156
158
  });
@@ -189,51 +191,52 @@ export function BranchListScreen({
189
191
  const statsLines = 1;
190
192
  const emptyLine = 1;
191
193
  const footerLines = 1;
192
- const fixedLines = headerLines + filterLines + statsLines + emptyLine + footerLines;
194
+ const fixedLines =
195
+ headerLines + filterLines + statsLines + emptyLine + footerLines;
193
196
  const contentHeight = rows - fixedLines;
194
197
  const limit = Math.max(5, contentHeight); // Minimum 5 items visible
195
198
 
196
199
  // Footer actions
197
200
  const footerActions = [
198
- { key: 'enter', description: 'Select' },
199
- { key: 'f', description: 'Filter' },
200
- { key: 'r', description: 'Refresh' },
201
- { key: 'm', description: 'Manage worktrees' },
202
- { key: 'c', description: 'Cleanup branches' },
201
+ { key: "enter", description: "Select" },
202
+ { key: "f", description: "Filter" },
203
+ { key: "r", description: "Refresh" },
204
+ { key: "m", description: "Manage worktrees" },
205
+ { key: "c", description: "Cleanup branches" },
203
206
  ];
204
207
 
205
208
  const formatLatestCommit = useCallback((timestamp?: number) => {
206
209
  if (!timestamp || Number.isNaN(timestamp)) {
207
- return '---';
210
+ return "---";
208
211
  }
209
212
 
210
213
  const date = new Date(timestamp * 1000);
211
214
  const year = date.getFullYear();
212
- const month = String(date.getMonth() + 1).padStart(2, '0');
213
- const day = String(date.getDate()).padStart(2, '0');
214
- const hours = String(date.getHours()).padStart(2, '0');
215
- const minutes = String(date.getMinutes()).padStart(2, '0');
215
+ const month = String(date.getMonth() + 1).padStart(2, "0");
216
+ const day = String(date.getDate()).padStart(2, "0");
217
+ const hours = String(date.getHours()).padStart(2, "0");
218
+ const minutes = String(date.getMinutes()).padStart(2, "0");
216
219
 
217
220
  return `${year}-${month}-${day} ${hours}:${minutes}`;
218
221
  }, []);
219
222
 
220
223
  const truncateToWidth = useCallback((value: string, maxWidth: number) => {
221
224
  if (maxWidth <= 0) {
222
- return '';
225
+ return "";
223
226
  }
224
227
 
225
228
  if (stringWidth(value) <= maxWidth) {
226
229
  return value;
227
230
  }
228
231
 
229
- const ellipsis = '';
232
+ const ellipsis = "";
230
233
  const ellipsisWidth = stringWidth(ellipsis);
231
234
  if (ellipsisWidth >= maxWidth) {
232
235
  return ellipsis;
233
236
  }
234
237
 
235
238
  let currentWidth = 0;
236
- let result = '';
239
+ let result = "";
237
240
 
238
241
  for (const char of value) {
239
242
  const charWidth = stringWidth(char);
@@ -250,60 +253,67 @@ export function BranchListScreen({
250
253
  const renderBranchRow = useCallback(
251
254
  (item: BranchItem, isSelected: boolean, context: { columns: number }) => {
252
255
  const columns = Math.max(20, context.columns);
253
- const arrow = isSelected ? '>' : ' ';
256
+ const arrow = isSelected ? ">" : " ";
254
257
  const timestampText = formatLatestCommit(item.latestCommitTimestamp);
255
258
  const timestampWidth = stringWidth(timestampText);
256
259
 
257
260
  const indicatorInfo = cleanupUI?.indicators?.[item.name];
258
- let indicatorIcon = indicatorInfo?.icon ?? '';
261
+ let indicatorIcon = indicatorInfo?.icon ?? "";
259
262
  if (indicatorIcon && indicatorInfo?.color && !isSelected) {
260
263
  switch (indicatorInfo.color) {
261
- case 'cyan':
264
+ case "cyan":
262
265
  indicatorIcon = chalk.cyan(indicatorIcon);
263
266
  break;
264
- case 'green':
267
+ case "green":
265
268
  indicatorIcon = chalk.green(indicatorIcon);
266
269
  break;
267
- case 'yellow':
270
+ case "yellow":
268
271
  indicatorIcon = chalk.yellow(indicatorIcon);
269
272
  break;
270
- case 'red':
273
+ case "red":
271
274
  indicatorIcon = chalk.red(indicatorIcon);
272
275
  break;
273
276
  default:
274
277
  break;
275
278
  }
276
279
  }
277
- const indicatorPrefix = indicatorIcon ? `${indicatorIcon} ` : '';
280
+ const indicatorPrefix = indicatorIcon ? `${indicatorIcon} ` : "";
278
281
  const staticPrefix = `${arrow} ${indicatorPrefix}`;
279
282
  const staticPrefixWidth = stringWidth(staticPrefix);
280
283
 
281
- const availableLeftWidth = Math.max(staticPrefixWidth, columns - timestampWidth - 1);
284
+ const availableLeftWidth = Math.max(
285
+ staticPrefixWidth,
286
+ columns - timestampWidth - 1,
287
+ );
282
288
  const maxLabelWidth = Math.max(0, availableLeftWidth - staticPrefixWidth);
283
289
  const truncatedLabel = truncateToWidth(item.label, maxLabelWidth);
284
290
  const leftText = `${staticPrefix}${truncatedLabel}`;
285
291
 
286
292
  const leftMeasuredWidth = stringWidth(leftText);
287
293
  const leftDisplayWidth = measureDisplayWidth(leftText);
288
- const baseGapWidth = Math.max(1, columns - leftMeasuredWidth - timestampWidth);
289
- const displayGapWidth = Math.max(1, columns - leftDisplayWidth - timestampWidth);
294
+ const baseGapWidth = Math.max(
295
+ 1,
296
+ columns - leftMeasuredWidth - timestampWidth,
297
+ );
298
+ const displayGapWidth = Math.max(
299
+ 1,
300
+ columns - leftDisplayWidth - timestampWidth,
301
+ );
290
302
  const cursorShift = Math.max(0, displayGapWidth - baseGapWidth);
291
303
 
292
- const gap = ' '.repeat(baseGapWidth);
293
- const cursorAdjust = cursorShift > 0 ? `\u001b[${cursorShift}C` : '';
304
+ const gap = " ".repeat(baseGapWidth);
305
+ const cursorAdjust = cursorShift > 0 ? `\u001b[${cursorShift}C` : "";
294
306
 
295
307
  let line = `${leftText}${gap}${cursorAdjust}${timestampText}`;
296
308
  const paddingWidth = Math.max(0, columns - stringWidth(line));
297
309
  if (paddingWidth > 0) {
298
- line += ' '.repeat(paddingWidth);
310
+ line += " ".repeat(paddingWidth);
299
311
  }
300
312
 
301
- const output = isSelected
302
- ? `\u001b[46m\u001b[30m${line}\u001b[0m`
303
- : line;
313
+ const output = isSelected ? `\u001b[46m\u001b[30m${line}\u001b[0m` : line;
304
314
  return <Text>{output}</Text>;
305
315
  },
306
- [cleanupUI, formatLatestCommit, truncateToWidth]
316
+ [cleanupUI, formatLatestCommit, truncateToWidth],
307
317
  );
308
318
 
309
319
  return (
@@ -325,14 +335,14 @@ export function BranchListScreen({
325
335
  onChange={setFilterQuery}
326
336
  onSubmit={() => {}} // No-op: filter is applied in real-time
327
337
  placeholder="Type to search..."
328
- blockKeys={['c', 'r', 'm', 'f']} // Block shortcuts while typing
338
+ blockKeys={["c", "r", "m", "f"]} // Block shortcuts while typing
329
339
  />
330
340
  ) : (
331
- <Text dimColor>{filterQuery || '(press f to filter)'}</Text>
341
+ <Text dimColor>{filterQuery || "(press f to filter)"}</Text>
332
342
  )}
333
343
  {filterQuery && (
334
344
  <Text dimColor>
335
- {' '}
345
+ {" "}
336
346
  (Showing {filteredBranches.length} of {branches.length})
337
347
  </Text>
338
348
  )}
@@ -370,22 +380,29 @@ export function BranchListScreen({
370
380
  </Box>
371
381
  )}
372
382
 
373
- {!loading && !error && branches.length > 0 && filteredBranches.length === 0 && filterQuery && (
374
- <Box>
375
- <Text dimColor>No branches match your filter</Text>
376
- </Box>
377
- )}
383
+ {!loading &&
384
+ !error &&
385
+ branches.length > 0 &&
386
+ filteredBranches.length === 0 &&
387
+ filterQuery && (
388
+ <Box>
389
+ <Text dimColor>No branches match your filter</Text>
390
+ </Box>
391
+ )}
378
392
 
379
- {!loading && !error && branches.length > 0 && filteredBranches.length > 0 && (
380
- <Select
381
- items={filteredBranches}
382
- onSelect={onSelect}
383
- limit={limit}
384
- disabled={Boolean(cleanupUI?.inputLocked)}
385
- renderIndicator={() => null}
386
- renderItem={renderBranchRow}
387
- />
388
- )}
393
+ {!loading &&
394
+ !error &&
395
+ branches.length > 0 &&
396
+ filteredBranches.length > 0 && (
397
+ <Select
398
+ items={filteredBranches}
399
+ onSelect={onSelect}
400
+ limit={limit}
401
+ disabled={Boolean(cleanupUI?.inputLocked)}
402
+ renderIndicator={() => null}
403
+ renderItem={renderBranchRow}
404
+ />
405
+ )}
389
406
  </Box>
390
407
 
391
408
  {cleanupUI?.footerMessage && (
@@ -1,11 +1,11 @@
1
- import React, { useState } 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';
1
+ import React, { useState } 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
7
 
8
- export type ExecutionMode = 'normal' | 'continue' | 'resume';
8
+ export type ExecutionMode = "normal" | "continue" | "resume";
9
9
 
10
10
  export interface ExecutionModeItem {
11
11
  label: string;
@@ -62,33 +62,34 @@ export function ExecutionModeSelectorScreen({
62
62
  // Execution mode options (Step 1)
63
63
  const modeItems: ExecutionModeItem[] = [
64
64
  {
65
- label: 'Normal',
66
- value: 'normal',
67
- description: 'Start fresh session',
65
+ label: "Normal",
66
+ value: "normal",
67
+ description: "Start fresh session",
68
68
  },
69
69
  {
70
- label: 'Continue',
71
- value: 'continue',
72
- description: 'Continue from last session',
70
+ label: "Continue",
71
+ value: "continue",
72
+ description: "Continue from last session",
73
73
  },
74
74
  {
75
- label: 'Resume',
76
- value: 'resume',
77
- description: 'Resume specific session',
75
+ label: "Resume",
76
+ value: "resume",
77
+ description: "Resume specific session",
78
78
  },
79
79
  ];
80
80
 
81
81
  // Skip permissions options (Step 2)
82
82
  const skipPermissionsItems: SkipPermissionsItem[] = [
83
83
  {
84
- label: 'No',
85
- value: 'no',
86
- description: 'Normal permission checks',
84
+ label: "No",
85
+ value: "no",
86
+ description: "Normal permission checks",
87
87
  },
88
88
  {
89
- label: 'Yes',
90
- value: 'yes',
91
- description: 'Skip permission checks (--dangerously-skip-permissions / --yolo)',
89
+ label: "Yes",
90
+ value: "yes",
91
+ description:
92
+ "Skip permission checks (--dangerously-skip-permissions / --yolo)",
92
93
  },
93
94
  ];
94
95
 
@@ -103,22 +104,22 @@ export function ExecutionModeSelectorScreen({
103
104
  if (selectedMode) {
104
105
  onSelect({
105
106
  mode: selectedMode,
106
- skipPermissions: item.value === 'yes',
107
+ skipPermissions: item.value === "yes",
107
108
  });
108
109
  }
109
110
  };
110
111
 
111
112
  // Footer actions
112
113
  const footerActions = [
113
- { key: 'enter', description: 'Select' },
114
- { key: 'esc', description: step === 2 ? 'Back to mode selection' : 'Back' },
114
+ { key: "enter", description: "Select" },
115
+ { key: "esc", description: step === 2 ? "Back to mode selection" : "Back" },
115
116
  ];
116
117
 
117
118
  return (
118
119
  <Box flexDirection="column" height={rows}>
119
120
  {/* Header */}
120
121
  <Header
121
- title={step === 1 ? 'Execution Mode' : 'Skip Permissions'}
122
+ title={step === 1 ? "Execution Mode" : "Skip Permissions"}
122
123
  titleColor="magenta"
123
124
  version={version}
124
125
  />
@@ -135,9 +136,15 @@ export function ExecutionModeSelectorScreen({
135
136
  ) : (
136
137
  <>
137
138
  <Box marginBottom={1}>
138
- <Text>Skip permission checks? (--dangerously-skip-permissions / --yolo)</Text>
139
+ <Text>
140
+ Skip permission checks? (--dangerously-skip-permissions /
141
+ --yolo)
142
+ </Text>
139
143
  </Box>
140
- <Select items={skipPermissionsItems} onSelect={handleSkipPermissionsSelect} />
144
+ <Select
145
+ items={skipPermissionsItems}
146
+ onSelect={handleSkipPermissionsSelect}
147
+ />
141
148
  </>
142
149
  )}
143
150
  </Box>
@@ -1,10 +1,10 @@
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
- import type { CleanupTarget } from '../../types.js';
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
+ import type { CleanupTarget } from "../../types.js";
8
8
 
9
9
  export interface PRItem {
10
10
  label: string;
@@ -44,7 +44,7 @@ export function PRCleanupScreen({
44
44
  useInput((input, key) => {
45
45
  if (key.escape) {
46
46
  onBack();
47
- } else if (input === 'r') {
47
+ } else if (input === "r") {
48
48
  onRefresh();
49
49
  }
50
50
  });
@@ -53,28 +53,28 @@ export function PRCleanupScreen({
53
53
  const prItems: PRItem[] = targets.map((target) => {
54
54
  const pr = target.pullRequest;
55
55
  const flags: string[] = [];
56
- if (target.cleanupType === 'worktree-and-branch') {
57
- flags.push('worktree');
56
+ if (target.cleanupType === "worktree-and-branch") {
57
+ flags.push("worktree");
58
58
  } else {
59
- flags.push('branch');
59
+ flags.push("branch");
60
60
  }
61
- if (target.reasons?.includes('merged-pr')) {
62
- flags.push('merged');
61
+ if (target.reasons?.includes("merged-pr")) {
62
+ flags.push("merged");
63
63
  }
64
- if (target.reasons?.includes('no-diff-with-base')) {
65
- flags.push('base');
64
+ if (target.reasons?.includes("no-diff-with-base")) {
65
+ flags.push("base");
66
66
  }
67
67
  if (target.hasUncommittedChanges) {
68
- flags.push('changes');
68
+ flags.push("changes");
69
69
  }
70
70
  if (target.hasUnpushedCommits) {
71
- flags.push('unpushed');
71
+ flags.push("unpushed");
72
72
  }
73
73
  if (target.isAccessible === false) {
74
- flags.push('inaccessible');
74
+ flags.push("inaccessible");
75
75
  }
76
76
 
77
- const flagText = flags.length > 0 ? ` [${flags.join(', ')}]` : '';
77
+ const flagText = flags.length > 0 ? ` [${flags.join(", ")}]` : "";
78
78
 
79
79
  const label = pr
80
80
  ? `${target.branch} - #${pr.number} ${pr.title}${flagText}`
@@ -98,9 +98,9 @@ export function PRCleanupScreen({
98
98
 
99
99
  // Footer actions
100
100
  const footerActions = [
101
- { key: 'enter', description: 'Cleanup' },
102
- { key: 'r', description: 'Refresh' },
103
- { key: 'esc', description: 'Back' },
101
+ { key: "enter", description: "Cleanup" },
102
+ { key: "r", description: "Refresh" },
103
+ { key: "esc", description: "Back" },
104
104
  ];
105
105
 
106
106
  return (
@@ -1,9 +1,9 @@
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';
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
7
 
8
8
  export interface SessionItem {
9
9
  label: string;
@@ -59,8 +59,8 @@ export function SessionSelectorScreen({
59
59
 
60
60
  // Footer actions
61
61
  const footerActions = [
62
- { key: 'enter', description: 'Select' },
63
- { key: 'esc', description: 'Back' },
62
+ { key: "enter", description: "Select" },
63
+ { key: "esc", description: "Back" },
64
64
  ];
65
65
 
66
66
  return (
@@ -1,9 +1,9 @@
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';
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
7
 
8
8
  export interface WorktreeItem {
9
9
  branch: string;
@@ -64,8 +64,8 @@ export function WorktreeManagerScreen({
64
64
 
65
65
  // Footer actions
66
66
  const footerActions = [
67
- { key: 'enter', description: 'Select' },
68
- { key: 'esc', description: 'Back' },
67
+ { key: "enter", description: "Select" },
68
+ { key: "esc", description: "Back" },
69
69
  ];
70
70
 
71
71
  return (
@@ -46,7 +46,9 @@ export function BranchActionSelectorScreen({
46
46
  (mode === "protected" ? "Switch to root branch" : "Use existing branch");
47
47
  const secondaryActionLabel =
48
48
  secondaryLabel ??
49
- (mode === "protected" ? "Create new branch from this branch" : "Create new branch");
49
+ (mode === "protected"
50
+ ? "Create new branch from this branch"
51
+ : "Create new branch");
50
52
 
51
53
  const items: SelectItem[] = [
52
54
  {
@@ -74,15 +76,18 @@ export function BranchActionSelectorScreen({
74
76
 
75
77
  // Footer actions
76
78
  const footerActions = [
77
- { key: 'enter', description: 'Select' },
78
- { key: 'esc', description: 'Back' },
79
+ { key: "enter", description: "Select" },
80
+ { key: "esc", description: "Back" },
79
81
  ];
80
82
 
81
83
  return (
82
84
  <Box flexDirection="column">
83
85
  <Box marginBottom={1}>
84
86
  <Text>
85
- Selected branch: <Text bold color="cyan">{selectedBranch}</Text>
87
+ Selected branch:{" "}
88
+ <Text bold color="cyan">
89
+ {selectedBranch}
90
+ </Text>
86
91
  </Text>
87
92
  </Box>
88
93
  {infoMessage ? (
@@ -8,7 +8,14 @@ export interface WorktreeInfo {
8
8
  export interface BranchInfo {
9
9
  name: string;
10
10
  type: "local" | "remote";
11
- branchType: "feature" | "bugfix" | "hotfix" | "release" | "main" | "develop" | "other";
11
+ branchType:
12
+ | "feature"
13
+ | "bugfix"
14
+ | "hotfix"
15
+ | "release"
16
+ | "main"
17
+ | "develop"
18
+ | "other";
12
19
  isCurrent: boolean;
13
20
  description?: string;
14
21
  worktree?: WorktreeInfo;