@ottocode/server 0.1.265 → 0.1.267

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 (74) hide show
  1. package/package.json +3 -3
  2. package/src/routes/auth/copilot.ts +699 -0
  3. package/src/routes/auth/oauth.ts +578 -0
  4. package/src/routes/auth/onboarding.ts +45 -0
  5. package/src/routes/auth/providers.ts +189 -0
  6. package/src/routes/auth/service.ts +167 -0
  7. package/src/routes/auth/state.ts +23 -0
  8. package/src/routes/auth/status.ts +203 -0
  9. package/src/routes/auth/wallet.ts +229 -0
  10. package/src/routes/auth.ts +12 -2080
  11. package/src/routes/config/models-service.ts +411 -0
  12. package/src/routes/config/models.ts +6 -426
  13. package/src/routes/config/providers-service.ts +237 -0
  14. package/src/routes/config/providers.ts +10 -242
  15. package/src/routes/files/handlers.ts +297 -0
  16. package/src/routes/files/service.ts +313 -0
  17. package/src/routes/files.ts +12 -608
  18. package/src/routes/git/commit-service.ts +207 -0
  19. package/src/routes/git/commit.ts +6 -220
  20. package/src/routes/git/remote-service.ts +116 -0
  21. package/src/routes/git/remote.ts +8 -115
  22. package/src/routes/git/staging-service.ts +111 -0
  23. package/src/routes/git/staging.ts +10 -205
  24. package/src/routes/mcp/auth.ts +338 -0
  25. package/src/routes/mcp/lifecycle.ts +263 -0
  26. package/src/routes/mcp/servers.ts +212 -0
  27. package/src/routes/mcp/service.ts +664 -0
  28. package/src/routes/mcp/state.ts +13 -0
  29. package/src/routes/mcp.ts +6 -1233
  30. package/src/routes/ottorouter/billing.ts +593 -0
  31. package/src/routes/ottorouter/service.ts +92 -0
  32. package/src/routes/ottorouter/topup.ts +301 -0
  33. package/src/routes/ottorouter/wallet.ts +370 -0
  34. package/src/routes/ottorouter.ts +6 -1319
  35. package/src/routes/research/service.ts +339 -0
  36. package/src/routes/research.ts +12 -390
  37. package/src/routes/sessions/crud.ts +563 -0
  38. package/src/routes/sessions/queue.ts +242 -0
  39. package/src/routes/sessions/retry.ts +121 -0
  40. package/src/routes/sessions/service.ts +768 -0
  41. package/src/routes/sessions/share.ts +434 -0
  42. package/src/routes/sessions.ts +8 -1977
  43. package/src/routes/skills/service.ts +221 -0
  44. package/src/routes/skills/spec.ts +309 -0
  45. package/src/routes/skills.ts +31 -909
  46. package/src/routes/terminals/service.ts +326 -0
  47. package/src/routes/terminals.ts +19 -295
  48. package/src/routes/tunnel/service.ts +217 -0
  49. package/src/routes/tunnel.ts +29 -219
  50. package/src/runtime/agent/registry-prompts.ts +147 -0
  51. package/src/runtime/agent/registry.ts +6 -124
  52. package/src/runtime/agent/runner-errors.ts +116 -0
  53. package/src/runtime/agent/runner-reminders.ts +45 -0
  54. package/src/runtime/agent/runner-setup-model.ts +75 -0
  55. package/src/runtime/agent/runner-setup-prompt.ts +185 -0
  56. package/src/runtime/agent/runner-setup-tools.ts +103 -0
  57. package/src/runtime/agent/runner-setup-utils.ts +21 -0
  58. package/src/runtime/agent/runner-setup.ts +54 -288
  59. package/src/runtime/agent/runner-telemetry.ts +112 -0
  60. package/src/runtime/agent/runner-text.ts +108 -0
  61. package/src/runtime/agent/runner-tool-observer.ts +86 -0
  62. package/src/runtime/agent/runner.ts +79 -378
  63. package/src/runtime/prompt/builder.ts +5 -1
  64. package/src/runtime/prompt/capabilities.ts +13 -8
  65. package/src/runtime/provider/custom.ts +73 -0
  66. package/src/runtime/provider/index.ts +2 -85
  67. package/src/runtime/provider/reasoning-builders.ts +280 -0
  68. package/src/runtime/provider/reasoning.ts +67 -264
  69. package/src/tools/adapter/events.ts +116 -0
  70. package/src/tools/adapter/execution.ts +160 -0
  71. package/src/tools/adapter/pending.ts +37 -0
  72. package/src/tools/adapter/persistence.ts +166 -0
  73. package/src/tools/adapter/results.ts +97 -0
  74. package/src/tools/adapter.ts +124 -451
