tlc-claude-code 1.4.4 → 1.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.
- package/dashboard/dist/App.js +28 -2
- package/dashboard/dist/api/health-diagnostics.d.ts +26 -0
- package/dashboard/dist/api/health-diagnostics.js +85 -0
- package/dashboard/dist/api/health-diagnostics.test.d.ts +1 -0
- package/dashboard/dist/api/health-diagnostics.test.js +126 -0
- package/dashboard/dist/api/index.d.ts +5 -0
- package/dashboard/dist/api/index.js +5 -0
- package/dashboard/dist/api/notes-api.d.ts +18 -0
- package/dashboard/dist/api/notes-api.js +68 -0
- package/dashboard/dist/api/notes-api.test.d.ts +1 -0
- package/dashboard/dist/api/notes-api.test.js +113 -0
- package/dashboard/dist/api/safeFetch.d.ts +50 -0
- package/dashboard/dist/api/safeFetch.js +135 -0
- package/dashboard/dist/api/safeFetch.test.d.ts +1 -0
- package/dashboard/dist/api/safeFetch.test.js +215 -0
- package/dashboard/dist/api/tasks-api.d.ts +32 -0
- package/dashboard/dist/api/tasks-api.js +98 -0
- package/dashboard/dist/api/tasks-api.test.d.ts +1 -0
- package/dashboard/dist/api/tasks-api.test.js +383 -0
- package/dashboard/dist/components/BugsPane.d.ts +20 -0
- package/dashboard/dist/components/BugsPane.js +210 -0
- package/dashboard/dist/components/BugsPane.test.d.ts +1 -0
- package/dashboard/dist/components/BugsPane.test.js +256 -0
- package/dashboard/dist/components/HealthPane.d.ts +3 -1
- package/dashboard/dist/components/HealthPane.js +44 -6
- package/dashboard/dist/components/HealthPane.test.js +105 -2
- package/dashboard/dist/components/RouterPane.d.ts +4 -3
- package/dashboard/dist/components/RouterPane.js +60 -57
- package/dashboard/dist/components/RouterPane.test.js +150 -96
- package/dashboard/dist/components/UpdateBanner.d.ts +26 -0
- package/dashboard/dist/components/UpdateBanner.js +30 -0
- package/dashboard/dist/components/UpdateBanner.test.d.ts +1 -0
- package/dashboard/dist/components/UpdateBanner.test.js +96 -0
- package/dashboard/dist/components/ui/EmptyState.d.ts +14 -0
- package/dashboard/dist/components/ui/EmptyState.js +58 -0
- package/dashboard/dist/components/ui/EmptyState.test.d.ts +1 -0
- package/dashboard/dist/components/ui/EmptyState.test.js +97 -0
- package/dashboard/dist/components/ui/ErrorState.d.ts +17 -0
- package/dashboard/dist/components/ui/ErrorState.js +80 -0
- package/dashboard/dist/components/ui/ErrorState.test.d.ts +1 -0
- package/dashboard/dist/components/ui/ErrorState.test.js +166 -0
- package/dashboard/package.json +3 -0
- package/package.json +1 -1
- package/server/dashboard/index.html +205 -8
- package/server/index.js +64 -0
- package/server/lib/api-provider.js +104 -186
- package/server/lib/api-provider.test.js +238 -336
- package/server/lib/cli-detector.js +90 -166
- package/server/lib/cli-detector.test.js +114 -269
- package/server/lib/cli-provider.js +142 -212
- package/server/lib/cli-provider.test.js +196 -349
- package/server/lib/debug.test.js +1 -1
- package/server/lib/devserver-router-api.js +54 -249
- package/server/lib/devserver-router-api.test.js +126 -426
- package/server/lib/introspect.js +309 -0
- package/server/lib/introspect.test.js +286 -0
- package/server/lib/model-router.js +107 -245
- package/server/lib/model-router.test.js +122 -313
- package/server/lib/output-schemas.js +146 -269
- package/server/lib/output-schemas.test.js +106 -307
- package/server/lib/provider-interface.js +99 -153
- package/server/lib/provider-interface.test.js +228 -394
- package/server/lib/provider-queue.js +164 -158
- package/server/lib/provider-queue.test.js +186 -315
- package/server/lib/router-config.js +99 -221
- package/server/lib/router-config.test.js +83 -237
- package/server/lib/router-setup-command.js +94 -419
- package/server/lib/router-setup-command.test.js +96 -375
- package/server/lib/router-status-api.js +93 -0
- package/server/lib/router-status-api.test.js +270 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router Status API Tests
|
|
3
|
+
* Phase 39, Task 3
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
6
|
+
import { getRouterStatus } from './router-status-api.js';
|
|
7
|
+
|
|
8
|
+
describe('Router Status API', () => {
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
vi.resetAllMocks();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
describe('getRouterStatus', () => {
|
|
14
|
+
it('returns providers object', async () => {
|
|
15
|
+
const mockDetectAllCLIs = vi.fn().mockResolvedValue({
|
|
16
|
+
claude: { found: true, path: '/usr/bin/claude', version: '1.0.0' },
|
|
17
|
+
codex: { found: false, path: null, version: null },
|
|
18
|
+
gemini: { found: true, path: '/usr/bin/gemini', version: '2.1.0' },
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const mockLoadRouterConfig = vi.fn().mockResolvedValue({
|
|
22
|
+
providers: {
|
|
23
|
+
claude: { type: 'cli', command: 'claude', capabilities: ['review', 'code-gen'] },
|
|
24
|
+
codex: { type: 'cli', command: 'codex', capabilities: ['review'] },
|
|
25
|
+
gemini: { type: 'cli', command: 'gemini', capabilities: ['design'] },
|
|
26
|
+
},
|
|
27
|
+
capabilities: {
|
|
28
|
+
'code-review': { providers: ['claude', 'gemini'] },
|
|
29
|
+
'code-gen': { providers: ['claude'] },
|
|
30
|
+
},
|
|
31
|
+
devserver: { url: null },
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const result = await getRouterStatus({
|
|
35
|
+
_detectAllCLIs: mockDetectAllCLIs,
|
|
36
|
+
_loadRouterConfig: mockLoadRouterConfig,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
expect(result).toHaveProperty('providers');
|
|
40
|
+
expect(result.providers).toHaveProperty('claude');
|
|
41
|
+
expect(result.providers).toHaveProperty('codex');
|
|
42
|
+
expect(result.providers).toHaveProperty('gemini');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('uses cli-detector to check availability', async () => {
|
|
46
|
+
const mockDetectAllCLIs = vi.fn().mockResolvedValue({
|
|
47
|
+
claude: { found: true, path: '/usr/bin/claude', version: '1.0.0' },
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const mockLoadRouterConfig = vi.fn().mockResolvedValue({
|
|
51
|
+
providers: { claude: { type: 'cli' } },
|
|
52
|
+
capabilities: {},
|
|
53
|
+
devserver: { url: null },
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
await getRouterStatus({
|
|
57
|
+
_detectAllCLIs: mockDetectAllCLIs,
|
|
58
|
+
_loadRouterConfig: mockLoadRouterConfig,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
expect(mockDetectAllCLIs).toHaveBeenCalled();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('returns capabilities from config', async () => {
|
|
65
|
+
const mockDetectAllCLIs = vi.fn().mockResolvedValue({
|
|
66
|
+
claude: { found: true, path: '/usr/bin/claude', version: '1.0.0' },
|
|
67
|
+
gemini: { found: true, path: '/usr/bin/gemini', version: '2.1.0' },
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const mockLoadRouterConfig = vi.fn().mockResolvedValue({
|
|
71
|
+
providers: {
|
|
72
|
+
claude: { type: 'cli' },
|
|
73
|
+
gemini: { type: 'cli' },
|
|
74
|
+
},
|
|
75
|
+
capabilities: {
|
|
76
|
+
'code-review': { providers: ['claude', 'gemini'] },
|
|
77
|
+
'code-gen': { providers: ['claude'] },
|
|
78
|
+
},
|
|
79
|
+
devserver: { url: null },
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const result = await getRouterStatus({
|
|
83
|
+
_detectAllCLIs: mockDetectAllCLIs,
|
|
84
|
+
_loadRouterConfig: mockLoadRouterConfig,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
expect(result).toHaveProperty('capabilities');
|
|
88
|
+
expect(result.capabilities).toHaveProperty('code-review');
|
|
89
|
+
expect(result.capabilities['code-review'].providers).toContain('claude');
|
|
90
|
+
expect(result.capabilities['code-review'].providers).toContain('gemini');
|
|
91
|
+
expect(result.capabilities).toHaveProperty('code-gen');
|
|
92
|
+
expect(result.capabilities['code-gen'].providers).toContain('claude');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('returns devserver status', async () => {
|
|
96
|
+
const mockDetectAllCLIs = vi.fn().mockResolvedValue({});
|
|
97
|
+
|
|
98
|
+
const mockLoadRouterConfig = vi.fn().mockResolvedValue({
|
|
99
|
+
providers: {},
|
|
100
|
+
capabilities: {},
|
|
101
|
+
devserver: { url: 'http://localhost:3000' },
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const mockCheckDevserver = vi.fn().mockResolvedValue(true);
|
|
105
|
+
|
|
106
|
+
const result = await getRouterStatus({
|
|
107
|
+
_detectAllCLIs: mockDetectAllCLIs,
|
|
108
|
+
_loadRouterConfig: mockLoadRouterConfig,
|
|
109
|
+
_checkDevserver: mockCheckDevserver,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
expect(result).toHaveProperty('devserver');
|
|
113
|
+
expect(result.devserver).toHaveProperty('connected');
|
|
114
|
+
expect(result.devserver).toHaveProperty('url');
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('handles missing config gracefully', async () => {
|
|
118
|
+
const mockDetectAllCLIs = vi.fn().mockResolvedValue({
|
|
119
|
+
claude: { found: true, path: '/usr/bin/claude', version: '1.0.0' },
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const mockLoadRouterConfig = vi.fn().mockRejectedValue(new Error('Config not found'));
|
|
123
|
+
|
|
124
|
+
const result = await getRouterStatus({
|
|
125
|
+
_detectAllCLIs: mockDetectAllCLIs,
|
|
126
|
+
_loadRouterConfig: mockLoadRouterConfig,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
expect(result).toHaveProperty('providers');
|
|
130
|
+
expect(result).toHaveProperty('capabilities');
|
|
131
|
+
expect(result).toHaveProperty('devserver');
|
|
132
|
+
expect(result).toHaveProperty('usage');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('provider detected=true when CLI found', async () => {
|
|
136
|
+
const mockDetectAllCLIs = vi.fn().mockResolvedValue({
|
|
137
|
+
claude: { found: true, path: '/usr/bin/claude', version: '1.0.0' },
|
|
138
|
+
codex: { found: false, path: null, version: null },
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const mockLoadRouterConfig = vi.fn().mockResolvedValue({
|
|
142
|
+
providers: {
|
|
143
|
+
claude: { type: 'cli' },
|
|
144
|
+
codex: { type: 'cli' },
|
|
145
|
+
},
|
|
146
|
+
capabilities: {},
|
|
147
|
+
devserver: { url: null },
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const result = await getRouterStatus({
|
|
151
|
+
_detectAllCLIs: mockDetectAllCLIs,
|
|
152
|
+
_loadRouterConfig: mockLoadRouterConfig,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
expect(result.providers.claude.detected).toBe(true);
|
|
156
|
+
expect(result.providers.claude.version).toBe('1.0.0');
|
|
157
|
+
expect(result.providers.codex.detected).toBe(false);
|
|
158
|
+
expect(result.providers.codex.version).toBeNull();
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe('Response format', () => {
|
|
163
|
+
it('matches expected dashboard format', async () => {
|
|
164
|
+
const mockDetectAllCLIs = vi.fn().mockResolvedValue({
|
|
165
|
+
claude: { found: true, path: '/usr/bin/claude', version: '1.0.0' },
|
|
166
|
+
codex: { found: false, path: null, version: null },
|
|
167
|
+
gemini: { found: true, path: '/usr/bin/gemini', version: '2.1.0' },
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const mockLoadRouterConfig = vi.fn().mockResolvedValue({
|
|
171
|
+
providers: {
|
|
172
|
+
claude: { type: 'cli', command: 'claude' },
|
|
173
|
+
codex: { type: 'cli', command: 'codex' },
|
|
174
|
+
gemini: { type: 'cli', command: 'gemini' },
|
|
175
|
+
},
|
|
176
|
+
capabilities: {
|
|
177
|
+
'code-review': { providers: ['claude', 'gemini'] },
|
|
178
|
+
'code-gen': { providers: ['claude'] },
|
|
179
|
+
},
|
|
180
|
+
devserver: { url: null },
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const result = await getRouterStatus({
|
|
184
|
+
_detectAllCLIs: mockDetectAllCLIs,
|
|
185
|
+
_loadRouterConfig: mockLoadRouterConfig,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Verify full response format
|
|
189
|
+
expect(result).toMatchObject({
|
|
190
|
+
providers: {
|
|
191
|
+
claude: { name: 'claude', type: 'cli', detected: true, version: '1.0.0' },
|
|
192
|
+
codex: { name: 'codex', type: 'cli', detected: false, version: null },
|
|
193
|
+
gemini: { name: 'gemini', type: 'cli', detected: true, version: '2.1.0' },
|
|
194
|
+
},
|
|
195
|
+
capabilities: {
|
|
196
|
+
'code-review': { providers: ['claude', 'gemini'] },
|
|
197
|
+
'code-gen': { providers: ['claude'] },
|
|
198
|
+
},
|
|
199
|
+
devserver: { connected: false, url: null },
|
|
200
|
+
usage: { requestsToday: 0, tokensUsed: 0 },
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
describe('Devserver connection', () => {
|
|
206
|
+
it('shows connected=true when devserver responds', async () => {
|
|
207
|
+
const mockDetectAllCLIs = vi.fn().mockResolvedValue({});
|
|
208
|
+
|
|
209
|
+
const mockLoadRouterConfig = vi.fn().mockResolvedValue({
|
|
210
|
+
providers: {},
|
|
211
|
+
capabilities: {},
|
|
212
|
+
devserver: { url: 'http://localhost:3000' },
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const mockCheckDevserver = vi.fn().mockResolvedValue(true);
|
|
216
|
+
|
|
217
|
+
const result = await getRouterStatus({
|
|
218
|
+
_detectAllCLIs: mockDetectAllCLIs,
|
|
219
|
+
_loadRouterConfig: mockLoadRouterConfig,
|
|
220
|
+
_checkDevserver: mockCheckDevserver,
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
expect(result.devserver.connected).toBe(true);
|
|
224
|
+
expect(result.devserver.url).toBe('http://localhost:3000');
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('shows connected=false when devserver fails', async () => {
|
|
228
|
+
const mockDetectAllCLIs = vi.fn().mockResolvedValue({});
|
|
229
|
+
|
|
230
|
+
const mockLoadRouterConfig = vi.fn().mockResolvedValue({
|
|
231
|
+
providers: {},
|
|
232
|
+
capabilities: {},
|
|
233
|
+
devserver: { url: 'http://localhost:3000' },
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
const mockCheckDevserver = vi.fn().mockResolvedValue(false);
|
|
237
|
+
|
|
238
|
+
const result = await getRouterStatus({
|
|
239
|
+
_detectAllCLIs: mockDetectAllCLIs,
|
|
240
|
+
_loadRouterConfig: mockLoadRouterConfig,
|
|
241
|
+
_checkDevserver: mockCheckDevserver,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
expect(result.devserver.connected).toBe(false);
|
|
245
|
+
expect(result.devserver.url).toBe('http://localhost:3000');
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('skips check when no devserver URL configured', async () => {
|
|
249
|
+
const mockDetectAllCLIs = vi.fn().mockResolvedValue({});
|
|
250
|
+
|
|
251
|
+
const mockLoadRouterConfig = vi.fn().mockResolvedValue({
|
|
252
|
+
providers: {},
|
|
253
|
+
capabilities: {},
|
|
254
|
+
devserver: { url: null },
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
const mockCheckDevserver = vi.fn();
|
|
258
|
+
|
|
259
|
+
const result = await getRouterStatus({
|
|
260
|
+
_detectAllCLIs: mockDetectAllCLIs,
|
|
261
|
+
_loadRouterConfig: mockLoadRouterConfig,
|
|
262
|
+
_checkDevserver: mockCheckDevserver,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
expect(mockCheckDevserver).not.toHaveBeenCalled();
|
|
266
|
+
expect(result.devserver.connected).toBe(false);
|
|
267
|
+
expect(result.devserver.url).toBeNull();
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
});
|