tlc-claude-code 1.6.0 → 1.6.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.
@@ -6,6 +6,55 @@ Write failing tests, then implement to make them pass.
6
6
 
7
7
  **Code like a senior engineer with 15+ years experience.** Every line should reflect:
8
8
 
9
+ ### Project Structure (NestJS-Style Modules)
10
+
11
+ **Group by domain entity, not by file type.** Each entity gets its own module folder:
12
+
13
+ ```
14
+ src/modules/{entity}/
15
+ ├── interfaces/ # Types and interfaces (NEVER at module root)
16
+ │ ├── {entity}.interface.ts
17
+ │ └── index.ts
18
+ ├── dto/ # Request/Response DTOs
19
+ │ ├── create.dto.ts
20
+ │ └── index.ts
21
+ ├── enums/ # Enums (no magic strings)
22
+ ├── constants/ # Configuration constants
23
+ ├── guards/ # Auth/permission middleware
24
+ ├── {entity}.service.ts # Business logic
25
+ ├── {entity}.controller.ts # HTTP handlers
26
+ ├── {entity}.repository.ts # Data access
27
+ ├── {entity}.seed.ts # Seed data (per-entity, not monolithic)
28
+ ├── {entity}.test.ts # Tests
29
+ └── index.ts # Barrel exports
30
+ ```
31
+
32
+ **Server/src root should ONLY contain:**
33
+ - `index.ts` - Entry point
34
+ - `lib/` - Core shared libraries
35
+ - `modules/` - Feature modules
36
+ - `shared/` - Cross-cutting utilities
37
+ - Config files
38
+
39
+ **❌ NEVER do this:**
40
+ ```
41
+ src/
42
+ services/ # ❌ All services dumped together
43
+ interfaces/ # ❌ All types dumped together
44
+ controllers/ # ❌ Flat controller folder
45
+
46
+ server/
47
+ auth.ts # ❌ Loose file at root (should be modules/auth/)
48
+ helpers.ts # ❌ Should be in lib/ or shared/
49
+ ```
50
+
51
+ **Key rules:**
52
+ - Interfaces ALWAYS in `interfaces/` subdirectory, never at module root
53
+ - No inline interfaces in service files - import from `interfaces/`
54
+ - No magic strings - use `enums/` or `constants/`
55
+ - Seeds per-entity, not one giant seeds.ts
56
+ - Every module has `index.ts` barrel export
57
+
9
58
  ### Code Quality
10
59
  - **Clean Architecture**: Separate concerns. Domain logic never depends on infrastructure.
11
60
  - **SOLID Principles**: Single responsibility, open/closed, Liskov substitution, interface segregation, dependency inversion.
@@ -117,13 +166,17 @@ Senior engineers know when rules don't apply:
117
166
 
118
167
  This is the core TLC command. Tests before code, one task at a time.
119
168
 
120
- **Overdrive Mode:** When tasks are independent, TLC auto-detects and offers parallel execution with multiple agents.
169
+ **Overdrive Mode (Opus 4.6):** When tasks are independent, TLC auto-detects and offers parallel execution with multiple agents. Agents are assigned models based on task complexity (opus for heavy, sonnet for standard, haiku for light). Failed agents can be resumed. No arbitrary cap on agent count.
121
170
 
122
171
  ## Usage
123
172
 
124
173
  ```
125
174
  /tlc:build <phase_number>
126
- /tlc:build <phase_number> --sequential # Force sequential mode
175
+ /tlc:build <phase_number> --sequential # Force sequential mode
176
+ /tlc:build <phase_number> --model sonnet # Force all agents to use sonnet
177
+ /tlc:build <phase_number> --model haiku # Force all agents to use haiku (fast/cheap)
178
+ /tlc:build <phase_number> --max-turns 30 # Limit agent execution length
179
+ /tlc:build <phase_number> --agents 5 # Limit parallel agents to 5
127
180
  ```
128
181
 
129
182
  ## Process
@@ -132,7 +185,7 @@ This is the core TLC command. Tests before code, one task at a time.
132
185
 
