tlc-claude-code 0.6.4 → 0.7.1

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/build.md CHANGED
@@ -24,14 +24,63 @@ This is the core TLC command. Tests before code, one task at a time.
24
24
 
25
25
  Read all `.planning/phases/{phase}-*-PLAN.md` files for this phase.
26
26
 
27
+ ### Step 1b: Sync and Claim (Multi-User)
28
+
29
+ Before starting work, coordinate with teammates:
30
+
31
+ 1. **Pull latest:** `git pull --rebase`
32
+ 2. **Get user identity:**
33
+ ```bash
34
+ if [ -n "$TLC_USER" ]; then
35
+ user=$TLC_USER
36
+ else
37
+ user=$(git config user.name | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
38
+ fi
39
+ ```
40
+ 3. **Parse task status:** Read `[>@user]` and `[x@user]` markers from plan
41
+ 4. **Show availability:**
42
+ ```
43
+ Phase 1 Tasks:
44
+ [x@alice] 1. Create schema (done)
45
+ [ ] 2. Add validation (available)
46
+ [>@bob] 3. Write migrations (bob is working)
47
+ [ ] 4. Integration tests (available)
48
+
49
+ Work on task 2? (Y/n)
50
+ ```
51
+ 5. **Claim selected task:** Update `[ ]` → `[>@{user}]`
52
+ 6. **Commit claim:** `git commit -m "claim: task 2 (@{user})"`
53
+ 7. **Push:** Prompt user or auto-push
54
+
55
+ If no markers exist in PLAN.md, skip this step (single-user mode).
56
+
27
57
  ### Step 2: Detect Test Framework
28
58
 
59
+ #### Check TLC Config First
60
+
61
+ If `.tlc.json` exists, use configured frameworks:
62
+
63
+ ```json
64
+ {
65
+ "testFrameworks": {
66
+ "primary": "mocha",
67
+ "installed": ["mocha", "chai", "sinon", "proxyquire"],
68
+ "run": ["mocha"]
69
+ }
70
+ }
71
+ ```
72
+
73
+ #### Auto-Detection (No Config)
74
+
29
75
  Check what's already set up:
76
+ - `.tlc.json` → Use configured framework
77
+ - `mocha` in package.json → Mocha (TLC default)
78
+ - `.mocharc.*` or `mocha.opts` → Mocha
30
79
  - `vitest.config.*` → Vitest
31
80
  - `jest.config.*` → Jest
32
81
  - `pytest.ini` or `pyproject.toml` with pytest → pytest
33
82
  - `spec/` directory → RSpec
34
- - None found → Set up based on PROJECT.md stack (see framework defaults below)
83
+ - None found → Set up mocha stack (TLC default)
35
84
 
36
85
  ### Step 3: Plan Tests for Each Task
37
86
 
@@ -84,7 +133,49 @@ Follow the project's test patterns. Test names should describe expected behavior
84
133
  ✗ "test login" (too vague)
85
134
  ```
86
135
 
87
- **Vitest/Jest (TypeScript):**
136
+ **Mocha/Chai (TLC Default):**
137
+ ```javascript
138
+ const { expect } = require('chai')
139
+ const sinon = require('sinon')
140
+ const proxyquire = require('proxyquire')
141
+
142
+ describe('login', () => {
143
+ let login, dbStub
144
+
145
+ beforeEach(() => {
146
+ dbStub = sinon.stub()
147
+ login = proxyquire('../src/auth/login', {
148
+ './db': { findUser: dbStub }
149
+ })
150
+ })
151
+
152
+ afterEach(() => {
153
+ sinon.restore()
154
+ })
155
+
156
+ it('returns user object for valid credentials', async () => {
157
+ dbStub.resolves({ id: 1, email: 'user@test.com' })
158
+
159
+ const result = await login('user@test.com', 'password123')
160
+
161
+ expect(result.user).to.exist
162
+ expect(result.user.email).to.equal('user@test.com')
163
+ })
164
+
165
+ it('throws AuthError for invalid password', async () => {
166
+ dbStub.resolves(null)
167
+
168
+ try {
169
+ await login('user@test.com', 'wrong')
170
+ expect.fail('Should have thrown')
171
+ } catch (err) {
172
+ expect(err.message).to.equal('Invalid credentials')
173
+ }
174
+ })
175
+ })
176
+ ```
177
+
178
+ **Vitest/Jest (Alternative):**
88
179
  ```typescript
