@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,462 @@
1
+ #!/usr/bin/env bash
2
+ # Prerequisite installation for claude-deck
3
+
4
+ # Attempt to source common Node.js version managers
5
+ # This ensures we detect Node even if it's not in the current PATH
6
+ source_node_managers() {
7
+ # nvm
8
+ if [[ -s "$HOME/.nvm/nvm.sh" ]]; then
9
+ source "$HOME/.nvm/nvm.sh" 2>/dev/null || true
10
+ fi
11
+
12
+ # fnm
13
+ if [[ -d "$HOME/.local/share/fnm" ]]; then
14
+ export PATH="$HOME/.local/share/fnm:$PATH"
15
+ eval "$(fnm env --use-on-cd 2>/dev/null || true)"
16
+ fi
17
+
18
+ # asdf
19
+ if [[ -f "$HOME/.asdf/asdf.sh" ]]; then
20
+ source "$HOME/.asdf/asdf.sh" 2>/dev/null || true
21
+ fi
22
+
23
+ # volta
24
+ if [[ -d "$HOME/.volta" ]]; then
25
+ export VOLTA_HOME="$HOME/.volta"
26
+ export PATH="$VOLTA_HOME/bin:$PATH"
27
+ fi
28
+
29
+ # Homebrew (if not already in PATH)
30
+ if [[ "$OS" == "macos" ]]; then
31
+ if [[ -f /opt/homebrew/bin/brew ]]; then
32
+ eval "$(/opt/homebrew/bin/brew shellenv 2>/dev/null || true)"
33
+ elif [[ -f /usr/local/bin/brew ]]; then
34
+ eval "$(/usr/local/bin/brew shellenv 2>/dev/null || true)"
35
+ fi
36
+ fi
37
+
38
+ # ~/.local/bin (common for user-installed binaries)
39
+ if [[ -d "$HOME/.local/bin" ]]; then
40
+ export PATH="$HOME/.local/bin:$PATH"
41
+ fi
42
+ }
43
+
44
+ # Check if Node.js is available (trying multiple sources)
45
+ check_node() {
46
+ # Try direct command first
47
+ if command -v node &> /dev/null; then
48
+ local version
49
+ version=$(node -v | sed 's/v//' | cut -d. -f1)
50
+ if [[ "$version" -ge 20 ]]; then
51
+ local node_path=$(command -v node)
52
+ log_success "Found Node.js v$(node -v | sed 's/v//') at $node_path"
53
+ return 0
54
+ fi
55
+ fi
56
+
57
+ # Source version managers and try again
58
+ source_node_managers
59
+
60
+ if command -v node &> /dev/null; then
61
+ local version
62
+ version=$(node -v | sed 's/v//' | cut -d. -f1)
63
+ if [[ "$version" -ge 20 ]]; then
64
+ local node_path=$(command -v node)
65
+ local manager=""
66
+
67
+ # Detect which manager provided it
68
+ if [[ "$node_path" == *"nvm"* ]]; then
69
+ manager=" (via nvm)"
70
+ elif [[ "$node_path" == *"fnm"* ]]; then
71
+ manager=" (via fnm)"
72
+ elif [[ "$node_path" == *"asdf"* ]]; then
73
+ manager=" (via asdf)"
74
+ elif [[ "$node_path" == *"volta"* ]]; then
75
+ manager=" (via volta)"
76
+ elif [[ "$node_path" == *"homebrew"* ]] || [[ "$node_path" == "/opt/homebrew"* ]] || [[ "$node_path" == "/usr/local"* ]]; then
77
+ manager=" (via Homebrew)"
78
+ fi
79
+
80
+ log_success "Found Node.js v$(node -v | sed 's/v//')$manager at $node_path"
81
+ return 0
82
+ fi
83
+ fi
84
+
85
+ return 1
86
+ }
87
+
88
+ # Check if ripgrep is available
89
+ check_ripgrep() {
90
+ if command -v rg &> /dev/null; then
91
+ local rg_path=$(command -v rg)
92
+ local rg_version=$(rg --version 2>/dev/null | head -n1 | awk '{print $2}' || echo "unknown")
93
+ log_success "Found ripgrep $rg_version at $rg_path"
94
+ return 0
95
+ fi
96
+
97
+ # Source common paths
98
+ source_node_managers
99
+
100
+ if command -v rg &> /dev/null; then
101
+ local rg_path=$(command -v rg)
102
+ local rg_version=$(rg --version 2>/dev/null | head -n1 | awk '{print $2}' || echo "unknown")
103
+ log_success "Found ripgrep $rg_version at $rg_path"
104
+ return 0
105
+ fi
106
+
107
+ return 1
108
+ }
109
+
110
+ # Check if git is available
111
+ check_git() {
112
+ if command -v git &> /dev/null; then
113
+ local git_path=$(command -v git)
114
+ local git_version=$(git --version 2>/dev/null | awk '{print $3}' || echo "unknown")
115
+ log_success "Found git $git_version at $git_path"
116
+ return 0
117
+ fi
118
+
119
+ # Check common locations
120
+ for git_path in /usr/bin/git /usr/local/bin/git /opt/homebrew/bin/git; do
121
+ if [[ -x "$git_path" ]]; then
122
+ export PATH="$(dirname "$git_path"):$PATH"
123
+ local git_version=$(git --version 2>/dev/null | awk '{print $3}' || echo "unknown")
124
+ log_success "Found git $git_version at $git_path"
125
+ return 0
126
+ fi
127
+ done
128
+
129
+ return 1
130
+ }
131
+
132
+ # Check if tmux is available
133
+ check_tmux() {
134
+ if command -v tmux &> /dev/null; then
135
+ local tmux_path=$(command -v tmux)
136
+ local tmux_version=$(tmux -V 2>/dev/null | awk '{print $2}' || echo "unknown")
137
+ log_success "Found tmux $tmux_version at $tmux_path"
138
+ return 0
139
+ fi
140
+
141
+ # Source common paths and check again
142
+ source_node_managers
143
+
144
+ if command -v tmux &> /dev/null; then
145
+ local tmux_path=$(command -v tmux)
146
+ local tmux_version=$(tmux -V 2>/dev/null | awk '{print $2}' || echo "unknown")
147
+ log_success "Found tmux $tmux_version at $tmux_path"
148
+ return 0
149
+ fi
150
+
151
+ return 1
152
+ }
153
+
154
+ install_homebrew() {
155
+ if command -v brew &> /dev/null; then
156
+ return 0
157
+ fi
158
+
159
+ log_info "Installing Homebrew..."
160
+ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
161
+
162
+ # Add to path for current session
163
+ if [[ -f /opt/homebrew/bin/brew ]]; then
164
+ eval "$(/opt/homebrew/bin/brew shellenv)"
165
+ elif [[ -f /usr/local/bin/brew ]]; then
166
+ eval "$(/usr/local/bin/brew shellenv)"
167
+ fi
168
+
169
+ # Add to shell profile so it's available in future sessions
170
+ local shell_profile=""
171
+ if [[ -n "$ZSH_VERSION" ]] && [[ -f "$HOME/.zshrc" ]]; then
172
+ shell_profile="$HOME/.zshrc"
173
+ elif [[ -n "$BASH_VERSION" ]] && [[ -f "$HOME/.bashrc" ]]; then
174
+ shell_profile="$HOME/.bashrc"
175
+ elif [[ -f "$HOME/.bash_profile" ]]; then
176
+ shell_profile="$HOME/.bash_profile"
177
+ fi
178
+
179
+ if [[ -n "$shell_profile" ]]; then
180
+ if ! grep -q "brew shellenv" "$shell_profile"; then
181
+ echo '' >> "$shell_profile"
182
+ echo '# Homebrew' >> "$shell_profile"
183
+ if [[ -f /opt/homebrew/bin/brew ]]; then
184
+ echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> "$shell_profile"
185
+ elif [[ -f /usr/local/bin/brew ]]; then
186
+ echo 'eval "$(/usr/local/bin/brew shellenv)"' >> "$shell_profile"
187
+ fi
188
+ fi
189
+ fi
190
+ }
191
+
192
+ install_node() {
193
+ if command -v node &> /dev/null; then
194
+ local version
195
+ version=$(node -v | sed 's/v//' | cut -d. -f1)
196
+ if [[ "$version" -ge 20 ]]; then
197
+ return 0
198
+ fi
199
+ log_warn "Node.js $version found, but 20+ required"
200
+ fi
201
+
202
+ log_info "Installing Node.js..."
203
+
204
+ case "$OS" in
205
+ macos)
206
+ # Check if user is admin - if not, use fnm (user-space install)
207
+ if ! groups | grep -q admin; then
208
+ log_info "Non-admin user detected - using fnm (Fast Node Manager)"
209
+ log_info "This installs Node.js to your home directory (no sudo needed)"
210
+
211
+ # Install fnm
212
+ curl -fsSL https://fnm.vercel.app/install | bash -s -- --skip-shell
213
+
214
+ # Add fnm to path for current session
215
+ export PATH="$HOME/.local/share/fnm:$PATH"
216
+ eval "$(fnm env --use-on-cd)"
217
+
218
+ # Install and use Node.js 20
219
+ fnm install 20
220
+ fnm use 20
221
+
222
+ # Add fnm to shell profile
223
+ local shell_profile=""
224
+ if [[ -f "$HOME/.zshrc" ]]; then
225
+ shell_profile="$HOME/.zshrc"
226
+ elif [[ -f "$HOME/.bashrc" ]]; then
227
+ shell_profile="$HOME/.bashrc"
228
+ elif [[ -f "$HOME/.bash_profile" ]]; then
229
+ shell_profile="$HOME/.bash_profile"
230
+ fi
231
+
232
+ if [[ -n "$shell_profile" ]]; then
233
+ if ! grep -q "fnm env" "$shell_profile"; then
234
+ echo '' >> "$shell_profile"
235
+ echo '# fnm (Fast Node Manager)' >> "$shell_profile"
236
+ echo 'eval "$(fnm env --use-on-cd)"' >> "$shell_profile"
237
+ log_info "Added fnm to $shell_profile"
238
+ fi
239
+ fi
240
+ else
241
+ # Admin user - use Homebrew
242
+ install_homebrew
243
+ brew install node
244
+ fi
245
+ ;;
246
+ debian)
247
+ curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
248
+ sudo apt-get install -y nodejs
249
+ ;;
250
+ redhat)
251
+ curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash -
252
+ sudo yum install -y nodejs
253
+ ;;
254
+ *)
255
+ log_error "Please install Node.js 20+ manually: https://nodejs.org"
256
+ exit 1
257
+ ;;
258
+ esac
259
+ }
260
+
261
+ install_git() {
262
+ if command -v git &> /dev/null; then
263
+ return 0
264
+ fi
265
+
266
+ log_info "Installing git..."
267
+
268
+ case "$OS" in
269
+ macos)
270
+ xcode-select --install 2>/dev/null || true
271
+ until command -v git &> /dev/null; do
272
+ sleep 5
273
+ done
274
+ ;;
275
+ debian)
276
+ sudo apt-get update
277
+ sudo apt-get install -y git
278
+ ;;
279
+ redhat)
280
+ sudo yum install -y git
281
+ ;;
282
+ esac
283
+ }
284
+
285
+ install_tmux() {
286
+ if command -v tmux &> /dev/null; then
287
+ return 0
288
+ fi
289
+
290
+ log_info "Installing tmux..."
291
+
292
+ case "$OS" in
293
+ macos)
294
+ # Check if user is admin
295
+ if ! groups | grep -q admin; then
296
+ log_error "tmux requires admin privileges to install via Homebrew."
297
+ log_error ""
298
+ log_error "Option 1: Ask your administrator to run: brew install tmux"
299
+ log_error "Option 2: Make yourself an admin:"
300
+ log_error " - Open System Settings → Users & Groups"
301
+ log_error " - Unlock and check 'Allow user to administer this computer'"
302
+ exit 1
303
+ else
304
+ install_homebrew
305
+ brew install tmux
306
+ fi
307
+ ;;
308
+ debian)
309
+ sudo apt-get update
310
+ sudo apt-get install -y tmux
311
+ ;;
312
+ redhat)
313
+ sudo yum install -y tmux
314
+ ;;
315
+ esac
316
+ }
317
+
318
+ install_ripgrep() {
319
+ if command -v rg &> /dev/null; then
320
+ return 0
321
+ fi
322
+
323
+ log_info "Installing ripgrep..."
324
+
325
+ case "$OS" in
326
+ macos)
327
+ # Check if user is admin
328
+ if ! groups | grep -q admin; then
329
+ # Non-admin: download pre-built binary from GitHub
330
+ log_info "Non-admin user - downloading pre-built ripgrep binary"
331
+
332
+ local arch
333
+ arch=$(uname -m)
334
+ local target
335
+ if [[ "$arch" == "arm64" ]]; then
336
+ target="aarch64-apple-darwin"
337
+ else
338
+ target="x86_64-apple-darwin"
339
+ fi
340
+
341
+ local version="14.1.0"
342
+ local url="https://github.com/BurntSushi/ripgrep/releases/download/${version}/ripgrep-${version}-${target}.tar.gz"
343
+ local tmp_dir="/tmp/ripgrep-install"
344
+
345
+ mkdir -p "$tmp_dir"
346
+ mkdir -p "$HOME/.local/bin"
347
+
348
+ curl -fsSL "$url" | tar -xz -C "$tmp_dir"
349
+ mv "$tmp_dir/ripgrep-${version}-${target}/rg" "$HOME/.local/bin/rg"
350
+ chmod +x "$HOME/.local/bin/rg"
351
+ rm -rf "$tmp_dir"
352
+
353
+ # Add to PATH if not already there
354
+ export PATH="$HOME/.local/bin:$PATH"
355
+
356
+ # Add to shell profile
357
+ local shell_profile=""
358
+ if [[ -f "$HOME/.zshrc" ]]; then
359
+ shell_profile="$HOME/.zshrc"
360
+ elif [[ -f "$HOME/.bashrc" ]]; then
361
+ shell_profile="$HOME/.bashrc"
362
+ elif [[ -f "$HOME/.bash_profile" ]]; then
363
+ shell_profile="$HOME/.bash_profile"
364
+ fi
365
+
366
+ if [[ -n "$shell_profile" ]]; then
367
+ if ! grep -q '.local/bin' "$shell_profile"; then
368
+ echo '' >> "$shell_profile"
369
+ echo '# Add local bin to PATH' >> "$shell_profile"
370
+ echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$shell_profile"
371
+ fi
372
+ fi
373
+
374
+ log_success "ripgrep installed to ~/.local/bin/rg"
375
+ else
376
+ # Admin user - use Homebrew
377
+ install_homebrew
378
+ brew install ripgrep
379
+ fi
380
+ ;;
381
+ debian)
382
+ sudo apt-get update
383
+ sudo apt-get install -y ripgrep
384
+ ;;
385
+ redhat)
386
+ sudo yum install -y ripgrep
387
+ ;;
388
+ esac
389
+ }
390
+
391
+ check_and_install_prerequisites() {
392
+ log_info "Checking prerequisites..."
393
+
394
+ local missing=()
395
+
396
+ # Check Node.js (with version manager detection)
397
+ if ! check_node; then
398
+ missing+=("node")
399
+ fi
400
+
401
+ # Check git (with path detection)
402
+ if ! check_git; then
403
+ missing+=("git")
404
+ fi
405
+
406
+ # Check tmux (with path detection)
407
+ if ! check_tmux; then
408
+ missing+=("tmux")
409
+ fi
410
+
411
+ # Check ripgrep (with path detection)
412
+ if ! check_ripgrep; then
413
+ missing+=("ripgrep")
414
+ fi
415
+
416
+ if [[ ${#missing[@]} -eq 0 ]]; then
417
+ log_success "All prerequisites met"
418
+ return 0
419
+ fi
420
+
421
+ log_warn "Missing prerequisites: ${missing[*]}"
422
+
423
+ if is_interactive; then
424
+ if ! prompt_yn "Install missing prerequisites?"; then
425
+ log_error "Please install manually: ${missing[*]}"
426
+ exit 1
427
+ fi
428
+ fi
429
+
430
+ for dep in "${missing[@]}"; do
431
+ case "$dep" in
432
+ node) install_node ;;
433
+ git) install_git ;;
434
+ tmux) install_tmux ;;
435
+ ripgrep) install_ripgrep ;;
436
+ esac
437
+ done
438
+
439
+ log_success "Prerequisites installed"
440
+
441
+ configure_tmux
442
+ }
443
+
444
+ configure_tmux() {
445
+ local tmux_conf="$HOME/.tmux.conf"
446
+ if [ ! -f "$tmux_conf" ] || ! grep -q "mouse on" "$tmux_conf" 2>/dev/null; then
447
+ log_info "Configuring tmux for ClaudeDeck..."
448
+ cat >> "$tmux_conf" << 'TMUX'
449
+
450
+ # ClaudeDeck: enable mouse for scroll support in web terminal
451
+ set -g mouse on
452
+ set -g history-limit 50000
453
+ set -g default-terminal "xterm-256color"
454
+ set -ga terminal-overrides ",xterm-256color:Tc"
455
+ TMUX
456
+ log_success "tmux configured (mouse on, 50k history)"
457
+ fi
458
+
459
+ if tmux list-sessions &>/dev/null; then
460
+ tmux set -g mouse on 2>/dev/null || true
461
+ fi
462
+ }
@@ -0,0 +1,134 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ echo "ClaudeDeck Setup"
5
+ echo "=============="
6
+ echo ""
7
+
8
+ OS=$(uname -s | tr '[:upper:]' '[:lower:]')
9
+
10
+ # ── Node.js ──────────────────────────────────────────────
11
+ if ! command -v node &> /dev/null; then
12
+ echo "Error: Node.js is not installed"
13
+ echo "Install Node.js 20+ from https://nodejs.org"
14
+ exit 1
15
+ fi
16
+
17
+ NODE_VERSION=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
18
+ if [ "$NODE_VERSION" -lt 20 ]; then
19
+ echo "Error: Node.js 20+ required (found v$NODE_VERSION)"
20
+ exit 1
21
+ fi
22
+ echo "✓ Node.js: $(node -v)"
23
+
24
+ # ── pnpm ─────────────────────────────────────────────────
25
+ if ! command -v pnpm &> /dev/null; then
26
+ echo "Installing pnpm..."
27
+ npm install -g pnpm
28
+ fi
29
+ echo "✓ pnpm: $(pnpm -v)"
30
+
31
+ # ── Build tools (for native modules: node-pty, better-sqlite3) ──
32
+ if [[ "$OS" == "linux" ]]; then
33
+ if ! dpkg -s build-essential &> /dev/null 2>&1; then
34
+ echo "Installing build tools..."
35
+ sudo apt-get update -qq
36
+ sudo apt-get install -y -qq build-essential python3
37
+ fi
38
+ echo "✓ Build tools: installed"
39
+ elif [[ "$OS" == "darwin" ]]; then
40
+ if ! xcode-select -p &> /dev/null 2>&1; then
41
+ echo "Installing Xcode Command Line Tools..."
42
+ xcode-select --install
43
+ echo "Re-run this script after installation completes."
44
+ exit 0
45
+ fi
46
+ echo "✓ Xcode CLT: installed"
47
+ fi
48
+
49
+ # ── tmux ─────────────────────────────────────────────────
50
+ if ! command -v tmux &> /dev/null; then
51
+ echo "Installing tmux..."
52
+ if [[ "$OS" == "linux" ]]; then
53
+ sudo apt-get install -y -qq tmux
54
+ elif [[ "$OS" == "darwin" ]]; then
55
+ brew install tmux
56
+ else
57
+ echo "Error: Install tmux manually"
58
+ exit 1
59
+ fi
60
+ fi
61
+ echo "✓ tmux: $(tmux -V)"
62
+
63
+ # ── tmux configuration ──────────────────────────────────
64
+ TMUX_CONF="$HOME/.tmux.conf"
65
+ if [ ! -f "$TMUX_CONF" ] || ! grep -q "mouse on" "$TMUX_CONF" 2>/dev/null; then
66
+ echo "Configuring tmux (mouse on for scroll support)..."
67
+ cat >> "$TMUX_CONF" << 'TMUX'
68
+
69
+ # ClaudeDeck: enable mouse for scroll support in web terminal
70
+ set -g mouse on
71
+ set -g history-limit 50000
72
+ set -g default-terminal "xterm-256color"
73
+ set -ga terminal-overrides ",xterm-256color:Tc"
74
+ TMUX
75
+ fi
76
+ echo "✓ tmux: mouse on configured"
77
+
78
+ # ── git ──────────────────────────────────────────────────
79
+ if ! command -v git &> /dev/null; then
80
+ echo "Error: git is not installed"
81
+ exit 1
82
+ fi
83
+ echo "✓ git: $(git --version | awk '{print $3}')"
84
+
85
+ # ── ripgrep (for code search) ────────────────────────────
86
+ if ! command -v rg &> /dev/null; then
87
+ echo "Installing ripgrep..."
88
+ if [[ "$OS" == "linux" ]]; then
89
+ sudo apt-get install -y -qq ripgrep
90
+ elif [[ "$OS" == "darwin" ]]; then
91
+ brew install ripgrep
92
+ fi
93
+ fi
94
+ if command -v rg &> /dev/null; then
95
+ echo "✓ ripgrep: $(rg --version | head -1 | awk '{print $2}')"
96
+ else
97
+ echo "⚠ ripgrep: not found (code search will be disabled)"
98
+ fi
99
+
100
+ # ── Claude Code CLI ──────────────────────────────────────
101
+ if ! command -v claude &> /dev/null; then
102
+ echo ""
103
+ echo "Claude Code CLI not found. Install with:"
104
+ echo " npm install -g @anthropic-ai/claude-code"
105
+ echo ""
106
+ echo "⚠ ClaudeDeck requires at least one AI CLI to function."
107
+ else
108
+ echo "✓ Claude CLI: installed"
109
+ fi
110
+
111
+ # ── Environment ──────────────────────────────────────────
112
+ if [ ! -f .env ]; then
113
+ if [ -f .env.example ]; then
114
+ cp .env.example .env
115
+ echo "✓ Created .env from .env.example"
116
+ fi
117
+ fi
118
+
119
+ # ── Data directory ───────────────────────────────────────
120
+ mkdir -p "$HOME/.claude-deck"
121
+ echo "✓ Data dir: ~/.claude-deck/"
122
+
123
+ # ── Install dependencies ────────────────────────────────
124
+ echo ""
125
+ echo "Installing dependencies..."
126
+ pnpm install
127
+
128
+ echo ""
129
+ echo "✓ Setup complete!"
130
+ echo ""
131
+ echo " Development: pnpm dev"
132
+ echo " Production: pnpm start"
133
+ echo " Port: ${PORT:-3011}"
134
+ echo ""