@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
@@ -21,7 +21,9 @@ const KEY_PATTERN = /^[A-Z0-9_]+$/;
21
21
 
22
22
  export function createEnvRow(variable?: Partial<EnvRow>): EnvRow {
23
23
  const row: EnvRow = {
24
- id: variable?.id ?? `env-${Date.now()}-${Math.random().toString(36).slice(2)}`,
24
+ id:
25
+ variable?.id ??
26
+ `env-${Date.now()}-${Math.random().toString(36).slice(2)}`,
25
27
  key: variable?.key ?? "",
26
28
  value: variable?.value ?? "",
27
29
  };
@@ -49,13 +51,20 @@ export function EnvEditor({
49
51
  allowAdd = true,
50
52
  emptyLabel = "環境変数はまだありません",
51
53
  }: EnvEditorProps) {
52
- const handleFieldChange = (id: string, field: "key" | "value", value: string) => {
54
+ const handleFieldChange = (
55
+ id: string,
56
+ field: "key" | "value",
57
+ value: string,
58
+ ) => {
53
59
  onChange(
54
60
  rows.map((row) =>
55
61
  row.id === id
56
62
  ? {
57
63
  ...row,
58
- [field]: field === "key" ? value.toUpperCase().replace(/[^A-Z0-9_]/g, "_") : value,
64
+ [field]:
65
+ field === "key"
66
+ ? value.toUpperCase().replace(/[^A-Z0-9_]/g, "_")
67
+ : value,
59
68
  }
60
69
  : row,
61
70
  ),
@@ -75,10 +84,16 @@ export function EnvEditor({
75
84
  <header className="env-editor__header">
76
85
  <div>
77
86
  <h3>{title}</h3>
78
- {description && <p className="env-editor__description">{description}</p>}
87
+ {description && (
88
+ <p className="env-editor__description">{description}</p>
89
+ )}
79
90
  </div>
80
91
  {allowAdd && (
81
- <button type="button" className="button button--secondary" onClick={handleAdd}>
92
+ <button
93
+ type="button"
94
+ className="button button--secondary"
95
+ onClick={handleAdd}
96
+ >
82
97
  変数を追加
83
98
  </button>
84
99
  )}
@@ -99,29 +114,47 @@ export function EnvEditor({
99
114
  {rows.map((row) => {
100
115
  const keyInvalid = isInvalidKey(row);
101
116
  return (
102
- <tr key={row.id} className={keyInvalid ? "env-editor__row--invalid" : undefined}>
117
+ <tr
118
+ key={row.id}
119
+ className={
120
+ keyInvalid ? "env-editor__row--invalid" : undefined
121
+ }
122
+ >
103
123
  <td>
104
124
  <input
105
125
  type="text"
106
126
  value={row.key}
107
- onChange={(event) => handleFieldChange(row.id, "key", event.target.value)}
127
+ onChange={(event) =>
128
+ handleFieldChange(row.id, "key", event.target.value)
129
+ }
108
130
  placeholder="EXAMPLE_KEY"
109
131
  />
110
132
  {row.importedFromOs && (
111
- <span className="pill pill--info" style={{ marginLeft: "0.5rem" }}>
133
+ <span
134
+ className="pill pill--info"
135
+ style={{ marginLeft: "0.5rem" }}
136
+ >
112
137
  OSから取り込み
113
138
  </span>
114
139
  )}
115
140
  {row.lastUpdated && (
116
- <span className="env-editor__meta">更新: {new Date(row.lastUpdated).toLocaleString()}</span>
141
+ <span className="env-editor__meta">
142
+ 更新: {new Date(row.lastUpdated).toLocaleString()}
143
+ </span>
144
+ )}
145
+ {keyInvalid && (
146
+ <p className="env-editor__error">
147
+ A-Z,0-9,_ のみ使用できます
148
+ </p>
117
149
  )}
118
- {keyInvalid && <p className="env-editor__error">A-Z,0-9,_ のみ使用できます</p>}
119
150
  </td>
120
151
  <td>
121
152
  <input
122
153
  type="text"
123
154
  value={row.value}
124
- onChange={(event) => handleFieldChange(row.id, "value", event.target.value)}
155
+ onChange={(event) =>
156
+ handleFieldChange(row.id, "value", event.target.value)
157
+ }
125
158
  placeholder="値"
126
159
  />
127
160
  </td>
@@ -69,7 +69,10 @@ const MERGE_STATUS_LABEL: Record<Branch["mergeStatus"], string> = {
69
69
  unknown: "状態不明",
70
70
  };
71
71
 
72
- const MERGE_STATUS_TONE: Record<Branch["mergeStatus"], "success" | "warning" | "muted"> = {
72
+ const MERGE_STATUS_TONE: Record<
73
+ Branch["mergeStatus"],
74
+ "success" | "warning" | "muted"
75
+ > = {
73
76
  merged: "success",
74
77
  unmerged: "warning",
75
78
  unknown: "muted",
@@ -99,7 +102,9 @@ export function BranchDetailPage() {
99
102
  const [selectedMode, setSelectedMode] = useState<ToolMode>("normal");
100
103
  const [skipPermissions, setSkipPermissions] = useState(false);
101
104
  const [extraArgsText, setExtraArgsText] = useState("");
102
- const [terminatingSessionId, setTerminatingSessionId] = useState<string | null>(null);
105
+ const [terminatingSessionId, setTerminatingSessionId] = useState<
106
+ string | null
107
+ >(null);
103
108
 
104
109
  const formattedCommitDate = useMemo(
105
110
  () => formatDate(branch?.commitDate),
@@ -177,12 +182,14 @@ export function BranchDetailPage() {
177
182
  () => [
178
183
  { id: "claude-code", label: "Claude Code", target: "claude" },
179
184
  { id: "codex-cli", label: "Codex CLI", target: "codex" },
180
- ...customTools.map((tool): SelectableTool => ({
181
- id: tool.id,
182
- label: tool.displayName,
183
- target: "custom" as const,
184
- definition: tool,
185
- })),
185
+ ...customTools.map(
186
+ (tool): SelectableTool => ({
187
+ id: tool.id,
188
+ label: tool.displayName,
189
+ target: "custom" as const,
190
+ definition: tool,
191
+ }),
192
+ ),
186
193
  ],
187
194
  [customTools],
188
195
  );
@@ -200,7 +207,9 @@ export function BranchDetailPage() {
200
207
  }
201
208
  }, [availableTools, selectedToolId]);
202
209
 
203
- const selectedTool = availableTools.find((tool) => tool.id === selectedToolId);
210
+ const selectedTool = availableTools.find(
211
+ (tool) => tool.id === selectedToolId,
212
+ );
204
213
 
205
214
  const selectedToolSummary: ToolSummary | null = useMemo(() => {
206
215
  if (!selectedTool) {
@@ -267,14 +276,18 @@ export function BranchDetailPage() {
267
276
  }
268
277
 
269
278
  if (!selectedTool) {
270
- setBanner({ type: "error", message: "起動するAIツールを選択してください" });
279
+ setBanner({
280
+ type: "error",
281
+ message: "起動するAIツールを選択してください",
282
+ });
271
283
  return;
272
284
  }
273
285
 
274
286
  if (needsRemoteSync) {
275
287
  setBanner({
276
288
  type: "error",
277
- message: "リモートの更新を取り込むまでAIツールは起動できません。『最新の変更を同期』を実行してください。",
289
+ message:
290
+ "リモートの更新を取り込むまでAIツールは起動できません。『最新の変更を同期』を実行してください。",
278
291
  });
279
292
  return;
280
293
  }
@@ -288,7 +301,12 @@ export function BranchDetailPage() {
288
301
  return;
289
302
  }
290
303
 
291
- if (skipPermissions && !window.confirm("権限チェックをスキップして起動します。自己責任で実行してください。続行しますか?")) {
304
+ if (
305
+ skipPermissions &&
306
+ !window.confirm(
307
+ "権限チェックをスキップして起動します。自己責任で実行してください。続行しますか?",
308
+ )
309
+ ) {
292
310
  return;
293
311
  }
294
312
 
@@ -342,7 +360,10 @@ export function BranchDetailPage() {
342
360
  setActiveSessionId(null);
343
361
  }
344
362
  } catch (err) {
345
- setBanner({ type: "error", message: formatError(err, "セッションの終了に失敗しました") });
363
+ setBanner({
364
+ type: "error",
365
+ message: formatError(err, "セッションの終了に失敗しました"),
366
+ });
346
367
  } finally {
347
368
  setTerminatingSessionId(null);
348
369
  }
@@ -350,23 +371,36 @@ export function BranchDetailPage() {
350
371
 
351
372
  const handleSyncBranch = async () => {
352
373
  if (!branch.worktreePath) {
353
- setBanner({ type: "error", message: "Worktreeが存在しないため同期できません。" });
374
+ setBanner({
375
+ type: "error",
376
+ message: "Worktreeが存在しないため同期できません。",
377
+ });
354
378
  return;
355
379
  }
356
380
 
357
381
  try {
358
- const result = await syncBranch.mutateAsync({ worktreePath: branch.worktreePath });
382
+ const result = await syncBranch.mutateAsync({
383
+ worktreePath: branch.worktreePath,
384
+ });
359
385
  if (result.pullStatus === "success") {
360
- setBanner({ type: "success", message: "リモートの最新変更を取り込みました。" });
386
+ setBanner({
387
+ type: "success",
388
+ message: "リモートの最新変更を取り込みました。",
389
+ });
361
390
  } else {
362
- const warning = result.warnings?.join("\n") ?? "fast-forward pull が完了しませんでした";
391
+ const warning =
392
+ result.warnings?.join("\n") ??
393
+ "fast-forward pull が完了しませんでした";
363
394
  setBanner({
364
395
  type: "error",
365
396
  message: `git pull --ff-only が失敗しました。\n${warning}`,
366
397
  });
367
398
  }
368
399
  } catch (err) {
369
- setBanner({ type: "error", message: formatError(err, "Git同期に失敗しました") });
400
+ setBanner({
401
+ type: "error",
402
+ message: formatError(err, "Git同期に失敗しました"),
403
+ });
370
404
  }
371
405
  };
372
406
 
@@ -400,12 +434,16 @@ export function BranchDetailPage() {
400
434
  <span className={`status-badge status-badge--${branch.type}`}>
401
435
  {BRANCH_TYPE_LABEL[branch.type]}
402
436
  </span>
403
- <span className={`status-badge status-badge--${MERGE_STATUS_TONE[branch.mergeStatus]}`}>
437
+ <span
438
+ className={`status-badge status-badge--${MERGE_STATUS_TONE[branch.mergeStatus]}`}
439
+ >
404
440
  {MERGE_STATUS_LABEL[branch.mergeStatus]}
405
441
  </span>
406
442
  <span
407
443
  className={`status-badge ${
408
- branch.worktreePath ? "status-badge--success" : "status-badge--muted"
444
+ branch.worktreePath
445
+ ? "status-badge--success"
446
+ : "status-badge--muted"
409
447
  }`}
410
448
  >
411
449
  {branch.worktreePath ? "Worktreeあり" : "Worktree未作成"}
@@ -450,11 +488,14 @@ export function BranchDetailPage() {
450
488
  <div>
451
489
  <h2>AIツール起動</h2>
452
490
  <p className="section-card__body">
453
- Web UI から直接AIツールを起動できます。設定したカスタムツールも一覧に表示されます。
491
+ Web UI
492
+ から直接AIツールを起動できます。設定したカスタムツールも一覧に表示されます。
454
493
  </p>
455
494
  </div>
456
495
  {configError && (
457
- <span className="pill pill--warning">設定の取得に失敗しました</span>
496
+ <span className="pill pill--warning">
497
+ 設定の取得に失敗しました
498
+ </span>
458
499
  )}
459
500
  </header>
460
501
 
@@ -469,7 +510,9 @@ export function BranchDetailPage() {
469
510
  <span>AIツール</span>
470
511
  <select
471
512
  value={selectedToolId}
472
- onChange={(event) => setSelectedToolId(event.target.value)}
513
+ onChange={(event) =>
514
+ setSelectedToolId(event.target.value)
515
+ }
473
516
  disabled={isConfigLoading}
474
517
  >
475
518
  {availableTools.map((tool) => (
@@ -484,7 +527,9 @@ export function BranchDetailPage() {
484
527
  <span>起動モード</span>
485
528
  <select
486
529
  value={selectedMode}
487
- onChange={(event) => setSelectedMode(event.target.value as ToolMode)}
530
+ onChange={(event) =>
531
+ setSelectedMode(event.target.value as ToolMode)
532
+ }
488
533
  >
489
534
  <option value="normal">normal</option>
490
535
  <option value="continue">continue</option>
@@ -497,7 +542,9 @@ export function BranchDetailPage() {
497
542
  <input
498
543
  type="text"
499
544
  value={extraArgsText}
500
- onChange={(event) => setExtraArgsText(event.target.value)}
545
+ onChange={(event) =>
546
+ setExtraArgsText(event.target.value)
547
+ }
501
548
  placeholder="--flag value"
502
549
  />
503
550
  </label>
@@ -508,39 +555,61 @@ export function BranchDetailPage() {
508
555
  <input
509
556
  type="checkbox"
510
557
  checked={skipPermissions}
511
- onChange={(event) => setSkipPermissions(event.target.checked)}
558
+ onChange={(event) =>
559
+ setSkipPermissions(event.target.checked)
560
+ }
512
561
  />
513
- <span style={{ marginLeft: "0.5rem" }}>権限チェックをスキップ (自己責任)</span>
562
+ <span style={{ marginLeft: "0.5rem" }}>
563
+ 権限チェックをスキップ (自己責任)
564
+ </span>
514
565
  </span>
515
566
  </label>
516
567
  {skipPermissions && (
517
568
  <div className="inline-banner inline-banner--warning">
518
569
  <p>
519
- 権限チェックをスキップすることで、CLI での `--dangerously-skip-permissions` 指定と同様のリスクを負います。
570
+ 権限チェックをスキップすることで、CLI での
571
+ `--dangerously-skip-permissions`
572
+ 指定と同様のリスクを負います。
520
573
  </p>
521
574
  </div>
522
575
  )}
523
576
  {needsRemoteSync && (
524
- <div className="inline-banner inline-banner--info" data-testid="sync-required">
577
+ <div
578
+ className="inline-banner inline-banner--info"
579
+ data-testid="sync-required"
580
+ >
525
581
  <p>
526
- リモートに未取得の更新 ({branch.divergence?.behind ?? 0} commits) があるため、AIツールを起動する前に同期してください。
582
+ リモートに未取得の更新 ({branch.divergence?.behind ?? 0}{" "}
583
+ commits)
584
+ があるため、AIツールを起動する前に同期してください。
527
585
  </p>
528
586
  <p className="section-card__body">
529
- CLI の `git fetch --all` と `git pull --ff-only` と同じ処理を Web UI から実行できます。
587
+ CLI の `git fetch --all` と `git pull --ff-only`
588
+ と同じ処理を Web UI から実行できます。
530
589
  </p>
531
590
  </div>
532
591
  )}
533
592
  {hasBlockingDivergence && (
534
- <div className="inline-banner inline-banner--warning" data-testid="divergence-warning">
593
+ <div
594
+ className="inline-banner inline-banner--warning"
595
+ data-testid="divergence-warning"
596
+ >
535
597
  <p>
536
- リモートとローカルの両方に未解決の差分があるため、Web UI でも CLI と同様に起動をブロックしています。
598
+ リモートとローカルの両方に未解決の差分があるため、Web UI
599
+ でも CLI と同様に起動をブロックしています。
537
600
  </p>
538
601
  <ul className="list-muted">
539
- <li>git fetch && git pull --ff-only origin {branch.name}</li>
540
- <li>必要に応じて git push origin {branch.name} でローカル進捗を共有</li>
602
+ <li>
603
+ git fetch && git pull --ff-only origin {branch.name}
604
+ </li>
605
+ <li>
606
+ 必要に応じて git push origin {branch.name}{" "}
607
+ でローカル進捗を共有
608
+ </li>
541
609
  </ul>
542
610
  <p className="section-card__body">
543
- rebase / merge などで差分を解消した後にページを更新してください。
611
+ rebase / merge
612
+ などで差分を解消した後にページを更新してください。
544
613
  </p>
545
614
  </div>
546
615
  )}
@@ -577,7 +646,9 @@ export function BranchDetailPage() {
577
646
  <dl className="metadata-grid metadata-grid--compact">
578
647
  <div>
579
648
  <dt>コマンド</dt>
580
- <dd className="tool-card__command">{selectedToolSummary.command}</dd>
649
+ <dd className="tool-card__command">
650
+ {selectedToolSummary.command}
651
+ </dd>
581
652
  </div>
582
653
  <div>
583
654
  <dt>defaultArgs</dt>
@@ -585,7 +656,9 @@ export function BranchDetailPage() {
585
656
  </div>
586
657
  <div>
587
658
  <dt>permissionSkipArgs</dt>
588
- <dd>{renderArgs(selectedToolSummary.permissionSkipArgs)}</dd>
659
+ <dd>
660
+ {renderArgs(selectedToolSummary.permissionSkipArgs)}
661
+ </dd>
589
662
  </div>
590
663
  {argsPreview && (
591
664
  <div className="metadata-grid__full">
@@ -605,13 +678,18 @@ export function BranchDetailPage() {
605
678
  <div>
606
679
  <h2>セッション履歴</h2>
607
680
  <p className="section-card__body">
608
- この Worktree に紐づいた最新の AI セッションが表示されます。CLI からの起動分も共有されます。
681
+ この Worktree に紐づいた最新の AI
682
+ セッションが表示されます。CLI からの起動分も共有されます。
609
683
  </p>
610
684
  </div>
611
- {isSessionsLoading && <span className="pill">読み込み中...</span>}
685
+ {isSessionsLoading && (
686
+ <span className="pill">読み込み中...</span>
687
+ )}
612
688
  </header>
613
689
  {branchSessions.length === 0 ? (
614
- <p className="section-card__body">セッション履歴はまだありません。</p>
690
+ <p className="section-card__body">
691
+ セッション履歴はまだありません。
692
+ </p>
615
693
  ) : (
616
694
  <div className="session-table-wrapper">
617
695
  <table className="session-table">
@@ -629,23 +707,40 @@ export function BranchDetailPage() {
629
707
  {branchSessions.slice(0, 5).map((session) => (
630
708
  <tr key={session.sessionId}>
631
709
  <td>
632
- <span className={`status-pill status-pill--${session.status}`}>
710
+ <span
711
+ className={`status-pill status-pill--${session.status}`}
712
+ >
633
713
  {SESSION_STATUS_LABEL[session.status]}
634
714
  </span>
635
715
  </td>
636
- <td>{session.toolType === "custom" ? session.toolName ?? "custom" : toolLabel(session.toolType)}</td>
716
+ <td>
717
+ {session.toolType === "custom"
718
+ ? (session.toolName ?? "custom")
719
+ : toolLabel(session.toolType)}
720
+ </td>
637
721
  <td>{session.mode}</td>
638
722
  <td>{formatDate(session.startedAt)}</td>
639
- <td>{session.endedAt ? formatDate(session.endedAt) : "--"}</td>
723
+ <td>
724
+ {session.endedAt
725
+ ? formatDate(session.endedAt)
726
+ : "--"}
727
+ </td>
640
728
  <td>
641
729
  {session.status === "running" ? (
642
730
  <button
643
731
  type="button"
644
732
  className="button button--ghost"
645
- onClick={() => handleTerminateSession(session.sessionId)}
646
- disabled={terminatingSessionId === session.sessionId || deleteSession.isPending}
733
+ onClick={() =>
734
+ handleTerminateSession(session.sessionId)
735
+ }
736
+ disabled={
737
+ terminatingSessionId === session.sessionId ||
738
+ deleteSession.isPending
739
+ }
647
740
  >
648
- {terminatingSessionId === session.sessionId ? "終了中..." : "終了"}
741
+ {terminatingSessionId === session.sessionId
742
+ ? "終了中..."
743
+ : "終了"}
649
744
  </button>
650
745
  ) : (
651
746
  <span className="session-table__muted">--</span>
@@ -698,10 +793,14 @@ export function BranchDetailPage() {
698
793
  </header>
699
794
  <div className="pill-group">
700
795
  <span className="pill">Ahead {branch.divergence.ahead}</span>
701
- <span className="pill">Behind {branch.divergence.behind}</span>
796
+ <span className="pill">
797
+ Behind {branch.divergence.behind}
798
+ </span>
702
799
  <span
703
800
  className={`pill ${
704
- branch.divergence.upToDate ? "pill--success" : "pill--warning"
801
+ branch.divergence.upToDate
802
+ ? "pill--success"
803
+ : "pill--warning"
705
804
  }`}
706
805
  >
707
806
  {branch.divergence.upToDate ? "最新" : "更新あり"}
@@ -718,8 +817,12 @@ export function BranchDetailPage() {
718
817
  <li>
719
818
  パス: <strong>{branch.worktreePath ?? "未作成"}</strong>
720
819
  </li>
721
- <li>AIツールの起動にはクリーンなワークツリーであることを推奨します。</li>
722
- <li>Worktreeを再作成すると既存のローカル変更が失われる可能性があります。</li>
820
+ <li>
821
+ AIツールの起動にはクリーンなワークツリーであることを推奨します。
822
+ </li>
823
+ <li>
824
+ Worktreeを再作成すると既存のローカル変更が失われる可能性があります。
825
+ </li>
723
826
  </ul>
724
827
  </section>
725
828
  </div>
@@ -745,7 +848,9 @@ export function BranchDetailPage() {
745
848
  className="button button--ghost"
746
849
  onClick={() => setIsTerminalFullscreen((prev) => !prev)}
747
850
  >
748
- {isTerminalFullscreen ? "通常表示に戻す" : "ターミナルを最大化"}
851
+ {isTerminalFullscreen
852
+ ? "通常表示に戻す"
853
+ : "ターミナルを最大化"}
749
854
  </button>
750
855
  </div>
751
856
  </div>
@@ -754,7 +859,10 @@ export function BranchDetailPage() {
754
859
  sessionId={activeSessionId}
755
860
  onExit={handleSessionExit}
756
861
  onError={(message) =>
757
- setBanner({ type: "error", message: message ?? "不明なエラー" })
862
+ setBanner({
863
+ type: "error",
864
+ message: message ?? "不明なエラー",
865
+ })
758
866
  }
759
867
  />
760
868
  </div>
@@ -832,7 +940,10 @@ function renderArgs(args?: string[] | null) {
832
940
  return args.join(" ");
833
941
  }
834
942
 
835
- const SESSION_STATUS_LABEL: Record<"pending" | "running" | "completed" | "failed", string> = {
943
+ const SESSION_STATUS_LABEL: Record<
944
+ "pending" | "running" | "completed" | "failed",
945
+ string
946
+ > = {
836
947
  pending: "pending",
837
948
  running: "running",
838
949
  completed: "completed",
@@ -17,7 +17,10 @@ const MERGE_STATUS_LABEL: Record<Branch["mergeStatus"], string> = {
17
17
  unknown: "状態不明",
18
18
  };
19
19
 
20
- const MERGE_STATUS_TONE: Record<Branch["mergeStatus"], "success" | "warning" | "muted"> = {
20
+ const MERGE_STATUS_TONE: Record<
21
+ Branch["mergeStatus"],
22
+ "success" | "warning" | "muted"
23
+ > = {
21
24
  merged: "success",
22
25
  unmerged: "warning",
23
26
  unknown: "muted",
@@ -37,9 +40,13 @@ export function BranchListPage() {
37
40
  const branches = data ?? [];
38
41
 
39
42
  const metrics = useMemo(() => {
40
- const worktrees = branches.filter((branch) => Boolean(branch.worktreePath)).length;
43
+ const worktrees = branches.filter((branch) =>
44
+ Boolean(branch.worktreePath),
45
+ ).length;
41
46
  const remote = branches.filter((branch) => branch.type === "remote").length;
42
- const healthy = branches.filter((branch) => branch.divergence?.upToDate).length;
47
+ const healthy = branches.filter(
48
+ (branch) => branch.divergence?.upToDate,
49
+ ).length;
43
50
 
44
51
  return {
45
52
  total: branches.length,
@@ -82,14 +89,17 @@ export function BranchListPage() {
82
89
  return {
83
90
  title: "ブランチの取得に失敗しました",
84
91
  description:
85
- error instanceof Error ? error.message : "未知のエラーが発生しました。",
92
+ error instanceof Error
93
+ ? error.message
94
+ : "未知のエラーが発生しました。",
86
95
  };
87
96
  }
88
97
 
89
98
  if (!branches.length) {
90
99
  return {
91
100
  title: "ブランチが見つかりません",
92
- description: "git fetch origin などで最新のブランチを取得してください。",
101
+ description:
102
+ "git fetch origin などで最新のブランチを取得してください。",
93
103
  };
94
104
  }
95
105
 
@@ -105,7 +115,9 @@ export function BranchListPage() {
105
115
  ローカルのGitブランチとAIツールをブラウザ上で一元管理し、Worktree状態を瞬時に
106
116
  可視化します。
107
117
  </p>
108
- <div className="page-hero__meta">リアルタイムで更新されるステータスビュー</div>
118
+ <div className="page-hero__meta">
119
+ リアルタイムで更新されるステータスビュー
120
+ </div>
109
121
  </header>
110
122
 
111
123
  <main className="page-content">
@@ -158,7 +170,7 @@ export function BranchListPage() {
158
170
  />
159
171
  </label>
160
172
  <span className="toolbar__count">
161
- {numberFormatter.format(filteredBranches.length)} / {" "}
173
+ {numberFormatter.format(filteredBranches.length)} /{" "}
162
174
  {numberFormatter.format(metrics.total)} branches
163
175
  </span>
164
176
  </section>
@@ -188,10 +200,14 @@ export function BranchListPage() {
188
200
  <h2>{branch.name}</h2>
189
201
  </div>
190
202
  <div className="badge-group">
191
- <span className={`status-badge status-badge--${branch.type}`}>
203
+ <span
204
+ className={`status-badge status-badge--${branch.type}`}
205
+ >
192
206
  {BRANCH_TYPE_LABEL[branch.type]}
193
207
  </span>
194
- <span className={`status-badge status-badge--${MERGE_STATUS_TONE[branch.mergeStatus]}`}>
208
+ <span
209
+ className={`status-badge status-badge--${MERGE_STATUS_TONE[branch.mergeStatus]}`}
210
+ >
195
211
  {MERGE_STATUS_LABEL[branch.mergeStatus]}
196
212
  </span>
197
213
  <span
@@ -227,11 +243,17 @@ export function BranchListPage() {
227
243
 
228
244
  {branch.divergence && (
229
245
  <div className="pill-group">
230
- <span className="pill">Ahead {branch.divergence.ahead}</span>
231
- <span className="pill">Behind {branch.divergence.behind}</span>
246
+ <span className="pill">
247
+ Ahead {branch.divergence.ahead}
248
+ </span>
249
+ <span className="pill">
250
+ Behind {branch.divergence.behind}
251
+ </span>
232
252
  <span
233
253
  className={`pill ${
234
- branch.divergence.upToDate ? "pill--success" : "pill--warning"
254
+ branch.divergence.upToDate
255
+ ? "pill--success"
256
+ : "pill--warning"
235
257
  }`}
236
258
  >
237
259
  {branch.divergence.upToDate ? "最新" : "更新あり"}
@@ -248,7 +270,9 @@ export function BranchListPage() {
248
270
  </Link>
249
271
  <span
250
272
  className={`info-pill ${
251
- branch.worktreePath ? "info-pill--success" : "info-pill--warning"
273
+ branch.worktreePath
274
+ ? "info-pill--success"
275
+ : "info-pill--warning"
252
276
  }`}
253
277
  >
254
278
  {branch.worktreePath ?? "Worktree未作成"}