@atercates/claude-deck 0.2.10 → 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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/scripts/install.sh +97 -141
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atercates/claude-deck",
3
- "version": "0.2.10",
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,19 +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
- # Options:
9
- # bash install.sh --port 3011 --ssh-host myserver.com --ssh-port 22 -y
10
- #
11
8
  # Update:
12
- # bash install.sh --update
9
+ # ~/.claude-deck/install.sh --update
10
+ #
11
+ # Options:
12
+ # --port 3011 --ssh-host myserver.com --ssh-port 22 -y
13
13
  #
14
14
 
15
15
  set -e
16
16
 
17
- # Colors
18
17
  RED='\033[0;31m'
19
18
  GREEN='\033[0;32m'
20
19
  BLUE='\033[0;34m'
@@ -29,29 +28,26 @@ log_warn() { echo -e "${YELLOW}==>${NC} $1"; }
29
28
  log_error() { echo -e "${RED}==>${NC} $1"; }
30
29
 
31
30
  INSTALL_DIR="$HOME/.claude-deck"
32
- PKG_NAME="@atercates/claude-deck"
33
- NODE_MIN_VERSION=24
31
+ PKG="@atercates/claude-deck"
32
+ NODE_MIN=24
34
33
 
35
- # ─── Parse CLI flags ──────────────────────────────────────────────────────────
34
+ # ─── Parse flags ──────────────────────────────────────────────────────────────
36
35
 
37
- FLAG_PORT=""
38
- FLAG_SSH_HOST=""
39
- FLAG_SSH_PORT=""
40
- FLAG_NONINTERACTIVE=false
41
- FLAG_UPDATE=false
36
+ FLAG_PORT="" FLAG_SSH_HOST="" FLAG_SSH_PORT=""
37
+ FLAG_NONINTERACTIVE=false FLAG_UPDATE=false
42
38
 
43
39
  while [[ $# -gt 0 ]]; do
44
40
  case "$1" in
45
- --port) FLAG_PORT="$2"; shift 2 ;;
46
- --ssh-host) FLAG_SSH_HOST="$2"; shift 2 ;;
47
- --ssh-port) FLAG_SSH_PORT="$2"; shift 2 ;;
48
- --yes|-y) FLAG_NONINTERACTIVE=true; shift ;;
49
- --update|-u) FLAG_UPDATE=true; shift ;;
50
- *) 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 ;;
51
47
  esac
52
48
  done
53
49
 
54
- # ─── Interactive prompts ──────────────────────────────────────────────────────
50
+ # ─── Helpers ──────────────────────────────────────────────────────────────────
55
51
 
