tlc-claude-code 1.8.1 → 1.8.2
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/.claude/commands/tlc/dashboard.md +138 -0
- package/CLAUDE.md +1 -0
- package/docker-compose.dev.yml +3 -22
- package/package.json +1 -1
- package/server/lib/output-schemas.test.js +15 -1
- package/server/setup.sh +271 -271
- package/templates/docker-compose.tlc.yml +38 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# /tlc:dashboard - TLC Dashboard Container
|
|
2
|
+
|
|
3
|
+
Manage the TLC dashboard as a standalone Docker container in any project.
|
|
4
|
+
|
|
5
|
+
## Instructions for Claude
|
|
6
|
+
|
|
7
|
+
### Step 1: Parse Arguments
|
|
8
|
+
|
|
9
|
+
The user may pass a subcommand:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
/tlc:dashboard → start (default)
|
|
13
|
+
/tlc:dashboard stop → stop
|
|
14
|
+
/tlc:dashboard rebuild → rebuild with latest TLC
|
|
15
|
+
/tlc:dashboard logs → tail logs
|
|
16
|
+
/tlc:dashboard status → show container status
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Step 2: Ensure docker-compose.tlc.yml Exists
|
|
20
|
+
|
|
21
|
+
Check if `docker-compose.tlc.yml` exists in the project root.
|
|
22
|
+
|
|
23
|
+
**If it does NOT exist:**
|
|
24
|
+
|
|
25
|
+
1. Find the TLC package directory:
|
|
26
|
+
```bash
|
|
27
|
+
TLC_DIR=$(node -e "try { console.log(require.resolve('tlc-claude-code/package.json').replace('/package.json','')) } catch(e) { console.log('') }")
|
|
28
|
+
```
|
|
29
|
+
If empty, try global:
|
|
30
|
+
```bash
|
|
31
|
+
TLC_DIR=$(npm root -g)/tlc-claude-code
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
2. Copy the template:
|
|
35
|
+
```bash
|
|
36
|
+
cp "$TLC_DIR/templates/docker-compose.tlc.yml" ./docker-compose.tlc.yml
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
3. If template not found, generate it inline (see Template section below).
|
|
40
|
+
|
|
41
|
+
4. Tell the user:
|
|
42
|
+
```
|
|
43
|
+
Created docker-compose.tlc.yml in your project root.
|
|
44
|
+
This file is YOURS — customize it freely. TLC will never overwrite it.
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**If it already exists:** Use it as-is. Never modify the user's file.
|
|
48
|
+
|
|
49
|
+
### Step 3: Execute Subcommand
|
|
50
|
+
|
|
51
|
+
**start (default):**
|
|
52
|
+
```bash
|
|
53
|
+
docker compose -f docker-compose.tlc.yml up -d
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Then show:
|
|
57
|
+
```
|
|
58
|
+
TLC Dashboard running at http://localhost:3147
|
|
59
|
+
|
|
60
|
+
Stop: /tlc:dashboard stop
|
|
61
|
+
Logs: /tlc:dashboard logs
|
|
62
|
+
Rebuild: /tlc:dashboard rebuild
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**stop:**
|
|
66
|
+
```bash
|
|
67
|
+
docker compose -f docker-compose.tlc.yml down
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**rebuild:**
|
|
71
|
+
```bash
|
|
72
|
+
docker compose -f docker-compose.tlc.yml build --no-cache
|
|
73
|
+
docker compose -f docker-compose.tlc.yml up -d
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**logs:**
|
|
77
|
+
```bash
|
|
78
|
+
docker compose -f docker-compose.tlc.yml logs -f --tail 50 dashboard
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**status:**
|
|
82
|
+
```bash
|
|
83
|
+
docker compose -f docker-compose.tlc.yml ps
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Step 4: Verify
|
|
87
|
+
|
|
88
|
+
After `start` or `rebuild`, check the dashboard is serving the React SPA:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Wait a few seconds for startup
|
|
92
|
+
sleep 5
|
|
93
|
+
curl -s http://localhost:3147 | head -5
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
If it contains `<div id="root">` → React SPA is running.
|
|
97
|
+
If it contains the old static HTML → warn the user that TLC needs updating.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Template
|
|
102
|
+
|
|
103
|
+
The `docker-compose.tlc.yml` template contains only the dashboard service:
|
|
104
|
+
|
|
105
|
+
```yaml
|
|
106
|
+
# TLC Dashboard
|
|
107
|
+
# This file is yours — customize freely. TLC will never overwrite it.
|
|
108
|
+
# Docs: https://github.com/jurgencalleja/TLC/wiki/devserver
|
|
109
|
+
|
|
110
|
+
services:
|
|
111
|
+
dashboard:
|
|
112
|
+
image: node:20-alpine
|
|
113
|
+
container_name: tlc-dashboard
|
|
114
|
+
working_dir: /project
|
|
115
|
+
command: >
|
|
116
|
+
sh -c "
|
|
117
|
+
npm install -g tlc-claude-code@latest &&
|
|
118
|
+
TLC_DIR=$$(npm root -g)/tlc-claude-code &&
|
|
119
|
+
cd /project && node $$TLC_DIR/server/index.js
|
|
120
|
+
"
|
|
121
|
+
environment:
|
|
122
|
+
- TLC_PORT=3147
|
|
123
|
+
- TLC_AUTH=false
|
|
124
|
+
ports:
|
|
125
|
+
- "${DASHBOARD_PORT:-3147}:3147"
|
|
126
|
+
volumes:
|
|
127
|
+
- .:/project
|
|
128
|
+
restart: on-failure
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Important Notes
|
|
134
|
+
|
|
135
|
+
- The compose file belongs to the USER. Never overwrite or modify it.
|
|
136
|
+
- If the user has customized ports, environment, or volumes — respect that.
|
|
137
|
+
- The dashboard serves the React SPA from `dashboard-web/dist/` (included in npm package since v1.8.1).
|
|
138
|
+
- This is independent from `/tlc:start` which manages the full dev environment (app, db, storage).
|
package/CLAUDE.md
CHANGED
|
@@ -96,6 +96,7 @@ Every TLC command is defined in `.claude/commands/tlc/*.md`. When you invoke a c
|
|
|
96
96
|
| "issues", "import issues" | `/tlc:issues` | Manual issue tracking |
|
|
97
97
|
| "checklist", "full check" | `/tlc:checklist` | Ad-hoc project review |
|
|
98
98
|
| "quick task", "small fix" | `/tlc:quick` | Coding without tests |
|
|
99
|
+
| "dashboard", "start dashboard", "dashboard container" | `/tlc:dashboard` | Running docker-compose manually |
|
|
99
100
|
|
|
100
101
|
### Before ANY work — run `/tlc`
|
|
101
102
|
|
package/docker-compose.dev.yml
CHANGED
|
@@ -94,7 +94,8 @@ services:
|
|
|
94
94
|
retries: 5
|
|
95
95
|
restart: on-failure
|
|
96
96
|
|
|
97
|
-
# TLC Dashboard
|
|
97
|
+
# TLC Dashboard (Express API + React SPA on port 3147)
|
|
98
|
+
# Since v1.8.1, the server serves the React dashboard from dashboard-web/dist/
|
|
98
99
|
dashboard:
|
|
99
100
|
image: node:20-alpine
|
|
100
101
|
container_name: tlc-${COMPOSE_PROJECT_NAME:-dev}-dashboard
|
|
@@ -105,7 +106,7 @@ services:
|
|
|
105
106
|
npm install -g tlc-claude-code@latest &&
|
|
106
107
|
TLC_DIR=/usr/local/lib/node_modules/tlc-claude-code &&
|
|
107
108
|
echo 'TLC installed at:' $$TLC_DIR &&
|
|
108
|
-
ls
|
|
109
|
+
ls $$TLC_DIR/dashboard-web/dist/index.html && echo '[TLC] React SPA ready' || echo '[TLC] WARNING: dashboard-web/dist not found' &&
|
|
109
110
|
cd /project && node $$TLC_DIR/server/index.js --proxy-only --skip-db
|
|
110
111
|
"
|
|
111
112
|
environment:
|
|
@@ -121,26 +122,6 @@ services:
|
|
|
121
122
|
- app
|
|
122
123
|
restart: on-failure
|
|
123
124
|
|
|
124
|
-
# TLC Dashboard Web (built from dashboard-web, serves static files via nginx)
|
|
125
|
-
dashboard-web:
|
|
126
|
-
build:
|
|
127
|
-
context: ./dashboard-web
|
|
128
|
-
dockerfile: Dockerfile
|
|
129
|
-
container_name: tlc-${COMPOSE_PROJECT_NAME:-dev}-dashboard-web
|
|
130
|
-
ports:
|
|
131
|
-
- "${DASHBOARD_WEB_PORT:-3002}:80"
|
|
132
|
-
environment:
|
|
133
|
-
- API_URL=http://dashboard:3147
|
|
134
|
-
depends_on:
|
|
135
|
-
- dashboard
|
|
136
|
-
restart: on-failure
|
|
137
|
-
healthcheck:
|
|
138
|
-
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:80/health"]
|
|
139
|
-
interval: 30s
|
|
140
|
-
timeout: 3s
|
|
141
|
-
start_period: 5s
|
|
142
|
-
retries: 3
|
|
143
|
-
|
|
144
125
|
# Playwright E2E Tests (optional - starts on demand)
|
|
145
126
|
playwright:
|
|
146
127
|
image: mcr.microsoft.com/playwright:v1.40.0-jammy
|
package/package.json
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { mkdirSync, writeFileSync, rmSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
2
4
|
import {
|
|
3
5
|
loadSchema,
|
|
4
6
|
validateOutput,
|
|
@@ -9,8 +11,20 @@ import {
|
|
|
9
11
|
schemaToPromptInstructions,
|
|
10
12
|
} from './output-schemas.js';
|
|
11
13
|
|
|
14
|
+
const schemasDir = join(process.cwd(), '.tlc', 'schemas');
|
|
15
|
+
const testSchema = { type: 'object', required: ['summary'], properties: { summary: { type: 'string' } } };
|
|
16
|
+
|
|
12
17
|
describe('Output Schemas', () => {
|
|
13
18
|
describe('loadSchema', () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
mkdirSync(schemasDir, { recursive: true });
|
|
21
|
+
writeFileSync(join(schemasDir, 'review-result.json'), JSON.stringify(testSchema));
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
rmSync(join(schemasDir, 'review-result.json'), { force: true });
|
|
26
|
+
});
|
|
27
|
+
|
|
14
28
|
it('reads from file', async () => {
|
|
15
29
|
const schema = await loadSchema('review-result');
|
|
16
30
|
expect(schema).toBeDefined();
|
package/server/setup.sh
CHANGED
|
@@ -1,271 +1,271 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
#
|
|
3
|
-
# TLC Server Setup Script
|
|
4
|
-
# Installs Docker and other requirements for TLC dev server
|
|
5
|
-
#
|
|
6
|
-
# Usage: sudo ./setup.sh
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
set -e
|
|
10
|
-
|
|
11
|
-
# Colors for output
|
|
12
|
-
RED='\033[0;31m'
|
|
13
|
-
GREEN='\033[0;32m'
|
|
14
|
-
YELLOW='\033[1;33m'
|
|
15
|
-
NC='\033[0m' # No Color
|
|
16
|
-
|
|
17
|
-
log_info() {
|
|
18
|
-
echo -e "${GREEN}[TLC]${NC} $1"
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
log_warn() {
|
|
22
|
-
echo -e "${YELLOW}[TLC]${NC} $1"
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
log_error() {
|
|
26
|
-
echo -e "${RED}[TLC]${NC} $1"
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
# Check if running as root
|
|
30
|
-
if [ "$EUID" -ne 0 ]; then
|
|
31
|
-
log_error "Please run with sudo: sudo ./setup.sh"
|
|
32
|
-
exit 1
|
|
33
|
-
fi
|
|
34
|
-
|
|
35
|
-
# Get the actual user (not root)
|
|
36
|
-
ACTUAL_USER=${SUDO_USER:-$USER}
|
|
37
|
-
if [ "$ACTUAL_USER" = "root" ]; then
|
|
38
|
-
log_error "Please run as a regular user with sudo, not as root directly"
|
|
39
|
-
exit 1
|
|
40
|
-
fi
|
|
41
|
-
|
|
42
|
-
log_info "Setting up TLC server requirements for user: $ACTUAL_USER"
|
|
43
|
-
|
|
44
|
-
# Detect OS
|
|
45
|
-
detect_os() {
|
|
46
|
-
if [ -f /etc/os-release ]; then
|
|
47
|
-
. /etc/os-release
|
|
48
|
-
OS=$ID
|
|
49
|
-
OS_VERSION=$VERSION_ID
|
|
50
|
-
elif [ "$(uname)" = "Darwin" ]; then
|
|
51
|
-
OS="macos"
|
|
52
|
-
OS_VERSION=$(sw_vers -productVersion)
|
|
53
|
-
else
|
|
54
|
-
OS="unknown"
|
|
55
|
-
fi
|
|
56
|
-
echo "$OS"
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
OS=$(detect_os)
|
|
60
|
-
log_info "Detected OS: $OS"
|
|
61
|
-
|
|
62
|
-
# Install Docker based on OS
|
|
63
|
-
install_docker() {
|
|
64
|
-
if command -v docker &> /dev/null; then
|
|
65
|
-
log_info "Docker already installed: $(docker --version)"
|
|
66
|
-
return 0
|
|
67
|
-
fi
|
|
68
|
-
|
|
69
|
-
log_info "Installing Docker..."
|
|
70
|
-
|
|
71
|
-
case $OS in
|
|
72
|
-
ubuntu|debian|pop)
|
|
73
|
-
# Remove old versions
|
|
74
|
-
apt-get remove -y docker docker-engine docker.io containerd runc 2>/dev/null || true
|
|
75
|
-
|
|
76
|
-
# Install prerequisites
|
|
77
|
-
apt-get update
|
|
78
|
-
apt-get install -y \
|
|
79
|
-
ca-certificates \
|
|
80
|
-
curl \
|
|
81
|
-
gnupg \
|
|
82
|
-
lsb-release
|
|
83
|
-
|
|
84
|
-
# Add Docker's official GPG key
|
|
85
|
-
install -m 0755 -d /etc/apt/keyrings
|
|
86
|
-
curl -fsSL https://download.docker.com/linux/$OS/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
|
87
|
-
chmod a+r /etc/apt/keyrings/docker.gpg
|
|
88
|
-
|
|
89
|
-
# Set up repository
|
|
90
|
-
echo \
|
|
91
|
-
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$OS \
|
|
92
|
-
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
93
|
-
|
|
94
|
-
# Install Docker
|
|
95
|
-
apt-get update
|
|
96
|
-
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|
97
|
-
|
|
98
|
-
log_info "Docker installed successfully"
|
|
99
|
-
;;
|
|
100
|
-
|
|
101
|
-
fedora|rhel|centos)
|
|
102
|
-
# Install prerequisites
|
|
103
|
-
dnf -y install dnf-plugins-core
|
|
104
|
-
|
|
105
|
-
# Add Docker repo
|
|
106
|
-
dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
|
|
107
|
-
|
|
108
|
-
# Install Docker
|
|
109
|
-
dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|
110
|
-
|
|
111
|
-
log_info "Docker installed successfully"
|
|
112
|
-
;;
|
|
113
|
-
|
|
114
|
-
arch|manjaro)
|
|
115
|
-
pacman -S --noconfirm docker docker-compose
|
|
116
|
-
log_info "Docker installed successfully"
|
|
117
|
-
;;
|
|
118
|
-
|
|
119
|
-
macos)
|
|
120
|
-
log_warn "Please install Docker Desktop from https://www.docker.com/products/docker-desktop"
|
|
121
|
-
log_warn "After installation, enable WSL integration if using WSL"
|
|
122
|
-
return 1
|
|
123
|
-
;;
|
|
124
|
-
|
|
125
|
-
*)
|
|
126
|
-
log_error "Unsupported OS: $OS"
|
|
127
|
-
log_error "Please install Docker manually: https://docs.docker.com/engine/install/"
|
|
128
|
-
return 1
|
|
129
|
-
;;
|
|
130
|
-
esac
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
# Configure Docker for non-root access
|
|
134
|
-
configure_docker_user() {
|
|
135
|
-
log_info "Configuring Docker for user: $ACTUAL_USER"
|
|
136
|
-
|
|
137
|
-
# Add user to docker group
|
|
138
|
-
if ! getent group docker > /dev/null; then
|
|
139
|
-
groupadd docker
|
|
140
|
-
fi
|
|
141
|
-
|
|
142
|
-
usermod -aG docker "$ACTUAL_USER"
|
|
143
|
-
log_info "Added $ACTUAL_USER to docker group"
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
# Start Docker service
|
|
147
|
-
start_docker() {
|
|
148
|
-
log_info "Starting Docker service..."
|
|
149
|
-
|
|
150
|
-
# Check if systemd is available (native Linux)
|
|
151
|
-
if command -v systemctl &> /dev/null && systemctl is-system-running &> /dev/null; then
|
|
152
|
-
systemctl enable docker
|
|
153
|
-
systemctl start docker
|
|
154
|
-
# Check if we're in WSL
|
|
155
|
-
elif grep -qi microsoft /proc/version 2>/dev/null; then
|
|
156
|
-
# WSL - use service command
|
|
157
|
-
service docker start || true
|
|
158
|
-
else
|
|
159
|
-
# Try service command as fallback
|
|
160
|
-
service docker start || true
|
|
161
|
-
fi
|
|
162
|
-
|
|
163
|
-
# Wait for Docker to be ready
|
|
164
|
-
log_info "Waiting for Docker to be ready..."
|
|
165
|
-
for i in {1..30}; do
|
|
166
|
-
if docker info &> /dev/null; then
|
|
167
|
-
log_info "Docker is ready"
|
|
168
|
-
return 0
|
|
169
|
-
fi
|
|
170
|
-
sleep 1
|
|
171
|
-
done
|
|
172
|
-
|
|
173
|
-
log_warn "Docker may not be fully started. You might need to restart your terminal or run: sudo service docker start"
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
# Pull PostgreSQL image
|
|
177
|
-
pull_postgres_image() {
|
|
178
|
-
log_info "Pulling PostgreSQL image (this may take a moment)..."
|
|
179
|
-
|
|
180
|
-
# Run as the actual user to ensure proper permissions
|
|
181
|
-
su - "$ACTUAL_USER" -c "docker pull postgres:16-alpine" 2>/dev/null || \
|
|
182
|
-
docker pull postgres:16-alpine
|
|
183
|
-
|
|
184
|
-
log_info "PostgreSQL image ready"
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
# Install Node.js if not present
|
|
188
|
-
install_nodejs() {
|
|
189
|
-
if command -v node &> /dev/null; then
|
|
190
|
-
NODE_VERSION=$(node --version)
|
|
191
|
-
log_info "Node.js already installed: $NODE_VERSION"
|
|
192
|
-
return 0
|
|
193
|
-
fi
|
|
194
|
-
|
|
195
|
-
log_info "Installing Node.js..."
|
|
196
|
-
|
|
197
|
-
case $OS in
|
|
198
|
-
ubuntu|debian|pop)
|
|
199
|
-
# Install Node.js 20.x LTS
|
|
200
|
-
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
|
|
201
|
-
apt-get install -y nodejs
|
|
202
|
-
;;
|
|
203
|
-
|
|
204
|
-
fedora|rhel|centos)
|
|
205
|
-
curl -fsSL https://rpm.nodesource.com/setup_20.x | bash -
|
|
206
|
-
dnf install -y nodejs
|
|
207
|
-
;;
|
|
208
|
-
|
|
209
|
-
arch|manjaro)
|
|
210
|
-
pacman -S --noconfirm nodejs npm
|
|
211
|
-
;;
|
|
212
|
-
|
|
213
|
-
macos)
|
|
214
|
-
log_warn "Please install Node.js from https://nodejs.org/"
|
|
215
|
-
return 1
|
|
216
|
-
;;
|
|
217
|
-
|
|
218
|
-
*)
|
|
219
|
-
log_warn "Please install Node.js manually: https://nodejs.org/"
|
|
220
|
-
return 1
|
|
221
|
-
;;
|
|
222
|
-
esac
|
|
223
|
-
|
|
224
|
-
log_info "Node.js installed: $(node --version)"
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
# Main setup
|
|
228
|
-
main() {
|
|
229
|
-
echo ""
|
|
230
|
-
echo " ████████╗██╗ ██████╗"
|
|
231
|
-
echo " ╚══██╔══╝██║ ██╔════╝"
|
|
232
|
-
echo " ██║ ██║ ██║"
|
|
233
|
-
echo " ██║ ██║ ██║"
|
|
234
|
-
echo " ██║ ███████╗╚██████╗"
|
|
235
|
-
echo " ╚═╝ ╚══════╝ ╚═════╝"
|
|
236
|
-
echo ""
|
|
237
|
-
echo " TLC Server Setup"
|
|
238
|
-
echo ""
|
|
239
|
-
|
|
240
|
-
# Install Docker
|
|
241
|
-
install_docker
|
|
242
|
-
|
|
243
|
-
# Configure Docker for user
|
|
244
|
-
configure_docker_user
|
|
245
|
-
|
|
246
|
-
# Start Docker
|
|
247
|
-
start_docker
|
|
248
|
-
|
|
249
|
-
# Pull PostgreSQL image
|
|
250
|
-
pull_postgres_image
|
|
251
|
-
|
|
252
|
-
# Check/install Node.js
|
|
253
|
-
install_nodejs
|
|
254
|
-
|
|
255
|
-
echo ""
|
|
256
|
-
log_info "=========================================="
|
|
257
|
-
log_info "Setup complete!"
|
|
258
|
-
log_info "=========================================="
|
|
259
|
-
echo ""
|
|
260
|
-
log_info "IMPORTANT: Log out and log back in (or restart your terminal)"
|
|
261
|
-
log_info "for Docker group permissions to take effect."
|
|
262
|
-
echo ""
|
|
263
|
-
log_info "Then you can run TLC server with:"
|
|
264
|
-
log_info " cd your-project && npx tlc-claude-code server"
|
|
265
|
-
echo ""
|
|
266
|
-
log_info "Or test Docker now with:"
|
|
267
|
-
log_info " sudo docker run hello-world"
|
|
268
|
-
echo ""
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
main "$@"
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# TLC Server Setup Script
|
|
4
|
+
# Installs Docker and other requirements for TLC dev server
|
|
5
|
+
#
|
|
6
|
+
# Usage: sudo ./setup.sh
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
set -e
|
|
10
|
+
|
|
11
|
+
# Colors for output
|
|
12
|
+
RED='\033[0;31m'
|
|
13
|
+
GREEN='\033[0;32m'
|
|
14
|
+
YELLOW='\033[1;33m'
|
|
15
|
+
NC='\033[0m' # No Color
|
|
16
|
+
|
|
17
|
+
log_info() {
|
|
18
|
+
echo -e "${GREEN}[TLC]${NC} $1"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
log_warn() {
|
|
22
|
+
echo -e "${YELLOW}[TLC]${NC} $1"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
log_error() {
|
|
26
|
+
echo -e "${RED}[TLC]${NC} $1"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# Check if running as root
|
|
30
|
+
if [ "$EUID" -ne 0 ]; then
|
|
31
|
+
log_error "Please run with sudo: sudo ./setup.sh"
|
|
32
|
+
exit 1
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# Get the actual user (not root)
|
|
36
|
+
ACTUAL_USER=${SUDO_USER:-$USER}
|
|
37
|
+
if [ "$ACTUAL_USER" = "root" ]; then
|
|
38
|
+
log_error "Please run as a regular user with sudo, not as root directly"
|
|
39
|
+
exit 1
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
log_info "Setting up TLC server requirements for user: $ACTUAL_USER"
|
|
43
|
+
|
|
44
|
+
# Detect OS
|
|
45
|
+
detect_os() {
|
|
46
|
+
if [ -f /etc/os-release ]; then
|
|
47
|
+
. /etc/os-release
|
|
48
|
+
OS=$ID
|
|
49
|
+
OS_VERSION=$VERSION_ID
|
|
50
|
+
elif [ "$(uname)" = "Darwin" ]; then
|
|
51
|
+
OS="macos"
|
|
52
|
+
OS_VERSION=$(sw_vers -productVersion)
|
|
53
|
+
else
|
|
54
|
+
OS="unknown"
|
|
55
|
+
fi
|
|
56
|
+
echo "$OS"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
OS=$(detect_os)
|
|
60
|
+
log_info "Detected OS: $OS"
|
|
61
|
+
|
|
62
|
+
# Install Docker based on OS
|
|
63
|
+
install_docker() {
|
|
64
|
+
if command -v docker &> /dev/null; then
|
|
65
|
+
log_info "Docker already installed: $(docker --version)"
|
|
66
|
+
return 0
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
log_info "Installing Docker..."
|
|
70
|
+
|
|
71
|
+
case $OS in
|
|
72
|
+
ubuntu|debian|pop)
|
|
73
|
+
# Remove old versions
|
|
74
|
+
apt-get remove -y docker docker-engine docker.io containerd runc 2>/dev/null || true
|
|
75
|
+
|
|
76
|
+
# Install prerequisites
|
|
77
|
+
apt-get update
|
|
78
|
+
apt-get install -y \
|
|
79
|
+
ca-certificates \
|
|
80
|
+
curl \
|
|
81
|
+
gnupg \
|
|
82
|
+
lsb-release
|
|
83
|
+
|
|
84
|
+
# Add Docker's official GPG key
|
|
85
|
+
install -m 0755 -d /etc/apt/keyrings
|
|
86
|
+
curl -fsSL https://download.docker.com/linux/$OS/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
|
87
|
+
chmod a+r /etc/apt/keyrings/docker.gpg
|
|
88
|
+
|
|
89
|
+
# Set up repository
|
|
90
|
+
echo \
|
|
91
|
+
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$OS \
|
|
92
|
+
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
93
|
+
|
|
94
|
+
# Install Docker
|
|
95
|
+
apt-get update
|
|
96
|
+
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|
97
|
+
|
|
98
|
+
log_info "Docker installed successfully"
|
|
99
|
+
;;
|
|
100
|
+
|
|
101
|
+
fedora|rhel|centos)
|
|
102
|
+
# Install prerequisites
|
|
103
|
+
dnf -y install dnf-plugins-core
|
|
104
|
+
|
|
105
|
+
# Add Docker repo
|
|
106
|
+
dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
|
|
107
|
+
|
|
108
|
+
# Install Docker
|
|
109
|
+
dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|
110
|
+
|
|
111
|
+
log_info "Docker installed successfully"
|
|
112
|
+
;;
|
|
113
|
+
|
|
114
|
+
arch|manjaro)
|
|
115
|
+
pacman -S --noconfirm docker docker-compose
|
|
116
|
+
log_info "Docker installed successfully"
|
|
117
|
+
;;
|
|
118
|
+
|
|
119
|
+
macos)
|
|
120
|
+
log_warn "Please install Docker Desktop from https://www.docker.com/products/docker-desktop"
|
|
121
|
+
log_warn "After installation, enable WSL integration if using WSL"
|
|
122
|
+
return 1
|
|
123
|
+
;;
|
|
124
|
+
|
|
125
|
+
*)
|
|
126
|
+
log_error "Unsupported OS: $OS"
|
|
127
|
+
log_error "Please install Docker manually: https://docs.docker.com/engine/install/"
|
|
128
|
+
return 1
|
|
129
|
+
;;
|
|
130
|
+
esac
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
# Configure Docker for non-root access
|
|
134
|
+
configure_docker_user() {
|
|
135
|
+
log_info "Configuring Docker for user: $ACTUAL_USER"
|
|
136
|
+
|
|
137
|
+
# Add user to docker group
|
|
138
|
+
if ! getent group docker > /dev/null; then
|
|
139
|
+
groupadd docker
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
usermod -aG docker "$ACTUAL_USER"
|
|
143
|
+
log_info "Added $ACTUAL_USER to docker group"
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
# Start Docker service
|
|
147
|
+
start_docker() {
|
|
148
|
+
log_info "Starting Docker service..."
|
|
149
|
+
|
|
150
|
+
# Check if systemd is available (native Linux)
|
|
151
|
+
if command -v systemctl &> /dev/null && systemctl is-system-running &> /dev/null; then
|
|
152
|
+
systemctl enable docker
|
|
153
|
+
systemctl start docker
|
|
154
|
+
# Check if we're in WSL
|
|
155
|
+
elif grep -qi microsoft /proc/version 2>/dev/null; then
|
|
156
|
+
# WSL - use service command
|
|
157
|
+
service docker start || true
|
|
158
|
+
else
|
|
159
|
+
# Try service command as fallback
|
|
160
|
+
service docker start || true
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
# Wait for Docker to be ready
|
|
164
|
+
log_info "Waiting for Docker to be ready..."
|
|
165
|
+
for i in {1..30}; do
|
|
166
|
+
if docker info &> /dev/null; then
|
|
167
|
+
log_info "Docker is ready"
|
|
168
|
+
return 0
|
|
169
|
+
fi
|
|
170
|
+
sleep 1
|
|
171
|
+
done
|
|
172
|
+
|
|
173
|
+
log_warn "Docker may not be fully started. You might need to restart your terminal or run: sudo service docker start"
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
# Pull PostgreSQL image
|
|
177
|
+
pull_postgres_image() {
|
|
178
|
+
log_info "Pulling PostgreSQL image (this may take a moment)..."
|
|
179
|
+
|
|
180
|
+
# Run as the actual user to ensure proper permissions
|
|
181
|
+
su - "$ACTUAL_USER" -c "docker pull postgres:16-alpine" 2>/dev/null || \
|
|
182
|
+
docker pull postgres:16-alpine
|
|
183
|
+
|
|
184
|
+
log_info "PostgreSQL image ready"
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
# Install Node.js if not present
|
|
188
|
+
install_nodejs() {
|
|
189
|
+
if command -v node &> /dev/null; then
|
|
190
|
+
NODE_VERSION=$(node --version)
|
|
191
|
+
log_info "Node.js already installed: $NODE_VERSION"
|
|
192
|
+
return 0
|
|
193
|
+
fi
|
|
194
|
+
|
|
195
|
+
log_info "Installing Node.js..."
|
|
196
|
+
|
|
197
|
+
case $OS in
|
|
198
|
+
ubuntu|debian|pop)
|
|
199
|
+
# Install Node.js 20.x LTS
|
|
200
|
+
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
|
|
201
|
+
apt-get install -y nodejs
|
|
202
|
+
;;
|
|
203
|
+
|
|
204
|
+
fedora|rhel|centos)
|
|
205
|
+
curl -fsSL https://rpm.nodesource.com/setup_20.x | bash -
|
|
206
|
+
dnf install -y nodejs
|
|
207
|
+
;;
|
|
208
|
+
|
|
209
|
+
arch|manjaro)
|
|
210
|
+
pacman -S --noconfirm nodejs npm
|
|
211
|
+
;;
|
|
212
|
+
|
|
213
|
+
macos)
|
|
214
|
+
log_warn "Please install Node.js from https://nodejs.org/"
|
|
215
|
+
return 1
|
|
216
|
+
;;
|
|
217
|
+
|
|
218
|
+
*)
|
|
219
|
+
log_warn "Please install Node.js manually: https://nodejs.org/"
|
|
220
|
+
return 1
|
|
221
|
+
;;
|
|
222
|
+
esac
|
|
223
|
+
|
|
224
|
+
log_info "Node.js installed: $(node --version)"
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
# Main setup
|
|
228
|
+
main() {
|
|
229
|
+
echo ""
|
|
230
|
+
echo " ████████╗██╗ ██████╗"
|
|
231
|
+
echo " ╚══██╔══╝██║ ██╔════╝"
|
|
232
|
+
echo " ██║ ██║ ██║"
|
|
233
|
+
echo " ██║ ██║ ██║"
|
|
234
|
+
echo " ██║ ███████╗╚██████╗"
|
|
235
|
+
echo " ╚═╝ ╚══════╝ ╚═════╝"
|
|
236
|
+
echo ""
|
|
237
|
+
echo " TLC Server Setup"
|
|
238
|
+
echo ""
|
|
239
|
+
|
|
240
|
+
# Install Docker
|
|
241
|
+
install_docker
|
|
242
|
+
|
|
243
|
+
# Configure Docker for user
|
|
244
|
+
configure_docker_user
|
|
245
|
+
|
|
246
|
+
# Start Docker
|
|
247
|
+
start_docker
|
|
248
|
+
|
|
249
|
+
# Pull PostgreSQL image
|
|
250
|
+
pull_postgres_image
|
|
251
|
+
|
|
252
|
+
# Check/install Node.js
|
|
253
|
+
install_nodejs
|
|
254
|
+
|
|
255
|
+
echo ""
|
|
256
|
+
log_info "=========================================="
|
|
257
|
+
log_info "Setup complete!"
|
|
258
|
+
log_info "=========================================="
|
|
259
|
+
echo ""
|
|
260
|
+
log_info "IMPORTANT: Log out and log back in (or restart your terminal)"
|
|
261
|
+
log_info "for Docker group permissions to take effect."
|
|
262
|
+
echo ""
|
|
263
|
+
log_info "Then you can run TLC server with:"
|
|
264
|
+
log_info " cd your-project && npx tlc-claude-code server"
|
|
265
|
+
echo ""
|
|
266
|
+
log_info "Or test Docker now with:"
|
|
267
|
+
log_info " sudo docker run hello-world"
|
|
268
|
+
echo ""
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
main "$@"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# TLC Dashboard
|
|
2
|
+
# This file is yours — customize freely. TLC will never overwrite it.
|
|
3
|
+
# Docs: https://github.com/jurgencalleja/TLC/wiki/devserver
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# docker compose -f docker-compose.tlc.yml up -d # start
|
|
7
|
+
# docker compose -f docker-compose.tlc.yml down # stop
|
|
8
|
+
# docker compose -f docker-compose.tlc.yml logs -f # logs
|
|
9
|
+
#
|
|
10
|
+
# Or use: /tlc:dashboard (start | stop | rebuild | logs | status)
|
|
11
|
+
|
|
12
|
+
services:
|
|
13
|
+
dashboard:
|
|
14
|
+
image: node:20-alpine
|
|
15
|
+
container_name: tlc-dashboard
|
|
16
|
+
working_dir: /project
|
|
17
|
+
command: >
|
|
18
|
+
sh -c "
|
|
19
|
+
echo '[TLC] Installing tlc-claude-code...' &&
|
|
20
|
+
npm install -g tlc-claude-code@latest &&
|
|
21
|
+
TLC_DIR=$$(npm root -g)/tlc-claude-code &&
|
|
22
|
+
ls $$TLC_DIR/dashboard-web/dist/index.html && echo '[TLC] React SPA ready' || echo '[TLC] WARNING: dashboard-web/dist not found' &&
|
|
23
|
+
echo '[TLC] Starting dashboard on port 3147...' &&
|
|
24
|
+
cd /project && node $$TLC_DIR/server/index.js
|
|
25
|
+
"
|
|
26
|
+
environment:
|
|
27
|
+
- TLC_PORT=3147
|
|
28
|
+
- TLC_AUTH=false
|
|
29
|
+
# Uncomment to enable authentication:
|
|
30
|
+
# - TLC_AUTH=true
|
|
31
|
+
# - TLC_AUTH_PASSWORD=your-password
|
|
32
|
+
# Uncomment to proxy your app:
|
|
33
|
+
# - TLC_APP_PORT=3000
|
|
34
|
+
ports:
|
|
35
|
+
- "${DASHBOARD_PORT:-3147}:3147"
|
|
36
|
+
volumes:
|
|
37
|
+
- .:/project
|
|
38
|
+
restart: on-failure
|