89
180
  import { describe, it, expect } from 'vitest'
90
181
  import { login } from '../src/auth/login'
@@ -223,7 +314,15 @@ git add src/auth/login.ts tests/auth/login.test.ts
223
314
  git commit -m "feat: {task-title} - phase {N}"
224
315
  ```
225
316
 
226
- #### 7e. Move to next task
317
+ #### 7e. Mark Task Complete (Multi-User)
318
+
319
+ If using multi-user mode (task had `[>@user]` marker):
320
+
321
+ 1. Update marker: `[>@{user}]` → `[x@{user}]`
322
+ 2. Commit: `git commit -m "complete: task {N} - {title} (@{user})"`
323
+ 3. Push to share progress with team
324
+
325
+ #### 7f. Move to next task
227
326
  Repeat 7a-7d for each task in the phase.
228
327
 
229
328
  **Critical Rules:**
@@ -255,31 +354,78 @@ Status: ✅ All tests passing (Green)
255
354
  {test runner output showing all pass}
256
355
  ```
257
356
 
258
- ## Framework Defaults (for new projects)
357
+ ## Framework Defaults
259
358
 
260
- If no test framework detected, set up based on PROJECT.md:
359
+ ### TLC Default: Mocha Stack
261
360
 
262
- | Stack in PROJECT.md | Framework | Setup |
263
- |---------------------|-----------|-------|
264
- | Next.js, React, Vite | Vitest | `npm install -D vitest`, create `vitest.config.ts` |
265
- | Node.js, Express | Vitest | `npm install -D vitest`, create `vitest.config.ts` |
266
- | Python, FastAPI, Flask | pytest | `pip install pytest`, create `pytest.ini` |
267
- | Go | go test | Built-in, create `*_test.go` files |
268
- | Ruby, Rails | RSpec | `gem install rspec`, `rspec --init` |
361
+ For JavaScript/TypeScript projects, TLC defaults to the mocha ecosystem:
269
362
 
270
- Default Vitest config:
271
- ```typescript
272
- import { defineConfig } from 'vitest/config'
363
+ | Library | Purpose | Install |
364
+ |---------|---------|---------|
365
+ | **mocha** | Test runner | `npm install -D mocha` |
366
+ | **chai** | Assertions | `npm install -D chai` |
367
+ | **sinon** | Mocks/stubs/spies | `npm install -D sinon` |
368
+ | **proxyquire** | Module mocking | `npm install -D proxyquire` |
273
369
 
274
- export default defineConfig({
275
- test: {
276
- globals: true,
277
- environment: 'node', // or 'jsdom' for React
370
+ Full setup:
371
+ ```bash
372
+ npm install -D mocha chai sinon proxyquire @types/mocha @types/chai @types/sinon
373
+ ```
374
+
375
+ Default `.mocharc.json`:
376
+ ```json
377
+ {
378
+ "extension": ["js", "ts"],
379
+ "spec": "test/**/*.test.{js,ts}",
380
+ "require": ["ts-node/register"],
381
+ "timeout": 5000
382
+ }
383
+ ```
384
+
385
+ Default `package.json` scripts:
386
+ ```json
387
+ {
388
+ "scripts": {
389
+ "test": "mocha",
390
+ "test:watch": "mocha --watch"
391
+ }
392
+ }
393
+ ```
394
+
395
+ ### Alternative Frameworks
396
+
397
+ | Stack | Framework | Setup |
398
+ |-------|-----------|-------|
399
+ | Vite projects | Vitest | `npm install -D vitest` |
400
+ | React/Meta ecosystem | Jest | `npm install -D jest` |
401
+ | Python | pytest | `pip install pytest` |
402
+ | Go | go test | Built-in |
403
+ | Ruby | RSpec | `gem install rspec` |
404
+
405
+ To use an alternative, run `/tlc:config` to configure.
406
+
407
+ ### Multi-Framework Support
408
+
409
+ Projects can have multiple test frameworks. Configure in `.tlc.json`:
410
+
411
+ ```json
412
+ {
413
+ "testFrameworks": {
414
+ "primary": "mocha",
415
+ "installed": ["mocha", "chai", "sinon", "jest"],
416
+ "run": ["mocha", "jest"]
278
417
  },
279
- })
418
+ "commands": {
419
+ "mocha": "npx mocha 'test/**/*.test.js'",
420
+ "jest": "npx jest",
421
+ "all": "npm test"
422
+ }
423
+ }
280
424
  ```
281
425
 
282
- Default pytest.ini:
426
+ When running tests, TLC will execute all frameworks in the `run` array.
427
+
428
+ Default pytest.ini (Python):
283
429
  ```ini