@@ -0,0 +1,326 @@
1
+ import type { Context } from 'hono';
2
+ import { streamSSE } from 'hono/streaming';
3
+ import type { TerminalManager } from '@ottocode/sdk';
4
+ import { logger } from '@ottocode/sdk';
5
+
6
+ export function listTerminals(terminalManager: TerminalManager) {
7
+ const terminals = terminalManager.list();
8
+ return {
9
+ terminals: terminals.map((terminal) => terminal.toJSON()),
10
+ count: terminals.length,
11
+ };
12
+ }
13
+
14
+ export async function createTerminal(
15
+ c: Context,
16
+ terminalManager: TerminalManager,
17
+ ) {
18
+ try {
19
+ const body = await c.req.json();
20
+ const { command, args, purpose, cwd, title } = body;
21
+
22
+ if (!command || !purpose) {
23
+ return c.json({ error: 'command and purpose are required' }, 400);
24
+ }
25
+
26
+ let resolvedCommand = command;
27
+ if (command === 'bash' || command === 'sh' || command === 'shell') {
28
+ resolvedCommand =
29
+ process.platform === 'win32'
30
+ ? process.env.COMSPEC || 'cmd.exe'
31
+ : process.env.SHELL || '/bin/bash';
32
+ }
33
+ const resolvedCwd = cwd || process.cwd();
34
+
35
+ const terminal = terminalManager.create({
36
+ command: resolvedCommand,
37
+ args: args || [],
38
+ purpose,
39
+ cwd: resolvedCwd,
40
+ createdBy: 'user',
41
+ title,
42
+ });
43
+
44
+ return c.json({
45
+ terminalId: terminal.id,
46
+ pid: terminal.pid,
47
+ purpose: terminal.purpose,
48
+ command: terminal.command,
49
+ });
50
+ } catch (error) {
51
+ logger.error('Error creating terminal', error);
52
+ const message = error instanceof Error ? error.message : String(error);
53
+ return c.json({ error: message }, 500);
54
+ }
55
+ }
56
+
57
+ export function getTerminal(c: Context, terminalManager: TerminalManager) {
58
+ const id = c.req.param('id');
59
+ const terminal = terminalManager.get(id);
60
+
61
+ if (!terminal) {
62
+ return c.json({ error: 'Terminal not found' }, 404);
63
+ }
64
+
65
+ return c.json({ terminal: terminal.toJSON() });
66
+ }
67
+
68
+ export function createTerminalWebSocketHandler(
69
+ terminalManager: TerminalManager,
70
+ id: string,
71
+ ) {
72
+ let onData: ((data: string) => void) | null = null;
73
+ let onExit: ((exitCode: number) => void) | null = null;
74
+
75
+ return {
76
+ onOpen(
77
+ _event: unknown,
78
+ ws: {
79
+ send: (data: string) => void;
80
+ close: (code?: number, reason?: string) => void;
81
+ },
82
+ ) {
83
+ const terminal = terminalManager.get(id);
84
+ if (!terminal) {
85
+ ws.close(4004, 'Terminal not found');
86
+ return;
87
+ }
88
+
89
+ const history = terminal.read();
90
+ for (const chunk of history) {
91
+ ws.send(chunk);
92
+ }
93
+
94
+ onData = (data: string) => {
95
+ try {
96
+ ws.send(data);
97
+ } catch {
98
+ // ws may be closed
99
+ }
100
+ };
101
+
102
+ onExit = (exitCode: number) => {
103
+ try {
104
+ ws.send(JSON.stringify({ type: 'exit', exitCode }));
105
+ ws.close(1000, 'Process exited');
106
+ } catch {
107
+ // ws may already be closed
108
+ }
109
+ };
110
+
111
+ terminal.onData(onData);
112
+ terminal.onExit(onExit);
113
+
114
+ if (terminal.status === 'exited') {
115
+ onExit(terminal.exitCode ?? 0);
116
+ }
117
+ },
118
+ onMessage(event: { data: unknown }, _ws: unknown) {
119
+ const terminal = terminalManager.get(id);
120
+ if (!terminal) return;
121
+
122
+ const raw = event.data;
123
+ const message =
124
+ typeof raw === 'string'
125
+ ? raw
126
+ : raw instanceof ArrayBuffer
127
+ ? new TextDecoder().decode(raw)
128
+ : String(raw);
129
+
130
+ if (message.startsWith('{')) {
131
+ try {
132
+ const msg = JSON.parse(message);
133
+ if (msg.type === 'resize' && msg.cols > 0 && msg.rows > 0) {
134
+ terminal.resize(msg.cols, msg.rows);
135
+ return;
136
+ }
137
+ } catch {
138
+ // not JSON, treat as input
139
+ }
140
+ }
141
+
142
+ terminal.write(message);
143
+ },
144
+ onClose() {
145
+ const terminal = terminalManager.get(id);
146
+ if (terminal) {
147
+ if (onData) terminal.removeDataListener(onData);
148
+ if (onExit) terminal.removeExitListener(onExit);
149
+ }
150
+ onData = null;
151
+ onExit = null;
152
+ },
153
+ onError() {
154
+ const terminal = terminalManager.get(id);
155
+ if (terminal) {
156
+ if (onData) terminal.removeDataListener(onData);
157
+ if (onExit) terminal.removeExitListener(onExit);
158
+ }
159
+ onData = null;
160
+ onExit = null;
161
+ },
162
+ };
163
+ }
164
+
165
+ export async function handleTerminalOutput(
166
+ c: Context,
167
+ terminalManager: TerminalManager,
168
+ ) {
169
+ const id = c.req.param('id');
170
+ const terminal = terminalManager.get(id);
171
+
172
+ if (!terminal) {
173
+ return c.json({ error: 'Terminal not found' }, 404);
174
+ }
175
+
176
+ const activeTerminal = terminal;
177
+
178
+ return streamSSE(c, async (stream) => {
179
+ const skipHistory = c.req.query('skipHistory') === 'true';
180
+ if (!skipHistory) {
181
+ const history = activeTerminal.read();
182
+ for (const line of history) {
183
+ await stream.write(
184
+ `data: ${JSON.stringify({ type: 'data', line })}\n\n`,
185
+ );
186
+ }
187
+ }
188
+
189
+ const sendEvent = async (payload: Record<string, unknown>) => {
190
+ try {
191
+ await stream.write(`data: ${JSON.stringify(payload)}\n\n`);
192
+ } catch (error) {
193
+ logger.error('SSE error writing event', error, { id });
194
+ }
195
+ };
196
+
197
+ const onData = (line: string) => {
198
+ void sendEvent({ type: 'data', line });
199
+ };
200
+
201
+ let resolveStream: (() => void) | null = null;
202
+ let finished = false;
203
+
204
+ const hb = setInterval(async () => {
205
+ try {
206
+ await stream.write(`: hb ${Date.now()}\n\n`);
207
+ } catch {
208
+ clearInterval(hb);
209
+ }
210
+ }, 15000);
211
+
212
+ function cleanup() {
213
+ activeTerminal.removeDataListener(onData);
214
+ activeTerminal.removeExitListener(onExit);
215
+ c.req.raw.signal.removeEventListener('abort', onAbort);
216
+ clearInterval(hb);
217
+ }
218
+
219
+ function finish() {
220
+ if (finished) {
221
+ return;
222
+ }
223
+ finished = true;
224
+ cleanup();
225
+ resolveStream?.();
226
+ }
227
+
228
+ async function onExit(exitCode: number) {
229
+ try {
230
+ await sendEvent({ type: 'exit', exitCode });
231
+ } finally {
232
+ stream.close();
233
+ finish();
234
+ }
235
+ }
236
+
237
+ function onAbort() {
238
+ stream.close();
239
+ finish();
240
+ }
241
+
242
+ terminal.onData(onData);
243
+ terminal.onExit(onExit);
244
+
245
+ c.req.raw.signal.addEventListener('abort', onAbort, { once: true });
246
+
247
+ const waitForClose = new Promise<void>((resolve) => {
248
+ resolveStream = resolve;
249
+ });
250
+
251
+ if (terminal.status === 'exited') {
252
+ void onExit(terminal.exitCode ?? 0);
253
+ }
254
+
255
+ await waitForClose;
256
+ });
257
+ }
258
+
259
+ export async function sendTerminalInput(
260
+ c: Context,
261
+ terminalManager: TerminalManager,
262
+ ) {
263
+ const id = c.req.param('id');
264
+ const terminal = terminalManager.get(id);
265
+
266
+ if (!terminal) {
267
+ return c.json({ error: 'Terminal not found' }, 404);
268
+ }
269
+
270
+ try {
271
+ const body = await c.req.json();
272
+ const { input } = body;
273
+
274
+ if (!input) {
275
+ return c.json({ error: 'input is required' }, 400);
276
+ }
277
+
278
+ terminal.write(input);
279
+ return c.json({ success: true });
280
+ } catch (error) {
281
+ const message = error instanceof Error ? error.message : String(error);
282
+ return c.json({ error: message }, 500);
283
+ }
284
+ }
285
+
286
+ export async function killTerminal(
287
+ c: Context,
288
+ terminalManager: TerminalManager,
289
+ ) {
290
+ const id = c.req.param('id');
291
+
292
+ try {
293
+ await terminalManager.kill(id);
294
+ return c.json({ success: true });
295
+ } catch (error) {
296
+ const message = error instanceof Error ? error.message : String(error);
297
+ return c.json({ error: message }, 500);
298
+ }
299
+ }
300
+
301
+ export async function resizeTerminal(
302
+ c: Context,
303
+ terminalManager: TerminalManager,
304
+ ) {
305
+ const id = c.req.param('id');
306
+ const terminal = terminalManager.get(id);
307
+
308
+ if (!terminal) {
309
+ return c.json({ error: 'Terminal not found' }, 404);
310
+ }
311
+
312
+ try {
313
+ const body = await c.req.json();
314
+ const { cols, rows } = body;
315
+
316
+ if (!cols || !rows || cols < 1 || rows < 1) {
317
+ return c.json({ error: 'valid cols and rows are required' }, 400);
318
+ }
319
+
320
+ terminal.resize(cols, rows);
321
+ return c.json({ success: true });
322
+ } catch (error) {
323
+ const message = error instanceof Error ? error.message : String(error);
324
+ return c.json({ error: message }, 500);
325
+ }
326
+ }
@@ -1,10 +1,17 @@
1
- import type { Context } from 'hono';
2
1
  import type { Hono } from 'hono';
