@factory/droid-sdk 0.6.0 → 0.8.0

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 (92) hide show
  1. package/README.md +35 -482
  2. package/dist/chunk-4G2RKM2H.js +25831 -0
  3. package/dist/chunk-4G2RKM2H.js.map +1 -0
  4. package/dist/chunk-ROFAQUG4.mjs +25831 -0
  5. package/dist/chunk-ROFAQUG4.mjs.map +1 -0
  6. package/dist/{index-CwXX5IUH.d.cts → index-_nUPGHpH.d.mts} +92630 -79659
  7. package/dist/{index-CwXX5IUH.d.ts → index-_nUPGHpH.d.ts} +92630 -79659
  8. package/dist/index.d.mts +4 -0
  9. package/dist/index.d.ts +4 -93103
  10. package/dist/index.js +829 -11745
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +830 -0
  13. package/dist/index.mjs.map +1 -0
  14. package/dist/node.d.mts +757 -0
  15. package/dist/node.d.ts +757 -0
  16. package/dist/node.js +4731 -0
  17. package/dist/node.js.map +1 -0
  18. package/dist/node.mjs +4731 -0
  19. package/dist/node.mjs.map +1 -0
  20. package/docs/typescript-sdk-reference.md +1437 -0
  21. package/examples/browser/daemon-lifecycle.ts +95 -0
  22. package/examples/browser/daemon-model-discovery.ts +47 -0
  23. package/examples/browser/daemon-multi-session.ts +66 -0
  24. package/examples/browser/daemon-session.ts +73 -0
  25. package/examples/browser/index.html +69 -0
  26. package/examples/browser/list-sessions.ts +50 -0
  27. package/examples/node/abort-session-stream.ts +34 -0
  28. package/examples/node/ask-user-elicitation.ts +39 -0
  29. package/examples/node/compact-session.ts +63 -0
  30. package/examples/node/custom-system-prompt.ts +35 -0
  31. package/examples/node/document-input.ts +58 -0
  32. package/examples/node/enter-spec-mode.ts +87 -0
  33. package/examples/node/external-mcp.ts +45 -0
  34. package/examples/node/fork-session.ts +56 -0
  35. package/examples/node/hook-execution.ts +94 -0
  36. package/examples/node/image-attachment.ts +41 -0
  37. package/examples/node/init-metadata.ts +24 -0
  38. package/examples/node/interrupt-session.ts +55 -0
  39. package/examples/node/list-sessions.ts +20 -0
  40. package/examples/node/model-discovery.ts +28 -0
  41. package/examples/node/model-selection.ts +35 -0
  42. package/examples/node/multi-turn-session.ts +37 -0
  43. package/examples/node/observability.ts +75 -0
  44. package/examples/node/partial-stream.ts +56 -0
  45. package/examples/node/permission-handler.ts +60 -0
  46. package/examples/node/rename-session.ts +33 -0
  47. package/examples/node/result-metadata.ts +43 -0
  48. package/examples/node/resume-session.ts +41 -0
  49. package/examples/node/rewind-session.ts +79 -0
  50. package/examples/node/run.ts +32 -0
  51. package/examples/node/sdk-mcp-tool.ts +56 -0
  52. package/examples/node/session-settings.ts +35 -0
  53. package/examples/node/session-stream.ts +59 -0
  54. package/examples/node/skills.ts +24 -0
  55. package/examples/node/spec-mode-new-session.ts +120 -0
  56. package/examples/node/spec-mode-same-session.ts +119 -0
  57. package/examples/node/structured-output.ts +96 -0
  58. package/examples/node/tool-controls.ts +26 -0
  59. package/examples/package.json +3 -0
  60. package/package.json +20 -42
  61. package/dist/index.cjs +0 -12135
  62. package/dist/index.cjs.map +0 -1
  63. package/dist/index.d.cts +0 -93103
  64. package/dist/protocol/index.cjs +0 -6466
  65. package/dist/protocol/index.cjs.map +0 -1
  66. package/dist/protocol/index.d.cts +0 -2
  67. package/dist/protocol/index.d.ts +0 -2
  68. package/dist/protocol/index.js +0 -6078
  69. package/dist/protocol/index.js.map +0 -1
  70. package/docs/daemon-usage-guide.md +0 -544
  71. package/docs/sdk-usage-guide.md +0 -748
  72. package/examples/abort-session-stream.ts +0 -34
  73. package/examples/daemon-multi-session.ts +0 -67
  74. package/examples/droid-dev-structured-output.ts +0 -44
  75. package/examples/fork-session.ts +0 -68
  76. package/examples/hook-execution.ts +0 -68
  77. package/examples/init-metadata.ts +0 -24
  78. package/examples/interrupt-session.ts +0 -35
  79. package/examples/list-sessions.ts +0 -19
  80. package/examples/multi-turn-session.ts +0 -40
  81. package/examples/permission-handler.ts +0 -41
  82. package/examples/readme-structured-output.ts +0 -26
  83. package/examples/result-metadata.ts +0 -63
  84. package/examples/run.ts +0 -39
  85. package/examples/sdk-mcp-tool.ts +0 -44
  86. package/examples/session-stream.ts +0 -57
  87. package/examples/spec-mode-new-session.ts +0 -61
  88. package/examples/spec-mode-same-session.ts +0 -72
  89. package/examples/structured-output.ts +0 -60
  90. package/examples/test-compact.ts +0 -65
  91. package/examples/test-rewind.ts +0 -87
  92. package/examples/tool-controls.ts +0 -37
