@getpaseo/server 0.1.91-beta.1 → 0.1.91

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 (50) hide show
  1. package/dist/scripts/supervisor.js +21 -0
  2. package/dist/server/server/agent/agent-manager.d.ts +1 -1
  3. package/dist/server/server/agent/agent-manager.js +23 -48
  4. package/dist/server/server/agent/agent-sdk-types.d.ts +15 -0
  5. package/dist/server/server/agent/prompt-attachments.js +8 -0
  6. package/dist/server/server/agent/provider-registry.d.ts +0 -1
  7. package/dist/server/server/agent/provider-registry.js +22 -4
  8. package/dist/server/server/agent/provider-snapshot-manager.js +19 -1
  9. package/dist/server/server/agent/providers/claude/agent.d.ts +5 -2
  10. package/dist/server/server/agent/providers/claude/agent.js +6 -2
  11. package/dist/server/server/agent/providers/claude/models.d.ts +1 -1
  12. package/dist/server/server/agent/providers/claude/models.js +6 -6
  13. package/dist/server/server/agent/providers/codex-app-server-agent.js +9 -5
  14. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.d.ts +1 -0
  15. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.js +4 -0
  16. package/dist/server/server/agent/providers/opencode-agent.d.ts +16 -2
  17. package/dist/server/server/agent/providers/opencode-agent.js +75 -4
  18. package/dist/server/server/agent/providers/pi/agent.d.ts +23 -1
  19. package/dist/server/server/agent/providers/pi/agent.js +219 -13
  20. package/dist/server/server/agent/providers/pi/cli-runtime.js +9 -0
  21. package/dist/server/server/agent/providers/pi/rpc-types.d.ts +9 -0
  22. package/dist/server/server/agent/providers/pi/runtime.d.ts +2 -0
  23. package/dist/server/server/agent/providers/pi/session-descriptor.d.ts +12 -0
  24. package/dist/server/server/agent/providers/pi/session-descriptor.js +304 -0
  25. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.d.ts +8 -0
  26. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.js +22 -0
  27. package/dist/server/server/agent/runtime-mcp-config.d.ts +8 -0
  28. package/dist/server/server/agent/runtime-mcp-config.js +50 -0
  29. package/dist/server/server/auth.js +16 -1
  30. package/dist/server/server/auto-archive-on-merge/archive-if-safe.js +2 -2
  31. package/dist/server/server/daemon-worker.js +84 -1
  32. package/dist/server/server/file-upload/index.d.ts +27 -0
  33. package/dist/server/server/file-upload/index.js +158 -0
  34. package/dist/server/server/loop-service.d.ts +12 -12
  35. package/dist/server/server/persisted-config.d.ts +11 -0
  36. package/dist/server/server/persisted-config.js +2 -1
  37. package/dist/server/server/persistence-hooks.js +6 -4
  38. package/dist/server/server/session.d.ts +5 -2
  39. package/dist/server/server/session.js +20 -2
  40. package/dist/server/server/speech/providers/local/runtime.js +1 -0
  41. package/dist/server/server/speech/providers/local/worker-client.d.ts +14 -1
  42. package/dist/server/server/speech/providers/local/worker-client.js +169 -7
  43. package/dist/server/server/websocket-server.d.ts +2 -0
  44. package/dist/server/server/websocket-server.js +20 -7
  45. package/dist/server/server/workspace-registry.d.ts +4 -4
  46. package/dist/server/utils/directory-suggestions.js +10 -5
  47. package/dist/server/utils/worktree.d.ts +4 -0
  48. package/dist/server/utils/worktree.js +19 -2
  49. package/dist/src/server/persisted-config.js +2 -1
  50. package/package.json +5 -5