133
186
  Read all `.planning/phases/{phase}-*-PLAN.md` files for this phase.
134
187
 
135
- ### Step 1a: Overdrive Detection (Auto-Parallel)
188
+ ### Step 1a: Overdrive Detection (Auto-Parallel, Opus 4.6)
136
189
 
137
190
  After loading plans, analyze task dependencies to determine if parallel execution is possible.
138
191
 
@@ -151,18 +204,19 @@ After loading plans, analyze task dependencies to determine if parallel executio
151
204
  2. Look for dependency markers in task descriptions
152
205
  3. Check "## Dependencies" section if present
153
206
  4. Identify independent tasks (no dependencies)
207
+ 5. Estimate task complexity for model assignment (heavy/standard/light)
154
208
 
155
209
  **If 2+ independent tasks found:**
156
210
  ```
157
- 🚀 Overdrive Mode Available
211
+ 🚀 Overdrive Mode Available (Opus 4.6)
158
212
 
159
213
  Phase 3 has 4 independent tasks that can run in parallel:
160
- - Task 1: Create user schema
161
- - Task 2: Add validation helpers
162
- - Task 3: Write migration scripts
163
- - Task 4: Create seed data
214
+ - Task 1: Create user schema [opus] (heavy)
215
+ - Task 2: Add validation helpers [sonnet] (standard)
216
+ - Task 3: Write migration scripts [sonnet] (standard)
217
+ - Task 4: Create seed data [haiku] (light)
164
218
 
165
- Recommended: 3 agents (optimal parallelism)
219
+ Recommended: 4 agents (one per independent task)
166
220
 
167
221
  Options:
168
222
  1) Overdrive mode (parallel agents) [Recommended]
@@ -170,6 +224,15 @@ Options:
170
224
  3) Let me pick which tasks to parallelize
171
225
  ```
172
226
 
227
+ **Model auto-selection per task complexity:**
228
+ | Complexity | Model | When |
229
+ |-----------|-------|------|
230
+ | Heavy | opus | Architecture, multi-file features, security, auth, database |
231
+ | Standard | sonnet | Normal implementation tasks (default) |
232
+ | Light | haiku | Config, boilerplate, DTOs, enums, constants, seed data |
233
+
234
+ Override with `--model sonnet` to force all agents to the same model.
235
+
173
236
  **If tasks have dependencies (waterfall):**
174
237
  ```
175
238
  📋 Sequential Mode
@@ -181,62 +244,87 @@ Phase 3 tasks have dependencies:
181
244
  Running in sequential order.
182
245
  ```
183
246
 
184
- ### Step 1b: Execute Overdrive (if selected)
247
+ ### Step 1b: Execute Overdrive (if selected) — Opus 4.6 Multi-Agent
185
248
 
186
- When overdrive mode is selected, spawn parallel agents:
249
+ When overdrive mode is selected, spawn parallel agents with per-task model selection:
187
250
 
188
251
  ```
189
- 🚀 Launching Overdrive Mode
252
+ 🚀 Launching Overdrive Mode (Opus 4.6)
190
253
 
191
- Spawning 3 agents in parallel...
254
+ Spawning 4 agents in parallel...
192
255
 
193
- Agent 1: Task 1 - Create user schema
194
- Agent 2: Task 2 - Add validation helpers
195
- Agent 3: Task 3 - Write migration scripts
256
+ Agent 1: Task 1 - Create user schema [opus]
257
+ Agent 2: Task 2 - Add validation helpers [sonnet]
258
+ Agent 3: Task 3 - Write migration scripts [sonnet]
259
+ Agent 4: Task 4 - Create seed data [haiku]
196
260
 
197
261
  [All agents spawned - working in background]
198
- [Task 4 queued for next available agent]
199
262
  ```
200
263
 
201
264
  **Agent execution rules:**
202
- - Each agent gets one task
265
+ - One agent per independent task (no arbitrary cap)
266
+ - Model assigned per task complexity (override with `--model`)
203
267
  - Agents work autonomously (no confirmation prompts)
204
268
  - Each agent commits after completing their task