284
430
  [pytest]
285
431
  testpaths = tests
package/ci.md ADDED
@@ -0,0 +1,414 @@
1
+ # /tlc:ci - CI/CD Integration
2
+
3
+ Generate CI/CD pipeline configuration for your TLC project.
4
+
5
+ ## Usage
6
+
7
+ ```
8
+ /tlc:ci [provider]
9
+ ```
10
+
11
+ Providers: `github`, `gitlab`, `bitbucket`, `azure`, `circle`
12
+
13
+ If no provider specified, auto-detects from git remote.
14
+
15
+ ## What This Does
16
+
17
+ 1. Detects your CI/CD platform from git remote
18
+ 2. Generates appropriate config file
19
+ 3. Includes test-first validation
20
+ 4. Adds regression test gates
21
+
22
+ ## GitHub Actions
23
+
24
+ Creates `.github/workflows/tlc.yml`:
25
+
26
+ ```yaml
27
+ name: TLC Pipeline
28
+
29
+ on:
30
+ push:
31
+ branches: [main, develop]
32
+ pull_request:
33
+ branches: [main]
34
+
35
+ jobs:
36
+ test:
37
+ runs-on: ubuntu-latest
38
+ steps:
39
+ - uses: actions/checkout@v4
40
+
41
+ - name: Setup Node.js
42
+ uses: actions/setup-node@v4
43
+ with:
44
+ node-version: '20'
45
+ cache: 'npm'
46
+
47
+ - name: Install dependencies
48
+ run: npm ci
49
+
50
+ - name: Run tests
51
+ run: npm test
52
+
53
+ - name: Upload coverage
54
+ uses: codecov/codecov-action@v4
55
+ if: always()
56
+
57
+ lint:
58
+ runs-on: ubuntu-latest
59
+ steps:
60
+ - uses: actions/checkout@v4
61
+ - uses: actions/setup-node@v4
62
+ with:
63
+ node-version: '20'
64
+ cache: 'npm'
65
+ - run: npm ci
66
+ - run: npm run lint
67
+
68
+ regression:
69
+ runs-on: ubuntu-latest
70
+ needs: [test]
71
+ if: github.event_name == 'pull_request'
72
+ steps:
73
+ - uses: actions/checkout@v4
74
+ with:
75
+ fetch-depth: 0
76
+
77
+ - uses: actions/setup-node@v4
78
+ with:
79
+ node-version: '20'
80
+ cache: 'npm'
81
+
82
+ - run: npm ci
83
+
84
+ - name: Check for untested code
85
+ run: |
86
+ # Get changed files
87
+ CHANGED=$(git diff --name-only origin/main...HEAD | grep -E '\.(ts|js|tsx|jsx)$' | grep -v '\.test\.' || true)
88
+
89
+ if [ -n "$CHANGED" ]; then
90
+ echo "Changed source files:"
91
+ echo "$CHANGED"
92
+
93
+ # Check each has corresponding test
94
+ for file in $CHANGED; do
95
+ testfile="${file%.*}.test.${file##*.}"
96
+ if [ ! -f "$testfile" ]; then
97
+ echo "::warning file=$file::No test file found for $file"
98
+ fi
99
+ done
100
+ fi
101
+
102
+ - name: Run regression tests
103
+ run: npm test -- --coverage
104
+
105
+ - name: Coverage diff
106
+ run: |
107
+ # Compare coverage with base branch
108
+ echo "Coverage report generated"
109
+ ```
110
+
111
+ ## GitLab CI
112
+
113
+ Creates `.gitlab-ci.yml`:
114
+
115
+ ```yaml
116
+ stages:
117
+ - test
118
+ - regression
119
+
120
+ default:
121
+ image: node:20
122
+ cache:
123
+ paths:
124
+ - node_modules/
125
+
126
+ test:
127
+ stage: test
128
+ script:
129
+ - npm ci
130
+ - npm test
131
+ coverage: '/Lines\s*:\s*(\d+\.?\d*)%/'
132
+ artifacts:
133
+ reports:
134
+ coverage_report:
135
+ coverage_format: cobertura
136
+ path: coverage/cobertura-coverage.xml
137
+
138
+ lint:
139
+ stage: test
140
+ script:
141
+ - npm ci
142
+ - npm run lint
143
+ allow_failure: true
144
+
145
+ regression:
146
+ stage: regression
147
+ only:
148
+ - merge_requests
149
+ script:
150
+ - npm ci
151
+ - |
152
+ CHANGED=$(git diff --name-only $CI_MERGE_REQUEST_DIFF_BASE_SHA...HEAD | grep -E '\.(ts|js)$' | grep -v '\.test\.' || true)
153
+ if [ -n "$CHANGED" ]; then
154
+ echo "Checking tests for changed files..."
155
+ for file in $CHANGED; do
156
+ testfile="${file%.*}.test.${file##*.}"
157
+ if [ ! -f "$testfile" ]; then
158
+ echo "WARNING: No test file for $file"
159
+ fi
160
+ done
161
+ fi
162
+ - npm test -- --coverage
163
+ ```
164
+
165
+ ## Bitbucket Pipelines
166
+
167
+ Creates `bitbucket-pipelines.yml`:
168
+
169
+ ```yaml
170
+ image: node:20
171
+
172
+ definitions:
173
+ caches:
174
+ npm: ~/.npm
175
+
176
+ pipelines:
177
+ default:
178
+ - step:
179
+ name: Test
180
+ caches:
181
+ - npm
182
+ script:
183
+ - npm ci
184
+ - npm test
185
+
186
+ pull-requests:
187
+ '**':
188
+ - step:
189
+ name: Test
190
+ caches:
191
+ - npm
192
+ script:
193
+ - npm ci
194
+ - npm test
195
+ - step:
196
+ name: Regression Check
197
+ caches:
198
+ - npm
199
+ script:
200
+ - npm ci
201
+ - npm test -- --coverage
202
+ ```
203
+
204
+ ## Azure Pipelines
205
+
206
+ Creates `azure-pipelines.yml`:
207
+
208
+ ```yaml
209
+ trigger:
210
+ - main
211
+ - develop
212
+
213
+ pool:
214
+ vmImage: 'ubuntu-latest'
215
+
216
+ stages:
217
+ - stage: Test
218
+ jobs:
219
+ - job: Test
220
+ steps:
221
+ - task: NodeTool@0
222
+ inputs:
223
+ versionSpec: '20.x'
224
+
225
+ - script: npm ci
226
+ displayName: Install dependencies
227
+
228
+ - script: npm test
229
+ displayName: Run tests
230
+
231
+ - task: PublishCodeCoverageResults@2
232
+ inputs:
233
+ summaryFileLocation: '$(System.DefaultWorkingDirectory)/coverage/cobertura-coverage.xml'
234
+
235
+ - stage: Regression
236
+ condition: eq(variables['Build.Reason'], 'PullRequest')
237
+ jobs:
238
+ - job: Regression
239
+ steps:
240
+ - task: NodeTool@0
241
+ inputs:
242
+ versionSpec: '20.x'
243
+ - script: npm ci
244
+ - script: npm test -- --coverage
245
+ displayName: Regression tests
246
+ ```
247
+
248
+ ## CircleCI
249
+
250
+ Creates `.circleci/config.yml`:
251
+
252
+ ```yaml
253
+ version: 2.1
254
+
255
+ executors:
256
+ node:
257
+ docker:
258
+ - image: cimg/node:20.0
259
+
260
+ jobs:
261
+ test:
262
+ executor: node
263
+ steps:
264
+ - checkout
265
+ - restore_cache:
266
+ keys:
267
+ - npm-{{ checksum "package-lock.json" }}
268
+ - run: npm ci
269
+ - save_cache:
270
+ paths:
271
+ - node_modules
272
+ key: npm-{{ checksum "package-lock.json" }}
273
+ - run: npm test
274
+ - store_test_results:
275
+ path: test-results
276
+ - store_artifacts:
277
+ path: coverage
278
+
279
+ regression:
280
+ executor: node
281
+ steps:
282
+ - checkout
283
+ - restore_cache:
284
+ keys:
285
+ - npm-{{ checksum "package-lock.json" }}
286
+ - run: npm ci
287
+ - run:
288
+ name: Check for untested code
289
+ command: |
290
+ CHANGED=$(git diff --name-only origin/main...HEAD | grep -E '\.(ts|js)$' | grep -v '\.test\.' || true)
291
+ if [ -n "$CHANGED" ]; then
292
+ echo "Changed files: $CHANGED"
293
+ fi
294
+ - run: npm test -- --coverage
295
+
296
+ workflows:
297
+ test-and-deploy:
298
+ jobs:
299
+ - test
300
+ - regression:
301
+ filters:
302
+ branches:
303
+ ignore: main
304
+ ```
305
+
306
+ ## Regression Test Features
307
+
308
+ ### Automatic Detection
309
+
310
+ The CI config includes regression checks that:
311
+
312
+ 1. **Identify changed files** in the PR/MR
313
+ 2. **Verify test coverage** for changed files
314
+ 3. **Run full test suite** to catch regressions
315
+ 4. **Report coverage diff** vs base branch
316
+
317
+ ### Configuring Regression Behavior
318
+
319
+ In `.tlc.json`:
320
+
321
+ ```json
322
+ {
323
+ "ci": {
324
+ "requireTestsForNewFiles": true,
325
+ "coverageThreshold": 80,
326
+ "failOnCoverageDecrease": true,
327
+ "regressionOnPR": true
328
+ }
329
+ }
330
+ ```
331
+
332
+ ### Coverage Requirements
333
+
334
+ Set minimum coverage in `package.json`:
335
+
336
+ ```json
337
+ {
338
+ "jest": {
339
+ "coverageThreshold": {
340
+ "global": {
341
+ "branches": 80,
342
+ "functions": 80,
343
+ "lines": 80,
344
+ "statements": 80
345
+ }
346
+ }
347
+ }
348
+ }
349
+ ```
350
+
351
+ Or for mocha with nyc:
352
+
353
+ ```json
354
+ {
355
+ "nyc": {
356
+ "check-coverage": true,
357
+ "lines": 80,
358
+ "functions": 80,
359
+ "branches": 80
360
+ }
361
+ }
362
+ ```
363
+
364
+ ## Import/Merge Regression
365
+
366
+ When importing external code (`/tlc:import-project`), automatically run regression:
367
+
368
+ ```
369
+ > /tlc:import-project ../legacy-api
370
+
371
+ Importing legacy-api...
372
+
373
+ Found 47 source files without tests.
374
+
375
+ Running regression tests on merge...
376
+ ✓ 23 existing tests pass
377
+ ⚠ 12 new files need tests
378
+
379
+ Create tasks for missing tests? (Y/n)
380
+ ```
381
+
382
+ ## Example Session
383
+
384
+ ```
385
+ > /tlc:ci
386
+
387
+ Detecting CI/CD platform...
388
+ Remote: git@github.com:acme/myproject.git
389
+ Platform: GitHub
390
+
391
+ Generating .github/workflows/tlc.yml...
392
+
393
+ Created CI pipeline with:
394
+ ✓ Test job (runs on all pushes)
395
+ ✓ Lint job (runs on all pushes)
396
+ ✓ Regression job (runs on PRs)
397
+ ✓ Coverage reporting (Codecov)
398
+
399
+ Commit this file? (Y/n) y
400
+
401
+ Committed: ci: add TLC GitHub Actions pipeline
402
+
403
+ Next steps:
404
+ 1. Push to GitHub
405
+ 2. Add CODECOV_TOKEN secret (optional)
406
+ 3. PRs will now require passing tests
407
+ ```
408
+
409
+ ## Notes
410
+
411
+ - CI config respects `.tlc.json` settings
412
+ - Coverage thresholds match project config
413
+ - Regression checks are PR-only by default
414
+ - Use `/tlc:ci --dry-run` to preview without creating files