tlc-claude-code 0.8.8 → 0.9.0
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/package.json +2 -7
- package/server/index.js +118 -0
package/package.json
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tlc-claude-code",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
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/",
|
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
|
|