@ottocode/server 0.1.260 → 0.1.261

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 (67) hide show
  1. package/package.json +4 -3
  2. package/src/index.ts +5 -4
  3. package/src/openapi/register.ts +92 -0
  4. package/src/openapi/route.ts +22 -0
  5. package/src/routes/ask.ts +210 -99
  6. package/src/routes/auth.ts +1701 -626
  7. package/src/routes/branch.ts +281 -90
  8. package/src/routes/config/agents.ts +79 -32
  9. package/src/routes/config/cwd.ts +46 -14
  10. package/src/routes/config/debug.ts +159 -30
  11. package/src/routes/config/defaults.ts +182 -64
  12. package/src/routes/config/main.ts +109 -73
  13. package/src/routes/config/models.ts +304 -137
  14. package/src/routes/config/providers.ts +462 -166
  15. package/src/routes/config/utils.ts +2 -2
  16. package/src/routes/doctor.ts +395 -161
  17. package/src/routes/files.ts +650 -260
  18. package/src/routes/git/branch.ts +143 -52
  19. package/src/routes/git/commit.ts +347 -141
  20. package/src/routes/git/diff.ts +239 -116
  21. package/src/routes/git/init.ts +103 -23
  22. package/src/routes/git/pull.ts +167 -65
  23. package/src/routes/git/push.ts +222 -117
  24. package/src/routes/git/remote.ts +401 -100
  25. package/src/routes/git/staging.ts +502 -141
  26. package/src/routes/git/status.ts +171 -78
  27. package/src/routes/mcp.ts +1129 -404
  28. package/src/routes/openapi.ts +27 -4
  29. package/src/routes/ottorouter.ts +1221 -389
  30. package/src/routes/provider-usage.ts +153 -36
  31. package/src/routes/research.ts +817 -370
  32. package/src/routes/root.ts +50 -6
  33. package/src/routes/session-approval.ts +228 -54
  34. package/src/routes/session-files.ts +265 -134
  35. package/src/routes/session-messages.ts +330 -150
  36. package/src/routes/session-stream.ts +83 -2
  37. package/src/routes/sessions.ts +1830 -780
  38. package/src/routes/skills.ts +849 -161
  39. package/src/routes/terminals.ts +469 -103
  40. package/src/routes/tunnel.ts +394 -118
  41. package/src/runtime/ask/service.ts +1 -0
  42. package/src/runtime/message/compaction-limits.ts +3 -3
  43. package/src/runtime/provider/reasoning.ts +2 -1
  44. package/src/runtime/session/db-operations.ts +4 -3
  45. package/src/runtime/utils/token.ts +7 -2
  46. package/src/tools/adapter.ts +21 -0
  47. package/src/openapi/paths/ask.ts +0 -81
  48. package/src/openapi/paths/auth.ts +0 -687
  49. package/src/openapi/paths/branch.ts +0 -102
  50. package/src/openapi/paths/config.ts +0 -485
  51. package/src/openapi/paths/doctor.ts +0 -165
  52. package/src/openapi/paths/files.ts +0 -236
  53. package/src/openapi/paths/git.ts +0 -690
  54. package/src/openapi/paths/mcp.ts +0 -339
  55. package/src/openapi/paths/messages.ts +0 -103
  56. package/src/openapi/paths/ottorouter.ts +0 -594
  57. package/src/openapi/paths/provider-usage.ts +0 -59
  58. package/src/openapi/paths/research.ts +0 -227
  59. package/src/openapi/paths/session-approval.ts +0 -93
  60. package/src/openapi/paths/session-extras.ts +0 -336
  61. package/src/openapi/paths/session-files.ts +0 -91
  62. package/src/openapi/paths/sessions.ts +0 -210
  63. package/src/openapi/paths/skills.ts +0 -377
  64. package/src/openapi/paths/stream.ts +0 -26
  65. package/src/openapi/paths/terminals.ts +0 -226
  66. package/src/openapi/paths/tunnel.ts +0 -163
  67. package/src/openapi/spec.ts +0 -73
@@ -8,201 +8,562 @@ import {
8
8
  gitDeleteSchema,
9
9
  } from './schemas.ts';
10
10
  import { validateAndGetGitRoot } from './utils.ts';
11
+ import { openApiRoute } from '../../openapi/route.ts';
11
12
 
12
13
  const execFileAsync = promisify(execFile);
13
14
 
