@akiojin/gwt 2.13.0 → 2.14.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 (295) hide show
  1. package/README.ja.md +33 -0
  2. package/README.md +31 -0
  3. package/dist/claude.d.ts.map +1 -1
  4. package/dist/claude.js +17 -11
  5. package/dist/claude.js.map +1 -1
  6. package/dist/cli/ui/components/App.d.ts +0 -6
  7. package/dist/cli/ui/components/App.d.ts.map +1 -1
  8. package/dist/cli/ui/components/App.js +27 -88
  9. package/dist/cli/ui/components/App.js.map +1 -1
  10. package/dist/cli/ui/components/common/Select.js +2 -2
  11. package/dist/cli/ui/components/common/Select.js.map +1 -1
  12. package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +1 -1
  13. package/dist/cli/ui/components/screens/BranchListScreen.js +14 -2
  14. package/dist/cli/ui/components/screens/BranchListScreen.js.map +1 -1
  15. package/dist/cli/ui/components/screens/BranchQuickStartScreen.d.ts.map +1 -1
  16. package/dist/cli/ui/components/screens/BranchQuickStartScreen.js +3 -3
  17. package/dist/cli/ui/components/screens/BranchQuickStartScreen.js.map +1 -1
  18. package/dist/cli/ui/utils/continueSession.d.ts.map +1 -1
  19. package/dist/cli/ui/utils/continueSession.js +1 -1
  20. package/dist/cli/ui/utils/continueSession.js.map +1 -1
  21. package/dist/client/assets/index-DPWWHorC.js +72 -0
  22. package/dist/client/assets/index-DsDNCy5f.css +1 -0
  23. package/dist/client/index.html +2 -2
  24. package/dist/codex.d.ts.map +1 -1
  25. package/dist/codex.js +21 -11
  26. package/dist/codex.js.map +1 -1
  27. package/dist/config/builtin-tools.d.ts.map +1 -1
  28. package/dist/config/builtin-tools.js +3 -2
  29. package/dist/config/builtin-tools.js.map +1 -1
  30. package/dist/config/shared-env.d.ts +41 -0
  31. package/dist/config/shared-env.d.ts.map +1 -0
  32. package/dist/config/shared-env.js +114 -0
  33. package/dist/config/shared-env.js.map +1 -0
  34. package/dist/gemini.d.ts.map +1 -1
  35. package/dist/gemini.js +20 -17
  36. package/dist/gemini.js.map +1 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +49 -7
  39. package/dist/index.js.map +1 -1
  40. package/dist/logging/logger.d.ts.map +1 -1
  41. package/dist/logging/logger.js +4 -1
  42. package/dist/logging/logger.js.map +1 -1
  43. package/dist/qwen.d.ts.map +1 -1
  44. package/dist/qwen.js +15 -11
  45. package/dist/qwen.js.map +1 -1
  46. package/dist/services/aiToolResolver.d.ts +41 -0
  47. package/dist/services/aiToolResolver.d.ts.map +1 -0
  48. package/dist/services/aiToolResolver.js +194 -0
  49. package/dist/services/aiToolResolver.js.map +1 -0
  50. package/dist/services/customToolResolver.d.ts +10 -0
  51. package/dist/services/customToolResolver.d.ts.map +1 -0
  52. package/dist/services/customToolResolver.js +71 -0
  53. package/dist/services/customToolResolver.js.map +1 -0
  54. package/dist/shared/aiToolConstants.d.ts +9 -0
  55. package/dist/shared/aiToolConstants.d.ts.map +1 -0
  56. package/dist/shared/aiToolConstants.js +29 -0
  57. package/dist/shared/aiToolConstants.js.map +1 -0
  58. package/dist/types/tools.d.ts +12 -0
  59. package/dist/types/tools.d.ts.map +1 -1
  60. package/dist/utils/prompt.d.ts.map +1 -1
  61. package/dist/utils/prompt.js.map +1 -1
  62. package/dist/utils/session.d.ts.map +1 -1
  63. package/dist/utils/session.js +15 -6
  64. package/dist/utils/session.js.map +1 -1
  65. package/dist/utils/terminal.d.ts +12 -3
  66. package/dist/utils/terminal.d.ts.map +1 -1
  67. package/dist/utils/terminal.js +5 -34
  68. package/dist/utils/terminal.js.map +1 -1
  69. package/dist/utils/webui.d.ts +8 -0
  70. package/dist/utils/webui.d.ts.map +1 -0
  71. package/dist/utils/webui.js +35 -0
  72. package/dist/utils/webui.js.map +1 -0
  73. package/dist/web/client/src/components/AIToolLaunchModal.d.ts +9 -0
  74. package/dist/web/client/src/components/AIToolLaunchModal.d.ts.map +1 -0
  75. package/dist/web/client/src/components/AIToolLaunchModal.js +363 -0
  76. package/dist/web/client/src/components/AIToolLaunchModal.js.map +1 -0
  77. package/dist/web/client/src/components/BranchGraph.d.ts.map +1 -1
  78. package/dist/web/client/src/components/BranchGraph.js +46 -49
  79. package/dist/web/client/src/components/BranchGraph.js.map +1 -1
  80. package/dist/web/client/src/components/CustomToolForm.d.ts +23 -0
  81. package/dist/web/client/src/components/CustomToolForm.d.ts.map +1 -0
  82. package/dist/web/client/src/components/CustomToolForm.js +209 -0
  83. package/dist/web/client/src/components/CustomToolForm.js.map +1 -0
  84. package/dist/web/client/src/components/CustomToolList.d.ts +10 -0
  85. package/dist/web/client/src/components/CustomToolList.d.ts.map +1 -0
  86. package/dist/web/client/src/components/CustomToolList.js +57 -0
  87. package/dist/web/client/src/components/CustomToolList.js.map +1 -0
  88. package/dist/web/client/src/components/EnvEditor.d.ts.map +1 -1
  89. package/dist/web/client/src/components/EnvEditor.js +33 -26
  90. package/dist/web/client/src/components/EnvEditor.js.map +1 -1
  91. package/dist/web/client/src/components/EnvironmentEditor.d.ts +17 -0
  92. package/dist/web/client/src/components/EnvironmentEditor.d.ts.map +1 -0
  93. package/dist/web/client/src/components/EnvironmentEditor.js +22 -0
  94. package/dist/web/client/src/components/EnvironmentEditor.js.map +1 -0
  95. package/dist/web/client/src/components/Terminal.d.ts.map +1 -1
  96. package/dist/web/client/src/components/Terminal.js +10 -3
  97. package/dist/web/client/src/components/Terminal.js.map +1 -1
  98. package/dist/web/client/src/components/branch-detail/BranchInfoCards.d.ts +10 -0
  99. package/dist/web/client/src/components/branch-detail/BranchInfoCards.d.ts.map +1 -0
  100. package/dist/web/client/src/components/branch-detail/BranchInfoCards.js +104 -0
  101. package/dist/web/client/src/components/branch-detail/BranchInfoCards.js.map +1 -0
  102. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.d.ts +22 -0
  103. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.d.ts.map +1 -0
  104. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js +79 -0
  105. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js.map +1 -0
  106. package/dist/web/client/src/components/branch-detail/TerminalPanel.d.ts +11 -0
  107. package/dist/web/client/src/components/branch-detail/TerminalPanel.d.ts.map +1 -0
  108. package/dist/web/client/src/components/branch-detail/TerminalPanel.js +32 -0
  109. package/dist/web/client/src/components/branch-detail/TerminalPanel.js.map +1 -0
  110. package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts +40 -0
  111. package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts.map +1 -0
  112. package/dist/web/client/src/components/branch-detail/ToolLauncher.js +147 -0
  113. package/dist/web/client/src/components/branch-detail/ToolLauncher.js.map +1 -0
  114. package/dist/web/client/src/components/branch-detail/index.d.ts +5 -0
  115. package/dist/web/client/src/components/branch-detail/index.d.ts.map +1 -0
  116. package/dist/web/client/src/components/branch-detail/index.js +5 -0
  117. package/dist/web/client/src/components/branch-detail/index.js.map +1 -0
  118. package/dist/web/client/src/components/common/BranchCard.d.ts +17 -0
  119. package/dist/web/client/src/components/common/BranchCard.d.ts.map +1 -0
  120. package/dist/web/client/src/components/common/BranchCard.js +36 -0
  121. package/dist/web/client/src/components/common/BranchCard.js.map +1 -0
  122. package/dist/web/client/src/components/common/MetricCard.d.ts +10 -0
  123. package/dist/web/client/src/components/common/MetricCard.d.ts.map +1 -0
  124. package/dist/web/client/src/components/common/MetricCard.js +10 -0
  125. package/dist/web/client/src/components/common/MetricCard.js.map +1 -0
  126. package/dist/web/client/src/components/common/PageHeader.d.ts +12 -0
  127. package/dist/web/client/src/components/common/PageHeader.d.ts.map +1 -0
  128. package/dist/web/client/src/components/common/PageHeader.js +14 -0
  129. package/dist/web/client/src/components/common/PageHeader.js.map +1 -0
  130. package/dist/web/client/src/components/common/SearchInput.d.ts +14 -0
  131. package/dist/web/client/src/components/common/SearchInput.d.ts.map +1 -0
  132. package/dist/web/client/src/components/common/SearchInput.js +15 -0
  133. package/dist/web/client/src/components/common/SearchInput.js.map +1 -0
  134. package/dist/web/client/src/components/common/StatusBadge.d.ts +10 -0
  135. package/dist/web/client/src/components/common/StatusBadge.d.ts.map +1 -0
  136. package/dist/web/client/src/components/common/StatusBadge.js +15 -0
  137. package/dist/web/client/src/components/common/StatusBadge.js.map +1 -0
  138. package/dist/web/client/src/components/common/index.d.ts +6 -0
  139. package/dist/web/client/src/components/common/index.d.ts.map +1 -0
  140. package/dist/web/client/src/components/common/index.js +6 -0
  141. package/dist/web/client/src/components/common/index.js.map +1 -0
  142. package/dist/web/client/src/components/ui/alert.d.ts +9 -0
  143. package/dist/web/client/src/components/ui/alert.d.ts.map +1 -0
  144. package/dist/web/client/src/components/ui/alert.js +25 -0
  145. package/dist/web/client/src/components/ui/alert.js.map +1 -0
  146. package/dist/web/client/src/components/ui/badge.d.ts +10 -0
  147. package/dist/web/client/src/components/ui/badge.d.ts.map +1 -0
  148. package/dist/web/client/src/components/ui/badge.js +25 -0
  149. package/dist/web/client/src/components/ui/badge.js.map +1 -0
  150. package/dist/web/client/src/components/ui/button.d.ts +12 -0
  151. package/dist/web/client/src/components/ui/button.d.ts.map +1 -0
  152. package/dist/web/client/src/components/ui/button.js +33 -0
  153. package/dist/web/client/src/components/ui/button.js.map +1 -0
  154. package/dist/web/client/src/components/ui/card.d.ts +9 -0
  155. package/dist/web/client/src/components/ui/card.d.ts.map +1 -0
  156. package/dist/web/client/src/components/ui/card.js +16 -0
  157. package/dist/web/client/src/components/ui/card.js.map +1 -0
  158. package/dist/web/client/src/components/ui/index.d.ts +8 -0
  159. package/dist/web/client/src/components/ui/index.d.ts.map +1 -0
  160. package/dist/web/client/src/components/ui/index.js +8 -0
  161. package/dist/web/client/src/components/ui/index.js.map +1 -0
  162. package/dist/web/client/src/components/ui/input.d.ts +4 -0
  163. package/dist/web/client/src/components/ui/input.d.ts.map +1 -0
  164. package/dist/web/client/src/components/ui/input.js +8 -0
  165. package/dist/web/client/src/components/ui/input.js.map +1 -0
  166. package/dist/web/client/src/components/ui/select.d.ts +14 -0
  167. package/dist/web/client/src/components/ui/select.d.ts.map +1 -0
  168. package/dist/web/client/src/components/ui/select.js +39 -0
  169. package/dist/web/client/src/components/ui/select.js.map +1 -0
  170. package/dist/web/client/src/components/ui/table.d.ts +11 -0
  171. package/dist/web/client/src/components/ui/table.d.ts.map +1 -0
  172. package/dist/web/client/src/components/ui/table.js +21 -0
  173. package/dist/web/client/src/components/ui/table.js.map +1 -0
  174. package/dist/web/client/src/hooks/useSessions.d.ts.map +1 -1
  175. package/dist/web/client/src/hooks/useSessions.js +6 -1
  176. package/dist/web/client/src/hooks/useSessions.js.map +1 -1
  177. package/dist/web/client/src/lib/utils.d.ts +7 -0
  178. package/dist/web/client/src/lib/utils.d.ts.map +1 -0
  179. package/dist/web/client/src/lib/utils.js +10 -0
  180. package/dist/web/client/src/lib/utils.js.map +1 -0
  181. package/dist/web/client/src/lib/websocket.d.ts +7 -0
  182. package/dist/web/client/src/lib/websocket.d.ts.map +1 -1
  183. package/dist/web/client/src/lib/websocket.js +44 -0
  184. package/dist/web/client/src/lib/websocket.js.map +1 -1
  185. package/dist/web/client/src/pages/BranchDetailPage.d.ts.map +1 -1
  186. package/dist/web/client/src/pages/BranchDetailPage.js +113 -361
  187. package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
  188. package/dist/web/client/src/pages/BranchListPage.d.ts.map +1 -1
  189. package/dist/web/client/src/pages/BranchListPage.js +89 -127
  190. package/dist/web/client/src/pages/BranchListPage.js.map +1 -1
  191. package/dist/web/client/src/pages/ConfigManagementPage.d.ts.map +1 -1
  192. package/dist/web/client/src/pages/ConfigManagementPage.js +46 -41
  193. package/dist/web/client/src/pages/ConfigManagementPage.js.map +1 -1
  194. package/dist/web/client/src/pages/ConfigPage.d.ts +3 -0
  195. package/dist/web/client/src/pages/ConfigPage.d.ts.map +1 -0
  196. package/dist/web/client/src/pages/ConfigPage.js +216 -0
  197. package/dist/web/client/src/pages/ConfigPage.js.map +1 -0
  198. package/dist/web/client/vite.config.d.ts.map +1 -1
  199. package/dist/web/client/vite.config.js +8 -1
  200. package/dist/web/client/vite.config.js.map +1 -1
  201. package/dist/web/server/index.d.ts +24 -2
  202. package/dist/web/server/index.d.ts.map +1 -1
  203. package/dist/web/server/index.js +46 -15
  204. package/dist/web/server/index.js.map +1 -1
  205. package/dist/web/server/pty/manager.d.ts +12 -10
  206. package/dist/web/server/pty/manager.d.ts.map +1 -1
  207. package/dist/web/server/pty/manager.js +76 -43
  208. package/dist/web/server/pty/manager.js.map +1 -1
  209. package/dist/web/server/routes/sessions.d.ts.map +1 -1
  210. package/dist/web/server/routes/sessions.js +35 -2
  211. package/dist/web/server/routes/sessions.js.map +1 -1
  212. package/dist/web/server/routes/worktrees.js +2 -2
  213. package/dist/web/server/routes/worktrees.js.map +1 -1
  214. package/dist/web/server/services/worktrees.d.ts.map +1 -1
  215. package/dist/web/server/services/worktrees.js +7 -1
  216. package/dist/web/server/services/worktrees.js.map +1 -1
  217. package/dist/web/server/tray.d.ts +24 -0
  218. package/dist/web/server/tray.d.ts.map +1 -0
  219. package/dist/web/server/tray.js +79 -0
  220. package/dist/web/server/tray.js.map +1 -0
  221. package/dist/web/server/websocket/handler.d.ts +18 -2
  222. package/dist/web/server/websocket/handler.d.ts.map +1 -1
  223. package/dist/web/server/websocket/handler.js +82 -9
  224. package/dist/web/server/websocket/handler.js.map +1 -1
  225. package/package.json +15 -2
  226. package/src/claude.ts +26 -15
  227. package/src/cli/ui/__tests__/components/common/Select.test.tsx +11 -0
  228. package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +17 -1
  229. package/src/cli/ui/__tests__/components/screens/BranchQuickStartScreen.test.tsx +4 -4
  230. package/src/cli/ui/components/App.tsx +33 -133
  231. package/src/cli/ui/components/common/Select.tsx +2 -2
  232. package/src/cli/ui/components/screens/BranchListScreen.tsx +43 -23
  233. package/src/cli/ui/components/screens/BranchQuickStartScreen.tsx +41 -46
  234. package/src/cli/ui/utils/continueSession.ts +1 -7
  235. package/src/codex.ts +31 -22
  236. package/src/config/builtin-tools.ts +6 -2
  237. package/src/config/shared-env.ts +139 -0
  238. package/src/gemini.ts +35 -22
  239. package/src/index.ts +54 -7
  240. package/src/logging/logger.ts +5 -2
  241. package/src/qwen.ts +28 -19
  242. package/src/services/aiToolResolver.ts +276 -0
  243. package/src/services/customToolResolver.ts +98 -0
  244. package/src/shared/aiToolConstants.ts +30 -0
  245. package/src/trayicon.d.ts +30 -0
  246. package/src/types/tools.ts +15 -0
  247. package/src/utils/prompt.ts +15 -9
  248. package/src/utils/session.ts +80 -26
  249. package/src/utils/terminal.ts +11 -41
  250. package/src/utils/webui.ts +43 -0
  251. package/src/web/client/components.json +21 -0
  252. package/src/web/client/src/components/AIToolLaunchModal.tsx +575 -0
  253. package/src/web/client/src/components/BranchGraph.tsx +95 -75
  254. package/src/web/client/src/components/CustomToolForm.tsx +386 -0
  255. package/src/web/client/src/components/CustomToolList.tsx +119 -0
  256. package/src/web/client/src/components/EnvEditor.tsx +91 -81
  257. package/src/web/client/src/components/EnvironmentEditor.tsx +97 -0
  258. package/src/web/client/src/components/Terminal.tsx +11 -3
  259. package/src/web/client/src/components/branch-detail/BranchInfoCards.tsx +179 -0
  260. package/src/web/client/src/components/branch-detail/SessionHistoryTable.tsx +181 -0
  261. package/src/web/client/src/components/branch-detail/TerminalPanel.tsx +92 -0
  262. package/src/web/client/src/components/branch-detail/ToolLauncher.tsx +327 -0
  263. package/src/web/client/src/components/branch-detail/index.ts +4 -0
  264. package/src/web/client/src/components/common/BranchCard.tsx +117 -0
  265. package/src/web/client/src/components/common/MetricCard.tsx +22 -0
  266. package/src/web/client/src/components/common/PageHeader.tsx +44 -0
  267. package/src/web/client/src/components/common/SearchInput.tsx +40 -0
  268. package/src/web/client/src/components/common/StatusBadge.tsx +37 -0
  269. package/src/web/client/src/components/common/index.ts +5 -0
  270. package/src/web/client/src/components/ui/alert.tsx +63 -0
  271. package/src/web/client/src/components/ui/badge.tsx +44 -0
  272. package/src/web/client/src/components/ui/button.tsx +57 -0
  273. package/src/web/client/src/components/ui/card.tsx +82 -0
  274. package/src/web/client/src/components/ui/index.ts +32 -0
  275. package/src/web/client/src/components/ui/input.tsx +21 -0
  276. package/src/web/client/src/components/ui/select.tsx +156 -0
  277. package/src/web/client/src/components/ui/table.tsx +119 -0
  278. package/src/web/client/src/hooks/useSessions.ts +10 -1
  279. package/src/web/client/src/index.css +46 -816
  280. package/src/web/client/src/lib/utils.ts +10 -0
  281. package/src/web/client/src/lib/websocket.ts +48 -1
  282. package/src/web/client/src/pages/BranchDetailPage.tsx +222 -694
  283. package/src/web/client/src/pages/BranchListPage.tsx +190 -236
  284. package/src/web/client/src/pages/ConfigManagementPage.tsx +94 -76
  285. package/src/web/client/src/pages/ConfigPage.tsx +362 -0
  286. package/src/web/client/vite.config.ts +8 -1
  287. package/src/web/server/index.ts +72 -15
  288. package/src/web/server/pty/manager.ts +128 -55
  289. package/src/web/server/routes/sessions.ts +59 -7
  290. package/src/web/server/routes/worktrees.ts +3 -3
  291. package/src/web/server/services/worktrees.ts +12 -4
  292. package/src/web/server/tray.ts +93 -0
  293. package/src/web/server/websocket/handler.ts +119 -13
  294. package/dist/client/assets/index-DeNwPosA.css +0 -1
  295. package/dist/client/assets/index-Dl798X5w.js +0 -32
