@atercates/claude-deck 0.2.1

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 (293) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +123 -0
  3. package/app/api/claude/hidden/route.ts +66 -0
  4. package/app/api/claude/projects/[name]/sessions/route.ts +71 -0
  5. package/app/api/claude/projects/route.ts +44 -0
  6. package/app/api/code-search/available/route.ts +12 -0
  7. package/app/api/code-search/route.ts +47 -0
  8. package/app/api/dev-servers/[id]/logs/route.ts +23 -0
  9. package/app/api/dev-servers/[id]/restart/route.ts +20 -0
  10. package/app/api/dev-servers/[id]/route.ts +51 -0
  11. package/app/api/dev-servers/[id]/stop/route.ts +20 -0
  12. package/app/api/dev-servers/detect/route.ts +39 -0
  13. package/app/api/dev-servers/route.ts +48 -0
  14. package/app/api/exec/route.ts +60 -0
  15. package/app/api/files/content/route.ts +76 -0
  16. package/app/api/files/route.ts +37 -0
  17. package/app/api/files/upload-temp/route.ts +41 -0
  18. package/app/api/git/check/route.ts +54 -0
  19. package/app/api/git/clone/route.ts +99 -0
  20. package/app/api/git/commit/route.ts +75 -0
  21. package/app/api/git/discard/route.ts +38 -0
  22. package/app/api/git/file-content/route.ts +64 -0
  23. package/app/api/git/history/[hash]/diff/route.ts +38 -0
  24. package/app/api/git/history/[hash]/route.ts +34 -0
  25. package/app/api/git/history/route.ts +27 -0
  26. package/app/api/git/multi-status/route.ts +46 -0
  27. package/app/api/git/pr/route.ts +164 -0
  28. package/app/api/git/push/route.ts +64 -0
  29. package/app/api/git/stage/route.ts +40 -0
  30. package/app/api/git/status/route.ts +51 -0
  31. package/app/api/git/unstage/route.ts +46 -0
  32. package/app/api/groups/[...path]/route.ts +136 -0
  33. package/app/api/groups/route.ts +93 -0
  34. package/app/api/orchestrate/spawn/route.ts +45 -0
  35. package/app/api/orchestrate/workers/[id]/route.ts +89 -0
  36. package/app/api/orchestrate/workers/route.ts +31 -0
  37. package/app/api/projects/[id]/detect/route.ts +27 -0
  38. package/app/api/projects/[id]/dev-servers/[dsId]/route.ts +66 -0
  39. package/app/api/projects/[id]/dev-servers/route.ts +51 -0
  40. package/app/api/projects/[id]/repositories/[repoId]/route.ts +67 -0
  41. package/app/api/projects/[id]/repositories/route.ts +74 -0
  42. package/app/api/projects/[id]/route.ts +108 -0
  43. package/app/api/projects/detect/route.ts +33 -0
  44. package/app/api/projects/route.ts +59 -0
  45. package/app/api/sessions/[id]/claude-session/route.ts +42 -0
  46. package/app/api/sessions/[id]/fork/route.ts +74 -0
  47. package/app/api/sessions/[id]/mcp-config/route.ts +34 -0
  48. package/app/api/sessions/[id]/messages/route.ts +60 -0
  49. package/app/api/sessions/[id]/pr/route.ts +188 -0
  50. package/app/api/sessions/[id]/preview/route.ts +42 -0
  51. package/app/api/sessions/[id]/route.ts +229 -0
  52. package/app/api/sessions/[id]/send-keys/route.ts +119 -0
  53. package/app/api/sessions/[id]/summarize/route.ts +331 -0
  54. package/app/api/sessions/init-script/route.ts +84 -0
  55. package/app/api/sessions/route.ts +209 -0
  56. package/app/api/sessions/status/route.ts +237 -0
  57. package/app/api/system/route.ts +9 -0
  58. package/app/api/tmux/kill-all/route.ts +57 -0
  59. package/app/api/tmux/rename/route.ts +30 -0
  60. package/app/globals.css +174 -0
  61. package/app/icon.svg +11 -0
  62. package/app/layout.tsx +122 -0
  63. package/app/page.tsx +629 -0
  64. package/components/ChatMessage.tsx +65 -0
  65. package/components/ChatView.tsx +276 -0
  66. package/components/ClaudeProjects/ClaudeProjectCard.tsx +195 -0
  67. package/components/ClaudeProjects/ClaudeProjectsSection.tsx +89 -0
  68. package/components/ClaudeProjects/ClaudeSessionCard.tsx +100 -0
  69. package/components/ClaudeProjects/index.ts +1 -0
  70. package/components/CodeSearch/CodeSearchResults.tsx +177 -0
  71. package/components/ConductorPanel.tsx +256 -0
  72. package/components/DevServers/DevServerCard.tsx +311 -0
  73. package/components/DevServers/DevServersSection.tsx +91 -0
  74. package/components/DevServers/ServerLogsModal.tsx +151 -0
  75. package/components/DevServers/StartServerDialog.tsx +359 -0
  76. package/components/DevServers/index.ts +4 -0
  77. package/components/DiffViewer/DiffModal.tsx +151 -0
  78. package/components/DiffViewer/UnifiedDiff.tsx +185 -0
  79. package/components/DiffViewer/index.tsx +2 -0
  80. package/components/DirectoryPicker.tsx +355 -0
  81. package/components/FileExplorer/FileEditor.tsx +276 -0
  82. package/components/FileExplorer/FileTabs.tsx +118 -0
  83. package/components/FileExplorer/FileTree.tsx +214 -0
  84. package/components/FileExplorer/HtmlRenderer.tsx +16 -0
  85. package/components/FileExplorer/MarkdownRenderer.tsx +18 -0
  86. package/components/FileExplorer/index.tsx +520 -0
  87. package/components/FilePicker.tsx +339 -0
  88. package/components/FolderPicker.tsx +201 -0
  89. package/components/GitDrawer/FileEditDialog.tsx +400 -0
  90. package/components/GitDrawer/index.tsx +464 -0
  91. package/components/GitPanel/CommitForm.tsx +205 -0
  92. package/components/GitPanel/CommitHistory.tsx +174 -0
  93. package/components/GitPanel/CommitItem.tsx +196 -0
  94. package/components/GitPanel/FileChanges.tsx +414 -0
  95. package/components/GitPanel/GitPanelTabs.tsx +39 -0
  96. package/components/GitPanel/index.tsx +817 -0
  97. package/components/MessageInput.tsx +82 -0
  98. package/components/NewClaudeSessionDialog.tsx +166 -0
  99. package/components/NewSessionDialog/AdvancedSettings.tsx +78 -0
  100. package/components/NewSessionDialog/AgentSelector.tsx +37 -0
  101. package/components/NewSessionDialog/CreatingOverlay.tsx +94 -0
  102. package/components/NewSessionDialog/NewSessionDialog.types.ts +136 -0
  103. package/components/NewSessionDialog/ProjectSelector.tsx +146 -0
  104. package/components/NewSessionDialog/WorkingDirectoryInput.tsx +55 -0
  105. package/components/NewSessionDialog/WorktreeSection.tsx +92 -0
  106. package/components/NewSessionDialog/hooks/useNewSessionForm.ts +370 -0
  107. package/components/NewSessionDialog/index.tsx +106 -0
  108. package/components/NotificationSettings.tsx +127 -0
  109. package/components/PRCreationModal.tsx +272 -0
  110. package/components/Pane/DesktopTabBar.tsx +353 -0
  111. package/components/Pane/MobileTabBar.tsx +210 -0
  112. package/components/Pane/OpenInVSCode.tsx +69 -0
  113. package/components/Pane/PaneSkeletons.tsx +57 -0
  114. package/components/Pane/index.tsx +558 -0
  115. package/components/PaneLayout.tsx +60 -0
  116. package/components/Projects/DevServersSection.tsx +140 -0
  117. package/components/Projects/DirectoryField.tsx +92 -0
  118. package/components/Projects/NewProjectDialog.tsx +188 -0
  119. package/components/Projects/NewProjectDialog.types.ts +46 -0
  120. package/components/Projects/ProjectCard.tsx +276 -0
  121. package/components/Projects/ProjectSettingsDialog.tsx +811 -0
  122. package/components/Projects/hooks/useNewProjectForm.ts +249 -0
  123. package/components/Projects/index.ts +3 -0
  124. package/components/Providers.tsx +49 -0
  125. package/components/QuickSwitcher.tsx +306 -0
  126. package/components/SessionList/KillAllConfirm.tsx +46 -0
  127. package/components/SessionList/SelectionToolbar.tsx +164 -0
  128. package/components/SessionList/SessionList.types.ts +37 -0
  129. package/components/SessionList/SessionListHeader.tsx +71 -0
  130. package/components/SessionList/hooks/useSessionListMutations.ts +269 -0
  131. package/components/SessionList/index.tsx +189 -0
  132. package/components/ShellDrawer/index.tsx +106 -0
  133. package/components/SidebarFooter.tsx +55 -0
  134. package/components/Terminal/KeybarToggleButton.tsx +45 -0
  135. package/components/Terminal/ScrollToBottomButton.tsx +32 -0
  136. package/components/Terminal/SearchBar.tsx +71 -0
  137. package/components/Terminal/TerminalToolbar.tsx +551 -0
  138. package/components/Terminal/VirtualKeyboard.tsx +711 -0
  139. package/components/Terminal/constants.ts +20 -0
  140. package/components/Terminal/hooks/index.ts +5 -0
  141. package/components/Terminal/hooks/resize-handlers.ts +140 -0
  142. package/components/Terminal/hooks/terminal-init.ts +151 -0
  143. package/components/Terminal/hooks/touch-scroll.ts +155 -0
  144. package/components/Terminal/hooks/useTerminalConnection.ts +282 -0
  145. package/components/Terminal/hooks/useTerminalConnection.types.ts +39 -0
  146. package/components/Terminal/hooks/useTerminalSearch.ts +103 -0
  147. package/components/Terminal/hooks/websocket-connection.ts +274 -0
  148. package/components/Terminal/index.tsx +320 -0
  149. package/components/ThemeToggle.tsx +168 -0
  150. package/components/TmuxSessions.tsx +132 -0
  151. package/components/ToolCallDisplay.tsx +71 -0
  152. package/components/WorkerCard.tsx +245 -0
  153. package/components/a/ABadge.tsx +115 -0
  154. package/components/a/AButton.tsx +163 -0
  155. package/components/a/ADialog.tsx +93 -0
  156. package/components/a/ADropdownMenu.tsx +279 -0
  157. package/components/a/AIconButton.tsx +190 -0
  158. package/components/a/ASheet.tsx +150 -0
  159. package/components/a/ATooltip.tsx +77 -0
  160. package/components/a/index.ts +64 -0
  161. package/components/mobile/SwipeSidebar.tsx +122 -0
  162. package/components/ui/badge.tsx +41 -0
  163. package/components/ui/button.tsx +60 -0
  164. package/components/ui/context-menu.tsx +197 -0
  165. package/components/ui/dialog.tsx +143 -0
  166. package/components/ui/dropdown-menu.tsx +257 -0
  167. package/components/ui/input.tsx +21 -0
  168. package/components/ui/scroll-area.tsx +52 -0
  169. package/components/ui/select.tsx +159 -0
  170. package/components/ui/skeleton.tsx +111 -0
  171. package/components/ui/switch.tsx +31 -0
  172. package/components/ui/textarea.tsx +21 -0
  173. package/components/ui/tooltip.tsx +32 -0
  174. package/components/views/DesktopView.tsx +244 -0
  175. package/components/views/MobileView.tsx +110 -0
  176. package/components/views/types.ts +75 -0
  177. package/contexts/PaneContext.tsx +336 -0
  178. package/data/claude/index.ts +9 -0
  179. package/data/claude/keys.ts +6 -0
  180. package/data/claude/queries.ts +120 -0
  181. package/data/claude/useClaudeUpdates.ts +37 -0
  182. package/data/code-search/index.ts +2 -0
  183. package/data/code-search/keys.ts +7 -0
  184. package/data/code-search/queries.ts +61 -0
  185. package/data/dev-servers/index.ts +8 -0
  186. package/data/dev-servers/keys.ts +4 -0
  187. package/data/dev-servers/queries.ts +104 -0
  188. package/data/files/index.ts +3 -0
  189. package/data/files/keys.ts +4 -0
  190. package/data/files/queries.ts +25 -0
  191. package/data/git/keys.ts +15 -0
  192. package/data/git/queries.ts +395 -0
  193. package/data/groups/index.ts +1 -0
  194. package/data/groups/mutations.ts +95 -0
  195. package/data/projects/index.ts +10 -0
  196. package/data/projects/keys.ts +4 -0
  197. package/data/projects/queries.ts +193 -0
  198. package/data/repositories/index.ts +7 -0
  199. package/data/repositories/keys.ts +5 -0
  200. package/data/repositories/queries.ts +122 -0
  201. package/data/sessions/index.ts +12 -0
  202. package/data/sessions/keys.ts +8 -0
  203. package/data/sessions/queries.ts +218 -0
  204. package/data/statuses/index.ts +1 -0
  205. package/data/statuses/queries.ts +69 -0
  206. package/hooks/useCopyToClipboard.ts +48 -0
  207. package/hooks/useDevServersManager.ts +73 -0
  208. package/hooks/useDirectoryBrowser.ts +90 -0
  209. package/hooks/useDrawerAnimation.ts +27 -0
  210. package/hooks/useFileDrop.ts +87 -0
  211. package/hooks/useFileEditor.ts +184 -0
  212. package/hooks/useGroups.ts +37 -0
  213. package/hooks/useHomePath.ts +34 -0
  214. package/hooks/useKeyRepeat.ts +55 -0
  215. package/hooks/useKeybarVisibility.ts +42 -0
  216. package/hooks/useNotifications.ts +257 -0
  217. package/hooks/useProjects.ts +53 -0
  218. package/hooks/useSessionStatuses.ts +30 -0
  219. package/hooks/useSessions.ts +86 -0
  220. package/hooks/useSpeechRecognition.ts +124 -0
  221. package/hooks/useViewport.ts +32 -0
  222. package/hooks/useViewportHeight.ts +50 -0
  223. package/lib/async-operations.ts +35 -0
  224. package/lib/banner.ts +81 -0
  225. package/lib/claude/jsonl-cache.ts +86 -0
  226. package/lib/claude/jsonl-reader.ts +271 -0
  227. package/lib/claude/process-manager.ts +278 -0
  228. package/lib/claude/stream-parser.ts +173 -0
  229. package/lib/claude/types.ts +154 -0
  230. package/lib/claude/watcher.ts +71 -0
  231. package/lib/client/session-registry.ts +111 -0
  232. package/lib/code-search.ts +121 -0
  233. package/lib/db/index.ts +48 -0
  234. package/lib/db/migrations.ts +45 -0
  235. package/lib/db/queries.ts +460 -0
  236. package/lib/db/schema.ts +114 -0
  237. package/lib/db/types.ts +92 -0
  238. package/lib/db.ts +2 -0
  239. package/lib/dev-servers.ts +509 -0
  240. package/lib/diff-parser.ts +221 -0
  241. package/lib/env-setup.ts +285 -0
  242. package/lib/file-upload.ts +34 -0
  243. package/lib/file-utils.ts +50 -0
  244. package/lib/files.ts +207 -0
  245. package/lib/git-history.ts +294 -0
  246. package/lib/git-status.ts +391 -0
  247. package/lib/git.ts +257 -0
  248. package/lib/mcp-config.ts +81 -0
  249. package/lib/multi-repo-git.ts +179 -0
  250. package/lib/notifications.ts +219 -0
  251. package/lib/orchestration.ts +448 -0
  252. package/lib/panes.ts +232 -0
  253. package/lib/ports.ts +97 -0
  254. package/lib/pr-generation.ts +307 -0
  255. package/lib/pr.ts +234 -0
  256. package/lib/projects.ts +578 -0
  257. package/lib/providers/registry.ts +70 -0
  258. package/lib/providers.ts +121 -0
  259. package/lib/query-client.ts +14 -0
  260. package/lib/rangeSelectionUtils.ts +65 -0
  261. package/lib/status-detector.ts +375 -0
  262. package/lib/terminal-themes.ts +265 -0
  263. package/lib/theme-config.ts +327 -0
  264. package/lib/utils.ts +6 -0
  265. package/lib/worktrees.ts +262 -0
  266. package/mcp/orchestration-server.ts +438 -0
  267. package/package.json +139 -0
  268. package/postcss.config.mjs +7 -0
  269. package/public/icon.svg +10 -0
  270. package/public/icons/icon-128x128.png +0 -0
  271. package/public/icons/icon-144x144.png +0 -0
  272. package/public/icons/icon-152x152.png +0 -0
  273. package/public/icons/icon-192x192.png +0 -0
  274. package/public/icons/icon-384x384.png +0 -0
  275. package/public/icons/icon-512x512.png +0 -0
  276. package/public/icons/icon-72x72.png +0 -0
  277. package/public/icons/icon-96x96.png +0 -0
  278. package/public/manifest.json +61 -0
  279. package/public/sw.js +64 -0
  280. package/scripts/agent-os +91 -0
  281. package/scripts/install.sh +48 -0
  282. package/scripts/lib/ai-clis.sh +132 -0
  283. package/scripts/lib/commands.sh +487 -0
  284. package/scripts/lib/common.sh +89 -0
  285. package/scripts/lib/prerequisites.sh +462 -0
  286. package/scripts/setup.sh +134 -0
  287. package/server.ts +155 -0
  288. package/stores/fileOpen.ts +26 -0
  289. package/stores/index.ts +1 -0
  290. package/stores/initialPrompt.ts +24 -0
  291. package/stores/sessionSelection.ts +48 -0
  292. package/styles/themes.css +603 -0
  293. package/tsconfig.json +33 -0