14
15
  export function registerStagingRoutes(app: Hono) {
15
- app.post('/v1/git/stage', async (c) => {
16
- try {
17
- const body = await c.req.json();
18
- const { files, project } = gitStageSchema.parse(body);
16
+ openApiRoute(
17
+ app,
18
+ {
19
+ method: 'post',
20
+ path: '/v1/git/stage',
21
+ tags: ['git'],
22
+ operationId: 'stageFiles',
23
+ summary: 'Stage files',
24
+ requestBody: {
25
+ required: true,
26
+ content: {
27
+ 'application/json': {
28
+ schema: {
29
+ type: 'object',
30
+ properties: {
31
+ project: {
32
+ type: 'string',
33
+ },
34
+ files: {
35
+ type: 'array',
36
+ items: {
37
+ type: 'string',
38
+ },
39
+ },
40
+ },
41
+ required: ['files'],
42
+ },
43
+ },
44
+ },
45
+ },
46
+ responses: {
47
+ '200': {
48
+ description: 'OK',
49
+ content: {
50
+ 'application/json': {
51
+ schema: {
52
+ type: 'object',
53
+ properties: {
54
+ status: {
55
+ type: 'string',
56
+ enum: ['ok'],
57
+ },
58
+ data: {
59
+ type: 'object',
60
+ properties: {
61
+ staged: {
62
+ type: 'array',
63
+ items: {
64
+ type: 'string',
65
+ },
66
+ },
67
+ failed: {
68
+ type: 'array',
69
+ items: {
70
+ type: 'string',
71
+ },
72
+ },
73
+ },
74
+ required: ['staged', 'failed'],
75
+ },
76
+ },
77
+ required: ['status', 'data'],
78
+ },
79
+ },
80
+ },
81
+ },
82
+ '500': {
83
+ description: 'Error',
84
+ content: {
85
+ 'application/json': {
86
+ schema: {
87
+ type: 'object',
88
+ properties: {
89
+ status: {
90
+ type: 'string',
91
+ enum: ['error'],
92
+ },
93
+ error: {
94
+ type: 'string',
95
+ },
96
+ code: {
97
+ type: 'string',
98
+ },
99
+ },
100
+ required: ['status', 'error'],
101
+ },
102
+ },
103
+ },
104
+ },
105
+ },
106
+ },
107
+ async (c) => {
108
+ try {
109
+ const body = await c.req.json();
110
+ const { files, project } = gitStageSchema.parse(body);
19
111
 
20
- const requestedPath = project || process.cwd();
112
+ const requestedPath = project || process.cwd();
21
113
 
22
- const validation = await validateAndGetGitRoot(requestedPath);
23
- if ('error' in validation) {
24
- return c.json(
25
- { status: 'error', error: validation.error, code: validation.code },
26
- 400,
27
- );
28
- }
114
+ const validation = await validateAndGetGitRoot(requestedPath);
115
+ if ('error' in validation) {
116
+ return c.json(
117
+ { status: 'error', error: validation.error, code: validation.code },
118
+ 400,
119
+ );
120
+ }
29
121
 
30
- const { gitRoot } = validation;
122
+ const { gitRoot } = validation;
31
123
 
32
- if (files.length === 0) {
124
+ if (files.length === 0) {
125
+ return c.json(
126
+ {
127
+ status: 'error',
128
+ error: 'No files specified',
129
+ },
130
+ 400,
131
+ );
132
+ }
133
+
134
+ await execFileAsync('git', ['add', ...files], { cwd: gitRoot });
135
+
136
+ return c.json({
137
+ status: 'ok',
138
+ data: {
139
+ staged: files,
140
+ },
141
+ });
142
+ } catch (error) {
33
143
  return c.json(
34
144
  {
35
145
  status: 'error',
36
- error: 'No files specified',
146
+ error:
147
+ error instanceof Error ? error.message : 'Failed to stage files',
37
148
  },
38
- 400,
149
+ 500,
39
150
  );
40
151
  }
152
+ },
153
+ );
41
154
 
42
- await execFileAsync('git', ['add', ...files], { cwd: gitRoot });
43
-
44
- return c.json({
45
- status: 'ok',
46
- data: {
47
- staged: files,
155
+ openApiRoute(
156
+ app,
157
+ {
158
+ method: 'post',
159
+ path: '/v1/git/unstage',
160
+ tags: ['git'],
161
+ operationId: 'unstageFiles',
162
+ summary: 'Unstage files',
163
+ requestBody: {
164
+ required: true,
165
+ content: {
166
+ 'application/json': {
167
+ schema: {
168
+ type: 'object',
169
+ properties: {
170
+ project: {
171
+ type: 'string',
172
+ },
173
+ files: {
174
+ type: 'array',
175
+ items: {
176
+ type: 'string',
177
+ },
178
+ },
179
+ },
180
+ required: ['files'],
181
+ },
182
+ },
183
+ },
184
+ },
185
+ responses: {
186
+ '200': {
187
+ description: 'OK',
188
+ content: {
189
+ 'application/json': {
190
+ schema: {
191
+ type: 'object',
192
+ properties: {
193
+ status: {
194
+ type: 'string',
195
+ enum: ['ok'],
196
+ },
197
+ data: {
198
+ type: 'object',
199
+ properties: {
200
+ unstaged: {
201
+ type: 'array',
202
+ items: {
203
+ type: 'string',
204
+ },
205
+ },
206
+ failed: {
207
+ type: 'array',
208
+ items: {
209
+ type: 'string',
210
+ },
211
+ },
212
+ },
213
+ required: ['unstaged', 'failed'],
214
+ },
215
+ },
216
+ required: ['status', 'data'],
217
+ },
218
+ },
219
+ },
48
220
  },
49
- });
50
- } catch (error) {
51
- return c.json(
52
- {
53
- status: 'error',
54
- error:
55
- error instanceof Error ? error.message : 'Failed to stage files',
221
+ '500': {
222
+ description: 'Error',
223
+ content: {
224
+ 'application/json': {
225
+ schema: {
226
+ type: 'object',
227
+ properties: {
228
+ status: {
229
+ type: 'string',
230
+ enum: ['error'],
231
+ },
232
+ error: {
233
+ type: 'string',
234
+ },
235
+ code: {
236
+ type: 'string',
237
+ },
238
+ },
239
+ required: ['status', 'error'],
240
+ },
241
+ },
242
+ },
56
243
  },
57
- 500,
58
- );
59
- }
60
- });
244
+ },
245
+ },
246
+ async (c) => {
247
+ try {
248
+ const body = await c.req.json();
249
+ const { files, project } = gitUnstageSchema.parse(body);
61
250
 
62
- app.post('/v1/git/unstage', async (c) => {
63
- try {
64
- const body = await c.req.json();
65
- const { files, project } = gitUnstageSchema.parse(body);
251
+ const requestedPath = project || process.cwd();
66
252
 
67
- const requestedPath = project || process.cwd();
253
+ const validation = await validateAndGetGitRoot(requestedPath);
254
+ if ('error' in validation) {
255
+ return c.json(
256
+ { status: 'error', error: validation.error, code: validation.code },
257
+ 400,
258
+ );
259
+ }
68
260
 
69
- const validation = await validateAndGetGitRoot(requestedPath);
70
- if ('error' in validation) {
71
- return c.json(
72
- { status: 'error', error: validation.error, code: validation.code },
73
- 400,
74
- );
75
- }
261
+ const { gitRoot } = validation;
262
+
263
+ if (files.length === 0) {
264
+ return c.json(
265
+ {
266
+ status: 'error',
267
+ error: 'No files specified',
268
+ },
269
+ 400,
270
+ );
271
+ }
76
272
 
77
- const { gitRoot } = validation;
273
+ await execFileAsync('git', ['reset', 'HEAD', '--', ...files], {
274
+ cwd: gitRoot,
275
+ });
78
276
 
79
- if (files.length === 0) {
277
+ return c.json({
278
+ status: 'ok',
279
+ data: {
280
+ unstaged: files,
281
+ },
282
+ });
283
+ } catch (error) {
80
284
  return c.json(
81
285
  {
82
286
  status: 'error',
83
- error: 'No files specified',
287
+ error:
288
+ error instanceof Error
289
+ ? error.message
290
+ : 'Failed to unstage files',
84
291
  },
85
- 400,
292
+ 500,
86
293
  );
87
294
  }
295
+ },
296
+ );
88
297
 
89
- await execFileAsync('git', ['reset', 'HEAD', '--', ...files], {
90
- cwd: gitRoot,
91
- });
92
-
93
- return c.json({
94
- status: 'ok',
95
- data: {
96
- unstaged: files,
298
+ openApiRoute(
299
+ app,
300
+ {
301
+ method: 'post',
302
+ path: '/v1/git/restore',
303
+ tags: ['git'],
304
+ operationId: 'restoreFiles',
305
+ summary: 'Restore files to HEAD',
306
+ requestBody: {
307
+ required: true,
308
+ content: {
309
+ 'application/json': {
310
+ schema: {
311
+ type: 'object',
312
+ properties: {
313
+ project: {
314
+ type: 'string',
315
+ },
316
+ files: {
317
+ type: 'array',
318
+ items: {
319
+ type: 'string',
320
+ },
321
+ },
322
+ },
323
+ required: ['files'],
324
+ },
325
+ },
326
+ },
327
+ },
328
+ responses: {
329
+ '200': {
330
+ description: 'OK',
331
+ content: {
332
+ 'application/json': {
333
+ schema: {
334
+ type: 'object',
335
+ properties: {
336
+ status: {
337
+ type: 'string',
338
+ enum: ['ok'],
339
+ },
340
+ data: {
341
+ type: 'object',
342
+ properties: {
343
+ restored: {
344
+ type: 'array',
345
+ items: {
346
+ type: 'string',
347
+ },
348
+ },
349
+ },
350
+ required: ['restored'],
351
+ },
352
+ },
353
+ required: ['status', 'data'],
354
+ },
355
+ },
356
+ },
97
357
  },
98
- });
99
- } catch (error) {
100
- return c.json(
101
- {
102
- status: 'error',
103
- error:
104
- error instanceof Error ? error.message : 'Failed to unstage files',
358
+ '500': {
359
+ description: 'Error',
360
+ content: {
361
+ 'application/json': {
362
+ schema: {
363
+ type: 'object',
364
+ properties: {
365
+ status: {
366
+ type: 'string',
367
+ enum: ['error'],
368
+ },
369
+ error: {
370
+ type: 'string',
371
+ },
372
+ code: {
373
+ type: 'string',
374
+ },
375
+ },
376
+ required: ['status', 'error'],
377
+ },
378
+ },
379
+ },
105
380
  },
106
- 500,
107
- );
108
- }
109
- });
381
+ },
382
+ },
383
+ async (c) => {
384
+ try {
385
+ const body = await c.req.json();
386
+ const { files, project } = gitRestoreSchema.parse(body);
110
387
 
111
- app.post('/v1/git/restore', async (c) => {
112
- try {
113
- const body = await c.req.json();
114
- const { files, project } = gitRestoreSchema.parse(body);
388
+ const requestedPath = project || process.cwd();
115
389
 
116
- const requestedPath = project || process.cwd();
390
+ const validation = await validateAndGetGitRoot(requestedPath);
391
+ if ('error' in validation) {
392
+ return c.json(
393
+ { status: 'error', error: validation.error, code: validation.code },
394
+ 400,
395
+ );
396
+ }
117
397
 
118
- const validation = await validateAndGetGitRoot(requestedPath);
119
- if ('error' in validation) {
120
- return c.json(
121
- { status: 'error', error: validation.error, code: validation.code },
122
- 400,
123
- );
124
- }
398
+ const { gitRoot } = validation;
399
+
400
+ if (files.length === 0) {
401
+ return c.json(
402
+ {
403
+ status: 'error',
404
+ error: 'No files specified',
405
+ },
406
+ 400,
407
+ );
408
+ }
125
409
 
126
- const { gitRoot } = validation;
410
+ await execFileAsync('git', ['restore', '--', ...files], {
411
+ cwd: gitRoot,
412
+ });
127
413
 
128
- if (files.length === 0) {
414
+ return c.json({
415
+ status: 'ok',
416
+ data: {
417
+ restored: files,
418
+ },
419
+ });
420
+ } catch (error) {
129
421
  return c.json(
130
422
  {
131
423
  status: 'error',
132
- error: 'No files specified',
424
+ error:
425
+ error instanceof Error
426
+ ? error.message
427
+ : 'Failed to restore files',
133
428
  },
134
- 400,
429
+ 500,
135
430
  );
136
431
  }
432
+ },
433
+ );
137
434
 
138
- await execFileAsync('git', ['restore', '--', ...files], {
139
- cwd: gitRoot,
140
- });
141
-
142
- return c.json({
143
- status: 'ok',
144
- data: {
145
- restored: files,
435
+ openApiRoute(
436
+ app,
437
+ {
438
+ method: 'post',
439
+ path: '/v1/git/delete',
440
+ tags: ['git'],
441
+ operationId: 'deleteFiles',
442
+ summary: 'Delete untracked files',
443
+ requestBody: {
444
+ required: true,
445
+ content: {
446
+ 'application/json': {
447
+ schema: {
448
+ type: 'object',
449
+ properties: {
450
+ project: {
451
+ type: 'string',
452
+ },
453
+ files: {
454
+ type: 'array',
455
+ items: {
456
+ type: 'string',
457
+ },
458
+ },
459
+ },
460
+ required: ['files'],
461
+ },
462
+ },
146
463
  },
147
- });
148
- } catch (error) {
149
- return c.json(
150
- {
151
- status: 'error',
152
- error:
153
- error instanceof Error ? error.message : 'Failed to restore files',
464
+ },
465
+ responses: {
466
+ '200': {
467
+ description: 'OK',
468
+ content: {
469
+ 'application/json': {
470
+ schema: {
471
+ type: 'object',
472
+ properties: {
473
+ status: {
474
+ type: 'string',
475
+ enum: ['ok'],
476
+ },
477
+ data: {
478
+ type: 'object',
479
+ properties: {
480
+ deleted: {
481
+ type: 'array',
482
+ items: {
483
+ type: 'string',
484
+ },
485
+ },
486
+ },
487
+ required: ['deleted'],
488
+ },
489
+ },
490
+ required: ['status', 'data'],
491
+ },
492
+ },
493
+ },
154
494
  },
155
- 500,
156
- );
157
- }
158
- });
495
+ '500': {
496
+ description: 'Error',
497
+ content: {
498
+ 'application/json': {
499
+ schema: {
500
+ type: 'object',
501
+ properties: {
502
+ status: {
503
+ type: 'string',
504
+ enum: ['error'],
505
+ },
506
+ error: {
507
+ type: 'string',
508
+ },
509
+ code: {
510
+ type: 'string',
511
+ },
512
+ },
513
+ required: ['status', 'error'],
514
+ },
515
+ },
516
+ },
517
+ },
518
+ },
519
+ },
520
+ async (c) => {
521
+ try {
522
+ const body = await c.req.json();
523
+ const { files, project } = gitDeleteSchema.parse(body);
159
524
 
160
- app.post('/v1/git/delete', async (c) => {
161
- try {
162
- const body = await c.req.json();
163
- const { files, project } = gitDeleteSchema.parse(body);
525
+ const requestedPath = project || process.cwd();
164
526
 
165
- const requestedPath = project || process.cwd();
527
+ const validation = await validateAndGetGitRoot(requestedPath);
528
+ if ('error' in validation) {
529
+ return c.json(
530
+ { status: 'error', error: validation.error, code: validation.code },
531
+ 400,
532
+ );
533
+ }
166
534
 
167
- const validation = await validateAndGetGitRoot(requestedPath);
168
- if ('error' in validation) {
169
- return c.json(
170
- { status: 'error', error: validation.error, code: validation.code },
171
- 400,
172
- );
173
- }
535
+ const { gitRoot } = validation;
536
+
537
+ if (files.length === 0) {
538
+ return c.json(
539
+ {
540
+ status: 'error',
541
+ error: 'No files specified',
542
+ },
543
+ 400,
544
+ );
545
+ }
174
546
 
175
- const { gitRoot } = validation;
547
+ await execFileAsync('git', ['clean', '-f', '--', ...files], {
548
+ cwd: gitRoot,
549
+ });
176
550
 
177
- if (files.length === 0) {
551
+ return c.json({
552
+ status: 'ok',
553
+ data: {
554
+ deleted: files,
555
+ },
556
+ });
557
+ } catch (error) {
178
558
  return c.json(
179
559
  {
180
560
  status: 'error',
181
- error: 'No files specified',
561
+ error:
562
+ error instanceof Error ? error.message : 'Failed to delete files',
182
563
  },
183
- 400,
564
+ 500,
184
565
  );
185
566
  }
186
-
187
- await execFileAsync('git', ['clean', '-f', '--', ...files], {
188
- cwd: gitRoot,
189
- });
190
-
191
- return c.json({
192
- status: 'ok',
193
- data: {
194
- deleted: files,
195
- },
196
- });
197
- } catch (error) {
198
- return c.json(
199
- {
200
- status: 'error',
201
- error:
202
- error instanceof Error ? error.message : 'Failed to delete files',
203
- },
204
- 500,
205
- );
206
- }
207
- });
567
+ },
568
+ );
208
569
  }