205
- - When an agent finishes, it can pick up queued tasks
206
269
  - All agents follow test-first methodology
270
+ - `max_turns` limits execution length (default: 50, override with `--max-turns`)
207
271
 
208
272
  **CRITICAL: Spawn all agents in a SINGLE message using multiple Task tool calls.**
209
273
 
210
274
  ```
211
- Task(description="Agent 1: Task 1", prompt="...", subagent_type="general-purpose", run_in_background=true)
212
- Task(description="Agent 2: Task 2", prompt="...", subagent_type="general-purpose", run_in_background=true)
213
- Task(description="Agent 3: Task 3", prompt="...", subagent_type="general-purpose", run_in_background=true)
275
+ Task(description="Agent 1: Task 1", prompt="...", subagent_type="general-purpose", model="opus", max_turns=50, run_in_background=true)
276
+ Task(description="Agent 2: Task 2", prompt="...", subagent_type="general-purpose", model="sonnet", max_turns=50, run_in_background=true)
277
+ Task(description="Agent 3: Task 3", prompt="...", subagent_type="general-purpose", model="sonnet", max_turns=50, run_in_background=true)
278
+ Task(description="Agent 4: Task 4", prompt="...", subagent_type="general-purpose", model="haiku", max_turns=50, run_in_background=true)
214
279
  ```
215
280
 
216
- **Live Progress Monitoring:**
281
+ **Live Progress Monitoring (TaskOutput):**
282
+
283
+ Use `TaskOutput` with `block=false` for non-blocking progress checks:
284
+
285
+ ```
286
+ TaskOutput(task_id="AGENT_ID_1", block=false, timeout=5000)
287
+ TaskOutput(task_id="AGENT_ID_2", block=false, timeout=5000)
288
+ ```
217
289
 
218
- While agents run in background, show live status using the AgentProgressMonitor:
290
+ Or use the AgentProgressMonitor for formatted status:
219
291
 
220
292
  ```bash
221
293
  node -e "
222
294
  const { AgentProgressMonitor } = require('./server/lib/agent-progress-monitor.js');
223
295
  const monitor = new AgentProgressMonitor('/tmp/claude-1000/-mnt-c-Code-TLC/tasks');
224
- const agents = ['AGENT_ID_1', 'AGENT_ID_2', 'AGENT_ID_3'];
296
+ const agents = ['AGENT_ID_1', 'AGENT_ID_2', 'AGENT_ID_3', 'AGENT_ID_4'];
225
297
  console.log(monitor.formatTable(agents));
226
298
  "
227
299
  ```
228
300
 
229
301
  Display format:
230
302
  ```
231
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
232
- 🚀 OVERDRIVE STATUS
233
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
234
- | Agent | Task | Tests | Phase |
235
- |-------|------|-------|-------|
236
- | a1b2c3 | README Generator | 29 ✓ | committed |
237
- | d4e5f6 | Flow Diagrams | 18 ✓ | implementing |
238
- | g7h8i9 | ADR Generator | - | writing-tests |
239
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
303
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
304
+ 🚀 OVERDRIVE STATUS (Opus 4.6)
305
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
306
+ | Agent | Task | Model | Tests | Phase |
307
+ |-------|------|-------|-------|-------|
308
+ | a1b2c3 | User Schema | opus | 29 ✓ | committed |
309
+ | d4e5f6 | Validation | sonnet | 18 ✓ | implementing |
310
+ | g7h8i9 | Migrations | sonnet | - | writing-tests |
311
+ | j0k1l2 | Seed Data | haiku | 5 ✓ | committed |
312
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
313
+ ```
314
+
315
+ **Handling Agent Failures (Opus 4.6 Resumption):**
316
+
317
+ If an agent fails or gets stuck:
318
+
319
+ ```
320
+ # Check if agent is stuck (non-blocking)
321
+ TaskOutput(task_id="AGENT_ID", block=false, timeout=5000)
322
+
323
+ # Cancel a stuck agent
324
+ TaskStop(task_id="AGENT_ID")
325
+
326
+ # Resume a failed agent from where it left off (full context preserved)
327
+ Task(resume="AGENT_ID", prompt="Continue from where you left off. Fix any errors and complete the task.")
240
328
  ```
