tlc-claude-code 1.2.28 → 1.3.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/README.md +9 -4
- package/dashboard/dist/components/UsagePane.d.ts +13 -0
- package/dashboard/dist/components/UsagePane.js +51 -0
- package/dashboard/dist/components/UsagePane.test.d.ts +1 -0
- package/dashboard/dist/components/UsagePane.test.js +142 -0
- package/dashboard/dist/components/WorkspaceDocsPane.d.ts +19 -0
- package/dashboard/dist/components/WorkspaceDocsPane.js +146 -0
- package/dashboard/dist/components/WorkspaceDocsPane.test.d.ts +1 -0
- package/dashboard/dist/components/WorkspaceDocsPane.test.js +242 -0
- package/dashboard/dist/components/WorkspacePane.d.ts +18 -0
- package/dashboard/dist/components/WorkspacePane.js +17 -0
- package/dashboard/dist/components/WorkspacePane.test.d.ts +1 -0
- package/dashboard/dist/components/WorkspacePane.test.js +84 -0
- package/package.json +15 -4
- package/scripts/capture-screenshots.js +170 -0
- package/scripts/docs-update.js +253 -0
- package/scripts/generate-screenshots.js +321 -0
- package/scripts/project-docs.js +377 -0
- package/scripts/vps-setup.sh +477 -0
- package/server/lib/architecture-command.js +450 -0
- package/server/lib/architecture-command.test.js +754 -0
- package/server/lib/ast-analyzer.js +324 -0
- package/server/lib/ast-analyzer.test.js +437 -0
- package/server/lib/auth-system.test.js +4 -1
- package/server/lib/boundary-detector.js +427 -0
- package/server/lib/boundary-detector.test.js +320 -0
- package/server/lib/budget-alerts.js +138 -0
- package/server/lib/budget-alerts.test.js +235 -0
- package/server/lib/candidates-tracker.js +210 -0
- package/server/lib/candidates-tracker.test.js +300 -0
- package/server/lib/checkpoint-manager.js +251 -0
- package/server/lib/checkpoint-manager.test.js +474 -0
- package/server/lib/circular-detector.js +337 -0
- package/server/lib/circular-detector.test.js +353 -0
- package/server/lib/cohesion-analyzer.js +310 -0
- package/server/lib/cohesion-analyzer.test.js +447 -0
- package/server/lib/contract-testing.js +625 -0
- package/server/lib/contract-testing.test.js +342 -0
- package/server/lib/conversion-planner.js +469 -0
- package/server/lib/conversion-planner.test.js +361 -0
- package/server/lib/convert-command.js +351 -0
- package/server/lib/convert-command.test.js +608 -0
- package/server/lib/coupling-calculator.js +189 -0
- package/server/lib/coupling-calculator.test.js +509 -0
- package/server/lib/dependency-graph.js +367 -0
- package/server/lib/dependency-graph.test.js +516 -0
- package/server/lib/duplication-detector.js +349 -0
- package/server/lib/duplication-detector.test.js +401 -0
- package/server/lib/example-service.js +616 -0
- package/server/lib/example-service.test.js +397 -0
- package/server/lib/impact-scorer.js +184 -0
- package/server/lib/impact-scorer.test.js +211 -0
- package/server/lib/mermaid-generator.js +358 -0
- package/server/lib/mermaid-generator.test.js +301 -0
- package/server/lib/messaging-patterns.js +750 -0
- package/server/lib/messaging-patterns.test.js +213 -0
- package/server/lib/microservice-template.js +386 -0
- package/server/lib/microservice-template.test.js +325 -0
- package/server/lib/new-project-microservice.js +450 -0
- package/server/lib/new-project-microservice.test.js +600 -0
- package/server/lib/refactor-command.js +326 -0
- package/server/lib/refactor-command.test.js +528 -0
- package/server/lib/refactor-executor.js +254 -0
- package/server/lib/refactor-executor.test.js +305 -0
- package/server/lib/refactor-observer.js +292 -0
- package/server/lib/refactor-observer.test.js +422 -0
- package/server/lib/refactor-progress.js +193 -0
- package/server/lib/refactor-progress.test.js +251 -0
- package/server/lib/refactor-reporter.js +237 -0
- package/server/lib/refactor-reporter.test.js +247 -0
- package/server/lib/semantic-analyzer.js +198 -0
- package/server/lib/semantic-analyzer.test.js +474 -0
- package/server/lib/service-scaffold.js +486 -0
- package/server/lib/service-scaffold.test.js +373 -0
- package/server/lib/shared-kernel.js +578 -0
- package/server/lib/shared-kernel.test.js +255 -0
- package/server/lib/traefik-config.js +282 -0
- package/server/lib/traefik-config.test.js +312 -0
- package/server/lib/usage-command.js +218 -0
- package/server/lib/usage-command.test.js +391 -0
- package/server/lib/usage-formatter.js +192 -0
- package/server/lib/usage-formatter.test.js +267 -0
- package/server/lib/usage-history.js +122 -0
- package/server/lib/usage-history.test.js +206 -0
- package/server/package-lock.json +14 -0
- package/server/package.json +1 -0
- package/templates/docs-sync.yml +91 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Generate terminal-style screenshots for documentation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { generateSync } = require('text-to-image');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
const OUTPUT_DIR = path.join(__dirname, '../docs/wiki/images');
|
|
11
|
+
|
|
12
|
+
// Terminal styling
|
|
13
|
+
const options = {
|
|
14
|
+
bgColor: '#1e1e1e',
|
|
15
|
+
textColor: '#d4d4d4',
|
|
16
|
+
fontFamily: 'Consolas, Monaco, monospace',
|
|
17
|
+
fontSize: 14,
|
|
18
|
+
lineHeight: 20,
|
|
19
|
+
margin: 20,
|
|
20
|
+
maxWidth: 700,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Screenshot definitions
|
|
24
|
+
const screenshots = {
|
|
25
|
+
'dashboard-overview': `
|
|
26
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
27
|
+
│ TLC Dashboard v1.2.28 │
|
|
28
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
29
|
+
│ │
|
|
30
|
+
│ Project: my-awesome-app │
|
|
31
|
+
│ Phase 2: User Authentication ████████░░ 80% │
|
|
32
|
+
│ │
|
|
33
|
+
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
|
34
|
+
│ │ Tasks │ │ Tests │ │ Coverage │ │
|
|
35
|
+
│ │ ██████████ 4/5 │ │ ✓ 47 passing │ │ 87% │ │
|
|
36
|
+
│ │ │ │ ✗ 2 failing │ │ ████████░░ │ │
|
|
37
|
+
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
|
|
38
|
+
│ │
|
|
39
|
+
│ Team: @alice (Task 3) @bob (Task 4) @charlie (available) │
|
|
40
|
+
│ │
|
|
41
|
+
│ [1] Tasks [2] Logs [3] Preview [4] Team [?] Help │
|
|
42
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
43
|
+
`,
|
|
44
|
+
|
|
45
|
+
'tlc-next-prompt': `
|
|
46
|
+
$ /tlc:next
|
|
47
|
+
|
|
48
|
+
Phase 2: User Authentication
|
|
49
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
50
|
+
|
|
51
|
+
Next: Build remaining 3 tasks (auto-parallel)
|
|
52
|
+
• Task 3: Session management
|
|
53
|
+
• Task 4: Password reset
|
|
54
|
+
• Task 5: OAuth integration
|
|
55
|
+
|
|
56
|
+
Proceed? [Y/n]: _
|
|
57
|
+
`,
|
|
58
|
+
|
|
59
|
+
'tlc-progress': `
|
|
60
|
+
$ /tlc:progress
|
|
61
|
+
|
|
62
|
+
my-awesome-app - Progress
|
|
63
|
+
═══════════════════════════════════════════════════════════════
|
|
64
|
+
|
|
65
|
+
Milestone: v1.0
|
|
66
|
+
Phase 2: User Authentication ████████░░ 80%
|
|
67
|
+
|
|
68
|
+
Tasks:
|
|
69
|
+
[x] 1. Create user schema @alice
|
|
70
|
+
[x] 2. Add validation @bob
|
|
71
|
+
[>] 3. Session management @alice (in progress)
|
|
72
|
+
[ ] 4. Password reset
|
|
73
|
+
[ ] 5. OAuth integration
|
|
74
|
+
|
|
75
|
+
Tests: 47 passing | 2 failing
|
|
76
|
+
Coverage: 87%
|
|
77
|
+
|
|
78
|
+
Next: Complete Task 3, then /tlc:build continues
|
|
79
|
+
`,
|
|
80
|
+
|
|
81
|
+
'build-parallel': `
|
|
82
|
+
$ /tlc:build 2
|
|
83
|
+
|
|
84
|
+
Analyzing task dependencies...
|
|
85
|
+
|
|
86
|
+
Independent tasks detected: 4
|
|
87
|
+
Starting parallel build with 4 agents...
|
|
88
|
+
|
|
89
|
+
Agent 1 ████████░░ Task 1: Create schema
|
|
90
|
+
Agent 2 ██████░░░░ Task 2: Add validation
|
|
91
|
+
Agent 3 ████░░░░░░ Task 3: Create endpoints
|
|
92
|
+
Agent 4 ██░░░░░░░░ Task 4: Error handling
|
|
93
|
+
|
|
94
|
+
Tests: 12 passing | 3 failing (in progress)
|
|
95
|
+
|
|
96
|
+
Agent 1 completed: Task 1 ✓
|
|
97
|
+
Agent 2 completed: Task 2 ✓
|
|
98
|
+
`,
|
|
99
|
+
|
|
100
|
+
'tlc-who': `
|
|
101
|
+
$ /tlc:who
|
|
102
|
+
|
|
103
|
+
Phase 2: User Authentication
|
|
104
|
+
═══════════════════════════════════════════════════════════════
|
|
105
|
+
|
|
106
|
+
Team Activity:
|
|
107
|
+
|
|
108
|
+
@alice
|
|
109
|
+
✓ Task 1: Create user schema (completed 2h ago)
|
|
110
|
+
→ Task 3: Session management (working now)
|
|
111
|
+
|
|
112
|
+
@bob
|
|
113
|
+
✓ Task 2: Add validation (completed 1h ago)
|
|
114
|
+
→ Task 4: Password reset (working now)
|
|
115
|
+
|
|
116
|
+
@charlie
|
|
117
|
+
No tasks claimed
|
|
118
|
+
|
|
119
|
+
Available Tasks:
|
|
120
|
+
[ ] Task 5: OAuth integration
|
|
121
|
+
|
|
122
|
+
Open Bugs: 1
|
|
123
|
+
BUG-012: Medium - Session expires too quickly
|
|
124
|
+
`,
|
|
125
|
+
|
|
126
|
+
'dashboard-tasks': `
|
|
127
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
128
|
+
│ Task Board Phase 2 │
|
|
129
|
+
├───────────────────┬───────────────────┬─────────────────────────┤
|
|
130
|
+
│ TODO │ IN PROGRESS │ DONE │
|
|
131
|
+
├───────────────────┼───────────────────┼─────────────────────────┤
|
|
132
|
+
│ │ │ │
|
|
133
|
+
│ ┌─────────────┐ │ ┌─────────────┐ │ ┌─────────────┐ │
|
|
134
|
+
│ │ Task 5 │ │ │ Task 3 │ │ │ Task 1 │ │
|
|
135
|
+
│ │ OAuth │ │ │ Sessions │ │ │ Schema │ │
|
|
136
|
+
│ │ │ │ │ @alice │ │ │ @alice ✓ │ │
|
|
137
|
+
│ └─────────────┘ │ ├─────────────┤ │ ├─────────────┤ │
|
|
138
|
+
│ │ │ Task 4 │ │ │ Task 2 │ │
|
|
139
|
+
│ │ │ Password │ │ │ Validation │ │
|
|
140
|
+
│ │ │ @bob │ │ │ @bob ✓ │ │
|
|
141
|
+
│ │ └─────────────┘ │ └─────────────┘ │
|
|
142
|
+
│ │ │ │
|
|
143
|
+
├───────────────────┴───────────────────┴─────────────────────────┤
|
|
144
|
+
│ [h/l] Move [j/k] Navigate [m] Move task [Enter] Details │
|
|
145
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
146
|
+
`,
|
|
147
|
+
|
|
148
|
+
'dashboard-logs': `
|
|
149
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
150
|
+
│ Log Stream [Auto-scroll ON] │
|
|
151
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
152
|
+
│ Filter: [All] [app] [test] [git] Search: _________ │
|
|
153
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
154
|
+
│ │
|
|
155
|
+
│ 14:32:01 [app] Server started on port 5001 │
|
|
156
|
+
│ 14:32:03 [app] Connected to database │
|
|
157
|
+
│ 14:32:15 [test] Running test suite... │
|
|
158
|
+
│ 14:32:16 [test] ✓ user.create returns 201 │
|
|
159
|
+
│ 14:32:16 [test] ✓ user.create validates email │
|
|
160
|
+
│ 14:32:17 [test] ✗ user.login handles expired session │
|
|
161
|
+
│ 14:32:18 [git] Commit: feat: add session management │
|
|
162
|
+
│ 14:32:20 [app] Request: POST /api/users │
|
|
163
|
+
│ 14:32:21 [app] Response: 201 Created (23ms) │
|
|
164
|
+
│ │
|
|
165
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
166
|
+
│ [/] Search [f] Filter [c] Clear [Space] Pause │
|
|
167
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
168
|
+
`,
|
|
169
|
+
|
|
170
|
+
'dashboard-team': `
|
|
171
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
172
|
+
│ Team │
|
|
173
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
174
|
+
│ │
|
|
175
|
+
│ Online │
|
|
176
|
+
│ ──────── │
|
|
177
|
+
│ ● @alice Task 3: Session management 2m ago │
|
|
178
|
+
│ ● @bob Task 4: Password reset 5m ago │
|
|
179
|
+
│ │
|
|
180
|
+
│ Away │
|
|
181
|
+
│ ──────── │
|
|
182
|
+
│ ○ @charlie No task claimed 1h ago │
|
|
183
|
+
│ │
|
|
184
|
+
│ Activity Feed │
|
|
185
|
+
│ ──────────── │
|
|
186
|
+
│ 14:30 @alice committed "add session middleware" │
|
|
187
|
+
│ 14:25 @bob claimed Task 4 │
|
|
188
|
+
│ 14:20 @alice completed Task 1 │
|
|
189
|
+
│ 14:15 @charlie released Task 3 │
|
|
190
|
+
│ │
|
|
191
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
192
|
+
`,
|
|
193
|
+
|
|
194
|
+
'test-first-red': `
|
|
195
|
+
$ npm test
|
|
196
|
+
|
|
197
|
+
User Authentication
|
|
198
|
+
✗ creates user with valid data
|
|
199
|
+
Expected: 201
|
|
200
|
+
Received: undefined
|
|
201
|
+
|
|
202
|
+
✗ rejects duplicate email
|
|
203
|
+
Error: Cannot read property 'status' of undefined
|
|
204
|
+
|
|
205
|
+
✗ hashes password before storing
|
|
206
|
+
Expected: password to be hashed
|
|
207
|
+
Received: undefined
|
|
208
|
+
|
|
209
|
+
3 failing (0 passing)
|
|
210
|
+
|
|
211
|
+
─────────────────────────────────────────────────────────────
|
|
212
|
+
RED PHASE: Tests written, implementation needed
|
|
213
|
+
─────────────────────────────────────────────────────────────
|
|
214
|
+
`,
|
|
215
|
+
|
|
216
|
+
'test-first-green': `
|
|
217
|
+
$ npm test
|
|
218
|
+
|
|
219
|
+
User Authentication
|
|
220
|
+
✓ creates user with valid data (12ms)
|
|
221
|
+
✓ rejects duplicate email (8ms)
|
|
222
|
+
✓ hashes password before storing (15ms)
|
|
223
|
+
✓ validates email format (3ms)
|
|
224
|
+
✓ requires password minimum length (2ms)
|
|
225
|
+
|
|
226
|
+
Session Management
|
|
227
|
+
✓ creates session on login (18ms)
|
|
228
|
+
✓ invalidates session on logout (5ms)
|
|
229
|
+
|
|
230
|
+
7 passing (63ms)
|
|
231
|
+
|
|
232
|
+
─────────────────────────────────────────────────────────────
|
|
233
|
+
GREEN PHASE: All tests passing ✓
|
|
234
|
+
─────────────────────────────────────────────────────────────
|
|
235
|
+
`,
|
|
236
|
+
|
|
237
|
+
'auto-review': `
|
|
238
|
+
$ /tlc:build 2 (auto-review)
|
|
239
|
+
|
|
240
|
+
═══════════════════════════════════════════════════════════════
|
|
241
|
+
Auto-Review Results
|
|
242
|
+
═══════════════════════════════════════════════════════════════
|
|
243
|
+
|
|
244
|
+
Test Coverage
|
|
245
|
+
src/auth/user.ts 94% ████████████████████░░
|
|
246
|
+
src/auth/session.ts 88% ██████████████████░░░░
|
|
247
|
+
src/auth/password.ts 100% ██████████████████████
|
|
248
|
+
|
|
249
|
+
TDD Compliance
|
|
250
|
+
✓ Tests committed before implementation
|
|
251
|
+
✓ All new code has corresponding tests
|
|
252
|
+
✓ No untested functions added
|
|
253
|
+
|
|
254
|
+
Security Check
|
|
255
|
+
✓ No hardcoded secrets
|
|
256
|
+
✓ Passwords properly hashed
|
|
257
|
+
✓ SQL injection protection
|
|
258
|
+
|
|
259
|
+
Quality Score: 92/100
|
|
260
|
+
|
|
261
|
+
Verdict: ✓ APPROVED
|
|
262
|
+
═══════════════════════════════════════════════════════════════
|
|
263
|
+
`,
|
|
264
|
+
|
|
265
|
+
'new-project-wizard': `
|
|
266
|
+
$ /tlc:new-project
|
|
267
|
+
|
|
268
|
+
═══════════════════════════════════════════════════════════════
|
|
269
|
+
TLC New Project Setup
|
|
270
|
+
═══════════════════════════════════════════════════════════════
|
|
271
|
+
|
|
272
|
+
What are you building?
|
|
273
|
+
> A task management API with user authentication
|
|
274
|
+
|
|
275
|
+
Who will use it?
|
|
276
|
+
> Development team for internal project tracking
|
|
277
|
+
|
|
278
|
+
Tech stack preferences?
|
|
279
|
+
[x] Node.js + Express
|
|
280
|
+
[ ] Python + FastAPI
|
|
281
|
+
[ ] Go + Gin
|
|
282
|
+
[ ] Other
|
|
283
|
+
|
|
284
|
+
Test framework?
|
|
285
|
+
[x] Vitest (recommended)
|
|
286
|
+
[ ] Jest
|
|
287
|
+
[ ] Mocha
|
|
288
|
+
|
|
289
|
+
Creating project structure...
|
|
290
|
+
✓ PROJECT.md
|
|
291
|
+
✓ .planning/ROADMAP.md
|
|
292
|
+
✓ .tlc.json
|
|
293
|
+
✓ package.json
|
|
294
|
+
|
|
295
|
+
Project ready! Run /tlc:next to begin.
|
|
296
|
+
`,
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
// Ensure output directory exists
|
|
300
|
+
if (!fs.existsSync(OUTPUT_DIR)) {
|
|
301
|
+
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Generate each screenshot
|
|
305
|
+
console.log('Generating screenshots...\n');
|
|
306
|
+
|
|
307
|
+
for (const [name, content] of Object.entries(screenshots)) {
|
|
308
|
+
const filename = `${name}.png`;
|
|
309
|
+
const filepath = path.join(OUTPUT_DIR, filename);
|
|
310
|
+
|
|
311
|
+
try {
|
|
312
|
+
const dataUri = generateSync(content.trim(), options);
|
|
313
|
+
const base64Data = dataUri.replace(/^data:image\/png;base64,/, '');
|
|
314
|
+
fs.writeFileSync(filepath, Buffer.from(base64Data, 'base64'));
|
|
315
|
+
console.log(` ✓ ${filename}`);
|
|
316
|
+
} catch (err) {
|
|
317
|
+
console.log(` ✗ ${filename}: ${err.message}`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
console.log('\nDone! Screenshots saved to docs/wiki/images/');
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Project Documentation Maintenance
|
|
4
|
+
*
|
|
5
|
+
* Works on any TLC project to:
|
|
6
|
+
* - Generate/update README sections
|
|
7
|
+
* - Create API documentation
|
|
8
|
+
* - Capture app screenshots
|
|
9
|
+
* - Sync to GitHub Wiki
|
|
10
|
+
* - Set up CI/CD for docs
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* npx tlc-docs # Full docs update
|
|
14
|
+
* npx tlc-docs setup # Set up docs automation
|
|
15
|
+
* npx tlc-docs readme # Update README
|
|
16
|
+
* npx tlc-docs screenshots # Capture screenshots
|
|
17
|
+
* npx tlc-docs api # Generate API docs
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
const { execSync, spawn } = require('child_process');
|
|
23
|
+
|
|
24
|
+
const PROJECT_DIR = process.cwd();
|
|
25
|
+
const DOCS_DIR = path.join(PROJECT_DIR, 'docs');
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get project info from package.json and .tlc.json
|
|
29
|
+
*/
|
|
30
|
+
function getProjectInfo() {
|
|
31
|
+
const info = {
|
|
32
|
+
name: path.basename(PROJECT_DIR),
|
|
33
|
+
version: '1.0.0',
|
|
34
|
+
description: '',
|
|
35
|
+
hasTypeScript: false,
|
|
36
|
+
hasPlaywright: false,
|
|
37
|
+
hasTLC: false,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Read package.json
|
|
41
|
+
const pkgPath = path.join(PROJECT_DIR, 'package.json');
|
|
42
|
+
if (fs.existsSync(pkgPath)) {
|
|
43
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
44
|
+
info.name = pkg.name || info.name;
|
|
45
|
+
info.version = pkg.version || info.version;
|
|
46
|
+
info.description = pkg.description || info.description;
|
|
47
|
+
info.hasTypeScript = !!pkg.devDependencies?.typescript || !!pkg.dependencies?.typescript;
|
|
48
|
+
info.hasPlaywright = !!pkg.devDependencies?.playwright || !!pkg.dependencies?.playwright;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Read .tlc.json
|
|
52
|
+
const tlcPath = path.join(PROJECT_DIR, '.tlc.json');
|
|
53
|
+
if (fs.existsSync(tlcPath)) {
|
|
54
|
+
const tlc = JSON.parse(fs.readFileSync(tlcPath, 'utf-8'));
|
|
55
|
+
info.hasTLC = true;
|
|
56
|
+
info.description = info.description || tlc.description;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Read PROJECT.md
|
|
60
|
+
const projectMdPath = path.join(PROJECT_DIR, 'PROJECT.md');
|
|
61
|
+
if (fs.existsSync(projectMdPath)) {
|
|
62
|
+
const content = fs.readFileSync(projectMdPath, 'utf-8');
|
|
63
|
+
const descMatch = content.match(/##\s*Description\s*\n+([^\n#]+)/i);
|
|
64
|
+
if (descMatch) {
|
|
65
|
+
info.description = info.description || descMatch[1].trim();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return info;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Set up docs automation for project
|
|
74
|
+
*/
|
|
75
|
+
function setupDocs() {
|
|
76
|
+
console.log('Setting up documentation automation...\n');
|
|
77
|
+
|
|
78
|
+
// Create docs directory
|
|
79
|
+
if (!fs.existsSync(DOCS_DIR)) {
|
|
80
|
+
fs.mkdirSync(DOCS_DIR, { recursive: true });
|
|
81
|
+
console.log(' ✓ Created docs/ directory');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Create images directory
|
|
85
|
+
const imagesDir = path.join(DOCS_DIR, 'images');
|
|
86
|
+
if (!fs.existsSync(imagesDir)) {
|
|
87
|
+
fs.mkdirSync(imagesDir, { recursive: true });
|
|
88
|
+
console.log(' ✓ Created docs/images/ directory');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Copy GitHub workflow
|
|
92
|
+
const workflowDir = path.join(PROJECT_DIR, '.github/workflows');
|
|
93
|
+
if (!fs.existsSync(workflowDir)) {
|
|
94
|
+
fs.mkdirSync(workflowDir, { recursive: true });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const workflowDest = path.join(workflowDir, 'docs-sync.yml');
|
|
98
|
+
if (!fs.existsSync(workflowDest)) {
|
|
99
|
+
// Try to find template in TLC installation
|
|
100
|
+
const templatePaths = [
|
|
101
|
+
path.join(__dirname, '../templates/docs-sync.yml'),
|
|
102
|
+
path.join(__dirname, '../../templates/docs-sync.yml'),
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
let templateContent = null;
|
|
106
|
+
for (const tp of templatePaths) {
|
|
107
|
+
if (fs.existsSync(tp)) {
|
|
108
|
+
templateContent = fs.readFileSync(tp, 'utf-8');
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (templateContent) {
|
|
114
|
+
fs.writeFileSync(workflowDest, templateContent);
|
|
115
|
+
console.log(' ✓ Created .github/workflows/docs-sync.yml');
|
|
116
|
+
} else {
|
|
117
|
+
console.log(' ⚠ Could not find docs-sync.yml template');
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
console.log(' ✓ docs-sync.yml already exists');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Add npm scripts if package.json exists
|
|
124
|
+
const pkgPath = path.join(PROJECT_DIR, 'package.json');
|
|
125
|
+
if (fs.existsSync(pkgPath)) {
|
|
126
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
127
|
+
let updated = false;
|
|
128
|
+
|
|
129
|
+
if (!pkg.scripts) pkg.scripts = {};
|
|
130
|
+
|
|
131
|
+
if (!pkg.scripts['docs']) {
|
|
132
|
+
pkg.scripts['docs'] = 'npx tlc-docs';
|
|
133
|
+
updated = true;
|
|
134
|
+
}
|
|
135
|
+
if (!pkg.scripts['docs:screenshots']) {
|
|
136
|
+
pkg.scripts['docs:screenshots'] = 'npx tlc-docs screenshots';
|
|
137
|
+
updated = true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (updated) {
|
|
141
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
142
|
+
console.log(' ✓ Added docs scripts to package.json');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Create initial docs structure
|
|
147
|
+
const gettingStartedPath = path.join(DOCS_DIR, 'getting-started.md');
|
|
148
|
+
if (!fs.existsSync(gettingStartedPath)) {
|
|
149
|
+
const info = getProjectInfo();
|
|
150
|
+
const content = `# Getting Started with ${info.name}
|
|
151
|
+
|
|
152
|
+
${info.description || 'Welcome to the project!'}
|
|
153
|
+
|
|
154
|
+
## Installation
|
|
155
|
+
|
|
156
|
+
\`\`\`bash
|
|
157
|
+
npm install
|
|
158
|
+
\`\`\`
|
|
159
|
+
|
|
160
|
+
## Usage
|
|
161
|
+
|
|
162
|
+
\`\`\`bash
|
|
163
|
+
npm start
|
|
164
|
+
\`\`\`
|
|
165
|
+
|
|
166
|
+
## Development
|
|
167
|
+
|
|
168
|
+
\`\`\`bash
|
|
169
|
+
npm run dev
|
|
170
|
+
\`\`\`
|
|
171
|
+
|
|
172
|
+
## Testing
|
|
173
|
+
|
|
174
|
+
\`\`\`bash
|
|
175
|
+
npm test
|
|
176
|
+
\`\`\`
|
|
177
|
+
`;
|
|
178
|
+
fs.writeFileSync(gettingStartedPath, content);
|
|
179
|
+
console.log(' ✓ Created docs/getting-started.md');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
console.log('\n✓ Documentation setup complete!');
|
|
183
|
+
console.log('\nNext steps:');
|
|
184
|
+
console.log(' 1. Push to GitHub to enable wiki sync');
|
|
185
|
+
console.log(' 2. Run /tlc:docs to update documentation');
|
|
186
|
+
console.log(' 3. Run /tlc:docs screenshots to capture app screenshots');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Update README with project info
|
|
191
|
+
*/
|
|
192
|
+
function updateReadme() {
|
|
193
|
+
const info = getProjectInfo();
|
|
194
|
+
const readmePath = path.join(PROJECT_DIR, 'README.md');
|
|
195
|
+
|
|
196
|
+
let content = '';
|
|
197
|
+
if (fs.existsSync(readmePath)) {
|
|
198
|
+
content = fs.readFileSync(readmePath, 'utf-8');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Update version badge if exists
|
|
202
|
+
const versionBadgePattern = /!\[version\]\([^)]*\)/gi;
|
|
203
|
+
if (versionBadgePattern.test(content)) {
|
|
204
|
+
content = content.replace(
|
|
205
|
+
versionBadgePattern,
|
|
206
|
+
``
|
|
207
|
+
);
|
|
208
|
+
console.log(' ✓ Updated version badge');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Update version references
|
|
212
|
+
const oldVersionPattern = /v\d+\.\d+\.\d+/g;
|
|
213
|
+
const updated = content.replace(oldVersionPattern, `v${info.version}`);
|
|
214
|
+
|
|
215
|
+
if (updated !== content) {
|
|
216
|
+
fs.writeFileSync(readmePath, updated);
|
|
217
|
+
console.log(' ✓ Updated version references');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Capture screenshots using Playwright
|
|
225
|
+
*/
|
|
226
|
+
async function captureScreenshots() {
|
|
227
|
+
console.log('Capturing screenshots...\n');
|
|
228
|
+
|
|
229
|
+
const info = getProjectInfo();
|
|
230
|
+
|
|
231
|
+
if (!info.hasPlaywright) {
|
|
232
|
+
console.log(' Installing Playwright...');
|
|
233
|
+
try {
|
|
234
|
+
execSync('npm install -D playwright', { cwd: PROJECT_DIR, stdio: 'pipe' });
|
|
235
|
+
execSync('npx playwright install chromium', { cwd: PROJECT_DIR, stdio: 'pipe' });
|
|
236
|
+
} catch (e) {
|
|
237
|
+
console.log(' ⚠ Could not install Playwright');
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Try to capture screenshots
|
|
243
|
+
const imagesDir = path.join(DOCS_DIR, 'images');
|
|
244
|
+
if (!fs.existsSync(imagesDir)) {
|
|
245
|
+
fs.mkdirSync(imagesDir, { recursive: true });
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Create a simple capture script
|
|
249
|
+
const captureScript = `
|
|
250
|
+
const { chromium } = require('playwright');
|
|
251
|
+
const path = require('path');
|
|
252
|
+
|
|
253
|
+
async function capture() {
|
|
254
|
+
const browser = await chromium.launch({ headless: true });
|
|
255
|
+
const page = await browser.newPage();
|
|
256
|
+
await page.setViewportSize({ width: 1280, height: 720 });
|
|
257
|
+
|
|
258
|
+
const urls = [
|
|
259
|
+
{ url: 'http://localhost:3000', name: 'homepage' },
|
|
260
|
+
{ url: 'http://localhost:3000/dashboard', name: 'dashboard' },
|
|
261
|
+
{ url: 'http://localhost:5001', name: 'app' },
|
|
262
|
+
{ url: 'http://localhost:3147', name: 'tlc-dashboard' },
|
|
263
|
+
];
|
|
264
|
+
|
|
265
|
+
for (const { url, name } of urls) {
|
|
266
|
+
try {
|
|
267
|
+
await page.goto(url, { timeout: 5000 });
|
|
268
|
+
await page.screenshot({
|
|
269
|
+
path: path.join('${imagesDir.replace(/\\/g, '\\\\')}', name + '.png'),
|
|
270
|
+
fullPage: false,
|
|
271
|
+
});
|
|
272
|
+
console.log(' ✓ ' + name + '.png');
|
|
273
|
+
} catch (e) {
|
|
274
|
+
// URL not accessible, skip
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
await browser.close();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
capture().catch(console.error);
|
|
282
|
+
`;
|
|
283
|
+
|
|
284
|
+
const tempScript = path.join(PROJECT_DIR, '.tlc-capture-temp.js');
|
|
285
|
+
fs.writeFileSync(tempScript, captureScript);
|
|
286
|
+
|
|
287
|
+
try {
|
|
288
|
+
execSync(`node ${tempScript}`, { cwd: PROJECT_DIR, stdio: 'inherit' });
|
|
289
|
+
} catch (e) {
|
|
290
|
+
console.log(' ⚠ Screenshot capture had issues (app may not be running)');
|
|
291
|
+
} finally {
|
|
292
|
+
fs.unlinkSync(tempScript);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Generate API documentation
|
|
298
|
+
*/
|
|
299
|
+
function generateApiDocs() {
|
|
300
|
+
console.log('Generating API documentation...\n');
|
|
301
|
+
|
|
302
|
+
const info = getProjectInfo();
|
|
303
|
+
|
|
304
|
+
if (info.hasTypeScript) {
|
|
305
|
+
console.log(' Detecting TypeScript, using TypeDoc...');
|
|
306
|
+
try {
|
|
307
|
+
execSync('npx typedoc --out docs/api src/', { cwd: PROJECT_DIR, stdio: 'pipe' });
|
|
308
|
+
console.log(' ✓ Generated API docs in docs/api/');
|
|
309
|
+
} catch (e) {
|
|
310
|
+
console.log(' ⚠ TypeDoc generation failed');
|
|
311
|
+
}
|
|
312
|
+
} else {
|
|
313
|
+
console.log(' No TypeScript detected, skipping API docs');
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Full documentation update
|
|
319
|
+
*/
|
|
320
|
+
async function fullUpdate() {
|
|
321
|
+
console.log('TLC Documentation Update\n');
|
|
322
|
+
console.log('═'.repeat(50));
|
|
323
|
+
|
|
324
|
+
const info = getProjectInfo();
|
|
325
|
+
console.log(`\nProject: ${info.name} v${info.version}\n`);
|
|
326
|
+
|
|
327
|
+
// Ensure docs directory exists
|
|
328
|
+
if (!fs.existsSync(DOCS_DIR)) {
|
|
329
|
+
console.log('No docs/ directory found. Running setup first...\n');
|
|
330
|
+
setupDocs();
|
|
331
|
+
console.log('');
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Update README
|
|
335
|
+
console.log('📄 README');
|
|
336
|
+
updateReadme();
|
|
337
|
+
|
|
338
|
+
// Generate API docs
|
|
339
|
+
console.log('\n📚 API Documentation');
|
|
340
|
+
generateApiDocs();
|
|
341
|
+
|
|
342
|
+
// Capture screenshots if possible
|
|
343
|
+
console.log('\n📸 Screenshots');
|
|
344
|
+
await captureScreenshots();
|
|
345
|
+
|
|
346
|
+
console.log('\n' + '═'.repeat(50));
|
|
347
|
+
console.log('\n✓ Documentation updated!');
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Main function
|
|
352
|
+
*/
|
|
353
|
+
async function main() {
|
|
354
|
+
const command = process.argv[2] || 'update';
|
|
355
|
+
|
|
356
|
+
switch (command) {
|
|
357
|
+
case 'setup':
|
|
358
|
+
setupDocs();
|
|
359
|
+
break;
|
|
360
|
+
case 'readme':
|
|
361
|
+
console.log('Updating README...\n');
|
|
362
|
+
updateReadme();
|
|
363
|
+
break;
|
|
364
|
+
case 'screenshots':
|
|
365
|
+
await captureScreenshots();
|
|
366
|
+
break;
|
|
367
|
+
case 'api':
|
|
368
|
+
generateApiDocs();
|
|
369
|
+
break;
|
|
370
|
+
case 'update':
|
|
371
|
+
default:
|
|
372
|
+
await fullUpdate();
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
main().catch(console.error);
|