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
|
@@ -1,307 +1,106 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
it('
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
expect(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
summary: 'Code looks good',
|
|
108
|
-
// Missing score and approved
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
const result = validateOutput(data, schema);
|
|
112
|
-
|
|
113
|
-
expect(result.valid).toBe(false);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('validates nested objects', () => {
|
|
117
|
-
const nestedSchema = {
|
|
118
|
-
type: 'object',
|
|
119
|
-
properties: {
|
|
120
|
-
issue: {
|
|
121
|
-
type: 'object',
|
|
122
|
-
properties: {
|
|
123
|
-
severity: { type: 'string', enum: ['critical', 'moderate', 'suggestion'] },
|
|
124
|
-
line: { type: 'integer' },
|
|
125
|
-
},
|
|
126
|
-
required: ['severity'],
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
const validData = {
|
|
132
|
-
issue: { severity: 'critical', line: 42 },
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
const invalidData = {
|
|
136
|
-
issue: { severity: 'invalid-severity' },
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
expect(validateOutput(validData, nestedSchema).valid).toBe(true);
|
|
140
|
-
expect(validateOutput(invalidData, nestedSchema).valid).toBe(false);
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
describe('BUILTIN_SCHEMAS', () => {
|
|
145
|
-
it('has review-result schema', () => {
|
|
146
|
-
const schema = BUILTIN_SCHEMAS['review-result'];
|
|
147
|
-
|
|
148
|
-
expect(schema).toBeDefined();
|
|
149
|
-
expect(schema.properties.summary).toBeDefined();
|
|
150
|
-
expect(schema.properties.issues).toBeDefined();
|
|
151
|
-
expect(schema.properties.score).toBeDefined();
|
|
152
|
-
expect(schema.properties.approved).toBeDefined();
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it('review-result has required fields', () => {
|
|
156
|
-
const schema = BUILTIN_SCHEMAS['review-result'];
|
|
157
|
-
|
|
158
|
-
expect(schema.required).toContain('summary');
|
|
159
|
-
expect(schema.required).toContain('issues');
|
|
160
|
-
expect(schema.required).toContain('score');
|
|
161
|
-
expect(schema.required).toContain('approved');
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('has design-result schema', () => {
|
|
165
|
-
const schema = BUILTIN_SCHEMAS['design-result'];
|
|
166
|
-
|
|
167
|
-
expect(schema).toBeDefined();
|
|
168
|
-
expect(schema.properties.mockups).toBeDefined();
|
|
169
|
-
expect(schema.properties.rationale).toBeDefined();
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it('design-result has required fields', () => {
|
|
173
|
-
const schema = BUILTIN_SCHEMAS['design-result'];
|
|
174
|
-
|
|
175
|
-
expect(schema.required).toContain('mockups');
|
|
176
|
-
expect(schema.required).toContain('rationale');
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it('has code-result schema', () => {
|
|
180
|
-
const schema = BUILTIN_SCHEMAS['code-result'];
|
|
181
|
-
|
|
182
|
-
expect(schema).toBeDefined();
|
|
183
|
-
expect(schema.properties.files).toBeDefined();
|
|
184
|
-
expect(schema.properties.explanation).toBeDefined();
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('code-result has required fields', () => {
|
|
188
|
-
const schema = BUILTIN_SCHEMAS['code-result'];
|
|
189
|
-
|
|
190
|
-
expect(schema.required).toContain('files');
|
|
191
|
-
expect(schema.required).toContain('explanation');
|
|
192
|
-
});
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
describe('buildPromptWithSchema', () => {
|
|
196
|
-
it('injects schema into prompt', () => {
|
|
197
|
-
const prompt = 'Review this code';
|
|
198
|
-
const schema = {
|
|
199
|
-
type: 'object',
|
|
200
|
-
properties: { result: { type: 'string' } },
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
const result = buildPromptWithSchema(prompt, schema);
|
|
204
|
-
|
|
205
|
-
expect(result).toContain('Review this code');
|
|
206
|
-
expect(result).toContain('JSON');
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it('includes schema structure', () => {
|
|
210
|
-
const prompt = 'Analyze';
|
|
211
|
-
const schema = {
|
|
212
|
-
type: 'object',
|
|
213
|
-
properties: {
|
|
214
|
-
summary: { type: 'string' },
|
|
215
|
-
score: { type: 'integer' },
|
|
216
|
-
},
|
|
217
|
-
required: ['summary'],
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
const result = buildPromptWithSchema(prompt, schema);
|
|
221
|
-
|
|
222
|
-
expect(result).toContain('summary');
|
|
223
|
-
expect(result).toContain('score');
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
it('returns original prompt when no schema', () => {
|
|
227
|
-
const prompt = 'Just a prompt';
|
|
228
|
-
|
|
229
|
-
const result = buildPromptWithSchema(prompt, null);
|
|
230
|
-
|
|
231
|
-
expect(result).toBe(prompt);
|
|
232
|
-
});
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
describe('schemaToPromptInstructions', () => {
|
|
236
|
-
it('creates text instructions from schema', () => {
|
|
237
|
-
const schema = {
|
|
238
|
-
type: 'object',
|
|
239
|
-
properties: {
|
|
240
|
-
summary: { type: 'string', description: 'A brief summary' },
|
|
241
|
-
score: { type: 'integer', minimum: 0, maximum: 100 },
|
|
242
|
-
},
|
|
243
|
-
required: ['summary', 'score'],
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
const instructions = schemaToPromptInstructions(schema);
|
|
247
|
-
|
|
248
|
-
expect(instructions).toContain('summary');
|
|
249
|
-
expect(instructions).toContain('score');
|
|
250
|
-
expect(instructions).toContain('required');
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
it('handles nested objects', () => {
|
|
254
|
-
const schema = {
|
|
255
|
-
type: 'object',
|
|
256
|
-
properties: {
|
|
257
|
-
data: {
|
|
258
|
-
type: 'object',
|
|
259
|
-
properties: {
|
|
260
|
-
value: { type: 'string' },
|
|
261
|
-
},
|
|
262
|
-
},
|
|
263
|
-
},
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
const instructions = schemaToPromptInstructions(schema);
|
|
267
|
-
|
|
268
|
-
expect(instructions).toContain('data');
|
|
269
|
-
expect(instructions).toContain('value');
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
it('handles arrays', () => {
|
|
273
|
-
const schema = {
|
|
274
|
-
type: 'object',
|
|
275
|
-
properties: {
|
|
276
|
-
items: {
|
|
277
|
-
type: 'array',
|
|
278
|
-
items: { type: 'string' },
|
|
279
|
-
},
|
|
280
|
-
},
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
const instructions = schemaToPromptInstructions(schema);
|
|
284
|
-
|
|
285
|
-
expect(instructions).toContain('items');
|
|
286
|
-
expect(instructions).toContain('array');
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
it('includes enum values', () => {
|
|
290
|
-
const schema = {
|
|
291
|
-
type: 'object',
|
|
292
|
-
properties: {
|
|
293
|
-
status: {
|
|
294
|
-
type: 'string',
|
|
295
|
-
enum: ['pending', 'approved', 'rejected'],
|
|
296
|
-
},
|
|
297
|
-
},
|
|
298
|
-
};
|
|
299
|
-
|
|
300
|
-
const instructions = schemaToPromptInstructions(schema);
|
|
301
|
-
|
|
302
|
-
expect(instructions).toContain('pending');
|
|
303
|
-
expect(instructions).toContain('approved');
|
|
304
|
-
expect(instructions).toContain('rejected');
|
|
305
|
-
});
|
|
306
|
-
});
|
|
307
|
-
});
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
loadSchema,
|
|
4
|
+
validateOutput,
|
|
5
|
+
reviewResultSchema,
|
|
6
|
+
designResultSchema,
|
|
7
|
+
codeResultSchema,
|
|
8
|
+
buildPromptWithSchema,
|
|
9
|
+
schemaToPromptInstructions,
|
|
10
|
+
} from './output-schemas.js';
|
|
11
|
+
|
|
12
|
+
describe('Output Schemas', () => {
|
|
13
|
+
describe('loadSchema', () => {
|
|
14
|
+
it('reads from file', async () => {
|
|
15
|
+
const schema = await loadSchema('review-result');
|
|
16
|
+
expect(schema).toBeDefined();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('returns parsed JSON', async () => {
|
|
20
|
+
const schema = await loadSchema('review-result');
|
|
21
|
+
expect(schema).toHaveProperty('type');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('handles missing schema file', async () => {
|
|
25
|
+
await expect(loadSchema('nonexistent')).rejects.toThrow();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('validateOutput', () => {
|
|
30
|
+
it('passes valid data', () => {
|
|
31
|
+
const schema = {
|
|
32
|
+
type: 'object',
|
|
33
|
+
required: ['summary'],
|
|
34
|
+
properties: {
|
|
35
|
+
summary: { type: 'string' },
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const result = validateOutput({ summary: 'Test' }, schema);
|
|
40
|
+
expect(result.valid).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('rejects invalid data', () => {
|
|
44
|
+
const schema = {
|
|
45
|
+
type: 'object',
|
|
46
|
+
required: ['summary'],
|
|
47
|
+
properties: {
|
|
48
|
+
summary: { type: 'string' },
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const result = validateOutput({ other: 'field' }, schema);
|
|
53
|
+
expect(result.valid).toBe(false);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe('Built-in Schemas', () => {
|
|
58
|
+
it('reviewResultSchema has required fields', () => {
|
|
59
|
+
expect(reviewResultSchema.properties).toHaveProperty('summary');
|
|
60
|
+
expect(reviewResultSchema.properties).toHaveProperty('issues');
|
|
61
|
+
expect(reviewResultSchema.properties).toHaveProperty('score');
|
|
62
|
+
expect(reviewResultSchema.properties).toHaveProperty('approved');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('designResultSchema has required fields', () => {
|
|
66
|
+
expect(designResultSchema.properties).toHaveProperty('mockups');
|
|
67
|
+
expect(designResultSchema.properties).toHaveProperty('rationale');
|
|
68
|
+
expect(designResultSchema.properties).toHaveProperty('alternatives');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('codeResultSchema has required fields', () => {
|
|
72
|
+
expect(codeResultSchema.properties).toHaveProperty('files');
|
|
73
|
+
expect(codeResultSchema.properties).toHaveProperty('explanation');
|
|
74
|
+
expect(codeResultSchema.properties).toHaveProperty('tests');
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('buildPromptWithSchema', () => {
|
|
79
|
+
it('injects schema into prompt', () => {
|
|
80
|
+
const prompt = 'Review this code';
|
|
81
|
+
const schema = { type: 'object', properties: { summary: { type: 'string' } } };
|
|
82
|
+
|
|
83
|
+
const enhanced = buildPromptWithSchema(prompt, schema);
|
|
84
|
+
|
|
85
|
+
expect(enhanced).toContain('Review this code');
|
|
86
|
+
expect(enhanced).toContain('JSON');
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe('schemaToPromptInstructions', () => {
|
|
91
|
+
it('creates text instructions', () => {
|
|
92
|
+
const schema = {
|
|
93
|
+
type: 'object',
|
|
94
|
+
properties: {
|
|
95
|
+
summary: { type: 'string', description: 'Brief summary' },
|
|
96
|
+
score: { type: 'number', description: 'Quality score 0-100' },
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const instructions = schemaToPromptInstructions(schema);
|
|
101
|
+
|
|
102
|
+
expect(instructions).toContain('summary');
|
|
103
|
+
expect(instructions).toContain('score');
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -1,153 +1,99 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provider Interface - Unified interface for CLI and API providers
|
|
3
|
-
*
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (!config.
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (config.type
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
throw new Error(`Invalid provider type: ${config.type}. Must be 'cli' or 'api'`);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Freeze capabilities to make them immutable
|
|
104
|
-
const capabilities = Object.freeze([...(config.capabilities || [])]);
|
|
105
|
-
|
|
106
|
-
// Default runner that throws (should be overridden)
|
|
107
|
-
const defaultRunner = async () => {
|
|
108
|
-
throw new Error('Provider runner not implemented');
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
const runner = config.runner || defaultRunner;
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Run a prompt through the provider
|
|
115
|
-
* @param {string} prompt - The prompt to send
|
|
116
|
-
* @param {Object} opts - Run options
|
|
117
|
-
* @param {string} [opts.outputFormat] - Output format ('json' or 'text')
|
|
118
|
-
* @param {string} [opts.sandbox] - Sandbox mode
|
|
119
|
-
* @param {Object} [opts.outputSchema] - JSON schema for output
|
|
120
|
-
* @param {string} [opts.cwd] - Working directory
|
|
121
|
-
* @returns {Promise<Object>} ProviderResult
|
|
122
|
-
*/
|
|
123
|
-
async function run(prompt, opts = {}) {
|
|
124
|
-
const result = await runner(prompt, opts);
|
|
125
|
-
|
|
126
|
-
// Calculate cost if we have token usage and pricing
|
|
127
|
-
if (result.tokenUsage && config.pricing) {
|
|
128
|
-
result.cost = calculateCost(result.tokenUsage, config.pricing);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return createProviderResult({
|
|
132
|
-
raw: result.raw,
|
|
133
|
-
parsed: result.parsed,
|
|
134
|
-
exitCode: result.exitCode,
|
|
135
|
-
tokenUsage: result.tokenUsage || null,
|
|
136
|
-
cost: result.cost || null,
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return {
|
|
141
|
-
name: config.name,
|
|
142
|
-
type: config.type,
|
|
143
|
-
command: config.command,
|
|
144
|
-
baseUrl: config.baseUrl,
|
|
145
|
-
model: config.model,
|
|
146
|
-
headlessArgs: config.headlessArgs,
|
|
147
|
-
pricing: config.pricing,
|
|
148
|
-
detected: config.detected || false,
|
|
149
|
-
devserverOnly: config.devserverOnly,
|
|
150
|
-
capabilities,
|
|
151
|
-
run,
|
|
152
|
-
};
|
|
153
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Provider Interface - Unified interface for CLI and API providers
|
|
3
|
+
* Phase 33, Task 1
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const ProviderType = {
|
|
7
|
+
CLI: 'cli',
|
|
8
|
+
API: 'api',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Validate provider configuration
|
|
13
|
+
*/
|
|
14
|
+
export function validateProviderConfig(config) {
|
|
15
|
+
const errors = [];
|
|
16
|
+
|
|
17
|
+
if (!config.name) {
|
|
18
|
+
errors.push('name is required');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!config.type) {
|
|
22
|
+
errors.push('type is required');
|
|
23
|
+
} else if (config.type !== ProviderType.CLI && config.type !== ProviderType.API) {
|
|
24
|
+
errors.push('invalid type: ' + config.type);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (config.type === ProviderType.CLI && !config.command) {
|
|
28
|
+
errors.push('command is required for CLI providers');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (config.type === ProviderType.API && !config.baseUrl) {
|
|
32
|
+
errors.push('baseUrl is required for API providers');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
valid: errors.length === 0,
|
|
37
|
+
errors,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Create a provider instance
|
|
43
|
+
*/
|
|
44
|
+
export function createProvider(config) {
|
|
45
|
+
const validation = validateProviderConfig(config);
|
|
46
|
+
if (!validation.valid) {
|
|
47
|
+
throw new Error('Invalid provider config: ' + validation.errors.join(', '));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const provider = {
|
|
51
|
+
name: config.name,
|
|
52
|
+
type: config.type,
|
|
53
|
+
capabilities: config.capabilities || [],
|
|
54
|
+
config,
|
|
55
|
+
_execute: null,
|
|
56
|
+
|
|
57
|
+
async run(prompt, options = {}) {
|
|
58
|
+
if (this._execute) {
|
|
59
|
+
return this._execute(prompt, options);
|
|
60
|
+
}
|
|
61
|
+
if (this.type === ProviderType.CLI) {
|
|
62
|
+
return this._runCLI(prompt, options);
|
|
63
|
+
} else {
|
|
64
|
+
return this._runAPI(prompt, options);
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
async _runCLI(prompt, options) {
|
|
69
|
+
return {
|
|
70
|
+
raw: '',
|
|
71
|
+
parsed: null,
|
|
72
|
+
exitCode: 0,
|
|
73
|
+
tokenUsage: { input: 0, output: 0 },
|
|
74
|
+
cost: 0,
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
async _runAPI(prompt, options) {
|
|
79
|
+
return {
|
|
80
|
+
raw: '',
|
|
81
|
+
parsed: null,
|
|
82
|
+
exitCode: 0,
|
|
83
|
+
tokenUsage: { input: 0, output: 0 },
|
|
84
|
+
cost: 0,
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
calculateCost(tokenUsage) {
|
|
89
|
+
const pricing = config.pricing || { inputPer1k: 0, outputPer1k: 0 };
|
|
90
|
+
const inputCost = (tokenUsage.input / 1000) * pricing.inputPer1k;
|
|
91
|
+
const outputCost = (tokenUsage.output / 1000) * pricing.outputPer1k;
|
|
92
|
+
return inputCost + outputCost;
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
return provider;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export default { createProvider, validateProviderConfig, ProviderType };
|