3
- import { streamSSE } from 'hono/streaming';
4
2
  import type { TerminalManager } from '@ottocode/sdk';
5
- import { logger } from '@ottocode/sdk';
6
3
  import { upgradeWebSocket } from '../ws.ts';
7
4
  import { openApiRoute } from '../openapi/route.ts';
5
+ import {
6
+ createTerminal,
7
+ createTerminalWebSocketHandler,
8
+ getTerminal,
9
+ handleTerminalOutput,
10
+ killTerminal,
11
+ listTerminals,
12
+ resizeTerminal,
13
+ sendTerminalInput,
14
+ } from './terminals/service.ts';
8
15
 
9
16
  export function registerTerminalsRoutes(
10
17
  app: Hono,
@@ -42,13 +49,7 @@ export function registerTerminalsRoutes(
42
49
  },
43
50
  },
44
51
  },
45
- async (c) => {
46
- const terminals = terminalManager.list();
47
- return c.json({
48
- terminals: terminals.map((t) => t.toJSON()),
49
- count: terminals.length,
50
- });
51
- },
52
+ (c) => c.json(listTerminals(terminalManager)),
52
53
  );
53
54
 
54
55
  openApiRoute(
@@ -122,45 +123,7 @@ export function registerTerminalsRoutes(
122
123
  },
123
124
  },
