tlc-claude-code 2.4.4 → 2.4.5

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.
@@ -936,15 +936,33 @@ Verdict: ❌ CHANGES REQUESTED
936
936
  ───────────────────────────────
937
937
  ```
938
938
 
939
- **Actions on failure:**
940
- 1. Add missing test files
941
- 2. Fix security issues
942
- 3. Split oversized files (>1000 lines) into focused sub-modules
943
- 4. Replace `any` types with proper interfaces or `unknown`
944
- 5. Add explicit return types to all exported functions
945
- 6. Re-run `/tlc:build {phase}` to retry
946
-
947
- **CRITICAL: Phase is NOT complete until review passes.**
939
+ **Review-Fix Loop (automatic — do not ask, just do it):**
940
+
941
+ When the review finds issues, fix them immediately and re-review. This is a loop, not a hand-off:
942
+
943
+ ```
944
+ Iteration 1: Review found 3 issues
945
+ Fix: add missing tests, remove hardcoded secret, split oversized file
946
+ → Run tests (must still pass after fixes)
947
+ → Commit fixes: "fix: review findings - phase {N}"
948
+
949
+ Iteration 2: Re-review → found 1 issue
950
+ → Fix: replace `any` type with interface
951
+ → Run tests
952
+ → Commit fix
953
+
954
+ Iteration 3: Re-review → clean
955
+ → Verdict: ✅ APPROVED
956
+ ```
957
+
958
+ **Loop rules:**
959
+ - Max 5 iterations. If still failing after 5, report remaining issues and stop.
960
+ - Run the full test suite after each fix batch (never break tests to fix review issues).
961
+ - Commit after each fix batch — don't accumulate.
962
+ - Each iteration re-runs ALL checks, not just the ones that failed (fixes can introduce new issues).
963
+ - Security issues are fixed first (highest priority), then coverage, then style.
964
+
965
+ **CRITICAL: Phase is NOT complete until review passes. The loop runs automatically — do not stop after reporting issues.**
948
966
 
949
967
  ### Step 11: Push Branch and Create PR (Mandatory)
950
968
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tlc-claude-code",
3
- "version": "2.4.4",
3
+ "version": "2.4.5",
4
4
  "description": "TLC - Test Led Coding for Claude Code",
5
5
  "bin": {
6
6
  "tlc-claude-code": "./bin/install.js",
@@ -19,16 +19,33 @@ const path = require('path');
19
19
  const ROUTABLE_COMMANDS = [
20
20
  'build', 'plan', 'review', 'test', 'coverage',
21
21
  'autofix', 'discuss', 'docs', 'edge-cases', 'quick',
22
+ 'design', 'vision',
22
23
  ];
23
24
 
24
25
  /**
25
- * Default routing: every routable command maps to claude with single strategy.
26
+ * Default routing: coding commands codex, thinking commands claude.
27
+ *
28
+ * Coding: build, quick, autofix (single) + edge-cases, review (parallel)
29
+ * Thinking: plan, discuss, docs, coverage, test, design, vision (single)
30
+ *
26
31
  * @type {Record<string, {models: string[], strategy: string}>}
27
32
  */
28
- const SHIPPED_DEFAULTS = {};
29
- for (const cmd of ROUTABLE_COMMANDS) {
30
- SHIPPED_DEFAULTS[cmd] = { models: ['claude'], strategy: 'single' };
31
- }
33
+ const SHIPPED_DEFAULTS = {
34
+ // Coding codex
35
+ 'build': { models: ['codex'], strategy: 'single' },
36
+ 'quick': { models: ['codex'], strategy: 'single' },
37
+ 'autofix': { models: ['codex'], strategy: 'single' },
38
+ 'edge-cases': { models: ['codex'], strategy: 'parallel' },
39
+ 'review': { models: ['codex', 'claude'], strategy: 'parallel' },
40
+ // Thinking — claude
41
+ 'plan': { models: ['codex', 'claude'], strategy: 'parallel' },
42
+ 'discuss': { models: ['claude'], strategy: 'single' },
43
+ 'docs': { models: ['claude'], strategy: 'single' },
44
+ 'coverage': { models: ['claude'], strategy: 'single' },
45
+ 'test': { models: ['claude'], strategy: 'single' },
46
+ 'design': { models: ['claude'], strategy: 'single' },
47
+ 'vision': { models: ['claude'], strategy: 'single' },
48
+ };
32
49
 
33
50
  /**
34
51
  * Load personal config from ~/.tlc/config.json
@@ -27,12 +27,27 @@ function mockFs(fileMap = {}) {
27
27
  describe('task-router-config', () => {
28
28
  // ── SHIPPED_DEFAULTS ──────────────────────────────────────────────
29
29
  describe('SHIPPED_DEFAULTS', () => {
30
- it('maps every routable command to claude/single', () => {
30
+ it('routes coding commands to codex', () => {
31
+ expect(SHIPPED_DEFAULTS['build']).toEqual({ models: ['codex'], strategy: 'single' });
32
+ expect(SHIPPED_DEFAULTS['quick']).toEqual({ models: ['codex'], strategy: 'single' });
33
+ expect(SHIPPED_DEFAULTS['autofix']).toEqual({ models: ['codex'], strategy: 'single' });
34
+ expect(SHIPPED_DEFAULTS['edge-cases']).toEqual({ models: ['codex'], strategy: 'parallel' });
35
+ expect(SHIPPED_DEFAULTS['review']).toEqual({ models: ['codex', 'claude'], strategy: 'parallel' });
36
+ });
37
+
38
+ it('routes thinking commands to claude', () => {
39
+ expect(SHIPPED_DEFAULTS['plan']).toEqual({ models: ['codex', 'claude'], strategy: 'parallel' });
40
+ expect(SHIPPED_DEFAULTS['discuss']).toEqual({ models: ['claude'], strategy: 'single' });
41
+ expect(SHIPPED_DEFAULTS['docs']).toEqual({ models: ['claude'], strategy: 'single' });
42
+ expect(SHIPPED_DEFAULTS['coverage']).toEqual({ models: ['claude'], strategy: 'single' });
43
+ expect(SHIPPED_DEFAULTS['test']).toEqual({ models: ['claude'], strategy: 'single' });
44
+ expect(SHIPPED_DEFAULTS['design']).toEqual({ models: ['claude'], strategy: 'single' });
45
+ expect(SHIPPED_DEFAULTS['vision']).toEqual({ models: ['claude'], strategy: 'single' });
46
+ });
47
+
48
+ it('has an entry for every routable command', () => {
31
49
  for (const cmd of ROUTABLE_COMMANDS) {
32
- expect(SHIPPED_DEFAULTS[cmd]).toEqual({
33
- models: ['claude'],
34
- strategy: 'single',
35
- });
50
+ expect(SHIPPED_DEFAULTS[cmd]).toBeDefined();
36
51
  }
37
52
  });
38
53
  });
@@ -43,6 +58,7 @@ describe('task-router-config', () => {
43
58
  const expected = [
44
59
  'build', 'plan', 'review', 'test', 'coverage',
45
60
  'autofix', 'discuss', 'docs', 'edge-cases', 'quick',
61
+ 'design', 'vision',
46
62
  ];
47
63
  for (const cmd of expected) {
48
64
  expect(ROUTABLE_COMMANDS).toContain(cmd);
@@ -128,7 +144,7 @@ describe('task-router-config', () => {
128
144
 
129
145
  // ── resolveRouting ────────────────────────────────────────────────
130
146
  describe('resolveRouting', () => {
131
- it('returns shipped defaults when no config exists', () => {
147
+ it('returns shipped defaults when no config exists (coding command)', () => {
132
148
  const fs = mockFs({});
133
149
  const result = resolveRouting({
134
150
  command: 'build',
@@ -137,6 +153,23 @@ describe('task-router-config', () => {
137
153
  fs,
138
154
  });
139
155
 
156
+ expect(result).toEqual({
157
+ models: ['codex'],
158
+ strategy: 'single',
159
+ source: 'shipped-defaults',
160
+ warnings: [],
161
+ });
162
+ });
163
+
164
+ it('returns shipped defaults when no config exists (thinking command)', () => {
165
+ const fs = mockFs({});
166
+ const result = resolveRouting({
167
+ command: 'discuss',
168
+ projectDir: '/project',
169
+ homeDir: '/home/user',
170
+ fs,
171
+ });
172
+
140
173
  expect(result).toEqual({
141
174
  models: ['claude'],
142
175
  strategy: 'single',
@@ -274,7 +307,7 @@ describe('task-router-config', () => {
274
307
  warnings: [],
275
308
  });
276
309
 
277
- // 'build' should still use defaults
310
+ // 'build' should still use its shipped default (codex/single)
278
311
  const buildResult = resolveRouting({
279
312
  command: 'build',
280
313
  projectDir: '/project',
@@ -282,7 +315,7 @@ describe('task-router-config', () => {
282
315
  fs,
283
316
  });
284
317
  expect(buildResult).toEqual({
285
- models: ['claude'],
318
+ models: ['codex'],
286
319
  strategy: 'single',
287
320
  source: 'shipped-defaults',
288
321
  warnings: [],
@@ -306,9 +339,9 @@ describe('task-router-config', () => {
306
339
  fs,
307
340
  });
308
341
 
309
- // Should keep default models but use personal strategy
342
+ // Should keep default models (codex for build) but use personal strategy
310
343
  expect(result.strategy).toBe('parallel');
311
- expect(result.models).toEqual(['claude']);
344
+ expect(result.models).toEqual(['codex']);
312
345
  expect(result.source).toBe('personal-config');
313
346
  expect(result.warnings).toEqual([]);
314
347
  });
@@ -393,7 +426,7 @@ describe('task-router-config', () => {
393
426
  });
394
427
 
395
428
  expect(result).toEqual({
396
- models: ['claude'],
429
+ models: ['codex'],
397
430
  strategy: 'single',
398
431
  source: 'shipped-defaults',
399
432
  warnings: [expect.stringContaining('/home/user/.tlc/config.json')],
@@ -413,7 +446,7 @@ describe('task-router-config', () => {
413
446
  });
414
447
 
415
448
  expect(result).toEqual({
416
- models: ['claude'],
449
+ models: ['codex'],
417
450
  strategy: 'single',
418
451
  source: 'shipped-defaults',
419
452
  warnings: [expect.stringContaining('/project/.tlc.json')],
@@ -433,7 +466,7 @@ describe('task-router-config', () => {
433
466
  fs,
434
467
  });
435
468
 
436
- expect(result.models).toEqual(['claude']);
469
+ expect(result.models).toEqual(['codex']);
437
470
  expect(result.strategy).toBe('single');
438
471
  expect(result.source).toBe('shipped-defaults');
439
472
  expect(result.warnings).toHaveLength(2);