241
329
 
242
330
  **Show status automatically:**
@@ -750,7 +838,7 @@ Writing tests for Task 2: Validation...
750
838
  Phase 1 complete. Ready for /tlc:verify 1
751
839
  ```
752
840
 
753
- ### Overdrive Mode (Independent Tasks)
841
+ ### Overdrive Mode (Independent Tasks, Opus 4.6)
754
842
 
755
843
  ```
756
844
  User: /tlc:build 2
@@ -758,15 +846,15 @@ User: /tlc:build 2
758
846
  Claude: Loading phase 2 plans...
759
847
  Found: 2-PLAN.md (4 tasks)
760
848
 
761
- 🚀 Overdrive Mode Available
849
+ 🚀 Overdrive Mode Available (Opus 4.6)
762
850
 
763
851
  Phase 2 has 4 independent tasks:
764
- - Task 1: Create API routes
765
- - Task 2: Add input validation
766
- - Task 3: Write error handlers
767
- - Task 4: Add rate limiting
852
+ - Task 1: Create API routes [sonnet] (standard)
853
+ - Task 2: Add input validation [sonnet] (standard)
854
+ - Task 3: Write error handlers [sonnet] (standard)
855
+ - Task 4: Add rate limiting config [haiku] (light)
768
856
 
769
- Recommended: 3 agents
857
+ Recommended: 4 agents (one per task)
770
858
 
771
859
  Options:
772
860
  1) Overdrive mode (parallel) [Recommended]
@@ -775,21 +863,20 @@ Options:
775
863
 
776
864
  User: 1
777
865
 
778
- Claude: 🚀 Launching Overdrive Mode
866
+ Claude: 🚀 Launching Overdrive Mode (Opus 4.6)
779
867
 
780
- Spawning 3 agents...
781
- [Agent 1] Task 1: Create API routes - STARTED
782
- [Agent 2] Task 2: Add input validation - STARTED
783
- [Agent 3] Task 3: Write error handlers - STARTED
784
- [Queued] Task 4: Add rate limiting
868
+ Spawning 4 agents...
869
+ [Agent 1] Task 1: Create API routes [sonnet] - STARTED
870
+ [Agent 2] Task 2: Add input validation [sonnet] - STARTED
871
+ [Agent 3] Task 3: Write error handlers [sonnet] - STARTED
872
+ [Agent 4] Task 4: Add rate limiting config [haiku] - STARTED
785
873
 
786
874
  ... agents working in background ...
787
875
 
788
- [Agent 2] ✅ Task 2 complete (3 commits)
789
- [Agent 2] Task 4: Add rate limiting - STARTED
790
- [Agent 1] ✅ Task 1 complete (4 commits)
791
- [Agent 3] ✅ Task 3 complete (2 commits)
792
- [Agent 2] ✅ Task 4 complete (2 commits)
876
+ [Agent 4] ✅ Task 4 complete (1 commit) [haiku - fast]
877
+ [Agent 2] Task 2 complete (3 commits) [sonnet]
878
+ [Agent 1] ✅ Task 1 complete (4 commits) [sonnet]
879
+ [Agent 3] ✅ Task 3 complete (2 commits) [sonnet]
793
880
 
794
881
  All agents complete. Running full test suite...
795
882
  ✅ 24 tests passing
@@ -814,18 +901,23 @@ Phase 2 complete. Ready for /tlc:verify 2
814
901
  - Suggest running `/tlc:build {phase}` again to retry
815
902
  - Or manually fix and run `/tlc:status` to verify
816
903
 
817
- **Overdrive mode issues:**
818
- - Agent stuck → Check with `TaskOutput` tool
904
+ **Overdrive mode issues (Opus 4.6):**
905
+ - Agent stuck → Check with `TaskOutput(task_id, block=false)`, cancel with `TaskStop(task_id)`
906
+ - Agent failed → Resume with `Task(resume=agent_id)` to continue from where it left off
819
907
  - Merge conflicts → Agents working on same files (rare if tasks are truly independent)
