@ottocode/server 0.1.212 → 0.1.215

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ottocode/server",
3
- "version": "0.1.212",
3
+ "version": "0.1.215",
4
4
  "description": "HTTP API server for ottocode",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -49,14 +49,14 @@
49
49
  "typecheck": "tsc --noEmit"
50
50
  },
51
51
  "dependencies": {
52
- "@ottocode/sdk": "0.1.212",
53
- "@ottocode/database": "0.1.212",
52
+ "@ottocode/sdk": "0.1.215",
53
+ "@ottocode/database": "0.1.215",
54
54
  "drizzle-orm": "^0.44.5",
55
55
  "hono": "^4.9.9",
56
- "zod": "^4.1.8"
56
+ "zod": "^4.3.6"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@types/bun": "latest",
60
- "typescript": "^5"
60
+ "typescript": "~5.9.3"
61
61
  }
62
62
  }
package/src/index.ts CHANGED
@@ -22,6 +22,8 @@ import { registerAuthRoutes } from './routes/auth.ts';
22
22
  import { registerTunnelRoutes } from './routes/tunnel.ts';
23
23
  import { registerMCPRoutes } from './routes/mcp.ts';
24
24
  import { registerProviderUsageRoutes } from './routes/provider-usage.ts';
25
+ import { registerDoctorRoutes } from './routes/doctor.ts';
26
+ import { registerSkillsRoutes } from './routes/skills.ts';
25
27
  import type { AgentConfigEntry } from './runtime/agent/registry.ts';
26
28
 
27
29
  const globalTerminalManager = new TerminalManager();
@@ -80,6 +82,8 @@ function initApp() {
80
82
  registerTunnelRoutes(app);
81
83
  registerMCPRoutes(app);
82
84
  registerProviderUsageRoutes(app);
85
+ registerDoctorRoutes(app);
86
+ registerSkillsRoutes(app);
83
87
 
84
88
  return app;
85
89
  }