124
125
  },
125
- async (c) => {
126
- try {
127
- const body = await c.req.json();
128
- const { command, args, purpose, cwd, title } = body;
129
-
130
- if (!command || !purpose) {
131
- return c.json({ error: 'command and purpose are required' }, 400);
132
- }
133
-
134
- let resolvedCommand = command;
135
- if (command === 'bash' || command === 'sh' || command === 'shell') {
136
- resolvedCommand =
137
- process.platform === 'win32'
138
- ? process.env.COMSPEC || 'cmd.exe'
139
- : process.env.SHELL || '/bin/bash';
140
- }
141
- const resolvedCwd = cwd || process.cwd();
142
-
143
- const terminal = terminalManager.create({
144
- command: resolvedCommand,
145
- args: args || [],
146
- purpose,
147
- cwd: resolvedCwd,
148
- createdBy: 'user',
149
- title,
150
- });
151
-
152
- return c.json({
153
- terminalId: terminal.id,
154
- pid: terminal.pid,
155
- purpose: terminal.purpose,
156
- command: terminal.command,
157
- });
158
- } catch (error) {
159
- logger.error('Error creating terminal', error);
160
- const message = error instanceof Error ? error.message : String(error);
161
- return c.json({ error: message }, 500);
162
- }
163
- },
126
+ (c) => createTerminal(c, terminalManager),
164
127
  );
