tlc-claude-code 0.8.7 → 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/bin/init.js CHANGED
@@ -79,16 +79,29 @@ echo ""
79
79
  # TODO: Implement full macOS/Linux support
80
80
  `;
81
81
 
82
+ // Detect OS - WSL counts as Windows since user will double-click .bat from Explorer
83
+ const isWSL = process.platform === 'linux' && fs.existsSync('/mnt/c');
84
+ const isWindows = process.platform === 'win32' || isWSL;
85
+ const launcherFile = isWindows ? 'tlc-start.bat' : 'tlc-start.sh';
86
+ const launcherPath = path.join(projectDir, launcherFile);
87
+
88
+ // FAST PATH: If already initialized, just confirm and exit
89
+ if (fs.existsSync(launcherPath) && fs.existsSync(path.join(projectDir, '.tlc.json'))) {
90
+ console.log('');
91
+ console.log(`[TLC] Already initialized. ${launcherFile} exists.`);
92
+ console.log('');
93
+ console.log('[TLC] To start: Double-click ' + launcherFile);
94
+ console.log('[TLC] To rebuild: tlc rebuild');
95
+ console.log('');
96
+ process.exit(0);
97
+ }
98
+
82
99
  console.log('');
83
100
  console.log(' ============================');
84
101
  console.log(' TLC Project Init');
85
102
  console.log(' ============================');
86
103
  console.log('');
87
104
 
88
- // Detect OS - WSL counts as Windows since user will double-click .bat from Explorer
89
- const isWSL = process.platform === 'linux' && fs.existsSync('/mnt/c');
90
- const isWindows = process.platform === 'win32' || isWSL;
91
-
92
105
  if (isWindows) {
93
106
  // Create Windows launcher
94
107
  const batPath = path.join(projectDir, 'tlc-start.bat');
package/package.json CHANGED
@@ -1,15 +1,10 @@
1
1
  {
2
2
  "name": "tlc-claude-code",
3
- "version": "0.8.7",
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
 
package/server.md CHANGED
@@ -4,7 +4,7 @@ Set up Docker-based development environment.
4
4
 
5
5
  ## Instructions for Claude
6
6
 
7
- **IMPORTANT: Keep this simple. Do exactly these steps:**
7
+ **CRITICAL: Do NOT analyze the codebase. Do NOT check files. Do NOT run any detection. Just execute the two steps below immediately.**
8
8
 
9
9
  ### Step 1: Create the launcher
10
10