820
- - One agent failed → Other agents continue; fix failed task manually
908
+ - One agent failed → Other agents continue; resume failed agent or fix manually
821
909
  - Want sequential instead → Use `--sequential` flag: `/tlc:build 2 --sequential`
910
+ - Cost too high → Use `--model haiku` to force all agents to haiku
911
+ - Agent running too long → Use `--max-turns 30` to limit execution
822
912
 
823
913
  ## Flags
824
914
 
825
915
  | Flag | Description |
826
916
  |------|-------------|
827
917
  | `--sequential` | Force sequential execution even if tasks are independent |
828
- | `--agents N` | Set max parallel agents (default: 3, max: 10) |
918
+ | `--agents N` | Limit parallel agents to N (default: one per independent task) |
919
+ | `--model MODEL` | Force all agents to use a specific model (opus, sonnet, haiku) |
920
+ | `--max-turns N` | Limit each agent's execution to N turns (default: 50) |
829
921
 
830
922
  ## When Overdrive is NOT Used
831
923
 
@@ -61,13 +61,13 @@ Add to `.tlc.json`:
61
61
  "claude": {
62
62
  "type": "cli",
63
63
  "command": "claude",
64
- "model": "claude-4-opus",
64
+ "model": "claude-opus-4-6",
65
65
  "capabilities": ["review", "code-gen", "refactor"]
66
66
  },
67
67
  "codex": {
68
68
  "type": "cli",
69
69
  "command": "codex",
70
- "model": "gpt-5.2",
70
+ "model": "gpt-5.3-codex",
71
71
  "capabilities": ["review", "code-gen"]
72
72
  },
73
73
  "gemini": {
@@ -89,9 +89,9 @@ Add to `.tlc.json`:
89
89
 
90
90
  ## Supported Models
91
91
 
92
- **Claude:** claude-4-opus, claude-4-sonnet, claude-3.5-sonnet, claude-3-opus, claude-3-sonnet, claude-3-haiku
92
+ **Claude:** claude-opus-4-6, claude-sonnet-4-5, claude-4-opus, claude-4-sonnet, claude-3.5-sonnet, claude-3-opus, claude-3-sonnet, claude-3-haiku
93
93
 
94
- **OpenAI/Codex:** gpt-5.2, gpt-5, gpt-4o, gpt-4o-mini, gpt-4-turbo, o3, o3-mini, o1, o1-mini, o1-pro
94
+ **OpenAI/Codex:** gpt-5.3-codex, gpt-5.2, gpt-5, gpt-4o, gpt-4o-mini, gpt-4-turbo, o3, o3-mini, o1, o1-mini, o1-pro
95
95
 
96
96
  **Gemini:** gemini-3-preview, gemini-3, gemini-2.5-pro, gemini-2.0-flash, gemini-2.0-flash-thinking, gemini-1.5-pro
97
97
 
@@ -229,7 +229,7 @@ Create `.tlc.json` with all settings:
229
229
  "autofix": true,
230
230
  "edgeCases": true,
231
231
  "prAutoReview": true,
232
- "maxAgents": 10
232
+ "maxAgents": "auto"
233
233
  }
234
234
  }
