tlc-claude-code 1.8.2 → 1.8.4
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/audit.md +39 -20
- package/.claude/commands/tlc/build.md +25 -1
- package/.claude/commands/tlc/cleanup.md +70 -0
- package/.claude/commands/tlc/plan.md +17 -1
- package/.claude/commands/tlc/review-pr.md +15 -0
- package/.claude/commands/tlc/review.md +62 -0
- package/.claude/commands/tlc/tlc.md +176 -1
- package/CODING-STANDARDS.md +139 -0
- package/package.json +1 -1
- package/server/index.js +17 -3
- package/server/lib/project-detector.js +27 -0
|
@@ -34,17 +34,24 @@ const { auditProject, generateReport } = require('./lib/standards/audit-checker'
|
|
|
34
34
|
|
|
35
35
|
Run `auditProject(projectPath)` which executes:
|
|
36
36
|
|
|
37
|
-
| Check | What It Finds |
|
|
38
|
-
|
|
39
|
-
| Standards Files | Missing CLAUDE.md or CODING-STANDARDS.md |
|
|
40
|
-
| Flat Folders | Files in src/services/, src/interfaces/, src/controllers/ |
|
|
41
|
-
| Inline Interfaces | `interface X {` inside *.service.ts files |
|
|
42
|
-
|
|
|
43
|
-
| Hardcoded
|
|
44
|
-
|
|
|
45
|
-
|
|
|
46
|
-
|
|
|
47
|
-
|
|
|
37
|
+
| Check | What It Finds | Severity |
|
|
38
|
+
|-------|---------------|----------|
|
|
39
|
+
| Standards Files | Missing CLAUDE.md or CODING-STANDARDS.md | error |
|
|
40
|
+
| Flat Folders | Files in src/services/, src/interfaces/, src/controllers/ | error |
|
|
41
|
+
| Inline Interfaces | `interface X {` inside *.service.ts or *.controller.ts files | error |
|
|
42
|
+
| Inline Constants | `const X =` hardcoded values inside service/controller files | warning |
|
|
43
|
+
| Hardcoded URLs | http:// or https:// URLs in code | error |
|
|
44
|
+
| Hardcoded Ports | `const port = 3000` patterns | error |
|
|
45
|
+
| Magic Strings | `=== 'active'` comparisons without constants | warning |
|
|
46
|
+
| Flat Seeds | Seed files in src/seeds/ instead of src/{entity}/seeds/ | warning |
|
|
47
|
+
| Missing JSDoc | Exported functions without `/**` comments | warning |
|
|
48
|
+
| Deep Imports | `../../../` style imports (3+ levels) | warning |
|
|
49
|
+
| **Oversized Files** | Files exceeding 1000 lines (warn at 500) | error/warning |
|
|
50
|
+
| **Overcrowded Folders** | Folders with >15 files directly inside (warn at 8) | error/warning |
|
|
51
|
+
| **`any` Type Usage** | `any` type annotations in TypeScript files | error |
|
|
52
|
+
| **Missing Return Types** | Exported functions without explicit return type | warning |
|
|
53
|
+
| **Missing Parameter Types** | Function parameters without type annotations | error |
|
|
54
|
+
| **Weak tsconfig** | `strict: true` not enabled in tsconfig.json | warning |
|
|
48
55
|
|
|
49
56
|
### Step 3: Generate Report
|
|
50
57
|
|
|
@@ -80,15 +87,27 @@ Status: {PASSED | FAILED}
|
|
|
80
87
|
TLC Audit Results
|
|
81
88
|
═══════════════════════════════════════════════════════════════
|
|
82
89
|
|
|
83
|
-
Status:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
Status: FAILED (18 issues found)
|
|
91
|
+
|
|
92
|
+
STRUCTURE
|
|
93
|
+
Standards Files: PASSED
|
|
94
|
+
Flat Folders: 3 issues
|
|
95
|
+
Overcrowded Folders: 2 issues (controllers/ has 22 files)
|
|
96
|
+
Oversized Files: 1 issue (csp.controller.ts: 2,041 lines)
|
|
97
|
+
|
|
98
|
+
TYPES & INTERFACES
|
|
99
|
+
Inline Interfaces: 2 issues
|
|
100
|
+
Inline Constants: 3 issues
|
|
101
|
+
any Type Usage: 5 issues
|
|
102
|
+
Missing Return Types: 4 issues
|
|
103
|
+
Missing Param Types: 2 issues
|
|
104
|
+
Weak tsconfig: PASSED
|
|
105
|
+
|
|
106
|
+
CODE QUALITY
|
|
107
|
+
Hardcoded URLs: 4 issues
|
|
108
|
+
Magic Strings: 2 issues
|
|
109
|
+
JSDoc Coverage: 8 issues (42% of exports undocumented)
|
|
110
|
+
Import Style: PASSED
|
|
92
111
|
|
|
93
112
|
Report saved to: .planning/AUDIT-REPORT.md
|
|
94
113
|
|
|
@@ -692,6 +692,11 @@ git diff --name-status main...HEAD
|
|
|
692
692
|
1. **Test Coverage** - Every implementation file has a test file
|
|
693
693
|
2. **TDD Compliance** - Commits show test-first pattern (score ≥ 50%)
|
|
694
694
|
3. **Security Scan** - No hardcoded secrets, eval(), innerHTML, etc.
|
|
695
|
+
4. **File Size** - No file exceeds 1000 lines (warning at 500+)
|
|
696
|
+
5. **Folder Size** - No folder exceeds 15 files (warning at 8+)
|
|
697
|
+
6. **Strict Typing** - No `any` types in new/changed files
|
|
698
|
+
7. **Return Types** - All exported functions have explicit return types
|
|
699
|
+
8. **Module Structure** - Files grouped by domain entity, not by type
|
|
695
700
|
|
|
696
701
|
**Review output:**
|
|
697
702
|
|
|
@@ -702,6 +707,10 @@ git diff --name-status main...HEAD
|
|
|
702
707
|
Test Coverage: ✅ 5/5 files covered
|
|
703
708
|
TDD Score: 75% ✅
|
|
704
709
|
Security: ✅ No issues
|
|
710
|
+
File Sizes: ✅ All under 1000 lines
|
|
711
|
+
Folder Sizes: ✅ All under 15 files
|
|
712
|
+
Strict Typing: ✅ No `any` found
|
|
713
|
+
Return Types: ✅ All exports typed
|
|
705
714
|
|
|
706
715
|
Verdict: ✅ APPROVED
|
|
707
716
|
───────────────────────────────
|
|
@@ -721,6 +730,18 @@ TDD Score: 25% ❌ (target: 50%)
|
|
|
721
730
|
Security: ❌ 1 high severity issue
|
|
722
731
|
└── Hardcoded password in src/config.js
|
|
723
732
|
|
|
733
|
+
File Sizes: ⚠️ 1 file over limit
|
|
734
|
+
└── src/api/users.controller.ts (1,247 lines) → split by feature
|
|
735
|
+
|
|
736
|
+
Strict Typing: ❌ 3 `any` types found
|
|
737
|
+
├── src/api/users.controller.ts:45 → define interface
|
|
738
|
+
├── src/api/users.controller.ts:89 → use `unknown`
|
|
739
|
+
└── src/services/email.ts:12 → define `EmailOptions` interface
|
|
740
|
+
|
|
741
|
+
Return Types: ⚠️ 2 exported functions missing return types
|
|
742
|
+
├── src/utils/helpers.ts:getConfig() → add `: AppConfig`
|
|
743
|
+
└── src/utils/helpers.ts:parseInput() → add `: ParsedInput`
|
|
744
|
+
|
|
724
745
|
Verdict: ❌ CHANGES REQUESTED
|
|
725
746
|
|
|
726
747
|
⚠️ Phase cannot complete until issues are fixed.
|
|
@@ -730,7 +751,10 @@ Verdict: ❌ CHANGES REQUESTED
|
|
|
730
751
|
**Actions on failure:**
|
|
731
752
|
1. Add missing test files
|
|
732
753
|
2. Fix security issues
|
|
733
|
-
3.
|
|
754
|
+
3. Split oversized files (>1000 lines) into focused sub-modules
|
|
755
|
+
4. Replace `any` types with proper interfaces or `unknown`
|
|
756
|
+
5. Add explicit return types to all exported functions
|
|
757
|
+
6. Re-run `/tlc:build {phase}` to retry
|
|
734
758
|
|
|
735
759
|
**CRITICAL: Phase is NOT complete until review passes.**
|
|
736
760
|
|
|
@@ -12,6 +12,10 @@ Automatically fix all coding standards violations. No prompts - just fixes every
|
|
|
12
12
|
- Extracts inline interfaces to types/ files
|
|
13
13
|
- Replaces magic strings with constants
|
|
14
14
|
- Adds missing JSDoc comments
|
|
15
|
+
- **Splits oversized files** (>1000 lines) into focused sub-modules
|
|
16
|
+
- **Organizes overcrowded folders** (>15 files) into domain subfolders
|
|
17
|
+
- **Replaces `any` types** with proper interfaces or `unknown`
|
|
18
|
+
- **Adds missing return types** to exported functions
|
|
15
19
|
4. Commits after each module/entity
|
|
16
20
|
5. Reports results when done
|
|
17
21
|
|
|
@@ -101,6 +105,72 @@ export function getUser(id: string): User { }
|
|
|
101
105
|
export function getUser(id: string): User { }
|
|
102
106
|
```
|
|
103
107
|
|
|
108
|
+
#### Oversized Files (>1000 lines)
|
|
109
|
+
```
|
|
110
|
+
// Before: csp.controller.ts (2,041 lines)
|
|
111
|
+
// Analyze the file's responsibilities and split by feature:
|
|
112
|
+
|
|
113
|
+
// After:
|
|
114
|
+
modules/csp/
|
|
115
|
+
controllers/
|
|
116
|
+
policy.controller.ts # Policy CRUD routes
|
|
117
|
+
report.controller.ts # Violation report routes
|
|
118
|
+
directive.controller.ts # Directive management routes
|
|
119
|
+
csp.routes.ts # Thin route registration
|
|
120
|
+
csp.service.ts # Shared business logic
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Split strategy:**
|
|
124
|
+
1. Count exported functions/methods and group by feature
|
|
125
|
+
2. Create a controller/service per feature group
|
|
126
|
+
3. Keep a thin "facade" file that re-exports or registers all routes
|
|
127
|
+
4. Move shared helpers to a utils file within the module
|
|
128
|
+
|
|
129
|
+
#### Overcrowded Folders (>15 files)
|
|
130
|
+
```
|
|
131
|
+
// Before: controllers/ with 22 files
|
|
132
|
+
// Group by domain:
|
|
133
|
+
|
|
134
|
+
// After:
|
|
135
|
+
modules/
|
|
136
|
+
auth/ # auth.controller.ts, auth.service.ts
|
|
137
|
+
user/ # user.controller.ts, user.service.ts
|
|
138
|
+
billing/ # payment.controller.ts, invoice.controller.ts
|
|
139
|
+
catalog/ # product.controller.ts, category.controller.ts
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### `any` Type Replacement
|
|
143
|
+
```typescript
|
|
144
|
+
// Before
|
|
145
|
+
function processData(data: any): any {
|
|
146
|
+
return data.items;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// After
|
|
150
|
+
interface ProcessInput {
|
|
151
|
+
items: unknown[];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function processData(data: ProcessInput): unknown[] {
|
|
155
|
+
return data.items;
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Strategy:** Read how the variable is used, infer the shape, create an interface.
|
|
160
|
+
|
|
161
|
+
#### Missing Return Types
|
|
162
|
+
```typescript
|
|
163
|
+
// Before
|
|
164
|
+
export function calculateTotal(items: CartItem[]) {
|
|
165
|
+
return items.reduce((sum, item) => sum + item.price, 0);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// After
|
|
169
|
+
export function calculateTotal(items: CartItem[]): number {
|
|
170
|
+
return items.reduce((sum, item) => sum + item.price, 0);
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
104
174
|
### Step 4: Commit After Each Module
|
|
105
175
|
|
|
106
176
|
After fixing all issues in an entity/module:
|
|
@@ -17,6 +17,12 @@ Research and create implementation plans with clear tasks.
|
|
|
17
17
|
- **Error boundaries**: Where can failures occur? How are they handled?
|
|
18
18
|
- **Data flow**: How does data enter, transform, and exit the system?
|
|
19
19
|
|
|
20
|
+
### Code Quality Gates
|
|
21
|
+
- **File size limit**: No file should exceed 1000 lines. Plan splits for large modules.
|
|
22
|
+
- **Folder limit**: No folder should exceed 15 files. Plan domain subfolders.
|
|
23
|
+
- **Strict typing**: Plan interfaces upfront — no `any` types, explicit return types.
|
|
24
|
+
- **Module structure**: Group by domain entity (NestJS-style), not by file type.
|
|
25
|
+
|
|
20
26
|
### Task Breakdown
|
|
21
27
|
- **Vertical slices**: Each task delivers testable, visible progress
|
|
22
28
|
- **Risk-first**: Tackle unknowns and integrations early
|
|
@@ -61,6 +67,13 @@ Each task should be:
|
|
|
61
67
|
- **Small** - completable in one focused session
|
|
62
68
|
- **Testable** - has clear pass/fail criteria
|
|
63
69
|
- **Independent** - minimal dependencies on other tasks
|
|
70
|
+
- **Standards-compliant** - won't produce files >1000 lines or folders >15 files
|
|
71
|
+
|
|
72
|
+
**Before finalizing tasks, check:**
|
|
73
|
+
1. Will any planned file exceed 1000 lines? → Split into sub-modules
|
|
74
|
+
2. Will any folder exceed 15 files? → Plan domain subfolders
|
|
75
|
+
3. Are all interfaces defined? → Add `interfaces/` directory per module
|
|
76
|
+
4. Are types explicit? → Plan typed interfaces, not `any`
|
|
64
77
|
|
|
65
78
|
#### Task Status Markers (Multi-User)
|
|
66
79
|
|
|
@@ -82,12 +95,15 @@ Use `/tlc:claim` to claim a task, `/tlc:release` to release one.
|
|
|
82
95
|
**Goal:** Define database schema for users table
|
|
83
96
|
|
|
84
97
|
**Files:**
|
|
85
|
-
- src/
|
|
98
|
+
- src/modules/user/interfaces/user.interface.ts
|
|
99
|
+
- src/modules/user/user.repository.ts
|
|
86
100
|
|
|
87
101
|
**Acceptance Criteria:**
|
|
88
102
|
- [ ] Schema has id, email, passwordHash, createdAt
|
|
89
103
|
- [ ] Email is unique
|
|
90
104
|
- [ ] Timestamps auto-populate
|
|
105
|
+
- [ ] All types explicit (no `any`)
|
|
106
|
+
- [ ] Exported functions have return types
|
|
91
107
|
|
|
92
108
|
**Test Cases:**
|
|
93
109
|
- Schema validates correct user data
|
|
@@ -42,6 +42,7 @@ Same checks as `/tlc:review`:
|
|
|
42
42
|
- Test coverage for changed files
|
|
43
43
|
- TDD compliance (commit order)
|
|
44
44
|
- Security scan
|
|
45
|
+
- **Coding standards** (file size, folder size, strict typing, return types, module structure)
|
|
45
46
|
|
|
46
47
|
### Step 4: Generate PR Comment
|
|
47
48
|
|
|
@@ -53,12 +54,17 @@ Same checks as `/tlc:review`:
|
|
|
53
54
|
| Test Coverage | ✅ All files covered |
|
|
54
55
|
| TDD Score | ✅ 75% |
|
|
55
56
|
| Security | ✅ No issues |
|
|
57
|
+
| File Sizes | ✅ All under 1000 lines |
|
|
58
|
+
| Folder Sizes | ✅ All under 15 files |
|
|
59
|
+
| Strict Typing | ✅ No `any` types |
|
|
60
|
+
| Return Types | ✅ All exports typed |
|
|
56
61
|
|
|
57
62
|
### Summary
|
|
58
63
|
|
|
59
64
|
- 8 files changed (5 impl, 3 tests)
|
|
60
65
|
- 4 commits analyzed
|
|
61
66
|
- No security vulnerabilities detected
|
|
67
|
+
- All coding standards met
|
|
62
68
|
|
|
63
69
|
### Verdict: ✅ APPROVED
|
|
64
70
|
|
|
@@ -134,6 +140,12 @@ TDD Score: 0% ❌
|
|
|
134
140
|
Security: ⚠️ 1 medium severity issue
|
|
135
141
|
└── console.log with sensitive data
|
|
136
142
|
|
|
143
|
+
Coding Standards: ❌ 4 issues
|
|
144
|
+
├── src/auth/login.js (1,247 lines) → split by feature
|
|
145
|
+
├── src/auth/login.js:45 → `any` type found
|
|
146
|
+
├── src/auth/login.js:89 → `any` type found
|
|
147
|
+
└── src/config.js:getConfig() → missing return type
|
|
148
|
+
|
|
137
149
|
Posting review...
|
|
138
150
|
|
|
139
151
|
─────────────────────────────────
|
|
@@ -145,6 +157,9 @@ See: https://github.com/org/repo/pull/43#review-123457
|
|
|
145
157
|
Required actions:
|
|
146
158
|
1. Add/update tests for modified files
|
|
147
159
|
2. Remove console.log with sensitive data
|
|
160
|
+
3. Split oversized file (>1000 lines)
|
|
161
|
+
4. Replace `any` types with proper interfaces
|
|
162
|
+
5. Add return types to exported functions
|
|
148
163
|
─────────────────────────────────
|
|
149
164
|
```
|
|
150
165
|
|
|
@@ -112,6 +112,65 @@ Scan diff for common security issues:
|
|
|
112
112
|
|
|
113
113
|
**Fail if:** Any HIGH severity issues found.
|
|
114
114
|
|
|
115
|
+
### Step 5b: Coding Standards Check
|
|
116
|
+
|
|
117
|
+
Scan all changed/added files for coding standards violations:
|
|
118
|
+
|
|
119
|
+
#### File Size Check
|
|
120
|
+
```bash
|
|
121
|
+
# For each changed implementation file
|
|
122
|
+
wc -l <file>
|
|
123
|
+
# >1000 lines = ERROR, 500-1000 = WARNING
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
#### Folder Size Check
|
|
127
|
+
```bash
|
|
128
|
+
# For each folder containing changed files
|
|
129
|
+
ls <folder> | wc -l
|
|
130
|
+
# >15 files = ERROR, 8-15 = WARNING
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
#### Strict Typing Check
|
|
134
|
+
```bash
|
|
135
|
+
# Scan changed .ts/.tsx files for `any` type
|
|
136
|
+
grep -n ': any' <file>
|
|
137
|
+
grep -n 'as any' <file>
|
|
138
|
+
grep -n '<any>' <file>
|
|
139
|
+
# Any match = ERROR
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### Return Type Check
|
|
143
|
+
```bash
|
|
144
|
+
# Scan changed .ts/.tsx files for exported functions missing return types
|
|
145
|
+
# Pattern: export function name(params) { (no : ReturnType before {)
|
|
146
|
+
grep -n 'export function.*)[[:space:]]*{' <file>
|
|
147
|
+
grep -n 'export const.*=.*=>.*{' <file>
|
|
148
|
+
# Missing return type on exported function = WARNING
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### Module Structure Check
|
|
152
|
+
```
|
|
153
|
+
# Flag flat folder anti-patterns in changed files:
|
|
154
|
+
# - src/services/ with >5 unrelated services → should be modules/{entity}/
|
|
155
|
+
# - src/controllers/ with >5 controllers → should be modules/{entity}/
|
|
156
|
+
# - src/interfaces/ at project root → should be per-module interfaces/
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Standards results in report:**
|
|
160
|
+
```
|
|
161
|
+
Coding Standards:
|
|
162
|
+
File Sizes: ✅ All under 1000 lines
|
|
163
|
+
Folder Sizes: ✅ All under 15 files
|
|
164
|
+
Strict Typing: ❌ 3 `any` types found
|
|
165
|
+
├── src/api/users.controller.ts:45
|
|
166
|
+
├── src/api/users.controller.ts:89
|
|
167
|
+
└── src/services/email.ts:12
|
|
168
|
+
Return Types: ⚠️ 2 missing on exports
|
|
169
|
+
Module Structure: ✅ Domain-grouped
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Fail if:** Any `any` types in new code, or files >1000 lines.
|
|
173
|
+
|
|
115
174
|
### Step 6: Invoke External Providers (Codex, Gemini)
|
|
116
175
|
|
|
117
176
|
**CRITICAL: This step runs automatically when providers are configured.**
|
|
@@ -220,6 +279,9 @@ Invoking Codex (GPT-5.2) for review...
|
|
|
220
279
|
- ✅ All changed files have tests
|
|
221
280
|
- ✅ TDD score: 75%
|
|
222
281
|
- ✅ No security issues detected
|
|
282
|
+
- ✅ All files under 1000 lines
|
|
283
|
+
- ✅ No `any` types
|
|
284
|
+
- ✅ All exports have return types
|
|
223
285
|
|
|
224
286
|
## Statistics
|
|
225
287
|
|
|
@@ -16,10 +16,185 @@ See `/tlc:build` for the complete engineering standards checklist.
|
|
|
16
16
|
|
|
17
17
|
## What This Does
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Detects project state, checks for TLC version upgrades, and launches the dashboard. If a newer TLC version is installed than the project has configured, it automatically upgrades config and commands before proceeding.
|
|
20
20
|
|
|
21
21
|
## Process
|
|
22
22
|
|
|
23
|
+
### Step 0: Check TLC Version (Upgrade Detection)
|
|
24
|
+
|
|
25
|
+
**Run this BEFORE anything else.** Compare installed TLC version against the project's `.tlc.json` version.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Get installed TLC version
|
|
29
|
+
installedVersion=$(node -e "
|
|
30
|
+
try {
|
|
31
|
+
const p = require('tlc-claude-code/package.json');
|
|
32
|
+
console.log(p.version);
|
|
33
|
+
} catch(e) {
|
|
34
|
+
// Try global
|
|
35
|
+
const { execSync } = require('child_process');
|
|
36
|
+
try {
|
|
37
|
+
const v = execSync('npm list -g tlc-claude-code --json 2>/dev/null', { encoding: 'utf-8' });
|
|
38
|
+
console.log(JSON.parse(v).dependencies['tlc-claude-code'].version);
|
|
39
|
+
} catch(e2) { console.log('unknown'); }
|
|
40
|
+
}
|
|
41
|
+
" 2>/dev/null)
|
|
42
|
+
|
|
43
|
+
# Get project TLC version from .tlc.json
|
|
44
|
+
projectVersion=$(node -e "
|
|
45
|
+
try {
|
|
46
|
+
const c = require('./.tlc.json');
|
|
47
|
+
console.log(c.tlcVersion || '0.0.0');
|
|
48
|
+
} catch(e) { console.log('0.0.0'); }
|
|
49
|
+
" 2>/dev/null)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**If `installedVersion` > `projectVersion`:**
|
|
53
|
+
|
|
54
|
+
Show upgrade notice and apply automatically:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
─────────────────────────────────────────────────────
|
|
58
|
+
TLC UPGRADE DETECTED
|
|
59
|
+
─────────────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
Installed: v{installedVersion}
|
|
62
|
+
Project: v{projectVersion}
|
|
63
|
+
|
|
64
|
+
New in this version:
|
|
65
|
+
{list new features — see Version Features Map below}
|
|
66
|
+
|
|
67
|
+
Applying upgrade...
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Then execute the upgrade steps:
|
|
71
|
+
|
|
72
|
+
#### Step 0.1: Merge New Config Sections into .tlc.json
|
|
73
|
+
|
|
74
|
+
Read the project's `.tlc.json`. For each new config section introduced since `projectVersion`, **add it ONLY if it doesn't already exist**. Never overwrite existing user settings.
|
|
75
|
+
|
|
76
|
+
```javascript
|
|
77
|
+
// Pseudo-code for config merge
|
|
78
|
+
const config = JSON.parse(fs.readFileSync('.tlc.json'));
|
|
79
|
+
|
|
80
|
+
// Add new sections only if missing
|
|
81
|
+
if (!config.router) {
|
|
82
|
+
config.router = {
|
|
83
|
+
providers: {},
|
|
84
|
+
capabilities: {}
|
|
85
|
+
};
|
|
86
|
+
console.log(' + Added: router (LLM provider routing)');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!config.dashboard) {
|
|
90
|
+
config.dashboard = {
|
|
91
|
+
port: 3147,
|
|
92
|
+
auth: false
|
|
93
|
+
};
|
|
94
|
+
console.log(' + Added: dashboard config');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!config.docs) {
|
|
98
|
+
config.docs = {
|
|
99
|
+
autoSync: false,
|
|
100
|
+
screenshots: []
|
|
101
|
+
};
|
|
102
|
+
console.log(' + Added: docs automation config');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Update version stamp
|
|
106
|
+
config.tlcVersion = installedVersion;
|
|
107
|
+
|
|
108
|
+
fs.writeFileSync('.tlc.json', JSON.stringify(config, null, 2));
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
#### Step 0.2: Update CLAUDE.md Command Dispatch
|
|
112
|
+
|
|
113
|
+
Read the project's `CLAUDE.md`. Check if the command dispatch table exists. If new commands were added since `projectVersion`, append them to the table.
|
|
114
|
+
|
|
115
|
+
**How to detect:** Read `.claude/commands/tlc/*.md` directory listing from the installed TLC package. Compare against the dispatch table entries in the project's `CLAUDE.md`. Add any missing rows.
|
|
116
|
+
|
|
117
|
+
**Never remove or reorder existing entries.** Only append new ones.
|
|
118
|
+
|
|
119
|
+
#### Step 0.3: Sync Command Files
|
|
120
|
+
|
|
121
|
+
The `.claude/commands/tlc/` directory should already be up-to-date if the user ran `tlc` (the CLI installer). But verify:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# Check if commands are current
|
|
125
|
+
installedCommandCount=$(ls node_modules/tlc-claude-code/.claude/commands/tlc/*.md 2>/dev/null | wc -l)
|
|
126
|
+
projectCommandCount=$(ls .claude/commands/tlc/*.md 2>/dev/null | wc -l)
|
|
127
|
+
|
|
128
|
+
if [ "$installedCommandCount" -gt "$projectCommandCount" ]; then
|
|
129
|
+
echo " + Syncing new commands to .claude/commands/tlc/"
|
|
130
|
+
cp node_modules/tlc-claude-code/.claude/commands/tlc/*.md .claude/commands/tlc/
|
|
131
|
+
fi
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### Step 0.4: Detect New LLM Providers
|
|
135
|
+
|
|
136
|
+
If the `router` section was just added (or is empty), scan for available CLI tools:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
which claude >/dev/null 2>&1 && echo "claude detected"
|
|
140
|
+
which codex >/dev/null 2>&1 && echo "codex detected"
|
|
141
|
+
which gemini >/dev/null 2>&1 && echo "gemini detected"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
If providers are detected but `router.providers` is empty, offer to configure:
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
LLM providers detected: claude, codex
|
|
148
|
+
|
|
149
|
+
Configure multi-model routing? (Y/n)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
If yes, populate `router.providers` with detected CLIs and default capability mappings.
|
|
153
|
+
|
|
154
|
+
If no, skip — user can run `/tlc:llm config` later.
|
|
155
|
+
|
|
156
|
+
#### Step 0.5: Report and Continue
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
─────────────────────────────────────────────────────
|
|
160
|
+
UPGRADE COMPLETE
|
|
161
|
+
─────────────────────────────────────────────────────
|
|
162
|
+
|
|
163
|
+
Updated .tlc.json:
|
|
164
|
+
+ router (LLM provider routing)
|
|
165
|
+
+ dashboard config
|
|
166
|
+
+ docs automation config
|
|
167
|
+
~ tlcVersion: 0.0.0 → 1.8.2
|
|
168
|
+
|
|
169
|
+
Synced:
|
|
170
|
+
+ 3 new commands added
|
|
171
|
+
+ CLAUDE.md dispatch table updated
|
|
172
|
+
|
|
173
|
+
Configure LLM routing now? → /tlc:llm config
|
|
174
|
+
Configure dashboard? → /tlc:dashboard
|
|
175
|
+
|
|
176
|
+
Continuing to dashboard...
|
|
177
|
+
─────────────────────────────────────────────────────
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Then continue to Step 1 (launch dashboard) as normal.
|
|
181
|
+
|
|
182
|
+
**If versions match:** Skip this step silently. No output.
|
|
183
|
+
|
|
184
|
+
#### Version Features Map
|
|
185
|
+
|
|
186
|
+
This map tells the upgrade which config sections to add based on version ranges. Update this when new features ship.
|
|
187
|
+
|
|
188
|
+
| Since Version | Config Section | Default Value | Description |
|
|
189
|
+
|---|---|---|---|
|
|
190
|
+
| 1.5.0 | `router` | `{ providers: {}, capabilities: {} }` | LLM multi-model routing |
|
|
191
|
+
| 1.5.0 | `enterprise` | `{ enabled: false }` | Enterprise features toggle |
|
|
192
|
+
| 1.7.0 | `docs` | `{ autoSync: false, screenshots: [] }` | Documentation automation |
|
|
193
|
+
| 1.8.0 | `dashboard` | `{ port: 3147, auth: false }` | Dashboard configuration |
|
|
194
|
+
| 1.8.2 | `dashboard.compose` | `"docker-compose.tlc.yml"` | Standalone dashboard compose file |
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
23
198
|
### Step 1: Launch Dashboard
|
|
24
199
|
|
|
25
200
|
Run the TLC dashboard:
|
package/CODING-STANDARDS.md
CHANGED
|
@@ -588,6 +588,141 @@ Refs: #456
|
|
|
588
588
|
|
|
589
589
|
---
|
|
590
590
|
|
|
591
|
+
## 18. File Size Limits
|
|
592
|
+
|
|
593
|
+
Large files are a code smell. They indicate a class or module is doing too much.
|
|
594
|
+
|
|
595
|
+
| Threshold | Action |
|
|
596
|
+
|---|---|
|
|
597
|
+
| **< 300 lines** | Ideal. No action needed. |
|
|
598
|
+
| **300-500 lines** | Acceptable. Review if it can be split. |
|
|
599
|
+
| **500-1000 lines** | Warning. Should be split into focused sub-modules. |
|
|
600
|
+
| **> 1000 lines** | Violation. MUST be split before merging. |
|
|
601
|
+
|
|
602
|
+
### How to Split
|
|
603
|
+
|
|
604
|
+
**Controllers with many routes:**
|
|
605
|
+
```
|
|
606
|
+
# Bad: csp.controller.ts (2,000+ lines)
|
|
607
|
+
# Good: Split by resource/feature:
|
|
608
|
+
modules/csp/
|
|
609
|
+
controllers/
|
|
610
|
+
policy.controller.ts # CRUD for policies
|
|
611
|
+
report.controller.ts # CSP violation reports
|
|
612
|
+
directive.controller.ts # Directive management
|
|
613
|
+
csp.routes.ts # Route registration (thin)
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
**Services with many methods:**
|
|
617
|
+
```
|
|
618
|
+
# Bad: user.service.ts (1,500 lines)
|
|
619
|
+
# Good: Split by responsibility:
|
|
620
|
+
modules/user/
|
|
621
|
+
services/
|
|
622
|
+
user-auth.service.ts # Login, register, password reset
|
|
623
|
+
user-profile.service.ts # Profile CRUD, avatar, preferences
|
|
624
|
+
user-admin.service.ts # Admin operations, ban, role changes
|
|
625
|
+
user.service.ts # Thin facade re-exporting sub-services
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
---
|
|
629
|
+
|
|
630
|
+
## 19. Folder Overcrowding
|
|
631
|
+
|
|
632
|
+
Too many files in one folder makes navigation difficult. Organize into subfolders by domain.
|
|
633
|
+
|
|
634
|
+
| Threshold | Action |
|
|
635
|
+
|---|---|
|
|
636
|
+
| **< 8 files** | Fine as-is. |
|
|
637
|
+
| **8-15 files** | Consider grouping into subfolders. |
|
|
638
|
+
| **> 15 files** | MUST be organized into subfolders. |
|
|
639
|
+
|
|
640
|
+
```
|
|
641
|
+
# Bad: 25 files dumped in controllers/
|
|
642
|
+
controllers/
|
|
643
|
+
auth.controller.ts
|
|
644
|
+
user.controller.ts
|
|
645
|
+
payment.controller.ts
|
|
646
|
+
invoice.controller.ts
|
|
647
|
+
product.controller.ts
|
|
648
|
+
... (20 more)
|
|
649
|
+
|
|
650
|
+
# Good: Organized by domain
|
|
651
|
+
modules/
|
|
652
|
+
auth/auth.controller.ts
|
|
653
|
+
user/user.controller.ts
|
|
654
|
+
billing/
|
|
655
|
+
payment.controller.ts
|
|
656
|
+
invoice.controller.ts
|
|
657
|
+
catalog/
|
|
658
|
+
product.controller.ts
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
---
|
|
662
|
+
|
|
663
|
+
## 20. Strict Typing
|
|
664
|
+
|
|
665
|
+
TypeScript without strict types is just JavaScript with extra steps.
|
|
666
|
+
|
|
667
|
+
### Rules
|
|
668
|
+
|
|
669
|
+
1. **No `any` type** - Use `unknown` and narrow, or define a proper interface.
|
|
670
|
+
2. **No implicit `any`** - Enable `noImplicitAny` in tsconfig.
|
|
671
|
+
3. **All functions must have explicit return types** - Not just exported functions.
|
|
672
|
+
4. **All parameters must be typed** - No untyped function parameters.
|
|
673
|
+
5. **Prefer `interface` over `type`** for object shapes - Easier to extend.
|
|
674
|
+
6. **Use `strict: true`** in tsconfig.json.
|
|
675
|
+
|
|
676
|
+
```typescript
|
|
677
|
+
// Bad: Missing types, implicit any
|
|
678
|
+
function processData(data) {
|
|
679
|
+
const result = data.items.map(item => item.value);
|
|
680
|
+
return result;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// Good: Explicit types everywhere
|
|
684
|
+
interface DataPayload {
|
|
685
|
+
items: Array<{ value: number }>;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
function processData(data: DataPayload): number[] {
|
|
689
|
+
return data.items.map((item) => item.value);
|
|
690
|
+
}
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
```typescript
|
|
694
|
+
// Bad: any type
|
|
695
|
+
function handleResponse(response: any): any {
|
|
696
|
+
return response.data;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// Good: Proper types
|
|
700
|
+
interface ApiResponse<T> {
|
|
701
|
+
data: T;
|
|
702
|
+
status: number;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
function handleResponse<T>(response: ApiResponse<T>): T {
|
|
706
|
+
return response.data;
|
|
707
|
+
}
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
### tsconfig.json Requirements
|
|
711
|
+
|
|
712
|
+
```json
|
|
713
|
+
{
|
|
714
|
+
"compilerOptions": {
|
|
715
|
+
"strict": true,
|
|
716
|
+
"noImplicitAny": true,
|
|
717
|
+
"noImplicitReturns": true,
|
|
718
|
+
"noUnusedLocals": true,
|
|
719
|
+
"noUnusedParameters": true
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
---
|
|
725
|
+
|
|
591
726
|
## AI Instructions
|
|
592
727
|
|
|
593
728
|
When generating code:
|
|
@@ -605,6 +740,10 @@ When generating code:
|
|
|
605
740
|
11. **Always** add JSDoc to public members
|
|
606
741
|
12. **Always** create index.ts with barrel exports
|
|
607
742
|
13. **Always** verify build passes after changes
|
|
743
|
+
14. **Never** let files exceed 1000 lines - split into sub-modules
|
|
744
|
+
15. **Never** let folders exceed 15 files - organize into subfolders
|
|
745
|
+
16. **Never** use `any` type - use `unknown` or proper interfaces
|
|
746
|
+
17. **Always** add explicit return types to functions
|
|
608
747
|
|
|
609
748
|
### Cleanup Tasks
|
|
610
749
|
|
package/package.json
CHANGED
package/server/index.js
CHANGED
|
@@ -57,6 +57,7 @@ const EXTERNAL_APP_PORT = parseInt(process.env.TLC_APP_PORT || '5000');
|
|
|
57
57
|
// State
|
|
58
58
|
let appProcess = null;
|
|
59
59
|
let appPort = 3000;
|
|
60
|
+
let appIsDocker = false; // true when app is Docker-managed (no local process)
|
|
60
61
|
let wsClients = new Set();
|
|
61
62
|
const logs = { app: [], test: [], git: [] };
|
|
62
63
|
const commandHistory = [];
|
|
@@ -485,6 +486,19 @@ async function startApp() {
|
|
|
485
486
|
|
|
486
487
|
appPort = project.port;
|
|
487
488
|
addLog('app', `Detected: ${project.name}`, 'info');
|
|
489
|
+
|
|
490
|
+
// Docker-managed apps: don't spawn, just proxy
|
|
491
|
+
if (project.type === 'docker') {
|
|
492
|
+
appIsDocker = true;
|
|
493
|
+
addLog('app', `App is Docker-managed — proxying to port ${appPort}`, 'info');
|
|
494
|
+
if (project.url) {
|
|
495
|
+
addLog('app', `App URL: ${project.url}`, 'info');
|
|
496
|
+
}
|
|
497
|
+
addLog('app', 'TLC will not spawn the app. Use Docker to manage it.', 'info');
|
|
498
|
+
broadcast('app-start', { port: appPort });
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
|
|
488
502
|
addLog('app', `Command: ${project.cmd} ${project.args.join(' ')}`, 'info');
|
|
489
503
|
addLog('app', `Port: ${appPort}`, 'info');
|
|
490
504
|
|
|
@@ -673,7 +687,7 @@ app.get('/api/status', (req, res) => {
|
|
|
673
687
|
const plan = parsePlan(PROJECT_DIR);
|
|
674
688
|
|
|
675
689
|
res.json({
|
|
676
|
-
appRunning: appProcess !== null,
|
|
690
|
+
appRunning: appProcess !== null || appIsDocker,
|
|
677
691
|
appPort,
|
|
678
692
|
testsPass: plan.testsPass || 0,
|
|
679
693
|
testsFail: plan.testsFail || 0,
|
|
@@ -1087,7 +1101,7 @@ app.get('/api/health', (req, res) => {
|
|
|
1087
1101
|
heapUsed: memUsage.heapUsed,
|
|
1088
1102
|
heapTotal: memUsage.heapTotal,
|
|
1089
1103
|
},
|
|
1090
|
-
appRunning: appProcess !== null,
|
|
1104
|
+
appRunning: appProcess !== null || appIsDocker,
|
|
1091
1105
|
appPort,
|
|
1092
1106
|
});
|
|
1093
1107
|
});
|
|
@@ -1486,7 +1500,7 @@ function getHealthData() {
|
|
|
1486
1500
|
memory: memUsed,
|
|
1487
1501
|
cpu: Math.min(cpuPercent, 100),
|
|
1488
1502
|
uptime: process.uptime(),
|
|
1489
|
-
appRunning: appProcess !== null,
|
|
1503
|
+
appRunning: appProcess !== null || appIsDocker,
|
|
1490
1504
|
appPort: appPort
|
|
1491
1505
|
};
|
|
1492
1506
|
}
|
|
@@ -10,6 +10,33 @@ function detectProject(projectDir) {
|
|
|
10
10
|
if (fs.existsSync(tlcConfigPath)) {
|
|
11
11
|
try {
|
|
12
12
|
const config = JSON.parse(fs.readFileSync(tlcConfigPath, 'utf-8'));
|
|
13
|
+
|
|
14
|
+
// Check devServer config (Docker-managed apps)
|
|
15
|
+
if (config.devServer) {
|
|
16
|
+
if (config.devServer.type === 'docker') {
|
|
17
|
+
return {
|
|
18
|
+
name: 'Docker-managed (' + (config.devServer.containerName || 'docker') + ')',
|
|
19
|
+
type: 'docker',
|
|
20
|
+
cmd: null,
|
|
21
|
+
args: [],
|
|
22
|
+
port: config.devServer.port || config.devServer.internalPort || 5000,
|
|
23
|
+
healthCheck: config.devServer.healthCheck || null,
|
|
24
|
+
url: config.devServer.url || null
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
// Non-docker devServer with explicit start command
|
|
28
|
+
if (config.devServer.startCommand) {
|
|
29
|
+
const parts = config.devServer.startCommand.split(' ');
|
|
30
|
+
return {
|
|
31
|
+
name: 'Custom (.tlc.json devServer)',
|
|
32
|
+
cmd: parts[0],
|
|
33
|
+
args: parts.slice(1),
|
|
34
|
+
port: config.devServer.port || 3000
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Legacy: check server config
|
|
13
40
|
if (config.server?.startCommand) {
|
|
14
41
|
const parts = config.server.startCommand.split(' ');
|
|
15
42
|
return {
|