@@ -0,0 +1,82 @@
1
+ "use client";
2
+
3
+ import { useState, useRef, useEffect } from "react";
4
+ import { Button } from "./ui/button";
5
+ import { Send, Square } from "lucide-react";
6
+
7
+ interface MessageInputProps {
8
+ onSend: (message: string) => void;
9
+ onCancel?: () => void;
10
+ disabled?: boolean;
11
+ placeholder?: string;
12
+ }
13
+
14
+ export function MessageInput({
15
+ onSend,
16
+ onCancel,
17
+ disabled,
18
+ placeholder = "Send a message...",
19
+ }: MessageInputProps) {
20
+ const [text, setText] = useState("");
21
+ const textareaRef = useRef<HTMLTextAreaElement>(null);
22
+
23
+ // Auto-resize textarea
24
+ useEffect(() => {
25
+ const textarea = textareaRef.current;
26
+ if (textarea) {
27
+ textarea.style.height = "auto";
28
+ textarea.style.height = Math.min(textarea.scrollHeight, 200) + "px";
29
+ }
30
+ }, [text]);
31
+
32
+ const handleSubmit = (e: React.FormEvent) => {
33
+ e.preventDefault();
34
+ if (text.trim() && !disabled) {
35
+ onSend(text.trim());
36
+ setText("");
37
+ }
38
+ };
39
+
40
+ const handleKeyDown = (e: React.KeyboardEvent) => {
41
+ if (e.key === "Enter" && !e.shiftKey) {
42
+ e.preventDefault();
43
+ handleSubmit(e);
44
+ }
45
+ };
46
+
47
+ return (
48
+ <form onSubmit={handleSubmit} className="border-border border-t p-4">
49
+ <div className="flex items-end gap-2">
50
+ <textarea
51
+ ref={textareaRef}
52
+ value={text}
53
+ onChange={(e) => setText(e.target.value)}
54
+ onKeyDown={handleKeyDown}
55
+ placeholder={placeholder}
56
+ disabled={disabled}
57
+ rows={1}
58
+ className="bg-muted border-input placeholder:text-muted-foreground focus:ring-ring flex-1 resize-none rounded-lg border px-3 py-2 text-sm focus:ring-1 focus:outline-none disabled:opacity-50"
59
+ />
60
+
61
+ {disabled && onCancel ? (
62
+ <Button
63
+ type="button"
64
+ variant="destructive"
65
+ size="icon"
66
+ onClick={onCancel}
67
+ >
68
+ <Square className="h-4 w-4" />
69
+ </Button>
70
+ ) : (
71
+ <Button type="submit" disabled={!text.trim() || disabled}>
72
+ <Send className="h-4 w-4" />
73
+ </Button>
74
+ )}
75
+ </div>
76
+
77
+ <p className="text-muted-foreground mt-2 text-xs">
78
+ Press Enter to send, Shift+Enter for new line
79
+ </p>
80
+ </form>
81
+ );
82
+ }
@@ -0,0 +1,166 @@
1
+ "use client";
2
+
3
+ import { useState, useEffect, useRef } from "react";
4
+ import {
5
+ Dialog,
6
+ DialogContent,
7
+ DialogHeader,
8
+ DialogTitle,
9
+ } from "@/components/ui/dialog";
10
+ import { Input } from "@/components/ui/input";
11
+ import { Button } from "@/components/ui/button";
12
+ import {
13
+ Select,
14
+ SelectContent,
15
+ SelectItem,
16
+ SelectTrigger,
17
+ SelectValue,
18
+ } from "@/components/ui/select";
19
+ import { Sparkles } from "lucide-react";
20
+ import type { ClaudeProject } from "@/data/claude";
21
+
22
+ const ADJECTIVES = [
23
+ "swift",
24
+ "bright",
25
+ "calm",
26
+ "bold",
27
+ "keen",
28
+ "vivid",
29
+ "crisp",
30
+ "warm",
31
+ "cool",
32
+ "sharp",
33
+ ];
34
+ const NOUNS = [
35
+ "falcon",
36
+ "river",
37
+ "prism",
38
+ "cedar",
39
+ "spark",
40
+ "orbit",
41
+ "ridge",
42
+ "frost",
43
+ "coral",
44
+ "flint",
45
+ ];
46
+
47
+ function generateName() {
48
+ const adj = ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)];
49
+ const noun = NOUNS[Math.floor(Math.random() * NOUNS.length)];
50
+ return `${adj}-${noun}`;
51
+ }
52
+
53
+ interface NewClaudeSessionDialogProps {
54
+ open: boolean;
55
+ projectName: string;
56
+ projects?: ClaudeProject[];
57
+ onClose: () => void;
58
+ onConfirm: (name: string, cwd?: string, projectName?: string) => void;
59
+ }
60
+
61
+ export function NewClaudeSessionDialog({
62
+ open,
63
+ projectName,
64
+ projects,
65
+ onClose,
66
+ onConfirm,
67
+ }: NewClaudeSessionDialogProps) {
68
+ const [name, setName] = useState("");
69
+ const [selectedProject, setSelectedProject] = useState(projectName);
70
+ const inputRef = useRef<HTMLInputElement>(null);
71
+
72
+ useEffect(() => {
73
+ if (open) {
74
+ setName(generateName());
75
+ setSelectedProject(projectName);
76
+ setTimeout(() => {
77
+ inputRef.current?.focus();
78
+ inputRef.current?.select();
79
+ }, 50);
80
+ }
81
+ }, [open, projectName]);
82
+
83
+ const handleSubmit = (e: React.FormEvent) => {
84
+ e.preventDefault();
85
+ const project = projects?.find((p) => p.name === selectedProject);
86
+ onConfirm(
87
+ name.trim() || generateName(),
88
+ project?.directory || undefined,
89
+ selectedProject || undefined
90
+ );
91
+ };
92
+
93
+ const showProjectSelector = projects && projects.length > 0 && !projectName;
94
+
95
+ return (
96
+ <Dialog open={open} onOpenChange={(o) => !o && onClose()}>
97
+ <DialogContent className="sm:max-w-sm">
98
+ <DialogHeader>
99
+ <DialogTitle className="text-base">New session</DialogTitle>
100
+ </DialogHeader>
101
+ <form onSubmit={handleSubmit} className="space-y-4">
102
+ {showProjectSelector ? (
103
+ <div>
104
+ <label className="text-muted-foreground mb-2 block text-xs">
105
+ Project
106
+ </label>
107
+ <Select
108
+ value={selectedProject}
109
+ onValueChange={setSelectedProject}
110
+ >
111
+ <SelectTrigger className="h-9">
112
+ <SelectValue placeholder="Select a project" />
113
+ </SelectTrigger>
114
+ <SelectContent>
115
+ {projects
116
+ .filter((p) => !p.hidden && p.sessionCount > 0)
117
+ .map((p) => (
118
+ <SelectItem key={p.name} value={p.name}>
119
+ {p.displayName}
120
+ </SelectItem>
121
+ ))}
122
+ </SelectContent>
123
+ </Select>
124
+ </div>
125
+ ) : (
126
+ projectName && (
127
+ <p className="text-muted-foreground text-xs">{projectName}</p>
128
+ )
129
+ )}
130
+ <div>
131
+ <div className="flex gap-2">
132
+ <Input
133
+ ref={inputRef}
134
+ value={name}
135
+ onChange={(e) => setName(e.target.value)}
136
+ placeholder="Session name"
137
+ className="h-9"
138
+ />
139
+ <Button
140
+ type="button"
141
+ variant="ghost"
142
+ size="icon-sm"
143
+ className="h-9 w-9 shrink-0"
144
+ onClick={() => setName(generateName())}
145
+ >
146
+ <Sparkles className="h-3.5 w-3.5" />
147
+ </Button>
148
+ </div>
149
+ </div>
150
+ <div className="flex justify-end gap-2">
151
+ <Button type="button" variant="ghost" size="sm" onClick={onClose}>
152
+ Cancel
153
+ </Button>
154
+ <Button
155
+ type="submit"
156
+ size="sm"
157
+ disabled={showProjectSelector && !selectedProject}
158
+ >
159
+ Create
160
+ </Button>
161
+ </div>
162
+ </form>
163
+ </DialogContent>
164
+ </Dialog>
165
+ );
166
+ }
@@ -0,0 +1,78 @@
1
+ import { ChevronRight } from "lucide-react";
2
+ import type { AgentType } from "@/lib/providers";
3
+ import { getProviderDefinition } from "@/lib/providers";
4
+
5
+ interface AdvancedSettingsProps {
6
+ open: boolean;
7
+ onOpenChange: (open: boolean) => void;
8
+ agentType: AgentType;
9
+ useTmux: boolean;
10
+ onUseTmuxChange: (checked: boolean) => void;
11
+ skipPermissions: boolean;
12
+ onSkipPermissionsChange: (checked: boolean) => void;
13
+ }
14
+
15
+ export function AdvancedSettings({
16
+ open,
17
+ onOpenChange,
18
+ agentType,
19
+ useTmux,
20
+ onUseTmuxChange,
21
+ skipPermissions,
22
+ onSkipPermissionsChange,
23
+ }: AdvancedSettingsProps) {
24
+ const provider = getProviderDefinition(agentType);
25
+ const supportsAutoApprove = Boolean(provider.autoApproveFlag);
26
+
27
+ return (
28
+ <div className="border-border rounded-lg border">
29
+ <button
30
+ type="button"
31
+ onClick={() => onOpenChange(!open)}
32
+ className="text-muted-foreground hover:text-foreground flex w-full items-center gap-2 px-3 py-2 text-sm transition-colors"
33
+ >
34
+ <ChevronRight
35
+ className={`h-4 w-4 transition-transform ${open ? "rotate-90" : ""}`}
36
+ />
37
+ Advanced Settings
38
+ </button>
39
+ {open && (
40
+ <div className="space-y-3 border-t px-3 py-3">
41
+ <div className="flex items-center gap-2">
42
+ <input
43
+ type="checkbox"
44
+ id="useTmux"
45
+ checked={useTmux}
46
+ onChange={(e) => onUseTmuxChange(e.target.checked)}
47
+ className="border-border bg-background accent-primary h-4 w-4 rounded"
48
+ />
49
+ <label htmlFor="useTmux" className="cursor-pointer text-sm">
50
+ Use tmux session
51
+ <span className="text-muted-foreground ml-1">
52
+ (enables detach/attach)
53
+ </span>
54
+ </label>
55
+ </div>
56
+ <div className="flex items-center gap-2">
57
+ <input
58
+ type="checkbox"
59
+ id="skipPermissions"
60
+ checked={skipPermissions}
61
+ disabled={!supportsAutoApprove}
62
+ onChange={(e) => onSkipPermissionsChange(e.target.checked)}
63
+ className="border-border bg-background accent-primary h-4 w-4 rounded disabled:cursor-not-allowed disabled:opacity-50"
64
+ />
65
+ <label htmlFor="skipPermissions" className="cursor-pointer text-sm">
66
+ Auto-approve tool calls
67
+ <span className="text-muted-foreground ml-1">
68
+ {supportsAutoApprove
69
+ ? `(${provider.autoApproveFlag})`
70
+ : "(not supported)"}
71
+ </span>
72
+ </label>
73
+ </div>
74
+ </div>
75
+ )}
76
+ </div>
77
+ );
78
+ }
@@ -0,0 +1,37 @@
1
+ import {
2
+ Select,
3
+ SelectContent,
4
+ SelectItem,
5
+ SelectTrigger,
6
+ SelectValue,
7
+ } from "@/components/ui/select";
8
+ import type { AgentType } from "@/lib/providers";
9
+ import { AGENT_OPTIONS } from "./NewSessionDialog.types";
10
+
11
+ interface AgentSelectorProps {
12
+ value: AgentType;
13
+ onChange: (value: AgentType) => void;
14
+ }
15
+
16
+ export function AgentSelector({ value, onChange }: AgentSelectorProps) {
17
+ return (
18
+ <div className="space-y-2">
19
+ <label className="text-sm font-medium">Agent</label>
20
+ <Select value={value} onValueChange={(v) => onChange(v as AgentType)}>
21
+ <SelectTrigger>
22
+ <SelectValue />
23
+ </SelectTrigger>
24
+ <SelectContent>
25
+ {AGENT_OPTIONS.map((option) => (
26
+ <SelectItem key={option.value} value={option.value}>
27
+ <span className="font-medium">{option.label}</span>
28
+ <span className="text-muted-foreground ml-2 text-xs">
29
+ {option.description}
30
+ </span>
31
+ </SelectItem>
32
+ ))}
33
+ </SelectContent>
34
+ </Select>
35
+ </div>
36
+ );
37
+ }
@@ -0,0 +1,94 @@
1
+ "use client";
2
+
3
+ import type { LucideIcon } from "lucide-react";
4
+ import { Loader2, GitBranch, Package, FileCode, Check } from "lucide-react";
5
+ import { cn } from "@/lib/utils";
6
+
7
+ export interface StepConfig {
8
+ id: string;
9
+ label: string;
10
+ icon: LucideIcon;
11
+ }
12
+
13
+ interface CreatingOverlayProps {
14
+ isWorktree: boolean;
15
+ step: string;
16
+ /** Override default steps and hint text */
17
+ steps?: StepConfig[];
18
+ hint?: string;
19
+ }
20
+
21
+ const worktreeSteps: StepConfig[] = [
22
+ { id: "worktree", label: "Creating worktree", icon: GitBranch },
23
+ { id: "setup", label: "Setting up environment", icon: Package },
24
+ { id: "done", label: "Finalizing", icon: FileCode },
25
+ ];
26
+
27
+ export function CreatingOverlay({
28
+ isWorktree,
29
+ step,
30
+ steps,
31
+ hint,
32
+ }: CreatingOverlayProps) {
33
+ const baseClasses =
34
+ "fixed inset-0 z-[60] flex flex-col items-center justify-center gap-3 bg-background/95 backdrop-blur-sm";
35
+
36
+ const resolvedSteps = steps ?? (isWorktree ? worktreeSteps : null);
37
+
38
+ if (!resolvedSteps) {
39
+ return (
40
+ <div className={baseClasses}>
41
+ <Loader2 className="text-primary h-8 w-8 animate-spin" />
42
+ <p className="text-sm font-medium">Creating session...</p>
43
+ </div>
44
+ );
45
+ }
46
+
47
+ const currentIndex = resolvedSteps.findIndex((s) => s.id === step);
48
+
49
+ return (
50
+ <div className={cn(baseClasses, "gap-6")}>
51
+ <Loader2 className="text-primary h-8 w-8 animate-spin" />
52
+ <div className="space-y-3">
53
+ {resolvedSteps.map((s, index) => {
54
+ const Icon = s.icon;
55
+ const isComplete = index < currentIndex;
56
+ const isCurrent = index === currentIndex;
57
+
58
+ return (
59
+ <div
60
+ key={s.id}
61
+ className={cn(
62
+ "flex items-center gap-3 text-sm transition-colors",
63
+ isComplete && "text-muted-foreground",
64
+ isCurrent && "text-foreground font-medium",
65
+ !isComplete && !isCurrent && "text-muted-foreground/50"
66
+ )}
67
+ >
68
+ <div
69
+ className={cn(
70
+ "flex h-6 w-6 items-center justify-center rounded-full",
71
+ isComplete && "bg-primary/20 text-primary",
72
+ isCurrent && "bg-primary text-primary-foreground",
73
+ !isComplete && !isCurrent && "bg-muted"
74
+ )}
75
+ >
76
+ {isComplete ? (
77
+ <Check className="h-3.5 w-3.5" />
78
+ ) : isCurrent ? (
79
+ <Loader2 className="h-3.5 w-3.5 animate-spin" />
80
+ ) : (
81
+ <Icon className="h-3.5 w-3.5" />
82
+ )}
83
+ </div>
84
+ <span>{s.label}</span>
85
+ </div>
86
+ );
87
+ })}
88
+ </div>
89
+ <p className="text-muted-foreground text-xs">
90
+ {hint ?? "This may take a minute for large codebases"}
91
+ </p>
92
+ </div>
93
+ );
94
+ }
@@ -0,0 +1,136 @@
1
+ import type { AgentType } from "@/lib/providers";
2
+ import type { ProjectWithDevServers } from "@/lib/projects";
3
+
4
+ // LocalStorage keys
5
+ export const SKIP_PERMISSIONS_KEY = "agentOS:skipPermissions";
6
+ export const AGENT_TYPE_KEY = "agentOS:defaultAgentType";
7
+ export const RECENT_DIRS_KEY = "agentOS:recentDirectories";
8
+ export const USE_TMUX_KEY = "agentOS:useTmux";
9
+ export const MAX_RECENT_DIRS = 5;
10
+
11
+ // Random feature name generator
12
+ const ADJECTIVES = [
13
+ "swift",
14
+ "blue",
15
+ "bright",
16
+ "calm",
17
+ "cool",
18
+ "dark",
19
+ "fast",
20
+ "gold",
21
+ "green",
22
+ "happy",
23
+ "iron",
24
+ "jade",
25
+ "keen",
26
+ "light",
27
+ "loud",
28
+ "mint",
29
+ "neat",
30
+ "nice",
31
+ "pink",
32
+ "pure",
33
+ "quick",
34
+ "red",
35
+ "sage",
36
+ "sharp",
37
+ "slim",
38
+ "soft",
39
+ "warm",
40
+ ];
41
+
42
+ const NOUNS = [
43
+ "falcon",
44
+ "river",
45
+ "storm",
46
+ "tiger",
47
+ "wave",
48
+ "cloud",
49
+ "flame",
50
+ "forest",
51
+ "garden",
52
+ "harbor",
53
+ "island",
54
+ "jungle",
55
+ "lake",
56
+ "meadow",
57
+ "ocean",
58
+ "peak",
59
+ "phoenix",
60
+ "rain",
61
+ "shadow",
62
+ "spark",
63
+ "star",
64
+ "stone",
65
+ "sun",
66
+ "thunder",
67
+ "tree",
68
+ "valley",
69
+ "wind",
70
+ "wolf",
71
+ ];
72
+
73
+ export function generateFeatureName(): string {
74
+ const adj = ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)];
75
+ const noun = NOUNS[Math.floor(Math.random() * NOUNS.length)];
76
+ return `${adj}-${noun}`;
77
+ }
78
+
79
+ // Git info from API
80
+ export interface GitInfo {
81
+ isGitRepo: boolean;
82
+ branches: string[];
83
+ defaultBranch: string | null;
84
+ currentBranch: string | null;
85
+ }
86
+
87
+ // Agent type options
88
+ export const AGENT_OPTIONS: {
89
+ value: AgentType;
90
+ label: string;
91
+ description: string;
92
+ }[] = [
93
+ { value: "claude", label: "Claude Code", description: "Anthropic's CLI" },
94
+ ];
95
+
96
+ // Props for main dialog
97
+ export interface NewSessionDialogProps {
98
+ open: boolean;
99
+ projects: ProjectWithDevServers[];
100
+ selectedProjectId?: string;
101
+ onClose: () => void;
102
+ onCreated: (sessionId: string) => void;
103
+ onCreateProject?: (
104
+ name: string,
105
+ workingDirectory: string,
106
+ agentType: AgentType
107
+ ) => Promise<string | null>;
108
+ }
109
+
110
+ // Form state
111
+ export interface NewSessionFormState {
112
+ name: string;
113
+ workingDirectory: string;
114
+ projectId: string | null;
115
+ agentType: AgentType;
116
+ skipPermissions: boolean;
117
+ useTmux: boolean;
118
+ initialPrompt: string;
119
+ // Worktree
120
+ useWorktree: boolean;
121
+ featureName: string;
122
+ baseBranch: string;
123
+ // Git
124
+ gitInfo: GitInfo | null;
125
+ checkingGit: boolean;
126
+ // UI
127
+ showNewProject: boolean;
128
+ newProjectName: string;
129
+ creatingProject: boolean;
130
+ advancedOpen: boolean;
131
+ // Submission
132
+ isLoading: boolean;
133
+ error: string | null;
134
+ // Recent
135
+ recentDirs: string[];
136
+ }