56
52
  ask() {
57
53
  local prompt="$1" default="$2" var="$3"
@@ -68,59 +64,86 @@ ask() {
68
64
  fi
69
65
  }
70
66
 
71
- # ─── Update mode ──────────────────────────────────────────────────────────────
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 ───────────────────────────────────────────────────────────────────
72
107
 
73
108
  if [[ "$FLAG_UPDATE" == true ]]; then
74
109
  echo ""
75
110
  echo -e "${BOLD} ClaudeDeck Update${NC}"
76
111
  echo ""
77
112
 
78
- if [[ ! -d "$INSTALL_DIR" ]]; then
113
+ if [[ ! -d "$INSTALL_DIR/node_modules/$PKG" ]]; then
79
114
  log_error "ClaudeDeck is not installed. Run without --update first."
80
115
  exit 1
81
116
  fi
82
117
 
83
- # Ensure node/pnpm in PATH
84
- [[ -x "$HOME/.n/bin/node" ]] && export PATH="$HOME/.n/bin:$PATH"
85
-
118
+ ensure_node
86
119
  cd "$INSTALL_DIR"
87
- CURRENT=$(node -e "console.log(require('./node_modules/$PKG_NAME/package.json').version)" 2>/dev/null || echo "unknown")
88
- log_info "Current version: $CURRENT"
89
120
 
90
- log_info "Updating $PKG_NAME..."
91
- pnpm update "$PKG_NAME" --latest 2>&1 | tail -3
121
+ CURRENT=$(pkg_version)
122
+ log_info "Current version: $CURRENT"
92
123
 
93
- NEW=$(node -e "console.log(require('./node_modules/$PKG_NAME/package.json').version)" 2>/dev/null || echo "unknown")
124
+ log_info "Updating..."
125
+ pnpm update "$PKG" --latest 2>&1 | tail -3
94
126
 
127
+ NEW=$(pkg_version)
95
128
  if [[ "$CURRENT" == "$NEW" ]]; then
96
129
  log_success "Already on latest version ($NEW)"
97
130
  else
98
131
  log_success "Updated: $CURRENT -> $NEW"
99
132
  fi
100
133
 
101
- # Copy source and rebuild
102
- log_info "Copying source..."
103
- rsync -a --delete \
104
- --exclude='node_modules' --exclude='.next' --exclude='.env' --exclude='*.db' --exclude='*.db-journal' \
105
- "$INSTALL_DIR/node_modules/$PKG_NAME/" "$INSTALL_DIR/app/"
106
-
107
- cd "$INSTALL_DIR/app"
134
+ cd "$(pkg_dir)"
108
135
  log_info "Installing dependencies..."
109
136
  pnpm install > /dev/null 2>&1
110
137
 
111
138
  log_info "Building..."
139
+ rm -f .next/build.lock
112
140
  pnpm build 2>&1 | tail -5
113
141
 
114
- # Restart service if running
115
142
  if systemctl is-active --quiet claudedeck 2>/dev/null; then
116
143
  log_info "Restarting service..."
117
144
  sudo systemctl restart claudedeck
118
145
  sleep 2
119
- if systemctl is-active --quiet claudedeck; then
120
- log_success "ClaudeDeck $NEW running"
121
- else
122
- log_error "Service failed to start. Check: sudo journalctl -u claudedeck -f"
123
- fi
146
+ systemctl is-active --quiet claudedeck && log_success "ClaudeDeck $NEW running" || log_error "Failed. Check: sudo journalctl -u claudedeck -f"
124
147
  else
125
148
  log_success "ClaudeDeck $NEW ready. Start with: sudo systemctl start claudedeck"
126
149
  fi
@@ -129,15 +152,14 @@ if [[ "$FLAG_UPDATE" == true ]]; then
129
152
  exit 0
130
153
  fi
131
154
 
132
- # ─── Header ───────────────────────────────────────────────────────────────────
155
+ # ─── Fresh install ────────────────────────────────────────────────────────────
133
156
 
134
157
  echo ""
135
158
  echo -e "${BOLD} ClaudeDeck Installer${NC}"
136
159
  echo -e "${DIM} Self-hosted web UI for Claude Code sessions${NC}"
137
160
  echo ""
138
161
 
139
- # ─── Check prerequisites ─────────────────────────────────────────────────────
140
-
162
+ # Prerequisites
141
163
  log_info "Checking prerequisites..."
142
164
 
143
165
  if ! command -v tmux &> /dev/null; then
@@ -152,53 +174,10 @@ if ! command -v tmux &> /dev/null; then
152
174
  fi
153
175
  fi
154
176
 
155
- # ─── Node.js ──────────────────────────────────────────────────────────────────
156
-
157
- install_node() {
158
- log_info "Installing Node.js $NODE_MIN_VERSION..."
159
- local N_PREFIX="$HOME/.n"
160
- mkdir -p "$N_PREFIX"
161
- curl -fsSL https://raw.githubusercontent.com/tj/n/master/bin/n -o /tmp/n
162
- chmod +x /tmp/n
163
- N_PREFIX="$N_PREFIX" /tmp/n "$NODE_MIN_VERSION"
164
- rm -f /tmp/n
165
- export PATH="$N_PREFIX/bin:$PATH"
166
- log_success "Node.js $(node --version) installed"
167
- }
168
-
169
- NODE_OK=false
170
- if command -v node &> /dev/null; then
171
- NODE_VERSION=$(node --version | sed 's/v//' | cut -d. -f1)
172
- if [[ "$NODE_VERSION" -ge "$NODE_MIN_VERSION" ]]; then
173
- NODE_OK=true
174
- log_success "Node.js $(node --version) found"
175
- fi
176
- fi
177
-
178
- if [[ "$NODE_OK" == false ]] && [[ -x "$HOME/.n/bin/node" ]]; then
179
- export PATH="$HOME/.n/bin:$PATH"
180
- NODE_VERSION=$(node --version | sed 's/v//' | cut -d. -f1)
181
- if [[ "$NODE_VERSION" -ge "$NODE_MIN_VERSION" ]]; then
182
- NODE_OK=true
183
- log_success "Node.js $(node --version) found in ~/.n"
184
- fi
185
- fi
186
-
187
- if [[ "$NODE_OK" == false ]]; then
188
- install_node
189
- fi
190
-
191
- # pnpm
192
- if ! command -v pnpm &> /dev/null; then
193
- log_info "Installing pnpm..."
194
- npm install -g pnpm > /dev/null 2>&1
195
- log_success "pnpm $(pnpm --version) installed"
196
- else
197
- log_success "pnpm $(pnpm --version) found"
198
- fi
199
-
200
- # ─── Configuration ────────────────────────────────────────────────────────────
177
+ ensure_node
178
+ ensure_pnpm
201
179
 
180
+ # Configuration
202
181
  echo ""
203
182
  log_info "Configuration"
204
183
  echo ""
@@ -209,39 +188,26 @@ SSH_PORT="${FLAG_SSH_PORT}"
209
188
 
210
189
  ask "Port" "3011" PORT
211
190
  ask "SSH host for VS Code remote button (leave empty to skip)" "" SSH_HOST
212
-
213
- if [[ -n "$SSH_HOST" ]]; then
214
- ask "SSH port" "22" SSH_PORT
215
- fi
216
-
191
+ [[ -n "$SSH_HOST" ]] && ask "SSH port" "22" SSH_PORT
217
192
  echo ""
218
193
 
219
- # ─── Install from npm ────────────────────────────────────────────────────────
220
-
194
+ # Install package
221
195
  mkdir -p "$INSTALL_DIR"
222
196
  cd "$INSTALL_DIR"
223
197
 
224
- # Initialize pnpm project if first install
225
198
  if [[ ! -f "package.json" ]]; then
226
199
  echo '{"name":"claude-deck-instance","private":true}' > package.json
227
200
  fi
228
201
 
229
- log_info "Installing $PKG_NAME from npm..."
230
- pnpm add "$PKG_NAME" 2>&1 | tail -3
202
+ log_info "Installing $PKG from npm..."
203
+ pnpm add "$PKG" 2>&1 | tail -3
231
204
 
232
- # Copy source to app directory (so we can build and run independently)
233
- log_info "Setting up application..."
234
- rsync -a --delete \
235
- --exclude='node_modules' --exclude='.next' --exclude='.env' --exclude='*.db' --exclude='*.db-journal' \
236
- "$INSTALL_DIR/node_modules/$PKG_NAME/" "$INSTALL_DIR/app/"
205
+ # Build inside the package directory
206
+ cd "$(pkg_dir)"
237
207
 
238
- cd "$INSTALL_DIR/app"
239
-
240
- # Dependencies
241
208
  log_info "Installing dependencies..."
242
209
  pnpm install > /dev/null 2>&1
243
210
 
244
- # Approve native builds if needed
245
211
  if ! grep -q "onlyBuiltDependencies" package.json 2>/dev/null; then
246
212
  node -e "
247
213
  const pkg = require('./package.json');
@@ -252,18 +218,12 @@ if ! grep -q "onlyBuiltDependencies" package.json 2>/dev/null; then
252
218
  pnpm install > /dev/null 2>&1
253
219
  fi
254
220
 
255
- # Write .env
221
+ # .env
256
222
  log_info "Writing .env..."
257
- cat > "$INSTALL_DIR/app/.env" << EOF
258
- PORT=$PORT
259
- EOF
260
-
261
- if [[ -n "$SSH_HOST" ]]; then
262
- echo "SSH_HOST=$SSH_HOST" >> "$INSTALL_DIR/app/.env"
263
- fi
264
- if [[ -n "$SSH_PORT" ]] && [[ "$SSH_PORT" != "22" ]]; then
265
- echo "SSH_PORT=$SSH_PORT" >> "$INSTALL_DIR/app/.env"
266
- 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"
267
227
 
268
228
  # Build
269
229
  log_info "Building for production (this may take a minute)..."
@@ -275,13 +235,16 @@ if [[ ! -f "$HOME/.tmux.conf" ]] || ! grep -q "mouse on" "$HOME/.tmux.conf" 2>/d
275
235
  echo "set -g mouse on" >> "$HOME/.tmux.conf"
276
236
  fi
277
237
 
278
- # ─── Systemd service ─────────────────────────────────────────────────────────
238
+ # Copy install script for easy updates
239
+ cp "$(pkg_dir)/scripts/install.sh" "$INSTALL_DIR/install.sh" 2>/dev/null || true
279
240
 
241
+ # ─── Systemd ──────────────────────────────────────────────────────────────────
242
+
243
+ APP_DIR="$(pkg_dir)"
280
244
  NODE_BIN=$(which node)
281
- TSX_BIN="$INSTALL_DIR/app/node_modules/.bin/tsx"
282
- APP_DIR="$INSTALL_DIR/app"
245
+ TSX_BIN="$APP_DIR/node_modules/.bin/tsx"
283
246
 
284
- SERVICE_FILE="[Unit]
247
+ SERVICE="[Unit]
285
248
  Description=ClaudeDeck
286
249
  After=network.target
287
250
 
@@ -301,40 +264,33 @@ WantedBy=multi-user.target"
301
264
  INSTALL_SERVICE=false
302
265
  if [[ -t 0 ]] && [[ "$FLAG_NONINTERACTIVE" == false ]]; then
303
266
  echo ""
304
- ask "Install as systemd service? (y/n)" "y" INSTALL_SVC_ANSWER
305
- [[ "$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
306
269
  else
307
270
  INSTALL_SERVICE=true
308
271
  fi
309
272
 
310
273
  if [[ "$INSTALL_SERVICE" == true ]]; then
311
274
  log_info "Installing systemd service..."
312
- echo "$SERVICE_FILE" | sudo tee /etc/systemd/system/claudedeck.service > /dev/null
275
+ echo "$SERVICE" | sudo tee /etc/systemd/system/claudedeck.service > /dev/null
313
276
  sudo systemctl daemon-reload
314
277
  sudo systemctl enable claudedeck > /dev/null 2>&1
315
278
  sudo systemctl restart claudedeck
316
279
  sleep 2
317
-
318
- if systemctl is-active --quiet claudedeck; then
319
- log_success "Service running on port $PORT"
320
- else
321
- log_error "Service failed to start. Check: sudo journalctl -u claudedeck -f"
322
- fi
280
+ systemctl is-active --quiet claudedeck && log_success "Service running on port $PORT" || log_error "Failed. Check: sudo journalctl -u claudedeck -f"
323
281
  fi
324
282
 
325
283
  # ─── Done ─────────────────────────────────────────────────────────────────────
326
284
 
327
- VERSION=$(node -e "console.log(require('./package.json').version)" 2>/dev/null || echo "")
285
+ VERSION=$(pkg_version)
328
286
 
329
287
  echo ""
330
288
  echo -e "${GREEN}${BOLD} ClaudeDeck${VERSION:+ v$VERSION} installed!${NC}"
331
289
  echo ""
332
290
  echo -e " ${BOLD}Local:${NC} http://localhost:$PORT"
333
- if [[ -n "$SSH_HOST" ]]; then
334
- echo -e " ${BOLD}Remote:${NC} Configure your reverse proxy to point to port $PORT"
335
- fi
291
+ [[ -n "$SSH_HOST" ]] && echo -e " ${BOLD}Remote:${NC} Configure your reverse proxy to point to port $PORT"
336
292
  echo ""
337
293
  echo -e " ${DIM}First visit will prompt you to create an account.${NC}"
338
294
  echo -e " ${DIM}Manage: sudo systemctl {start|stop|restart|status} claudedeck${NC}"
339
- echo -e " ${DIM}Update: bash install.sh --update${NC}"
295
+ echo -e " ${DIM}Update: ~/.claude-deck/install.sh --update${NC}"
340
296
  echo ""