@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 +0 -6
- package/package.json +1 -1
- package/scripts/install.sh +148 -123
package/README.md
CHANGED
|
@@ -2,12 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Self-hosted web UI for managing Claude Code sessions.
|
|
4
4
|
|
|
5
|
-
[](https://discord.gg/cSjutkCGAh)
|
|
6
|
-
|
|
7
|
-
https://github.com/user-attachments/assets/0e2e66f7-037e-4739-99ec-608d1840df0a
|
|
8
|
-
|
|
9
|
-

|
|
10
|
-
|
|
11
5
|
## Installation
|
|
12
6
|
|
|
13
7
|
### Quick Install
|
package/package.json
CHANGED
package/scripts/install.sh
CHANGED
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
#
|
|
3
3
|
# ClaudeDeck Installer
|
|
4
4
|
#
|
|
5
|
-
#
|
|
5
|
+
# Install:
|
|
6
6
|
# curl -fsSL https://raw.githubusercontent.com/ATERCATES/claude-deck/main/scripts/install.sh | bash
|
|
7
7
|
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
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
|
-
|
|
30
|
-
|
|
31
|
+
PKG="@atercates/claude-deck"
|
|
32
|
+
NODE_MIN=24
|
|
31
33
|
|
|
32
|
-
# ─── Parse
|
|
34
|
+
# ─── Parse flags ──────────────────────────────────────────────────────────────
|
|
33
35
|
|
|
34
|
-
FLAG_PORT=""
|
|
35
|
-
|
|
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)
|
|
42
|
-
--ssh-host)
|
|
43
|
-
--ssh-port)
|
|
44
|
-
--yes|-y)
|
|
45
|
-
|
|
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
|
-
# ───
|
|
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
|
-
|
|
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
|
-
#
|
|
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
|
-
|
|
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
|
-
#
|
|
194
|
+
# Install package
|
|
195
|
+
mkdir -p "$INSTALL_DIR"
|
|
196
|
+
cd "$INSTALL_DIR"
|
|
161
197
|
|
|
162
|
-
if [[ -
|
|
163
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
221
|
+
# .env
|
|
191
222
|
log_info "Writing .env..."
|
|
192
|
-
|
|
193
|
-
PORT=$PORT
|
|
194
|
-
|
|
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
|
-
#
|
|
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="$
|
|
245
|
+
TSX_BIN="$APP_DIR/node_modules/.bin/tsx"
|
|
217
246
|
|
|
218
|
-
|
|
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=$
|
|
254
|
+
WorkingDirectory=$APP_DIR
|
|
226
255
|
Environment=NODE_ENV=production
|
|
227
|
-
Environment=PATH=$(dirname "$NODE_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"
|
|
239
|
-
[[ "$
|
|
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 "$
|
|
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
|
-
|
|
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}
|
|
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 ""
|