@@ -0,0 +1,497 @@
1
+ import { errorResponse } from '../helpers';
2
+
3
+ export const authPaths = {
4
+ '/v1/auth/status': {
5
+ get: {
6
+ tags: ['auth'],
7
+ operationId: 'getAuthStatus',
8
+ summary: 'Get auth status for all providers',
9
+ responses: {
10
+ 200: {
11
+ description: 'OK',
12
+ content: {
13
+ 'application/json': {
14
+ schema: {
15
+ type: 'object',
16
+ properties: {
17
+ onboardingComplete: { type: 'boolean' },
18
+ setu: {
19
+ type: 'object',
20
+ properties: {
21
+ configured: { type: 'boolean' },
22
+ publicKey: { type: 'string' },
23
+ },
24
+ required: ['configured'],
25
+ },
26
+ providers: {
27
+ type: 'object',
28
+ additionalProperties: {
29
+ type: 'object',
30
+ properties: {
31
+ configured: { type: 'boolean' },
32
+ type: {
33
+ type: 'string',
34
+ enum: ['api', 'oauth', 'wallet'],
35
+ },
36
+ label: { type: 'string' },
37
+ supportsOAuth: { type: 'boolean' },
38
+ modelCount: { type: 'integer' },
39
+ costRange: {
40
+ type: 'object',
41
+ nullable: true,
42
+ properties: {
43
+ min: { type: 'number' },
44
+ max: { type: 'number' },
45
+ },
46
+ required: ['min', 'max'],
47
+ },
48
+ },
49
+ required: [
50
+ 'configured',
51
+ 'label',
52
+ 'supportsOAuth',
53
+ 'modelCount',
54
+ ],
55
+ },
56
+ },
57
+ defaults: {
58
+ type: 'object',
59
+ properties: {
60
+ agent: { type: 'string' },
61
+ provider: { type: 'string' },
62
+ model: { type: 'string' },
63
+ },
64
+ },
65
+ },
66
+ required: ['onboardingComplete', 'setu', 'providers'],
67
+ },
68
+ },
69
+ },
70
+ },
71
+ },
72
+ },
73
+ },
74
+ '/v1/auth/setu/setup': {
75
+ post: {
76
+ tags: ['auth'],
77
+ operationId: 'setupSetuWallet',
78
+ summary: 'Setup or ensure Setu wallet',
79
+ responses: {
80
+ 200: {
81
+ description: 'OK',
82
+ content: {
83
+ 'application/json': {
84
+ schema: {
85
+ type: 'object',
86
+ properties: {
87
+ success: { type: 'boolean' },
88
+ publicKey: { type: 'string' },
89
+ isNew: { type: 'boolean' },
90
+ },
91
+ required: ['success', 'publicKey', 'isNew'],
92
+ },
93
+ },
94
+ },
95
+ },
96
+ },
97
+ },
98
+ },
99
+ '/v1/auth/setu/import': {
100
+ post: {
101
+ tags: ['auth'],
102
+ operationId: 'importSetuWallet',
103
+ summary: 'Import Setu wallet from private key',
104
+ requestBody: {
105
+ required: true,
106
+ content: {
107
+ 'application/json': {
108
+ schema: {
109
+ type: 'object',
110
+ properties: {
111
+ privateKey: { type: 'string' },
112
+ },
113
+ required: ['privateKey'],
114
+ },
115
+ },
116
+ },
117
+ },
118
+ responses: {
119
+ 200: {
120
+ description: 'OK',
121
+ content: {
122
+ 'application/json': {
123
+ schema: {
124
+ type: 'object',
125
+ properties: {
126
+ success: { type: 'boolean' },
127
+ publicKey: { type: 'string' },
128
+ },
129
+ required: ['success', 'publicKey'],
130
+ },
131
+ },
132
+ },
133
+ },
134
+ 400: errorResponse(),
135
+ },
136
+ },
137
+ },
138
+ '/v1/auth/setu/export': {
139
+ get: {
140
+ tags: ['auth'],
141
+ operationId: 'exportSetuWallet',
142
+ summary: 'Export Setu wallet private key',
143
+ responses: {
144
+ 200: {
145
+ description: 'OK',
146
+ content: {
147
+ 'application/json': {
148
+ schema: {
149
+ type: 'object',
150
+ properties: {
151
+ success: { type: 'boolean' },
152
+ publicKey: { type: 'string' },
153
+ privateKey: { type: 'string' },
154
+ },
155
+ required: ['success', 'publicKey', 'privateKey'],
156
+ },
157
+ },
158
+ },
159
+ },
160
+ 404: errorResponse(),
161
+ },
162
+ },
163
+ },
164
+ '/v1/auth/{provider}': {
165
+ post: {
166
+ tags: ['auth'],
167
+ operationId: 'addProviderApiKey',
168
+ summary: 'Add API key for a provider',
169
+ parameters: [
170
+ {
171
+ in: 'path',
172
+ name: 'provider',
173
+ required: true,
174
+ schema: { type: 'string' },
175
+ },
176
+ ],
177
+ requestBody: {
178
+ required: true,
179
+ content: {
180
+ 'application/json': {
181
+ schema: {
182
+ type: 'object',
183
+ properties: {
184
+ apiKey: { type: 'string' },
185
+ },
186
+ required: ['apiKey'],
187
+ },
188
+ },
189
+ },
190
+ },
191
+ responses: {
192
+ 200: {
193
+ description: 'OK',
194
+ content: {
195
+ 'application/json': {
196
+ schema: {
197
+ type: 'object',
198
+ properties: {
199
+ success: { type: 'boolean' },
200
+ provider: { type: 'string' },
201
+ },
202
+ required: ['success', 'provider'],
203
+ },
204
+ },
205
+ },
206
+ },
207
+ 400: errorResponse(),
208
+ },
209
+ },
210
+ delete: {
211
+ tags: ['auth'],
212
+ operationId: 'removeProvider',
213
+ summary: 'Remove auth for a provider',
214
+ parameters: [
215
+ {
216
+ in: 'path',
217
+ name: 'provider',
218
+ required: true,
219
+ schema: { type: 'string' },
220
+ },
221
+ ],
222
+ responses: {
223
+ 200: {
224
+ description: 'OK',
225
+ content: {
226
+ 'application/json': {
227
+ schema: {
228
+ type: 'object',
229
+ properties: {
230
+ success: { type: 'boolean' },
231
+ provider: { type: 'string' },
232
+ },
233
+ required: ['success', 'provider'],
234
+ },
235
+ },
236
+ },
237
+ },
238
+ 400: errorResponse(),
239
+ },
240
+ },
241
+ },
242
+ '/v1/auth/{provider}/oauth/url': {
243
+ post: {
244
+ tags: ['auth'],
245
+ operationId: 'getOAuthUrl',
246
+ summary: 'Get OAuth authorization URL',
247
+ parameters: [
248
+ {
249
+ in: 'path',
250
+ name: 'provider',
251
+ required: true,
252
+ schema: { type: 'string' },
253
+ },
254
+ ],
255
+ requestBody: {
256
+ required: false,
257
+ content: {
258
+ 'application/json': {
259
+ schema: {
260
+ type: 'object',
261
+ properties: {
262
+ mode: {
263
+ type: 'string',
264
+ enum: ['max', 'console'],
265
+ default: 'max',
266
+ },
267
+ },
268
+ },
269
+ },
270
+ },
271
+ },
272
+ responses: {
273
+ 200: {
274
+ description: 'OK',
275
+ content: {
276
+ 'application/json': {
277
+ schema: {
278
+ type: 'object',
279
+ properties: {
280
+ url: { type: 'string' },
281
+ sessionId: { type: 'string' },
282
+ provider: { type: 'string' },
283
+ },
284
+ required: ['url', 'sessionId', 'provider'],
285
+ },
286
+ },
287
+ },
288
+ },
289
+ 400: errorResponse(),
290
+ },
291
+ },
292
+ },
293
+ '/v1/auth/{provider}/oauth/exchange': {
294
+ post: {
295
+ tags: ['auth'],
296
+ operationId: 'exchangeOAuthCode',
297
+ summary: 'Exchange OAuth code for tokens',
298
+ parameters: [
299
+ {
300
+ in: 'path',
301
+ name: 'provider',
302
+ required: true,
303
+ schema: { type: 'string' },
304
+ },
305
+ ],
306
+ requestBody: {
307
+ required: true,
308
+ content: {
309
+ 'application/json': {
310
+ schema: {
311
+ type: 'object',
312
+ properties: {
313
+ code: { type: 'string' },
314
+ sessionId: { type: 'string' },
315
+ },
316
+ required: ['code', 'sessionId'],
317
+ },
318
+ },
319
+ },
320
+ },
321
+ responses: {
322
+ 200: {
323
+ description: 'OK',
324
+ content: {
325
+ 'application/json': {
326
+ schema: {
327
+ type: 'object',
328
+ properties: {
329
+ success: { type: 'boolean' },
330
+ provider: { type: 'string' },
331
+ },
332
+ required: ['success', 'provider'],
333
+ },
334
+ },
335
+ },
336
+ },
337
+ 400: errorResponse(),
338
+ },
339
+ },
340
+ },
341
+ '/v1/auth/{provider}/oauth/start': {
342
+ get: {
343
+ tags: ['auth'],
344
+ operationId: 'startOAuth',
345
+ summary: 'Start OAuth flow with redirect',
346
+ parameters: [
347
+ {
348
+ in: 'path',
349
+ name: 'provider',
350
+ required: true,
351
+ schema: { type: 'string' },
352
+ },
353
+ {
354
+ in: 'query',
355
+ name: 'mode',
356
+ required: false,
357
+ schema: {
358
+ type: 'string',
359
+ enum: ['max', 'console'],
360
+ default: 'max',
361
+ },
362
+ },
363
+ ],
364
+ responses: {
365
+ 302: { description: 'Redirect to OAuth provider' },
366
+ 400: errorResponse(),
367
+ },
368
+ },
369
+ },
370
+ '/v1/auth/{provider}/oauth/callback': {
371
+ get: {
372
+ tags: ['auth'],
373
+ operationId: 'oauthCallback',
374
+ summary: 'OAuth callback handler',
375
+ parameters: [
376
+ {
377
+ in: 'path',
378
+ name: 'provider',
379
+ required: true,
380
+ schema: { type: 'string' },
381
+ },
382
+ {
383
+ in: 'query',
384
+ name: 'code',
385
+ required: false,
386
+ schema: { type: 'string' },
387
+ },
388
+ {
389
+ in: 'query',
390
+ name: 'fragment',
391
+ required: false,
392
+ schema: { type: 'string' },
393
+ },
394
+ ],
395
+ responses: {
396
+ 200: {
397
+ description: 'HTML response',
398
+ content: { 'text/html': { schema: { type: 'string' } } },
399
+ },
400
+ },
401
+ },
402
+ },
403
+ '/v1/auth/copilot/device/start': {
404
+ post: {
405
+ tags: ['auth'],
406
+ operationId: 'startCopilotDeviceFlow',
407
+ summary: 'Start Copilot device flow authentication',
408
+ responses: {
409
+ 200: {
410
+ description: 'OK',
411
+ content: {
412
+ 'application/json': {
413
+ schema: {
414
+ type: 'object',
415
+ properties: {
416
+ sessionId: { type: 'string' },
417
+ userCode: { type: 'string' },
418
+ verificationUri: { type: 'string' },
419
+ interval: { type: 'integer' },
420
+ },
421
+ required: [
422
+ 'sessionId',
423
+ 'userCode',
424
+ 'verificationUri',
425
+ 'interval',
426
+ ],
427
+ },
428
+ },
429
+ },
430
+ },
431
+ },
432
+ },
433
+ },
434
+ '/v1/auth/copilot/device/poll': {
435
+ post: {
436
+ tags: ['auth'],
437
+ operationId: 'pollCopilotDeviceFlow',
438
+ summary: 'Poll Copilot device flow for completion',
439
+ requestBody: {
440
+ required: true,
441
+ content: {
442
+ 'application/json': {
443
+ schema: {
444
+ type: 'object',
445
+ properties: {
446
+ sessionId: { type: 'string' },
447
+ },
448
+ required: ['sessionId'],
449
+ },
450
+ },
451
+ },
452
+ },
453
+ responses: {
454
+ 200: {
455
+ description: 'OK',
456
+ content: {
457
+ 'application/json': {
458
+ schema: {
459
+ type: 'object',
460
+ properties: {
461
+ status: {
462
+ type: 'string',
463
+ enum: ['complete', 'pending', 'error'],
464
+ },
465
+ error: { type: 'string' },
466
+ },
467
+ required: ['status'],
468
+ },
469
+ },
470
+ },
471
+ },
472
+ 400: errorResponse(),
473
+ },
474
+ },
475
+ },
476
+ '/v1/auth/onboarding/complete': {
477
+ post: {
478
+ tags: ['auth'],
479
+ operationId: 'completeOnboarding',
480
+ summary: 'Mark onboarding as complete',
481
+ responses: {
482
+ 200: {
483
+ description: 'OK',
484
+ content: {
485
+ 'application/json': {
486
+ schema: {
487
+ type: 'object',
488
+ properties: { success: { type: 'boolean' } },
489
+ required: ['success'],
490
+ },
491
+ },
492
+ },
493
+ },
494
+ },
495
+ },
496
+ },
497
+ } as const;
@@ -0,0 +1,102 @@
1
+ import { errorResponse, projectQueryParam } from '../helpers';
2
+
3
+ const sessionIdParam = {
4
+ in: 'path',
5
+ name: 'sessionId',
6
+ required: true,
7
+ schema: { type: 'string' },
8
+ } as const;
9
+
10
+ export const branchPaths = {
11
+ '/v1/sessions/{sessionId}/branch': {
12
+ post: {
13
+ tags: ['sessions'],
14
+ operationId: 'createBranch',
15
+ summary: 'Create a branch from a session message',
16
+ parameters: [sessionIdParam, projectQueryParam()],
17
+ requestBody: {
18
+ required: true,
19
+ content: {
20
+ 'application/json': {
21
+ schema: {
22
+ type: 'object',
23
+ properties: {
24
+ fromMessageId: { type: 'string' },
25
+ provider: { type: 'string' },
26
+ model: { type: 'string' },
27
+ agent: { type: 'string' },
28
+ title: { type: 'string' },
29
+ },
30
+ required: ['fromMessageId'],
31
+ },
32
+ },
33
+ },
34
+ },
35
+ responses: {
36
+ 201: {
37
+ description: 'Created',
38
+ content: {
39
+ 'application/json': {
40
+ schema: { $ref: '#/components/schemas/Session' },
41
+ },
42
+ },
43
+ },
44
+ 400: errorResponse(),
45
+ },
46
+ },
47
+ },
48
+ '/v1/sessions/{sessionId}/branches': {
49
+ get: {
50
+ tags: ['sessions'],
51
+ operationId: 'listBranches',
52
+ summary: 'List branches of a session',
53
+ parameters: [sessionIdParam, projectQueryParam()],
54
+ responses: {
55
+ 200: {
56
+ description: 'OK',
57
+ content: {
58
+ 'application/json': {
59
+ schema: {
60
+ type: 'object',
61
+ properties: {
62
+ branches: {
63
+ type: 'array',
64
+ items: { $ref: '#/components/schemas/Session' },
65
+ },
66
+ },
67
+ required: ['branches'],
68
+ },
69
+ },
70
+ },
71
+ },
72
+ },
73
+ },
74
+ },
75
+ '/v1/sessions/{sessionId}/parent': {
76
+ get: {
77
+ tags: ['sessions'],
78
+ operationId: 'getParentSession',
79
+ summary: 'Get parent session of a branch',
80
+ parameters: [sessionIdParam, projectQueryParam()],
81
+ responses: {
82
+ 200: {
83
+ description: 'OK',
84
+ content: {
85
+ 'application/json': {
86
+ schema: {
87
+ type: 'object',
88
+ properties: {
89
+ parent: {
90
+ nullable: true,
91
+ allOf: [{ $ref: '#/components/schemas/Session' }],
92
+ },
93
+ },
94
+ required: ['parent'],
95
+ },
96
+ },
97
+ },
98
+ },
99
+ },
100
+ },
101
+ },
102
+ } as const;
@@ -215,4 +215,47 @@ export const configPaths = {
215
215
  },
216
216
  },
217
217
  },
218
+ '/v1/config/models': {
219
+ get: {
220
+ tags: ['config'],
221
+ operationId: 'getAllModels',
222
+ summary: 'Get all models across authorized providers',
223
+ parameters: [projectQueryParam()],
224
+ responses: {
225
+ 200: {
226
+ description: 'OK',
227
+ content: {
228
+ 'application/json': {
229
+ schema: {
230
+ type: 'object',
231
+ additionalProperties: {
232
+ type: 'object',
233
+ properties: {
234
+ label: { type: 'string' },
235
+ authType: { type: 'string' },
236
+ models: {
237
+ type: 'array',
238
+ items: {
239
+ type: 'object',
240
+ properties: {
241
+ id: { type: 'string' },
242
+ label: { type: 'string' },
243
+ toolCall: { type: 'boolean' },
244
+ reasoningText: { type: 'boolean' },
245
+ vision: { type: 'boolean' },
246
+ attachment: { type: 'boolean' },
247
+ },
248
+ required: ['id', 'label'],
249
+ },
250
+ },
251
+ },
252
+ required: ['label', 'models'],
253
+ },
254
+ },
255
+ },
256
+ },
257
+ },
258
+ },
259
+ },
260
+ },
218
261
  } as const;