165
128
 
166
129
  openApiRoute(
@@ -202,16 +165,7 @@ export function registerTerminalsRoutes(
202
165
  },
203
166
  },
204
167
  },
205
- async (c) => {
206
- const id = c.req.param('id');
207
- const terminal = terminalManager.get(id);
208
-
209
- if (!terminal) {
210
- return c.json({ error: 'Terminal not found' }, 404);
211
- }
212
-
213
- return c.json({ terminal: terminal.toJSON() });
214
- },
168
+ (c) => getTerminal(c, terminalManager),
215
169
  );
216
170
 
217
171
  openApiRoute(
@@ -238,186 +192,10 @@ export function registerTerminalsRoutes(
238
192
  },
239
193
  upgradeWebSocket((c) => {
240
194
  const id = c.req.param('id');
241
-
242
- let onData: ((data: string) => void) | null = null;
243
- let onExit: ((exitCode: number) => void) | null = null;
244
-
245
- return {
246
- onOpen(_event, ws) {
247
- const terminal = terminalManager.get(id);
248
- if (!terminal) {
249
- ws.close(4004, 'Terminal not found');
250
- return;
251
- }
252
-
253
- const history = terminal.read();
254
- for (const chunk of history) {
255
- ws.send(chunk);
256
- }
257
-
258
- onData = (data: string) => {
259
- try {
260
- ws.send(data);
261
- } catch {
262
- // ws may be closed
263
- }
264
- };
265
-
266
- onExit = (exitCode: number) => {
267
- try {
268
- ws.send(JSON.stringify({ type: 'exit', exitCode }));
269
- ws.close(1000, 'Process exited');
270
- } catch {
271
- // ws may already be closed
272
- }
273
- };
274
-
275
- terminal.onData(onData);
276
- terminal.onExit(onExit);
277
-
278
- if (terminal.status === 'exited') {
279
- onExit(terminal.exitCode ?? 0);
280
- }
281
- },
282
- onMessage(event, _ws) {
283
- const terminal = terminalManager.get(id);
284
- if (!terminal) return;
285
-
286
- const raw = event.data;
287
- const message =
288
- typeof raw === 'string'
289
- ? raw
290
- : raw instanceof ArrayBuffer
291
- ? new TextDecoder().decode(raw)
292
- : String(raw);
293
-
294
- if (message.startsWith('{')) {
295
- try {
296
- const msg = JSON.parse(message);
297
- if (msg.type === 'resize' && msg.cols > 0 && msg.rows > 0) {
298
- terminal.resize(msg.cols, msg.rows);
299
- return;
300
- }
301
- } catch {
302
- // not JSON, treat as input
303
- }
304
- }
305
-
306
- terminal.write(message);
307
- },
308
- onClose() {
309
- const terminal = terminalManager.get(id);
310
- if (terminal) {
311
- if (onData) terminal.removeDataListener(onData);
312
- if (onExit) terminal.removeExitListener(onExit);
313
- }
314
- onData = null;
315
- onExit = null;
316
- },
317
- onError() {
318
- const terminal = terminalManager.get(id);
319
- if (terminal) {
320
- if (onData) terminal.removeDataListener(onData);
321
- if (onExit) terminal.removeExitListener(onExit);
322
- }
323
- onData = null;
324
- onExit = null;
325
- },
326
- };
195
+ return createTerminalWebSocketHandler(terminalManager, id);
327
196
  }),
328
197
  );