235
235
  ```
package/CLAUDE.md CHANGED
@@ -89,6 +89,17 @@ All implementation follows **Red → Green → Refactor**:
89
89
 
90
90
  Tests are written BEFORE implementation, not after.
91
91
 
92
+ ## Context Management
93
+
94
+ **Use multiple sessions/agents for large tasks.** When working in overdrive mode or across workspaces:
95
+ - Use the `Task` tool to spawn sub-agents for independent work (research, testing, building)
96
+ - Keep the main conversation focused on orchestration and decisions
97
+ - Delegate file-heavy operations (reading many files, running test suites) to sub-agents
98
+ - This prevents context window overflow, which causes crashes and lost work
99
+ - Especially critical in workspace mode where multiple repos are involved
100
+
101
+ **Signs you need to delegate:** If you've read 15+ files, run 10+ commands, or the conversation is getting long — spawn a sub-agent for the next chunk of work.
102
+
92
103
  ## After TLC Updates
93
104
 
94
105
  If TLC command files are updated, re-read them before executing. Check version in `package.json`.
package/README.md CHANGED
@@ -72,7 +72,7 @@ Or use `/tlc` for the full dashboard.
72
72
  ### For Solo Developers
73
73
 
74
74
  - **Test-first by default** — Claude writes tests before code
75
- - **Auto-parallelization** — Up to 10 agents run independent tasks simultaneously
75
+ - **Auto-parallelization** — Agents run independent tasks simultaneously with per-task model selection (Opus 4.6)
76
76
  - **`/tlc:next`** — One command to progress. No decisions needed.
77
77
  - **Smart dashboard** — See progress, run actions
78
78
  - **Coverage gaps** — Find and fix untested code
@@ -103,7 +103,7 @@ Or use `/tlc` for the full dashboard.
103
103
  | `/tlc` | Smart dashboard — full status view |
104
104
  | `/tlc:new-project` | Start new project with roadmap |
105
105
  | `/tlc:init` | Add TLC to existing codebase |
106
- | `/tlc:build` | Write tests → implement (auto-parallelizes up to 10 agents) |
106
+ | `/tlc:build` | Write tests → implement (auto-parallelizes with model selection) |
107
107
  | `/tlc:coverage` | Find and fix untested code |
108
108
  | `/tlc:quality` | Test quality scoring |
109
109
  | `/tlc:autofix` | Auto-repair failing tests |
@@ -121,6 +121,26 @@ services:
121
121
  - app
122
122
  restart: on-failure
123
123
 
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
+
124
144
  # Playwright E2E Tests (optional - starts on demand)
125
145
  playwright:
126
146
  image: mcr.microsoft.com/playwright:v1.40.0-jammy
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tlc-claude-code",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "TLC - Test Led Coding for Claude Code",
5
5
  "bin": {
6
6
  "tlc": "./bin/tlc.js",
package/server/index.js CHANGED
@@ -1,5 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // Suppress punycode deprecation from upstream deps (http-proxy-middleware, ws)
4
+ const originalEmit = process.emit;
5
+ process.emit = function (event, error) {
6
+ if (event === 'warning' && error?.name === 'DeprecationWarning' && error?.message?.includes('punycode')) {
7
+ return false;
8
+ }
9
+ return originalEmit.apply(process, arguments);
10
+ };
11
+
3
12
  const express = require('express');
4
13
  const { createServer } = require('http');
5
14
  const { WebSocketServer } = require('ws');
@@ -50,6 +59,7 @@ let appProcess = null;
50
59
  let appPort = 3000;
51
60
  let wsClients = new Set();
52
61
  const logs = { app: [], test: [], git: [] };
62
+ const commandHistory = [];
53
63
 
54
64
  // Create Express app
55
65
  const app = express();
@@ -944,6 +954,177 @@ app.post('/api/test', (req, res) => {
944
954
  res.json({ success: true });
945
955
  });
946
956
 
957
+ // ============================================
958
+ // Command Execution API
959
+ // ============================================
960
+
961
+ // GET /api/commands/history - Return command execution history
962
+ app.get('/api/commands/history', (req, res) => {
963
+ res.json({ success: true, history: commandHistory });
964
+ });
965
+
966
+ // POST /api/commands/:command - Execute a TLC command
967
+ app.post('/api/commands/:command', (req, res) => {
968
+ const command = req.params.command;
969
+ const { args } = req.body || {};
970
+
971
+ // Whitelist of allowed TLC commands
972
+ const allowedCommands = ['plan', 'build', 'verify', 'bug', 'claim', 'release', 'who', 'progress'];
973
+ if (!allowedCommands.includes(command)) {
974
+ return res.status(400).json({ success: false, error: `Unknown command: ${command}. Allowed: ${allowedCommands.join(', ')}` });
975
+ }
976
+
977
+ const entry = {
978
+ id: `cmd-${Date.now()}`,
979
+ command,
980
+ args: args || null,
981
+ status: 'running',
982
+ startedAt: new Date().toISOString(),
983
+ output: '',
984
+ };
985
+ commandHistory.push(entry);
986
+ if (commandHistory.length > 100) commandHistory.shift();
987
+
988
+ addLog('app', `Executing command: tlc:${command}${args ? ' ' + args : ''}`, 'info');
989
+ broadcast('command-started', { id: entry.id, command });
990
+
991
+ // Build the CLI command
992
+ const cliArgs = ['tlc', command];
993
+ if (args) cliArgs.push(args);
994
+ const fullCmd = `npx ${cliArgs.join(' ')}`;
995
+
996
+ const cmdProcess = spawn('npx', cliArgs.slice(1), {
997
+ cwd: PROJECT_DIR,
998
+ env: { ...process.env },
999
+ shell: true,
1000
+ });
1001
+
1002
+ let output = '';
1003
+
1004
+ cmdProcess.stdout.on('data', (data) => {
1005
+ const text = data.toString();
1006
+ output += text;
1007
+ broadcast('command-output', { id: entry.id, data: text, stream: 'stdout' });
1008
+ });
1009
+
1010
+ cmdProcess.stderr.on('data', (data) => {
1011
+ const text = data.toString();
1012
+ output += text;
1013
+ broadcast('command-output', { id: entry.id, data: text, stream: 'stderr' });
1014
+ });
1015
+
1016
+ cmdProcess.on('exit', (code) => {
1017
+ entry.status = code === 0 ? 'completed' : 'failed';
1018
+ entry.exitCode = code;
1019
+ entry.output = output;
1020
+ entry.completedAt = new Date().toISOString();
1021
+ broadcast('command-completed', { id: entry.id, exitCode: code });
1022
+ addLog('app', `Command tlc:${command} ${code === 0 ? 'completed' : 'failed'} (exit ${code})`, code === 0 ? 'info' : 'error');
1023
+ });
1024
+
1025
+ cmdProcess.on('error', (err) => {
1026
+ entry.status = 'failed';
1027
+ entry.output = err.message;
1028
+ entry.completedAt = new Date().toISOString();
1029
+ broadcast('command-completed', { id: entry.id, error: err.message });
1030
+ addLog('app', `Command tlc:${command} error: ${err.message}`, 'error');
1031
+ });
1032
+
1033
+ res.json({ success: true, id: entry.id, command, message: `Command tlc:${command} started` });
1034
+ });
1035
+
1036
+ // ============================================
1037
+ // Dashboard Completion API (Phase 62)
1038
+ // ============================================
1039
+
1040
+ // GET /api/config - Read .tlc.json configuration
1041
+ app.get('/api/config', (req, res) => {
1042
+ try {
1043
+ const tlcPath = path.join(PROJECT_DIR, '.tlc.json');
1044
+ if (!fs.existsSync(tlcPath)) {
1045
+ return res.json({});
1046
+ }
1047
+ const config = JSON.parse(fs.readFileSync(tlcPath, 'utf-8'));
1048
+ res.json(config);
1049
+ } catch (err) {
1050
+ res.status(500).json({ error: err.message });
1051
+ }
1052
+ });
1053
+
1054
+ // PUT /api/config - Write .tlc.json configuration
1055
+ app.put('/api/config', (req, res) => {
1056
+ try {
1057
+ const tlcPath = path.join(PROJECT_DIR, '.tlc.json');
1058
+ const config = req.body;
1059
+ if (!config || typeof config !== 'object') {
1060
+ return res.status(400).json({ error: 'Invalid config object' });
1061
+ }
1062
+ fs.writeFileSync(tlcPath, JSON.stringify(config, null, 2));
1063
+ res.json({ success: true, config });
1064
+ } catch (err) {
1065
+ res.status(500).json({ error: err.message });
1066
+ }
1067
+ });
1068
+
1069
+ // GET /api/health - System health status
1070
+ app.get('/api/health', (req, res) => {
1071
+ const memUsage = process.memoryUsage();
1072
+ res.json({
1073
+ status: 'ok',
1074
+ timestamp: new Date().toISOString(),
1075
+ uptime: process.uptime(),
1076
+ memory: {
1077
+ rss: memUsage.rss,
1078
+ heapUsed: memUsage.heapUsed,
1079
+ heapTotal: memUsage.heapTotal,
1080
+ },
1081
+ appRunning: appProcess !== null,
1082
+ appPort,
1083
+ });
1084
+ });
1085
+
1086
+ // GET /api/tasks/:id - Get single task by ID
1087
+ app.get('/api/tasks/:id', (req, res) => {
1088
+ const plan = parsePlan(PROJECT_DIR);
1089
+ const task = (plan.tasks || []).find(t => t.id === req.params.id);
1090
+ if (!task) {
1091
+ return res.status(404).json({ error: 'Task not found' });
1092
+ }
1093
+ res.json(task);
1094
+ });
1095
+
1096
+ // PATCH /api/tasks/:id - Update task status/owner
1097
+ app.patch('/api/tasks/:id', (req, res) => {
1098
+ const plan = parsePlan(PROJECT_DIR);
1099
+ const task = (plan.tasks || []).find(t => t.id === req.params.id);
1100
+ if (!task) {
1101
+ return res.status(404).json({ error: 'Task not found' });
1102
+ }
1103
+ const updates = req.body;
1104
+ const updated = { ...task, ...updates };
1105
+ broadcast('task-update', updated);
1106
+ addLog('app', `Task ${req.params.id} updated`, 'info');
1107
+ res.json(updated);
1108
+ });
1109
+
1110
+ // DELETE /api/tasks/:id - Delete task
1111
+ app.delete('/api/tasks/:id', (req, res) => {
1112
+ broadcast('task-update', { id: req.params.id, deleted: true });
1113
+ addLog('app', `Task ${req.params.id} deleted`, 'info');
1114
+ res.status(204).send();
1115
+ });
1116
+
1117
+ // DELETE /api/logs/:type - Clear logs by type
1118
+ app.delete('/api/logs/:type', (req, res) => {
1119
+ const type = req.params.type;
1120
+ if (logs[type]) {
1121
+ logs[type] = [];
1122
+ res.json({ success: true });
1123
+ } else {
1124
+ res.status(404).json({ error: 'Unknown log type' });
1125
+ }
1126
+ });
1127
+
947
1128
  // ============================================
948
1129
  // Agent Registry API (Phase 32)
949
1130
  // ============================================
@@ -1014,6 +1195,37 @@ app.get('/api/agents/:id', (req, res) => {
1014
1195
  }
1015
1196
  });
1016
1197
 
1198
+ // Stop a running agent
1199
+ app.post('/api/agents/:id/stop', (req, res) => {
1200
+ try {
1201
+ const registry = getAgentRegistry();
1202
+ const agent = registry.getAgent(req.params.id);
1203
+ if (!agent) {
1204
+ return res.status(404).json({ success: false, error: 'Agent not found' });
1205
+ }
1206
+
1207
+ // Transition state to stopped
1208
+ if (agent.stateMachine) {
1209
+ const currentState = agent.stateMachine.getState();
1210
+ if (currentState === 'stopped' || currentState === 'completed') {
1211
+ return res.status(400).json({ success: false, error: `Agent is already ${currentState}` });
1212
+ }
1213
+ const result = agent.stateMachine.transition('stopped', { reason: req.body.reason || 'Stopped via API' });
1214
+ if (!result.success) {
1215
+ // If formal transition fails, force the state
1216
+ agent.stateMachine.forceState('stopped', { reason: req.body.reason || 'Force stopped via API' });
1217
+ }
1218
+ }
1219
+
1220
+ broadcast('agent-updated', formatAgent(agent));
1221
+ addLog('app', `Agent ${agent.name || req.params.id} stopped`, 'info');
1222
+
1223
+ res.json({ success: true, agent: formatAgent(agent) });
1224
+ } catch (err) {
1225
+ res.status(500).json({ success: false, error: err.message });
1226
+ }
1227
+ });
1228
+
1017
1229
  // Register new agent
1018
1230
  app.post('/api/agents', (req, res) => {
1019
1231
  try {