package/dist/node.mjs ADDED
@@ -0,0 +1,4731 @@
1
+ import {
2
+ AbortError,
3
+ AddMcpServerRequestParamsSchema,
4
+ AddMcpServerRequestSchema,
5
+ AddMcpServerResponseSchema,
6
+ AddMcpServerResultSchema,
7
+ AddUserMessageRequestParamsSchema,
8
+ AddUserMessageRequestSchema,
9
+ AddUserMessageResponseSchema,
10
+ AddUserMessageResultSchema,
11
+ AppendMessagesResponseSchema,
12
+ ApplyPatchToolConfirmationDetailsSchema,
13
+ AskUserCollectedAnswerSchema,
14
+ AskUserConfirmationDetailsSchema,
15
+ AskUserQuestionSchema,
16
+ AskUserRequestParamsSchema,
17
+ AskUserRequestSchema,
18
+ AskUserResponseSchema,
19
+ AskUserResultSchema,
20
+ AssistantTextCompleteNotificationSchema,
21
+ AssistantTextDeltaNotificationSchema,
22
+ AuthenticateMcpServerRequestParamsSchema,
23
+ AuthenticateMcpServerRequestSchema,
24
+ AuthenticateMcpServerResponseSchema,
25
+ AuthenticateMcpServerResultSchema,
26
+ AutonomyLevel,
27
+ AvailableModelConfigSchema,
28
+ Base64ImageSourceSchema,
29
+ BaseNotificationSchema,
30
+ BaseRequestSchema,
31
+ BaseResponseFailureSchema,
32
+ BaseResponseSuccessSchema,
33
+ COMPACTION_TIMEOUT,
34
+ CancelMcpAuthRequestParamsSchema,
35
+ CancelMcpAuthRequestSchema,
36
+ CancelMcpAuthResponseSchema,
37
+ CancelMcpAuthResultSchema,
38
+ ChangeWorkingDirectoryRequestParamsSchema,
39
+ ChangeWorkingDirectoryRequestSchema,
40
+ ChangeWorkingDirectoryResponseSchema,
41
+ ChangeWorkingDirectoryResultSchema,
42
+ ClearMcpAuthRequestParamsSchema,
43
+ ClearMcpAuthRequestSchema,
44
+ ClearMcpAuthResponseSchema,
45
+ ClearMcpAuthResultSchema,
46
+ CliRequestOrNotificationSchema,
47
+ ClientDestroyedError,
48
+ ClientRequestSchema,
49
+ ClientUiSurface,
50
+ CloseSessionRequestParamsSchema,
51
+ CloseSessionRequestSchema,
52
+ CloseSessionResponseSchema,
53
+ CloseSessionResultSchema,
54
+ CompactSessionRequestParamsSchema,
55
+ CompactSessionRequestSchema,
56
+ CompactSessionResponseSchema,
57
+ CompactSessionResultSchema,
58
+ ComputeLimitExceededError,
59
+ ComputerConnectAttemptTrigger,
60
+ ComputerConnectStartType,
61
+ ComputerListResponseSchema,
62
+ ComputerMetricSchema,
63
+ ComputerMetricsResponseSchema,
64
+ ComputerSchema,
65
+ ConcurrentStreamError,
66
+ ConnectionClosedError,
67
+ ConnectionError,
68
+ ConnectionFailureReason,
69
+ ContentBlockSchema,
70
+ ContextBreakdownCategorySchema,
71
+ ContextStatsAccuracy,
72
+ ContextStatsSchema,
73
+ CreateMessageNotificationSchema,
74
+ CreateToolConfirmationDetailsSchema,
75
+ DEFAULT_LOCAL_DAEMON_WS_URL,
76
+ DEFAULT_REQUEST_TIMEOUT,
77
+ DaemonAuthenticationMode,
78
+ DaemonClient,
79
+ DaemonDroidEvent,
80
+ DaemonRequestPermissionSchema,
81
+ DaemonSessionController,
82
+ DecompSessionType,
83
+ DiscoveredIssueSchema,
84
+ DismissalRecordSchema,
85
+ DismissalType,
86
+ DocumentBlockSchema,
87
+ DocumentSourceSchema,
88
+ DroidClientError,
89
+ DroidClientMethod,
90
+ DroidErrorType,
91
+ DroidEvent,
92
+ DroidHookEventSchema,
93
+ DroidHookExecutionResultSchema,
94
+ DroidHookOutputSchema,
95
+ DroidHookSpecificOutputSchema,
96
+ DroidInteractionMode,
97
+ DroidMessageType,
98
+ DroidServerMethod,
99
+ DroidWorkingState,
100
+ DroidWorkingStateChangedNotificationSchema,
101
+ EditToolConfirmationDetailsSchema,
102
+ EmptyResultSchema,
103
+ ErrorDetailSchema,
104
+ ErrorNotificationSchema,
105
+ ExecToolInfoSchema,
106
+ ExecuteRewindRequestParamsSchema,
107
+ ExecuteRewindRequestSchema,
108
+ ExecuteRewindResponseSchema,
109
+ ExecuteRewindResultSchema,
110
+ ExecuteToolConfirmationDetailsSchema,
111
+ ExitSpecModeConfirmationDetailsSchema,
112
+ FACTORY_CLIENT_HEADER,
113
+ FACTORY_CLIENT_VERSION,
114
+ FACTORY_PROTOCOL_VERSION,
115
+ FACTORY_PROTOCOL_VERSION2,
116
+ FactoryDaemonTransport,
117
+ FactoryDroidMessageRole,
118
+ FactoryDroidMessageSchema,
119
+ FeatureStatus,
120
+ FeatureSuccessState,
121
+ FeatureSuccessStateSchema,
122
+ ForkSessionRequestParamsSchema,
123
+ ForkSessionRequestSchema,
124
+ ForkSessionResponseSchema,
125
+ ForkSessionResultSchema,
126
+ GetContextBreakdownResponseSchema,
127
+ GetContextBreakdownResultSchema,
128
+ GetContextStatsRequestParamsSchema,
129
+ GetContextStatsRequestSchema,
130
+ GetContextStatsResponseSchema,
131
+ GetRewindInfoRequestParamsSchema,
132
+ GetRewindInfoRequestSchema,
133
+ GetRewindInfoResponseSchema,
134
+ GetRewindInfoResultSchema,
135
+ GitRepoInfoSchema,
136
+ HandoffItemsDismissedEntrySchema,
137
+ HandoffSchema,
138
+ HookCommandSchema,
139
+ HookExecutionCompletedNotificationSchema,
140
+ HookExecutionStartedNotificationSchema,
141
+ HookResultSchema,
142
+ HttpHeaderSchema,
143
+ HttpMcpSchema,
144
+ IPC_DAEMON_URL,
145
+ ImageBlockSchema,
146
+ InProcessDaemonClientTransport,
147
+ InitializeSessionRequestParamsSchema,
148
+ InitializeSessionRequestSchema,
149
+ InitializeSessionResponseSchema,
150
+ InitializeSessionResultSchema,
151
+ InitializeSessionResultSchema2,
152
+ InteractiveCheckSchema,
153
+ InterruptSessionRequestParamsSchema,
154
+ InterruptSessionRequestSchema,
155
+ InterruptSessionResponseSchema,
156
+ InterruptSessionResultSchema,
157
+ InvalidSessionCwdError,
158
+ IpcDaemonClientTransport,
159
+ IssueSeverity,
160
+ JSONRPC_VERSION,
161
+ JSONRPC_VERSION2,
162
+ JSONRPC_VERSION3,
163
+ JsonArraySchema,
164
+ JsonObjectSchema,
165
+ JsonRpcBaseResponseSchema,
166
+ JsonRpcEnvelopeSchema,
167
+ JsonRpcErrorCode,
168
+ JsonRpcErrorSchema,
169
+ JsonRpcMessageSchema,
170
+ JsonRpcMessageType,
171
+ JsonRpcNotificationSchema,
172
+ JsonRpcRequestError,
173
+ JsonRpcRequestSchema,
174
+ JsonRpcResponseFailureSchema,
175
+ JsonRpcResponseSchema,
176
+ JsonRpcResponseSuccessSchema,
177
+ JsonValueSchema,
178
+ KillWorkerSessionRequestParamsSchema,
179
+ KillWorkerSessionRequestSchema,
180
+ KillWorkerSessionResponseSchema,
181
+ KillWorkerSessionResultSchema,
182
+ LEGACY_FACTORY_API_VERSION,
183
+ LEGACY_FACTORY_API_VERSION2,
184
+ LOCAL_MACHINE_ID,
185
+ ListCommandsResponseSchema,
186
+ ListMcpRegistryRequestParamsSchema,
187
+ ListMcpRegistryRequestSchema,
188
+ ListMcpRegistryResponseSchema,
189
+ ListMcpRegistryResultSchema,
190
+ ListMcpServersRequestParamsSchema,
191
+ ListMcpServersRequestSchema,
192
+ ListMcpServersResponseSchema,
193
+ ListMcpServersResultSchema,
194
+ ListMcpToolsRequestParamsSchema,
195
+ ListMcpToolsRequestSchema,
196
+ ListMcpToolsResponseSchema,
197
+ ListMcpToolsResultSchema,
198
+ ListModelsOptionsSchema,
199
+ ListModelsResponseSchema,
200
+ ListModelsResultSchema,
201
+ ListSkillsRequestParamsSchema,
202
+ ListSkillsRequestSchema,
203
+ ListSkillsResponseSchema,
204
+ ListSkillsResultSchema,
205
+ ListToolsRequestParamsSchema,
206
+ ListToolsRequestSchema,
207
+ ListToolsResponseSchema,
208
+ ListToolsResultSchema,
209
+ LoadSessionRequestParamsSchema,
210
+ LoadSessionRequestSchema,
211
+ LoadSessionResponseSchema,
212
+ LoadSessionResultSchema,
213
+ MACHINE_TYPE_WEBSOCKET_OVERRIDES,
214
+ MANAGED_COMPUTER_MAX_RETRIES,
215
+ MCP_AUTH_TIMEOUT,
216
+ MachineTemplateBuildStatusSchema,
217
+ MachineTemplateListResponseSchema,
218
+ MachineTemplateSchema,
219
+ MachineType,
220
+ McpAuthCompletedNotificationSchema,
221
+ McpAuthOutcome,
222
+ McpAuthRequiredNotificationSchema,
223
+ McpHttpServerConfigFieldsSchema,
224
+ McpRegistryServerSchema,
225
+ McpServerConfigSchema,
226
+ McpServerStatus,
227
+ McpServerStatusInfoSchema,
228
+ McpServerType,
229
+ McpSseServerConfigFieldsSchema,
230
+ McpStatus,
231
+ McpStatusChangedNotificationSchema,
232
+ McpStatusSummarySchema,
233
+ McpStdioServerConfigFieldsSchema,
234
+ McpToolConfirmationDetailsSchema,
235
+ McpToolInfoSchema,
236
+ McpToolInputSchemaSchema,
237
+ MessageVisibility,
238
+ MetaError,
239
+ Metric,
240
+ MilestoneValidationTriggeredEntrySchema,
241
+ MissionAcceptedEntrySchema,
242
+ MissionFeatureSchema,
243
+ MissionFeaturesChangedNotificationSchema,
244
+ MissionHeartbeatNotificationSchema,
245
+ MissionPausedEntrySchema,
246
+ MissionProgressEntryNotificationSchema,
247
+ MissionResumedEntrySchema,
248
+ MissionRunStartedEntrySchema,
249
+ MissionState,
250
+ MissionStateChangedNotificationSchema,
251
+ MissionStateSchema,
252
+ MissionWorkerCompletedNotificationSchema,
253
+ MissionWorkerStartedNotificationSchema,
254
+ ModelInfoSchema,
255
+ ModelMetadataSchema,
256
+ ModelProvider,
257
+ MultiMissionStateManager,
258
+ MultiSessionStateManager,
259
+ OtelTracing,
260
+ OutputFormatSchema,
261
+ OutputFormatType,
262
+ PermissionResolvedNotificationSchema,
263
+ ProcessExitError,
264
+ ProgressLogEntrySchema,
265
+ ProgressLogEntryType,
266
+ ProposeMissionConfirmationDetailsSchema,
267
+ ProtocolError,
268
+ QueuedUserMessageDisplayGroup,
269
+ QueuedUserMessageKind,
270
+ REWIND_TIMEOUT,
271
+ ReasoningEffort,
272
+ RedactedThinkingBlockSchema,
273
+ RefreshComputerResponseSchema,
274
+ RelayConnectionError,
275
+ RemoteSessionListResponseSchema,
276
+ RemoteSessionSchema,
277
+ RemoveMcpServerRequestParamsSchema,
278
+ RemoveMcpServerRequestSchema,
279
+ RemoveMcpServerResponseSchema,
280
+ RemoveMcpServerResultSchema,
281
+ RenameSessionRequestParamsSchema,
282
+ RenameSessionRequestSchema,
283
+ RenameSessionResponseSchema,
284
+ RenameSessionResultSchema,
285
+ RequestPermissionRequestParamsSchema,
286
+ RequestPermissionRequestSchema,
287
+ RequestPermissionResponseSchema,
288
+ RequestPermissionResultSchema,
289
+ ResolveQueuedUserMessageResponseSchema,
290
+ RewindEvictedFileSchema,
291
+ RewindFileCreationSchema,
292
+ RewindFileSnapshotSchema,
293
+ SDK_TAG,
294
+ SDK_VERSION,
295
+ SESSION_INIT_TIMEOUT,
296
+ SLACK_DELEGATION_MAX_RETRIES,
297
+ ServerRequestHandlerType,
298
+ SessionError,
299
+ SessionMetadataSchema,
300
+ SessionNotFoundError,
301
+ SessionNotificationParamsSchema,
302
+ SessionNotificationPayloadSchema,
303
+ SessionNotificationSchema,
304
+ SessionNotificationSchemaList,
305
+ SessionNotificationType,
306
+ SessionPlatform,
307
+ SessionReplacedError,
308
+ SessionReplacementError,
309
+ SessionSettingsFileSchema,
310
+ SessionSettingsSchema,
311
+ SessionSourceSchema,
312
+ SessionStartDecompSessionTypeSchema,
313
+ SessionStartEventSchema,
314
+ SessionTagSchema,
315
+ SessionTitleUpdatedNotificationSchema,
316
+ SessionTokenUsageChangedNotificationSchema,
317
+ SetSkillDisabledRequestParamsSchema,
318
+ SetSkillDisabledRequestSchema,
319
+ SetSkillDisabledResponseSchema,
320
+ SetSkillDisabledResultSchema,
321
+ SettingsLevel,
322
+ SettingsUpdatedNotificationSchema,
323
+ SettingsUpdatedPayloadSchema,
324
+ SkillDeviationSchema,
325
+ SkillFeedbackSchema,
326
+ SkillInfoSchema,
327
+ SkillLocation,
328
+ SkillResourceSchema,
329
+ SpanAttribute,
330
+ SpanEvent,
331
+ SpanName,
332
+ SseMcpSchema,
333
+ StartMissionRunConfirmationDetailsSchema,
334
+ StdioMcpSchema,
335
+ StreamStateTracker,
336
+ StructuredOutputErrorSchema,
337
+ StructuredOutputNotificationSchema,
338
+ SubmitBugReportRequestParamsSchema,
339
+ SubmitBugReportRequestSchema,
340
+ SubmitBugReportResponseSchema,
341
+ SubmitBugReportResultSchema,
342
+ SubmitMcpAuthCodeRequestParamsSchema,
343
+ SubmitMcpAuthCodeRequestSchema,
344
+ SubmitMcpAuthCodeResponseSchema,
345
+ SubmitMcpAuthCodeResultSchema,
346
+ SubmitMcpAuthErrorResponseSchema,
347
+ SuccessResultSchema,
348
+ TestCaseSchema,
349
+ TestFileSchema,
350
+ TestsSchema,
351
+ TextBlockSchema,
352
+ ThinkingBlockSchema,
353
+ ThinkingTextCompleteNotificationSchema,
354
+ ThinkingTextDeltaNotificationSchema,
355
+ TimeoutError,
356
+ ToggleMcpServerRequestParamsSchema,
357
+ ToggleMcpServerRequestSchema,
358
+ ToggleMcpServerResponseSchema,
359
+ ToggleMcpServerResultSchema,
360
+ ToggleMcpToolRequestParamsSchema,
361
+ ToggleMcpToolRequestSchema,
362
+ ToggleMcpToolResponseSchema,
363
+ ToggleMcpToolResultSchema,
364
+ TokenUsageSchema,
365
+ ToolCallNotificationSchema,
366
+ ToolConfirmationDetailsSchema,
367
+ ToolConfirmationInfoSchema,
368
+ ToolConfirmationListItemSchema,
369
+ ToolConfirmationOutcome,
370
+ ToolConfirmationType,
371
+ ToolProgressUpdateNotificationSchema,
372
+ ToolProgressUpdateSchema,
373
+ ToolResultNotificationSchema,
374
+ ToolResultSchema,
375
+ ToolSelectionOverridesSchema,
376
+ ToolUseSchema,
377
+ ToolUseSchema2,
378
+ TraceContextMetaSchema,
379
+ TunnelConnection,
380
+ UpdateSessionSettingsRequestParamsSchema,
381
+ UpdateSessionSettingsRequestSchema,
382
+ UpdateSessionSettingsResponseSchema,
383
+ UpdateSessionSettingsResultSchema,
384
+ VerificationCommandSchema,
385
+ VerificationSchema,
386
+ WarmupCacheResponseSchema,
387
+ WebSocketConnectionError,
388
+ WebSocketDaemonTransport,
389
+ WorkerCompletedEntrySchema,
390
+ WorkerFailedEntrySchema,
391
+ WorkerPausedEntrySchema,
392
+ WorkerSelectedFeatureEntrySchema,
393
+ WorkerStartedEntrySchema,
394
+ WorkerStateInfoSchema,
395
+ buildUserMessageContentBlocks,
396
+ configureDaemonCoreDeps,
397
+ connectAndAuthenticate,
398
+ connectToDaemon,
399
+ connectWithRetry,
400
+ convertNotificationToStreamMessage,
401
+ createComputer,
402
+ createResponseSchema,
403
+ createWebSocketDaemonClient,
404
+ defaultDaemonCoreDeps,
405
+ deleteComputer,
406
+ extractInnerNotification,
407
+ filterMessagesForUI,
408
+ getComputer,
409
+ getComputerByName,
410
+ getComputerMetrics,
411
+ getMachineTemplate,
412
+ getPermissionToolInputForDisplay,
413
+ getQueuedUserMessageDisplayGroup,
414
+ getQueuedUserMessageReviewPriority,
415
+ getSubagentCallingMetadata,
416
+ getToolResultBlocks,
417
+ getToolResultToolUseId,
418
+ hasDecoupledInteractionSettings,
419
+ hasSubagentSessionTag,
420
+ inspectJsonRpcEnvelope,
421
+ isDaemonQueuedMessageKind,
422
+ isPendingToolResultMarker,
423
+ isPersistedHookMessage,
424
+ isReviewableQueuedMessageKind,
425
+ listComputers,
426
+ listMachineTemplates,
427
+ listRemoteSessions,
428
+ machineTypeToMachineConnectionType,
429
+ mergeSessionSettings,
430
+ orderMessagesByParentChain,
431
+ recordComputerConnectSli,
432
+ refreshComputer,
433
+ repairParentChainCorruption,
434
+ restartComputer,
435
+ retryInstallDeps,
436
+ retryWithLogger,
437
+ streamFromClient,
438
+ sumTokenUsage,
439
+ summarizeSessionToolUsage,
440
+ toError,
441
+ unwrapResponseResult,
442
+ updateComputer,
443
+ wireAbortSignal
444
+ } from "./chunk-ROFAQUG4.mjs";
445
+
446
+ // src/exec-core/client.ts
447
+ import EventEmitter from "events";
448
+ import { v4 as uuidv4 } from "uuid";
449
+ import { z } from "zod";
450
+
451
+ // src/exec-core/constants.ts
452
+ var DEFAULT_REQUEST_TIMEOUT2 = 3e4;
453
+ var SESSION_INIT_TIMEOUT2 = 6e4;
454
+ var COMPACTION_TIMEOUT2 = 24e4;
455
+ var MCP_AUTH_TIMEOUT2 = 3e5;
456
+ var WINDOWS_JOB_OBJECT_ERROR_MARKER = "AssignProcessToJobObject";
457
+ var CLI_JSONRPC_CHILD_SPAWN_LATENCY_METRIC = "cli_jsonrpc_child_spawn_latency";
458
+ var noopLogger = {
459
+ info() {
460
+ },
461
+ warn() {
462
+ },
463
+ exception() {
464
+ }
465
+ };
466
+
467
+ // src/exec-core/default-deps.ts
468
+ function getRuntimeEnvironment() {
469
+ return globalThis.process?.env ?? {};
470
+ }
471
+ var defaultExecCoreDeps = {
472
+ logger: {
473
+ info() {
474
+ },
475
+ warn() {
476
+ },
477
+ exception() {
478
+ }
479
+ },
480
+ metrics: {
481
+ addToCounter() {
482
+ },
483
+ recordDuration() {
484
+ }
485
+ },
486
+ tracing: {
487
+ getCurrentContext() {
488
+ return void 0;
489
+ },
490
+ injectContext() {
491
+ }
492
+ },
493
+ commandResolver: {
494
+ resolveDroidCommand(isDevelopment) {
495
+ return {
496
+ execPath: isDevelopment ? "droid-dev" : "droid",
497
+ prefixArgs: []
498
+ };
499
+ }
500
+ },
501
+ factoryPathResolver: {
502
+ getFactoryHome() {
503
+ const env = getRuntimeEnvironment();
504
+ return env.FACTORY_HOME_OVERRIDE ?? env.HOME ?? env.USERPROFILE ?? "";
505
+ },
506
+ getFactoryDirName() {
507
+ return ".factory";
508
+ }
509
+ },
510
+ environmentResolver: {
511
+ resolveTransportLogEnvValue() {
512
+ return getRuntimeEnvironment().FACTORY_DROID_SDK_TRANSPORT_LOG;
513
+ },
514
+ sanitizeSpawnEnv(env) {
515
+ return env;
516
+ }
517
+ }
518
+ };
519
+
520
+ // src/exec-core/enums.ts
521
+ var DroidClientEvent = /* @__PURE__ */ ((DroidClientEvent2) => {
522
+ DroidClientEvent2["SESSION_NOTIFICATION"] = "session_notification";
523
+ DroidClientEvent2["REQUEST_PERMISSION"] = "request_permission";
524
+ DroidClientEvent2["ASK_USER"] = "ask_user";
525
+ DroidClientEvent2["ERROR"] = "error";
526
+ return DroidClientEvent2;
527
+ })(DroidClientEvent || {});
528
+ var DroidProcessMode = /* @__PURE__ */ ((DroidProcessMode2) => {
529
+ DroidProcessMode2["Acp"] = "acp";
530
+ DroidProcessMode2["StreamJsonRpc"] = "stream-jsonrpc";
531
+ return DroidProcessMode2;
532
+ })(DroidProcessMode || {});
533
+ var TransportDirection = /* @__PURE__ */ ((TransportDirection2) => {
534
+ TransportDirection2["In"] = "in";
535
+ TransportDirection2["Out"] = "out";
536
+ TransportDirection2["OutFailed"] = "out_failed";
537
+ return TransportDirection2;
538
+ })(TransportDirection || {});
539
+
540
+ // ../droid-sdk-core/src/observability.ts
541
+ function sanitizeAttributes(attributes) {
542
+ if (attributes === void 0) {
543
+ return void 0;
544
+ }
545
+ const sanitized = {};
546
+ for (const [key, value] of Object.entries(attributes)) {
547
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
548
+ sanitized[key] = value;
549
+ }
550
+ }
551
+ return Object.keys(sanitized).length > 0 ? sanitized : void 0;
552
+ }
553
+ function serializeError(error) {
554
+ if (error instanceof Error) {
555
+ const code = "code" in error && typeof error.code === "string" ? error.code : void 0;
556
+ return {
557
+ name: error.name || void 0,
558
+ message: error.message,
559
+ ...code !== void 0 && { code }
560
+ };
561
+ }
562
+ return { message: String(error) };
563
+ }
564
+ function handleSinkFailure(error, options) {
565
+ try {
566
+ options?.onError?.(error);
567
+ } catch {
568
+ }
569
+ }
570
+ function emitDroidLog(observability, event, options) {
571
+ const sink = observability?.logger;
572
+ if (!sink) {
573
+ return false;
574
+ }
575
+ try {
576
+ sink.log({
577
+ level: event.level,
578
+ name: event.name,
579
+ message: event.message,
580
+ attributes: sanitizeAttributes(event.attributes),
581
+ ...event.error !== void 0 && {
582
+ error: serializeError(event.error)
583
+ }
584
+ });
585
+ return true;
586
+ } catch (error) {
587
+ handleSinkFailure(error, options);
588
+ return false;
589
+ }
590
+ }
591
+ function recordDroidMetric(observability, event, options) {
592
+ const sink = observability?.metrics;
593
+ if (!sink) {
594
+ return false;
595
+ }
596
+ try {
597
+ sink.record({
598
+ name: event.name,
599
+ kind: event.kind,
600
+ value: event.value,
601
+ unit: event.unit,
602
+ attributes: sanitizeAttributes(event.attributes)
603
+ });
604
+ return true;
605
+ } catch (error) {
606
+ handleSinkFailure(error, options);
607
+ return false;
608
+ }
609
+ }
610
+ function injectDroidTraceContext(observability, carrier, options) {
611
+ const sink = observability?.tracing;
612
+ if (!sink) {
613
+ return false;
614
+ }
615
+ try {
616
+ sink.inject(carrier);
617
+ return true;
618
+ } catch (error) {
619
+ handleSinkFailure(error, options);
620
+ return false;
621
+ }
622
+ }
623
+
624
+ // src/exec-core/deps.ts
625
+ function logWarn(logger, message, metadata) {
626
+ logger.warn(message, metadata);
627
+ }
628
+
629
+ // src/exec-core/observability-adapter.ts
630
+ function createSinkFailureOptions(fallback) {
631
+ return {
632
+ onError(sinkError) {
633
+ logWarn(fallback, "[droid-sdk observability] customer sink threw", {
634
+ cause: sinkError
635
+ });
636
+ }
637
+ };
638
+ }
639
+ var CONTENT_BEARING_KEYS = ["output", "preview", "stderrTail"];
640
+ function redactContentForCustomerSink(metadata) {
641
+ if (metadata === void 0) {
642
+ return void 0;
643
+ }
644
+ let redacted;
645
+ for (const key of CONTENT_BEARING_KEYS) {
646
+ if (!(key in metadata)) {
647
+ continue;
648
+ }
649
+ redacted ??= { ...metadata };
650
+ const value = redacted[key];
651
+ delete redacted[key];
652
+ if (typeof value === "string") {
653
+ redacted[`${key}ByteLength`] = new TextEncoder().encode(value).byteLength;
654
+ }
655
+ }
656
+ return redacted ?? metadata;
657
+ }
658
+ function createLogger(observability, fallback) {
659
+ const sink = observability?.logger;
660
+ if (!sink) {
661
+ return fallback;
662
+ }
663
+ const sinkObservability = { logger: sink };
664
+ const sinkFailureOptions = createSinkFailureOptions(fallback);
665
+ return {
666
+ info(message, metadata) {
667
+ emitDroidLog(
668
+ sinkObservability,
669
+ {
670
+ level: "info",
671
+ name: "droid.sdk.info",
672
+ message,
673
+ attributes: redactContentForCustomerSink(metadata)
674
+ },
675
+ sinkFailureOptions
676
+ );
677
+ },
678
+ warn(message, metadata) {
679
+ emitDroidLog(
680
+ sinkObservability,
681
+ {
682
+ level: "warn",
683
+ name: "droid.sdk.warn",
684
+ message,
685
+ attributes: redactContentForCustomerSink(metadata)
686
+ },
687
+ sinkFailureOptions
688
+ );
689
+ },
690
+ exception(error, message, metadata) {
691
+ emitDroidLog(
692
+ sinkObservability,
693
+ {
694
+ level: "error",
695
+ name: "droid.sdk.error",
696
+ message,
697
+ attributes: redactContentForCustomerSink(metadata),
698
+ error
699
+ },
700
+ sinkFailureOptions
701
+ );
702
+ }
703
+ };
704
+ }
705
+ function createMetrics(observability, fallback, failureLogger) {
706
+ const sink = observability?.metrics;
707
+ if (!sink) {
708
+ return fallback;
709
+ }
710
+ const sinkObservability = { metrics: sink };
711
+ const sinkFailureOptions = createSinkFailureOptions(failureLogger);
712
+ return {
713
+ addToCounter(metric, value, tags) {
714
+ recordDroidMetric(
715
+ sinkObservability,
716
+ {
717
+ name: metric,
718
+ kind: "counter",
719
+ value,
720
+ unit: "1",
721
+ attributes: tags
722
+ },
723
+ sinkFailureOptions
724
+ );
725
+ },
726
+ recordDuration(metric, valueMs, tags) {
727
+ recordDroidMetric(
728
+ sinkObservability,
729
+ {
730
+ name: metric,
731
+ kind: "histogram",
732
+ value: valueMs,
733
+ unit: "ms",
734
+ attributes: tags
735
+ },
736
+ sinkFailureOptions
737
+ );
738
+ }
739
+ };
740
+ }
741
+ function createTracing(observability, fallback, failureLogger) {
742
+ const sink = observability?.tracing;
743
+ if (!sink) {
744
+ return fallback;
745
+ }
746
+ const sinkObservability = { tracing: sink };
747
+ const sinkFailureOptions = createSinkFailureOptions(failureLogger);
748
+ return {
749
+ getCurrentContext() {
750
+ return {};
751
+ },
752
+ injectContext(meta) {
753
+ const carrier = {};
754
+ if (!injectDroidTraceContext(sinkObservability, carrier, sinkFailureOptions)) {
755
+ return;
756
+ }
757
+ if (carrier.traceparent !== void 0) {
758
+ meta.traceparent = carrier.traceparent;
759
+ }
760
+ if (carrier.tracestate !== void 0) {
761
+ meta.tracestate = carrier.tracestate;
762
+ }
763
+ }
764
+ };
765
+ }
766
+ function resolveExecCoreDeps(observability, fallback = defaultExecCoreDeps) {
767
+ return {
768
+ logger: createLogger(observability, fallback.logger),
769
+ metrics: createMetrics(observability, fallback.metrics, fallback.logger),
770
+ tracing: createTracing(observability, fallback.tracing, fallback.logger),
771
+ commandResolver: fallback.commandResolver,
772
+ factoryPathResolver: fallback.factoryPathResolver,
773
+ environmentResolver: fallback.environmentResolver
774
+ };
775
+ }
776
+
777
+ // src/exec-core/client.ts
778
+ function getResponseId(response) {
779
+ const parsed = JsonRpcBaseResponseSchema.safeParse(response);
780
+ return parsed.success ? parsed.data.id : void 0;
781
+ }
782
+ var JsonRpcEnvelopePeekSchema = JsonRpcEnvelopeSchema.partial().extend({
783
+ type: z.nativeEnum(JsonRpcMessageType).optional(),
784
+ method: z.string().optional(),
785
+ id: z.string().nullable().optional()
786
+ }).passthrough();
787
+ function inspectJsonRpcEnvelope2(message) {
788
+ const result = JsonRpcEnvelopePeekSchema.safeParse(message);
789
+ if (!result.success) {
790
+ return { protocolVersionMismatch: null };
791
+ }
792
+ const envelope = result.data;
793
+ return {
794
+ protocolVersionMismatch: envelope.factoryProtocolVersion !== void 0 && envelope.factoryProtocolVersion !== FACTORY_PROTOCOL_VERSION ? {
795
+ localFactoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
796
+ peerFactoryProtocolVersion: envelope.factoryProtocolVersion,
797
+ messageType: envelope.type,
798
+ method: envelope.method,
799
+ requestId: envelope.id
800
+ } : null
801
+ };
802
+ }
803
+ var DroidClient = class _DroidClient extends EventEmitter {
804
+ transport;
805
+ requestTimeout;
806
+ sessionInitTimeout;
807
+ pendingRequests = /* @__PURE__ */ new Map();
808
+ permissionHandlers = /* @__PURE__ */ new Map();
809
+ askUserHandlers = /* @__PURE__ */ new Map();
810
+ pendingPermissionRequests = /* @__PURE__ */ new Map();
811
+ pendingAskUserRequests = /* @__PURE__ */ new Map();
812
+ currentSessionId = null;
813
+ peerProtocolVersion;
814
+ /**
815
+ * Sticky error from a transport failure. Once set, all subsequent
816
+ * `sendRequest()` calls throw this error immediately, preventing
817
+ * requests from hanging on a dead transport.
818
+ */
819
+ transportError = null;
820
+ completedTurnObserved = false;
821
+ logger;
822
+ tracing;
823
+ onRequestSettled;
824
+ constructor(options, deps = defaultExecCoreDeps) {
825
+ super();
826
+ this.transport = options.transport;
827
+ const resolved = resolveExecCoreDeps(options.observability, deps);
828
+ this.logger = resolved.logger;
829
+ this.tracing = resolved.tracing;
830
+ this.requestTimeout = options.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT2;
831
+ this.sessionInitTimeout = options.sessionInitTimeout ?? SESSION_INIT_TIMEOUT2;
832
+ this.onRequestSettled = options.onRequestSettled;
833
+ this.transport.onMessage((message) => {
834
+ void this.handleMessage(message).catch((error) => {
835
+ const err = error instanceof Error ? error : new Error(String(error));
836
+ this.emit(
837
+ "session_notification" /* SESSION_NOTIFICATION */,
838
+ _DroidClient.createNotificationEvent(
839
+ _DroidClient.createErrorNotification(err)
840
+ )
841
+ );
842
+ });
843
+ });
844
+ this.transport.onError((error) => {
845
+ const err = error instanceof Error ? error : new Error(String(error));
846
+ const expectedCleanExit = err instanceof ProcessExitError && err.exitCode === 0 && this.completedTurnObserved;
847
+ if (expectedCleanExit) {
848
+ this.logger.info("[DroidClient] Process exited after completed turn", {
849
+ exitCode: err.exitCode
850
+ });
851
+ } else {
852
+ this.logger.exception(err, "Transport error");
853
+ }
854
+ this.transportError = err;
855
+ this.rejectAllPending(err);
856
+ if (this.listenerCount("error" /* ERROR */) > 0) {
857
+ this.emit("error" /* ERROR */, err);
858
+ }
859
+ this.emit(
860
+ "session_notification" /* SESSION_NOTIFICATION */,
861
+ _DroidClient.createNotificationEvent(
862
+ _DroidClient.createErrorNotification(err)
863
+ )
864
+ );
865
+ });
866
+ }
867
+ get sessionId() {
868
+ return this.currentSessionId;
869
+ }
870
+ get isConnected() {
871
+ return this.transport.isConnected;
872
+ }
873
+ requireMcpOAuthOptOutSupport() {
874
+ if (this.peerProtocolVersion === FACTORY_PROTOCOL_VERSION) {
875
+ return;
876
+ }
877
+ throw new ProtocolError(
878
+ "MCP OAuth opt-out requires a confirmed matching Droid protocol version. The connected Droid reported an incompatible protocol version and cannot disable OAuth for MCP servers.",
879
+ {
880
+ value: {
881
+ localFactoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
882
+ peerFactoryProtocolVersion: this.peerProtocolVersion
883
+ }
884
+ }
885
+ );
886
+ }
887
+ validateMcpServersProtocolSupport(mcpServers) {
888
+ if (mcpServers?.some((server) => "oauth" in server && server.oauth === false)) {
889
+ this.requireMcpOAuthOptOutSupport();
890
+ }
891
+ }
892
+ async initializeSession(params) {
893
+ const request = {
894
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
895
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
896
+ type: "request",
897
+ jsonrpc: JSONRPC_VERSION2,
898
+ id: uuidv4(),
899
+ method: "droid.initialize_session" /* INITIALIZE_SESSION */,
900
+ params
901
+ };
902
+ const rawResponse = await this.sendRequest(
903
+ request,
904
+ this.sessionInitTimeout
905
+ );
906
+ const response = InitializeSessionResponseSchema.parse(rawResponse);
907
+ this.peerProtocolVersion = response.factoryProtocolVersion;
908
+ if (response.error) {
909
+ throw new ProtocolError("Initialize session request failed", {
910
+ requestId: request.id,
911
+ code: response.error.code,
912
+ message: response.error.message,
913
+ data: response.error.data
914
+ });
915
+ }
916
+ this.validateMcpServersProtocolSupport(params.mcpServers);
917
+ const result = InitializeSessionResultSchema.parse(response.result);
918
+ this.currentSessionId = result.sessionId;
919
+ return response;
920
+ }
921
+ async loadSession(params) {
922
+ const request = {
923
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
924
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
925
+ type: "request",
926
+ jsonrpc: JSONRPC_VERSION2,
927
+ id: uuidv4(),
928
+ method: "droid.load_session" /* LOAD_SESSION */,
929
+ params
930
+ };
931
+ const rawResponse = await this.sendRequest(
932
+ request,
933
+ this.sessionInitTimeout
934
+ );
935
+ const response = LoadSessionResponseSchema.parse(rawResponse);
936
+ this.peerProtocolVersion = response.factoryProtocolVersion;
937
+ if (response.error) {
938
+ const isSessionNotFound = response.error.code === -32004 /* ENTITY_NOT_FOUND */;
939
+ if (isSessionNotFound) {
940
+ throw new SessionNotFoundError(params.sessionId, {
941
+ requestId: request.id,
942
+ code: response.error.code,
943
+ message: response.error.message,
944
+ data: response.error.data
945
+ });
946
+ }
947
+ throw new ProtocolError("Load session request failed", {
948
+ requestId: request.id,
949
+ code: response.error.code,
950
+ message: response.error.message,
951
+ data: response.error.data
952
+ });
953
+ }
954
+ this.validateMcpServersProtocolSupport(params.mcpServers);
955
+ this.currentSessionId = params.sessionId;
956
+ return response;
957
+ }
958
+ async addUserMessage(params, requestId) {
959
+ if (!this.currentSessionId) {
960
+ throw new SessionError(
961
+ "No active session. Call initializeSession or loadSession first."
962
+ );
963
+ }
964
+ this.completedTurnObserved = false;
965
+ const request = {
966
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
967
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
968
+ type: "request",
969
+ jsonrpc: JSONRPC_VERSION2,
970
+ id: requestId ?? uuidv4(),
971
+ method: "droid.add_user_message" /* ADD_USER_MESSAGE */,
972
+ params: {
973
+ ...params.messageId && { messageId: params.messageId },
974
+ text: params.text,
975
+ images: params.images,
976
+ imagePaths: params.imagePaths,
977
+ files: params.files,
978
+ outputFormat: params.outputFormat,
979
+ ...params.skipAgentLoop && { skipAgentLoop: params.skipAgentLoop },
980
+ queuePlacement: params.queuePlacement ?? "end_of_turn" /* EndOfTurn */,
981
+ ...params.role && { role: params.role },
982
+ ...params.visibility && { visibility: params.visibility }
983
+ }
984
+ };
985
+ const rawResponse = await this.sendRequest(request);
986
+ const response = AddUserMessageResponseSchema.parse(rawResponse);
987
+ if (response.error) {
988
+ throw new ProtocolError("Add user message request failed", {
989
+ requestId: request.id,
990
+ code: response.error.code,
991
+ message: response.error.message,
992
+ data: response.error.data
993
+ });
994
+ }
995
+ return response;
996
+ }
997
+ /**
998
+ * Persists user-only messages without starting an agent turn.
999
+ *
1000
+ * Use for daemon-owned activity that belongs in session history but was not
1001
+ * produced by the agent, such as commands run while a session starts.
1002
+ */
1003
+ async appendMessages(params, requestId) {
1004
+ if (!this.currentSessionId) {
1005
+ throw new SessionError(
1006
+ "No active session. Call initializeSession or loadSession first."
1007
+ );
1008
+ }
1009
+ const request = {
1010
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1011
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1012
+ type: "request",
1013
+ jsonrpc: JSONRPC_VERSION2,
1014
+ id: requestId ?? uuidv4(),
1015
+ method: "droid.append_messages" /* APPEND_MESSAGES */,
1016
+ params
1017
+ };
1018
+ const rawResponse = await this.sendRequest(request);
1019
+ const response = AppendMessagesResponseSchema.parse(rawResponse);
1020
+ if (response.error) {
1021
+ throw new ProtocolError("Append messages request failed", {
1022
+ requestId: request.id,
1023
+ code: response.error.code,
1024
+ message: response.error.message,
1025
+ data: response.error.data
1026
+ });
1027
+ }
1028
+ return response;
1029
+ }
1030
+ async resolveQueuedUserMessage(params) {
1031
+ if (!this.currentSessionId) {
1032
+ throw new SessionError(
1033
+ "No active session. Call initializeSession or loadSession first."
1034
+ );
1035
+ }
1036
+ const request = {
1037
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1038
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1039
+ type: "request",
1040
+ jsonrpc: JSONRPC_VERSION2,
1041
+ id: uuidv4(),
1042
+ method: "droid.resolve_queued_user_message" /* RESOLVE_QUEUED_USER_MESSAGE */,
1043
+ params
1044
+ };
1045
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1046
+ const response = ResolveQueuedUserMessageResponseSchema.parse(rawResponse);
1047
+ if (response.error) {
1048
+ throw new ProtocolError("Resolve queued user message request failed", {
1049
+ requestId: request.id,
1050
+ code: response.error.code,
1051
+ message: response.error.message,
1052
+ data: response.error.data
1053
+ });
1054
+ }
1055
+ return response;
1056
+ }
1057
+ async interruptSession(params = {}) {
1058
+ if (!this.currentSessionId) {
1059
+ throw new SessionError(
1060
+ "No active session. Call initializeSession or loadSession first."
1061
+ );
1062
+ }
1063
+ const request = {
1064
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1065
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1066
+ type: "request",
1067
+ jsonrpc: JSONRPC_VERSION2,
1068
+ id: uuidv4(),
1069
+ method: "droid.interrupt_session" /* INTERRUPT_SESSION */,
1070
+ params
1071
+ };
1072
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1073
+ const response = InterruptSessionResponseSchema.parse(rawResponse);
1074
+ if (response.error) {
1075
+ throw new ProtocolError("Interrupt session request failed", {
1076
+ requestId: request.id,
1077
+ code: response.error.code,
1078
+ message: response.error.message,
1079
+ data: response.error.data
1080
+ });
1081
+ }
1082
+ return response;
1083
+ }
1084
+ async closeSession(params = {}) {
1085
+ if (!this.currentSessionId) {
1086
+ throw new SessionError(
1087
+ "No active session. Call initializeSession or loadSession first."
1088
+ );
1089
+ }
1090
+ const request = {
1091
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1092
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1093
+ type: "request",
1094
+ jsonrpc: JSONRPC_VERSION2,
1095
+ id: uuidv4(),
1096
+ method: "droid.close_session" /* CLOSE_SESSION */,
1097
+ params
1098
+ };
1099
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1100
+ const response = CloseSessionResponseSchema.parse(rawResponse);
1101
+ if (response.error) {
1102
+ throw new ProtocolError("Close session request failed", {
1103
+ requestId: request.id,
1104
+ code: response.error.code,
1105
+ message: response.error.message,
1106
+ data: response.error.data
1107
+ });
1108
+ }
1109
+ return response;
1110
+ }
1111
+ async killWorkerSession(params) {
1112
+ if (!this.currentSessionId) {
1113
+ throw new SessionError(
1114
+ "No active session. Call initializeSession or loadSession first."
1115
+ );
1116
+ }
1117
+ const request = {
1118
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1119
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1120
+ type: "request",
1121
+ jsonrpc: JSONRPC_VERSION2,
1122
+ id: uuidv4(),
1123
+ method: "droid.kill_worker_session" /* KILL_WORKER_SESSION */,
1124
+ params
1125
+ };
1126
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1127
+ const response = KillWorkerSessionResponseSchema.parse(rawResponse);
1128
+ if (response.error) {
1129
+ throw new ProtocolError("Kill worker session request failed", {
1130
+ requestId: request.id,
1131
+ code: response.error.code,
1132
+ message: response.error.message,
1133
+ data: response.error.data
1134
+ });
1135
+ }
1136
+ return response;
1137
+ }
1138
+ async updateSessionSettings(params, requestId) {
1139
+ if (!this.currentSessionId) {
1140
+ throw new SessionError(
1141
+ "No active session. Call initializeSession or loadSession first."
1142
+ );
1143
+ }
1144
+ const request = {
1145
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1146
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1147
+ type: "request",
1148
+ jsonrpc: JSONRPC_VERSION2,
1149
+ id: requestId ?? uuidv4(),
1150
+ method: "droid.update_session_settings" /* UPDATE_SESSION_SETTINGS */,
1151
+ params
1152
+ };
1153
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1154
+ const responseParsed = UpdateSessionSettingsResponseSchema.safeParse(rawResponse);
1155
+ if (!responseParsed.success) {
1156
+ throw new ProtocolError(
1157
+ "Invalid update session settings response format",
1158
+ {
1159
+ requestId: request.id,
1160
+ code: -32700 /* PARSE_ERROR */,
1161
+ message: responseParsed.error.message,
1162
+ data: rawResponse
1163
+ }
1164
+ );
1165
+ }
1166
+ const response = responseParsed.data;
1167
+ if (response.error) {
1168
+ throw new ProtocolError("Update session settings request failed", {
1169
+ requestId: request.id,
1170
+ code: response.error.code,
1171
+ message: response.error.message,
1172
+ data: response.error.data
1173
+ });
1174
+ }
1175
+ return response;
1176
+ }
1177
+ async changeWorkingDirectory(params) {
1178
+ if (!this.currentSessionId) {
1179
+ throw new SessionError(
1180
+ "No active session. Call initializeSession or loadSession first."
1181
+ );
1182
+ }
1183
+ const request = {
1184
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1185
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1186
+ type: "request",
1187
+ jsonrpc: JSONRPC_VERSION2,
1188
+ id: uuidv4(),
1189
+ method: "droid.change_working_directory" /* CHANGE_WORKING_DIRECTORY */,
1190
+ params
1191
+ };
1192
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1193
+ const response = ChangeWorkingDirectoryResponseSchema.parse(rawResponse);
1194
+ if (response.error) {
1195
+ throw new ProtocolError("Change working directory request failed", {
1196
+ requestId: request.id,
1197
+ code: response.error.code,
1198
+ message: response.error.message,
1199
+ data: response.error.data
1200
+ });
1201
+ }
1202
+ return response;
1203
+ }
1204
+ async toggleMcpServer(params) {
1205
+ if (!this.currentSessionId) {
1206
+ throw new SessionError(
1207
+ "No active session. Call initializeSession or loadSession first."
1208
+ );
1209
+ }
1210
+ const request = {
1211
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1212
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1213
+ type: "request",
1214
+ jsonrpc: JSONRPC_VERSION2,
1215
+ id: uuidv4(),
1216
+ method: "droid.toggle_mcp_server" /* TOGGLE_MCP_SERVER */,
1217
+ params: {
1218
+ serverName: params.serverName,
1219
+ enabled: params.enabled,
1220
+ settingsLevel: params.settingsLevel
1221
+ }
1222
+ };
1223
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1224
+ const response = ToggleMcpServerResponseSchema.parse(rawResponse);
1225
+ return response;
1226
+ }
1227
+ async authenticateMcpServer(params) {
1228
+ if (!this.currentSessionId) {
1229
+ throw new SessionError(
1230
+ "No active session. Call initializeSession or loadSession first."
1231
+ );
1232
+ }
1233
+ const request = {
1234
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1235
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1236
+ type: "request",
1237
+ jsonrpc: JSONRPC_VERSION2,
1238
+ id: uuidv4(),
1239
+ method: "droid.authenticate_mcp_server" /* AUTHENTICATE_MCP_SERVER */,
1240
+ params: {
1241
+ serverName: params.serverName
1242
+ }
1243
+ };
1244
+ const rawResponse = await this.sendRequest(request, MCP_AUTH_TIMEOUT2);
1245
+ const response = AuthenticateMcpServerResponseSchema.parse(rawResponse);
1246
+ return response;
1247
+ }
1248
+ async cancelMcpAuth(params) {
1249
+ if (!this.currentSessionId) {
1250
+ throw new SessionError(
1251
+ "No active session. Call initializeSession or loadSession first."
1252
+ );
1253
+ }
1254
+ const request = {
1255
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1256
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1257
+ type: "request",
1258
+ jsonrpc: JSONRPC_VERSION2,
1259
+ id: uuidv4(),
1260
+ method: "droid.cancel_mcp_auth" /* CANCEL_MCP_AUTH */,
1261
+ params: {
1262
+ serverName: params.serverName
1263
+ }
1264
+ };
1265
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1266
+ const response = CancelMcpAuthResponseSchema.parse(rawResponse);
1267
+ return response;
1268
+ }
1269
+ async clearMcpAuth(params) {
1270
+ if (!this.currentSessionId) {
1271
+ throw new SessionError(
1272
+ "No active session. Call initializeSession or loadSession first."
1273
+ );
1274
+ }
1275
+ const request = {
1276
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1277
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1278
+ type: "request",
1279
+ jsonrpc: JSONRPC_VERSION2,
1280
+ id: uuidv4(),
1281
+ method: "droid.clear_mcp_auth" /* CLEAR_MCP_AUTH */,
1282
+ params: {
1283
+ serverName: params.serverName
1284
+ }
1285
+ };
1286
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1287
+ const response = ClearMcpAuthResponseSchema.parse(rawResponse);
1288
+ return response;
1289
+ }
1290
+ async addMcpServer(params) {
1291
+ if (!this.currentSessionId) {
1292
+ throw new SessionError(
1293
+ "No active session. Call initializeSession or loadSession first."
1294
+ );
1295
+ }
1296
+ if (params.oauth === false) {
1297
+ this.requireMcpOAuthOptOutSupport();
1298
+ }
1299
+ const request = {
1300
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1301
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1302
+ type: "request",
1303
+ jsonrpc: JSONRPC_VERSION2,
1304
+ id: uuidv4(),
1305
+ method: "droid.add_mcp_server" /* ADD_MCP_SERVER */,
1306
+ params
1307
+ };
1308
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1309
+ const response = AddMcpServerResponseSchema.parse(rawResponse);
1310
+ return response;
1311
+ }
1312
+ async removeMcpServer(params) {
1313
+ if (!this.currentSessionId) {
1314
+ throw new SessionError(
1315
+ "No active session. Call initializeSession or loadSession first."
1316
+ );
1317
+ }
1318
+ const request = {
1319
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1320
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1321
+ type: "request",
1322
+ jsonrpc: JSONRPC_VERSION2,
1323
+ id: uuidv4(),
1324
+ method: "droid.remove_mcp_server" /* REMOVE_MCP_SERVER */,
1325
+ params
1326
+ };
1327
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1328
+ const response = RemoveMcpServerResponseSchema.parse(rawResponse);
1329
+ return response;
1330
+ }
1331
+ async listModels(params = {}) {
1332
+ const request = {
1333
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1334
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1335
+ type: "request",
1336
+ jsonrpc: JSONRPC_VERSION2,
1337
+ id: uuidv4(),
1338
+ method: "droid.list_models" /* LIST_MODELS */,
1339
+ params
1340
+ };
1341
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1342
+ return ListModelsResponseSchema.parse(rawResponse);
1343
+ }
1344
+ async listMcpRegistry() {
1345
+ if (!this.currentSessionId) {
1346
+ throw new SessionError(
1347
+ "No active session. Call initializeSession or loadSession first."
1348
+ );
1349
+ }
1350
+ const request = {
1351
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1352
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1353
+ type: "request",
1354
+ jsonrpc: JSONRPC_VERSION2,
1355
+ id: uuidv4(),
1356
+ method: "droid.list_mcp_registry" /* LIST_MCP_REGISTRY */,
1357
+ params: {}
1358
+ };
1359
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1360
+ const response = ListMcpRegistryResponseSchema.parse(rawResponse);
1361
+ return response;
1362
+ }
1363
+ async listMcpTools() {
1364
+ if (!this.currentSessionId) {
1365
+ throw new SessionError(
1366
+ "No active session. Call initializeSession or loadSession first."
1367
+ );
1368
+ }
1369
+ const request = {
1370
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1371
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1372
+ type: "request",
1373
+ jsonrpc: JSONRPC_VERSION2,
1374
+ id: uuidv4(),
1375
+ method: "droid.list_mcp_tools" /* LIST_MCP_TOOLS */,
1376
+ params: {}
1377
+ };
1378
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1379
+ const response = ListMcpToolsResponseSchema.parse(rawResponse);
1380
+ return response;
1381
+ }
1382
+ async listTools(params = {}) {
1383
+ const request = {
1384
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1385
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1386
+ type: "request",
1387
+ jsonrpc: JSONRPC_VERSION2,
1388
+ id: uuidv4(),
1389
+ method: "droid.list_tools" /* LIST_TOOLS */,
1390
+ params
1391
+ };
1392
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1393
+ const response = ListToolsResponseSchema.parse(rawResponse);
1394
+ return response;
1395
+ }
1396
+ async listMcpServers() {
1397
+ if (!this.currentSessionId) {
1398
+ throw new SessionError(
1399
+ "No active session. Call initializeSession or loadSession first."
1400
+ );
1401
+ }
1402
+ const request = {
1403
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1404
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1405
+ type: "request",
1406
+ jsonrpc: JSONRPC_VERSION2,
1407
+ id: uuidv4(),
1408
+ method: "droid.list_mcp_servers" /* LIST_MCP_SERVERS */,
1409
+ params: {}
1410
+ };
1411
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1412
+ const response = ListMcpServersResponseSchema.parse(rawResponse);
1413
+ return response;
1414
+ }
1415
+ async toggleMcpTool(serverName, toolName, enabled) {
1416
+ if (!this.currentSessionId) {
1417
+ throw new SessionError(
1418
+ "No active session. Call initializeSession or loadSession first."
1419
+ );
1420
+ }
1421
+ const request = {
1422
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1423
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1424
+ type: "request",
1425
+ jsonrpc: JSONRPC_VERSION2,
1426
+ id: uuidv4(),
1427
+ method: "droid.toggle_mcp_tool" /* TOGGLE_MCP_TOOL */,
1428
+ params: { serverName, toolName, enabled }
1429
+ };
1430
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1431
+ const response = ToggleMcpToolResponseSchema.parse(rawResponse);
1432
+ return response;
1433
+ }
1434
+ async submitMcpAuthCode(params) {
1435
+ if (!this.currentSessionId) {
1436
+ throw new SessionError(
1437
+ "No active session. Call initializeSession or loadSession first."
1438
+ );
1439
+ }
1440
+ const request = {
1441
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1442
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1443
+ type: "request",
1444
+ jsonrpc: JSONRPC_VERSION2,
1445
+ id: uuidv4(),
1446
+ method: "droid.submit_mcp_auth_code" /* SUBMIT_MCP_AUTH_CODE */,
1447
+ params
1448
+ };
1449
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1450
+ const response = SubmitMcpAuthCodeResponseSchema.parse(rawResponse);
1451
+ return response;
1452
+ }
1453
+ async submitMcpAuthError(params) {
1454
+ if (!this.currentSessionId) {
1455
+ throw new SessionError(
1456
+ "No active session. Call initializeSession or loadSession first."
1457
+ );
1458
+ }
1459
+ const request = {
1460
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1461
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1462
+ type: "request",
1463
+ jsonrpc: JSONRPC_VERSION2,
1464
+ id: uuidv4(),
1465
+ method: "droid.submit_mcp_auth_error" /* SUBMIT_MCP_AUTH_ERROR */,
1466
+ params
1467
+ };
1468
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1469
+ const response = SubmitMcpAuthErrorResponseSchema.parse(rawResponse);
1470
+ return response;
1471
+ }
1472
+ async listSkills() {
1473
+ if (!this.currentSessionId) {
1474
+ throw new SessionError(
1475
+ "No active session. Call initializeSession or loadSession first."
1476
+ );
1477
+ }
1478
+ const request = {
1479
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1480
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1481
+ type: "request",
1482
+ jsonrpc: JSONRPC_VERSION2,
1483
+ id: uuidv4(),
1484
+ method: "droid.list_skills" /* LIST_SKILLS */,
1485
+ params: {}
1486
+ };
1487
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1488
+ const response = ListSkillsResponseSchema.parse(rawResponse);
1489
+ return response;
1490
+ }
1491
+ async setSkillDisabled(skillName, disabled, settingsLevel) {
1492
+ if (!this.currentSessionId) {
1493
+ throw new SessionError(
1494
+ "No active session. Call initializeSession or loadSession first."
1495
+ );
1496
+ }
1497
+ const request = {
1498
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1499
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1500
+ type: "request",
1501
+ jsonrpc: JSONRPC_VERSION2,
1502
+ id: uuidv4(),
1503
+ method: "droid.set_skill_disabled" /* SET_SKILL_DISABLED */,
1504
+ params: { skillName, disabled, settingsLevel }
1505
+ };
1506
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1507
+ return SetSkillDisabledResponseSchema.parse(rawResponse);
1508
+ }
1509
+ async listCommands() {
1510
+ if (!this.currentSessionId) {
1511
+ throw new SessionError(
1512
+ "No active session. Call initializeSession or loadSession first."
1513
+ );
1514
+ }
1515
+ const request = {
1516
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1517
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1518
+ type: "request",
1519
+ jsonrpc: JSONRPC_VERSION2,
1520
+ id: uuidv4(),
1521
+ method: "droid.list_commands" /* LIST_COMMANDS */,
1522
+ params: {}
1523
+ };
1524
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1525
+ const response = ListCommandsResponseSchema.parse(rawResponse);
1526
+ return response;
1527
+ }
1528
+ async getContextStats() {
1529
+ if (!this.currentSessionId) {
1530
+ throw new SessionError(
1531
+ "No active session. Call initializeSession or loadSession first."
1532
+ );
1533
+ }
1534
+ const request = {
1535
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1536
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1537
+ type: "request",
1538
+ jsonrpc: JSONRPC_VERSION2,
1539
+ id: uuidv4(),
1540
+ method: "droid.get_context_stats" /* GET_CONTEXT_STATS */,
1541
+ params: {}
1542
+ };
1543
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1544
+ const response = GetContextStatsResponseSchema.parse(rawResponse);
1545
+ return response;
1546
+ }
1547
+ async getContextBreakdown() {
1548
+ if (!this.currentSessionId) {
1549
+ throw new SessionError(
1550
+ "No active session. Call initializeSession or loadSession first."
1551
+ );
1552
+ }
1553
+ const request = {
1554
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1555
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1556
+ type: "request",
1557
+ jsonrpc: JSONRPC_VERSION2,
1558
+ id: uuidv4(),
1559
+ method: "droid.get_context_breakdown" /* GET_CONTEXT_BREAKDOWN */,
1560
+ params: {}
1561
+ };
1562
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1563
+ const response = GetContextBreakdownResponseSchema.parse(rawResponse);
1564
+ return response;
1565
+ }
1566
+ async submitBugReport(userComment, clientLogs, source) {
1567
+ if (!this.currentSessionId) {
1568
+ throw new SessionError(
1569
+ "No active session. Call initializeSession or loadSession first."
1570
+ );
1571
+ }
1572
+ const request = {
1573
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1574
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1575
+ type: "request",
1576
+ jsonrpc: JSONRPC_VERSION2,
1577
+ id: uuidv4(),
1578
+ method: "droid.submit_bug_report" /* SUBMIT_BUG_REPORT */,
1579
+ params: { userComment, clientLogs, source }
1580
+ };
1581
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1582
+ const response = SubmitBugReportResponseSchema.parse(rawResponse);
1583
+ return response;
1584
+ }
1585
+ async getRewindInfo(params, timeout = this.requestTimeout) {
1586
+ if (!this.currentSessionId) {
1587
+ throw new SessionError(
1588
+ "No active session. Call initializeSession or loadSession first."
1589
+ );
1590
+ }
1591
+ const request = {
1592
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1593
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1594
+ type: "request",
1595
+ jsonrpc: JSONRPC_VERSION2,
1596
+ id: uuidv4(),
1597
+ method: "droid.get_rewind_info" /* GET_REWIND_INFO */,
1598
+ params: {
1599
+ sessionId: this.currentSessionId,
1600
+ messageId: params.messageId
1601
+ }
1602
+ };
1603
+ const rawResponse = await this.sendRequest(request, timeout);
1604
+ return GetRewindInfoResponseSchema.parse(rawResponse);
1605
+ }
1606
+ async executeRewind(params) {
1607
+ if (!this.currentSessionId) {
1608
+ throw new SessionError(
1609
+ "No active session. Call initializeSession or loadSession first."
1610
+ );
1611
+ }
1612
+ const request = {
1613
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1614
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1615
+ type: "request",
1616
+ jsonrpc: JSONRPC_VERSION2,
1617
+ id: uuidv4(),
1618
+ method: "droid.execute_rewind" /* EXECUTE_REWIND */,
1619
+ params: {
1620
+ sessionId: this.currentSessionId,
1621
+ messageId: params.messageId,
1622
+ filesToRestore: params.filesToRestore,
1623
+ filesToDelete: params.filesToDelete,
1624
+ forkTitle: params.forkTitle
1625
+ }
1626
+ };
1627
+ const rawResponse = await this.sendRequest(
1628
+ request,
1629
+ this.requestTimeout * 2
1630
+ );
1631
+ return ExecuteRewindResponseSchema.parse(rawResponse);
1632
+ }
1633
+ async compactSession(params) {
1634
+ if (!this.currentSessionId) {
1635
+ throw new SessionError(
1636
+ "No active session. Call initializeSession or loadSession first."
1637
+ );
1638
+ }
1639
+ const request = {
1640
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1641
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1642
+ type: "request",
1643
+ jsonrpc: JSONRPC_VERSION2,
1644
+ id: uuidv4(),
1645
+ method: "droid.compact_session" /* COMPACT_SESSION */,
1646
+ params: {
1647
+ customInstructions: params.customInstructions
1648
+ }
1649
+ };
1650
+ const rawResponse = await this.sendRequest(request, COMPACTION_TIMEOUT2);
1651
+ return CompactSessionResponseSchema.parse(rawResponse);
1652
+ }
1653
+ async forkSession(params) {
1654
+ if (!this.currentSessionId) {
1655
+ throw new SessionError(
1656
+ "No active session. Call initializeSession or loadSession first."
1657
+ );
1658
+ }
1659
+ const request = {
1660
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1661
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1662
+ type: "request",
1663
+ jsonrpc: JSONRPC_VERSION2,
1664
+ id: uuidv4(),
1665
+ method: "droid.fork_session" /* FORK_SESSION */,
1666
+ params: params ?? {}
1667
+ };
1668
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1669
+ return ForkSessionResponseSchema.parse(rawResponse);
1670
+ }
1671
+ async renameSession(params, requestId) {
1672
+ if (!this.currentSessionId) {
1673
+ throw new SessionError(
1674
+ "No active session. Call initializeSession or loadSession first."
1675
+ );
1676
+ }
1677
+ const request = {
1678
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1679
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1680
+ type: "request",
1681
+ jsonrpc: JSONRPC_VERSION2,
1682
+ id: requestId ?? uuidv4(),
1683
+ method: "droid.rename_session" /* RENAME_SESSION */,
1684
+ params: {
1685
+ title: params.title
1686
+ }
1687
+ };
1688
+ const rawResponse = await this.sendRequest(request, this.requestTimeout);
1689
+ return RenameSessionResponseSchema.parse(rawResponse);
1690
+ }
1691
+ async warmupCache() {
1692
+ const response = {
1693
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
1694
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
1695
+ type: "response",
1696
+ jsonrpc: JSONRPC_VERSION2,
1697
+ id: uuidv4(),
1698
+ result: {}
1699
+ };
1700
+ return WarmupCacheResponseSchema.parse(response);
1701
+ }
1702
+ onNotification(callback, filter) {
1703
+ const handler = (notification) => {
1704
+ if (filter?.type !== void 0 && filter.type !== notification.params.notification.type) {
1705
+ return;
1706
+ }
1707
+ try {
1708
+ callback(notification);
1709
+ } catch {
1710
+ }
1711
+ };
1712
+ this.on("session_notification" /* SESSION_NOTIFICATION */, handler);
1713
+ return () => this.off("session_notification" /* SESSION_NOTIFICATION */, handler);
1714
+ }
1715
+ onError(callback) {
1716
+ const handler = (error) => {
1717
+ try {
1718
+ callback(error);
1719
+ } catch {
1720
+ }
1721
+ };
1722
+ this.on("error" /* ERROR */, handler);
1723
+ if (this.transportError) {
1724
+ handler(this.transportError);
1725
+ }
1726
+ return () => this.off("error" /* ERROR */, handler);
1727
+ }
1728
+ setPermissionHandler(handler) {
1729
+ this.permissionHandlers.set(
1730
+ "default",
1731
+ async (event) => await handler(event)
1732
+ );
1733
+ }
1734
+ clearPermissionHandler() {
1735
+ this.permissionHandlers.delete("default");
1736
+ }
1737
+ setAskUserHandler(handler) {
1738
+ this.askUserHandlers.set("default", async (event) => await handler(event));
1739
+ }
1740
+ clearAskUserHandler() {
1741
+ this.askUserHandlers.delete("default");
1742
+ }
1743
+ async close() {
1744
+ const closeError = new ConnectionError(
1745
+ "Droid client closed: pending requests cancelled"
1746
+ );
1747
+ this.rejectAllPending(closeError);
1748
+ this.permissionHandlers.clear();
1749
+ this.askUserHandlers.clear();
1750
+ this.removeAllListeners();
1751
+ await this.transport.close();
1752
+ }
1753
+ rejectAllPending(error) {
1754
+ this.pendingRequests.forEach(({ timeoutId, reject }, requestId) => {
1755
+ if (timeoutId) {
1756
+ clearTimeout(timeoutId);
1757
+ }
1758
+ reject(error);
1759
+ this.notifyRequestSettled(requestId);
1760
+ });
1761
+ this.pendingRequests.clear();
1762
+ this.pendingPermissionRequests.forEach(({ reject }) => {
1763
+ reject(error);
1764
+ });
1765
+ this.pendingPermissionRequests.clear();
1766
+ this.pendingAskUserRequests.forEach(({ reject }) => {
1767
+ reject(error);
1768
+ });
1769
+ this.pendingAskUserRequests.clear();
1770
+ }
1771
+ settleRequest(requestId) {
1772
+ this.pendingRequests.delete(requestId);
1773
+ this.notifyRequestSettled(requestId);
1774
+ }
1775
+ notifyRequestSettled(requestId) {
1776
+ try {
1777
+ this.onRequestSettled?.(requestId);
1778
+ } catch {
1779
+ }
1780
+ }
1781
+ async sendRequest(request, timeout) {
1782
+ if (this.transportError) {
1783
+ throw this.transportError;
1784
+ }
1785
+ const responsePromise = new Promise(
1786
+ (resolve2, reject) => {
1787
+ const timeoutId = timeout ? setTimeout(() => {
1788
+ this.settleRequest(request.id);
1789
+ reject(
1790
+ new TimeoutError("Send request timed out", {
1791
+ requestId: request.id,
1792
+ method: request.method,
1793
+ timeout
1794
+ })
1795
+ );
1796
+ }, timeout) : void 0;
1797
+ this.pendingRequests.set(request.id, {
1798
+ method: request.method,
1799
+ resolve: resolve2,
1800
+ reject,
1801
+ timeoutId
1802
+ });
1803
+ }
1804
+ );
1805
+ const _meta = {};
1806
+ this.tracing.injectContext(_meta, this.tracing.getCurrentContext());
1807
+ const requestWithMeta = _meta.traceparent ? { ...request, _meta } : request;
1808
+ try {
1809
+ this.logger.info("[DroidClient] [daemon -> droid] sending request", {
1810
+ requestId: request.id,
1811
+ method: request.method
1812
+ });
1813
+ await this.transport.send(JSON.stringify(requestWithMeta));
1814
+ } catch (error) {
1815
+ const pending = this.pendingRequests.get(request.id);
1816
+ if (pending) {
1817
+ if (pending.timeoutId) {
1818
+ clearTimeout(pending.timeoutId);
1819
+ }
1820
+ this.settleRequest(request.id);
1821
+ pending.reject(
1822
+ new ProtocolError("[daemon -> droid] Failed to send request", {
1823
+ requestId: request.id,
1824
+ cause: error
1825
+ })
1826
+ );
1827
+ }
1828
+ }
1829
+ return responsePromise;
1830
+ }
1831
+ async handleMessage(message) {
1832
+ try {
1833
+ const parsed = JSON.parse(message);
1834
+ if ("result" in parsed || "error" in parsed) {
1835
+ this.handleResponse(parsed);
1836
+ } else if ("method" in parsed) {
1837
+ await this.handleEvent(parsed);
1838
+ } else {
1839
+ throw new ProtocolError("Invalid message format", {
1840
+ message
1841
+ });
1842
+ }
1843
+ } catch {
1844
+ this.logger.warn("[DroidClient] Failed to handle message", {
1845
+ messageByteLength: new TextEncoder().encode(message).byteLength
1846
+ });
1847
+ }
1848
+ }
1849
+ handleResponse(response) {
1850
+ try {
1851
+ const responseId = getResponseId(response);
1852
+ if (responseId !== null && responseId !== void 0) {
1853
+ const pending = this.pendingRequests.get(responseId);
1854
+ if (pending) {
1855
+ let validatedResponse;
1856
+ switch (pending.method) {
1857
+ case "droid.initialize_session" /* INITIALIZE_SESSION */:
1858
+ validatedResponse = InitializeSessionResponseSchema.parse(response);
1859
+ break;
1860
+ case "droid.load_session" /* LOAD_SESSION */:
1861
+ validatedResponse = LoadSessionResponseSchema.parse(response);
1862
+ break;
1863
+ case "droid.add_user_message" /* ADD_USER_MESSAGE */:
1864
+ validatedResponse = AddUserMessageResponseSchema.parse(response);
1865
+ break;
1866
+ case "droid.append_messages" /* APPEND_MESSAGES */:
1867
+ validatedResponse = AppendMessagesResponseSchema.parse(response);
1868
+ break;
1869
+ case "droid.resolve_queued_user_message" /* RESOLVE_QUEUED_USER_MESSAGE */:
1870
+ validatedResponse = ResolveQueuedUserMessageResponseSchema.parse(response);
1871
+ break;
1872
+ case "droid.interrupt_session" /* INTERRUPT_SESSION */:
1873
+ validatedResponse = InterruptSessionResponseSchema.parse(response);
1874
+ break;
1875
+ case "droid.close_session" /* CLOSE_SESSION */:
1876
+ validatedResponse = CloseSessionResponseSchema.parse(response);
1877
+ break;
1878
+ case "droid.update_session_settings" /* UPDATE_SESSION_SETTINGS */:
1879
+ validatedResponse = UpdateSessionSettingsResponseSchema.parse(response);
1880
+ break;
1881
+ case "droid.change_working_directory" /* CHANGE_WORKING_DIRECTORY */:
1882
+ validatedResponse = ChangeWorkingDirectoryResponseSchema.parse(response);
1883
+ break;
1884
+ case "droid.toggle_mcp_server" /* TOGGLE_MCP_SERVER */:
1885
+ validatedResponse = ToggleMcpServerResponseSchema.parse(response);
1886
+ break;
1887
+ case "droid.authenticate_mcp_server" /* AUTHENTICATE_MCP_SERVER */:
1888
+ validatedResponse = AuthenticateMcpServerResponseSchema.parse(response);
1889
+ break;
1890
+ case "droid.cancel_mcp_auth" /* CANCEL_MCP_AUTH */:
1891
+ validatedResponse = CancelMcpAuthResponseSchema.parse(response);
1892
+ break;
1893
+ case "droid.clear_mcp_auth" /* CLEAR_MCP_AUTH */:
1894
+ validatedResponse = ClearMcpAuthResponseSchema.parse(response);
1895
+ break;
1896
+ case "droid.add_mcp_server" /* ADD_MCP_SERVER */:
1897
+ validatedResponse = AddMcpServerResponseSchema.parse(response);
1898
+ break;
1899
+ case "droid.remove_mcp_server" /* REMOVE_MCP_SERVER */:
1900
+ validatedResponse = RemoveMcpServerResponseSchema.parse(response);
1901
+ break;
1902
+ case "droid.list_models" /* LIST_MODELS */:
1903
+ validatedResponse = ListModelsResponseSchema.parse(response);
1904
+ break;
1905
+ case "droid.list_mcp_registry" /* LIST_MCP_REGISTRY */:
1906
+ validatedResponse = ListMcpRegistryResponseSchema.parse(response);
1907
+ break;
1908
+ case "droid.list_mcp_tools" /* LIST_MCP_TOOLS */:
1909
+ validatedResponse = ListMcpToolsResponseSchema.parse(response);
1910
+ break;
1911
+ case "droid.list_tools" /* LIST_TOOLS */:
1912
+ validatedResponse = ListToolsResponseSchema.parse(response);
1913
+ break;
1914
+ case "droid.toggle_mcp_tool" /* TOGGLE_MCP_TOOL */:
1915
+ validatedResponse = ToggleMcpToolResponseSchema.parse(response);
1916
+ break;
1917
+ case "droid.submit_mcp_auth_code" /* SUBMIT_MCP_AUTH_CODE */:
1918
+ validatedResponse = SubmitMcpAuthCodeResponseSchema.parse(response);
1919
+ break;
1920
+ case "droid.submit_mcp_auth_error" /* SUBMIT_MCP_AUTH_ERROR */:
1921
+ validatedResponse = SubmitMcpAuthErrorResponseSchema.parse(response);
1922
+ break;
1923
+ case "droid.kill_worker_session" /* KILL_WORKER_SESSION */:
1924
+ validatedResponse = KillWorkerSessionResponseSchema.parse(response);
1925
+ break;
1926
+ case "droid.list_skills" /* LIST_SKILLS */:
1927
+ validatedResponse = ListSkillsResponseSchema.parse(response);
1928
+ break;
1929
+ case "droid.set_skill_disabled" /* SET_SKILL_DISABLED */:
1930
+ validatedResponse = SetSkillDisabledResponseSchema.parse(response);
1931
+ break;
1932
+ case "droid.list_commands" /* LIST_COMMANDS */:
1933
+ validatedResponse = ListCommandsResponseSchema.parse(response);
1934
+ break;
1935
+ case "droid.submit_bug_report" /* SUBMIT_BUG_REPORT */:
1936
+ validatedResponse = SubmitBugReportResponseSchema.parse(response);
1937
+ break;
1938
+ case "droid.list_mcp_servers" /* LIST_MCP_SERVERS */:
1939
+ validatedResponse = ListMcpServersResponseSchema.parse(response);
1940
+ break;
1941
+ case "droid.get_rewind_info" /* GET_REWIND_INFO */:
1942
+ validatedResponse = GetRewindInfoResponseSchema.parse(response);
1943
+ break;
1944
+ case "droid.execute_rewind" /* EXECUTE_REWIND */:
1945
+ validatedResponse = ExecuteRewindResponseSchema.parse(response);
1946
+ break;
1947
+ case "droid.compact_session" /* COMPACT_SESSION */:
1948
+ validatedResponse = CompactSessionResponseSchema.parse(response);
1949
+ break;
1950
+ case "droid.fork_session" /* FORK_SESSION */:
1951
+ validatedResponse = ForkSessionResponseSchema.parse(response);
1952
+ break;
1953
+ case "droid.rename_session" /* RENAME_SESSION */:
1954
+ validatedResponse = RenameSessionResponseSchema.parse(response);
1955
+ break;
1956
+ case "droid.get_context_stats" /* GET_CONTEXT_STATS */:
1957
+ validatedResponse = GetContextStatsResponseSchema.parse(response);
1958
+ break;
1959
+ case "droid.get_context_breakdown" /* GET_CONTEXT_BREAKDOWN */:
1960
+ validatedResponse = GetContextBreakdownResponseSchema.parse(response);
1961
+ break;
1962
+ case "droid.warmup_cache" /* WARMUP_CACHE */:
1963
+ validatedResponse = WarmupCacheResponseSchema.parse(response);
1964
+ break;
1965
+ default: {
1966
+ const exhaustiveCheck = pending.method;
1967
+ throw new DroidClientError(
1968
+ "Unsupported method in response handler",
1969
+ {
1970
+ method: exhaustiveCheck
1971
+ }
1972
+ );
1973
+ }
1974
+ }
1975
+ if (pending.timeoutId) {
1976
+ clearTimeout(pending.timeoutId);
1977
+ }
1978
+ this.settleRequest(responseId);
1979
+ pending.resolve(validatedResponse);
1980
+ } else {
1981
+ const validatedResponse = JsonRpcBaseResponseSchema.parse(response);
1982
+ this.logger.info(
1983
+ "[DroidClient] Received response for request not in pending map",
1984
+ {
1985
+ requestId: validatedResponse.id ?? void 0
1986
+ }
1987
+ );
1988
+ }
1989
+ }
1990
+ } catch (error) {
1991
+ const responseId = getResponseId(response);
1992
+ const pending = responseId !== null && responseId !== void 0 ? this.pendingRequests.get(responseId) : void 0;
1993
+ const zodIssues = error instanceof z.ZodError ? error.issues.map((issue) => ({
1994
+ path: issue.path,
1995
+ code: issue.code,
1996
+ message: issue.message
1997
+ })) : void 0;
1998
+ this.logger.exception(error, "Invalid response format", {
1999
+ method: pending?.method,
2000
+ requestId: responseId ?? void 0,
2001
+ zodIssues
2002
+ });
2003
+ const err = error instanceof Error ? error : new Error(String(error));
2004
+ const code = error instanceof z.ZodError ? -32700 /* PARSE_ERROR */ : -32603 /* INTERNAL_ERROR */;
2005
+ const message = code === -32700 /* PARSE_ERROR */ ? "Invalid response format" : "Internal error while handling response";
2006
+ if (responseId === null || responseId === void 0) {
2007
+ return;
2008
+ }
2009
+ if (!pending) {
2010
+ this.logger.info(
2011
+ "[DroidClient] Dropping unhandleable response with no pending request",
2012
+ {
2013
+ requestId: responseId,
2014
+ code,
2015
+ message: err.message
2016
+ }
2017
+ );
2018
+ return;
2019
+ }
2020
+ if (pending.timeoutId) {
2021
+ clearTimeout(pending.timeoutId);
2022
+ }
2023
+ this.settleRequest(responseId);
2024
+ const syntheticFailure = {
2025
+ jsonrpc: JSONRPC_VERSION2,
2026
+ type: "response",
2027
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
2028
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
2029
+ id: responseId,
2030
+ error: {
2031
+ code,
2032
+ message,
2033
+ data: err.message
2034
+ }
2035
+ };
2036
+ pending.resolve(syntheticFailure);
2037
+ }
2038
+ }
2039
+ async handleEvent(event) {
2040
+ try {
2041
+ const validatedEvent = CliRequestOrNotificationSchema.parse(event);
2042
+ if (validatedEvent.method === "droid.session_notification" /* SESSION_NOTIFICATION */) {
2043
+ const notification = validatedEvent.params.notification;
2044
+ if (notification.type === "agent_turn_completed" /* AGENT_TURN_COMPLETED */) {
2045
+ this.completedTurnObserved = true;
2046
+ } else if (notification.type === "droid_working_state_changed" /* DROID_WORKING_STATE_CHANGED */ && notification.newState !== "idle" /* Idle */) {
2047
+ this.completedTurnObserved = false;
2048
+ }
2049
+ this.emit("session_notification" /* SESSION_NOTIFICATION */, validatedEvent);
2050
+ } else if (validatedEvent.method === "droid.request_permission" /* REQUEST_PERMISSION */) {
2051
+ await this.handlePermissionRequest(validatedEvent);
2052
+ } else if (validatedEvent.method === "droid.ask_user" /* ASK_USER */) {
2053
+ await this.handleAskUserRequest(validatedEvent);
2054
+ }
2055
+ } catch (error) {
2056
+ this.logDroppedEventParseError(error, event);
2057
+ await this.replyWithParseFailureIfRequest(error, event);
2058
+ }
2059
+ }
2060
+ /**
2061
+ * When an incoming CLI->client request fails to parse, send back a
2062
+ * structurally valid JsonRpcBaseResponseFailure so the peer's pending
2063
+ * request doesn't hang. No-ops for notifications (no id to reply on)
2064
+ * or events we can't correlate.
2065
+ */
2066
+ async replyWithParseFailureIfRequest(error, event) {
2067
+ const type = _DroidClient.getNestedString(event, ["type"]);
2068
+ const id = _DroidClient.getNestedString(event, ["id"]);
2069
+ if (type !== "request" || !id) {
2070
+ return;
2071
+ }
2072
+ const err = error instanceof Error ? error : new Error(String(error));
2073
+ const code = error instanceof z.ZodError ? -32600 /* INVALID_REQUEST */ : -32603 /* INTERNAL_ERROR */;
2074
+ const message = code === -32600 /* INVALID_REQUEST */ ? "Invalid request format" : "Internal error while handling request";
2075
+ const errorResponse = {
2076
+ jsonrpc: JSONRPC_VERSION2,
2077
+ type: "response",
2078
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
2079
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
2080
+ id,
2081
+ error: {
2082
+ code,
2083
+ message,
2084
+ data: err.message
2085
+ }
2086
+ };
2087
+ try {
2088
+ await this.transport.send(JSON.stringify(errorResponse));
2089
+ } catch (sendError) {
2090
+ this.logger.exception(
2091
+ sendError,
2092
+ "Failed to send parse-failure response back to peer"
2093
+ );
2094
+ }
2095
+ }
2096
+ /**
2097
+ * Invariant: parsing failures for incoming events (notifications or
2098
+ * server-initiated requests) must NEVER surface as user-visible ERROR
2099
+ * notifications. Version skew, unknown inner enum values, missing
2100
+ * fields, or malformed shapes all degrade to a log-and-drop so the
2101
+ * session continues quietly instead of flashing a synthetic error on
2102
+ * every
2103
+ */
2104
+ logDroppedEventParseError(error, event) {
2105
+ const { protocolVersionMismatch } = inspectJsonRpcEnvelope2(event);
2106
+ const method = _DroidClient.getNestedString(event, ["method"]);
2107
+ const notificationType = _DroidClient.getNestedString(event, [
2108
+ "params",
2109
+ "notification",
2110
+ "type"
2111
+ ]);
2112
+ const sessionId = this.currentSessionId ?? _DroidClient.getNestedString(event, ["params", "sessionId"]);
2113
+ const meta = {
2114
+ value: {
2115
+ method: method ?? void 0,
2116
+ notificationType: notificationType ?? void 0,
2117
+ protocolVersionMismatch: protocolVersionMismatch ?? void 0,
2118
+ sessionId: sessionId ?? void 0
2119
+ }
2120
+ };
2121
+ if (protocolVersionMismatch) {
2122
+ this.logger.info(
2123
+ "[DroidClient] Dropping unsupported event from newer peer",
2124
+ meta
2125
+ );
2126
+ } else {
2127
+ this.logger.warn("[DroidClient] Dropping malformed event", {
2128
+ ...meta,
2129
+ cause: error
2130
+ });
2131
+ }
2132
+ }
2133
+ async handlePermissionRequest(event) {
2134
+ if (this.pendingPermissionRequests.has(event.id)) {
2135
+ this.logger.info(
2136
+ "[DroidClient] Ignoring duplicate pending permission request",
2137
+ {
2138
+ requestId: event.id
2139
+ }
2140
+ );
2141
+ return;
2142
+ }
2143
+ this.logger.info("[DroidClient] Handling permission request", {
2144
+ requestId: event.id,
2145
+ toolCount: event.params.toolUses.length
2146
+ });
2147
+ this.emit("request_permission" /* REQUEST_PERMISSION */, event);
2148
+ let selectedOption = "cancel" /* Cancel */;
2149
+ let comment;
2150
+ let editedSpecContent;
2151
+ const handler = this.permissionHandlers.get("default");
2152
+ if (handler) {
2153
+ try {
2154
+ this.logger.info(
2155
+ "[DroidClient] Waiting for permission handler to resolve",
2156
+ {
2157
+ requestId: event.id
2158
+ }
2159
+ );
2160
+ const handlerPromise = new Promise(
2161
+ (resolve2, reject) => {
2162
+ this.pendingPermissionRequests.set(event.id, { reject });
2163
+ handler(event).then(resolve2).catch(reject).finally(() => {
2164
+ this.pendingPermissionRequests.delete(event.id);
2165
+ });
2166
+ }
2167
+ );
2168
+ const handlerResult = await handlerPromise;
2169
+ if (typeof handlerResult === "string" && handlerResult === "proceed_edit" /* ProceedEdit */) {
2170
+ throw new DroidClientError(
2171
+ "Permission handler returned proceed_edit without editedSpecContent"
2172
+ );
2173
+ }
2174
+ const parsedHandlerResult = RequestPermissionResultSchema.safeParse(
2175
+ typeof handlerResult === "string" ? { selectedOption: handlerResult } : handlerResult
2176
+ );
2177
+ if (parsedHandlerResult.success) {
2178
+ selectedOption = parsedHandlerResult.data.selectedOption;
2179
+ comment = parsedHandlerResult.data.comment;
2180
+ editedSpecContent = parsedHandlerResult.data.editedSpecContent;
2181
+ } else {
2182
+ throw new DroidClientError(
2183
+ "Permission handler returned invalid result",
2184
+ {
2185
+ cause: parsedHandlerResult.error
2186
+ }
2187
+ );
2188
+ }
2189
+ if (!event.params.options.some(
2190
+ (option) => option.value === selectedOption
2191
+ )) {
2192
+ throw new DroidClientError(
2193
+ `Permission handler selected unavailable option: ${selectedOption}`
2194
+ );
2195
+ }
2196
+ this.logger.info("[DroidClient] Permission handler resolved", {
2197
+ requestId: event.id,
2198
+ result: selectedOption
2199
+ });
2200
+ } catch (error) {
2201
+ this.logger.exception(
2202
+ error,
2203
+ "Failed to handle permission request (processing)"
2204
+ );
2205
+ const err = error instanceof Error ? error : new Error(String(error));
2206
+ this.emit(
2207
+ "session_notification" /* SESSION_NOTIFICATION */,
2208
+ _DroidClient.createNotificationEvent(
2209
+ _DroidClient.createErrorNotification(err)
2210
+ )
2211
+ );
2212
+ this.pendingPermissionRequests.delete(event.id);
2213
+ const cancelResponse = {
2214
+ type: "response",
2215
+ jsonrpc: JSONRPC_VERSION2,
2216
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
2217
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
2218
+ id: event.id,
2219
+ result: {
2220
+ selectedOption: "cancel" /* Cancel */
2221
+ }
2222
+ };
2223
+ try {
2224
+ await this.transport.send(JSON.stringify(cancelResponse));
2225
+ } catch (sendError) {
2226
+ this.logger.exception(
2227
+ sendError,
2228
+ "Failed to handle permission request (send cancellation)"
2229
+ );
2230
+ const sendErr = sendError instanceof Error ? sendError : new Error(String(sendError));
2231
+ this.emit(
2232
+ "session_notification" /* SESSION_NOTIFICATION */,
2233
+ _DroidClient.createNotificationEvent(
2234
+ _DroidClient.createErrorNotification(sendErr)
2235
+ )
2236
+ );
2237
+ }
2238
+ return;
2239
+ }
2240
+ }
2241
+ const response = {
2242
+ type: "response",
2243
+ jsonrpc: JSONRPC_VERSION2,
2244
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
2245
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
2246
+ id: event.id,
2247
+ result: {
2248
+ selectedOption,
2249
+ ...comment !== void 0 && { comment },
2250
+ ...editedSpecContent !== void 0 && { editedSpecContent }
2251
+ }
2252
+ };
2253
+ this.logger.info("[DroidClient] Sending permission response back to CLI", {
2254
+ requestId: event.id,
2255
+ result: String(selectedOption)
2256
+ });
2257
+ await this.transport.send(JSON.stringify(response));
2258
+ }
2259
+ async handleAskUserRequest(event) {
2260
+ this.logger.info("[DroidClient] Handling ask-user request", {
2261
+ requestId: event.id,
2262
+ toolCallId: event.params.toolCallId,
2263
+ questionCount: event.params.questions.length
2264
+ });
2265
+ this.emit("ask_user" /* ASK_USER */, event);
2266
+ let result = { cancelled: true, answers: [] };
2267
+ const handler = this.askUserHandlers.get("default");
2268
+ if (handler) {
2269
+ try {
2270
+ this.logger.info(
2271
+ "[DroidClient] Waiting for ask-user handler to resolve",
2272
+ {
2273
+ requestId: event.id
2274
+ }
2275
+ );
2276
+ const handlerPromise = new Promise((resolve2, reject) => {
2277
+ this.pendingAskUserRequests.set(event.id, { reject });
2278
+ handler(event).then(resolve2).catch(reject).finally(() => {
2279
+ this.pendingAskUserRequests.delete(event.id);
2280
+ });
2281
+ });
2282
+ const parsedResult = AskUserResultSchema.safeParse(
2283
+ await handlerPromise
2284
+ );
2285
+ if (!parsedResult.success) {
2286
+ throw new DroidClientError(
2287
+ "AskUser handler returned invalid result",
2288
+ {
2289
+ cause: parsedResult.error
2290
+ }
2291
+ );
2292
+ }
2293
+ result = parsedResult.data;
2294
+ this.logger.info("[DroidClient] Ask-user handler resolved", {
2295
+ requestId: event.id,
2296
+ cancelled: result.cancelled ?? false,
2297
+ answerCount: result.answers.length
2298
+ });
2299
+ } catch (error) {
2300
+ this.logger.exception(error, "Failed to handle ask-user request");
2301
+ const err = error instanceof Error ? error : new Error(String(error));
2302
+ this.emit(
2303
+ "session_notification" /* SESSION_NOTIFICATION */,
2304
+ _DroidClient.createNotificationEvent(
2305
+ _DroidClient.createErrorNotification(err)
2306
+ )
2307
+ );
2308
+ this.pendingAskUserRequests.delete(event.id);
2309
+ const cancelResponse = {
2310
+ jsonrpc: JSONRPC_VERSION2,
2311
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
2312
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
2313
+ type: "response",
2314
+ id: event.id,
2315
+ result: {
2316
+ cancelled: true,
2317
+ answers: []
2318
+ }
2319
+ };
2320
+ try {
2321
+ await this.transport.send(JSON.stringify(cancelResponse));
2322
+ } catch (sendError) {
2323
+ this.logger.exception(
2324
+ sendError,
2325
+ "Failed to send ask-user cancellation"
2326
+ );
2327
+ }
2328
+ return;
2329
+ }
2330
+ }
2331
+ const response = {
2332
+ type: "response",
2333
+ jsonrpc: JSONRPC_VERSION2,
2334
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
2335
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
2336
+ id: event.id,
2337
+ result
2338
+ };
2339
+ this.logger.info("[DroidClient] Sending ask-user response back to CLI", {
2340
+ requestId: event.id,
2341
+ cancelled: result.cancelled ?? false
2342
+ });
2343
+ await this.transport.send(JSON.stringify(response));
2344
+ }
2345
+ static getErrorType(error) {
2346
+ switch (error.constructor) {
2347
+ case ConnectionError:
2348
+ return "ConnectionError" /* CONNECTION_ERROR */;
2349
+ case ProtocolError:
2350
+ return "ProtocolError" /* PROTOCOL_ERROR */;
2351
+ case SessionError:
2352
+ return "SessionError" /* SESSION_ERROR */;
2353
+ case TimeoutError:
2354
+ return "TimeoutError" /* TIMEOUT_ERROR */;
2355
+ case ProcessExitError:
2356
+ return "ProcessExitError" /* PROCESS_EXIT_ERROR */;
2357
+ case DroidClientError:
2358
+ return "DroidClientError" /* DROID_CLIENT_ERROR */;
2359
+ default:
2360
+ return "Error" /* ERROR */;
2361
+ }
2362
+ }
2363
+ static createErrorNotification(error) {
2364
+ return {
2365
+ type: "error" /* ERROR */,
2366
+ message: error.message,
2367
+ errorType: _DroidClient.getErrorType(error),
2368
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2369
+ ...error instanceof ProcessExitError && error.exitCode !== void 0 ? { exitCode: error.exitCode } : {},
2370
+ error: {
2371
+ name: error.name,
2372
+ message: error.message
2373
+ }
2374
+ };
2375
+ }
2376
+ static getNestedString(value, path3) {
2377
+ let current = value;
2378
+ for (const key of path3) {
2379
+ if (!_DroidClient.isRecord(current)) {
2380
+ return null;
2381
+ }
2382
+ current = current[key];
2383
+ }
2384
+ return typeof current === "string" ? current : null;
2385
+ }
2386
+ static isRecord(value) {
2387
+ return typeof value === "object" && value !== null;
2388
+ }
2389
+ /**
2390
+ * Create a full SessionNotificationEvent for locally-generated notifications.
2391
+ * Used when the SDK needs to emit error notifications that weren't received from the CLI.
2392
+ */
2393
+ static createNotificationEvent(notification) {
2394
+ return {
2395
+ jsonrpc: JSONRPC_VERSION2,
2396
+ type: "notification",
2397
+ factoryApiVersion: LEGACY_FACTORY_API_VERSION,
2398
+ factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
2399
+ method: "droid.session_notification" /* SESSION_NOTIFICATION */,
2400
+ params: { notification }
2401
+ };
2402
+ }
2403
+ };
2404
+
2405
+ // src/exec-core/managed-process.ts
2406
+ import { spawnSync } from "child_process";
2407
+ import fs2 from "fs";
2408
+ import * as readline from "readline";
2409
+
2410
+ // src/exec-core/runtime-utils.ts
2411
+ import { homedir } from "os";
2412
+ import { join } from "path";
2413
+ function isErrnoException(error) {
2414
+ return error !== null && typeof error === "object" && "code" in error && typeof error.code === "string";
2415
+ }
2416
+ function expandTilde(filepath) {
2417
+ if (!filepath) {
2418
+ return filepath;
2419
+ }
2420
+ if (filepath === "~") {
2421
+ return homedir();
2422
+ }
2423
+ if (filepath.startsWith("~/") || filepath.startsWith("~\\")) {
2424
+ return join(homedir(), filepath.slice(2));
2425
+ }
2426
+ return filepath;
2427
+ }
2428
+
2429
+ // src/exec-core/transport-logger.ts
2430
+ import fs from "fs";
2431
+ import path from "path";
2432
+ var LOG_FILE_NAME = "droid-transport.log";
2433
+ var LOG_DIR_MODE = 448;
2434
+ var LOG_FILE_MODE = 384;
2435
+ var state = null;
2436
+ var enabledCache = null;
2437
+ var HOST_PID_TAG = `host_pid=${process.pid}`;
2438
+ function isTruthy(value) {
2439
+ const v = value.trim().toLowerCase();
2440
+ return v !== "" && v !== "0" && v !== "false" && v !== "off" && v !== "no";
2441
+ }
2442
+ function directionMarker(direction) {
2443
+ switch (direction) {
2444
+ case "in" /* In */:
2445
+ return "IN ";
2446
+ case "out" /* Out */:
2447
+ return "OUT";
2448
+ case "out_failed" /* OutFailed */:
2449
+ return "OUT!";
2450
+ default:
2451
+ return "???";
2452
+ }
2453
+ }
2454
+ function isTransportLoggingEnabled(deps = defaultExecCoreDeps) {
2455
+ if (enabledCache !== null) return enabledCache;
2456
+ enabledCache = isTruthy(
2457
+ deps.environmentResolver.resolveTransportLogEnvValue() ?? ""
2458
+ );
2459
+ return enabledCache;
2460
+ }
2461
+ function looksLikePath(value) {
2462
+ return path.isAbsolute(value) || value.startsWith("~") || value.startsWith("./") || value.startsWith("../") || value.startsWith(".\\") || value.startsWith("..\\") || value.includes("/") || value.includes("\\");
2463
+ }
2464
+ function resolveLogPath(deps) {
2465
+ const envValue = deps.environmentResolver.resolveTransportLogEnvValue();
2466
+ const pathResolver = deps.factoryPathResolver;
2467
+ if (envValue && looksLikePath(envValue)) {
2468
+ if (envValue === "~" || envValue.startsWith("~/") || envValue.startsWith("~\\")) {
2469
+ const rest = envValue.slice(2);
2470
+ const home = pathResolver.getFactoryHome();
2471
+ return rest ? path.join(home, rest) : home;
2472
+ }
2473
+ return envValue;
2474
+ }
2475
+ return path.join(
2476
+ pathResolver.getFactoryHome(),
2477
+ pathResolver.getFactoryDirName(),
2478
+ "logs",
2479
+ LOG_FILE_NAME
2480
+ );
2481
+ }
2482
+ function initState(deps) {
2483
+ const result = { stream: null, failed: false };
2484
+ try {
2485
+ const logPath = resolveLogPath(deps);
2486
+ const logsDir = path.dirname(logPath);
2487
+ const logsDirExisted = fs.existsSync(logsDir);
2488
+ if (!logsDirExisted) {
2489
+ fs.mkdirSync(logsDir, { recursive: true, mode: LOG_DIR_MODE });
2490
+ }
2491
+ if (process.platform !== "win32" && !logsDirExisted) {
2492
+ try {
2493
+ fs.chmodSync(logsDir, LOG_DIR_MODE);
2494
+ } catch (chmodError) {
2495
+ logWarn(
2496
+ deps.logger,
2497
+ "[droid-sdk transport-logger] failed to chmod logs dir",
2498
+ {
2499
+ cause: chmodError
2500
+ }
2501
+ );
2502
+ }
2503
+ }
2504
+ const stream = fs.createWriteStream(logPath, {
2505
+ flags: "a",
2506
+ encoding: "utf8",
2507
+ mode: LOG_FILE_MODE
2508
+ });
2509
+ if (process.platform !== "win32") {
2510
+ try {
2511
+ fs.chmodSync(logPath, LOG_FILE_MODE);
2512
+ } catch (chmodError) {
2513
+ logWarn(
2514
+ deps.logger,
2515
+ "[droid-sdk transport-logger] failed to chmod log file",
2516
+ {
2517
+ cause: chmodError
2518
+ }
2519
+ );
2520
+ }
2521
+ }
2522
+ stream.on("error", (streamError) => {
2523
+ deps.logger.warn("[droid-sdk transport-logger] write stream error", {
2524
+ cause: streamError
2525
+ });
2526
+ result.stream = null;
2527
+ result.failed = true;
2528
+ });
2529
+ result.stream = stream;
2530
+ } catch (initError) {
2531
+ logWarn(
2532
+ deps.logger,
2533
+ "[droid-sdk transport-logger] failed to open log file",
2534
+ {
2535
+ cause: initError
2536
+ }
2537
+ );
2538
+ result.failed = true;
2539
+ }
2540
+ return result;
2541
+ }
2542
+ function getState(deps) {
2543
+ if (!isTransportLoggingEnabled(deps)) return null;
2544
+ if (state === null) {
2545
+ state = initState(deps);
2546
+ }
2547
+ if (state.failed) return null;
2548
+ return state;
2549
+ }
2550
+ function logTransportMessage(direction, message, childPid, deps = defaultExecCoreDeps) {
2551
+ const s = getState(deps);
2552
+ if (!s || !s.stream) return;
2553
+ try {
2554
+ const marker = directionMarker(direction);
2555
+ const childTag = `[child_pid=${childPid ?? "-"}]`;
2556
+ s.stream.write(
2557
+ `[${(/* @__PURE__ */ new Date()).toISOString()}] [${HOST_PID_TAG}] ${childTag} ${marker} ${message}
2558
+ `
2559
+ );
2560
+ } catch (writeError) {
2561
+ logWarn(
2562
+ deps.logger,
2563
+ "[droid-sdk transport-logger] write failed, disabling",
2564
+ {
2565
+ cause: writeError
2566
+ }
2567
+ );
2568
+ s.failed = true;
2569
+ s.stream = null;
2570
+ }
2571
+ }
2572
+ async function __resetTransportLoggerForTests(deps = defaultExecCoreDeps) {
2573
+ const stream = state?.stream ?? null;
2574
+ state = null;
2575
+ enabledCache = null;
2576
+ if (!stream) return;
2577
+ await new Promise((resolve2) => {
2578
+ stream.once("finish", () => resolve2());
2579
+ stream.once("error", () => resolve2());
2580
+ try {
2581
+ stream.end();
2582
+ } catch (endError) {
2583
+ logWarn(
2584
+ deps.logger,
2585
+ "[droid-sdk transport-logger] failed to end stream on reset",
2586
+ {
2587
+ cause: endError
2588
+ }
2589
+ );
2590
+ resolve2();
2591
+ }
2592
+ });
2593
+ }
2594
+
2595
+ // src/exec-core/managed-process.ts
2596
+ var MAX_NON_JSON_LOG_LENGTH = 200;
2597
+ var EXIT_STDIO_DRAIN_TIMEOUT_MS = 2e3;
2598
+ var GRACEFUL_EXIT_TIMEOUT_MS = 2e3;
2599
+ var FORCED_EXIT_TIMEOUT_MS = 3e3;
2600
+ function describeSpawnError(error, context) {
2601
+ if (!isErrnoException(error)) {
2602
+ return `Failed to start Droid: ${error.message}`;
2603
+ }
2604
+ if (error.code === "ENOENT") {
2605
+ if (context?.cwd && !fs2.existsSync(context.cwd)) {
2606
+ return `Failed to start Droid: working directory does not exist (${context.cwd})`;
2607
+ }
2608
+ return `Failed to start Droid: executable not found${context?.execPath ? ` (${context.execPath})` : ""}`;
2609
+ }
2610
+ if (error.code === "EACCES") {
2611
+ return `Failed to start Droid: permission denied${context?.execPath ? ` (${context.execPath})` : ""}`;
2612
+ }
2613
+ return `Failed to start Droid: ${error.code}`;
2614
+ }
2615
+ function describeExitError(code, signal) {
2616
+ if (signal) {
2617
+ return `Droid process was killed (${signal})`;
2618
+ }
2619
+ if (code !== null) {
2620
+ return `Droid process exited unexpectedly (exit code ${code})`;
2621
+ }
2622
+ return "Droid process exited unexpectedly";
2623
+ }
2624
+ var ManagedProcessImpl = class {
2625
+ constructor(childProcess, logPrefix, spawnContext, deps, transportLoggerDeps = deps) {
2626
+ this.logPrefix = logPrefix;
2627
+ this.spawnContext = spawnContext;
2628
+ this.transportLoggerDeps = transportLoggerDeps;
2629
+ this._childProcess = childProcess;
2630
+ this.logger = deps.logger;
2631
+ this.setupHandlers();
2632
+ }
2633
+ logPrefix;
2634
+ spawnContext;
2635
+ transportLoggerDeps;
2636
+ _childProcess;
2637
+ messageHandler = null;
2638
+ errorHandler = null;
2639
+ readlineInterface = null;
2640
+ isClosing = false;
2641
+ /** Latch so exit teardown/classification runs exactly once per process. */
2642
+ exitFinalized = false;
2643
+ exitDrainTimer = null;
2644
+ /**
2645
+ * Sticky error from a process error or unexpected exit event. Once set,
2646
+ * all subsequent `send()` calls throw this error immediately instead of
2647
+ * hanging on a dead transport.
2648
+ */
2649
+ processError = null;
2650
+ queuedSendPromise = Promise.resolve();
2651
+ logger;
2652
+ get childProcess() {
2653
+ if (!this._childProcess) {
2654
+ throw new ConnectionError("Process not connected");
2655
+ }
2656
+ return this._childProcess;
2657
+ }
2658
+ setupHandlers() {
2659
+ if (!this.childProcess.stdout) {
2660
+ throw new ConnectionError("Failed to get process stdout");
2661
+ }
2662
+ this.readlineInterface = readline.createInterface({
2663
+ input: this.childProcess.stdout,
2664
+ crlfDelay: Infinity
2665
+ });
2666
+ this.readlineInterface.on("line", (line) => {
2667
+ const trimmedLine = line.trim();
2668
+ if (this.messageHandler && trimmedLine) {
2669
+ if (trimmedLine.startsWith("{") || trimmedLine.startsWith("[")) {
2670
+ logTransportMessage(
2671
+ "in" /* In */,
2672
+ trimmedLine,
2673
+ this._childProcess?.pid,
2674
+ this.transportLoggerDeps
2675
+ );
2676
+ this.messageHandler(trimmedLine);
2677
+ } else {
2678
+ const truncated = trimmedLine.length > MAX_NON_JSON_LOG_LENGTH ? trimmedLine.substring(0, MAX_NON_JSON_LOG_LENGTH) : trimmedLine;
2679
+ this.logger.warn("[droid process] non-JSON output", {
2680
+ state: this.logPrefix,
2681
+ output: truncated
2682
+ });
2683
+ }
2684
+ }
2685
+ });
2686
+ this.childProcess.on("error", (error) => {
2687
+ this.processError = new ConnectionError(
2688
+ describeSpawnError(error, this.spawnContext),
2689
+ {
2690
+ error,
2691
+ cwd: this.spawnContext?.cwd,
2692
+ execPath: this.spawnContext?.execPath
2693
+ }
2694
+ );
2695
+ if (!this.isClosing && this.errorHandler) {
2696
+ this.errorHandler(this.processError);
2697
+ }
2698
+ });
2699
+ this.childProcess.on("exit", (code, signal) => {
2700
+ this.exitDrainTimer = setTimeout(() => {
2701
+ this.finalizeExit(code, signal);
2702
+ }, EXIT_STDIO_DRAIN_TIMEOUT_MS);
2703
+ this.exitDrainTimer.unref?.();
2704
+ });
2705
+ this.childProcess.on("close", (code, signal) => {
2706
+ this.finalizeExit(code, signal);
2707
+ });
2708
+ if (this.childProcess.stderr) {
2709
+ this.childProcess.stderr.on("data", (data) => {
2710
+ this.logger.warn("[droid process] stderr", {
2711
+ state: this.logPrefix,
2712
+ output: data.toString()
2713
+ });
2714
+ });
2715
+ }
2716
+ }
2717
+ finalizeExit(code, signal) {
2718
+ if (this.exitFinalized) {
2719
+ return;
2720
+ }
2721
+ this.exitFinalized = true;
2722
+ if (this.exitDrainTimer) {
2723
+ clearTimeout(this.exitDrainTimer);
2724
+ this.exitDrainTimer = null;
2725
+ }
2726
+ this._childProcess = null;
2727
+ if (this.readlineInterface) {
2728
+ this.readlineInterface.close();
2729
+ this.readlineInterface = null;
2730
+ }
2731
+ if (!this.isClosing) {
2732
+ this.processError = new ProcessExitError(
2733
+ describeExitError(code, signal),
2734
+ {
2735
+ exitCode: code ?? void 0,
2736
+ signal: signal ?? void 0
2737
+ }
2738
+ );
2739
+ if (this.errorHandler) {
2740
+ this.errorHandler(this.processError);
2741
+ }
2742
+ }
2743
+ }
2744
+ async send(message) {
2745
+ if (this.processError) {
2746
+ throw this.processError;
2747
+ }
2748
+ if (!this._childProcess || !this._childProcess.stdin) {
2749
+ throw new ConnectionError("Process not connected");
2750
+ }
2751
+ const previousSends = this.queuedSendPromise;
2752
+ this.queuedSendPromise = (async () => {
2753
+ await previousSends.catch(() => {
2754
+ });
2755
+ if (!this._childProcess || !this._childProcess.stdin || this._childProcess.killed || this.isClosing) {
2756
+ throw new ConnectionError("Process disconnected before write");
2757
+ }
2758
+ await new Promise((resolve2, reject) => {
2759
+ try {
2760
+ if (!this._childProcess || !this._childProcess.stdin) {
2761
+ reject(new ConnectionError("Process stdin unavailable"));
2762
+ return;
2763
+ }
2764
+ const stdin = this._childProcess.stdin;
2765
+ if ("writable" in stdin && !stdin.writable) {
2766
+ reject(new ConnectionError("Process stdin is not writable"));
2767
+ return;
2768
+ }
2769
+ const childPid = this._childProcess?.pid;
2770
+ stdin.write(`${message}
2771
+ `, (error) => {
2772
+ if (error) {
2773
+ logTransportMessage(
2774
+ "out_failed" /* OutFailed */,
2775
+ message,
2776
+ childPid,
2777
+ this.transportLoggerDeps
2778
+ );
2779
+ const errorMessage = error.message || String(error);
2780
+ if (errorMessage.includes("EPIPE") || errorMessage.includes("ECONNRESET")) {
2781
+ reject(
2782
+ new ConnectionError("Process stdin closed during write", {
2783
+ error
2784
+ })
2785
+ );
2786
+ } else {
2787
+ reject(
2788
+ new ConnectionError("Failed to write to process stdin", {
2789
+ error
2790
+ })
2791
+ );
2792
+ }
2793
+ } else {
2794
+ logTransportMessage(
2795
+ "out" /* Out */,
2796
+ message,
2797
+ childPid,
2798
+ this.transportLoggerDeps
2799
+ );
2800
+ resolve2();
2801
+ }
2802
+ });
2803
+ } catch (error) {
2804
+ logWarn(
2805
+ this.logger,
2806
+ "[ManagedProcess] Error writing to process stdin",
2807
+ {
2808
+ cause: error
2809
+ }
2810
+ );
2811
+ reject(
2812
+ new ConnectionError("Error writing to process stdin", {
2813
+ error: error instanceof Error ? error : new Error(String(error))
2814
+ })
2815
+ );
2816
+ }
2817
+ });
2818
+ })();
2819
+ return this.queuedSendPromise;
2820
+ }
2821
+ onMessage(handler) {
2822
+ this.messageHandler = handler;
2823
+ }
2824
+ onError(handler) {
2825
+ this.errorHandler = handler;
2826
+ }
2827
+ async close() {
2828
+ this.isClosing = true;
2829
+ if (this._childProcess) {
2830
+ const processToClose = this._childProcess;
2831
+ if (processToClose.pid === void 0 || processToClose.exitCode !== null || processToClose.signalCode !== null && processToClose.signalCode !== void 0) {
2832
+ this._childProcess = null;
2833
+ } else {
2834
+ await new Promise((resolve2) => {
2835
+ let forcedExitTimeout;
2836
+ const gracefulExitTimeout = setTimeout(() => {
2837
+ if (processToClose.exitCode === null) {
2838
+ if (process.platform === "win32") {
2839
+ this.killProcessTree(processToClose, "SIGKILL");
2840
+ } else {
2841
+ this.killProcessTree(processToClose, "SIGTERM");
2842
+ forcedExitTimeout = setTimeout(() => {
2843
+ if (processToClose.exitCode === null) {
2844
+ this.killProcessTree(processToClose, "SIGKILL");
2845
+ }
2846
+ }, FORCED_EXIT_TIMEOUT_MS);
2847
+ }
2848
+ }
2849
+ }, GRACEFUL_EXIT_TIMEOUT_MS);
2850
+ processToClose.once("exit", () => {
2851
+ clearTimeout(gracefulExitTimeout);
2852
+ if (forcedExitTimeout) clearTimeout(forcedExitTimeout);
2853
+ resolve2();
2854
+ });
2855
+ if (processToClose.stdin) {
2856
+ processToClose.stdin.end();
2857
+ }
2858
+ });
2859
+ }
2860
+ }
2861
+ if (this.readlineInterface) {
2862
+ this.readlineInterface.close();
2863
+ this.readlineInterface = null;
2864
+ }
2865
+ this.exitFinalized = true;
2866
+ if (this.exitDrainTimer) {
2867
+ clearTimeout(this.exitDrainTimer);
2868
+ this.exitDrainTimer = null;
2869
+ }
2870
+ this._childProcess = null;
2871
+ this.isClosing = false;
2872
+ }
2873
+ killProcessTree(childProcess, signal) {
2874
+ if (process.platform !== "win32" || childProcess.pid === void 0) {
2875
+ childProcess.kill(signal);
2876
+ return;
2877
+ }
2878
+ const result = spawnSync(
2879
+ "taskkill",
2880
+ ["/PID", String(childProcess.pid), "/T", "/F"],
2881
+ {
2882
+ stdio: "ignore",
2883
+ windowsHide: true
2884
+ }
2885
+ );
2886
+ if (!result.error && result.status === 0) {
2887
+ return;
2888
+ }
2889
+ logWarn(
2890
+ this.logger,
2891
+ "[ManagedProcess] Failed to kill Windows process tree",
2892
+ {
2893
+ pid: childProcess.pid,
2894
+ signal,
2895
+ status: result.status,
2896
+ cause: result.error
2897
+ }
2898
+ );
2899
+ childProcess.kill(signal);
2900
+ }
2901
+ get isConnected() {
2902
+ return this._childProcess !== null && !this._childProcess.killed && this._childProcess.stdin !== null && !this._childProcess.stdin.destroyed && ("writable" in this._childProcess.stdin ? this._childProcess.stdin.writable : true);
2903
+ }
2904
+ };
2905
+
2906
+ // src/exec-core/process-manager.ts
2907
+ import { spawn } from "child_process";
2908
+
2909
+ // src/exec-core/windows-job-object-retry.ts
2910
+ var DEFAULT_BACKOFF_MS = [50, 150, 400];
2911
+ var DEFAULT_MAX_RETRIES = 2;
2912
+ var DEFAULT_GRACE_PERIOD_MS = 250;
2913
+ var defaultSleep = (ms) => new Promise((resolve2) => {
2914
+ setTimeout(resolve2, ms);
2915
+ });
2916
+ function observeEarlySpawnFailure(childProcess, gracePeriodMs, sleep) {
2917
+ const observation = {
2918
+ exited: false,
2919
+ code: null,
2920
+ signal: null,
2921
+ error: null,
2922
+ stderr: ""
2923
+ };
2924
+ const stderrListener = (data) => {
2925
+ observation.stderr += data.toString();
2926
+ };
2927
+ const exitListener = (code, signal) => {
2928
+ observation.exited = true;
2929
+ observation.code = code;
2930
+ observation.signal = signal;
2931
+ };
2932
+ const errorListener = (err) => {
2933
+ observation.error = err;
2934
+ };
2935
+ childProcess.stderr?.on("data", stderrListener);
2936
+ childProcess.once("exit", exitListener);
2937
+ childProcess.once("error", errorListener);
2938
+ const cleanup = () => {
2939
+ childProcess.stderr?.off("data", stderrListener);
2940
+ childProcess.off("exit", exitListener);
2941
+ childProcess.off("error", errorListener);
2942
+ };
2943
+ return new Promise((resolve2) => {
2944
+ const resolveAndCleanup = () => {
2945
+ cleanup();
2946
+ resolve2(observation);
2947
+ };
2948
+ const onExitResolve = () => {
2949
+ setImmediate(resolveAndCleanup);
2950
+ };
2951
+ childProcess.once("exit", onExitResolve);
2952
+ childProcess.once("error", onExitResolve);
2953
+ void sleep(gracePeriodMs).then(() => {
2954
+ childProcess.off("exit", onExitResolve);
2955
+ childProcess.off("error", onExitResolve);
2956
+ resolveAndCleanup();
2957
+ });
2958
+ });
2959
+ }
2960
+ async function spawnWithWindowsJobObjectRetry(spawnFactory, options = {}) {
2961
+ const enabled = options.enabled ?? process.platform === "win32";
2962
+ if (!enabled) {
2963
+ return spawnFactory();
2964
+ }
2965
+ const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
2966
+ const backoff = options.backoffMs ?? DEFAULT_BACKOFF_MS;
2967
+ const gracePeriodMs = options.gracePeriodMs ?? DEFAULT_GRACE_PERIOD_MS;
2968
+ const sleep = options.sleep ?? defaultSleep;
2969
+ const logPrefix = options.logPrefix ?? "[spawnWithWindowsJobObjectRetry]";
2970
+ const logger = options.logger ?? noopLogger;
2971
+ let lastChild = null;
2972
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
2973
+ const child = spawnFactory();
2974
+ lastChild = child;
2975
+ const observation = await observeEarlySpawnFailure(
2976
+ child,
2977
+ gracePeriodMs,
2978
+ sleep
2979
+ );
2980
+ if (!observation.exited && !observation.error) {
2981
+ return child;
2982
+ }
2983
+ const isRetryableJobObjectFailure = observation.stderr.includes(WINDOWS_JOB_OBJECT_ERROR_MARKER) || observation.exited && observation.code !== 0 && !observation.error;
2984
+ if (attempt === maxRetries || !isRetryableJobObjectFailure) {
2985
+ return child;
2986
+ }
2987
+ logger.warn("spawnWithWindowsJobObjectRetry: retrying on early failure", {
2988
+ name: logPrefix,
2989
+ attempt: attempt + 1,
2990
+ maxAttempts: maxRetries,
2991
+ exitCode: observation.code,
2992
+ signal: observation.signal,
2993
+ stderrTail: observation.stderr.slice(-256)
2994
+ });
2995
+ try {
2996
+ await options.disposeEarlyExited?.(child);
2997
+ } catch (disposeErr) {
2998
+ logWarn(logger, "spawnWithWindowsJobObjectRetry: dispose error", {
2999
+ cause: disposeErr instanceof Error ? disposeErr : new Error(String(disposeErr)),
3000
+ name: logPrefix
3001
+ });
3002
+ }
3003
+ await sleep(backoff[attempt] ?? backoff[backoff.length - 1] ?? 400);
3004
+ }
3005
+ if (lastChild) return lastChild;
3006
+ throw new DroidClientError(
3007
+ "spawnWithWindowsJobObjectRetry: exhausted retries without child",
3008
+ {}
3009
+ );
3010
+ }
3011
+
3012
+ // src/exec-core/process-manager.ts
3013
+ function buildArgs(config) {
3014
+ const args = [];
3015
+ if (config.mode === "acp" /* Acp */) {
3016
+ args.push("exec", "--output-format", "acp");
3017
+ } else {
3018
+ args.push(
3019
+ "exec",
3020
+ "--input-format",
3021
+ "stream-jsonrpc",
3022
+ "--output-format",
3023
+ "stream-jsonrpc"
3024
+ );
3025
+ }
3026
+ if (config.extraArgs) {
3027
+ args.push(...config.extraArgs);
3028
+ }
3029
+ return args;
3030
+ }
3031
+ var DroidProcessManager = class {
3032
+ deps;
3033
+ transportLoggerDeps;
3034
+ logger;
3035
+ commandResolver;
3036
+ constructor(options = {}, deps = defaultExecCoreDeps) {
3037
+ const resolved = resolveExecCoreDeps(options.observability, deps);
3038
+ this.deps = resolved;
3039
+ this.transportLoggerDeps = deps;
3040
+ this.logger = resolved.logger;
3041
+ this.commandResolver = resolved.commandResolver;
3042
+ }
3043
+ /**
3044
+ * Spawn a new droid process with the given configuration.
3045
+ *
3046
+ * Returns a synchronous ManagedProcess as soon as the OS reports the child
3047
+ * as spawned. This does not retry Windows Job Object spawn failures — use
3048
+ * {@link DroidProcessManager#spawnWithWindowsRetry} for that.
3049
+ */
3050
+ spawn(config) {
3051
+ const { logPrefix, execPath, expandedCwd, childProcess } = this.spawnChildProcess(config);
3052
+ return new ManagedProcessImpl(
3053
+ childProcess,
3054
+ logPrefix,
3055
+ {
3056
+ cwd: expandedCwd,
3057
+ execPath
3058
+ },
3059
+ this.deps,
3060
+ this.transportLoggerDeps
3061
+ );
3062
+ }
3063
+ /**
3064
+ * Spawn a droid process with automatic retry for the Windows Job Object
3065
+ * spawn error class (FAC-19070). On non-Windows platforms this behaves
3066
+ * identically to {@link DroidProcessManager#spawn} but returns a promise.
3067
+ *
3068
+ * When a Windows child process exits within the startup grace period and
3069
+ * the exit looks like the `AssignProcessToJobObject` failure pattern, the
3070
+ * dead child is disposed and a fresh spawn is attempted, up to the
3071
+ * configured retry cap.
3072
+ */
3073
+ async spawnWithWindowsRetry(config, retryOptions = {}) {
3074
+ if (process.platform !== "win32") {
3075
+ return this.spawn(config);
3076
+ }
3077
+ const planned = this.prepareSpawn(config);
3078
+ const childProcess = await spawnWithWindowsJobObjectRetry(
3079
+ () => this.invokeNodeSpawn(planned),
3080
+ {
3081
+ ...retryOptions,
3082
+ logPrefix: "[DroidProcessManager]",
3083
+ logger: this.logger,
3084
+ disposeEarlyExited: (child) => {
3085
+ try {
3086
+ child.stdin?.end();
3087
+ } catch (stdinErr) {
3088
+ logWarn(
3089
+ this.logger,
3090
+ "DroidProcessManager: stdin.end() threw during dispose",
3091
+ {
3092
+ cause: stdinErr instanceof Error ? stdinErr : new Error(String(stdinErr))
3093
+ }
3094
+ );
3095
+ }
3096
+ try {
3097
+ child.kill();
3098
+ } catch (killErr) {
3099
+ logWarn(
3100
+ this.logger,
3101
+ "DroidProcessManager: kill() threw during dispose",
3102
+ {
3103
+ cause: killErr instanceof Error ? killErr : new Error(String(killErr))
3104
+ }
3105
+ );
3106
+ }
3107
+ }
3108
+ }
3109
+ );
3110
+ if (!childProcess.stdout || !childProcess.stdin) {
3111
+ throw new ConnectionError("Failed to get process stdio");
3112
+ }
3113
+ return new ManagedProcessImpl(
3114
+ childProcess,
3115
+ planned.logPrefix,
3116
+ {
3117
+ cwd: planned.expandedCwd,
3118
+ execPath: planned.execPath
3119
+ },
3120
+ this.deps,
3121
+ this.transportLoggerDeps
3122
+ );
3123
+ }
3124
+ prepareSpawn(config) {
3125
+ const command = this.commandResolver.resolveDroidCommand(
3126
+ config.isDevelopment ?? false
3127
+ );
3128
+ const execPath = config.execPath || command.execPath;
3129
+ const prefixArgs = config.execPath ? [] : command.prefixArgs;
3130
+ const args = [...prefixArgs, ...buildArgs(config)];
3131
+ const expandedCwd = config.cwd ? expandTilde(config.cwd) : void 0;
3132
+ const logPrefix = config.mode === "acp" /* Acp */ ? "[droid acp]" : "[droid exec]";
3133
+ this.logger.info("[droid process] Spawning", {
3134
+ state: logPrefix,
3135
+ path: execPath,
3136
+ args,
3137
+ cwd: expandedCwd,
3138
+ version: process.env.CLI_VERSION || "unknown"
3139
+ });
3140
+ return {
3141
+ logPrefix,
3142
+ execPath,
3143
+ expandedCwd,
3144
+ args,
3145
+ env: {
3146
+ ...this.deps.environmentResolver.sanitizeSpawnEnv({
3147
+ ...process.env,
3148
+ ...config.env
3149
+ }),
3150
+ ...config.trustedEnv
3151
+ },
3152
+ enableIpc: config.enableIpc ?? false,
3153
+ stdio: config.stdio
3154
+ };
3155
+ }
3156
+ invokeNodeSpawn(planned) {
3157
+ const options = {
3158
+ cwd: planned.expandedCwd,
3159
+ env: planned.env,
3160
+ stdio: planned.stdio ?? (planned.enableIpc ? ["pipe", "pipe", "pipe", "ipc"] : ["pipe", "pipe", "pipe"])
3161
+ };
3162
+ if (planned.enableIpc) {
3163
+ options.serialization = "json";
3164
+ }
3165
+ return spawn(planned.execPath, planned.args, options);
3166
+ }
3167
+ spawnChildProcess(config) {
3168
+ const planned = this.prepareSpawn(config);
3169
+ const childProcess = this.invokeNodeSpawn(planned);
3170
+ if (!childProcess.stdout || !childProcess.stdin) {
3171
+ throw new ConnectionError("Failed to get process stdio");
3172
+ }
3173
+ return {
3174
+ logPrefix: planned.logPrefix,
3175
+ execPath: planned.execPath,
3176
+ expandedCwd: planned.expandedCwd,
3177
+ childProcess
3178
+ };
3179
+ }
3180
+ };
3181
+
3182
+ // src/exec-core/process-transport.ts
3183
+ var ProcessTransport = class {
3184
+ managedProcess = null;
3185
+ processManager;
3186
+ options;
3187
+ // Store handlers that may be registered before connect() is called
3188
+ messageHandler = null;
3189
+ errorHandler = null;
3190
+ metrics;
3191
+ constructor(options = {}, deps = defaultExecCoreDeps) {
3192
+ this.options = options;
3193
+ const resolved = resolveExecCoreDeps(options.observability, deps);
3194
+ this.metrics = resolved.metrics;
3195
+ this.processManager = new DroidProcessManager(
3196
+ {
3197
+ observability: options.observability
3198
+ },
3199
+ deps
3200
+ );
3201
+ }
3202
+ async connect() {
3203
+ if (this.managedProcess && this.managedProcess.isConnected) {
3204
+ throw new ConnectionError("Transport already connected");
3205
+ }
3206
+ const config = {
3207
+ execPath: this.options.droidExecPath,
3208
+ isDevelopment: this.options.isDevelopment,
3209
+ mode: "stream-jsonrpc" /* StreamJsonRpc */,
3210
+ cwd: this.options.cwd,
3211
+ env: this.options.env,
3212
+ extraArgs: this.options.droidExecExtraArgs,
3213
+ enableIpc: this.options.enableIpc
3214
+ };
3215
+ const spawnStart = performance.now();
3216
+ let spawnOutcome = "error";
3217
+ try {
3218
+ this.managedProcess = process.platform === "win32" ? await this.processManager.spawnWithWindowsRetry(config) : this.processManager.spawn(config);
3219
+ spawnOutcome = "success";
3220
+ } finally {
3221
+ this.metrics.recordDuration(
3222
+ CLI_JSONRPC_CHILD_SPAWN_LATENCY_METRIC,
3223
+ performance.now() - spawnStart,
3224
+ { outcome: spawnOutcome, source: "process_transport" }
3225
+ );
3226
+ }
3227
+ if (this.messageHandler) {
3228
+ this.managedProcess.onMessage(this.messageHandler);
3229
+ }
3230
+ if (this.errorHandler) {
3231
+ this.managedProcess.onError(this.errorHandler);
3232
+ }
3233
+ }
3234
+ async send(message) {
3235
+ if (!this.managedProcess) {
3236
+ throw new ConnectionError("Transport not connected");
3237
+ }
3238
+ return this.managedProcess.send(message);
3239
+ }
3240
+ onMessage(handler) {
3241
+ this.messageHandler = handler;
3242
+ if (this.managedProcess) {
3243
+ this.managedProcess.onMessage(handler);
3244
+ }
3245
+ }
3246
+ onError(handler) {
3247
+ this.errorHandler = handler;
3248
+ if (this.managedProcess) {
3249
+ this.managedProcess.onError(handler);
3250
+ }
3251
+ }
3252
+ async close() {
3253
+ if (this.managedProcess) {
3254
+ await this.managedProcess.close();
3255
+ this.managedProcess = null;
3256
+ }
3257
+ }
3258
+ get isConnected() {
3259
+ return this.managedProcess?.isConnected ?? false;
3260
+ }
3261
+ getManagedProcess() {
3262
+ return this.managedProcess;
3263
+ }
3264
+ };
3265
+
3266
+ // src/helpers.ts
3267
+ function resolveApiKey(apiKey) {
3268
+ const resolved = apiKey ?? process.env.FACTORY_API_KEY;
3269
+ if (!resolved) {
3270
+ throw new DroidClientError(
3271
+ "No Factory API key found. Pass `apiKey` when creating the session, or set the FACTORY_API_KEY environment variable."
3272
+ );
3273
+ }
3274
+ return resolved;
3275
+ }
3276
+ async function createTransport(options) {
3277
+ if (options.transport) {
3278
+ return options.transport;
3279
+ }
3280
+ const processTransport = new ProcessTransport({
3281
+ droidExecPath: options.execPath,
3282
+ droidExecExtraArgs: options.execArgs,
3283
+ cwd: options.cwd,
3284
+ env: { ...options.env, FACTORY_API_KEY: resolveApiKey(options.apiKey) },
3285
+ observability: options.observability
3286
+ });
3287
+ await processTransport.connect();
3288
+ return processTransport;
3289
+ }
3290
+ function setupClientHandlers(client, options) {
3291
+ if (options.permissionHandler) {
3292
+ const handler = options.permissionHandler;
3293
+ client.setPermissionHandler((event) => handler(event.params));
3294
+ }
3295
+ if (options.askUserHandler) {
3296
+ const handler = options.askUserHandler;
3297
+ client.setAskUserHandler((event) => handler(event.params));
3298
+ }
3299
+ }
3300
+ async function createConfiguredClient(options) {
3301
+ const transport = await createTransport(options);
3302
+ const client = new DroidClient({
3303
+ transport,
3304
+ observability: options.observability
3305
+ });
3306
+ setupClientHandlers(client, options);
3307
+ return { transport, client };
3308
+ }
3309
+ async function closeQuietly(resource) {
3310
+ if (!resource) {
3311
+ return;
3312
+ }
3313
+ try {
3314
+ await resource.close();
3315
+ } catch {
3316
+ }
3317
+ }
3318
+ function buildInitParams(options) {
3319
+ return {
3320
+ machineId: options.machineId ?? "default",
3321
+ cwd: options.cwd ?? process.cwd(),
3322
+ ...options.modelId !== void 0 && { modelId: options.modelId },
3323
+ ...options.autonomyLevel !== void 0 && {
3324
+ autonomyLevel: options.autonomyLevel
3325
+ },
3326
+ ...options.interactionMode !== void 0 && {
3327
+ interactionMode: options.interactionMode
3328
+ },
3329
+ ...options.reasoningEffort !== void 0 && {
3330
+ reasoningEffort: options.reasoningEffort
3331
+ },
3332
+ ...options.systemPrompt !== void 0 && {
3333
+ systemPrompt: options.systemPrompt
3334
+ },
3335
+ ...options.specModeModelId !== void 0 && {
3336
+ specModeModelId: options.specModeModelId
3337
+ },
3338
+ ...options.specModeReasoningEffort !== void 0 && {
3339
+ specModeReasoningEffort: options.specModeReasoningEffort
3340
+ },
3341
+ ...options.mcpServers !== void 0 && {
3342
+ mcpServers: options.mcpServers
3343
+ },
3344
+ ...options.disabledToolIds !== void 0 && {
3345
+ disabledToolIds: options.disabledToolIds
3346
+ },
3347
+ ...options.sessionSource !== void 0 && {
3348
+ sessionSource: options.sessionSource
3349
+ },
3350
+ ...options.autoRejectPermissionRequests !== void 0 && {
3351
+ autoRejectPermissionRequests: options.autoRejectPermissionRequests
3352
+ },
3353
+ ...options.disableBuiltinSkills !== void 0 && {
3354
+ disableBuiltinSkills: options.disableBuiltinSkills
3355
+ },
3356
+ tags: [...options.tags ?? [], SDK_TAG]
3357
+ };
3358
+ }
3359
+
3360
+ // src/mcp.ts
3361
+ import { randomBytes, timingSafeEqual } from "crypto";
3362
+ import { once } from "events";
3363
+ import http from "http";
3364
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3365
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
3366
+ import { z as z2 } from "zod";
3367
+ function tool(name, description, inputSchemaOrHandler, handler) {
3368
+ if (typeof inputSchemaOrHandler === "function") {
3369
+ const actualHandler = inputSchemaOrHandler;
3370
+ return {
3371
+ name,
3372
+ description,
3373
+ handler: (input) => actualHandler(input)
3374
+ };
3375
+ }
3376
+ if (!handler) {
3377
+ throw new Error(`Missing handler for SDK MCP tool "${name}"`);
3378
+ }
3379
+ const inputObjectSchema = z2.object(inputSchemaOrHandler);
3380
+ return {
3381
+ name,
3382
+ description,
3383
+ inputSchema: inputSchemaOrHandler,
3384
+ handler: (input) => handler(inputObjectSchema.parse(input))
3385
+ };
3386
+ }
3387
+ function isSdkMcpServer(server) {
3388
+ return server instanceof SdkMcpServer;
3389
+ }
3390
+ function toCallToolResult(result) {
3391
+ if (typeof result === "string") {
3392
+ return {
3393
+ content: [{ type: "text", text: result }]
3394
+ };
3395
+ }
3396
+ return result;
3397
+ }
3398
+ async function readJsonBody(req) {
3399
+ const chunks = [];
3400
+ for await (const chunk of req) {
3401
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
3402
+ }
3403
+ if (chunks.length === 0) {
3404
+ return void 0;
3405
+ }
3406
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
3407
+ }
3408
+ function writeJsonError(res, statusCode, message, headers = {}) {
3409
+ if (res.headersSent) {
3410
+ return;
3411
+ }
3412
+ res.writeHead(statusCode, {
3413
+ "content-type": "application/json",
3414
+ ...headers
3415
+ });
3416
+ res.end(
3417
+ JSON.stringify({
3418
+ jsonrpc: JSONRPC_VERSION,
3419
+ error: { code: -32603 /* INTERNAL_ERROR */, message },
3420
+ id: null
3421
+ })
3422
+ );
3423
+ }
3424
+ function hasValidBearerToken(authorization, token) {
3425
+ if (!authorization) {
3426
+ return false;
3427
+ }
3428
+ const separator = authorization.indexOf(" ");
3429
+ if (separator === -1 || authorization.slice(0, separator).toLowerCase() !== "bearer") {
3430
+ return false;
3431
+ }
3432
+ const actual = Buffer.from(authorization.slice(separator + 1));
3433
+ const expected = Buffer.from(token);
3434
+ return actual.length === expected.length && timingSafeEqual(actual, expected);
3435
+ }
3436
+ var SdkMcpServer = class {
3437
+ name;
3438
+ version;
3439
+ tools;
3440
+ _httpServer = null;
3441
+ _url = null;
3442
+ _token = null;
3443
+ constructor(options) {
3444
+ this.name = options.name;
3445
+ this.version = options.version ?? "1.0.0";
3446
+ this.tools = options.tools;
3447
+ }
3448
+ get config() {
3449
+ if (!this._url || !this._token) {
3450
+ return null;
3451
+ }
3452
+ return {
3453
+ type: "http" /* Http */,
3454
+ name: this.name,
3455
+ url: this._url,
3456
+ oauth: false,
3457
+ headers: [
3458
+ {
3459
+ name: "Authorization",
3460
+ value: `Bearer ${this._token}`
3461
+ }
3462
+ ]
3463
+ };
3464
+ }
3465
+ async start() {
3466
+ if (this.config) {
3467
+ return this.config;
3468
+ }
3469
+ this._token = randomBytes(32).toString("base64url");
3470
+ this._httpServer = http.createServer((req, res) => {
3471
+ void this.handleRequest(req, res);
3472
+ });
3473
+ this._httpServer.listen(0, "127.0.0.1");
3474
+ await once(this._httpServer, "listening");
3475
+ const address = this._httpServer.address();
3476
+ if (!address || typeof address === "string") {
3477
+ throw new Error("Unable to determine SDK MCP server address");
3478
+ }
3479
+ this._url = `http://127.0.0.1:${address.port}/mcp`;
3480
+ const config = this.config;
3481
+ if (!config) {
3482
+ throw new Error("Unable to start SDK MCP server");
3483
+ }
3484
+ return config;
3485
+ }
3486
+ async close() {
3487
+ const server = this._httpServer;
3488
+ this._httpServer = null;
3489
+ this._url = null;
3490
+ this._token = null;
3491
+ if (!server) {
3492
+ return;
3493
+ }
3494
+ server.closeAllConnections?.();
3495
+ server.close();
3496
+ await once(server, "close");
3497
+ }
3498
+ createMcpServer() {
3499
+ const server = new McpServer({
3500
+ name: this.name,
3501
+ version: this.version
3502
+ });
3503
+ for (const sdkTool of this.tools) {
3504
+ server.registerTool(
3505
+ sdkTool.name,
3506
+ {
3507
+ description: sdkTool.description,
3508
+ ...sdkTool.inputSchema && {
3509
+ inputSchema: sdkTool.inputSchema
3510
+ }
3511
+ },
3512
+ async (input) => toCallToolResult(await sdkTool.handler(input))
3513
+ );
3514
+ }
3515
+ return server;
3516
+ }
3517
+ async handleRequest(req, res) {
3518
+ if (req.url !== "/mcp") {
3519
+ res.writeHead(404).end();
3520
+ return;
3521
+ }
3522
+ if (req.method !== "POST") {
3523
+ res.writeHead(405).end();
3524
+ return;
3525
+ }
3526
+ const token = this._token;
3527
+ if (!token || !hasValidBearerToken(req.headers.authorization, token)) {
3528
+ writeJsonError(res, 401, "Unauthorized", {
3529
+ "www-authenticate": "Bearer"
3530
+ });
3531
+ return;
3532
+ }
3533
+ const server = this.createMcpServer();
3534
+ const transport = new StreamableHTTPServerTransport({
3535
+ sessionIdGenerator: void 0
3536
+ });
3537
+ res.on("close", () => {
3538
+ void transport.close();
3539
+ void server.close();
3540
+ });
3541
+ try {
3542
+ const body = await readJsonBody(req);
3543
+ await server.connect(transport);
3544
+ await transport.handleRequest(req, res, body);
3545
+ } catch (error) {
3546
+ writeJsonError(
3547
+ res,
3548
+ 500,
3549
+ error instanceof Error ? error.message : "Internal server error"
3550
+ );
3551
+ await transport.close();
3552
+ await server.close();
3553
+ }
3554
+ }
3555
+ };
3556
+ function createSdkMcpServer(options) {
3557
+ return new SdkMcpServer(options);
3558
+ }
3559
+ async function startSdkMcpServers(servers) {
3560
+ if (!servers) {
3561
+ return { cleanup: async () => {
3562
+ } };
3563
+ }
3564
+ const startedServers = [];
3565
+ const mcpServers = [];
3566
+ try {
3567
+ for (const server of servers) {
3568
+ if (isSdkMcpServer(server)) {
3569
+ mcpServers.push(await server.start());
3570
+ startedServers.push(server);
3571
+ } else {
3572
+ mcpServers.push(server);
3573
+ }
3574
+ }
3575
+ } catch (error) {
3576
+ await Promise.all(startedServers.map((server) => server.close()));
3577
+ throw error;
3578
+ }
3579
+ return {
3580
+ mcpServers,
3581
+ cleanup: async () => {
3582
+ await Promise.all(startedServers.map((server) => server.close()));
3583
+ }
3584
+ };
3585
+ }
3586
+
3587
+ // src/session.ts
3588
+ var DroidSession = class _DroidSession {
3589
+ /** @internal */
3590
+ constructor(client, sessionId, metadata, _runtime, cleanupCallbacks = []) {
3591
+ this._runtime = _runtime;
3592
+ this._client = client;
3593
+ this._sessionId = sessionId;
3594
+ this._settings = metadata.settings;
3595
+ this._cwd = metadata.cwd;
3596
+ this._cleanupCallbacks = cleanupCallbacks;
3597
+ this._bindMetadataNotifications();
3598
+ this._bindAbortSignal();
3599
+ }
3600
+ _runtime;
3601
+ _client;
3602
+ _sessionId;
3603
+ _settings;
3604
+ _cwd;
3605
+ _settingsRevision = 0;
3606
+ _status = "active";
3607
+ _replacementSessionId;
3608
+ _cleanupAbortSignal = null;
3609
+ _cleanupCallbacks = [];
3610
+ _activeBridges = /* @__PURE__ */ new Set();
3611
+ _notificationCleanups = /* @__PURE__ */ new Set();
3612
+ get id() {
3613
+ return this._sessionId;
3614
+ }
3615
+ get settings() {
3616
+ return this._settings;
3617
+ }
3618
+ get cwd() {
3619
+ return this._cwd;
3620
+ }
3621
+ async *stream(prompt, options) {
3622
+ this._ensureNotClosed();
3623
+ yield* streamFromClient(
3624
+ {
3625
+ onNotification: (handler) => this._client.onNotification((notification) => {
3626
+ const inner = extractInnerNotification(notification);
3627
+ if (inner) handler(inner);
3628
+ }),
3629
+ onError: (handler) => this._client.onError(handler),
3630
+ addUserMessage: (params) => this._client.addUserMessage(params),
3631
+ interruptSession: () => this._client.interruptSession()
3632
+ },
3633
+ this._sessionId,
3634
+ this._activeBridges,
3635
+ prompt,
3636
+ options
3637
+ );
3638
+ }
3639
+ async interrupt() {
3640
+ this._ensureNotClosed();
3641
+ await this._client.interruptSession();
3642
+ }
3643
+ async close() {
3644
+ if (this._status === "closed" || this._status === "replaced") {
3645
+ return;
3646
+ }
3647
+ this._status = "closed";
3648
+ this._releaseHandleSubscriptions();
3649
+ this._cleanupAbortSignal?.();
3650
+ this._cleanupAbortSignal = null;
3651
+ for (const bridge of this._activeBridges) {
3652
+ bridge.signalDone();
3653
+ bridge.release();
3654
+ }
3655
+ try {
3656
+ await this._client.closeSession({ reason: "other" }).catch(() => {
3657
+ });
3658
+ await this._client.close();
3659
+ } finally {
3660
+ const cleanups = this._cleanupCallbacks.splice(0);
3661
+ await Promise.all(cleanups.map((cleanup) => cleanup()));
3662
+ }
3663
+ }
3664
+ async updateSettings(params) {
3665
+ this._ensureNotClosed();
3666
+ const revision = this._settingsRevision;
3667
+ const result = unwrapResponseResult(
3668
+ await this._client.updateSessionSettings(params)
3669
+ );
3670
+ if (params.disabledToolIds !== void 0) {
3671
+ this._runtime.loadParams.disabledToolIds = params.disabledToolIds;
3672
+ }
3673
+ if (this._settingsRevision === revision) {
3674
+ this._settings = mergeSessionSettings(this._settings, params);
3675
+ }
3676
+ return result;
3677
+ }
3678
+ async enterSpecMode(params = {}) {
3679
+ return this.updateSettings({
3680
+ interactionMode: "spec" /* Spec */,
3681
+ ...params
3682
+ });
3683
+ }
3684
+ async exitSpecMode() {
3685
+ return this.updateSettings({
3686
+ interactionMode: "auto" /* Auto */
3687
+ });
3688
+ }
3689
+ async addMcpServer(params) {
3690
+ this._ensureNotClosed();
3691
+ return unwrapResponseResult(await this._client.addMcpServer(params));
3692
+ }
3693
+ async removeMcpServer(params) {
3694
+ this._ensureNotClosed();
3695
+ return unwrapResponseResult(await this._client.removeMcpServer(params));
3696
+ }
3697
+ async toggleMcpServer(params) {
3698
+ this._ensureNotClosed();
3699
+ return unwrapResponseResult(await this._client.toggleMcpServer(params));
3700
+ }
3701
+ async listMcpServers() {
3702
+ this._ensureNotClosed();
3703
+ return unwrapResponseResult(await this._client.listMcpServers());
3704
+ }
3705
+ async listMcpTools() {
3706
+ this._ensureNotClosed();
3707
+ return unwrapResponseResult(await this._client.listMcpTools()).tools;
3708
+ }
3709
+ async listTools(params = {}) {
3710
+ this._ensureNotClosed();
3711
+ return unwrapResponseResult(await this._client.listTools(params)).tools.map(
3712
+ ({ id: _protocolId, llmId, currentlyAllowed, ...tool2 }) => ({
3713
+ ...tool2,
3714
+ id: llmId,
3715
+ allowed: currentlyAllowed
3716
+ })
3717
+ );
3718
+ }
3719
+ async authenticateMcpServer(params) {
3720
+ this._ensureNotClosed();
3721
+ return unwrapResponseResult(
3722
+ await this._client.authenticateMcpServer(params)
3723
+ );
3724
+ }
3725
+ async listSkills() {
3726
+ this._ensureNotClosed();
3727
+ return unwrapResponseResult(await this._client.listSkills());
3728
+ }
3729
+ async setSkillDisabled(params) {
3730
+ this._ensureNotClosed();
3731
+ return unwrapResponseResult(
3732
+ await this._client.setSkillDisabled(
3733
+ params.skillName,
3734
+ params.disabled,
3735
+ params.settingsLevel
3736
+ )
3737
+ );
3738
+ }
3739
+ async getRewindInfo(params) {
3740
+ this._ensureNotClosed();
3741
+ return unwrapResponseResult(await this._client.getRewindInfo(params));
3742
+ }
3743
+ async rewind(params) {
3744
+ const { session, result } = await this._runReplacement(
3745
+ () => this._client.executeRewind(params).then(unwrapResponseResult)
3746
+ );
3747
+ const { newSessionId: _newSessionId, ...metadata } = result;
3748
+ return { session, ...metadata };
3749
+ }
3750
+ async compact(params) {
3751
+ const { session, result } = await this._runReplacement(
3752
+ () => this._client.compactSession(params ?? {}).then(unwrapResponseResult)
3753
+ );
3754
+ return { session, removedCount: result.removedCount };
3755
+ }
3756
+ async fork(params = {}) {
3757
+ const { session } = await this._runReplacement(
3758
+ () => this._client.forkSession(params).then(unwrapResponseResult)
3759
+ );
3760
+ return session;
3761
+ }
3762
+ async getContextStats() {
3763
+ this._ensureNotClosed();
3764
+ return unwrapResponseResult(await this._client.getContextStats());
3765
+ }
3766
+ async rename(params) {
3767
+ this._ensureNotClosed();
3768
+ unwrapResponseResult(await this._client.renameSession(params));
3769
+ }
3770
+ onNotification(callback, filter) {
3771
+ this._ensureNotClosed();
3772
+ const unsubscribe = this._client.onNotification(callback, filter);
3773
+ const cleanup = () => {
3774
+ this._notificationCleanups.delete(cleanup);
3775
+ unsubscribe();
3776
+ };
3777
+ this._notificationCleanups.add(cleanup);
3778
+ return cleanup;
3779
+ }
3780
+ _ensureNotClosed() {
3781
+ if (this._status === "replaced" && this._replacementSessionId) {
3782
+ throw new SessionReplacedError(
3783
+ this._sessionId,
3784
+ this._replacementSessionId
3785
+ );
3786
+ }
3787
+ if (this._status !== "active") {
3788
+ throw new ConnectionError(
3789
+ this._status === "replacing" ? "Session replacement is already in progress." : "Session has been closed. Create a new session to continue."
3790
+ );
3791
+ }
3792
+ }
3793
+ _beginReplacement() {
3794
+ this._ensureNotClosed();
3795
+ if (this._activeBridges.size > 0) {
3796
+ throw new ConcurrentStreamError(this._sessionId);
3797
+ }
3798
+ this._status = "replacing";
3799
+ }
3800
+ async _runReplacement(operation) {
3801
+ this._beginReplacement();
3802
+ let result;
3803
+ try {
3804
+ result = await operation();
3805
+ } catch (error) {
3806
+ if (this._status === "replacing") {
3807
+ this._status = "active";
3808
+ }
3809
+ throw error;
3810
+ }
3811
+ if (this._status !== "replacing") {
3812
+ throw new SessionReplacementError(this._sessionId, result.newSessionId, {
3813
+ cause: new ConnectionError(
3814
+ "Session closed while replacement was in progress."
3815
+ ),
3816
+ rollbackError: new ConnectionError(
3817
+ "The source session was already closed."
3818
+ )
3819
+ });
3820
+ }
3821
+ return {
3822
+ session: await this._loadReplacement(result.newSessionId),
3823
+ result
3824
+ };
3825
+ }
3826
+ async _loadReplacement(replacementSessionId) {
3827
+ try {
3828
+ const loadResult = unwrapResponseResult(
3829
+ await this._client.loadSession({
3830
+ ...this._runtime.loadParams,
3831
+ sessionId: replacementSessionId
3832
+ })
3833
+ );
3834
+ if (this._status !== "replacing") {
3835
+ throw new ConnectionError(
3836
+ "Session closed while replacement was loading."
3837
+ );
3838
+ }
3839
+ this._cleanupAbortSignal?.();
3840
+ this._cleanupAbortSignal = null;
3841
+ this._releaseHandleSubscriptions();
3842
+ const cleanupCallbacks = this._cleanupCallbacks;
3843
+ this._cleanupCallbacks = [];
3844
+ const replacement = new _DroidSession(
3845
+ this._client,
3846
+ replacementSessionId,
3847
+ { settings: loadResult.settings, cwd: loadResult.cwd },
3848
+ this._runtime,
3849
+ cleanupCallbacks
3850
+ );
3851
+ this._replacementSessionId = replacementSessionId;
3852
+ this._status = "replaced";
3853
+ return replacement;
3854
+ } catch (cause) {
3855
+ if (this._status !== "replacing") {
3856
+ throw new SessionReplacementError(
3857
+ this._sessionId,
3858
+ replacementSessionId,
3859
+ {
3860
+ cause,
3861
+ rollbackError: new ConnectionError(
3862
+ "The source session was closed before rollback."
3863
+ )
3864
+ }
3865
+ );
3866
+ }
3867
+ let rollbackResult;
3868
+ try {
3869
+ rollbackResult = unwrapResponseResult(
3870
+ await this._client.loadSession({
3871
+ ...this._runtime.loadParams,
3872
+ sessionId: this._sessionId
3873
+ })
3874
+ );
3875
+ } catch (rollbackError) {
3876
+ await this._disposeAfterFailedRollback();
3877
+ throw new SessionReplacementError(
3878
+ this._sessionId,
3879
+ replacementSessionId,
3880
+ { cause, rollbackError }
3881
+ );
3882
+ }
3883
+ if (this._status !== "replacing") {
3884
+ const rollbackError = new ConnectionError(
3885
+ "Session closed while replacement rollback was loading."
3886
+ );
3887
+ await this._disposeAfterFailedRollback();
3888
+ throw new SessionReplacementError(
3889
+ this._sessionId,
3890
+ replacementSessionId,
3891
+ { cause, rollbackError }
3892
+ );
3893
+ }
3894
+ this._settings = rollbackResult.settings;
3895
+ this._cwd = rollbackResult.cwd;
3896
+ this._status = "active";
3897
+ throw new SessionReplacementError(this._sessionId, replacementSessionId, {
3898
+ cause
3899
+ });
3900
+ }
3901
+ }
3902
+ _bindAbortSignal() {
3903
+ this._cleanupAbortSignal = wireAbortSignal(
3904
+ this._runtime.abortSignal,
3905
+ () => void this.close()
3906
+ );
3907
+ }
3908
+ _bindMetadataNotifications() {
3909
+ const unsubscribe = this._client.onNotification((notification) => {
3910
+ const inner = extractInnerNotification(notification);
3911
+ if (inner?.type === "settings_updated" /* SETTINGS_UPDATED */) {
3912
+ this._settings = mergeSessionSettings(this._settings, inner.settings);
3913
+ this._settingsRevision++;
3914
+ } else if (inner?.type === "session_working_directory_changed" /* SESSION_WORKING_DIRECTORY_CHANGED */) {
3915
+ this._cwd = inner.cwd;
3916
+ }
3917
+ });
3918
+ const cleanup = () => {
3919
+ this._notificationCleanups.delete(cleanup);
3920
+ unsubscribe();
3921
+ };
3922
+ this._notificationCleanups.add(cleanup);
3923
+ }
3924
+ _releaseHandleSubscriptions() {
3925
+ for (const cleanup of [...this._notificationCleanups]) cleanup();
3926
+ }
3927
+ async _disposeAfterFailedRollback() {
3928
+ this._status = "closed";
3929
+ this._cleanupAbortSignal?.();
3930
+ this._cleanupAbortSignal = null;
3931
+ this._releaseHandleSubscriptions();
3932
+ await closeQuietly(this._client);
3933
+ const cleanups = this._cleanupCallbacks.splice(0);
3934
+ await Promise.allSettled(
3935
+ cleanups.map((cleanup) => Promise.resolve().then(cleanup))
3936
+ );
3937
+ }
3938
+ };
3939
+ function createReplacementLoadParams(options, mcpServers) {
3940
+ return {
3941
+ mcpServers,
3942
+ disabledToolIds: options.disabledToolIds,
3943
+ autoRejectPermissionRequests: options.autoRejectPermissionRequests,
3944
+ disableBuiltinSkills: options.disableBuiltinSkills,
3945
+ sessionSource: options.sessionSource
3946
+ };
3947
+ }
3948
+ async function createSession(options = {}) {
3949
+ const { client } = await createConfiguredClient(options);
3950
+ let cleanupInitAbortSignal = options.abortSignal?.aborted ? () => {
3951
+ } : wireAbortSignal(options.abortSignal, () => {
3952
+ void closeQuietly(client);
3953
+ });
3954
+ let sdkMcpServers;
3955
+ try {
3956
+ sdkMcpServers = await startSdkMcpServers(options.mcpServers);
3957
+ const initParams = buildInitParams({
3958
+ ...options,
3959
+ mcpServers: sdkMcpServers.mcpServers
3960
+ });
3961
+ const initResult = unwrapResponseResult(
3962
+ await client.initializeSession(initParams)
3963
+ );
3964
+ const session = new DroidSession(
3965
+ client,
3966
+ initResult.sessionId,
3967
+ {
3968
+ settings: initResult.settings,
3969
+ cwd: initResult.worktree?.path ?? initParams.cwd
3970
+ },
3971
+ {
3972
+ abortSignal: options.abortSignal,
3973
+ loadParams: createReplacementLoadParams(
3974
+ options,
3975
+ sdkMcpServers.mcpServers
3976
+ )
3977
+ },
3978
+ [sdkMcpServers.cleanup]
3979
+ );
3980
+ cleanupInitAbortSignal();
3981
+ cleanupInitAbortSignal = () => {
3982
+ };
3983
+ return session;
3984
+ } catch (error) {
3985
+ cleanupInitAbortSignal();
3986
+ await sdkMcpServers?.cleanup();
3987
+ await closeQuietly(client);
3988
+ throw error;
3989
+ }
3990
+ }
3991
+ async function resumeSession(sessionId, options = {}) {
3992
+ const { client } = await createConfiguredClient(options);
3993
+ let cleanupLoadAbortSignal = options.abortSignal?.aborted ? () => {
3994
+ } : wireAbortSignal(options.abortSignal, () => {
3995
+ void closeQuietly(client);
3996
+ });
3997
+ let sdkMcpServers;
3998
+ try {
3999
+ sdkMcpServers = await startSdkMcpServers(options.mcpServers);
4000
+ const replacementLoadParams = createReplacementLoadParams(
4001
+ options,
4002
+ sdkMcpServers.mcpServers
4003
+ );
4004
+ const loadResult = unwrapResponseResult(
4005
+ await client.loadSession({ sessionId, ...replacementLoadParams })
4006
+ );
4007
+ const session = new DroidSession(
4008
+ client,
4009
+ sessionId,
4010
+ { settings: loadResult.settings, cwd: loadResult.cwd },
4011
+ {
4012
+ abortSignal: options.abortSignal,
4013
+ loadParams: replacementLoadParams
4014
+ },
4015
+ [sdkMcpServers.cleanup]
4016
+ );
4017
+ cleanupLoadAbortSignal();
4018
+ cleanupLoadAbortSignal = () => {
4019
+ };
4020
+ return session;
4021
+ } catch (error) {
4022
+ cleanupLoadAbortSignal();
4023
+ await sdkMcpServers?.cleanup();
4024
+ await closeQuietly(client);
4025
+ throw error;
4026
+ }
4027
+ }
4028
+
4029
+ // src/run.ts
4030
+ async function run(prompt, options = {}) {
4031
+ const session = await createSession(options);
4032
+ try {
4033
+ for await (const msg of session.stream(prompt, {
4034
+ ...options,
4035
+ includePartialMessages: false
4036
+ })) {
4037
+ if (msg.type === DroidMessageType.Result) {
4038
+ return msg;
4039
+ }
4040
+ }
4041
+ throw new Error("Stream completed without a result message");
4042
+ } finally {
4043
+ await session.close();
4044
+ }
4045
+ }
4046
+
4047
+ // src/session-discovery.ts
4048
+ import * as fs3 from "fs";
4049
+ import * as os from "os";
4050
+ import * as path2 from "path";
4051
+ var FAVORITES_FILE = ".favorites";
4052
+ var SESSION_EXTENSION = ".jsonl";
4053
+ var SETTINGS_SUFFIX = ".settings.json";
4054
+ var MISSION_TAG_PREFIX = "mission:";
4055
+ var MISSION_ID_METADATA_KEY = "missionId";
4056
+ var DECOMP_SESSION_TYPE_TAG = "decompSessionType";
4057
+ var DECOMP_SESSION_TYPE_METADATA_KEY = "value";
4058
+ var LF = 10;
4059
+ var CR = 13;
4060
+ var SPACE = 32;
4061
+ var TAB = 9;
4062
+ var PARSE_OVERSAMPLE = 20;
4063
+ function readFileBuffer(filePath) {
4064
+ try {
4065
+ return fs3.readFileSync(filePath);
4066
+ } catch {
4067
+ return null;
4068
+ }
4069
+ }
4070
+ function parseJsonBuffer(buf) {
4071
+ try {
4072
+ return JSON.parse(buf.toString("utf-8"));
4073
+ } catch {
4074
+ return null;
4075
+ }
4076
+ }
4077
+ function scanBufferForLines(buf) {
4078
+ let nonEmptyLineCount = 0;
4079
+ let firstLineEnd = -1;
4080
+ let currentLineHasContent = false;
4081
+ for (let i = 0; i < buf.length; i++) {
4082
+ const ch = buf[i];
4083
+ if (ch === LF) {
4084
+ if (currentLineHasContent) nonEmptyLineCount++;
4085
+ if (firstLineEnd === -1) firstLineEnd = i;
4086
+ currentLineHasContent = false;
4087
+ } else if (ch !== CR && ch !== SPACE && ch !== TAB) {
4088
+ currentLineHasContent = true;
4089
+ }
4090
+ }
4091
+ if (currentLineHasContent) nonEmptyLineCount++;
4092
+ const end = firstLineEnd === -1 ? buf.length : firstLineEnd > 0 && buf[firstLineEnd - 1] === CR ? firstLineEnd - 1 : firstLineEnd;
4093
+ return {
4094
+ firstLine: buf.subarray(0, end),
4095
+ nonEmptyLineCount
4096
+ };
4097
+ }
4098
+ function loadFavorites(sessionsDir) {
4099
+ const buf = readFileBuffer(path2.join(sessionsDir, FAVORITES_FILE));
4100
+ if (!buf) return /* @__PURE__ */ new Set();
4101
+ const parsed = parseJsonBuffer(buf);
4102
+ if (!Array.isArray(parsed)) return /* @__PURE__ */ new Set();
4103
+ return new Set(parsed.filter((id) => typeof id === "string"));
4104
+ }
4105
+ function loadSettingsFile(directory, sessionId) {
4106
+ const buf = readFileBuffer(
4107
+ path2.join(directory, `${sessionId}${SETTINGS_SUFFIX}`)
4108
+ );
4109
+ if (!buf) return null;
4110
+ const parsed = parseJsonBuffer(buf);
4111
+ if (parsed === null) return null;
4112
+ const result = SessionSettingsFileSchema.safeParse(parsed);
4113
+ return result.success ? result.data : null;
4114
+ }
4115
+ function getMissionMetadataFromTags(settings) {
4116
+ if (!settings?.tags) return {};
4117
+ const missionTag = settings.tags.find(
4118
+ (tag) => tag.name.startsWith(MISSION_TAG_PREFIX)
4119
+ );
4120
+ const roleTag = settings.tags.find(
4121
+ (tag) => tag.name === DECOMP_SESSION_TYPE_TAG
4122
+ );
4123
+ return {
4124
+ decompMissionId: missionTag?.metadata?.[MISSION_ID_METADATA_KEY],
4125
+ decompSessionType: roleTag?.metadata?.[DECOMP_SESSION_TYPE_METADATA_KEY]
4126
+ };
4127
+ }
4128
+ function parseSessionFile(candidate, ctx) {
4129
+ const buf = readFileBuffer(candidate.sessionPath);
4130
+ if (!buf) return null;
4131
+ const scanned = scanBufferForLines(buf);
4132
+ const firstParsed = parseJsonBuffer(scanned.firstLine);
4133
+ if (firstParsed === null) return null;
4134
+ const firstResult = SessionStartEventSchema.safeParse(firstParsed);
4135
+ if (!firstResult.success) return null;
4136
+ const summary = firstResult.data;
4137
+ if (ctx.requiredCwd !== void 0 && (summary.cwd === void 0 || path2.resolve(summary.cwd) !== ctx.requiredCwd)) {
4138
+ return null;
4139
+ }
4140
+ const settingsName = `${candidate.sessionId}${SETTINGS_SUFFIX}`;
4141
+ const settings = candidate.siblingNames.has(settingsName) ? loadSettingsFile(candidate.directory, candidate.sessionId) : null;
4142
+ if (settings?.archivedAt) return null;
4143
+ const tagMeta = getMissionMetadataFromTags(settings);
4144
+ const decompSessionType = summary.decompSessionType ?? SessionStartDecompSessionTypeSchema.safeParse(tagMeta.decompSessionType).data;
4145
+ const messageCount = Math.max(0, scanned.nonEmptyLineCount - 1);
4146
+ return {
4147
+ id: candidate.sessionId,
4148
+ title: summary.title,
4149
+ owner: summary.owner ?? "",
4150
+ messageCount,
4151
+ modifiedTime: candidate.stats.mtime,
4152
+ createdTime: candidate.stats.birthtime || candidate.stats.ctime,
4153
+ isFavorite: ctx.favorites.has(candidate.sessionId),
4154
+ cwd: summary.cwd,
4155
+ decompSessionType,
4156
+ decompMissionId: tagMeta.decompMissionId ?? summary.decompMissionId
4157
+ };
4158
+ }
4159
+ function readDirEntries(directory) {
4160
+ try {
4161
+ return fs3.readdirSync(directory, { withFileTypes: true });
4162
+ } catch {
4163
+ return [];
4164
+ }
4165
+ }
4166
+ function collectCandidates(directory, entries) {
4167
+ const siblingNames = new Set(entries.map((e) => e.name));
4168
+ const candidates = [];
4169
+ for (const entry of entries) {
4170
+ if (entry.isDirectory()) continue;
4171
+ if (!entry.name.endsWith(SESSION_EXTENSION)) continue;
4172
+ const sessionPath = path2.join(directory, entry.name);
4173
+ let stats;
4174
+ try {
4175
+ stats = fs3.statSync(sessionPath);
4176
+ } catch {
4177
+ continue;
4178
+ }
4179
+ candidates.push({
4180
+ sessionId: entry.name.slice(0, -SESSION_EXTENSION.length),
4181
+ sessionPath,
4182
+ directory,
4183
+ siblingNames,
4184
+ stats
4185
+ });
4186
+ }
4187
+ return candidates;
4188
+ }
4189
+ function parseUpTo(candidates, ctx, limit) {
4190
+ const out = [];
4191
+ for (const candidate of candidates) {
4192
+ if (limit !== void 0 && out.length >= limit) break;
4193
+ const metadata = parseSessionFile(candidate, ctx);
4194
+ if (metadata) out.push(metadata);
4195
+ }
4196
+ return out;
4197
+ }
4198
+ function sanitizePathToDirectoryName(cwd) {
4199
+ let expandedPath = cwd;
4200
+ if (cwd.startsWith("~/") || cwd === "~") {
4201
+ expandedPath = path2.join(os.homedir(), cwd.slice(1));
4202
+ }
4203
+ const absolutePath = path2.resolve(expandedPath);
4204
+ let canonicalPath = absolutePath;
4205
+ try {
4206
+ canonicalPath = fs3.realpathSync(absolutePath);
4207
+ } catch {
4208
+ canonicalPath = absolutePath;
4209
+ }
4210
+ const normalized = canonicalPath.replace(/[\\/]+$/, "");
4211
+ if (process.platform === "win32") {
4212
+ return `-${normalized.replace(/^([A-Z]):/i, "$1").replace(/[\\/]+/g, "-")}`;
4213
+ }
4214
+ return `-${normalized.replace(/^\/+/, "").replace(/\/+/g, "-")}`;
4215
+ }
4216
+ function getDefaultSessionsDir() {
4217
+ return path2.join(os.homedir(), ".factory", "sessions");
4218
+ }
4219
+ async function listSessions(options = {}) {
4220
+ const sessionsDir = options.sessionsDir ?? getDefaultSessionsDir();
4221
+ const favorites = loadFavorites(sessionsDir);
4222
+ const rootEntries = readDirEntries(sessionsDir);
4223
+ const legacyCandidates = collectCandidates(sessionsDir, rootEntries);
4224
+ const projectCandidates = [];
4225
+ let requiredCwd;
4226
+ if (options.fetchOutsideCWD) {
4227
+ for (const entry of rootEntries) {
4228
+ if (!entry.isDirectory()) continue;
4229
+ if (!entry.name.startsWith("-")) continue;
4230
+ const dir = path2.join(sessionsDir, entry.name);
4231
+ projectCandidates.push(...collectCandidates(dir, readDirEntries(dir)));
4232
+ }
4233
+ } else {
4234
+ const normalizedCwd = path2.resolve(options.cwd ?? process.cwd());
4235
+ requiredCwd = normalizedCwd;
4236
+ const projectDir = path2.join(
4237
+ sessionsDir,
4238
+ sanitizePathToDirectoryName(normalizedCwd)
4239
+ );
4240
+ projectCandidates.push(
4241
+ ...collectCandidates(projectDir, readDirEntries(projectDir))
4242
+ );
4243
+ }
4244
+ const byMtimeDesc = (a, b) => b.stats.mtime.getTime() - a.stats.mtime.getTime();
4245
+ projectCandidates.sort(byMtimeDesc);
4246
+ legacyCandidates.sort(byMtimeDesc);
4247
+ const parseLimit = options.limit !== void 0 && options.limit >= 0 ? options.limit + PARSE_OVERSAMPLE : void 0;
4248
+ const ctx = { favorites };
4249
+ const legacyCtx = requiredCwd !== void 0 ? { favorites, requiredCwd } : ctx;
4250
+ const projectSessions = parseUpTo(projectCandidates, ctx, parseLimit);
4251
+ const legacySessions = parseUpTo(legacyCandidates, legacyCtx, parseLimit);
4252
+ const byId = /* @__PURE__ */ new Map();
4253
+ for (const session of [...projectSessions, ...legacySessions]) {
4254
+ const existing = byId.get(session.id);
4255
+ if (!existing || session.modifiedTime.getTime() > existing.modifiedTime.getTime()) {
4256
+ byId.set(session.id, session);
4257
+ }
4258
+ }
4259
+ const sorted = Array.from(byId.values()).sort(
4260
+ (a, b) => b.modifiedTime.getTime() - a.modifiedTime.getTime()
4261
+ );
4262
+ if (options.limit !== void 0 && options.limit >= 0) {
4263
+ return sorted.slice(0, options.limit);
4264
+ }
4265
+ return sorted;
4266
+ }
4267
+
4268
+ // src/model-discovery.ts
4269
+ async function listModels(options = {}) {
4270
+ const { includeDisabled, ...transportOptions } = options;
4271
+ const { client } = await createConfiguredClient(transportOptions);
4272
+ try {
4273
+ const response = await client.listModels({
4274
+ ...includeDisabled !== void 0 && { includeDisabled }
4275
+ });
4276
+ return unwrapResponseResult(response).models;
4277
+ } finally {
4278
+ await closeQuietly(client);
4279
+ }
4280
+ }
4281
+ export {
4282
+ AbortError,
4283
+ AddMcpServerRequestParamsSchema,
4284
+ AddMcpServerRequestSchema,
4285
+ AddMcpServerResponseSchema,
4286
+ AddMcpServerResultSchema,
4287
+ AddUserMessageRequestParamsSchema,
4288
+ AddUserMessageRequestSchema,
4289
+ AddUserMessageResponseSchema,
4290
+ AddUserMessageResultSchema,
4291
+ ApplyPatchToolConfirmationDetailsSchema,
4292
+ AskUserCollectedAnswerSchema,
4293
+ AskUserConfirmationDetailsSchema,
4294
+ AskUserQuestionSchema,
4295
+ AskUserRequestParamsSchema,
4296
+ AskUserRequestSchema,
4297
+ AskUserResponseSchema,
4298
+ AskUserResultSchema,
4299
+ AssistantTextCompleteNotificationSchema,
4300
+ AssistantTextDeltaNotificationSchema,
4301
+ AuthenticateMcpServerRequestParamsSchema,
4302
+ AuthenticateMcpServerRequestSchema,
4303
+ AuthenticateMcpServerResponseSchema,
4304
+ AuthenticateMcpServerResultSchema,
4305
+ AutonomyLevel,
4306
+ AvailableModelConfigSchema,
4307
+ Base64ImageSourceSchema,
4308
+ BaseNotificationSchema,
4309
+ BaseRequestSchema,
4310
+ BaseResponseFailureSchema,
4311
+ BaseResponseSuccessSchema,
4312
+ CLI_JSONRPC_CHILD_SPAWN_LATENCY_METRIC,
4313
+ COMPACTION_TIMEOUT,
4314
+ CancelMcpAuthRequestParamsSchema,
4315
+ CancelMcpAuthRequestSchema,
4316
+ CancelMcpAuthResponseSchema,
4317
+ CancelMcpAuthResultSchema,
4318
+ ChangeWorkingDirectoryRequestParamsSchema,
4319
+ ChangeWorkingDirectoryRequestSchema,
4320
+ ChangeWorkingDirectoryResponseSchema,
4321
+ ChangeWorkingDirectoryResultSchema,
4322
+ ClearMcpAuthRequestParamsSchema,
4323
+ ClearMcpAuthRequestSchema,
4324
+ ClearMcpAuthResponseSchema,
4325
+ ClearMcpAuthResultSchema,
4326
+ CliRequestOrNotificationSchema,
4327
+ ClientDestroyedError,
4328
+ ClientRequestSchema,
4329
+ ClientUiSurface,
4330
+ CloseSessionRequestParamsSchema,
4331
+ CloseSessionRequestSchema,
4332
+ CloseSessionResponseSchema,
4333
+ CloseSessionResultSchema,
4334
+ CompactSessionRequestParamsSchema,
4335
+ CompactSessionRequestSchema,
4336
+ CompactSessionResponseSchema,
4337
+ CompactSessionResultSchema,
4338
+ ComputeLimitExceededError,
4339
+ ComputerConnectAttemptTrigger,
4340
+ ComputerConnectStartType,
4341
+ ComputerListResponseSchema,
4342
+ ComputerMetricSchema,
4343
+ ComputerMetricsResponseSchema,
4344
+ ComputerSchema,
4345
+ ConcurrentStreamError,
4346
+ ConnectionClosedError,
4347
+ ConnectionError,
4348
+ ConnectionFailureReason,
4349
+ ContentBlockSchema,
4350
+ ContextBreakdownCategorySchema,
4351
+ GetContextBreakdownResultSchema as ContextBreakdownResultSchema,
4352
+ ContextStatsAccuracy,
4353
+ ContextStatsSchema,
4354
+ CreateMessageNotificationSchema,
4355
+ CreateToolConfirmationDetailsSchema,
4356
+ DEFAULT_LOCAL_DAEMON_WS_URL,
4357
+ DEFAULT_REQUEST_TIMEOUT,
4358
+ DaemonAuthenticationMode,
4359
+ DaemonClient,
4360
+ MetaError as DaemonClientMetaError,
4361
+ DaemonDroidEvent,
4362
+ DaemonRequestPermissionSchema,
4363
+ DaemonSessionController,
4364
+ DecompSessionType,
4365
+ DiscoveredIssueSchema,
4366
+ DismissalRecordSchema,
4367
+ DismissalType,
4368
+ DocumentBlockSchema,
4369
+ DocumentSourceSchema,
4370
+ DroidClient,
4371
+ DroidClientError,
4372
+ DroidClientEvent,
4373
+ DroidClientMethod,
4374
+ DroidErrorType,
4375
+ DroidEvent,
4376
+ DroidHookEventSchema,
4377
+ DroidHookExecutionResultSchema,
4378
+ DroidHookOutputSchema,
4379
+ DroidHookSpecificOutputSchema,
4380
+ DroidInteractionMode,
4381
+ DroidMessageType,
4382
+ DroidProcessManager,
4383
+ DroidProcessMode,
4384
+ DroidServerMethod,
4385
+ DroidSession,
4386
+ DroidWorkingState,
4387
+ DroidWorkingStateChangedNotificationSchema,
4388
+ EditToolConfirmationDetailsSchema,
4389
+ EmptyResultSchema,
4390
+ ErrorDetailSchema,
4391
+ ErrorNotificationSchema,
4392
+ ExecToolInfoSchema,
4393
+ ExecuteRewindRequestParamsSchema,
4394
+ ExecuteRewindRequestSchema,
4395
+ ExecuteRewindResponseSchema,
4396
+ ExecuteRewindResultSchema,
4397
+ ExecuteToolConfirmationDetailsSchema,
4398
+ ExitSpecModeConfirmationDetailsSchema,
4399
+ FACTORY_CLIENT_HEADER,
4400
+ FACTORY_CLIENT_VERSION,
4401
+ FACTORY_PROTOCOL_VERSION2 as FACTORY_PROTOCOL_VERSION,
4402
+ FactoryDaemonTransport,
4403
+ FactoryDroidMessageRole,
4404
+ FactoryDroidMessageSchema,
4405
+ FeatureStatus,
4406
+ FeatureSuccessState,
4407
+ FeatureSuccessStateSchema,
4408
+ ForkSessionRequestParamsSchema,
4409
+ ForkSessionRequestSchema,
4410
+ ForkSessionResponseSchema,
4411
+ ForkSessionResultSchema,
4412
+ GetContextStatsRequestParamsSchema,
4413
+ GetContextStatsRequestSchema,
4414
+ GetContextStatsResponseSchema,
4415
+ ContextStatsSchema as GetContextStatsResultSchema,
4416
+ GetRewindInfoRequestParamsSchema,
4417
+ GetRewindInfoRequestSchema,
4418
+ GetRewindInfoResponseSchema,
4419
+ GetRewindInfoResultSchema,
4420
+ GitRepoInfoSchema,
4421
+ HandoffItemsDismissedEntrySchema,
4422
+ HandoffSchema,
4423
+ HookCommandSchema,
4424
+ HookExecutionCompletedNotificationSchema,
4425
+ HookExecutionStartedNotificationSchema,
4426
+ HookResultSchema,
4427
+ HttpHeaderSchema,
4428
+ HttpMcpSchema as HttpMcpConfigSchema,
4429
+ IPC_DAEMON_URL,
4430
+ ImageBlockSchema,
4431
+ InProcessDaemonClientTransport,
4432
+ InitializeSessionRequestParamsSchema,
4433
+ InitializeSessionRequestSchema,
4434
+ InitializeSessionResponseSchema,
4435
+ InitializeSessionResultSchema2 as InitializeSessionResultSchema,
4436
+ InteractiveCheckSchema,
4437
+ InterruptSessionRequestParamsSchema,
4438
+ InterruptSessionRequestSchema,
4439
+ InterruptSessionResponseSchema,
4440
+ InterruptSessionResultSchema,
4441
+ InvalidSessionCwdError,
4442
+ IpcDaemonClientTransport,
4443
+ IssueSeverity,
4444
+ JSONRPC_VERSION3 as JSONRPC_VERSION,
4445
+ JsonArraySchema,
4446
+ JsonObjectSchema,
4447
+ JsonRpcEnvelopeSchema,
4448
+ JsonRpcErrorCode,
4449
+ JsonRpcErrorSchema,
4450
+ JsonRpcMessageSchema,
4451
+ JsonRpcMessageType,
4452
+ JsonRpcNotificationSchema,
4453
+ JsonRpcRequestError,
4454
+ JsonRpcRequestSchema,
4455
+ JsonRpcResponseFailureSchema,
4456
+ JsonRpcResponseSchema,
4457
+ JsonRpcResponseSuccessSchema,
4458
+ JsonValueSchema,
4459
+ KillWorkerSessionRequestParamsSchema,
4460
+ KillWorkerSessionRequestSchema,
4461
+ KillWorkerSessionResponseSchema,
4462
+ KillWorkerSessionResultSchema,
4463
+ LEGACY_FACTORY_API_VERSION2 as LEGACY_FACTORY_API_VERSION,
4464
+ LOCAL_MACHINE_ID,
4465
+ ListMcpRegistryRequestParamsSchema,
4466
+ ListMcpRegistryRequestSchema,
4467
+ ListMcpRegistryResponseSchema,
4468
+ ListMcpRegistryResultSchema,
4469
+ ListMcpServersRequestParamsSchema,
4470
+ ListMcpServersRequestSchema,
4471
+ ListMcpServersResponseSchema,
4472
+ ListMcpServersResultSchema,
4473
+ ListMcpToolsRequestParamsSchema,
4474
+ ListMcpToolsRequestSchema,
4475
+ ListMcpToolsResponseSchema,
4476
+ ListMcpToolsResultSchema,
4477
+ ListModelsOptionsSchema,
4478
+ ListModelsResultSchema,
4479
+ ListSkillsRequestParamsSchema,
4480
+ ListSkillsRequestSchema,
4481
+ ListSkillsResponseSchema,
4482
+ ListSkillsResultSchema,
4483
+ ListToolsRequestParamsSchema,
4484
+ ListToolsRequestSchema,
4485
+ ListToolsResponseSchema,
4486
+ ListToolsResultSchema,
4487
+ LoadSessionRequestParamsSchema,
4488
+ LoadSessionRequestSchema,
4489
+ LoadSessionResponseSchema,
4490
+ LoadSessionResultSchema,
4491
+ MACHINE_TYPE_WEBSOCKET_OVERRIDES,
4492
+ MANAGED_COMPUTER_MAX_RETRIES,
4493
+ MCP_AUTH_TIMEOUT,
4494
+ MachineTemplateBuildStatusSchema,
4495
+ MachineTemplateListResponseSchema,
4496
+ MachineTemplateSchema,
4497
+ MachineType,
4498
+ ManagedProcessImpl,
4499
+ McpAuthCompletedNotificationSchema,
4500
+ McpAuthOutcome,
4501
+ McpAuthRequiredNotificationSchema,
4502
+ McpHttpServerConfigFieldsSchema,
4503
+ McpRegistryServerSchema,
4504
+ McpServerConfigSchema,
4505
+ McpServerStatus,
4506
+ McpServerStatusInfoSchema,
4507
+ McpServerType,
4508
+ McpSseServerConfigFieldsSchema,
4509
+ McpStatus,
4510
+ McpStatusChangedNotificationSchema,
4511
+ McpStatusSummarySchema,
4512
+ McpStdioServerConfigFieldsSchema,
4513
+ McpToolConfirmationDetailsSchema,
4514
+ McpToolInfoSchema,
4515
+ McpToolInputSchemaSchema,
4516
+ MessageVisibility,
4517
+ Metric,
4518
+ MilestoneValidationTriggeredEntrySchema,
4519
+ MissionAcceptedEntrySchema,
4520
+ MissionFeatureSchema,
4521
+ MissionFeaturesChangedNotificationSchema,
4522
+ MissionHeartbeatNotificationSchema,
4523
+ MissionPausedEntrySchema,
4524
+ MissionProgressEntryNotificationSchema,
4525
+ MissionResumedEntrySchema,
4526
+ MissionRunStartedEntrySchema,
4527
+ MissionStateSchema as MissionSnapshotSchema,
4528
+ MissionState,
4529
+ MissionStateChangedNotificationSchema,
4530
+ MissionWorkerCompletedNotificationSchema,
4531
+ MissionWorkerStartedNotificationSchema,
4532
+ ModelInfoSchema,
4533
+ ModelMetadataSchema,
4534
+ ModelProvider,
4535
+ MultiMissionStateManager,
4536
+ MultiSessionStateManager,
4537
+ OtelTracing,
4538
+ OutputFormatSchema,
4539
+ OutputFormatType,
4540
+ PermissionResolvedNotificationSchema,
4541
+ ProcessExitError,
4542
+ ProcessTransport,
4543
+ ProgressLogEntrySchema,
4544
+ ProgressLogEntryType,
4545
+ ProposeMissionConfirmationDetailsSchema,
4546
+ ProtocolError,
4547
+ QueuedUserMessageDisplayGroup,
4548
+ QueuedUserMessageKind,
4549
+ REWIND_TIMEOUT,
4550
+ ReasoningEffort,
4551
+ RedactedThinkingBlockSchema,
4552
+ RefreshComputerResponseSchema,
4553
+ RelayConnectionError,
4554
+ RemoteSessionListResponseSchema,
4555
+ RemoteSessionSchema,
4556
+ RemoveMcpServerRequestParamsSchema,
4557
+ RemoveMcpServerRequestSchema,
4558
+ RemoveMcpServerResponseSchema,
4559
+ RemoveMcpServerResultSchema,
4560
+ RenameSessionRequestParamsSchema,
4561
+ RenameSessionRequestSchema,
4562
+ RenameSessionResponseSchema,
4563
+ RenameSessionResultSchema,
4564
+ RequestPermissionRequestParamsSchema,
4565
+ RequestPermissionRequestSchema,
4566
+ RequestPermissionResponseSchema,
4567
+ RequestPermissionResultSchema,
4568
+ RewindEvictedFileSchema,
4569
+ RewindFileCreationSchema,
4570
+ RewindFileSnapshotSchema,
4571
+ SDK_TAG,
4572
+ SDK_VERSION,
4573
+ SESSION_INIT_TIMEOUT,
4574
+ SLACK_DELEGATION_MAX_RETRIES,
4575
+ SdkMcpServer,
4576
+ ServerRequestHandlerType,
4577
+ SessionError,
4578
+ SessionMetadataSchema,
4579
+ SessionNotFoundError,
4580
+ SessionNotificationParamsSchema,
4581
+ SessionNotificationPayloadSchema,
4582
+ SessionNotificationSchema,
4583
+ SessionNotificationSchemaList,
4584
+ SessionNotificationType,
4585
+ SessionPlatform,
4586
+ SessionReplacedError,
4587
+ SessionReplacementError,
4588
+ SessionSettingsFileSchema,
4589
+ SessionSettingsSchema,
4590
+ SessionSourceSchema,
4591
+ SessionStartEventSchema,
4592
+ SessionTagSchema,
4593
+ SessionTitleUpdatedNotificationSchema,
4594
+ SessionTokenUsageChangedNotificationSchema,
4595
+ SetSkillDisabledRequestParamsSchema,
4596
+ SetSkillDisabledRequestSchema,
4597
+ SetSkillDisabledResponseSchema,
4598
+ SetSkillDisabledResultSchema,
4599
+ SettingsLevel,
4600
+ SettingsUpdatedNotificationSchema,
4601
+ SettingsUpdatedPayloadSchema,
4602
+ SkillDeviationSchema,
4603
+ SkillFeedbackSchema,
4604
+ SkillInfoSchema,
4605
+ SkillLocation,
4606
+ SkillResourceSchema,
4607
+ SpanAttribute,
4608
+ SpanEvent,
4609
+ SpanName,
4610
+ SseMcpSchema as SseMcpConfigSchema,
4611
+ StartMissionRunConfirmationDetailsSchema,
4612
+ StdioMcpSchema as StdioMcpConfigSchema,
4613
+ StreamStateTracker,
4614
+ StructuredOutputErrorSchema,
4615
+ StructuredOutputNotificationSchema,
4616
+ SubmitBugReportRequestParamsSchema,
4617
+ SubmitBugReportRequestSchema,
4618
+ SubmitBugReportResponseSchema,
4619
+ SubmitBugReportResultSchema,
4620
+ SubmitMcpAuthCodeRequestParamsSchema,
4621
+ SubmitMcpAuthCodeRequestSchema,
4622
+ SubmitMcpAuthCodeResponseSchema,
4623
+ SubmitMcpAuthCodeResultSchema,
4624
+ SuccessResultSchema,
4625
+ TestCaseSchema,
4626
+ TestFileSchema,
4627
+ TestsSchema,
4628
+ TextBlockSchema,
4629
+ ThinkingBlockSchema,
4630
+ ThinkingTextCompleteNotificationSchema,
4631
+ ThinkingTextDeltaNotificationSchema,
4632
+ TimeoutError,
4633
+ ToggleMcpServerRequestParamsSchema,
4634
+ ToggleMcpServerRequestSchema,
4635
+ ToggleMcpServerResponseSchema,
4636
+ ToggleMcpServerResultSchema,
4637
+ ToggleMcpToolRequestParamsSchema,
4638
+ ToggleMcpToolRequestSchema,
4639
+ ToggleMcpToolResponseSchema,
4640
+ ToggleMcpToolResultSchema,
4641
+ TokenUsageSchema,
4642
+ ToolCallNotificationSchema,
4643
+ ToolConfirmationDetailsSchema,
4644
+ ToolConfirmationInfoSchema,
4645
+ ToolConfirmationListItemSchema,
4646
+ ToolConfirmationOutcome,
4647
+ ToolConfirmationType,
4648
+ ToolProgressUpdateNotificationSchema,
4649
+ ToolProgressUpdateSchema,
4650
+ ToolResultSchema as ToolResultBlockSchema,
4651
+ ToolResultNotificationSchema,
4652
+ ToolSelectionOverridesSchema,
4653
+ ToolUseSchema as ToolUseBlockSchema,
4654
+ ToolUseSchema2 as ToolUseSchema,
4655
+ TraceContextMetaSchema,
4656
+ TransportDirection,
4657
+ TunnelConnection,
4658
+ UpdateSessionSettingsRequestParamsSchema,
4659
+ UpdateSessionSettingsRequestSchema,
4660
+ UpdateSessionSettingsResponseSchema,
4661
+ UpdateSessionSettingsResultSchema,
4662
+ VerificationCommandSchema,
4663
+ VerificationSchema,
4664
+ WINDOWS_JOB_OBJECT_ERROR_MARKER,
4665
+ WebSocketConnectionError,
4666
+ WebSocketDaemonTransport,
4667
+ WorkerCompletedEntrySchema,
4668
+ WorkerFailedEntrySchema,
4669
+ WorkerPausedEntrySchema,
4670
+ WorkerSelectedFeatureEntrySchema,
4671
+ WorkerStartedEntrySchema,
4672
+ WorkerStateInfoSchema,
4673
+ __resetTransportLoggerForTests,
4674
+ buildUserMessageContentBlocks,
4675
+ configureDaemonCoreDeps,
4676
+ connectAndAuthenticate,
4677
+ connectToDaemon,
4678
+ connectWithRetry,
4679
+ convertNotificationToStreamMessage,
4680
+ createComputer,
4681
+ createResponseSchema,
4682
+ createSdkMcpServer,
4683
+ createSession,
4684
+ createWebSocketDaemonClient,
4685
+ defaultDaemonCoreDeps,
4686
+ deleteComputer,
4687
+ filterMessagesForUI,
4688
+ getComputer,
4689
+ getComputerByName,
4690
+ getComputerMetrics,
4691
+ getMachineTemplate,
4692
+ getPermissionToolInputForDisplay,
4693
+ getQueuedUserMessageDisplayGroup,
4694
+ getQueuedUserMessageReviewPriority,
4695
+ getSubagentCallingMetadata,
4696
+ getToolResultBlocks,
4697
+ getToolResultToolUseId,
4698
+ hasDecoupledInteractionSettings,
4699
+ hasSubagentSessionTag,
4700
+ inspectJsonRpcEnvelope,
4701
+ isDaemonQueuedMessageKind,
4702
+ isPendingToolResultMarker,
4703
+ isPersistedHookMessage,
4704
+ isReviewableQueuedMessageKind,
4705
+ isTransportLoggingEnabled,
4706
+ listComputers,
4707
+ listMachineTemplates,
4708
+ listModels,
4709
+ listRemoteSessions,
4710
+ listSessions,
4711
+ logTransportMessage,
4712
+ machineTypeToMachineConnectionType,
4713
+ noopLogger,
4714
+ orderMessagesByParentChain,
4715
+ recordComputerConnectSli,
4716
+ refreshComputer,
4717
+ repairParentChainCorruption,
4718
+ resolveExecCoreDeps,
4719
+ restartComputer,
4720
+ resumeSession,
4721
+ retryInstallDeps,
4722
+ retryWithLogger,
4723
+ run,
4724
+ spawnWithWindowsJobObjectRetry,
4725
+ sumTokenUsage,
4726
+ summarizeSessionToolUsage,
4727
+ toError,
4728
+ tool,
4729
+ updateComputer
4730
+ };
4731
+ //# sourceMappingURL=node.mjs.map