@@ -2,37 +2,22 @@ import React, { useMemo, useState } from "react";
2
2
  import { Link } from "react-router-dom";
3
3
  import { useBranches } from "../hooks/useBranches";
4
4
  import { BranchGraph } from "../components/BranchGraph";
5
+ import { PageHeader } from "@/components/common/PageHeader";
6
+ import { MetricCard } from "@/components/common/MetricCard";
7
+ import { SearchInput } from "@/components/common/SearchInput";
8
+ import {
9
+ Card,
10
+ CardHeader,
11
+ CardContent,
12
+ CardFooter,
13
+ } from "@/components/ui/card";
14
+ import { Badge } from "@/components/ui/badge";
15
+ import { Button } from "@/components/ui/button";
16
+ import { Alert, AlertDescription } from "@/components/ui/alert";
5
17
  import type { Branch } from "../../../../types/api.js";
6
18
 
7
19
  const numberFormatter = new Intl.NumberFormat("ja-JP");
8
20
 
9
- const BRANCH_TYPE_LABEL: Record<Branch["type"], string> = {
10
- local: "ローカル",
11
- remote: "リモート",
12
- };
13
-
14
- const MERGE_STATUS_LABEL: Record<Branch["mergeStatus"], string> = {
15
- merged: "マージ済み",
16
- unmerged: "未マージ",
17
- unknown: "状態不明",
18
- };
19
-
20
- const MERGE_STATUS_TONE: Record<
21
- Branch["mergeStatus"],
22
- "success" | "warning" | "muted"
23
- > = {
24
- merged: "success",
25
- unmerged: "warning",
26
- unknown: "muted",
27
- };
28
-
29
- interface PageStateMessage {
30
- title: string;
31
- description: string;
32
- }
33
-
34
- const SEARCH_PLACEHOLDER = "ブランチ名やタイプで検索...";
35
-
36
21
  export function BranchListPage() {
37
22
  const { data, isLoading, error } = useBranches();
38
23
  const [query, setQuery] = useState("");
@@ -40,28 +25,17 @@ export function BranchListPage() {
40
25
  const branches = data ?? [];
41
26
 
42
27
  const metrics = useMemo(() => {
43
- const worktrees = branches.filter((branch) =>
44
- Boolean(branch.worktreePath),
45
- ).length;
46
- const remote = branches.filter((branch) => branch.type === "remote").length;
47
- const healthy = branches.filter(
48
- (branch) => branch.divergence?.upToDate,
49
- ).length;
28
+ const worktrees = branches.filter((b) => Boolean(b.worktreePath)).length;
29
+ const remote = branches.filter((b) => b.type === "remote").length;
30
+ const healthy = branches.filter((b) => b.divergence?.upToDate).length;
50
31
 
51
- return {
52
- total: branches.length,
53
- worktrees,
54
- remote,
55
- healthy,
56
- };
32
+ return { total: branches.length, worktrees, remote, healthy };
57
33
  }, [branches]);
58
34
 
59
35
  const normalizedQuery = query.trim().toLowerCase();
60
36
 
61
37
  const filteredBranches = useMemo(() => {
62
- if (!normalizedQuery) {
63
- return branches;
64
- }
38
+ if (!normalizedQuery) return branches;
65
39
 
66
40
  return branches.filter((branch) => {
67
41
  const haystack = [
@@ -77,208 +51,129 @@ export function BranchListPage() {
77
51
  });
78
52
  }, [branches, normalizedQuery]);
79
53
 
80
- const pageState: PageStateMessage | null = useMemo(() => {
81
- if (isLoading) {
82
- return {
83
- title: "データを読み込み中",
84
- description: "最新のブランチ一覧を取得しています...",
85
- };
86
- }
87
-
88
- if (error) {
89
- return {
90
- title: "ブランチの取得に失敗しました",
91
- description:
92
- error instanceof Error
93
- ? error.message
94
- : "未知のエラーが発生しました。",
95
- };
96
- }
97
-
98
- if (!branches.length) {
99
- return {
100
- title: "ブランチが見つかりません",
101
- description:
102
- "git fetch origin などで最新のブランチを取得してください。",
103
- };
104
- }
105
-
106
- return null;
107
- }, [branches.length, error, isLoading]);
54
+ // Loading state
55
+ if (isLoading) {
56
+ return (
57
+ <div className="min-h-screen bg-background">
58
+ <PageHeader
59
+ eyebrow="WORKTREE DASHBOARD"
60
+ title="gwt Control Center"
61
+ subtitle="Loading branch data..."
62
+ />
63
+ <main className="mx-auto max-w-7xl px-6 py-8">
64
+ <div className="flex items-center justify-center py-20">
65
+ <div className="text-center">
66
+ <div className="mb-4 text-4xl">⏳</div>
67
+ <p className="text-muted-foreground">Loading branches...</p>
68
+ </div>
69
+ </div>
70
+ </main>
71
+ </div>
72
+ );
73
+ }
74
+
75
+ // Error state
76
+ if (error) {
77
+ return (
78
+ <div className="min-h-screen bg-background">
79
+ <PageHeader eyebrow="WORKTREE DASHBOARD" title="gwt Control Center" />
80
+ <main className="mx-auto max-w-7xl px-6 py-8">
81
+ <Alert variant="destructive">
82
+ <AlertDescription>
83
+ {error instanceof Error
84
+ ? error.message
85
+ : "Failed to load branches"}
86
+ </AlertDescription>
87
+ </Alert>
88
+ </main>
89
+ </div>
90
+ );
91
+ }
92
+
93
+ // Empty state
94
+ if (!branches.length) {
95
+ return (
96
+ <div className="min-h-screen bg-background">
97
+ <PageHeader eyebrow="WORKTREE DASHBOARD" title="gwt Control Center" />
98
+ <main className="mx-auto max-w-7xl px-6 py-8">
99
+ <Card className="border-dashed">
100
+ <CardContent className="flex flex-col items-center justify-center py-12">
101
+ <div className="mb-4 text-4xl">📭</div>
102
+ <h3 className="mb-2 text-lg font-semibold">No branches found</h3>
103
+ <p className="text-sm text-muted-foreground">
104
+ Try running{" "}
105
+ <code className="rounded bg-muted px-1">git fetch origin</code>{" "}
106
+ to sync branches.
107
+ </p>
108
+ </CardContent>
109
+ </Card>
110
+ </main>
111
+ </div>
112
+ );
113
+ }
108
114
 
109
115
  return (
110
- <div className="app-shell">
111
- <header className="page-hero">
112
- <p className="page-hero__eyebrow">WORKTREE DASHBOARD</p>
113
- <h1>gwt Control Center</h1>
114
- <p>
115
- ローカルのGitブランチとAIツールをブラウザ上で一元管理し、Worktree状態を瞬時に
116
- 可視化します。
117
- </p>
118
- <div className="page-hero__meta">
119
- リアルタイムで更新されるステータスビュー
120
- </div>
121
- </header>
122
-
123
- <main className="page-content">
124
- {!pageState && filteredBranches.length > 0 && (
116
+ <div className="min-h-screen bg-background">
117
+ <PageHeader
118
+ eyebrow="WORKTREE DASHBOARD"
119
+ title="gwt Control Center"
120
+ subtitle="Manage Git branches and AI tools from your browser"
121
+ />
122
+
123
+ <main className="mx-auto max-w-7xl space-y-6 px-6 py-8">
124
+ {/* Branch Graph */}
125
+ {filteredBranches.length > 0 && (
125
126
  <BranchGraph branches={filteredBranches} />
126
127
  )}
127
128
 
128
- <section className="metrics-grid">
129
- <article className="metric-card">
130
- <p className="metric-card__label">総ブランチ数</p>
131
- <p className="metric-card__value" data-testid="metric-total">
132
- {numberFormatter.format(metrics.total)}
133
- </p>
134
- <p className="metric-card__hint">ローカル + リモート</p>
135
- </article>
136
- <article className="metric-card">
137
- <p className="metric-card__label">作成済みWorktree</p>
138
- <p className="metric-card__value" data-testid="metric-worktrees">
139
- {numberFormatter.format(metrics.worktrees)}
140
- </p>
141
- <p className="metric-card__hint">即座にAIツールを起動可能</p>
142
- </article>
143
- <article className="metric-card">
144
- <p className="metric-card__label">リモート追跡ブランチ</p>
145
- <p className="metric-card__value">
146
- {numberFormatter.format(metrics.remote)}
147
- </p>
148
- <p className="metric-card__hint">origin との同期ステータス</p>
149
- </article>
150
- <article className="metric-card">
151
- <p className="metric-card__label">最新コミットが最新</p>
152
- <p className="metric-card__value">
153
- {numberFormatter.format(metrics.healthy)}
154
- </p>
155
- <p className="metric-card__hint">divergence 0 のブランチ</p>
156
- </article>
157
- </section>
158
-
159
- <section className="toolbar">
160
- <label className="toolbar__field">
161
- <span className="toolbar__icon" aria-hidden="true">
162
- 🔍
163
- </span>
164
- <input
165
- type="search"
166
- className="search-input"
167
- placeholder={SEARCH_PLACEHOLDER}
168
- value={query}
169
- onChange={(event) => setQuery(event.target.value)}
170
- />
171
- </label>
172
- <span className="toolbar__count">
173
- {numberFormatter.format(filteredBranches.length)} /{" "}
174
- {numberFormatter.format(metrics.total)} branches
175
- </span>
129
+ {/* Metrics Grid */}
130
+ <section className="grid grid-cols-2 gap-4 md:grid-cols-4">
131
+ <MetricCard
132
+ label="Total Branches"
133
+ value={numberFormatter.format(metrics.total)}
134
+ hint="Local + Remote"
135
+ />
136
+ <MetricCard
137
+ label="Active Worktrees"
138
+ value={numberFormatter.format(metrics.worktrees)}
139
+ hint="Ready for AI tools"
140
+ />
141
+ <MetricCard
142
+ label="Remote Tracking"
143
+ value={numberFormatter.format(metrics.remote)}
144
+ hint="Synced with origin"
145
+ />
146
+ <MetricCard
147
+ label="Up to Date"
148
+ value={numberFormatter.format(metrics.healthy)}
149
+ hint="No divergence"
150
+ />
176
151
  </section>
177
152
 
178
- {pageState ? (
179
- <div className="page-state page-state--card">
180
- <h2>{pageState.title}</h2>
181
- <p>{pageState.description}</p>
182
- </div>
183
- ) : filteredBranches.length === 0 ? (
184
- <div className="empty-state">
185
- <h3>一致するブランチがありません</h3>
186
- <p>
187
- 検索条件を見直すか、タグ・ブランチタイプ・コミットメッセージなど別のキーワードを
188
- 試してください。
189
- </p>
190
- </div>
153
+ {/* Search */}
154
+ <SearchInput
155
+ value={query}
156
+ onChange={setQuery}
157
+ placeholder="Search branches by name, type, or commit..."
158
+ count={{ filtered: filteredBranches.length, total: metrics.total }}
159
+ />
160
+
161
+ {/* Branch Grid */}
162
+ {filteredBranches.length === 0 ? (
163
+ <Card className="border-dashed">
164
+ <CardContent className="flex flex-col items-center justify-center py-12">
165
+ <h3 className="mb-2 text-lg font-semibold">
166
+ No matching branches
167
+ </h3>
168
+ <p className="text-sm text-muted-foreground">
169
+ Try a different search term or clear the filter.
170
+ </p>
171
+ </CardContent>
172
+ </Card>
191
173
  ) : (
192
- <div className="branch-grid">
174
+ <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
193
175
  {filteredBranches.map((branch) => (
194
- <article key={branch.name} className="branch-card">
195
- <div className="branch-card__header">
196
- <div>
197
- <p className="branch-card__eyebrow">
198
- {BRANCH_TYPE_LABEL[branch.type]}ブランチ
199
- </p>
200
- <h2>{branch.name}</h2>
201
- </div>
202
- <div className="badge-group">
203
- <span
204
- className={`status-badge status-badge--${branch.type}`}
205
- >
206
- {BRANCH_TYPE_LABEL[branch.type]}
207
- </span>
208
- <span
209
- className={`status-badge status-badge--${MERGE_STATUS_TONE[branch.mergeStatus]}`}
210
- >
211
- {MERGE_STATUS_LABEL[branch.mergeStatus]}
212
- </span>
213
- <span
214
- className={`status-badge ${
215
- branch.worktreePath
216
- ? "status-badge--success"
217
- : "status-badge--muted"
218
- }`}
219
- >
220
- {branch.worktreePath ? "Worktreeあり" : "Worktree未作成"}
221
- </span>
222
- </div>
223
- </div>
224
-
225
- <p className="branch-card__commit">
226
- {branch.commitMessage ?? "コミットメッセージがありません"}
227
- </p>
228
-
229
- <dl className="metadata-grid metadata-grid--compact">
230
- <div>
231
- <dt>最新コミット</dt>
232
- <dd>{branch.commitHash.slice(0, 7)}</dd>
233
- </div>
234
- <div>
235
- <dt>Author</dt>
236
- <dd>{branch.author ?? "N/A"}</dd>
237
- </div>
238
- <div>
239
- <dt>Worktree</dt>
240
- <dd>{branch.worktreePath ?? "未作成"}</dd>
241
- </div>
242
- </dl>
243
-
244
- {branch.divergence && (
245
- <div className="pill-group">
246
- <span className="pill">
247
- Ahead {branch.divergence.ahead}
248
- </span>
249
- <span className="pill">
250
- Behind {branch.divergence.behind}
251
- </span>
252
- <span
253
- className={`pill ${
254
- branch.divergence.upToDate
255
- ? "pill--success"
256
- : "pill--warning"
257
- }`}
258
- >
259
- {branch.divergence.upToDate ? "最新" : "更新あり"}
260
- </span>
261
- </div>
262
- )}
263
-
264
- <div className="branch-card__actions">
265
- <Link
266
- className="button button--ghost"
267
- to={`/${encodeURIComponent(branch.name)}`}
268
- >
269
- 詳細を見る
270
- </Link>
271
- <span
272
- className={`info-pill ${
273
- branch.worktreePath
274
- ? "info-pill--success"
275
- : "info-pill--warning"
276
- }`}
277
- >
278
- {branch.worktreePath ?? "Worktree未作成"}
279
- </span>
280
- </div>
281
- </article>
176
+ <BranchCardItem key={branch.name} branch={branch} />
282
177
  ))}
283
178
  </div>
284
179
  )}
@@ -286,3 +181,62 @@ export function BranchListPage() {
286
181
  </div>
287
182
  );
288
183
  }
184
+
185
+ // Extracted Branch Card component
186
+ function BranchCardItem({ branch }: { branch: Branch }) {
187
+ return (
188
+ <Card className="flex flex-col transition-colors hover:border-muted-foreground/50">
189
+ <CardHeader className="pb-3">
190
+ <div className="flex items-start justify-between gap-2">
191
+ <div className="min-w-0 flex-1">
192
+ <p className="text-xs font-medium uppercase tracking-wider text-muted-foreground">
193
+ {branch.type === "local" ? "Local" : "Remote"} Branch
194
+ </p>
195
+ <h3 className="mt-1 truncate font-semibold" title={branch.name}>
196
+ {branch.name}
197
+ </h3>
198
+ </div>
199
+ <div className="flex flex-wrap justify-end gap-1">
200
+ <Badge variant={branch.type === "local" ? "local" : "remote"}>
201
+ {branch.type === "local" ? "L" : "R"}
202
+ </Badge>
203
+ {branch.worktreePath && <Badge variant="success">WT</Badge>}
204
+ </div>
205
+ </div>
206
+ </CardHeader>
207
+
208
+ <CardContent className="flex-1 pb-3">
209
+ <p className="line-clamp-2 text-sm text-muted-foreground">
210
+ {branch.commitMessage ?? "No commit message"}
211
+ </p>
212
+
213
+ {branch.divergence && (
214
+ <div className="mt-3 flex flex-wrap gap-1.5">
215
+ {branch.divergence.ahead > 0 && (
216
+ <Badge variant="outline" className="text-xs">
217
+ ↑ {branch.divergence.ahead}
218
+ </Badge>
219
+ )}
220
+ {branch.divergence.behind > 0 && (
221
+ <Badge variant="outline" className="text-xs">
222
+ ↓ {branch.divergence.behind}
223
+ </Badge>
224
+ )}
225
+ <Badge
226
+ variant={branch.divergence.upToDate ? "success" : "warning"}
227
+ className="text-xs"
228
+ >
229
+ {branch.divergence.upToDate ? "Up to date" : "Needs sync"}
230
+ </Badge>
231
+ </div>
232
+ )}
233
+ </CardContent>
234
+
235
+ <CardFooter className="pt-0">
236
+ <Button variant="ghost" size="sm" asChild className="w-full">
237
+ <Link to={`/${encodeURIComponent(branch.name)}`}>View Details →</Link>
238
+ </Button>
239
+ </CardFooter>
240
+ </Card>
241
+ );
242
+ }