@@ -0,0 +1,158 @@
1
+ import { appendFile, mkdir, rm, writeFile } from "node:fs/promises";
2
+ import { basename, join } from "node:path";
3
+ import { FileTransferOpcode } from "@getpaseo/protocol/binary-frames/index";
4
+ import { getErrorMessage } from "@getpaseo/protocol/error-utils";
5
+ export class FileUploadStore {
6
+ constructor(options) {
7
+ this.pending = new Map();
8
+ this.paseoHome = options.paseoHome;
9
+ this.staleUploadTimeoutMs =
10
+ options.staleUploadTimeoutMs ?? FileUploadStore.defaultStaleUploadTimeoutMs;
11
+ }
12
+ beginUpload(request) {
13
+ const existingUpload = this.pending.get(request.requestId);
14
+ if (existingUpload) {
15
+ this.clearPendingUpload(existingUpload);
16
+ void existingUpload.queue.then(() => this.removeUploadDirectory(existingUpload));
17
+ }
18
+ const fileName = sanitizeFileName(request.fileName);
19
+ const attempt = existingUpload ? existingUpload.attempt + 1 : 1;
20
+ const id = buildUploadId(request.requestId, attempt);
21
+ const uploadDir = join(this.paseoHome, "uploads", id);
22
+ const upload = {
23
+ requestId: request.requestId,
24
+ id,
25
+ attempt,
26
+ fileName,
27
+ mimeType: request.mimeType,
28
+ size: request.size,
29
+ path: join(uploadDir, fileName),
30
+ receivedBytes: 0,
31
+ started: false,
32
+ staleTimeout: this.createStaleUploadTimeout(request.requestId),
33
+ queue: Promise.resolve(),
34
+ };
35
+ this.pending.set(request.requestId, upload);
36
+ }
37
+ async receiveFrame(frame) {
38
+ const upload = this.pending.get(frame.requestId);
39
+ if (!upload) {
40
+ return null;
41
+ }
42
+ this.refreshStaleUploadTimeout(upload);
43
+ const operation = upload.queue.then(() => this.applyFrame(upload, frame));
44
+ upload.queue = operation.then(() => undefined, () => undefined);
45
+ return operation;
46
+ }
47
+ async applyFrame(upload, frame) {
48
+ if (this.pending.get(upload.requestId) !== upload) {
49
+ return null;
50
+ }
51
+ try {
52
+ if (frame.opcode === FileTransferOpcode.FileBegin) {
53
+ await this.startWriting(upload);
54
+ return null;
55
+ }
56
+ if (frame.opcode === FileTransferOpcode.FileChunk) {
57
+ await this.writeChunk(upload, frame.payload);
58
+ return null;
59
+ }
60
+ return await this.completeUpload(upload);
61
+ }
62
+ catch (error) {
63
+ await this.removeFailedUpload(upload);
64
+ return buildUploadResponse(upload, getErrorMessage(error));
65
+ }
66
+ }
67
+ async startWriting(upload) {
68
+ await mkdir(join(this.paseoHome, "uploads", upload.id), { recursive: true });
69
+ await writeFile(upload.path, new Uint8Array());
70
+ upload.started = true;
71
+ }
72
+ async writeChunk(upload, bytes) {
73
+ if (!upload.started) {
74
+ throw new Error("Upload chunks arrived before file begin.");
75
+ }
76
+ const nextReceivedBytes = upload.receivedBytes + bytes.byteLength;
77
+ if (nextReceivedBytes > upload.size) {
78
+ throw new Error(`Upload exceeded declared size: expected ${upload.size}, received ${nextReceivedBytes}.`);
79
+ }
80
+ await appendFile(upload.path, bytes);
81
+ upload.receivedBytes += bytes.byteLength;
82
+ }
83
+ async completeUpload(upload) {
84
+ this.clearPendingUpload(upload);
85
+ if (upload.receivedBytes !== upload.size) {
86
+ await this.removeUploadDirectory(upload);
87
+ return buildUploadResponse(upload, `Upload size mismatch: expected ${upload.size}, received ${upload.receivedBytes}.`);
88
+ }
89
+ return buildUploadResponse(upload, null);
90
+ }
91
+ createStaleUploadTimeout(requestId) {
92
+ const timeout = setTimeout(() => {
93
+ this.expireStaleUpload(requestId);
94
+ }, this.staleUploadTimeoutMs);
95
+ timeout.unref?.();
96
+ return timeout;
97
+ }
98
+ refreshStaleUploadTimeout(upload) {
99
+ clearTimeout(upload.staleTimeout);
100
+ upload.staleTimeout = this.createStaleUploadTimeout(upload.requestId);
101
+ }
102
+ expireStaleUpload(requestId) {
103
+ const upload = this.pending.get(requestId);
104
+ if (!upload) {
105
+ return;
106
+ }
107
+ this.clearPendingUpload(upload);
108
+ const cleanup = upload.queue.then(() => this.removeUploadDirectory(upload), () => this.removeUploadDirectory(upload));
109
+ upload.queue = cleanup.then(() => undefined, () => undefined);
110
+ }
111
+ clearPendingUpload(upload) {
112
+ clearTimeout(upload.staleTimeout);
113
+ if (this.pending.get(upload.requestId) === upload) {
114
+ this.pending.delete(upload.requestId);
115
+ }
116
+ }
117
+ async removeFailedUpload(upload) {
118
+ this.clearPendingUpload(upload);
119
+ await this.removeUploadDirectory(upload);
120
+ }
121
+ async removeUploadDirectory(upload) {
122
+ await rm(join(this.paseoHome, "uploads", upload.id), { recursive: true, force: true }).catch(() => undefined);
123
+ }
124
+ }
125
+ FileUploadStore.defaultStaleUploadTimeoutMs = 10 * 60 * 1000;
126
+ function buildUploadResponse(upload, error) {
127
+ return {
128
+ type: "file.upload.response",
129
+ payload: {
130
+ requestId: upload.requestId,
131
+ file: error
132
+ ? null
133
+ : {
134
+ type: "uploaded_file",
135
+ id: upload.id,
136
+ fileName: upload.fileName,
137
+ mimeType: upload.mimeType,
138
+ size: upload.size,
139
+ path: upload.path,
140
+ },
141
+ error,
142
+ },
143
+ };
144
+ }
145
+ function sanitizeUploadId(value) {
146
+ return value.replace(/[^a-zA-Z0-9._-]/g, "_") || "file";
147
+ }
148
+ function buildUploadId(requestId, attempt) {
149
+ const baseId = `upload_${sanitizeUploadId(requestId)}`;
150
+ return attempt === 1 ? baseId : `${baseId}_${attempt}`;
151
+ }
152
+ function sanitizeFileName(value) {
153
+ const name = basename(value)
154
+ .replace(/[^a-zA-Z0-9._ -]/g, "_")
155
+ .trim();
156
+ return name.length > 0 && name !== "." && name !== ".." ? name : "upload";
157
+ }
158
+ //# sourceMappingURL=index.js.map
@@ -13,16 +13,16 @@ declare const LoopLogEntrySchema: z.ZodObject<{
13
13
  }, "strip", z.ZodTypeAny, {
14
14
  text: string;
15
15
  level: "error" | "info";
16
- source: "worker" | "loop" | "verifier" | "verify-check";
17
- timestamp: string;
18
16
  seq: number;
17
+ timestamp: string;
18
+ source: "worker" | "loop" | "verifier" | "verify-check";
19
19
  iteration: number | null;
20
20
  }, {
21
21
  text: string;
22
22
  level: "error" | "info";
23
- source: "worker" | "loop" | "verifier" | "verify-check";
24
- timestamp: string;
25
23
  seq: number;
24
+ timestamp: string;
25
+ source: "worker" | "loop" | "verifier" | "verify-check";
26
26
  iteration: number | null;
27
27
  }>;
