@atercates/claude-deck 0.2.9 → 0.2.11

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.
package/README.md CHANGED
@@ -2,12 +2,6 @@
2
2
 
3
3
  Self-hosted web UI for managing Claude Code sessions.
4
4
 
5
- [![Discord](https://img.shields.io/badge/Discord-Join%20us-5865F2?logo=discord&logoColor=white)](https://discord.gg/cSjutkCGAh)
6
-
7
- https://github.com/user-attachments/assets/0e2e66f7-037e-4739-99ec-608d1840df0a
8
-
9
- ![ClaudeDeck Screenshot](screenshot-v2.png)
10
-
11
5
  ## Installation
12
6
 
13
7
  ### Quick Install
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atercates/claude-deck",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "description": "Self-hosted web UI for managing Claude Code sessions",
5
5
  "bin": {
6
6
  "claude-deck": "./scripts/claude-deck"
@@ -2,16 +2,18 @@
2
2
  #
3
3
  # ClaudeDeck Installer
4
4
  #
5
- # Usage:
5
+ # Install:
6
6
  # curl -fsSL https://raw.githubusercontent.com/ATERCATES/claude-deck/main/scripts/install.sh | bash
7
7
  #
8
- # Or with options:
9
- # bash install.sh --port 3011 --ssh-host myserver.com --ssh-port 22
8
+ # Update:
9
+ # ~/.claude-deck/install.sh --update
10
+ #
11
+ # Options:
12
+ # --port 3011 --ssh-host myserver.com --ssh-port 22 -y
10
13
  #
11
14
 
12
15
  set -e
13
16
 
14
- # Colors
15
17
  RED='\033[0;31m'
16
18
  GREEN='\033[0;32m'
17
19
  BLUE='\033[0;34m'
@@ -26,27 +28,26 @@ log_warn() { echo -e "${YELLOW}==>${NC} $1"; }
26
28
  log_error() { echo -e "${RED}==>${NC} $1"; }
27
29
 
28
30
  INSTALL_DIR="$HOME/.claude-deck"
29
- REPO_URL="https://github.com/ATERCATES/claude-deck.git"
30
- NODE_MIN_VERSION=24
31
+ PKG="@atercates/claude-deck"
32
+ NODE_MIN=24
31
33
 
32
- # ─── Parse CLI flags ──────────────────────────────────────────────────────────
34
+ # ─── Parse flags ──────────────────────────────────────────────────────────────
33
35
 
34
- FLAG_PORT=""
35
- FLAG_SSH_HOST=""
36
- FLAG_SSH_PORT=""
37
- FLAG_NONINTERACTIVE=false
36
+ FLAG_PORT="" FLAG_SSH_HOST="" FLAG_SSH_PORT=""
37
+ FLAG_NONINTERACTIVE=false FLAG_UPDATE=false
38
38
 
39
39
  while [[ $# -gt 0 ]]; do
40
40
  case "$1" in
41
- --port) FLAG_PORT="$2"; shift 2 ;;
42
- --ssh-host) FLAG_SSH_HOST="$2"; shift 2 ;;
43
- --ssh-port) FLAG_SSH_PORT="$2"; shift 2 ;;
44
- --yes|-y) FLAG_NONINTERACTIVE=true; shift ;;
45
- *) shift ;;
41
+ --port) FLAG_PORT="$2"; shift 2 ;;
42
+ --ssh-host) FLAG_SSH_HOST="$2"; shift 2 ;;
43
+ --ssh-port) FLAG_SSH_PORT="$2"; shift 2 ;;
44
+ --yes|-y) FLAG_NONINTERACTIVE=true; shift ;;
45
+ --update|-u) FLAG_UPDATE=true; shift ;;
46
+ *) shift ;;
46
47
  esac
47
48
  done
48
49
 
49
- # ─── Interactive prompts ──────────────────────────────────────────────────────
50
+ # ─── Helpers ──────────────────────────────────────────────────────────────────
50
51
 
