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
|
-
**
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
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
|
@@ -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:
|
|
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
|
-
|
|
30
|
-
|
|
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('
|
|
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]).
|
|
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
|
|
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: ['
|
|
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(['
|
|
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: ['
|
|
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: ['
|
|
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(['
|
|
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);
|