28
28
  declare const LoopVerifyCheckResultSchema: z.ZodObject<{
@@ -312,16 +312,16 @@ declare const LoopRecordSchema: z.ZodObject<{
312
312
  }, "strip", z.ZodTypeAny, {
313
313
  text: string;
314
314
  level: "error" | "info";
315
- source: "worker" | "loop" | "verifier" | "verify-check";
316
- timestamp: string;
317
315
  seq: number;
316
+ timestamp: string;
317
+ source: "worker" | "loop" | "verifier" | "verify-check";
318
318
  iteration: number | null;
319
319
  }, {
320
320
  text: string;
321
321
  level: "error" | "info";
322
- source: "worker" | "loop" | "verifier" | "verify-check";
323
- timestamp: string;
324
322
  seq: number;
323
+ timestamp: string;
324
+ source: "worker" | "loop" | "verifier" | "verify-check";
325
325
  iteration: number | null;
326
326
  }>, "many">;
327
327
  nextLogSeq: z.ZodNumber;
@@ -382,9 +382,9 @@ declare const LoopRecordSchema: z.ZodObject<{
382
382
  logs: {
383
383
  text: string;
384
384
  level: "error" | "info";
385
- source: "worker" | "loop" | "verifier" | "verify-check";
386
- timestamp: string;
387
385
  seq: number;
386
+ timestamp: string;
387
+ source: "worker" | "loop" | "verifier" | "verify-check";
388
388
  iteration: number | null;
389
389
  }[];
390
390
  nextLogSeq: number;
@@ -443,9 +443,9 @@ declare const LoopRecordSchema: z.ZodObject<{
443
443
  logs: {
444
444
  text: string;
445
445
  level: "error" | "info";
446
- source: "worker" | "loop" | "verifier" | "verify-check";
447
- timestamp: string;
448
446
  seq: number;
447
+ timestamp: string;
448
+ source: "worker" | "loop" | "verifier" | "verify-check";
449
449
  iteration: number | null;
450
450
  }[];
451
451
  nextLogSeq: number;
@@ -3,6 +3,7 @@ import type { AgentProviderRuntimeSettingsMap } from "./agent/provider-launch-co
3
3
  export declare const LogLevelSchema: z.ZodEnum<["trace", "debug", "info", "warn", "error", "fatal"]>;
4
4
  export declare const LogFormatSchema: z.ZodEnum<["pretty", "json"]>;
5
5
  export declare const PersistedConfigSchema: z.ZodObject<{
6
+ $schema: z.ZodOptional<z.ZodString>;
6
7
  version: z.ZodOptional<z.ZodLiteral<1>>;
7
8
  daemon: z.ZodOptional<z.ZodEffects<z.ZodObject<{
8
9
  listen: z.ZodOptional<z.ZodString>;
@@ -229,6 +230,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
229
230
  description: z.ZodOptional<z.ZodString>;
230
231
  command: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
231
232
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
233
+ params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
232
234
  models: z.ZodOptional<z.ZodArray<z.ZodObject<{
233
235
  id: z.ZodString;
234
236
  label: z.ZodString;
@@ -322,6 +324,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
322
324
  order: z.ZodOptional<z.ZodNumber>;
323
325
  }, "strip", z.ZodTypeAny, {
324
326
  description?: string | undefined;
327
+ params?: Record<string, unknown> | undefined;
325
328
  label?: string | undefined;
326
329
  enabled?: boolean | undefined;
327
330
  command?: string[] | undefined;
@@ -355,6 +358,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
355
358
  order?: number | undefined;
356
359
  }, {
357
360
  description?: string | undefined;
361
+ params?: Record<string, unknown> | undefined;
358
362
  label?: string | undefined;
359
363
  enabled?: boolean | undefined;
360
364
  command?: string[] | undefined;
@@ -388,6 +392,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
388
392
  order?: number | undefined;
389
393
  }>>, Record<string, {
390
394
  description?: string | undefined;
395
+ params?: Record<string, unknown> | undefined;
391
396
  label?: string | undefined;
392
397
  enabled?: boolean | undefined;
393
398
  command?: string[] | undefined;
@@ -421,6 +426,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
421
426
  order?: number | undefined;
422
427
  }>, Record<string, {
423
428
  description?: string | undefined;
429
+ params?: Record<string, unknown> | undefined;
424
430
  label?: string | undefined;
425
431
  enabled?: boolean | undefined;
426
432
  command?: string[] | undefined;
@@ -454,6 +460,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
454
460
  order?: number | undefined;
455
461
  }>>, Record<string, {
456
462
  description?: string | undefined;
463
+ params?: Record<string, unknown> | undefined;
457
464
  label?: string | undefined;
458
465
  enabled?: boolean | undefined;
459
466
  command?: string[] | undefined;
@@ -523,6 +530,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
523
530
  } | undefined;
524
531
  providers?: Record<string, {
525
532
  description?: string | undefined;
533
+ params?: Record<string, unknown> | undefined;
526
534
  label?: string | undefined;
527
535
  enabled?: boolean | undefined;
528
536
  command?: string[] | undefined;
@@ -924,6 +932,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
924
932
  } | undefined;
925
933
  providers?: Record<string, {
926
934
  description?: string | undefined;
935
+ params?: Record<string, unknown> | undefined;
927
936
  label?: string | undefined;
928
937
  enabled?: boolean | undefined;
929
938
  command?: string[] | undefined;
@@ -957,6 +966,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
957
966
  order?: number | undefined;
958
967
  }> | undefined;
959
968
  } | undefined;
969
+ $schema?: string | undefined;
960
970
  app?: {
961
971
  baseUrl?: string | undefined;
962
972
  } | undefined;
@@ -1061,6 +1071,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
1061
1071
  } | undefined;
1062
1072
  providers?: unknown;
1063
1073
  } | undefined;
1074
+ $schema?: string | undefined;
1064
1075
  app?: {
1065
1076
  baseUrl?: string | undefined;
1066
1077
  } | undefined;
@@ -129,7 +129,7 @@ const AgentMetadataGenerationSchema = z
129
129
  providers: z.array(StructuredGenerationProviderConfigSchema).optional(),
130
130
  })