329
198
 
330
- const handleTerminalOutput = async (c: Context) => {
331
- const id = c.req.param('id');
332
- const terminal = terminalManager.get(id);
333
-
334
- if (!terminal) {
335
- return c.json({ error: 'Terminal not found' }, 404);
336
- }
337
-
338
- const activeTerminal = terminal;
339
-
340
- return streamSSE(c, async (stream) => {
341
- const skipHistory = c.req.query('skipHistory') === 'true';
342
- if (!skipHistory) {
343
- const history = activeTerminal.read();
344
- for (const line of history) {
345
- await stream.write(
346
- `data: ${JSON.stringify({ type: 'data', line })}\n\n`,
347
- );
348
- }
349
- }
350
-
351
- const sendEvent = async (payload: Record<string, unknown>) => {
352
- try {
353
- await stream.write(`data: ${JSON.stringify(payload)}\n\n`);
354
- } catch (error) {
355
- logger.error('SSE error writing event', error, { id });
356
- }
357
- };
358
-
359
- const onData = (line: string) => {
360
- void sendEvent({ type: 'data', line });
361
- };
362
-
363
- let resolveStream: (() => void) | null = null;
364
- let finished = false;
365
-
366
- const hb = setInterval(async () => {
367
- try {
368
- await stream.write(`: hb ${Date.now()}\n\n`);
369
- } catch {
370
- clearInterval(hb);
371
- }
372
- }, 15000);
373
-
374
- function cleanup() {
375
- activeTerminal.removeDataListener(onData);
376
- activeTerminal.removeExitListener(onExit);
377
- c.req.raw.signal.removeEventListener('abort', onAbort);
378
- clearInterval(hb);
379
- }
380
-
381
- function finish() {
382
- if (finished) {
383
- return;
384
- }
385
- finished = true;
386
- cleanup();
387
- resolveStream?.();
388
- }
389
-
390
- async function onExit(exitCode: number) {
391
- try {
392
- await sendEvent({ type: 'exit', exitCode });
393
- } finally {
394
- stream.close();
395
- finish();
396
- }
397
- }
398
-
399
- function onAbort() {
400
- stream.close();
401
- finish();
402
- }
403
-
404
- terminal.onData(onData);
405
- terminal.onExit(onExit);
406
-
407
- c.req.raw.signal.addEventListener('abort', onAbort, { once: true });
408
-
409
- const waitForClose = new Promise<void>((resolve) => {
410
- resolveStream = resolve;
411
- });
412
-
413
- if (terminal.status === 'exited') {
414
- void onExit(terminal.exitCode ?? 0);
415
- }
416
-
417
- await waitForClose;
418
- });
419
- };
420
-
421
199
  openApiRoute(
422
200
  app,
423
201
  {
@@ -449,7 +227,7 @@ export function registerTerminalsRoutes(
449
227
  },
450
228
  },
451
229
  },
