tlc-claude-code 0.8.8 → 0.9.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.
- package/README.md +0 -2
- package/bin/init.js +41 -8
- package/docker-compose.dev.yml +16 -0
- package/package.json +3 -7
- package/server/index.js +118 -0
- package/start-dev.sh +91 -0
package/README.md
CHANGED
|
@@ -172,8 +172,6 @@ tlc rebuild # After package.json changes or to get a clean slate
|
|
|
172
172
|
|
|
173
173
|
**Requirements:** [Docker Desktop](https://www.docker.com/products/docker-desktop)
|
|
174
174
|
|
|
175
|
-
> **Note:** Windows only for now. macOS/Linux support coming soon.
|
|
176
|
-
|
|
177
175
|
---
|
|
178
176
|
|
|
179
177
|
## Test Quality
|
package/bin/init.js
CHANGED
|
@@ -57,7 +57,7 @@ powershell -ExecutionPolicy Bypass -File "%TLC_DIR%\\start-dev.ps1" -ProjectPath
|
|
|
57
57
|
pause
|
|
58
58
|
`;
|
|
59
59
|
|
|
60
|
-
// macOS/Linux shell script
|
|
60
|
+
// macOS/Linux shell script
|
|
61
61
|
const shContent = `#!/bin/bash
|
|
62
62
|
# ========================================
|
|
63
63
|
# TLC Dev Server Launcher
|
|
@@ -68,15 +68,48 @@ const shContent = `#!/bin/bash
|
|
|
68
68
|
# Database: localhost:5433
|
|
69
69
|
# ========================================
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
set -e
|
|
72
|
+
|
|
73
|
+
# Find TLC installation
|
|
74
|
+
TLC_DIR=""
|
|
75
|
+
LOCATIONS=(
|
|
76
|
+
"$HOME/.nvm/versions/node/*/lib/node_modules/tlc-claude-code"
|
|
77
|
+
"/usr/local/lib/node_modules/tlc-claude-code"
|
|
78
|
+
"/usr/lib/node_modules/tlc-claude-code"
|
|
79
|
+
"$HOME/.npm-global/lib/node_modules/tlc-claude-code"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Check npm global
|
|
83
|
+
NPM_ROOT=$(npm root -g 2>/dev/null || echo "")
|
|
84
|
+
if [ -n "$NPM_ROOT" ] && [ -f "$NPM_ROOT/tlc-claude-code/start-dev.sh" ]; then
|
|
85
|
+
TLC_DIR="$NPM_ROOT/tlc-claude-code"
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# Check common locations
|
|
89
|
+
if [ -z "$TLC_DIR" ]; then
|
|
90
|
+
for pattern in "\${LOCATIONS[@]}"; do
|
|
91
|
+
for dir in $pattern; do
|
|
92
|
+
if [ -f "$dir/start-dev.sh" ]; then
|
|
93
|
+
TLC_DIR="$dir"
|
|
94
|
+
break 2
|
|
95
|
+
fi
|
|
96
|
+
done
|
|
97
|
+
done
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
if [ -z "$TLC_DIR" ]; then
|
|
101
|
+
echo "[TLC] ERROR: Could not find TLC installation"
|
|
102
|
+
echo "[TLC] Install with: npm install -g tlc-claude-code"
|
|
103
|
+
exit 1
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
PROJECT_PATH="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
|
|
107
|
+
|
|
108
|
+
echo "[TLC] Found TLC at: $TLC_DIR"
|
|
109
|
+
echo "[TLC] Starting dev server for: $PROJECT_PATH"
|
|
77
110
|
echo ""
|
|
78
111
|
|
|
79
|
-
|
|
112
|
+
exec "$TLC_DIR/start-dev.sh" "$PROJECT_PATH"
|
|
80
113
|
`;
|
|
81
114
|
|
|
82
115
|
// Detect OS - WSL counts as Windows since user will double-click .bat from Explorer
|
package/docker-compose.dev.yml
CHANGED
|
@@ -79,5 +79,21 @@ services:
|
|
|
79
79
|
- app
|
|
80
80
|
restart: on-failure
|
|
81
81
|
|
|
82
|
+
# Playwright E2E Tests (optional - starts on demand)
|
|
83
|
+
playwright:
|
|
84
|
+
image: mcr.microsoft.com/playwright:v1.40.0-jammy
|
|
85
|
+
container_name: tlc-${COMPOSE_PROJECT_NAME:-dev}-playwright
|
|
86
|
+
working_dir: /app
|
|
87
|
+
profiles:
|
|
88
|
+
- test
|
|
89
|
+
command: npx playwright test
|
|
90
|
+
environment:
|
|
91
|
+
- BASE_URL=http://app:5000
|
|
92
|
+
- CI=true
|
|
93
|
+
volumes:
|
|
94
|
+
- ${PROJECT_DIR:-.}:/app
|
|
95
|
+
depends_on:
|
|
96
|
+
- app
|
|
97
|
+
|
|
82
98
|
volumes:
|
|
83
99
|
postgres-data:
|
package/package.json
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tlc-claude-code",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "TLC - Test Led Coding for Claude Code",
|
|
5
5
|
"bin": {
|
|
6
6
|
"tlc": "./bin/tlc.js",
|
|
7
|
-
"tlc-claude-code": "./bin/install.js"
|
|
8
|
-
"tlc-dashboard": "./dashboard/dist/index.js",
|
|
9
|
-
"tlc-server": "./bin/server.js",
|
|
10
|
-
"tlc-setup": "./bin/setup.js",
|
|
11
|
-
"tlc-init": "./bin/init.js",
|
|
12
|
-
"tlc-rebuild": "./bin/rebuild.js"
|
|
7
|
+
"tlc-claude-code": "./bin/install.js"
|
|
13
8
|
},
|
|
14
9
|
"files": [
|
|
15
10
|
"bin/",
|
|
@@ -18,6 +13,7 @@
|
|
|
18
13
|
"server/",
|
|
19
14
|
"docker-compose.dev.yml",
|
|
20
15
|
"start-dev.ps1",
|
|
16
|
+
"start-dev.sh",
|
|
21
17
|
"start-dev.bat",
|
|
22
18
|
"*.md",
|
|
23
19
|
"install.sh"
|
package/server/index.js
CHANGED
|
@@ -211,6 +211,7 @@ app.get('/api/status', (req, res) => {
|
|
|
211
211
|
appPort,
|
|
212
212
|
testsPass: plan.testsPass || 0,
|
|
213
213
|
testsFail: plan.testsFail || 0,
|
|
214
|
+
tasks: plan.tasks?.length || 0,
|
|
214
215
|
bugsOpen: bugs.filter(b => b.status === 'open').length,
|
|
215
216
|
phase: plan.currentPhase,
|
|
216
217
|
phaseName: plan.currentPhaseName
|
|
@@ -235,6 +236,123 @@ app.get('/api/tasks', (req, res) => {
|
|
|
235
236
|
});
|
|
236
237
|
});
|
|
237
238
|
|
|
239
|
+
// Plan content endpoint
|
|
240
|
+
app.get('/api/plan', (req, res) => {
|
|
241
|
+
const plan = parsePlan(PROJECT_DIR);
|
|
242
|
+
let content = '';
|
|
243
|
+
|
|
244
|
+
// Try to read current phase plan file
|
|
245
|
+
const phasesDir = path.join(PROJECT_DIR, '.planning', 'phases');
|
|
246
|
+
if (plan.currentPhase && fs.existsSync(phasesDir)) {
|
|
247
|
+
const planFile = path.join(phasesDir, `${plan.currentPhase}-PLAN.md`);
|
|
248
|
+
if (fs.existsSync(planFile)) {
|
|
249
|
+
content = fs.readFileSync(planFile, 'utf-8');
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Fallback to ROADMAP.md
|
|
254
|
+
if (!content) {
|
|
255
|
+
const roadmapFile = path.join(PROJECT_DIR, '.planning', 'ROADMAP.md');
|
|
256
|
+
if (fs.existsSync(roadmapFile)) {
|
|
257
|
+
content = fs.readFileSync(roadmapFile, 'utf-8');
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
res.json({
|
|
262
|
+
phase: plan.currentPhase,
|
|
263
|
+
phaseName: plan.currentPhaseName,
|
|
264
|
+
content
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// Test checklist endpoint
|
|
269
|
+
app.get('/api/tests', (req, res) => {
|
|
270
|
+
const plan = parsePlan(PROJECT_DIR);
|
|
271
|
+
let items = [];
|
|
272
|
+
|
|
273
|
+
// Try to read TESTS.md for current phase
|
|
274
|
+
const phasesDir = path.join(PROJECT_DIR, '.planning', 'phases');
|
|
275
|
+
if (plan.currentPhase && fs.existsSync(phasesDir)) {
|
|
276
|
+
const testsFile = path.join(phasesDir, `${plan.currentPhase}-TESTS.md`);
|
|
277
|
+
if (fs.existsSync(testsFile)) {
|
|
278
|
+
const content = fs.readFileSync(testsFile, 'utf-8');
|
|
279
|
+
// Parse checkboxes
|
|
280
|
+
const lines = content.split('\n');
|
|
281
|
+
for (const line of lines) {
|
|
282
|
+
const match = line.match(/^[-*]\s*\[([ x])\]\s*(.+)$/i);
|
|
283
|
+
if (match) {
|
|
284
|
+
items.push({
|
|
285
|
+
checked: match[1].toLowerCase() === 'x',
|
|
286
|
+
text: match[2].trim()
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
res.json({ items });
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// Bugs list endpoint
|
|
297
|
+
app.get('/api/bugs', (req, res) => {
|
|
298
|
+
const bugs = parseBugs(PROJECT_DIR);
|
|
299
|
+
res.json(bugs);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// Changelog endpoint
|
|
303
|
+
app.get('/api/changelog', (req, res) => {
|
|
304
|
+
try {
|
|
305
|
+
const { execSync } = require('child_process');
|
|
306
|
+
const output = execSync('git log --oneline -20 --pretty=format:"%h|%s|%an|%ar"', {
|
|
307
|
+
cwd: PROJECT_DIR,
|
|
308
|
+
encoding: 'utf-8'
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
const commits = output.trim().split('\n').filter(Boolean).map(line => {
|
|
312
|
+
const [hash, message, author, date] = line.split('|');
|
|
313
|
+
return { hash, message, author, date };
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
res.json({ commits });
|
|
317
|
+
} catch (e) {
|
|
318
|
+
res.json({ commits: [] });
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
// Playwright endpoint
|
|
323
|
+
app.post('/api/playwright', (req, res) => {
|
|
324
|
+
addLog('test', '--- Running Playwright tests ---', 'info');
|
|
325
|
+
|
|
326
|
+
const testProcess = spawn('npx', ['playwright', 'test'], {
|
|
327
|
+
cwd: PROJECT_DIR,
|
|
328
|
+
env: { ...process.env, CI: 'true' },
|
|
329
|
+
shell: true
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
testProcess.stdout.on('data', (data) => {
|
|
333
|
+
const text = data.toString().trim();
|
|
334
|
+
if (text) {
|
|
335
|
+
broadcast('test-output', { data: text, stream: 'stdout' });
|
|
336
|
+
addLog('test', text);
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
testProcess.stderr.on('data', (data) => {
|
|
341
|
+
const text = data.toString().trim();
|
|
342
|
+
if (text) {
|
|
343
|
+
broadcast('test-output', { data: text, stream: 'stderr' });
|
|
344
|
+
addLog('test', text, 'error');
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
testProcess.on('exit', (code) => {
|
|
349
|
+
broadcast('test-complete', { exitCode: code });
|
|
350
|
+
addLog('test', `Playwright ${code === 0 ? 'passed' : 'failed'}`, code === 0 ? 'success' : 'error');
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
res.json({ success: true });
|
|
354
|
+
});
|
|
355
|
+
|
|
238
356
|
app.post('/api/bug', (req, res) => {
|
|
239
357
|
const { description, url, screenshot, severity } = req.body;
|
|
240
358
|
|
package/start-dev.sh
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# TLC Dev Server Launcher
|
|
4
|
+
# Usage: ./start-dev.sh [project-path]
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
PROJECT_PATH="${1:-$(pwd)}"
|
|
9
|
+
|
|
10
|
+
echo ""
|
|
11
|
+
echo " ============================"
|
|
12
|
+
echo " TLC Dev Server"
|
|
13
|
+
echo " ============================"
|
|
14
|
+
echo ""
|
|
15
|
+
|
|
16
|
+
# Check Docker
|
|
17
|
+
echo "[TLC] Checking Docker..."
|
|
18
|
+
if ! docker info >/dev/null 2>&1; then
|
|
19
|
+
echo "[TLC] Docker is not running."
|
|
20
|
+
|
|
21
|
+
# Try to start Docker based on OS
|
|
22
|
+
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
23
|
+
echo "[TLC] Starting Docker Desktop..."
|
|
24
|
+
open -a Docker
|
|
25
|
+
elif [[ -f /etc/debian_version ]] || [[ -f /etc/redhat-release ]]; then
|
|
26
|
+
echo "[TLC] Starting Docker service..."
|
|
27
|
+
sudo systemctl start docker 2>/dev/null || sudo service docker start 2>/dev/null || true
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
echo "[TLC] Waiting for Docker..."
|
|
31
|
+
TIMEOUT=60
|
|
32
|
+
ELAPSED=0
|
|
33
|
+
while [ $ELAPSED -lt $TIMEOUT ]; do
|
|
34
|
+
sleep 2
|
|
35
|
+
ELAPSED=$((ELAPSED + 2))
|
|
36
|
+
if docker info >/dev/null 2>&1; then
|
|
37
|
+
break
|
|
38
|
+
fi
|
|
39
|
+
printf "."
|
|
40
|
+
done
|
|
41
|
+
echo ""
|
|
42
|
+
|
|
43
|
+
if ! docker info >/dev/null 2>&1; then
|
|
44
|
+
echo "[TLC] ERROR: Docker failed to start"
|
|
45
|
+
echo "[TLC] Please start Docker manually and try again"
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
echo "[TLC] Docker is ready!"
|
|
51
|
+
|
|
52
|
+
# Resolve project path
|
|
53
|
+
PROJECT_PATH="$(cd "$PROJECT_PATH" 2>/dev/null && pwd)"
|
|
54
|
+
if [ -z "$PROJECT_PATH" ]; then
|
|
55
|
+
echo "[TLC] ERROR: Invalid project path"
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Get project name from directory
|
|
60
|
+
PROJECT_NAME=$(basename "$PROJECT_PATH" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9')
|
|
61
|
+
if [ -z "$PROJECT_NAME" ]; then
|
|
62
|
+
PROJECT_NAME="dev"
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
echo "[TLC] Project: $PROJECT_PATH"
|
|
66
|
+
echo "[TLC] Name: $PROJECT_NAME"
|
|
67
|
+
|
|
68
|
+
# Set environment
|
|
69
|
+
export PROJECT_DIR="$PROJECT_PATH"
|
|
70
|
+
export COMPOSE_PROJECT_NAME="$PROJECT_NAME"
|
|
71
|
+
|
|
72
|
+
# Find TLC installation directory
|
|
73
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
74
|
+
cd "$SCRIPT_DIR"
|
|
75
|
+
|
|
76
|
+
echo ""
|
|
77
|
+
echo "[TLC] Starting services..."
|
|
78
|
+
echo " Dashboard: http://localhost:3147"
|
|
79
|
+
echo " App: http://localhost:5000"
|
|
80
|
+
echo " DB Admin: http://localhost:8080"
|
|
81
|
+
echo " Database: localhost:5433 (postgres/postgres)"
|
|
82
|
+
echo ""
|
|
83
|
+
echo "[TLC] Containers: tlc-$PROJECT_NAME-*"
|
|
84
|
+
echo "[TLC] Press Ctrl+C to stop"
|
|
85
|
+
echo ""
|
|
86
|
+
|
|
87
|
+
# Run docker-compose
|
|
88
|
+
docker-compose -f docker-compose.dev.yml up --build
|
|
89
|
+
|
|
90
|
+
echo ""
|
|
91
|
+
echo "[TLC] Stopped."
|