tlc-claude-code 1.4.2 → 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.
Files changed (113) hide show
  1. package/dashboard/dist/App.js +28 -2
  2. package/dashboard/dist/api/health-diagnostics.d.ts +26 -0
  3. package/dashboard/dist/api/health-diagnostics.js +85 -0
  4. package/dashboard/dist/api/health-diagnostics.test.d.ts +1 -0
  5. package/dashboard/dist/api/health-diagnostics.test.js +126 -0
  6. package/dashboard/dist/api/index.d.ts +5 -0
  7. package/dashboard/dist/api/index.js +5 -0
  8. package/dashboard/dist/api/notes-api.d.ts +18 -0
  9. package/dashboard/dist/api/notes-api.js +68 -0
  10. package/dashboard/dist/api/notes-api.test.d.ts +1 -0
  11. package/dashboard/dist/api/notes-api.test.js +113 -0
  12. package/dashboard/dist/api/safeFetch.d.ts +50 -0
  13. package/dashboard/dist/api/safeFetch.js +135 -0
  14. package/dashboard/dist/api/safeFetch.test.d.ts +1 -0
  15. package/dashboard/dist/api/safeFetch.test.js +215 -0
  16. package/dashboard/dist/api/tasks-api.d.ts +32 -0
  17. package/dashboard/dist/api/tasks-api.js +98 -0
  18. package/dashboard/dist/api/tasks-api.test.d.ts +1 -0
  19. package/dashboard/dist/api/tasks-api.test.js +383 -0
  20. package/dashboard/dist/components/BugsPane.d.ts +20 -0
  21. package/dashboard/dist/components/BugsPane.js +210 -0
  22. package/dashboard/dist/components/BugsPane.test.d.ts +1 -0
  23. package/dashboard/dist/components/BugsPane.test.js +256 -0
  24. package/dashboard/dist/components/HealthPane.d.ts +3 -1
  25. package/dashboard/dist/components/HealthPane.js +44 -6
  26. package/dashboard/dist/components/HealthPane.test.js +105 -2
  27. package/dashboard/dist/components/RouterPane.d.ts +4 -3
  28. package/dashboard/dist/components/RouterPane.js +60 -57
  29. package/dashboard/dist/components/RouterPane.test.js +150 -96
  30. package/dashboard/dist/components/UpdateBanner.d.ts +26 -0
  31. package/dashboard/dist/components/UpdateBanner.js +30 -0
  32. package/dashboard/dist/components/UpdateBanner.test.d.ts +1 -0
  33. package/dashboard/dist/components/UpdateBanner.test.js +96 -0
  34. package/dashboard/dist/components/accessibility.test.d.ts +1 -0
  35. package/dashboard/dist/components/accessibility.test.js +116 -0
  36. package/dashboard/dist/components/layout/MobileNav.d.ts +16 -0
  37. package/dashboard/dist/components/layout/MobileNav.js +31 -0
  38. package/dashboard/dist/components/layout/MobileNav.test.d.ts +1 -0
  39. package/dashboard/dist/components/layout/MobileNav.test.js +111 -0
  40. package/dashboard/dist/components/performance.test.d.ts +1 -0
  41. package/dashboard/dist/components/performance.test.js +114 -0
  42. package/dashboard/dist/components/responsive.test.d.ts +1 -0
  43. package/dashboard/dist/components/responsive.test.js +114 -0
  44. package/dashboard/dist/components/ui/Dropdown.d.ts +22 -0
  45. package/dashboard/dist/components/ui/Dropdown.js +109 -0
  46. package/dashboard/dist/components/ui/Dropdown.test.d.ts +1 -0
  47. package/dashboard/dist/components/ui/Dropdown.test.js +105 -0
  48. package/dashboard/dist/components/ui/EmptyState.d.ts +14 -0
  49. package/dashboard/dist/components/ui/EmptyState.js +58 -0
  50. package/dashboard/dist/components/ui/EmptyState.test.d.ts +1 -0
  51. package/dashboard/dist/components/ui/EmptyState.test.js +97 -0
  52. package/dashboard/dist/components/ui/ErrorState.d.ts +17 -0
  53. package/dashboard/dist/components/ui/ErrorState.js +80 -0
  54. package/dashboard/dist/components/ui/ErrorState.test.d.ts +1 -0
  55. package/dashboard/dist/components/ui/ErrorState.test.js +166 -0
  56. package/dashboard/dist/components/ui/Modal.d.ts +13 -0
  57. package/dashboard/dist/components/ui/Modal.js +25 -0
  58. package/dashboard/dist/components/ui/Modal.test.d.ts +1 -0
  59. package/dashboard/dist/components/ui/Modal.test.js +91 -0
  60. package/dashboard/dist/components/ui/Skeleton.d.ts +32 -0
  61. package/dashboard/dist/components/ui/Skeleton.js +48 -0
  62. package/dashboard/dist/components/ui/Skeleton.test.d.ts +1 -0
  63. package/dashboard/dist/components/ui/Skeleton.test.js +125 -0
  64. package/dashboard/dist/components/ui/Toast.d.ts +32 -0
  65. package/dashboard/dist/components/ui/Toast.js +21 -0
  66. package/dashboard/dist/components/ui/Toast.test.d.ts +1 -0
  67. package/dashboard/dist/components/ui/Toast.test.js +118 -0
  68. package/dashboard/dist/hooks/useTheme.d.ts +37 -0
  69. package/dashboard/dist/hooks/useTheme.js +96 -0
  70. package/dashboard/dist/hooks/useTheme.test.d.ts +1 -0
  71. package/dashboard/dist/hooks/useTheme.test.js +94 -0
  72. package/dashboard/dist/hooks/useWebSocket.d.ts +17 -0
  73. package/dashboard/dist/hooks/useWebSocket.js +100 -0
  74. package/dashboard/dist/hooks/useWebSocket.test.d.ts +1 -0
  75. package/dashboard/dist/hooks/useWebSocket.test.js +115 -0
  76. package/dashboard/dist/stores/projectStore.d.ts +44 -0
  77. package/dashboard/dist/stores/projectStore.js +76 -0
  78. package/dashboard/dist/stores/projectStore.test.d.ts +1 -0
  79. package/dashboard/dist/stores/projectStore.test.js +114 -0
  80. package/dashboard/dist/stores/uiStore.d.ts +29 -0
  81. package/dashboard/dist/stores/uiStore.js +72 -0
  82. package/dashboard/dist/stores/uiStore.test.d.ts +1 -0
  83. package/dashboard/dist/stores/uiStore.test.js +93 -0
  84. package/dashboard/package.json +6 -3
  85. package/docker-compose.dev.yml +6 -1
  86. package/package.json +1 -1
  87. package/server/dashboard/index.html +1545 -791
  88. package/server/index.js +64 -0
  89. package/server/lib/api-provider.js +104 -186
  90. package/server/lib/api-provider.test.js +238 -336
  91. package/server/lib/cli-detector.js +90 -166
  92. package/server/lib/cli-detector.test.js +114 -269
  93. package/server/lib/cli-provider.js +142 -212
  94. package/server/lib/cli-provider.test.js +196 -349
  95. package/server/lib/debug.test.js +1 -1
  96. package/server/lib/devserver-router-api.js +54 -249
  97. package/server/lib/devserver-router-api.test.js +126 -426
  98. package/server/lib/introspect.js +309 -0
  99. package/server/lib/introspect.test.js +286 -0
  100. package/server/lib/model-router.js +107 -245
  101. package/server/lib/model-router.test.js +122 -313
  102. package/server/lib/output-schemas.js +146 -269
  103. package/server/lib/output-schemas.test.js +106 -307
  104. package/server/lib/provider-interface.js +99 -153
  105. package/server/lib/provider-interface.test.js +228 -394
  106. package/server/lib/provider-queue.js +164 -158
  107. package/server/lib/provider-queue.test.js +186 -315
  108. package/server/lib/router-config.js +99 -221
  109. package/server/lib/router-config.test.js +83 -237
  110. package/server/lib/router-setup-command.js +94 -419
  111. package/server/lib/router-setup-command.test.js +96 -375
  112. package/server/lib/router-status-api.js +93 -0
  113. package/server/lib/router-status-api.test.js +270 -0
