@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,487 @@
1
+ #!/usr/bin/env bash
2
+ # Command implementations for claude-deck
3
+
4
+ cmd_install() {
5
+ local use_local=false
6
+ [[ "${1:-}" == "--local" ]] && use_local=true
7
+
8
+ log_info "Installing ClaudeDeck..."
9
+ echo ""
10
+
11
+ # Check and install prerequisites
12
+ check_and_install_prerequisites
13
+
14
+ # Prompt for AI CLI installation
15
+ prompt_ai_cli_install
16
+
17
+ # Create directory structure
18
+ mkdir -p "$AGENT_OS_HOME"
19
+
20
+ # Clone, copy local, or update repo
21
+ if [[ -d "$REPO_DIR" ]]; then
22
+ if [[ "$use_local" == true ]]; then
23
+ log_info "Updating from local source..."
24
+ rsync -a --delete --exclude='.git' --exclude='node_modules' --exclude='.next' --exclude='*.db*' "$LOCAL_REPO/" "$REPO_DIR/"
25
+ else
26
+ log_info "Repository already exists, pulling latest..."
27
+ cd "$REPO_DIR"
28
+ git pull --ff-only
29
+ fi
30
+ cd "$REPO_DIR"
31
+ else
32
+ if [[ "$use_local" == true ]]; then
33
+ log_info "Copying from local source..."
34
+ rsync -a --exclude='.git' --exclude='node_modules' --exclude='.next' --exclude='*.db*' "$LOCAL_REPO/" "$REPO_DIR/"
35
+ cd "$REPO_DIR"
36
+ git init
37
+ else
38
+ log_info "Cloning repository..."
39
+ git clone "$REPO_URL" "$REPO_DIR"
40
+ cd "$REPO_DIR"
41
+ fi
42
+ fi
43
+
44
+ # Install dependencies
45
+ log_info "Installing dependencies..."
46
+ npm install --legacy-peer-deps
47
+
48
+ # Build for production
49
+ log_info "Building for production..."
50
+ npm run build
51
+
52
+ # Create CLI symlink (prefer ~/.local/bin to avoid sudo)
53
+ log_info "Adding claude-deck to PATH..."
54
+ local bin_dir="$HOME/.local/bin"
55
+ local needs_path_update=false
56
+
57
+ mkdir -p "$bin_dir"
58
+ ln -sf "$REPO_DIR/scripts/claude-deck" "$bin_dir/claude-deck"
59
+
60
+ # Check if ~/.local/bin is in PATH
61
+ if [[ ":$PATH:" != *":$bin_dir:"* ]]; then
62
+ needs_path_update=true
63
+ # Add to shell profile
64
+ local shell_profile=""
65
+ if [[ -f "$HOME/.zshrc" ]]; then
66
+ shell_profile="$HOME/.zshrc"
67
+ elif [[ -f "$HOME/.bashrc" ]]; then
68
+ shell_profile="$HOME/.bashrc"
69
+ elif [[ -f "$HOME/.bash_profile" ]]; then
70
+ shell_profile="$HOME/.bash_profile"
71
+ fi
72
+
73
+ if [[ -n "$shell_profile" ]]; then
74
+ if ! grep -q 'export PATH="$HOME/.local/bin:$PATH"' "$shell_profile" 2>/dev/null; then
75
+ echo '' >> "$shell_profile"
76
+ echo '# Added by ClaudeDeck' >> "$shell_profile"
77
+ echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$shell_profile"
78
+ fi
79
+ fi
80
+ fi
81
+
82
+ echo ""
83
+ log_success "ClaudeDeck installed successfully!"
84
+ echo ""
85
+
86
+ if [[ "$needs_path_update" == true ]]; then
87
+ echo "Note: ~/.local/bin was added to your PATH."
88
+ echo "Run 'source ~/.zshrc' or restart your terminal, then:"
89
+ echo ""
90
+ fi
91
+
92
+ echo "Next steps:"
93
+ echo " claude-deck start Start the server"
94
+ echo " claude-deck enable Auto-start on boot"
95
+ echo " claude-deck status Show URLs"
96
+ }
97
+
98
+ cmd_start() {
99
+ if is_running; then
100
+ local pid
101
+ pid=$(get_pid)
102
+ log_warn "ClaudeDeck is already running (PID: $pid)"
103
+ return 0
104
+ fi
105
+
106
+ if [[ ! -d "$REPO_DIR" ]]; then
107
+ log_error "ClaudeDeck is not installed. Run 'claude-deck install' first."
108
+ exit 1
109
+ fi
110
+
111
+ log_info "Starting ClaudeDeck..."
112
+
113
+ cd "$REPO_DIR"
114
+
115
+ # Rotate log if too big (> 10MB)
116
+ if [[ -f "$LOG_FILE" ]]; then
117
+ local size
118
+ size=$(stat -f%z "$LOG_FILE" 2>/dev/null || stat -c%s "$LOG_FILE" 2>/dev/null || echo 0)
119
+ if [[ "$size" -gt 10485760 ]]; then
120
+ mv "$LOG_FILE" "$LOG_FILE.old"
121
+ fi
122
+ fi
123
+
124
+ # Start server in background
125
+ nohup npm start >> "$LOG_FILE" 2>&1 &
126
+ local pid=$!
127
+ echo "$pid" > "$PID_FILE"
128
+
129
+ # Wait and verify
130
+ sleep 2
131
+ if ! ps -p "$pid" &> /dev/null; then
132
+ log_error "Failed to start ClaudeDeck. Check logs: claude-deck logs"
133
+ rm -f "$PID_FILE"
134
+ exit 1
135
+ fi
136
+
137
+ log_success "ClaudeDeck started (PID: $pid)"
138
+ echo ""
139
+ echo " Local: http://localhost:$PORT"
140
+
141
+ local ts_ip
142
+ ts_ip=$(get_tailscale_ip)
143
+ if [[ -n "$ts_ip" ]]; then
144
+ echo " Tailscale: http://$ts_ip:$PORT"
145
+ fi
146
+ echo ""
147
+ echo "Run 'claude-deck logs' to view logs"
148
+ }
149
+
150
+ cmd_stop() {
151
+ if ! is_running; then
152
+ log_warn "ClaudeDeck is not running"
153
+ return 0
154
+ fi
155
+
156
+ local pid
157
+ pid=$(get_pid)
158
+ log_info "Stopping ClaudeDeck (PID: $pid)..."
159
+
160
+ kill "$pid" 2>/dev/null || true
161
+
162
+ # Wait for graceful shutdown with progress
163
+ local count=0
164
+ printf " Waiting for shutdown"
165
+ while ps -p "$pid" &> /dev/null && [[ $count -lt 10 ]]; do
166
+ printf "."
167
+ sleep 1
168
+ ((count++))
169
+ done
170
+ echo ""
171
+
172
+ # Force kill if still running
173
+ if ps -p "$pid" &> /dev/null; then
174
+ log_warn "Force killing..."
175
+ kill -9 "$pid" 2>/dev/null || true
176
+ sleep 1
177
+ fi
178
+
179
+ rm -f "$PID_FILE"
180
+ log_success "ClaudeDeck stopped"
181
+ }
182
+
183
+ cmd_restart() {
184
+ cmd_stop
185
+ sleep 1
186
+ cmd_start
187
+ }
188
+
189
+ cmd_run() {
190
+ # Start if not running
191
+ if ! is_running; then
192
+ cmd_start
193
+ fi
194
+
195
+ # Wait a moment for server to be ready
196
+ sleep 1
197
+
198
+ local url="http://localhost:$PORT"
199
+ log_info "Opening $url..."
200
+
201
+ # Open in browser
202
+ if [[ "$OS" == "macos" ]]; then
203
+ open "$url"
204
+ elif command -v xdg-open &> /dev/null; then
205
+ xdg-open "$url"
206
+ elif command -v wslview &> /dev/null; then
207
+ wslview "$url"
208
+ else
209
+ log_warn "Could not detect browser. Open manually: $url"
210
+ fi
211
+ }
212
+
213
+ cmd_status() {
214
+ echo ""
215
+ if is_running; then
216
+ local pid
217
+ pid=$(get_pid)
218
+ echo -e " Status: ${GREEN}Running${NC} (PID: $pid)"
219
+ echo " Port: $PORT"
220
+ echo " Local: http://localhost:$PORT"
221
+
222
+ local ts_ip
223
+ ts_ip=$(get_tailscale_ip)
224
+ if [[ -n "$ts_ip" ]]; then
225
+ echo " Tailscale: http://$ts_ip:$PORT"
226
+ fi
227
+
228
+ echo " Logs: $LOG_FILE"
229
+ echo " Install: $REPO_DIR"
230
+ else
231
+ echo -e " Status: ${RED}Stopped${NC}"
232
+
233
+ if [[ -d "$REPO_DIR" ]]; then
234
+ echo " Install: $REPO_DIR"
235
+ echo ""
236
+ echo " Run 'claude-deck start' to start the server"
237
+ else
238
+ echo " Install: Not installed"
239
+ echo ""
240
+ echo " Run 'claude-deck install' to install"
241
+ fi
242
+ fi
243
+ echo ""
244
+ }
245
+
246
+ cmd_logs() {
247
+ if [[ ! -f "$LOG_FILE" ]]; then
248
+ log_warn "No log file found"
249
+ exit 1
250
+ fi
251
+
252
+ tail -f "$LOG_FILE"
253
+ }
254
+
255
+ cmd_update() {
256
+ if [[ ! -d "$REPO_DIR" ]]; then
257
+ log_error "ClaudeDeck is not installed. Run 'claude-deck install' first."
258
+ exit 1
259
+ fi
260
+
261
+ local was_running=false
262
+ if is_running; then
263
+ was_running=true
264
+ cmd_stop
265
+ fi
266
+
267
+ log_info "Updating ClaudeDeck..."
268
+
269
+ cd "$REPO_DIR"
270
+
271
+ # Fetch and check
272
+ git fetch
273
+ local local_hash remote_hash
274
+ local_hash=$(git rev-parse HEAD)
275
+ remote_hash=$(git rev-parse @{u})
276
+
277
+ if [[ "$local_hash" == "$remote_hash" ]]; then
278
+ log_success "Already up to date"
279
+ else
280
+ log_info "Pulling latest changes..."
281
+ git pull --ff-only
282
+
283
+ log_info "Installing dependencies..."
284
+ npm install --legacy-peer-deps
285
+
286
+ log_info "Rebuilding..."
287
+ npm run build
288
+
289
+ log_success "Update complete!"
290
+ fi
291
+
292
+ if [[ "$was_running" == true ]]; then
293
+ cmd_start
294
+ fi
295
+ }
296
+
297
+ cmd_enable() {
298
+ if [[ ! -d "$REPO_DIR" ]]; then
299
+ log_error "ClaudeDeck is not installed. Run 'claude-deck install' first."
300
+ exit 1
301
+ fi
302
+
303
+ local script_path
304
+ script_path=$(realpath "$0")
305
+
306
+ if [[ "$OS" == "macos" ]]; then
307
+ local plist_path="$HOME/Library/LaunchAgents/com.claude-deck.plist"
308
+
309
+ cat > "$plist_path" << EOF
310
+ <?xml version="1.0" encoding="UTF-8"?>
311
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
312
+ <plist version="1.0">
313
+ <dict>
314
+ <key>Label</key>
315
+ <string>com.claude-deck</string>
316
+ <key>ProgramArguments</key>
317
+ <array>
318
+ <string>$script_path</string>
319
+ <string>start</string>
320
+ </array>
321
+ <key>RunAtLoad</key>
322
+ <true/>
323
+ <key>KeepAlive</key>
324
+ <false/>
325
+ <key>StandardOutPath</key>
326
+ <string>$LOG_FILE</string>
327
+ <key>StandardErrorPath</key>
328
+ <string>$LOG_FILE</string>
329
+ <key>EnvironmentVariables</key>
330
+ <dict>
331
+ <key>PATH</key>
332
+ <string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin</string>
333
+ </dict>
334
+ </dict>
335
+ </plist>
336
+ EOF
337
+
338
+ launchctl load "$plist_path" 2>/dev/null || true
339
+ log_success "Auto-start enabled (launchd)"
340
+ echo " Plist: $plist_path"
341
+
342
+ elif [[ -d /etc/systemd ]]; then
343
+ local service_dir="$HOME/.config/systemd/user"
344
+ local service_path="$service_dir/claude-deck.service"
345
+
346
+ mkdir -p "$service_dir"
347
+
348
+ cat > "$service_path" << EOF
349
+ [Unit]
350
+ Description=ClaudeDeck - AI Coding Session Manager
351
+ After=network.target
352
+
353
+ [Service]
354
+ Type=simple
355
+ ExecStart=$script_path start-foreground
356
+ Restart=on-failure
357
+ RestartSec=10
358
+ Environment=PATH=/usr/local/bin:/usr/bin:/bin
359
+
360
+ [Install]
361
+ WantedBy=default.target
362
+ EOF
363
+
364
+ systemctl --user daemon-reload
365
+ systemctl --user enable claude-deck
366
+ log_success "Auto-start enabled (systemd)"
367
+ echo " Service: $service_path"
368
+
369
+ else
370
+ log_error "Could not detect init system (launchd/systemd)"
371
+ exit 1
372
+ fi
373
+ }
374
+
375
+ cmd_disable() {
376
+ if [[ "$OS" == "macos" ]]; then
377
+ local plist_path="$HOME/Library/LaunchAgents/com.claude-deck.plist"
378
+
379
+ if [[ -f "$plist_path" ]]; then
380
+ launchctl unload "$plist_path" 2>/dev/null || true
381
+ rm -f "$plist_path"
382
+ log_success "Auto-start disabled"
383
+ else
384
+ log_warn "Auto-start was not enabled"
385
+ fi
386
+
387
+ elif [[ -d /etc/systemd ]]; then
388
+ systemctl --user disable claude-deck 2>/dev/null || true
389
+ rm -f "$HOME/.config/systemd/user/claude-deck.service"
390
+ systemctl --user daemon-reload
391
+ log_success "Auto-start disabled"
392
+
393
+ else
394
+ log_error "Could not detect init system"
395
+ exit 1
396
+ fi
397
+ }
398
+
399
+ cmd_uninstall() {
400
+ echo ""
401
+ log_warn "This will remove ClaudeDeck and all its data."
402
+
403
+ if ! prompt_yn "Are you sure?" "n"; then
404
+ log_info "Cancelled"
405
+ exit 0
406
+ fi
407
+
408
+ # Detect if installed via npm (check if script is in node_modules)
409
+ local installed_via_npm=false
410
+ if [[ "$SCRIPT_DIR" == *"node_modules"* ]]; then
411
+ installed_via_npm=true
412
+ fi
413
+
414
+ # Stop if running
415
+ if is_running; then
416
+ cmd_stop
417
+ fi
418
+
419
+ # Disable auto-start
420
+ cmd_disable 2>/dev/null || true
421
+
422
+ # Remove CLI symlink (only for non-npm installs)
423
+ if [[ "$installed_via_npm" == false ]]; then
424
+ if [[ -L "$HOME/.local/bin/claude-deck" ]]; then
425
+ log_info "Removing CLI symlink..."
426
+ rm -f "$HOME/.local/bin/claude-deck"
427
+ elif [[ -L "/usr/local/bin/claude-deck" ]]; then
428
+ # Legacy location
429
+ log_info "Removing CLI symlink..."
430
+ sudo rm -f "/usr/local/bin/claude-deck"
431
+ fi
432
+ fi
433
+
434
+ # Remove installation directory
435
+ if [[ -d "$AGENT_OS_HOME" ]]; then
436
+ log_info "Removing $AGENT_OS_HOME..."
437
+ rm -rf "$AGENT_OS_HOME"
438
+ fi
439
+
440
+ log_success "ClaudeDeck uninstalled"
441
+
442
+ # If installed via npm, provide instructions to remove the global package
443
+ if [[ "$installed_via_npm" == true ]]; then
444
+ echo ""
445
+ log_info "To completely remove the CLI, run:"
446
+ echo " npm uninstall -g @atercates/claude-deck"
447
+ fi
448
+ }
449
+
450
+ cmd_start_foreground() {
451
+ if [[ ! -d "$REPO_DIR" ]]; then
452
+ log_error "ClaudeDeck is not installed."
453
+ exit 1
454
+ fi
455
+
456
+ cd "$REPO_DIR"
457
+
458
+ # Create PID file before exec (PID stays the same after exec)
459
+ echo "$$" > "$PID_FILE"
460
+
461
+ exec npm start
462
+ }
463
+
464
+ cmd_help() {
465
+ echo ""
466
+ echo -e "${BOLD}ClaudeDeck${NC} - Self-hosted AI coding session manager"
467
+ echo ""
468
+ echo "Usage: claude-deck <command>"
469
+ echo ""
470
+ echo "Commands:"
471
+ echo " install Install ClaudeDeck (auto-installs dependencies)"
472
+ echo " run Start server and open in browser"
473
+ echo " start Start the server in background"
474
+ echo " stop Stop the server"
475
+ echo " restart Restart the server"
476
+ echo " status Show server status and URLs"
477
+ echo " logs Tail server logs"
478
+ echo " update Update to latest version"
479
+ echo " enable Enable auto-start on boot"
480
+ echo " disable Disable auto-start"
481
+ echo " uninstall Remove ClaudeDeck completely"
482
+ echo ""
483
+ echo "Environment variables:"
484
+ echo " AGENT_OS_HOME Installation directory (default: ~/.claude-deck)"
485
+ echo " AGENT_OS_PORT Server port (default: 3011)"
486
+ echo ""
487
+ }
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env bash
2
+ # Common utilities for claude-deck scripts
3
+
4
+ # Colors
5
+ RED='\033[0;31m'
6
+ GREEN='\033[0;32m'
7
+ YELLOW='\033[1;33m'
8
+ BLUE='\033[0;34m'
9
+ NC='\033[0m'
10
+
11
+ # Logging
12
+ log_info() { echo -e "${BLUE}==>${NC} $1"; }
13
+ log_success() { echo -e "${GREEN}==>${NC} $1"; }
14
+ log_warn() { echo -e "${YELLOW}==>${NC} $1"; }
15
+ log_error() { echo -e "${RED}==>${NC} $1"; }
16
+
17
+ # OS Detection
18
+ detect_os() {
19
+ case "$(uname -s)" in
20
+ Darwin*)
21
+ echo "macos"
22
+ ;;
23
+ Linux*)
24
+ if [[ -f /etc/debian_version ]]; then
25
+ echo "debian"
26
+ elif [[ -f /etc/redhat-release ]]; then
27
+ echo "redhat"
28
+ else
29
+ echo "linux"
30
+ fi
31
+ ;;
32
+ *)
33
+ echo "unknown"
34
+ ;;
35
+ esac
36
+ }
37
+
38
+ # Check if running interactively
39
+ is_interactive() {
40
+ [[ -t 0 ]] && [[ -t 1 ]]
41
+ }
42
+
43
+ # Prompt for yes/no
44
+ prompt_yn() {
45
+ local prompt="$1"
46
+ local default="${2:-y}"
47
+
48
+ if ! is_interactive; then
49
+ [[ "$default" == "y" ]]
50
+ return
51
+ fi
52
+
53
+ local yn_prompt
54
+ if [[ "$default" == "y" ]]; then
55
+ yn_prompt="[Y/n]"
56
+ else
57
+ yn_prompt="[y/N]"
58
+ fi
59
+
60
+ read -p "$prompt $yn_prompt " -r response
61
+ response="${response:-$default}"
62
+
63
+ [[ "$response" =~ ^[Yy] ]]
64
+ }
65
+
66
+ # Process management helpers
67
+ get_pid() {
68
+ local pid_file="$AGENT_OS_HOME/claude-deck.pid"
69
+ if [[ -f "$pid_file" ]]; then
70
+ local pid
71
+ pid=$(cat "$pid_file")
72
+ if kill -0 "$pid" 2>/dev/null; then
73
+ echo "$pid"
74
+ return 0
75
+ fi
76
+ fi
77
+ return 1
78
+ }
79
+
80
+ is_running() {
81
+ get_pid &>/dev/null
82
+ }
83
+
84
+ # Get Tailscale IP if available
85
+ get_tailscale_ip() {
86
+ if command -v tailscale &> /dev/null; then
87
+ tailscale ip -4 2>/dev/null | head -1
88
+ fi
89
+ }