51
52
  ask() {
52
53
  local prompt="$1" default="$2" var="$3"
@@ -63,22 +64,104 @@ ask() {
63
64
  fi
64
65
  }
65
66
 
66
- # ─── Header ───────────────────────────────────────────────────────────────────
67
+ ensure_node() {
68
+ # Check PATH first, then ~/.n
69
+ [[ -x "$HOME/.n/bin/node" ]] && export PATH="$HOME/.n/bin:$PATH"
70
+
71
+ if command -v node &> /dev/null; then
72
+ local v=$(node --version | sed 's/v//' | cut -d. -f1)
73
+ if [[ "$v" -ge "$NODE_MIN" ]]; then
74
+ log_success "Node.js $(node --version) found"
75
+ return
76
+ fi
77
+ fi
78
+
79
+ log_info "Installing Node.js $NODE_MIN..."
80
+ local N_PREFIX="$HOME/.n"
81
+ mkdir -p "$N_PREFIX"
82
+ curl -fsSL https://raw.githubusercontent.com/tj/n/master/bin/n -o /tmp/n && chmod +x /tmp/n
83
+ N_PREFIX="$N_PREFIX" /tmp/n "$NODE_MIN" && rm -f /tmp/n
84
+ export PATH="$N_PREFIX/bin:$PATH"
85
+ log_success "Node.js $(node --version) installed"
86
+ }
87
+
88
+ ensure_pnpm() {
89
+ if command -v pnpm &> /dev/null; then
90
+ log_success "pnpm $(pnpm --version) found"
91
+ else
92
+ log_info "Installing pnpm..."
93
+ npm install -g pnpm > /dev/null 2>&1
94
+ log_success "pnpm $(pnpm --version) installed"
95
+ fi
96
+ }
97
+
98
+ pkg_dir() {
99
+ echo "$INSTALL_DIR/node_modules/$PKG"
100
+ }
101
+
102
+ pkg_version() {
103
+ node -e "console.log(require('$(pkg_dir)/package.json').version)" 2>/dev/null || echo "unknown"
104
+ }
105
+
106
+ # ─── Update ───────────────────────────────────────────────────────────────────
107
+
108
+ if [[ "$FLAG_UPDATE" == true ]]; then
109
+ echo ""
110
+ echo -e "${BOLD} ClaudeDeck Update${NC}"
111
+ echo ""
112
+
113
+ if [[ ! -d "$INSTALL_DIR/node_modules/$PKG" ]]; then
114
+ log_error "ClaudeDeck is not installed. Run without --update first."
115
+ exit 1
116
+ fi
117
+
118
+ ensure_node
119
+ cd "$INSTALL_DIR"
120
+
121
+ CURRENT=$(pkg_version)
122
+ log_info "Current version: $CURRENT"
123
+
124
+ log_info "Updating..."
125
+ pnpm update "$PKG" --latest 2>&1 | tail -3
126
+
127
+ NEW=$(pkg_version)
128
+ if [[ "$CURRENT" == "$NEW" ]]; then
129
+ log_success "Already on latest version ($NEW)"
130
+ else
131
+ log_success "Updated: $CURRENT -> $NEW"
132
+ fi
133
+
134
+ cd "$(pkg_dir)"
135
+ log_info "Installing dependencies..."
136
+ pnpm install > /dev/null 2>&1
137
+
138
+ log_info "Building..."
139
+ rm -f .next/build.lock
140
+ pnpm build 2>&1 | tail -5
141
+
142
+ if systemctl is-active --quiet claudedeck 2>/dev/null; then
143
+ log_info "Restarting service..."
144
+ sudo systemctl restart claudedeck
145
+ sleep 2
146
+ systemctl is-active --quiet claudedeck && log_success "ClaudeDeck $NEW running" || log_error "Failed. Check: sudo journalctl -u claudedeck -f"
147
+ else
148
+ log_success "ClaudeDeck $NEW ready. Start with: sudo systemctl start claudedeck"
149
+ fi
150
+
151
+ echo ""
152
+ exit 0
153
+ fi
154
+
155
+ # ─── Fresh install ────────────────────────────────────────────────────────────
67
156
 
68
157
  echo ""
69
158
  echo -e "${BOLD} ClaudeDeck Installer${NC}"
70
159
  echo -e "${DIM} Self-hosted web UI for Claude Code sessions${NC}"
71
160
  echo ""
72
161
 
73
- # ─── Check prerequisites ─────────────────────────────────────────────────────
74
-
162
+ # Prerequisites
75
163
  log_info "Checking prerequisites..."
76
164
 
77
- if ! command -v git &> /dev/null; then
78
- log_error "git is required. Install it with: sudo apt install git"
79
- exit 1
80
- fi
81
-
82
165
  if ! command -v tmux &> /dev/null; then
83
166
  log_warn "tmux is not installed (required for session management)"
84
167
  ask "Install tmux now? (y/n)" "y" INSTALL_TMUX
@@ -91,55 +174,10 @@ if ! command -v tmux &> /dev/null; then
91
174
  fi
92
175
  fi
93
176
 
94
- # ─── Node.js ──────────────────────────────────────────────────────────────────
95
-
96
- install_node() {
97
- log_info "Installing Node.js $NODE_MIN_VERSION..."
98
- local N_PREFIX="$HOME/.n"
99
- mkdir -p "$N_PREFIX"
100
- curl -fsSL https://raw.githubusercontent.com/tj/n/master/bin/n -o /tmp/n
101
- chmod +x /tmp/n
102
- N_PREFIX="$N_PREFIX" /tmp/n "$NODE_MIN_VERSION"
103
- rm -f /tmp/n
104
- export PATH="$N_PREFIX/bin:$PATH"
105
- log_success "Node.js $(node --version) installed"
106
- }
107
-
108
- # Check for existing node
109
- NODE_OK=false
110
- if command -v node &> /dev/null; then
111
- NODE_VERSION=$(node --version | sed 's/v//' | cut -d. -f1)
112
- if [[ "$NODE_VERSION" -ge "$NODE_MIN_VERSION" ]]; then
113
- NODE_OK=true
114
- log_success "Node.js $(node --version) found"
115
- fi
116
- fi
117
-
118
- # Check ~/.n/bin as well
119
- if [[ "$NODE_OK" == false ]] && [[ -x "$HOME/.n/bin/node" ]]; then
120
- export PATH="$HOME/.n/bin:$PATH"
121
- NODE_VERSION=$(node --version | sed 's/v//' | cut -d. -f1)
122
- if [[ "$NODE_VERSION" -ge "$NODE_MIN_VERSION" ]]; then
123
- NODE_OK=true
124
- log_success "Node.js $(node --version) found in ~/.n"
125
- fi
126
- fi
127
-
128
- if [[ "$NODE_OK" == false ]]; then
129
- install_node
130
- fi
131
-
132
- # pnpm
133
- if ! command -v pnpm &> /dev/null; then
134
- log_info "Installing pnpm..."
135
- npm install -g pnpm > /dev/null 2>&1
136
- log_success "pnpm $(pnpm --version) installed"
137
- else
138
- log_success "pnpm $(pnpm --version) found"
139
- fi
140
-
141
- # ─── Configuration ────────────────────────────────────────────────────────────
177
+ ensure_node
178
+ ensure_pnpm
142
179
 
180
+ # Configuration
143
181
  echo ""
144
182
  log_info "Configuration"
145
183
  echo ""
@@ -150,34 +188,27 @@ SSH_PORT="${FLAG_SSH_PORT}"
150
188
 
151
189
  ask "Port" "3011" PORT
152
190
  ask "SSH host for VS Code remote button (leave empty to skip)" "" SSH_HOST
153
-
154
- if [[ -n "$SSH_HOST" ]]; then
155
- ask "SSH port" "22" SSH_PORT
156
- fi
157
-
191
+ [[ -n "$SSH_HOST" ]] && ask "SSH port" "22" SSH_PORT
158
192
  echo ""
159
193
 
160
- # ─── Install ──────────────────────────────────────────────────────────────────
194
+ # Install package
195
+ mkdir -p "$INSTALL_DIR"
196
+ cd "$INSTALL_DIR"
161
197
 
162
- if [[ -d "$INSTALL_DIR/repo" ]]; then
163
- log_info "Updating existing installation..."
164
- cd "$INSTALL_DIR/repo"
165
- git pull --ff-only
166
- else
167
- log_info "Cloning ClaudeDeck..."
168
- mkdir -p "$INSTALL_DIR"
169
- git clone "$REPO_URL" "$INSTALL_DIR/repo"
170
- cd "$INSTALL_DIR/repo"
198
+ if [[ ! -f "package.json" ]]; then
199
+ echo '{"name":"claude-deck-instance","private":true}' > package.json
171
200
  fi
172
201
 
173
- # Dependencies
202
+ log_info "Installing $PKG from npm..."
203
+ pnpm add "$PKG" 2>&1 | tail -3
204
+
205
+ # Build inside the package directory
206
+ cd "$(pkg_dir)"
207
+
174
208
  log_info "Installing dependencies..."
175
209
  pnpm install > /dev/null 2>&1
176
210
 
177
- # Approve native builds if needed
178
- if grep -q "onlyBuiltDependencies" package.json 2>/dev/null; then
179
- : # already configured
180
- else
211
+ if ! grep -q "onlyBuiltDependencies" package.json 2>/dev/null; then
181
212
  node -e "
182
213
  const pkg = require('./package.json');
183
214
  pkg.pnpm = pkg.pnpm || {};
@@ -187,18 +218,12 @@ else
187
218
  pnpm install > /dev/null 2>&1
188
219
  fi
189
220
 
190
- # Write .env
221
+ # .env
191
222
  log_info "Writing .env..."
192
- cat > "$INSTALL_DIR/repo/.env" << EOF
193
- PORT=$PORT
194
- EOF
195
-
196
- if [[ -n "$SSH_HOST" ]]; then
197
- echo "SSH_HOST=$SSH_HOST" >> "$INSTALL_DIR/repo/.env"
198
- fi
199
- if [[ -n "$SSH_PORT" ]] && [[ "$SSH_PORT" != "22" ]]; then
200
- echo "SSH_PORT=$SSH_PORT" >> "$INSTALL_DIR/repo/.env"
201
- fi
223
+ ENV_FILE="$(pkg_dir)/.env"
224
+ echo "PORT=$PORT" > "$ENV_FILE"
225
+ [[ -n "$SSH_HOST" ]] && echo "SSH_HOST=$SSH_HOST" >> "$ENV_FILE"
226
+ [[ -n "$SSH_PORT" && "$SSH_PORT" != "22" ]] && echo "SSH_PORT=$SSH_PORT" >> "$ENV_FILE"
202
227
 
203
228
  # Build
204
229
  log_info "Building for production (this may take a minute)..."
@@ -210,21 +235,25 @@ if [[ ! -f "$HOME/.tmux.conf" ]] || ! grep -q "mouse on" "$HOME/.tmux.conf" 2>/d
210
235
  echo "set -g mouse on" >> "$HOME/.tmux.conf"
211
236
  fi
212
237
 
213
- # ─── Systemd service ─────────────────────────────────────────────────────────
238
+ # Copy install script for easy updates
239
+ cp "$(pkg_dir)/scripts/install.sh" "$INSTALL_DIR/install.sh" 2>/dev/null || true
214
240
 
241
+ # ─── Systemd ──────────────────────────────────────────────────────────────────
242
+
243
+ APP_DIR="$(pkg_dir)"
215
244
  NODE_BIN=$(which node)
216
- TSX_BIN="$INSTALL_DIR/repo/node_modules/.bin/tsx"
245
+ TSX_BIN="$APP_DIR/node_modules/.bin/tsx"
217
246
 
218
- SERVICE_FILE="[Unit]
247
+ SERVICE="[Unit]
219
248
  Description=ClaudeDeck
220
249
  After=network.target
221
250
 
222
251
  [Service]
223
252
  Type=simple
224
253
  User=$USER
225
- WorkingDirectory=$INSTALL_DIR/repo
254
+ WorkingDirectory=$APP_DIR
226
255
  Environment=NODE_ENV=production
227
- Environment=PATH=$(dirname "$NODE_BIN"):$INSTALL_DIR/repo/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
256
+ Environment=PATH=$(dirname "$NODE_BIN"):$APP_DIR/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
228
257
  ExecStart=$TSX_BIN --env-file=.env server.ts
229
258
  Restart=on-failure
230
259
  RestartSec=5
@@ -235,37 +264,33 @@ WantedBy=multi-user.target"
235
264
  INSTALL_SERVICE=false
236
265
  if [[ -t 0 ]] && [[ "$FLAG_NONINTERACTIVE" == false ]]; then
237
266
  echo ""
238
- ask "Install as systemd service? (y/n)" "y" INSTALL_SVC_ANSWER
239
- [[ "$INSTALL_SVC_ANSWER" == "y" ]] && INSTALL_SERVICE=true
267
+ ask "Install as systemd service? (y/n)" "y" SVC_ANSWER
268
+ [[ "$SVC_ANSWER" == "y" ]] && INSTALL_SERVICE=true
240
269
  else
241
270
  INSTALL_SERVICE=true
242
271
  fi
243
272
 
244
273
  if [[ "$INSTALL_SERVICE" == true ]]; then
245
274
  log_info "Installing systemd service..."
246
- echo "$SERVICE_FILE" | sudo tee /etc/systemd/system/claudedeck.service > /dev/null
275
+ echo "$SERVICE" | sudo tee /etc/systemd/system/claudedeck.service > /dev/null
247
276
  sudo systemctl daemon-reload
248
277
  sudo systemctl enable claudedeck > /dev/null 2>&1
249
278
  sudo systemctl restart claudedeck
250
279
  sleep 2
251
-
252
- if systemctl is-active --quiet claudedeck; then
253
- log_success "Service running on port $PORT"
254
- else
255
- log_error "Service failed to start. Check: sudo journalctl -u claudedeck -f"
256
- fi
280
+ systemctl is-active --quiet claudedeck && log_success "Service running on port $PORT" || log_error "Failed. Check: sudo journalctl -u claudedeck -f"
257
281
  fi
258
282
 
259
283
  # ─── Done ─────────────────────────────────────────────────────────────────────
260
284
 
285
+ VERSION=$(pkg_version)
286
+
261
287
  echo ""
262
- echo -e "${GREEN}${BOLD} ClaudeDeck installed!${NC}"
288
+ echo -e "${GREEN}${BOLD} ClaudeDeck${VERSION:+ v$VERSION} installed!${NC}"
263
289
  echo ""
264
290
  echo -e " ${BOLD}Local:${NC} http://localhost:$PORT"
265
- if [[ -n "$SSH_HOST" ]]; then
266
- echo -e " ${BOLD}Remote:${NC} Configure your reverse proxy to point to port $PORT"
267
- fi
291
+ [[ -n "$SSH_HOST" ]] && echo -e " ${BOLD}Remote:${NC} Configure your reverse proxy to point to port $PORT"
268
292
  echo ""
269
293
  echo -e " ${DIM}First visit will prompt you to create an account.${NC}"
270
- echo -e " ${DIM}Commands: sudo systemctl {start|stop|restart|status} claudedeck${NC}"
294
+ echo -e " ${DIM}Manage: sudo systemctl {start|stop|restart|status} claudedeck${NC}"
295
+ echo -e " ${DIM}Update: ~/.claude-deck/install.sh --update${NC}"
271
296
  echo ""