@@ -1,245 +1,107 @@
1
- /**
2
- * Model Router - Routes requests to appropriate provider
3
- *
4
- * Implements two-tier routing:
5
- * - Local: CLI tools detected on the machine (free)
6
- * - Devserver: Headless CLI or API providers (paid)
7
- */
8
-
9
- import { detectAllCLIs, clearCache } from './cli-detector.js';
10
- import { createCLIProvider } from './cli-provider.js';
11
- import { createAPIProvider } from './api-provider.js';
12
- import fs from 'fs/promises';
13
- import path from 'path';
14
-
15
- /**
16
- * Default router configuration
17
- */
18
- export const DEFAULT_CONFIG = {
19
- providers: {
20
- claude: {
21
- type: 'cli',
22
- command: 'claude',
23
- headlessArgs: ['-p', '--output-format', 'json'],
24
- capabilities: ['review', 'code-gen', 'refactor', 'explain'],
25
- },
26
- codex: {
27
- type: 'cli',
28
- command: 'codex',
29
- headlessArgs: ['exec', '--json', '--sandbox', 'read-only'],
30
- capabilities: ['review', 'code-gen', 'refactor'],
31
- },
32
- gemini: {
33
- type: 'cli',
34
- command: 'gemini',
35
- headlessArgs: ['-p', '--output-format', 'json'],
36
- capabilities: ['design', 'vision', 'review', 'image-gen'],
37
- },
38
- deepseek: {
39
- type: 'api',
40
- baseUrl: 'https://api.deepseek.com',
41
- model: 'deepseek-coder',
42
- capabilities: ['review'],
43
- devserverOnly: true,
44
- },
45
- },
46
- capabilities: {
47
- review: {
48
- providers: ['claude', 'codex', 'deepseek'],
49
- consensus: 'majority',
50
- },
51
- design: {
52
- providers: ['gemini'],
53
- },
54
- 'code-gen': {
55
- providers: ['claude'],
56
- },
57
- },
58
- devserver: {
59
- url: null,
60
- queue: {
61
- maxConcurrent: 3,
62
- timeout: 120000,
63
- },
64
- },
65
- };
66
-
67
- /**
68
- * Load router configuration from .tlc.json
69
- * @param {string} projectDir - Project directory
70
- * @returns {Promise<Object>} Router configuration
71
- */
72
- export async function loadConfig(projectDir) {
73
- try {
74
- const configPath = path.join(projectDir, '.tlc.json');
75
- const content = await fs.readFile(configPath, 'utf8');
76
- const config = JSON.parse(content);
77
-
78
- // Merge with defaults
79
- return {
80
- providers: {
81
- ...DEFAULT_CONFIG.providers,
82
- ...(config.router?.providers || {}),
83
- },
84
- capabilities: {
85
- ...DEFAULT_CONFIG.capabilities,
86
- ...(config.router?.capabilities || {}),
87
- },
88
- devserver: {
89
- ...DEFAULT_CONFIG.devserver,
90
- ...(config.router?.devserver || {}),
91
- },
92
- };
93
- } catch (err) {
94
- // Return defaults if no config file
95
- return DEFAULT_CONFIG;
96
- }
97
- }
98
-
99
- /**
100
- * Create a router instance
101
- * @param {Object} [config] - Router configuration
102
- * @returns {Promise<Object>} Router instance
103
- */
104
- export async function createRouter(config = DEFAULT_CONFIG) {
105
- // Detect local CLIs
106
- const detectedCLIs = await detectAllCLIs();
107
-
108
- // Create provider instances
109
- const providers = new Map();
110
-
111
- for (const [name, providerConfig] of Object.entries(config.providers || {})) {
112
- const detected = detectedCLIs.has(name);
113
- const cliInfo = detectedCLIs.get(name);
114
-
115
- if (providerConfig.type === 'cli') {
116
- providers.set(name, createCLIProvider({
117
- name,
118
- ...providerConfig,
119
- detected,
120
- version: cliInfo?.version,
121
- devserverUrl: config.devserver?.url,
122
- }));
123
- } else if (providerConfig.type === 'api') {
124
- providers.set(name, createAPIProvider({
125
- name,
126
- ...providerConfig,
127
- }));
128
- }
129
- }
130
-
131
- /**
132
- * Resolve a provider by name
133
- * @param {string} name - Provider name
134
- * @returns {Object|null} Resolution result { provider, via } or null
135
- */
136
- function resolveProvider(name) {
137
- const provider = providers.get(name);
138
- if (!provider) return null;
139
-
140
- // Determine routing
141
- if (provider.type === 'cli' && provider.detected) {
142
- return { provider, via: 'local' };
143
- }
144
-
145
- // Fall back to devserver
146
- return { provider, via: 'devserver' };
147
- }
148
-
149
- /**
150
- * Resolve providers for a capability
151
- * @param {string} capability - Capability name
152
- * @returns {Object[]} Array of providers
153
- */
154
- function resolveCapability(capability) {
155
- const capConfig = config.capabilities?.[capability];
156
- if (!capConfig) return [];
157
-
158
- const resolved = [];
159
-
160
- for (const providerName of capConfig.providers || []) {
161
- const result = resolveProvider(providerName);
162
- if (result) {
163
- resolved.push({
164
- ...result.provider,
165
- via: result.via,
166
- });
167
- }
168
- }
169
-
170
- return resolved;
171
- }
172
-
173
- /**
174
- * Run a prompt through providers for a capability
175
- * @param {string} capability - Capability name
176
- * @param {string} prompt - The prompt
177
- * @param {Object} [opts] - Run options
178
- * @returns {Promise<Object[]>} Array of results
179
- */
180
- async function run(capability, prompt, opts = {}) {
181
- const capProviders = resolveCapability(capability);
182
-
183
- if (capProviders.length === 0) {
184
- throw new Error(`No providers available for capability: ${capability}`);
185
- }
186
-
187
- // Run all providers in parallel
188
- const results = await Promise.all(
189
- capProviders.map(async (provider) => {
190
- try {
191
- const result = await provider.run(prompt, opts);
192
- return {
193
- provider: provider.name,
194
- via: provider.via,
195
- success: true,
196
- result,
197
- };
198
- } catch (err) {
199
- return {
200
- provider: provider.name,
201
- via: provider.via,
202
- success: false,
203
- error: err.message,
204
- };
205
- }
206
- })
207
- );
208
-
209
- return results;
210
- }
211
-
212
- /**
213
- * Get router status
214
- * @returns {Object} Status information
215
- */
216
- function getStatus() {
217
- const status = {
218
- providers: {},
219
- devserver: {
220
- configured: !!config.devserver?.url,
221
- url: config.devserver?.url,
222
- },
223
- };
224
-
225
- for (const [name, provider] of providers) {
226
- status.providers[name] = {
227
- type: provider.type,
228
- detected: provider.detected,
229
- capabilities: provider.capabilities,
230
- };
231
- }
232
-
233
- return status;
234
- }
235
-
236
- return {
237
- resolveProvider,
238
- resolveCapability,
239
- run,
240
- getStatus,
241
- providers,
242
- config,
243
- };
244
- }
245
-
1
+ /**
2
+ * Model Router - Route requests to appropriate provider
3
+ * Phase 33, Task 5
4
+ */
5
+
6
+ import { detectCLI } from './cli-detector.js';
7
+ import { readFile } from 'fs/promises';
8
+ import { join } from 'path';
9
+
10
+ const DEFAULT_CONFIG = {
11
+ providers: {},
12
+ capabilities: {},
13
+ devserver: { url: null },
14
+ };
15
+
16
+ export class ModelRouter {
17
+ constructor(config = {}) {
18
+ this.config = { ...DEFAULT_CONFIG, ...config };
19
+ this.devserverUrl = config.devserver?.url || null;
20
+ this._detectCLI = detectCLI;
21
+ this._readConfig = null;
22
+ }
23
+
24
+ async resolveProvider(name) {
25
+ const providerConfig = this.config.providers[name];
26
+ if (!providerConfig) {
27
+ throw new Error('Unknown provider: ' + name);
28
+ }
29
+
30
+ // API providers always go to devserver
31
+ if (providerConfig.type === 'api') {
32
+ return {
33
+ name,
34
+ config: providerConfig,
35
+ location: 'devserver',
36
+ available: !!this.devserverUrl,
37
+ };
38
+ }
39
+
40
+ // CLI providers: try local first
41
+ const detected = await this._detectCLI(providerConfig.command || name);
42
+ if (detected.found) {
43
+ return {
44
+ name,
45
+ config: providerConfig,
46
+ location: 'local',
47
+ path: detected.path,
48
+ available: true,
49
+ };
50
+ }
51
+
52
+ // Fall back to devserver
53
+ return {
54
+ name,
55
+ config: providerConfig,
56
+ location: 'devserver',
57
+ available: !!this.devserverUrl,
58
+ };
59
+ }
60
+
61
+ async resolveCapability(capability) {
62
+ const capConfig = this.config.capabilities[capability];
63
+ if (!capConfig) {
64
+ return [];
65
+ }
66
+
67
+ const providers = [];
68
+ for (const name of capConfig.providers || []) {
69
+ const provider = await this.resolveProvider(name);
70
+ providers.push(provider);
71
+ }
72
+
73
+ return providers;
74
+ }
75
+
76
+ async loadConfig() {
77
+ try {
78
+ let configData;
79
+ if (this._readConfig) {
80
+ configData = await this._readConfig();
81
+ } else {
82
+ const configPath = join(process.cwd(), '.tlc.json');
83
+ const content = await readFile(configPath, 'utf-8');
84
+ configData = JSON.parse(content);
85
+ }
86
+
87
+ if (configData.router) {
88
+ this.config = { ...DEFAULT_CONFIG, ...configData.router };
89
+ this.devserverUrl = configData.router.devserver?.url || null;
90
+ }
91
+ } catch {
92
+ // Use defaults
93
+ }
94
+ }
95
+ }
96
+
97
+ export async function resolveProvider(name, config) {
98
+ const router = new ModelRouter(config);
99
+ return router.resolveProvider(name);
100
+ }
101
+
102
+ export async function resolveCapability(capability, config) {
103
+ const router = new ModelRouter(config);
104
+ return router.resolveCapability(capability);
105
+ }
106
+
107
+ export default { ModelRouter, resolveProvider, resolveCapability };