452
- handleTerminalOutput,
230
+ (c) => handleTerminalOutput(c, terminalManager),
453
231
  );
454
232
  openApiRoute(
455
233
  app,
@@ -478,7 +256,7 @@ export function registerTerminalsRoutes(
478
256
  },
479
257
  },
480
258
  },
481
- handleTerminalOutput,
259
+ (c) => handleTerminalOutput(c, terminalManager),
482
260
  );
483
261
 
484
262
  openApiRoute(
@@ -534,29 +312,7 @@ export function registerTerminalsRoutes(
534
312
  },
535
313
  },
536
314
  },
537
- async (c) => {
538
- const id = c.req.param('id');
539
- const terminal = terminalManager.get(id);
540
-
541
- if (!terminal) {
542
- return c.json({ error: 'Terminal not found' }, 404);
543
- }
544
-
545
- try {
546
- const body = await c.req.json();
547
- const { input } = body;
548
-
549
- if (!input) {
550
- return c.json({ error: 'input is required' }, 400);
551
- }
552
-
553
- terminal.write(input);
554
- return c.json({ success: true });
555
- } catch (error) {
556
- const message = error instanceof Error ? error.message : String(error);
557
- return c.json({ error: message }, 500);
558
- }
559
- },
315
+ (c) => sendTerminalInput(c, terminalManager),
560
316
  );
561
317
 
562
318
  openApiRoute(
@@ -595,17 +351,7 @@ export function registerTerminalsRoutes(
595
351
  },
596
352
  },
597
353
  },
598
- async (c) => {
599
- const id = c.req.param('id');
600
-
601
- try {
602
- await terminalManager.kill(id);
603
- return c.json({ success: true });
604
- } catch (error) {
605
- const message = error instanceof Error ? error.message : String(error);
606
- return c.json({ error: message }, 500);
607
- }
608
- },
354
+ (c) => killTerminal(c, terminalManager),
609
355
  );
610
356
 
611
357
  openApiRoute(
@@ -656,28 +402,6 @@ export function registerTerminalsRoutes(
656
402
  '404': { description: 'Terminal not found' },
657
403
  },
658
404
  },
659
- async (c) => {
660
- const id = c.req.param('id');
661
- const terminal = terminalManager.get(id);
662
-
663
- if (!terminal) {
664
- return c.json({ error: 'Terminal not found' }, 404);
665
- }
666
-
667
- try {
668
- const body = await c.req.json();
669
- const { cols, rows } = body;
670
-
671
- if (!cols || !rows || cols < 1 || rows < 1) {
672
- return c.json({ error: 'valid cols and rows are required' }, 400);
673
- }
674
-
675
- terminal.resize(cols, rows);
676
- return c.json({ success: true });
677
- } catch (error) {
678
- const message = error instanceof Error ? error.message : String(error);
679
- return c.json({ error: message }, 500);
680
- }
681
- },
405
+ (c) => resizeTerminal(c, terminalManager),
682
406
  );
683
407
  }