@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
@@ -0,0 +1,117 @@
1
+ import React from "react";
2
+ import { Link } from "react-router-dom";
3
+ import {
4
+ Card,
5
+ CardHeader,
6
+ CardContent,
7
+ CardFooter,
8
+ } from "@/components/ui/card";
9
+ import { Badge } from "@/components/ui/badge";
10
+ import { cn } from "@/lib/utils";
11
+
12
+ interface BranchCardProps {
13
+ name: string;
14
+ type: "local" | "remote" | "both";
15
+ isProtected?: boolean;
16
+ hasWorktree?: boolean;
17
+ lastCommit?: string;
18
+ lastCommitDate?: string;
19
+ ahead?: number;
20
+ behind?: number;
21
+ merged?: boolean;
22
+ href?: string;
23
+ className?: string;
24
+ }
25
+
26
+ export function BranchCard({
27
+ name,
28
+ type,
29
+ isProtected,
30
+ hasWorktree,
31
+ lastCommit,
32
+ lastCommitDate,
33
+ ahead,
34
+ behind,
35
+ merged,
36
+ href,
37
+ className,
38
+ }: BranchCardProps) {
39
+ const content = (
40
+ <Card
41
+ className={cn(
42
+ "transition-colors hover:border-muted-foreground/30",
43
+ className,
44
+ )}
45
+ >
46
+ <CardHeader className="pb-2">
47
+ <div className="flex items-start justify-between gap-2">
48
+ <div className="min-w-0 flex-1">
49
+ <p className="text-xs font-medium uppercase tracking-wider text-muted-foreground">
50
+ Branch
51
+ </p>
52
+ <h3 className="mt-1 truncate text-sm font-semibold">{name}</h3>
53
+ </div>
54
+ <div className="flex flex-wrap gap-1">
55
+ {type === "local" && <Badge variant="local">Local</Badge>}
56
+ {type === "remote" && <Badge variant="remote">Remote</Badge>}
57
+ {type === "both" && (
58
+ <>
59
+ <Badge variant="local">L</Badge>
60
+ <Badge variant="remote">R</Badge>
61
+ </>
62
+ )}
63
+ </div>
64
+ </div>
65
+ </CardHeader>
66
+ <CardContent className="py-2">
67
+ {lastCommit && (
68
+ <p className="line-clamp-2 text-xs text-muted-foreground">
69
+ {lastCommit}
70
+ </p>
71
+ )}
72
+ </CardContent>
73
+ <CardFooter className="flex flex-wrap gap-2 pt-2">
74
+ {isProtected && (
75
+ <Badge variant="warning" className="text-xs">
76
+ Protected
77
+ </Badge>
78
+ )}
79
+ {hasWorktree && (
80
+ <Badge variant="success" className="text-xs">
81
+ Worktree
82
+ </Badge>
83
+ )}
84
+ {merged && (
85
+ <Badge variant="secondary" className="text-xs">
86
+ Merged
87
+ </Badge>
88
+ )}
89
+ {ahead !== undefined && ahead > 0 && (
90
+ <Badge variant="outline" className="text-xs">
91
+ ↑{ahead}
92
+ </Badge>
93
+ )}
94
+ {behind !== undefined && behind > 0 && (
95
+ <Badge variant="outline" className="text-xs">
96
+ ↓{behind}
97
+ </Badge>
98
+ )}
99
+ {lastCommitDate && (
100
+ <span className="ml-auto text-xs text-muted-foreground">
101
+ {lastCommitDate}
102
+ </span>
103
+ )}
104
+ </CardFooter>
105
+ </Card>
106
+ );
107
+
108
+ if (href) {
109
+ return (
110
+ <Link to={href} className="block">
111
+ {content}
112
+ </Link>
113
+ );
114
+ }
115
+
116
+ return content;
117
+ }
@@ -0,0 +1,22 @@
1
+ import React from "react";
2
+ import { Card } from "@/components/ui/card";
3
+ import { cn } from "@/lib/utils";
4
+
5
+ interface MetricCardProps {
6
+ label: string;
7
+ value: string | number;
8
+ hint?: string;
9
+ className?: string;
10
+ }
11
+
12
+ export function MetricCard({ label, value, hint, className }: MetricCardProps) {
13
+ return (
14
+ <Card className={cn("p-5", className)}>
15
+ <p className="text-xs font-medium uppercase tracking-wider text-muted-foreground">
16
+ {label}
17
+ </p>
18
+ <p className="mt-1 text-3xl font-semibold tabular-nums">{value}</p>
19
+ {hint && <p className="mt-1 text-xs text-muted-foreground">{hint}</p>}
20
+ </Card>
21
+ );
22
+ }
@@ -0,0 +1,44 @@
1
+ import React from "react";
2
+ import { cn } from "@/lib/utils";
3
+
4
+ interface PageHeaderProps {
5
+ eyebrow?: string;
6
+ title: string;
7
+ subtitle?: string;
8
+ actions?: React.ReactNode;
9
+ children?: React.ReactNode;
10
+ className?: string;
11
+ }
12
+
13
+ export function PageHeader({
14
+ eyebrow,
15
+ title,
16
+ subtitle,
17
+ actions,
18
+ children,
19
+ className,
20
+ }: PageHeaderProps) {
21
+ return (
22
+ <header
23
+ className={cn("border-b border-border bg-card/50 px-6 py-8", className)}
24
+ >
25
+ <div className="mx-auto max-w-7xl">
26
+ {eyebrow && (
27
+ <p className="mb-2 text-xs font-medium uppercase tracking-widest text-muted-foreground">
28
+ {eyebrow}
29
+ </p>
30
+ )}
31
+ <div className="flex flex-wrap items-start justify-between gap-4">
32
+ <div>
33
+ <h1 className="text-2xl font-bold tracking-tight">{title}</h1>
34
+ {subtitle && (
35
+ <p className="mt-1 text-sm text-muted-foreground">{subtitle}</p>
36
+ )}
37
+ {children}
38
+ </div>
39
+ {actions && <div className="flex gap-2">{actions}</div>}
40
+ </div>
41
+ </div>
42
+ </header>
43
+ );
44
+ }
@@ -0,0 +1,40 @@
1
+ import React from "react";
2
+ import { Search } from "lucide-react";
3
+ import { Input } from "@/components/ui/input";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ interface SearchInputProps {
7
+ value: string;
8
+ onChange: (value: string) => void;
9
+ placeholder?: string;
10
+ className?: string;
11
+ count?: { filtered: number; total: number };
12
+ }
13
+
14
+ export function SearchInput({
15
+ value,
16
+ onChange,
17
+ placeholder = "Search...",
18
+ className,
19
+ count,
20
+ }: SearchInputProps) {
21
+ return (
22
+ <div className={cn("flex items-center gap-3", className)}>
23
+ <div className="relative flex-1">
24
+ <Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
25
+ <Input
26
+ type="text"
27
+ value={value}
28
+ onChange={(e) => onChange(e.target.value)}
29
+ placeholder={placeholder}
30
+ className="pl-9"
31
+ />
32
+ </div>
33
+ {count && (
34
+ <span className="text-sm text-muted-foreground">
35
+ {count.filtered} / {count.total}
36
+ </span>
37
+ )}
38
+ </div>
39
+ );
40
+ }
@@ -0,0 +1,37 @@
1
+ import React from "react";
2
+ import { Badge } from "@/components/ui/badge";
3
+ import { cn } from "@/lib/utils";
4
+
5
+ type StatusType =
6
+ | "local"
7
+ | "remote"
8
+ | "success"
9
+ | "warning"
10
+ | "muted"
11
+ | "default";
12
+
13
+ interface StatusBadgeProps {
14
+ status: StatusType;
15
+ children: React.ReactNode;
16
+ className?: string;
17
+ }
18
+
19
+ export function StatusBadge({ status, children, className }: StatusBadgeProps) {
20
+ const variantMap: Record<
21
+ StatusType,
22
+ "local" | "remote" | "success" | "warning" | "secondary" | "default"
23
+ > = {
24
+ local: "local",
25
+ remote: "remote",
26
+ success: "success",
27
+ warning: "warning",
28
+ muted: "secondary",
29
+ default: "default",
30
+ };
31
+
32
+ return (
33
+ <Badge variant={variantMap[status]} className={cn(className)}>
34
+ {children}
35
+ </Badge>
36
+ );
37
+ }
@@ -0,0 +1,5 @@
1
+ export { PageHeader } from "./PageHeader";
2
+ export { StatusBadge } from "./StatusBadge";
3
+ export { MetricCard } from "./MetricCard";
4
+ export { BranchCard } from "./BranchCard";
5
+ export { SearchInput } from "./SearchInput";
@@ -0,0 +1,63 @@
1
+ import * as React from "react";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import { cn } from "@/lib/utils";
4
+
5
+ const alertVariants = cva(
6
+ "relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
7
+ {
8
+ variants: {
9
+ variant: {
10
+ default: "bg-background text-foreground",
11
+ destructive:
12
+ "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
13
+ success:
14
+ "border-green-500/50 bg-green-500/10 text-green-400 [&>svg]:text-green-400",
15
+ warning:
16
+ "border-yellow-500/50 bg-yellow-500/10 text-yellow-400 [&>svg]:text-yellow-400",
17
+ info: "border-blue-500/50 bg-blue-500/10 text-blue-400 [&>svg]:text-blue-400",
18
+ },
19
+ },
20
+ defaultVariants: {
21
+ variant: "default",
22
+ },
23
+ },
24
+ );
25
+
26
+ const Alert = React.forwardRef<
27
+ HTMLDivElement,
28
+ React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
29
+ >(({ className, variant, ...props }, ref) => (
30
+ <div
31
+ ref={ref}
32
+ role="alert"
33
+ className={cn(alertVariants({ variant }), className)}
34
+ {...props}
35
+ />
36
+ ));
37
+ Alert.displayName = "Alert";
38
+
39
+ const AlertTitle = React.forwardRef<
40
+ HTMLParagraphElement,
41
+ React.HTMLAttributes<HTMLHeadingElement>
42
+ >(({ className, ...props }, ref) => (
43
+ <h5
44
+ ref={ref}
45
+ className={cn("mb-1 font-medium leading-none tracking-tight", className)}
46
+ {...props}
47
+ />
48
+ ));
49
+ AlertTitle.displayName = "AlertTitle";
50
+
51
+ const AlertDescription = React.forwardRef<
52
+ HTMLParagraphElement,
53
+ React.HTMLAttributes<HTMLParagraphElement>
54
+ >(({ className, ...props }, ref) => (
55
+ <div
56
+ ref={ref}
57
+ className={cn("text-sm [&_p]:leading-relaxed", className)}
58
+ {...props}
59
+ />
60
+ ));
61
+ AlertDescription.displayName = "AlertDescription";
62
+
63
+ export { Alert, AlertTitle, AlertDescription };
@@ -0,0 +1,44 @@
1
+ import * as React from "react";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import { cn } from "@/lib/utils";
4
+
5
+ const badgeVariants = cva(
6
+ "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
7
+ {
8
+ variants: {
9
+ variant: {
10
+ default:
11
+ "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
12
+ secondary:
13
+ "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
14
+ destructive:
15
+ "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
16
+ outline: "text-foreground",
17
+ success:
18
+ "border-transparent bg-green-500/15 text-green-400 border-green-500/30",
19
+ warning:
20
+ "border-transparent bg-yellow-500/15 text-yellow-400 border-yellow-500/30",
21
+ local:
22
+ "border-transparent bg-purple-500/15 text-purple-400 border-purple-500/30",
23
+ remote:
24
+ "border-transparent bg-blue-500/15 text-blue-400 border-blue-500/30",
25
+ },
26
+ },
27
+ defaultVariants: {
28
+ variant: "default",
29
+ },
30
+ },
31
+ );
32
+
33
+ export interface BadgeProps
34
+ extends
35
+ React.HTMLAttributes<HTMLDivElement>,
36
+ VariantProps<typeof badgeVariants> {}
37
+
38
+ function Badge({ className, variant, ...props }: BadgeProps) {
39
+ return (
40
+ <div className={cn(badgeVariants({ variant }), className)} {...props} />
41
+ );
42
+ }
43
+
44
+ export { Badge, badgeVariants };
@@ -0,0 +1,57 @@
1
+ import * as React from "react";
2
+ import { Slot } from "@radix-ui/react-slot";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ const buttonVariants = cva(
7
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default:
12
+ "bg-primary text-primary-foreground shadow hover:bg-primary/90",
13
+ destructive:
14
+ "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
15
+ outline:
16
+ "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
17
+ secondary:
18
+ "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
19
+ ghost: "hover:bg-accent hover:text-accent-foreground",
20
+ link: "text-primary underline-offset-4 hover:underline",
21
+ },
22
+ size: {
23
+ default: "h-9 px-4 py-2",
24
+ sm: "h-8 rounded-md px-3 text-xs",
25
+ lg: "h-10 rounded-md px-8",
26
+ icon: "h-9 w-9",
27
+ },
28
+ },
29
+ defaultVariants: {
30
+ variant: "default",
31
+ size: "default",
32
+ },
33
+ },
34
+ );
35
+
36
+ export interface ButtonProps
37
+ extends
38
+ React.ButtonHTMLAttributes<HTMLButtonElement>,
39
+ VariantProps<typeof buttonVariants> {
40
+ asChild?: boolean;
41
+ }
42
+
43
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
44
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
45
+ const Comp = asChild ? Slot : "button";
46
+ return (
47
+ <Comp
48
+ className={cn(buttonVariants({ variant, size, className }))}
49
+ ref={ref}
50
+ {...props}
51
+ />
52
+ );
53
+ },
54
+ );
55
+ Button.displayName = "Button";
56
+
57
+ export { Button, buttonVariants };
@@ -0,0 +1,82 @@
1
+ import * as React from "react";
2
+ import { cn } from "@/lib/utils";
3
+
4
+ const Card = React.forwardRef<
5
+ HTMLDivElement,
6
+ React.HTMLAttributes<HTMLDivElement>
7
+ >(({ className, ...props }, ref) => (
8
+ <div
9
+ ref={ref}
10
+ className={cn(
11
+ "rounded-lg border border-border bg-card text-card-foreground shadow",
12
+ className,
13
+ )}
14
+ {...props}
15
+ />
16
+ ));
17
+ Card.displayName = "Card";
18
+
19
+ const CardHeader = React.forwardRef<
20
+ HTMLDivElement,
21
+ React.HTMLAttributes<HTMLDivElement>
22
+ >(({ className, ...props }, ref) => (
23
+ <div
24
+ ref={ref}
25
+ className={cn("flex flex-col space-y-1.5 p-6", className)}
26
+ {...props}
27
+ />
28
+ ));
29
+ CardHeader.displayName = "CardHeader";
30
+
31
+ const CardTitle = React.forwardRef<
32
+ HTMLDivElement,
33
+ React.HTMLAttributes<HTMLDivElement>
34
+ >(({ className, ...props }, ref) => (
35
+ <div
36
+ ref={ref}
37
+ className={cn("font-semibold leading-none tracking-tight", className)}
38
+ {...props}
39
+ />
40
+ ));
41
+ CardTitle.displayName = "CardTitle";
42
+
43
+ const CardDescription = React.forwardRef<
44
+ HTMLDivElement,
45
+ React.HTMLAttributes<HTMLDivElement>
46
+ >(({ className, ...props }, ref) => (
47
+ <div
48
+ ref={ref}
49
+ className={cn("text-sm text-muted-foreground", className)}
50
+ {...props}
51
+ />
52
+ ));
53
+ CardDescription.displayName = "CardDescription";
54
+
55
+ const CardContent = React.forwardRef<
56
+ HTMLDivElement,
57
+ React.HTMLAttributes<HTMLDivElement>
58
+ >(({ className, ...props }, ref) => (
59
+ <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
60
+ ));
61
+ CardContent.displayName = "CardContent";
62
+
63
+ const CardFooter = React.forwardRef<
64
+ HTMLDivElement,
65
+ React.HTMLAttributes<HTMLDivElement>
66
+ >(({ className, ...props }, ref) => (
67
+ <div
68
+ ref={ref}
69
+ className={cn("flex items-center p-6 pt-0", className)}
70
+ {...props}
71
+ />
72
+ ));
73
+ CardFooter.displayName = "CardFooter";
74
+
75
+ export {
76
+ Card,
77
+ CardHeader,
78
+ CardFooter,
79
+ CardTitle,
80
+ CardDescription,
81
+ CardContent,
82
+ };
@@ -0,0 +1,32 @@
1
+ export { Button, buttonVariants } from "./button";
2
+ export {
3
+ Card,
4
+ CardHeader,
5
+ CardFooter,
6
+ CardTitle,
7
+ CardDescription,
8
+ CardContent,
9
+ } from "./card";
10
+ export { Badge, badgeVariants } from "./badge";
11
+ export { Input } from "./input";
12
+ export {
13
+ Select,
14
+ SelectGroup,
15
+ SelectValue,
16
+ SelectTrigger,
17
+ SelectContent,
18
+ SelectLabel,
19
+ SelectItem,
20
+ SelectSeparator,
21
+ } from "./select";
22
+ export {
23
+ Table,
24
+ TableHeader,
25
+ TableBody,
26
+ TableFooter,
27
+ TableHead,
28
+ TableRow,
29
+ TableCell,
30
+ TableCaption,
31
+ } from "./table";
32
+ export { Alert, AlertTitle, AlertDescription } from "./alert";
@@ -0,0 +1,21 @@
1
+ import * as React from "react";
2
+ import { cn } from "@/lib/utils";
3
+
4
+ const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
5
+ ({ className, type, ...props }, ref) => {
6
+ return (
7
+ <input
8
+ type={type}
9
+ className={cn(
10
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
11
+ className,
12
+ )}
13
+ ref={ref}
14
+ {...props}
15
+ />
16
+ );
17
+ },
18
+ );
19
+ Input.displayName = "Input";
20
+
21
+ export { Input };