131
131
  .strict();
132
- const BUILTIN_PROVIDER_IDS = ["claude", "codex", "copilot", "opencode", "pi"];
132
+ const BUILTIN_PROVIDER_IDS = ["claude", "codex", "copilot", "opencode", "pi", "omp"];
133
133
  function isLegacyProviderEntry(value) {
134
134
  if (!value || typeof value !== "object" || Array.isArray(value)) {
135
135
  return false;
@@ -169,6 +169,7 @@ function normalizeAgentProviders(value) {
169
169
  }
170
170
  export const PersistedConfigSchema = z
171
171
  .object({
172
+ $schema: z.string().optional(),
172
173
  // v1 schema marker
173
174
  version: z.literal(1).optional(),
174
175
  // v1 config layout
@@ -1,3 +1,4 @@
1
+ import { stripInternalPaseoMcpServer } from "./agent/runtime-mcp-config.js";
1
2
  function getLogger(logger) {
2
3
  return logger.child({ module: "persistence" });
3
4
  }
@@ -21,7 +22,8 @@ export function attachAgentStoragePersistence(logger, agentManager, storage) {
21
22
  return unsubscribe;
22
23
  }
23
24
  export function buildConfigOverrides(record) {
24
- return {
25
+ return stripInternalPaseoMcpServer({
26
+ provider: record.provider,
25
27
  cwd: record.cwd,
26
28
  modeId: record.lastModeId ?? record.config?.modeId ?? undefined,
27
29
  model: record.config?.model ?? undefined,
@@ -30,7 +32,7 @@ export function buildConfigOverrides(record) {
30
32
  extra: record.config?.extra ?? undefined,
31
33
  systemPrompt: record.config?.systemPrompt ?? undefined,
32
34
  mcpServers: record.config?.mcpServers ?? undefined,
33
- };
35
+ });
34
36
  }
35
37
  export function buildSessionConfig(record, options) {
36
38
  const validProviders = options?.validProviders;
@@ -39,7 +41,7 @@ export function buildSessionConfig(record, options) {
39
41
  return null;
40
42
  }
41
43
  const overrides = buildConfigOverrides(record);
42
- return {
44
+ return stripInternalPaseoMcpServer({
43
45
  provider: record.provider,
44
46
  cwd: record.cwd,
45
47
  modeId: overrides.modeId,
@@ -49,7 +51,7 @@ export function buildSessionConfig(record, options) {
49
51
  extra: overrides.extra,
50
52
  systemPrompt: overrides.systemPrompt,
51
53
  mcpServers: overrides.mcpServers,
52
- };
54
+ });
53
55
  }
54
56
  export function isStoredAgentProviderAvailable(record, validProviders) {
55
57
  return buildSessionConfig(record, { validProviders }) !== null;
@@ -1,7 +1,7 @@
1
1
  import { type ClientCapability } from "@getpaseo/protocol/client-capabilities";
2
2
  import { type AgentSnapshotPayload, type SessionInboundMessage, type SessionOutboundMessage, type WorkspaceSetupSnapshot } from "./messages.js";
3
3
  import type { TerminalManager } from "../terminal/terminal-manager.js";
4
- import { type TerminalStreamFrame } from "@getpaseo/protocol/binary-frames/index";
4
+ import { type BinaryFrame } from "@getpaseo/protocol/binary-frames/index";
5
5
  import type { SpeechToTextProvider, TextToSpeechProvider } from "./speech/speech-provider.js";
6
6
  import type { TurnDetectionProvider } from "./speech/turn-detection-provider.js";
7
7
  import type { VoiceCallerContext, VoiceSpeakHandler } from "./voice-types.js";
@@ -181,6 +181,7 @@ export declare class Session {
181
181
  private readonly workspaceSetupSnapshots;
182
182
  private readonly workspaceGitFetchSubscriptions;
183
183
  private readonly workspaceGitSubscriptions;
184
+ private readonly fileUploads;
184
185
  private readonly workspaceDirectory;
185
186
  private registerVoiceSpeakHandler?;
186
187
  private unregisterVoiceSpeakHandler?;
@@ -286,7 +287,7 @@ export declare class Session {
286
287
  private dispatchScheduleMessage;
287
288
  private dispatchMiscMessage;
288
289
  resetPeakInflight(): void;
289
- handleBinaryFrame(frame: TerminalStreamFrame): void;
290
+ handleBinaryFrame(binaryFrame: BinaryFrame): Promise<void>;
290
291
  private handleRestartServerRequest;
291
292
  private handleShutdownServerRequest;
292
293
  private emitLifecycleIntent;
@@ -420,6 +421,8 @@ export declare class Session {
420
421
  * Handle read-only file explorer requests scoped to a workspace cwd
421
422
  */
422
423
  private handleFileExplorerRequest;
424
+ private handleFileUploadRequest;
425
+ private handleFileTransferFrame;
423
426
  /**
424
427
  * Handle project icon request for a given cwd
425
428
  */
@@ -8,6 +8,7 @@ import { CLIENT_CAPS } from "@getpaseo/protocol/client-capabilities";
8
8
  import { serializeAgentStreamEvent, } from "./messages.js";
9
9
  import { TerminalSessionController } from "../terminal/terminal-session-controller.js";
10
10
  import { encodeFileTransferFrame, FileTransferOpcode, } from "@getpaseo/protocol/binary-frames/index";
11
+ import { FileUploadStore } from "./file-upload/index.js";
11
12
  import { CursorError } from "./pagination/cursor.js";
12
13
  import { SortablePager } from "./pagination/sortable-pager.js";
13
14
  import { TTSManager } from "./agent/tts-manager.js";
@@ -327,6 +328,7 @@ export class Session {
327
328
  this.onLifecycleIntent = onLifecycleIntent ?? null;
328
329
  this.downloadTokenStore = downloadTokenStore;
329
330
  this.pushTokenStore = pushTokenStore;
331
+ this.fileUploads = new FileUploadStore({ paseoHome });
330
332
  this.paseoHome = paseoHome;
331
333
  this.worktreesRoot = worktreesRoot;
332
334
  this.sessionLogger = logger.child({
@@ -1322,6 +1324,9 @@ export class Session {
1322
1324
  return this.handleProjectIconRequest(msg);
1323
1325
  case "file_download_token_request":
1324
1326
  return this.handleFileDownloadTokenRequest(msg);
1327
+ case "file.upload.request":
1328
+ this.handleFileUploadRequest(msg);
1329
+ return undefined;
1325
1330
  default:
1326
1331
  return undefined;
1327
1332
  }
@@ -1419,8 +1424,12 @@ export class Session {
1419
1424
  resetPeakInflight() {
1420
1425
  this.peakInflightRequests = this.inflightRequests;
1421
1426
  }
1422
- handleBinaryFrame(frame) {
1423
- this.terminalController.handleBinaryFrame(frame);
1427
+ async handleBinaryFrame(binaryFrame) {
1428
+ if (binaryFrame.kind === "file_transfer") {
1429
+ await this.handleFileTransferFrame(binaryFrame.frame);
1430
+ return;
1431
+ }
1432
+ this.terminalController.handleBinaryFrame(binaryFrame.frame);
1424
1433
  }
1425
1434
  async handleRestartServerRequest(requestId, reason) {
1426
1435
  const payload = {
@@ -4395,6 +4404,15 @@ export class Session {
4395
4404
  });
4396
4405
  }
4397
4406
  }
4407
+ handleFileUploadRequest(request) {
4408
+ this.fileUploads.beginUpload(request);
4409
+ }
4410
+ async handleFileTransferFrame(frame) {
4411
+ const response = await this.fileUploads.receiveFrame(frame);
4412
+ if (response) {
4413
+ this.emit(response);
4414
+ }
4415
+ }
4398
4416
  /**
4399
4417
  * Handle project icon request for a given cwd
4400
4418
  */
@@ -67,6 +67,7 @@ export async function initializeLocalSpeechServices(params) {
67
67
  });
68
68
  const workerClient = localConfig
69
69
  ? new LocalSpeechWorkerClient({
70
+ logger,
70
71
  config: {
71
72
  modelsDir: localConfig.modelsDir,
72
73
  voiceSttModel: localModels.voiceLocalSttModel,
@@ -1,4 +1,5 @@
1
1
  import { EventEmitter } from "node:events";
2
+ import { Readable } from "node:stream";
2
3
  import type pino from "pino";
3
4
  import type { SpeechStreamResult, SpeechToTextProvider, StreamingTranscriptionSession, TextToSpeechProvider } from "../../speech-provider.js";
4
5
  import type { TurnDetectionProvider, TurnDetectionSession } from "../../turn-detection-provider.js";
@@ -6,20 +7,24 @@ import type { LocalSpeechSessionKind, LocalSpeechTranscriptionResult, LocalSpeec
6
7
  interface LocalSpeechWorkerProcess {
7
8
  connected: boolean;
8
9
  killed: boolean;
10
+ pid?: number;
11
+ stderr?: Readable | null;
9
12
  send(message: LocalSpeechWorkerRequest, callback: (error: Error | null) => void): boolean;
10
13
  disconnect(): void;
11
14
  kill(): boolean;
12
15
  on(event: "message", listener: (message: LocalSpeechWorkerToParentMessage) => void): this;
13
- on(event: "exit", listener: (code: number | null, signal: NodeJS.Signals | null) => void): this;
16
+ on(event: "close", listener: (code: number | null, signal: NodeJS.Signals | null) => void): this;
14
17
  }
15
18
  interface LocalSpeechWorkerClientOptions {
16
19
  config: LocalSpeechWorkerConfig;
20
+ logger: pino.Logger;
17
21
  requestTimeoutMs?: number;
18
22
  idleTtlMs?: number;
19
23
  forkWorker?: () => LocalSpeechWorkerProcess;
20
24
  }
21
25
  export declare class LocalSpeechWorkerClient {
22
26
  private readonly config;
27
+ private readonly logger;
23
28
  private readonly requestTimeoutMs;
24
29
  private readonly idleTtlMs;
25
30
  private readonly forkWorker;
@@ -27,8 +32,12 @@ export declare class LocalSpeechWorkerClient {
27
32
  private readonly activeSessionIds;
28
33
  private readonly sessionEmitters;
29
34
  private worker;
35
+ private workerPid;
36
+ private stderrTail;
37
+ private stderrLineBuffer;
30
38
  private inFlightRequests;
31
39
  private idleTimer;
40
+ private readonly intentionalWorkerCloses;
32
41
  constructor(options: LocalSpeechWorkerClientOptions);
33
42
  synthesizeSpeech(text: string): Promise<SpeechStreamResult>;
34
43
  transcribeVoice(audio: Buffer, format: string): Promise<LocalSpeechTranscriptionResult>;
@@ -45,10 +54,14 @@ export declare class LocalSpeechWorkerClient {
45
54
  shutdown(): void;
46
55
  private sendRequest;
47
56
  private ensureWorker;
57
+ private handleWorkerStderr;
48
58
  private handleWorkerMessage;
49
59
  private handleWorkerExit;
60
+ private describePendingRequests;
61
+ private getStderrTail;
50
62
  private rejectAllPending;
51
63
  private emitSessionError;
64
+ private emitErrorIfObserved;
52
65
  private scheduleIdleShutdownIfReady;
53
66
  private clearIdleTimer;
54
67
  }