@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
@@ -3,119 +3,420 @@ import { execFile } from 'node:child_process';
3
3
  import { promisify } from 'node:util';
4
4
  import { gitRemoteAddSchema, gitRemoteRemoveSchema } from './schemas.ts';
5
5
  import { validateAndGetGitRoot } from './utils.ts';
6
+ import { openApiRoute } from '../../openapi/route.ts';
6
7
 
7
8
  const execFileAsync = promisify(execFile);
8
9
 
9
10
  export function registerRemoteRoutes(app: Hono) {
10
- app.get('/v1/git/remotes', async (c) => {
11
- try {
12
- const project = c.req.query('project');
13
- const requestedPath = project || process.cwd();
11
+ openApiRoute(
12
+ app,
13
+ {
14
+ method: 'get',
15
+ path: '/v1/git/remotes',
16
+ tags: ['git'],
17
+ operationId: 'getGitRemotes',
18
+ summary: 'List git remotes',
19
+ parameters: [
20
+ {
21
+ in: 'query',
22
+ name: 'project',
23
+ required: false,
24
+ schema: {
25
+ type: 'string',
26
+ },
27
+ description:
28
+ 'Project root override (defaults to current working directory).',
29
+ },
30
+ ],
31
+ responses: {
32
+ '200': {
33
+ description: 'OK',
34
+ content: {
35
+ 'application/json': {
36
+ schema: {
37
+ type: 'object',
38
+ properties: {
39
+ status: {
40
+ type: 'string',
41
+ enum: ['ok'],
42
+ },
43
+ data: {
44
+ type: 'object',
45
+ properties: {
46
+ remotes: {
47
+ type: 'array',
48
+ items: {
49
+ type: 'object',
50
+ properties: {
51
+ name: {
52
+ type: 'string',
53
+ },
54
+ url: {
55
+ type: 'string',
56
+ },
57
+ type: {
58
+ type: 'string',
59
+ },
60
+ },
61
+ required: ['name', 'url', 'type'],
62
+ },
63
+ },
64
+ },
65
+ required: ['remotes'],
66
+ },
67
+ },
68
+ required: ['status', 'data'],
69
+ },
70
+ },
71
+ },
72
+ },
73
+ '400': {
74
+ description: 'Error',
75
+ content: {
76
+ 'application/json': {
77
+ schema: {
78
+ type: 'object',
79
+ properties: {
80
+ status: {
81
+ type: 'string',
82
+ enum: ['error'],
83
+ },
84
+ error: {
85
+ type: 'string',
86
+ },
87
+ code: {
88
+ type: 'string',
89
+ },
90
+ },
91
+ required: ['status', 'error'],
92
+ },
93
+ },
94
+ },
95
+ },
96
+ '500': {
97
+ description: 'Error',
98
+ content: {
99
+ 'application/json': {
100
+ schema: {
101
+ type: 'object',
102
+ properties: {
103
+ status: {
104
+ type: 'string',
105
+ enum: ['error'],
106
+ },
107
+ error: {
108
+ type: 'string',
109
+ },
110
+ code: {
111
+ type: 'string',
112
+ },
113
+ },
114
+ required: ['status', 'error'],
115
+ },
116
+ },
117
+ },
118
+ },
119
+ },
120
+ },
121
+ async (c) => {
122
+ try {
123
+ const project = c.req.query('project');
124
+ const requestedPath = project || process.cwd();
14
125
 
15
- const validation = await validateAndGetGitRoot(requestedPath);
16
- if ('error' in validation) {
17
- return c.json(
18
- { status: 'error', error: validation.error, code: validation.code },
19
- 400,
20
- );
21
- }
126
+ const validation = await validateAndGetGitRoot(requestedPath);
127
+ if ('error' in validation) {
128
+ return c.json(
129
+ { status: 'error', error: validation.error, code: validation.code },
130
+ 400,
131
+ );
132
+ }
22
133
 
23
- const { gitRoot } = validation;
24
-
25
- const { stdout } = await execFileAsync('git', ['remote', '-v'], {
26
- cwd: gitRoot,
27
- });
28
-
29
- const remotes: { name: string; url: string; type: string }[] = [];
30
- const seen = new Set<string>();
31
- for (const line of stdout.trim().split('\n').filter(Boolean)) {
32
- const match = line.match(/^(\S+)\s+(\S+)\s+\((\w+)\)$/);
33
- if (match) {
34
- const key = `${match[1]}:${match[3]}`;
35
- if (!seen.has(key)) {
36
- seen.add(key);
37
- remotes.push({
38
- name: match[1],
39
- url: match[2],
40
- type: match[3],
41
- });
134
+ const { gitRoot } = validation;
135
+
136
+ const { stdout } = await execFileAsync('git', ['remote', '-v'], {
137
+ cwd: gitRoot,
138
+ });
139
+
140
+ const remotes: { name: string; url: string; type: string }[] = [];
141
+ const seen = new Set<string>();
142
+ for (const line of stdout.trim().split('\n').filter(Boolean)) {
143
+ const match = line.match(/^(\S+)\s+(\S+)\s+\((\w+)\)$/);
144
+ if (match) {
145
+ const key = `${match[1]}:${match[3]}`;
146
+ if (!seen.has(key)) {
147
+ seen.add(key);
148
+ remotes.push({
149
+ name: match[1],
150
+ url: match[2],
151
+ type: match[3],
152
+ });
153
+ }
42
154
  }
43
155
  }
44
- }
45
156
 
46
- return c.json({ status: 'ok', data: { remotes } });
47
- } catch (error) {
48
- return c.json(
49
- {
50
- status: 'error',
51
- error:
52
- error instanceof Error ? error.message : 'Failed to list remotes',
53
- },
54
- 500,
55
- );
56
- }
57
- });
58
-
59
- app.post('/v1/git/remotes', async (c) => {
60
- try {
61
- const body = await c.req.json().catch(() => ({}));
62
- const { project, name, url } = gitRemoteAddSchema.parse(body);
63
- const requestedPath = project || process.cwd();
64
-
65
- const validation = await validateAndGetGitRoot(requestedPath);
66
- if ('error' in validation) {
157
+ return c.json({ status: 'ok', data: { remotes } });
158
+ } catch (error) {
67
159
  return c.json(
68
- { status: 'error', error: validation.error, code: validation.code },
69
- 400,
160
+ {
161
+ status: 'error',
162
+ error:
163
+ error instanceof Error ? error.message : 'Failed to list remotes',
164
+ },
165
+ 500,
70
166
  );
71
167
  }
168
+ },
169
+ );
72
170
 
73
- const { gitRoot } = validation;
74
-
75
- await execFileAsync('git', ['remote', 'add', name, url], {
76
- cwd: gitRoot,
77
- });
78
-
79
- return c.json({
80
- status: 'ok',
81
- data: { name, url },
82
- });
83
- } catch (error) {
84
- const message =
85
- error instanceof Error ? error.message : 'Failed to add remote';
86
- const status = message.includes('already exists') ? 400 : 500;
87
- return c.json({ status: 'error', error: message }, status);
88
- }
89
- });
90
-
91
- app.delete('/v1/git/remotes', async (c) => {
92
- try {
93
- const body = await c.req.json().catch(() => ({}));
94
- const { project, name } = gitRemoteRemoveSchema.parse(body);
95
- const requestedPath = project || process.cwd();
96
-
97
- const validation = await validateAndGetGitRoot(requestedPath);
98
- if ('error' in validation) {
99
- return c.json(
100
- { status: 'error', error: validation.error, code: validation.code },
101
- 400,
102
- );
171
+ openApiRoute(
172
+ app,
173
+ {
174
+ method: 'post',
175
+ path: '/v1/git/remotes',
176
+ tags: ['git'],
177
+ operationId: 'addGitRemote',
178
+ summary: 'Add a git remote',
179
+ requestBody: {
180
+ required: true,
181
+ content: {
182
+ 'application/json': {
183
+ schema: {
184
+ type: 'object',
185
+ properties: {
186
+ project: {
187
+ type: 'string',
188
+ },
189
+ name: {
190
+ type: 'string',
191
+ },
192
+ url: {
193
+ type: 'string',
194
+ },
195
+ },
196
+ required: ['name', 'url'],
197
+ },
198
+ },
199
+ },
200
+ },
201
+ responses: {
202
+ '200': {
203
+ description: 'OK',
204
+ content: {
205
+ 'application/json': {
206
+ schema: {
207
+ type: 'object',
208
+ properties: {
209
+ status: {
210
+ type: 'string',
211
+ enum: ['ok'],
212
+ },
213
+ data: {
214
+ type: 'object',
215
+ properties: {
216
+ name: {
217
+ type: 'string',
218
+ },
219
+ url: {
220
+ type: 'string',
221
+ },
222
+ },
223
+ required: ['name', 'url'],
224
+ },
225
+ },
226
+ required: ['status', 'data'],
227
+ },
228
+ },
229
+ },
230
+ },
231
+ '400': {
232
+ description: 'Error',
233
+ content: {
234
+ 'application/json': {
235
+ schema: {
236
+ type: 'object',
237
+ properties: {
238
+ status: {
239
+ type: 'string',
240
+ enum: ['error'],
241
+ },
242
+ error: {
243
+ type: 'string',
244
+ },
245
+ code: {
246
+ type: 'string',
247
+ },
248
+ },
249
+ required: ['status', 'error'],
250
+ },
251
+ },
252
+ },
253
+ },
254
+ '500': {
255
+ description: 'Error',
256
+ content: {
257
+ 'application/json': {
258
+ schema: {
259
+ type: 'object',
260
+ properties: {
261
+ status: {
262
+ type: 'string',
263
+ enum: ['error'],
264
+ },
265
+ error: {
266
+ type: 'string',
267
+ },
268
+ code: {
269
+ type: 'string',
270
+ },
271
+ },
272
+ required: ['status', 'error'],
273
+ },
274
+ },
275
+ },
276
+ },
277
+ },
278
+ },
279
+ async (c) => {
280
+ try {
281
+ const body = await c.req.json().catch(() => ({}));
282
+ const { project, name, url } = gitRemoteAddSchema.parse(body);
283
+ const requestedPath = project || process.cwd();
284
+
285
+ const validation = await validateAndGetGitRoot(requestedPath);
286
+ if ('error' in validation) {
287
+ return c.json(
288
+ { status: 'error', error: validation.error, code: validation.code },
289
+ 400,
290
+ );
291
+ }
292
+
293
+ const { gitRoot } = validation;
294
+
295
+ await execFileAsync('git', ['remote', 'add', name, url], {
296
+ cwd: gitRoot,
297
+ });
298
+
299
+ return c.json({
300
+ status: 'ok',
301
+ data: { name, url },
302
+ });
303
+ } catch (error) {
304
+ const message =
305
+ error instanceof Error ? error.message : 'Failed to add remote';
306
+ const status = message.includes('already exists') ? 400 : 500;
307
+ return c.json({ status: 'error', error: message }, status);
103
308
  }
309
+ },
310
+ );
104
311
 
105
- const { gitRoot } = validation;
106
-
107
- await execFileAsync('git', ['remote', 'remove', name], {
108
- cwd: gitRoot,
109
- });
110
-
111
- return c.json({
112
- status: 'ok',
113
- data: { removed: name },
114
- });
115
- } catch (error) {
116
- const message =
117
- error instanceof Error ? error.message : 'Failed to remove remote';
118
- return c.json({ status: 'error', error: message }, 500);
119
- }
120
- });
312
+ openApiRoute(
313
+ app,
314
+ {
315
+ method: 'delete',
316
+ path: '/v1/git/remotes',
317
+ tags: ['git'],
318
+ operationId: 'removeGitRemote',
319
+ summary: 'Remove a git remote',
320
+ requestBody: {
321
+ required: true,
322
+ content: {
323
+ 'application/json': {
324
+ schema: {
325
+ type: 'object',
326
+ properties: {
327
+ project: {
328
+ type: 'string',
329
+ },
330
+ name: {
331
+ type: 'string',
332
+ },
333
+ },
334
+ required: ['name'],
335
+ },
336
+ },
337
+ },
338
+ },
339
+ responses: {
340
+ '200': {
341
+ description: 'OK',
342
+ content: {
343
+ 'application/json': {
344
+ schema: {
345
+ type: 'object',
346
+ properties: {
347
+ status: {
348
+ type: 'string',
349
+ enum: ['ok'],
350
+ },
351
+ data: {
352
+ type: 'object',
353
+ properties: {
354
+ removed: {
355
+ type: 'string',
356
+ },
357
+ },
358
+ required: ['removed'],
359
+ },
360
+ },
361
+ required: ['status', 'data'],
362
+ },
363
+ },
364
+ },
365
+ },
366
+ '500': {
367
+ description: 'Error',
368
+ content: {
369
+ 'application/json': {
370
+ schema: {
371
+ type: 'object',
372
+ properties: {
373
+ status: {
374
+ type: 'string',
375
+ enum: ['error'],
376
+ },
377
+ error: {
378
+ type: 'string',
379
+ },
380
+ code: {
381
+ type: 'string',
382
+ },
383
+ },
384
+ required: ['status', 'error'],
385
+ },
386
+ },
387
+ },
388
+ },
389
+ },
390
+ },
391
+ async (c) => {
392
+ try {
393
+ const body = await c.req.json().catch(() => ({}));
394
+ const { project, name } = gitRemoteRemoveSchema.parse(body);
395
+ const requestedPath = project || process.cwd();
396
+
397
+ const validation = await validateAndGetGitRoot(requestedPath);
398
+ if ('error' in validation) {
399
+ return c.json(
400
+ { status: 'error', error: validation.error, code: validation.code },
401
+ 400,
402
+ );
403
+ }
404
+
405
+ const { gitRoot } = validation;
406
+
407
+ await execFileAsync('git', ['remote', 'remove', name], {
408
+ cwd: gitRoot,
409
+ });
410
+
411
+ return c.json({
412
+ status: 'ok',
413
+ data: { removed: name },
414
+ });
415
+ } catch (error) {
416
+ const message =
417
+ error instanceof Error ? error.message : 'Failed to remove remote';
418
+ return c.json({ status: 'error', error: message }, 500);
419
+ }
420
+ },
421
+ );
121
422
  }