@factory/droid-sdk 0.9.1 → 0.11.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.
- package/README.md +53 -0
- package/dist/api.d.mts +15058 -0
- package/dist/api.d.ts +15058 -0
- package/dist/api.js +253 -0
- package/dist/api.js.map +1 -0
- package/dist/api.mjs +253 -0
- package/dist/api.mjs.map +1 -0
- package/dist/chunk-7ZD7MMNA.mjs +2268 -0
- package/dist/chunk-7ZD7MMNA.mjs.map +1 -0
- package/dist/{chunk-YSKO6SPT.js → chunk-KAAWCHO4.js} +32033 -17088
- package/dist/chunk-KAAWCHO4.js.map +1 -0
- package/dist/chunk-NWFX4MPJ.mjs +41630 -0
- package/dist/chunk-NWFX4MPJ.mjs.map +1 -0
- package/dist/chunk-ZQ7TS73S.js +2268 -0
- package/dist/chunk-ZQ7TS73S.js.map +1 -0
- package/dist/{index-C06W9tbN.d.mts → index-Cf2WtJqJ.d.mts} +134169 -84330
- package/dist/{index-C06W9tbN.d.ts → index-Cf2WtJqJ.d.ts} +134169 -84330
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +91 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +99 -10
- package/dist/node.d.mts +223 -43
- package/dist/node.d.ts +223 -43
- package/dist/node.js +2033 -776
- package/dist/node.js.map +1 -1
- package/dist/node.mjs +1756 -499
- package/dist/node.mjs.map +1 -1
- package/examples/browser/daemon-lifecycle.ts +4 -6
- package/examples/node/custom-model-editing-disposable.sh +88 -0
- package/examples/node/custom-model-editing-disposable.ts +171 -0
- package/examples/node/custom-model-editing.ts +55 -0
- package/examples/node/hook-execution.ts +3 -2
- package/examples/node/rest-api.ts +55 -0
- package/examples/node/sdk-mcp-tool.ts +5 -3
- package/examples/node/start-workstream.ts +76 -0
- package/examples/node/tool-controls.ts +7 -5
- package/package.json +14 -3
- package/dist/chunk-TWSTJMV7.mjs +0 -26685
- package/dist/chunk-TWSTJMV7.mjs.map +0 -1
- package/dist/chunk-YSKO6SPT.js.map +0 -1
package/dist/node.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
AddUserMessageRequestSchema,
|
|
9
9
|
AddUserMessageResponseSchema,
|
|
10
10
|
AddUserMessageResultSchema,
|
|
11
|
+
AnswerSessionElicitationResponseSchema,
|
|
11
12
|
AppendMessagesResponseSchema,
|
|
12
13
|
ApplyPatchToolConfirmationDetailsSchema,
|
|
13
14
|
AskUserCollectedAnswerSchema,
|
|
@@ -62,19 +63,23 @@ import {
|
|
|
62
63
|
ComputerListResponseSchema,
|
|
63
64
|
ComputerMetricSchema,
|
|
64
65
|
ComputerMetricsResponseSchema,
|
|
66
|
+
ComputerReadSchema,
|
|
65
67
|
ComputerSchema,
|
|
66
68
|
ConcurrentStreamError,
|
|
67
69
|
ConnectionClosedError,
|
|
68
70
|
ConnectionError,
|
|
69
71
|
ConnectionFailureReason,
|
|
70
72
|
ContentBlockSchema,
|
|
73
|
+
ContextApiError,
|
|
71
74
|
ContextBreakdownCategorySchema,
|
|
72
75
|
ContextStatsAccuracy,
|
|
73
76
|
ContextStatsSchema,
|
|
74
77
|
CreateMessageNotificationSchema,
|
|
75
78
|
CreateToolConfirmationDetailsSchema,
|
|
79
|
+
DEFAULT_CONNECTION_CONFIG,
|
|
76
80
|
DEFAULT_LOCAL_DAEMON_WS_URL,
|
|
77
81
|
DEFAULT_REQUEST_TIMEOUT,
|
|
82
|
+
DROID_RUNNING_STATES,
|
|
78
83
|
DaemonAuthenticationMode,
|
|
79
84
|
DaemonClient,
|
|
80
85
|
DaemonDroidEvent,
|
|
@@ -88,6 +93,7 @@ import {
|
|
|
88
93
|
DocumentSourceSchema,
|
|
89
94
|
DroidClientError,
|
|
90
95
|
DroidClientMethod,
|
|
96
|
+
DroidConnectionEndedError,
|
|
91
97
|
DroidErrorType,
|
|
92
98
|
DroidEvent,
|
|
93
99
|
DroidHookEventSchema,
|
|
@@ -101,9 +107,13 @@ import {
|
|
|
101
107
|
DroidWorkingStateChangedNotificationSchema,
|
|
102
108
|
EditToolConfirmationDetailsSchema,
|
|
103
109
|
EmptyResultSchema,
|
|
110
|
+
EnvironmentComputerTimeoutError,
|
|
111
|
+
EnvironmentListResponseSchema,
|
|
112
|
+
EnvironmentSchema,
|
|
104
113
|
ErrorDetailSchema,
|
|
105
114
|
ErrorNotificationSchema,
|
|
106
115
|
ExecToolInfoSchema,
|
|
116
|
+
ExecToolInfoWithSchemasSchema,
|
|
107
117
|
ExecuteRewindRequestParamsSchema,
|
|
108
118
|
ExecuteRewindRequestSchema,
|
|
109
119
|
ExecuteRewindResponseSchema,
|
|
@@ -113,7 +123,6 @@ import {
|
|
|
113
123
|
FACTORY_CLIENT_HEADER,
|
|
114
124
|
FACTORY_CLIENT_VERSION,
|
|
115
125
|
FACTORY_PROTOCOL_VERSION,
|
|
116
|
-
FACTORY_PROTOCOL_VERSION2,
|
|
117
126
|
FactoryDaemonTransport,
|
|
118
127
|
FactoryDroidMessageRole,
|
|
119
128
|
FactoryDroidMessageSchema,
|
|
@@ -129,6 +138,7 @@ import {
|
|
|
129
138
|
GetContextStatsRequestParamsSchema,
|
|
130
139
|
GetContextStatsRequestSchema,
|
|
131
140
|
GetContextStatsResponseSchema,
|
|
141
|
+
GetHandoffSummaryResponseSchema,
|
|
132
142
|
GetRewindInfoRequestParamsSchema,
|
|
133
143
|
GetRewindInfoRequestSchema,
|
|
134
144
|
GetRewindInfoResponseSchema,
|
|
@@ -160,7 +170,6 @@ import {
|
|
|
160
170
|
IssueSeverity,
|
|
161
171
|
JSONRPC_VERSION,
|
|
162
172
|
JSONRPC_VERSION2,
|
|
163
|
-
JSONRPC_VERSION3,
|
|
164
173
|
JsonArraySchema,
|
|
165
174
|
JsonObjectSchema,
|
|
166
175
|
JsonRpcBaseResponseSchema,
|
|
@@ -176,6 +185,7 @@ import {
|
|
|
176
185
|
JsonRpcResponseSchema,
|
|
177
186
|
JsonRpcResponseSuccessSchema,
|
|
178
187
|
JsonValueSchema,
|
|
188
|
+
KillBackgroundProcessResponseSchema,
|
|
179
189
|
KillWorkerSessionRequestParamsSchema,
|
|
180
190
|
KillWorkerSessionRequestSchema,
|
|
181
191
|
KillWorkerSessionResponseSchema,
|
|
@@ -183,6 +193,7 @@ import {
|
|
|
183
193
|
LEGACY_FACTORY_API_VERSION,
|
|
184
194
|
LEGACY_FACTORY_API_VERSION2,
|
|
185
195
|
LOCAL_MACHINE_ID,
|
|
196
|
+
LfLineDecoder,
|
|
186
197
|
ListCommandsResponseSchema,
|
|
187
198
|
ListMcpRegistryRequestParamsSchema,
|
|
188
199
|
ListMcpRegistryRequestSchema,
|
|
@@ -199,6 +210,7 @@ import {
|
|
|
199
210
|
ListModelsOptionsSchema,
|
|
200
211
|
ListModelsResponseSchema,
|
|
201
212
|
ListModelsResultSchema,
|
|
213
|
+
ListSessionElicitationsResponseSchema,
|
|
202
214
|
ListSkillsRequestParamsSchema,
|
|
203
215
|
ListSkillsRequestSchema,
|
|
204
216
|
ListSkillsResponseSchema,
|
|
@@ -206,11 +218,14 @@ import {
|
|
|
206
218
|
ListToolsRequestParamsSchema,
|
|
207
219
|
ListToolsRequestSchema,
|
|
208
220
|
ListToolsResponseSchema,
|
|
221
|
+
ListToolsResponseWithSchemasSchema,
|
|
209
222
|
ListToolsResultSchema,
|
|
223
|
+
ListToolsResultWithSchemasSchema,
|
|
210
224
|
LoadSessionRequestParamsSchema,
|
|
211
225
|
LoadSessionRequestSchema,
|
|
212
226
|
LoadSessionResponseSchema,
|
|
213
227
|
LoadSessionResultSchema,
|
|
228
|
+
MACHINE_TYPE_CONFIG,
|
|
214
229
|
MACHINE_TYPE_WEBSOCKET_OVERRIDES,
|
|
215
230
|
MANAGED_COMPUTER_MAX_RETRIES,
|
|
216
231
|
MCP_AUTH_TIMEOUT,
|
|
@@ -243,6 +258,7 @@ import {
|
|
|
243
258
|
MissionFeatureSchema,
|
|
244
259
|
MissionFeaturesChangedNotificationSchema,
|
|
245
260
|
MissionHeartbeatNotificationSchema,
|
|
261
|
+
MissionMachineTargetKind,
|
|
246
262
|
MissionPausedEntrySchema,
|
|
247
263
|
MissionProgressEntryNotificationSchema,
|
|
248
264
|
MissionResumedEntrySchema,
|
|
@@ -261,6 +277,12 @@ import {
|
|
|
261
277
|
OutputFormatSchema,
|
|
262
278
|
OutputFormatType,
|
|
263
279
|
PermissionResolvedNotificationSchema,
|
|
280
|
+
PickOptionsRequestParamsSchema,
|
|
281
|
+
PickOptionsRequestSchema,
|
|
282
|
+
PickOptionsResponseSchema,
|
|
283
|
+
PickOptionsResultSchema,
|
|
284
|
+
PickOptionsRowSchema,
|
|
285
|
+
PickOptionsUnavailableError,
|
|
264
286
|
ProcessExitError,
|
|
265
287
|
ProgressLogEntrySchema,
|
|
266
288
|
ProgressLogEntryType,
|
|
@@ -272,6 +294,7 @@ import {
|
|
|
272
294
|
ReasoningEffort,
|
|
273
295
|
RedactedThinkingBlockSchema,
|
|
274
296
|
RefreshComputerResponseSchema,
|
|
297
|
+
RefreshConnectorToolCatalogResponseSchema,
|
|
275
298
|
RelayConnectionError,
|
|
276
299
|
RemoteSessionListResponseSchema,
|
|
277
300
|
RemoteSessionSchema,
|
|
@@ -283,6 +306,7 @@ import {
|
|
|
283
306
|
RenameSessionRequestSchema,
|
|
284
307
|
RenameSessionResponseSchema,
|
|
285
308
|
RenameSessionResultSchema,
|
|
309
|
+
RequestCancelledError,
|
|
286
310
|
RequestPermissionRequestParamsSchema,
|
|
287
311
|
RequestPermissionRequestSchema,
|
|
288
312
|
RequestPermissionResponseSchema,
|
|
@@ -291,13 +315,22 @@ import {
|
|
|
291
315
|
RewindEvictedFileSchema,
|
|
292
316
|
RewindFileCreationSchema,
|
|
293
317
|
RewindFileSnapshotSchema,
|
|
318
|
+
SDK_CLIENT_METADATA,
|
|
294
319
|
SDK_IDENTITY,
|
|
295
320
|
SDK_REQUEST_ATTRIBUTION,
|
|
296
321
|
SDK_TAG,
|
|
297
322
|
SDK_VERSION,
|
|
298
323
|
SESSION_INIT_TIMEOUT,
|
|
299
324
|
SLACK_DELEGATION_MAX_RETRIES,
|
|
325
|
+
SandboxEnvironmentSchema,
|
|
300
326
|
ServerRequestHandlerType,
|
|
327
|
+
SessionArtifactAction,
|
|
328
|
+
SessionArtifactKind,
|
|
329
|
+
SessionArtifactProvider,
|
|
330
|
+
SessionArtifactSchema,
|
|
331
|
+
SessionArtifactSource,
|
|
332
|
+
SessionArtifactsSchema,
|
|
333
|
+
SessionElicitationSchema,
|
|
301
334
|
SessionError,
|
|
302
335
|
SessionMetadataSchema,
|
|
303
336
|
SessionNotFoundError,
|
|
@@ -348,6 +381,7 @@ import {
|
|
|
348
381
|
SubmitMcpAuthCodeResultSchema,
|
|
349
382
|
SubmitMcpAuthErrorResponseSchema,
|
|
350
383
|
SuccessResultSchema,
|
|
384
|
+
SummarizeForMembersResponseSchema,
|
|
351
385
|
TestCaseSchema,
|
|
352
386
|
TestFileSchema,
|
|
353
387
|
TestsSchema,
|
|
@@ -371,11 +405,15 @@ import {
|
|
|
371
405
|
ToolConfirmationListItemSchema,
|
|
372
406
|
ToolConfirmationOutcome,
|
|
373
407
|
ToolConfirmationType,
|
|
408
|
+
ToolJsonSchemaSchema,
|
|
374
409
|
ToolProgressUpdateNotificationSchema,
|
|
375
410
|
ToolProgressUpdateSchema,
|
|
376
411
|
ToolResultNotificationSchema,
|
|
377
412
|
ToolResultSchema,
|
|
413
|
+
ToolResultSchemaDescriptorSchema,
|
|
414
|
+
ToolSchemasSchema,
|
|
378
415
|
ToolSelectionOverridesSchema,
|
|
416
|
+
ToolSourceSchema,
|
|
379
417
|
ToolUseSchema,
|
|
380
418
|
ToolUseSchema2,
|
|
381
419
|
TraceContextMetaSchema,
|
|
@@ -395,57 +433,98 @@ import {
|
|
|
395
433
|
WorkerSelectedFeatureEntrySchema,
|
|
396
434
|
WorkerStartedEntrySchema,
|
|
397
435
|
WorkerStateInfoSchema,
|
|
436
|
+
answerRemoteSessionElicitation,
|
|
437
|
+
appendContextSession,
|
|
398
438
|
buildUserMessageContentBlocks,
|
|
399
439
|
configureDaemonCoreDeps,
|
|
400
440
|
connectAndAuthenticate,
|
|
401
441
|
connectToDaemon,
|
|
402
442
|
connectWithRetry,
|
|
403
443
|
convertNotificationToStreamMessage,
|
|
444
|
+
createApiRequest,
|
|
404
445
|
createComputer,
|
|
446
|
+
createContextDocument,
|
|
447
|
+
createContextFile,
|
|
448
|
+
createContextSpace,
|
|
449
|
+
createFactoryApi,
|
|
450
|
+
createOrRecoverComputer,
|
|
405
451
|
createResponseSchema,
|
|
406
452
|
createWebSocketDaemonClient,
|
|
407
453
|
defaultDaemonCoreDeps,
|
|
408
454
|
deleteComputer,
|
|
455
|
+
deleteContextDocument,
|
|
456
|
+
deleteContextFile,
|
|
457
|
+
emitDroidLog,
|
|
458
|
+
encodeLegacyStartupLoadOptions,
|
|
459
|
+
escapeJsonLineSeparators,
|
|
409
460
|
extractInnerNotification,
|
|
410
461
|
filterMessagesForUI,
|
|
411
462
|
getComputer,
|
|
412
463
|
getComputerByName,
|
|
413
464
|
getComputerMetrics,
|
|
465
|
+
getContextDocument,
|
|
466
|
+
getContextDocumentByPath,
|
|
467
|
+
getContextSession,
|
|
468
|
+
getContextSpace,
|
|
414
469
|
getMachineTemplate,
|
|
415
470
|
getPermissionToolInputForDisplay,
|
|
416
471
|
getQueuedUserMessageDisplayGroup,
|
|
417
472
|
getQueuedUserMessageReviewPriority,
|
|
473
|
+
getSandboxEnvironmentLaunchRepositories,
|
|
474
|
+
getSandboxEnvironmentLaunchSource,
|
|
418
475
|
getSubagentCallingMetadata,
|
|
419
476
|
getToolResultBlocks,
|
|
420
477
|
getToolResultToolUseId,
|
|
421
478
|
hasDecoupledInteractionSettings,
|
|
422
479
|
hasSubagentSessionTag,
|
|
480
|
+
injectDroidTraceContext,
|
|
423
481
|
inspectJsonRpcEnvelope,
|
|
424
482
|
isDaemonQueuedMessageKind,
|
|
483
|
+
isEnvironmentComputerReady,
|
|
484
|
+
isOfferedPermissionOutcome,
|
|
425
485
|
isPendingToolResultMarker,
|
|
426
486
|
isPersistedHookMessage,
|
|
487
|
+
isProtocolVersionAtLeast,
|
|
427
488
|
isReviewableQueuedMessageKind,
|
|
489
|
+
isSandboxEnvironmentLaunchable,
|
|
428
490
|
listComputers,
|
|
491
|
+
listContextDocuments,
|
|
492
|
+
listContextSessions,
|
|
493
|
+
listContextSpaces,
|
|
494
|
+
listEnvironments,
|
|
429
495
|
listMachineTemplates,
|
|
496
|
+
listRemoteSessionElicitations,
|
|
430
497
|
listRemoteSessions,
|
|
431
498
|
machineTypeToMachineConnectionType,
|
|
432
499
|
mergeSessionSettings,
|
|
433
|
-
|
|
500
|
+
parseResponse,
|
|
501
|
+
readContextFilePart,
|
|
502
|
+
readContextSessionRecords,
|
|
434
503
|
recordComputerConnectSli,
|
|
504
|
+
recordDroidMetric,
|
|
435
505
|
refreshComputer,
|
|
436
|
-
|
|
506
|
+
registerContextSession,
|
|
507
|
+
resolveAskUserHandler,
|
|
508
|
+
resolvePermissionHandler,
|
|
437
509
|
restartComputer,
|
|
438
510
|
retryInstallDeps,
|
|
439
511
|
retryWithLogger,
|
|
512
|
+
runWithAbort,
|
|
513
|
+
sessionTagsUpdateForPeer,
|
|
440
514
|
streamFromClient,
|
|
441
515
|
sumTokenUsage,
|
|
442
516
|
summarizeSessionToolUsage,
|
|
443
517
|
toError,
|
|
518
|
+
trustedIdentityFromComputerResponse,
|
|
444
519
|
unwrapResponseResult,
|
|
445
520
|
updateComputer,
|
|
521
|
+
updateContextDocument,
|
|
522
|
+
uploadContextFilePart,
|
|
523
|
+
waitForEnvironmentComputer,
|
|
446
524
|
wireAbortSignal,
|
|
447
525
|
withSdkTag
|
|
448
|
-
} from "./chunk-
|
|
526
|
+
} from "./chunk-NWFX4MPJ.mjs";
|
|
527
|
+
import "./chunk-7ZD7MMNA.mjs";
|
|
449
528
|
|
|
450
529
|
// src/exec-core/client.ts
|
|
451
530
|
import EventEmitter from "events";
|
|
@@ -454,7 +533,7 @@ import { z } from "zod";
|
|
|
454
533
|
|
|
455
534
|
// src/exec-core/constants.ts
|
|
456
535
|
var DEFAULT_REQUEST_TIMEOUT2 = 3e4;
|
|
457
|
-
var SESSION_INIT_TIMEOUT2 =
|
|
536
|
+
var SESSION_INIT_TIMEOUT2 = 12e4;
|
|
458
537
|
var COMPACTION_TIMEOUT2 = 24e4;
|
|
459
538
|
var MCP_AUTH_TIMEOUT2 = 3e5;
|
|
460
539
|
var WINDOWS_JOB_OBJECT_ERROR_MARKER = "AssignProcessToJobObject";
|
|
@@ -517,6 +596,9 @@ var defaultExecCoreDeps = {
|
|
|
517
596
|
},
|
|
518
597
|
sanitizeSpawnEnv(env) {
|
|
519
598
|
return env;
|
|
599
|
+
},
|
|
600
|
+
buildRuntimeSettingsAuthorityEnv() {
|
|
601
|
+
return {};
|
|
520
602
|
}
|
|
521
603
|
}
|
|
522
604
|
};
|
|
@@ -526,6 +608,7 @@ var DroidClientEvent = /* @__PURE__ */ ((DroidClientEvent2) => {
|
|
|
526
608
|
DroidClientEvent2["SESSION_NOTIFICATION"] = "session_notification";
|
|
527
609
|
DroidClientEvent2["REQUEST_PERMISSION"] = "request_permission";
|
|
528
610
|
DroidClientEvent2["ASK_USER"] = "ask_user";
|
|
611
|
+
DroidClientEvent2["PICK_OPTIONS"] = "pick_options";
|
|
529
612
|
DroidClientEvent2["ERROR"] = "error";
|
|
530
613
|
return DroidClientEvent2;
|
|
531
614
|
})(DroidClientEvent || {});
|
|
@@ -541,90 +624,6 @@ var TransportDirection = /* @__PURE__ */ ((TransportDirection2) => {
|
|
|
541
624
|
return TransportDirection2;
|
|
542
625
|
})(TransportDirection || {});
|
|
543
626
|
|
|
544
|
-
// ../droid-sdk-core/src/observability.ts
|
|
545
|
-
function sanitizeAttributes(attributes) {
|
|
546
|
-
if (attributes === void 0) {
|
|
547
|
-
return void 0;
|
|
548
|
-
}
|
|
549
|
-
const sanitized = {};
|
|
550
|
-
for (const [key, value] of Object.entries(attributes)) {
|
|
551
|
-
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
552
|
-
sanitized[key] = value;
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
return Object.keys(sanitized).length > 0 ? sanitized : void 0;
|
|
556
|
-
}
|
|
557
|
-
function serializeError(error) {
|
|
558
|
-
if (error instanceof Error) {
|
|
559
|
-
const code = "code" in error && typeof error.code === "string" ? error.code : void 0;
|
|
560
|
-
return {
|
|
561
|
-
name: error.name || void 0,
|
|
562
|
-
message: error.message,
|
|
563
|
-
...code !== void 0 && { code }
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
return { message: String(error) };
|
|
567
|
-
}
|
|
568
|
-
function handleSinkFailure(error, options) {
|
|
569
|
-
try {
|
|
570
|
-
options?.onError?.(error);
|
|
571
|
-
} catch {
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
function emitDroidLog(observability, event, options) {
|
|
575
|
-
const sink = observability?.logger;
|
|
576
|
-
if (!sink) {
|
|
577
|
-
return false;
|
|
578
|
-
}
|
|
579
|
-
try {
|
|
580
|
-
sink.log({
|
|
581
|
-
level: event.level,
|
|
582
|
-
name: event.name,
|
|
583
|
-
message: event.message,
|
|
584
|
-
attributes: sanitizeAttributes(event.attributes),
|
|
585
|
-
...event.error !== void 0 && {
|
|
586
|
-
error: serializeError(event.error)
|
|
587
|
-
}
|
|
588
|
-
});
|
|
589
|
-
return true;
|
|
590
|
-
} catch (error) {
|
|
591
|
-
handleSinkFailure(error, options);
|
|
592
|
-
return false;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
function recordDroidMetric(observability, event, options) {
|
|
596
|
-
const sink = observability?.metrics;
|
|
597
|
-
if (!sink) {
|
|
598
|
-
return false;
|
|
599
|
-
}
|
|
600
|
-
try {
|
|
601
|
-
sink.record({
|
|
602
|
-
name: event.name,
|
|
603
|
-
kind: event.kind,
|
|
604
|
-
value: event.value,
|
|
605
|
-
unit: event.unit,
|
|
606
|
-
attributes: sanitizeAttributes(event.attributes)
|
|
607
|
-
});
|
|
608
|
-
return true;
|
|
609
|
-
} catch (error) {
|
|
610
|
-
handleSinkFailure(error, options);
|
|
611
|
-
return false;
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
function injectDroidTraceContext(observability, carrier, options) {
|
|
615
|
-
const sink = observability?.tracing;
|
|
616
|
-
if (!sink) {
|
|
617
|
-
return false;
|
|
618
|
-
}
|
|
619
|
-
try {
|
|
620
|
-
sink.inject(carrier);
|
|
621
|
-
return true;
|
|
622
|
-
} catch (error) {
|
|
623
|
-
handleSinkFailure(error, options);
|
|
624
|
-
return false;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
|
|
628
627
|
// src/exec-core/deps.ts
|
|
629
628
|
function logWarn(logger, message, metadata) {
|
|
630
629
|
logger.warn(message, metadata);
|
|
@@ -779,15 +778,21 @@ function resolveExecCoreDeps(observability, fallback = defaultExecCoreDeps) {
|
|
|
779
778
|
}
|
|
780
779
|
|
|
781
780
|
// src/exec-core/client.ts
|
|
782
|
-
function
|
|
783
|
-
const
|
|
784
|
-
return
|
|
781
|
+
function isDroidConnectionEnded(error) {
|
|
782
|
+
const failure = error instanceof ProtocolError ? error.cause : error;
|
|
783
|
+
return failure instanceof DroidConnectionEndedError || failure instanceof ProcessExitError;
|
|
785
784
|
}
|
|
786
785
|
var JsonRpcEnvelopePeekSchema = JsonRpcEnvelopeSchema.partial().extend({
|
|
787
786
|
type: z.nativeEnum(JsonRpcMessageType).optional(),
|
|
788
787
|
method: z.string().optional(),
|
|
789
788
|
id: z.string().nullable().optional()
|
|
790
789
|
}).passthrough();
|
|
790
|
+
function getResponseId(response2) {
|
|
791
|
+
const parsed = JsonRpcEnvelopePeekSchema.safeParse(response2);
|
|
792
|
+
return parsed.success ? parsed.data.id : void 0;
|
|
793
|
+
}
|
|
794
|
+
var MCP_OAUTH_OPT_OUT_PROTOCOL_VERSION = "1.78.0";
|
|
795
|
+
var PERMISSION_WITHDRAWN = /* @__PURE__ */ Symbol("permission withdrawn");
|
|
791
796
|
function inspectJsonRpcEnvelope2(message) {
|
|
792
797
|
const result = JsonRpcEnvelopePeekSchema.safeParse(message);
|
|
793
798
|
if (!result.success) {
|
|
@@ -811,10 +816,21 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
811
816
|
pendingRequests = /* @__PURE__ */ new Map();
|
|
812
817
|
permissionHandlers = /* @__PURE__ */ new Map();
|
|
813
818
|
askUserHandlers = /* @__PURE__ */ new Map();
|
|
819
|
+
pickOptionsHandlers = /* @__PURE__ */ new Map();
|
|
814
820
|
pendingPermissionRequests = /* @__PURE__ */ new Map();
|
|
815
821
|
pendingAskUserRequests = /* @__PURE__ */ new Map();
|
|
822
|
+
/**
|
|
823
|
+
* Queued (non-blocking) AskUser requests that arrived before an AskUser
|
|
824
|
+
* handler was set, as when a reloaded session asks its pending queued sets
|
|
825
|
+
* again during the load. Answering one without a handler would record it
|
|
826
|
+
* as dismissed, and the agent never waits on it, so it waits for the
|
|
827
|
+
* handler instead.
|
|
828
|
+
*/
|
|
829
|
+
heldQueuedAskUserRequests = [];
|
|
830
|
+
pendingPickOptionsRequests = /* @__PURE__ */ new Map();
|
|
816
831
|
currentSessionId = null;
|
|
817
832
|
peerProtocolVersion;
|
|
833
|
+
peerEnforcesQueueOwnership = false;
|
|
818
834
|
/**
|
|
819
835
|
* Sticky error from a transport failure. Once set, all subsequent
|
|
820
836
|
* `sendRequest()` calls throw this error immediately, preventing
|
|
@@ -822,14 +838,20 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
822
838
|
*/
|
|
823
839
|
transportError = null;
|
|
824
840
|
completedTurnObserved = false;
|
|
841
|
+
/**
|
|
842
|
+
* Set once the droid sends `droid.disconnect`. It reads no further
|
|
843
|
+
* requests from then on, so it no longer counts as connected even while its
|
|
844
|
+
* transport stays open.
|
|
845
|
+
*/
|
|
846
|
+
disconnected = false;
|
|
825
847
|
logger;
|
|
826
848
|
tracing;
|
|
827
849
|
onRequestSettled;
|
|
828
850
|
getRequestAttribution;
|
|
829
851
|
constructor(options, deps = defaultExecCoreDeps) {
|
|
830
852
|
super();
|
|
831
|
-
this.transport = options.transport;
|
|
832
853
|
const resolved = resolveExecCoreDeps(options.observability, deps);
|
|
854
|
+
this.transport = options.transport;
|
|
833
855
|
this.logger = resolved.logger;
|
|
834
856
|
this.tracing = resolved.tracing;
|
|
835
857
|
this.requestTimeout = options.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT2;
|
|
@@ -849,13 +871,18 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
849
871
|
});
|
|
850
872
|
this.transport.onError((error) => {
|
|
851
873
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
852
|
-
const
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
874
|
+
const sessionId = this.addressedSessionId;
|
|
875
|
+
const expectedExit = err instanceof ProcessExitError && (err.isRequestedStop || err.exitCode === 0 && this.completedTurnObserved);
|
|
876
|
+
if (expectedExit) {
|
|
877
|
+
this.logger.info("[DroidClient] Process exited as expected", {
|
|
878
|
+
sessionId,
|
|
879
|
+
exitCode: err.exitCode,
|
|
880
|
+
signal: err.signal
|
|
856
881
|
});
|
|
857
882
|
} else {
|
|
858
|
-
this.logger.exception(err, "Transport error"
|
|
883
|
+
this.logger.exception(err, "Transport error", {
|
|
884
|
+
sessionId
|
|
885
|
+
});
|
|
859
886
|
}
|
|
860
887
|
this.transportError = err;
|
|
861
888
|
this.rejectAllPending(err);
|
|
@@ -873,18 +900,62 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
873
900
|
get sessionId() {
|
|
874
901
|
return this.currentSessionId;
|
|
875
902
|
}
|
|
903
|
+
/**
|
|
904
|
+
* The session that an inbound prompt or transport fault belongs to. A
|
|
905
|
+
* session start or load in flight owns it, because the CLI replays a loaded
|
|
906
|
+
* session's pending prompts before it answers the load; otherwise the
|
|
907
|
+
* current session does. Undefined when that is ambiguous: a start with no
|
|
908
|
+
* session id yet, or several starts and loads in flight.
|
|
909
|
+
*
|
|
910
|
+
* @internal
|
|
911
|
+
*/
|
|
912
|
+
get addressedSessionId() {
|
|
913
|
+
const pendingSessionIds = /* @__PURE__ */ new Set();
|
|
914
|
+
for (const pendingRequest of this.pendingRequests.values()) {
|
|
915
|
+
if (pendingRequest.method === "droid.initialize_session" /* INITIALIZE_SESSION */ && pendingRequest.sessionId === void 0) {
|
|
916
|
+
return void 0;
|
|
917
|
+
}
|
|
918
|
+
if (pendingRequest.sessionId !== void 0) {
|
|
919
|
+
pendingSessionIds.add(pendingRequest.sessionId);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
if (pendingSessionIds.size > 1) {
|
|
923
|
+
return void 0;
|
|
924
|
+
}
|
|
925
|
+
const [pendingSessionId] = pendingSessionIds;
|
|
926
|
+
return pendingSessionId ?? this.currentSessionId ?? void 0;
|
|
927
|
+
}
|
|
876
928
|
get isConnected() {
|
|
877
|
-
return this.transport.isConnected;
|
|
929
|
+
return !this.disconnected && this.transport.isConnected;
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* Whether the worker runs in a child process. A daemon's shutdown cuts such
|
|
933
|
+
* a worker off from its owner before closing it, and from then on it reads
|
|
934
|
+
* no request; a worker hosted in this process still answers.
|
|
935
|
+
*/
|
|
936
|
+
get runsInChildProcess() {
|
|
937
|
+
return (this.transport.getManagedProcess?.() ?? null) !== null;
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* Whether the runner refuses a queue change from someone other than the
|
|
941
|
+
* prompt's author. Older runners ignore the author on such a change.
|
|
942
|
+
*/
|
|
943
|
+
get enforcesQueueOwnership() {
|
|
944
|
+
return this.peerEnforcesQueueOwnership;
|
|
878
945
|
}
|
|
879
946
|
requireMcpOAuthOptOutSupport() {
|
|
880
|
-
if (
|
|
947
|
+
if (isProtocolVersionAtLeast(
|
|
948
|
+
this.peerProtocolVersion,
|
|
949
|
+
MCP_OAUTH_OPT_OUT_PROTOCOL_VERSION
|
|
950
|
+
)) {
|
|
881
951
|
return;
|
|
882
952
|
}
|
|
883
953
|
throw new ProtocolError(
|
|
884
|
-
|
|
954
|
+
`MCP OAuth opt-out requires Droid protocol version ${MCP_OAUTH_OPT_OUT_PROTOCOL_VERSION} or newer. The connected Droid reported an older or unknown protocol version and cannot disable OAuth for MCP servers.`,
|
|
885
955
|
{
|
|
886
956
|
value: {
|
|
887
957
|
localFactoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
958
|
+
minimumFactoryProtocolVersion: MCP_OAUTH_OPT_OUT_PROTOCOL_VERSION,
|
|
888
959
|
peerFactoryProtocolVersion: this.peerProtocolVersion
|
|
889
960
|
}
|
|
890
961
|
}
|
|
@@ -897,36 +968,38 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
897
968
|
}
|
|
898
969
|
async initializeSession(params) {
|
|
899
970
|
const request = {
|
|
900
|
-
factoryApiVersion:
|
|
971
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
901
972
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
902
973
|
type: "request",
|
|
903
974
|
jsonrpc: JSONRPC_VERSION2,
|
|
904
975
|
id: uuidv4(),
|
|
905
976
|
method: "droid.initialize_session" /* INITIALIZE_SESSION */,
|
|
906
|
-
params
|
|
977
|
+
params: encodeLegacyStartupLoadOptions(params)
|
|
907
978
|
};
|
|
908
979
|
const rawResponse = await this.sendRequest(
|
|
909
980
|
request,
|
|
910
|
-
this.sessionInitTimeout
|
|
981
|
+
this.sessionInitTimeout,
|
|
982
|
+
params.sessionId
|
|
911
983
|
);
|
|
912
|
-
const
|
|
913
|
-
this.peerProtocolVersion =
|
|
914
|
-
if (
|
|
984
|
+
const response2 = InitializeSessionResponseSchema.parse(rawResponse);
|
|
985
|
+
this.peerProtocolVersion = response2.factoryProtocolVersion;
|
|
986
|
+
if (response2.error) {
|
|
915
987
|
throw new ProtocolError("Initialize session request failed", {
|
|
916
988
|
requestId: request.id,
|
|
917
|
-
code:
|
|
918
|
-
message:
|
|
919
|
-
data:
|
|
989
|
+
code: response2.error.code,
|
|
990
|
+
message: response2.error.message,
|
|
991
|
+
data: response2.error.data
|
|
920
992
|
});
|
|
921
993
|
}
|
|
922
994
|
this.validateMcpServersProtocolSupport(params.mcpServers);
|
|
923
|
-
const result = InitializeSessionResultSchema.parse(
|
|
995
|
+
const result = InitializeSessionResultSchema.parse(response2.result);
|
|
996
|
+
this.peerEnforcesQueueOwnership = result.enforcesQueueOwnership === true;
|
|
924
997
|
this.currentSessionId = result.sessionId;
|
|
925
|
-
return
|
|
998
|
+
return response2;
|
|
926
999
|
}
|
|
927
1000
|
async loadSession(params) {
|
|
928
1001
|
const request = {
|
|
929
|
-
factoryApiVersion:
|
|
1002
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
930
1003
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
931
1004
|
type: "request",
|
|
932
1005
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -936,30 +1009,32 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
936
1009
|
};
|
|
937
1010
|
const rawResponse = await this.sendRequest(
|
|
938
1011
|
request,
|
|
939
|
-
this.sessionInitTimeout
|
|
1012
|
+
this.sessionInitTimeout,
|
|
1013
|
+
params.sessionId
|
|
940
1014
|
);
|
|
941
|
-
const
|
|
942
|
-
this.peerProtocolVersion =
|
|
943
|
-
if (
|
|
944
|
-
const isSessionNotFound =
|
|
1015
|
+
const response2 = LoadSessionResponseSchema.parse(rawResponse);
|
|
1016
|
+
this.peerProtocolVersion = response2.factoryProtocolVersion;
|
|
1017
|
+
if (response2.error) {
|
|
1018
|
+
const isSessionNotFound = response2.error.code === -32004 /* ENTITY_NOT_FOUND */;
|
|
945
1019
|
if (isSessionNotFound) {
|
|
946
1020
|
throw new SessionNotFoundError(params.sessionId, {
|
|
947
1021
|
requestId: request.id,
|
|
948
|
-
code:
|
|
949
|
-
message:
|
|
950
|
-
data:
|
|
1022
|
+
code: response2.error.code,
|
|
1023
|
+
message: response2.error.message,
|
|
1024
|
+
data: response2.error.data
|
|
951
1025
|
});
|
|
952
1026
|
}
|
|
953
1027
|
throw new ProtocolError("Load session request failed", {
|
|
954
1028
|
requestId: request.id,
|
|
955
|
-
code:
|
|
956
|
-
message:
|
|
957
|
-
data:
|
|
1029
|
+
code: response2.error.code,
|
|
1030
|
+
message: response2.error.message,
|
|
1031
|
+
data: response2.error.data
|
|
958
1032
|
});
|
|
959
1033
|
}
|
|
960
1034
|
this.validateMcpServersProtocolSupport(params.mcpServers);
|
|
1035
|
+
this.peerEnforcesQueueOwnership = response2.result?.enforcesQueueOwnership === true;
|
|
961
1036
|
this.currentSessionId = params.sessionId;
|
|
962
|
-
return
|
|
1037
|
+
return response2;
|
|
963
1038
|
}
|
|
964
1039
|
async addUserMessage(params, requestId) {
|
|
965
1040
|
if (!this.currentSessionId) {
|
|
@@ -969,7 +1044,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
969
1044
|
}
|
|
970
1045
|
this.completedTurnObserved = false;
|
|
971
1046
|
const request = {
|
|
972
|
-
factoryApiVersion:
|
|
1047
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
973
1048
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
974
1049
|
type: "request",
|
|
975
1050
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -981,16 +1056,16 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
981
1056
|
}
|
|
982
1057
|
};
|
|
983
1058
|
const rawResponse = await this.sendRequest(request);
|
|
984
|
-
const
|
|
985
|
-
if (
|
|
1059
|
+
const response2 = AddUserMessageResponseSchema.parse(rawResponse);
|
|
1060
|
+
if (response2.error) {
|
|
986
1061
|
throw new ProtocolError("Add user message request failed", {
|
|
987
1062
|
requestId: request.id,
|
|
988
|
-
code:
|
|
989
|
-
message:
|
|
990
|
-
data:
|
|
1063
|
+
code: response2.error.code,
|
|
1064
|
+
message: response2.error.message,
|
|
1065
|
+
data: response2.error.data
|
|
991
1066
|
});
|
|
992
1067
|
}
|
|
993
|
-
return
|
|
1068
|
+
return response2;
|
|
994
1069
|
}
|
|
995
1070
|
/**
|
|
996
1071
|
* Persists user-only messages without starting an agent turn.
|
|
@@ -1005,7 +1080,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1005
1080
|
);
|
|
1006
1081
|
}
|
|
1007
1082
|
const request = {
|
|
1008
|
-
factoryApiVersion:
|
|
1083
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1009
1084
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1010
1085
|
type: "request",
|
|
1011
1086
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1014,16 +1089,16 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1014
1089
|
params
|
|
1015
1090
|
};
|
|
1016
1091
|
const rawResponse = await this.sendRequest(request);
|
|
1017
|
-
const
|
|
1018
|
-
if (
|
|
1092
|
+
const response2 = AppendMessagesResponseSchema.parse(rawResponse);
|
|
1093
|
+
if (response2.error) {
|
|
1019
1094
|
throw new ProtocolError("Append messages request failed", {
|
|
1020
1095
|
requestId: request.id,
|
|
1021
|
-
code:
|
|
1022
|
-
message:
|
|
1023
|
-
data:
|
|
1096
|
+
code: response2.error.code,
|
|
1097
|
+
message: response2.error.message,
|
|
1098
|
+
data: response2.error.data
|
|
1024
1099
|
});
|
|
1025
1100
|
}
|
|
1026
|
-
return
|
|
1101
|
+
return response2;
|
|
1027
1102
|
}
|
|
1028
1103
|
async resolveQueuedUserMessage(params) {
|
|
1029
1104
|
if (!this.currentSessionId) {
|
|
@@ -1032,7 +1107,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1032
1107
|
);
|
|
1033
1108
|
}
|
|
1034
1109
|
const request = {
|
|
1035
|
-
factoryApiVersion:
|
|
1110
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1036
1111
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1037
1112
|
type: "request",
|
|
1038
1113
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1041,16 +1116,16 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1041
1116
|
params
|
|
1042
1117
|
};
|
|
1043
1118
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1044
|
-
const
|
|
1045
|
-
if (
|
|
1119
|
+
const response2 = ResolveQueuedUserMessageResponseSchema.parse(rawResponse);
|
|
1120
|
+
if (response2.error) {
|
|
1046
1121
|
throw new ProtocolError("Resolve queued user message request failed", {
|
|
1047
1122
|
requestId: request.id,
|
|
1048
|
-
code:
|
|
1049
|
-
message:
|
|
1050
|
-
data:
|
|
1123
|
+
code: response2.error.code,
|
|
1124
|
+
message: response2.error.message,
|
|
1125
|
+
data: response2.error.data
|
|
1051
1126
|
});
|
|
1052
1127
|
}
|
|
1053
|
-
return
|
|
1128
|
+
return response2;
|
|
1054
1129
|
}
|
|
1055
1130
|
async interruptSession(params = {}) {
|
|
1056
1131
|
if (!this.currentSessionId) {
|
|
@@ -1059,7 +1134,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1059
1134
|
);
|
|
1060
1135
|
}
|
|
1061
1136
|
const request = {
|
|
1062
|
-
factoryApiVersion:
|
|
1137
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1063
1138
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1064
1139
|
type: "request",
|
|
1065
1140
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1068,16 +1143,16 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1068
1143
|
params
|
|
1069
1144
|
};
|
|
1070
1145
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1071
|
-
const
|
|
1072
|
-
if (
|
|
1146
|
+
const response2 = InterruptSessionResponseSchema.parse(rawResponse);
|
|
1147
|
+
if (response2.error) {
|
|
1073
1148
|
throw new ProtocolError("Interrupt session request failed", {
|
|
1074
1149
|
requestId: request.id,
|
|
1075
|
-
code:
|
|
1076
|
-
message:
|
|
1077
|
-
data:
|
|
1150
|
+
code: response2.error.code,
|
|
1151
|
+
message: response2.error.message,
|
|
1152
|
+
data: response2.error.data
|
|
1078
1153
|
});
|
|
1079
1154
|
}
|
|
1080
|
-
return
|
|
1155
|
+
return response2;
|
|
1081
1156
|
}
|
|
1082
1157
|
async closeSession(params = {}) {
|
|
1083
1158
|
if (!this.currentSessionId) {
|
|
@@ -1086,7 +1161,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1086
1161
|
);
|
|
1087
1162
|
}
|
|
1088
1163
|
const request = {
|
|
1089
|
-
factoryApiVersion:
|
|
1164
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1090
1165
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1091
1166
|
type: "request",
|
|
1092
1167
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1095,16 +1170,16 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1095
1170
|
params
|
|
1096
1171
|
};
|
|
1097
1172
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1098
|
-
const
|
|
1099
|
-
if (
|
|
1173
|
+
const response2 = CloseSessionResponseSchema.parse(rawResponse);
|
|
1174
|
+
if (response2.error) {
|
|
1100
1175
|
throw new ProtocolError("Close session request failed", {
|
|
1101
1176
|
requestId: request.id,
|
|
1102
|
-
code:
|
|
1103
|
-
message:
|
|
1104
|
-
data:
|
|
1177
|
+
code: response2.error.code,
|
|
1178
|
+
message: response2.error.message,
|
|
1179
|
+
data: response2.error.data
|
|
1105
1180
|
});
|
|
1106
1181
|
}
|
|
1107
|
-
return
|
|
1182
|
+
return response2;
|
|
1108
1183
|
}
|
|
1109
1184
|
async killWorkerSession(params) {
|
|
1110
1185
|
if (!this.currentSessionId) {
|
|
@@ -1113,7 +1188,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1113
1188
|
);
|
|
1114
1189
|
}
|
|
1115
1190
|
const request = {
|
|
1116
|
-
factoryApiVersion:
|
|
1191
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1117
1192
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1118
1193
|
type: "request",
|
|
1119
1194
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1122,16 +1197,16 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1122
1197
|
params
|
|
1123
1198
|
};
|
|
1124
1199
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1125
|
-
const
|
|
1126
|
-
if (
|
|
1200
|
+
const response2 = KillWorkerSessionResponseSchema.parse(rawResponse);
|
|
1201
|
+
if (response2.error) {
|
|
1127
1202
|
throw new ProtocolError("Kill worker session request failed", {
|
|
1128
1203
|
requestId: request.id,
|
|
1129
|
-
code:
|
|
1130
|
-
message:
|
|
1131
|
-
data:
|
|
1204
|
+
code: response2.error.code,
|
|
1205
|
+
message: response2.error.message,
|
|
1206
|
+
data: response2.error.data
|
|
1132
1207
|
});
|
|
1133
1208
|
}
|
|
1134
|
-
return
|
|
1209
|
+
return response2;
|
|
1135
1210
|
}
|
|
1136
1211
|
async updateSessionSettings(params, requestId) {
|
|
1137
1212
|
if (!this.currentSessionId) {
|
|
@@ -1140,13 +1215,13 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1140
1215
|
);
|
|
1141
1216
|
}
|
|
1142
1217
|
const request = {
|
|
1143
|
-
factoryApiVersion:
|
|
1218
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1144
1219
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1145
1220
|
type: "request",
|
|
1146
1221
|
jsonrpc: JSONRPC_VERSION2,
|
|
1147
1222
|
id: requestId ?? uuidv4(),
|
|
1148
1223
|
method: "droid.update_session_settings" /* UPDATE_SESSION_SETTINGS */,
|
|
1149
|
-
params
|
|
1224
|
+
params: sessionTagsUpdateForPeer(params, this.peerProtocolVersion)
|
|
1150
1225
|
};
|
|
1151
1226
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1152
1227
|
const responseParsed = UpdateSessionSettingsResponseSchema.safeParse(rawResponse);
|
|
@@ -1161,16 +1236,16 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1161
1236
|
}
|
|
1162
1237
|
);
|
|
1163
1238
|
}
|
|
1164
|
-
const
|
|
1165
|
-
if (
|
|
1239
|
+
const response2 = responseParsed.data;
|
|
1240
|
+
if (response2.error) {
|
|
1166
1241
|
throw new ProtocolError("Update session settings request failed", {
|
|
1167
1242
|
requestId: request.id,
|
|
1168
|
-
code:
|
|
1169
|
-
message:
|
|
1170
|
-
data:
|
|
1243
|
+
code: response2.error.code,
|
|
1244
|
+
message: response2.error.message,
|
|
1245
|
+
data: response2.error.data
|
|
1171
1246
|
});
|
|
1172
1247
|
}
|
|
1173
|
-
return
|
|
1248
|
+
return response2;
|
|
1174
1249
|
}
|
|
1175
1250
|
async changeWorkingDirectory(params) {
|
|
1176
1251
|
if (!this.currentSessionId) {
|
|
@@ -1179,7 +1254,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1179
1254
|
);
|
|
1180
1255
|
}
|
|
1181
1256
|
const request = {
|
|
1182
|
-
factoryApiVersion:
|
|
1257
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1183
1258
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1184
1259
|
type: "request",
|
|
1185
1260
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1188,16 +1263,16 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1188
1263
|
params
|
|
1189
1264
|
};
|
|
1190
1265
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1191
|
-
const
|
|
1192
|
-
if (
|
|
1266
|
+
const response2 = ChangeWorkingDirectoryResponseSchema.parse(rawResponse);
|
|
1267
|
+
if (response2.error) {
|
|
1193
1268
|
throw new ProtocolError("Change working directory request failed", {
|
|
1194
1269
|
requestId: request.id,
|
|
1195
|
-
code:
|
|
1196
|
-
message:
|
|
1197
|
-
data:
|
|
1270
|
+
code: response2.error.code,
|
|
1271
|
+
message: response2.error.message,
|
|
1272
|
+
data: response2.error.data
|
|
1198
1273
|
});
|
|
1199
1274
|
}
|
|
1200
|
-
return
|
|
1275
|
+
return response2;
|
|
1201
1276
|
}
|
|
1202
1277
|
async toggleMcpServer(params) {
|
|
1203
1278
|
if (!this.currentSessionId) {
|
|
@@ -1206,7 +1281,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1206
1281
|
);
|
|
1207
1282
|
}
|
|
1208
1283
|
const request = {
|
|
1209
|
-
factoryApiVersion:
|
|
1284
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1210
1285
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1211
1286
|
type: "request",
|
|
1212
1287
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1219,8 +1294,8 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1219
1294
|
}
|
|
1220
1295
|
};
|
|
1221
1296
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1222
|
-
const
|
|
1223
|
-
return
|
|
1297
|
+
const response2 = ToggleMcpServerResponseSchema.parse(rawResponse);
|
|
1298
|
+
return response2;
|
|
1224
1299
|
}
|
|
1225
1300
|
async authenticateMcpServer(params) {
|
|
1226
1301
|
if (!this.currentSessionId) {
|
|
@@ -1229,7 +1304,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1229
1304
|
);
|
|
1230
1305
|
}
|
|
1231
1306
|
const request = {
|
|
1232
|
-
factoryApiVersion:
|
|
1307
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1233
1308
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1234
1309
|
type: "request",
|
|
1235
1310
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1240,8 +1315,8 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1240
1315
|
}
|
|
1241
1316
|
};
|
|
1242
1317
|
const rawResponse = await this.sendRequest(request, MCP_AUTH_TIMEOUT2);
|
|
1243
|
-
const
|
|
1244
|
-
return
|
|
1318
|
+
const response2 = AuthenticateMcpServerResponseSchema.parse(rawResponse);
|
|
1319
|
+
return response2;
|
|
1245
1320
|
}
|
|
1246
1321
|
async cancelMcpAuth(params) {
|
|
1247
1322
|
if (!this.currentSessionId) {
|
|
@@ -1250,7 +1325,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1250
1325
|
);
|
|
1251
1326
|
}
|
|
1252
1327
|
const request = {
|
|
1253
|
-
factoryApiVersion:
|
|
1328
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1254
1329
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1255
1330
|
type: "request",
|
|
1256
1331
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1261,8 +1336,8 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1261
1336
|
}
|
|
1262
1337
|
};
|
|
1263
1338
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1264
|
-
const
|
|
1265
|
-
return
|
|
1339
|
+
const response2 = CancelMcpAuthResponseSchema.parse(rawResponse);
|
|
1340
|
+
return response2;
|
|
1266
1341
|
}
|
|
1267
1342
|
async clearMcpAuth(params) {
|
|
1268
1343
|
if (!this.currentSessionId) {
|
|
@@ -1271,7 +1346,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1271
1346
|
);
|
|
1272
1347
|
}
|
|
1273
1348
|
const request = {
|
|
1274
|
-
factoryApiVersion:
|
|
1349
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1275
1350
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1276
1351
|
type: "request",
|
|
1277
1352
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1282,8 +1357,8 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1282
1357
|
}
|
|
1283
1358
|
};
|
|
1284
1359
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1285
|
-
const
|
|
1286
|
-
return
|
|
1360
|
+
const response2 = ClearMcpAuthResponseSchema.parse(rawResponse);
|
|
1361
|
+
return response2;
|
|
1287
1362
|
}
|
|
1288
1363
|
async addMcpServer(params) {
|
|
1289
1364
|
if (!this.currentSessionId) {
|
|
@@ -1295,7 +1370,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1295
1370
|
this.requireMcpOAuthOptOutSupport();
|
|
1296
1371
|
}
|
|
1297
1372
|
const request = {
|
|
1298
|
-
factoryApiVersion:
|
|
1373
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1299
1374
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1300
1375
|
type: "request",
|
|
1301
1376
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1304,8 +1379,8 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1304
1379
|
params
|
|
1305
1380
|
};
|
|
1306
1381
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1307
|
-
const
|
|
1308
|
-
return
|
|
1382
|
+
const response2 = AddMcpServerResponseSchema.parse(rawResponse);
|
|
1383
|
+
return response2;
|
|
1309
1384
|
}
|
|
1310
1385
|
async removeMcpServer(params) {
|
|
1311
1386
|
if (!this.currentSessionId) {
|
|
@@ -1314,7 +1389,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1314
1389
|
);
|
|
1315
1390
|
}
|
|
1316
1391
|
const request = {
|
|
1317
|
-
factoryApiVersion:
|
|
1392
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1318
1393
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1319
1394
|
type: "request",
|
|
1320
1395
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1323,12 +1398,12 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1323
1398
|
params
|
|
1324
1399
|
};
|
|
1325
1400
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1326
|
-
const
|
|
1327
|
-
return
|
|
1401
|
+
const response2 = RemoveMcpServerResponseSchema.parse(rawResponse);
|
|
1402
|
+
return response2;
|
|
1328
1403
|
}
|
|
1329
1404
|
async listModels(params = {}) {
|
|
1330
1405
|
const request = {
|
|
1331
|
-
factoryApiVersion:
|
|
1406
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1332
1407
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1333
1408
|
type: "request",
|
|
1334
1409
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1346,7 +1421,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1346
1421
|
);
|
|
1347
1422
|
}
|
|
1348
1423
|
const request = {
|
|
1349
|
-
factoryApiVersion:
|
|
1424
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1350
1425
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1351
1426
|
type: "request",
|
|
1352
1427
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1355,8 +1430,26 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1355
1430
|
params: {}
|
|
1356
1431
|
};
|
|
1357
1432
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1358
|
-
const
|
|
1359
|
-
return
|
|
1433
|
+
const response2 = ListMcpRegistryResponseSchema.parse(rawResponse);
|
|
1434
|
+
return response2;
|
|
1435
|
+
}
|
|
1436
|
+
async refreshConnectorToolCatalog(params = {}) {
|
|
1437
|
+
if (!this.currentSessionId) {
|
|
1438
|
+
throw new SessionError(
|
|
1439
|
+
"No active session. Call initializeSession or loadSession first."
|
|
1440
|
+
);
|
|
1441
|
+
}
|
|
1442
|
+
const request = {
|
|
1443
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1444
|
+
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1445
|
+
type: "request",
|
|
1446
|
+
jsonrpc: JSONRPC_VERSION2,
|
|
1447
|
+
id: uuidv4(),
|
|
1448
|
+
method: "droid.refresh_connector_tool_catalog" /* REFRESH_CONNECTOR_TOOL_CATALOG */,
|
|
1449
|
+
params
|
|
1450
|
+
};
|
|
1451
|
+
const response2 = await this.sendRequest(request, this.requestTimeout);
|
|
1452
|
+
return RefreshConnectorToolCatalogResponseSchema.parse(response2);
|
|
1360
1453
|
}
|
|
1361
1454
|
async listMcpTools() {
|
|
1362
1455
|
if (!this.currentSessionId) {
|
|
@@ -1365,7 +1458,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1365
1458
|
);
|
|
1366
1459
|
}
|
|
1367
1460
|
const request = {
|
|
1368
|
-
factoryApiVersion:
|
|
1461
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1369
1462
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1370
1463
|
type: "request",
|
|
1371
1464
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1374,12 +1467,13 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1374
1467
|
params: {}
|
|
1375
1468
|
};
|
|
1376
1469
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1377
|
-
const
|
|
1378
|
-
return
|
|
1470
|
+
const response2 = ListMcpToolsResponseSchema.parse(rawResponse);
|
|
1471
|
+
return response2;
|
|
1379
1472
|
}
|
|
1380
1473
|
async listTools(params = {}) {
|
|
1474
|
+
const schemasRequested = params.includeSchemas === true;
|
|
1381
1475
|
const request = {
|
|
1382
|
-
factoryApiVersion:
|
|
1476
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1383
1477
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1384
1478
|
type: "request",
|
|
1385
1479
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1388,8 +1482,29 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1388
1482
|
params
|
|
1389
1483
|
};
|
|
1390
1484
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1391
|
-
const
|
|
1392
|
-
|
|
1485
|
+
const response2 = ListToolsResponseSchema.parse(rawResponse);
|
|
1486
|
+
if (!schemasRequested || !("result" in response2)) {
|
|
1487
|
+
return response2;
|
|
1488
|
+
}
|
|
1489
|
+
const strictResult = ListToolsResultWithSchemasSchema.safeParse(
|
|
1490
|
+
response2.result
|
|
1491
|
+
);
|
|
1492
|
+
if (strictResult.success) {
|
|
1493
|
+
return response2;
|
|
1494
|
+
}
|
|
1495
|
+
const result = ListToolsResultSchema.parse(response2.result);
|
|
1496
|
+
const missingSchemaIds = [];
|
|
1497
|
+
for (const tool2 of result.tools) {
|
|
1498
|
+
if (tool2.schemas === void 0) {
|
|
1499
|
+
missingSchemaIds.push(tool2.llmId);
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
if (missingSchemaIds.length > 0) {
|
|
1503
|
+
throw new ProtocolError(
|
|
1504
|
+
`The installed Droid version did not return requested schemas for tool IDs: ${missingSchemaIds.join(", ")}. Update Droid and try again.`
|
|
1505
|
+
);
|
|
1506
|
+
}
|
|
1507
|
+
throw strictResult.error;
|
|
1393
1508
|
}
|
|
1394
1509
|
async listMcpServers() {
|
|
1395
1510
|
if (!this.currentSessionId) {
|
|
@@ -1398,7 +1513,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1398
1513
|
);
|
|
1399
1514
|
}
|
|
1400
1515
|
const request = {
|
|
1401
|
-
factoryApiVersion:
|
|
1516
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1402
1517
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1403
1518
|
type: "request",
|
|
1404
1519
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1407,8 +1522,8 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1407
1522
|
params: {}
|
|
1408
1523
|
};
|
|
1409
1524
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1410
|
-
const
|
|
1411
|
-
return
|
|
1525
|
+
const response2 = ListMcpServersResponseSchema.parse(rawResponse);
|
|
1526
|
+
return response2;
|
|
1412
1527
|
}
|
|
1413
1528
|
async toggleMcpTool(serverName, toolName, enabled) {
|
|
1414
1529
|
if (!this.currentSessionId) {
|
|
@@ -1417,7 +1532,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1417
1532
|
);
|
|
1418
1533
|
}
|
|
1419
1534
|
const request = {
|
|
1420
|
-
factoryApiVersion:
|
|
1535
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1421
1536
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1422
1537
|
type: "request",
|
|
1423
1538
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1426,8 +1541,8 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1426
1541
|
params: { serverName, toolName, enabled }
|
|
1427
1542
|
};
|
|
1428
1543
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1429
|
-
const
|
|
1430
|
-
return
|
|
1544
|
+
const response2 = ToggleMcpToolResponseSchema.parse(rawResponse);
|
|
1545
|
+
return response2;
|
|
1431
1546
|
}
|
|
1432
1547
|
async submitMcpAuthCode(params) {
|
|
1433
1548
|
if (!this.currentSessionId) {
|
|
@@ -1436,7 +1551,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1436
1551
|
);
|
|
1437
1552
|
}
|
|
1438
1553
|
const request = {
|
|
1439
|
-
factoryApiVersion:
|
|
1554
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1440
1555
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1441
1556
|
type: "request",
|
|
1442
1557
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1445,8 +1560,8 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1445
1560
|
params
|
|
1446
1561
|
};
|
|
1447
1562
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1448
|
-
const
|
|
1449
|
-
return
|
|
1563
|
+
const response2 = SubmitMcpAuthCodeResponseSchema.parse(rawResponse);
|
|
1564
|
+
return response2;
|
|
1450
1565
|
}
|
|
1451
1566
|
async submitMcpAuthError(params) {
|
|
1452
1567
|
if (!this.currentSessionId) {
|
|
@@ -1455,7 +1570,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1455
1570
|
);
|
|
1456
1571
|
}
|
|
1457
1572
|
const request = {
|
|
1458
|
-
factoryApiVersion:
|
|
1573
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1459
1574
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1460
1575
|
type: "request",
|
|
1461
1576
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1464,27 +1579,27 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1464
1579
|
params
|
|
1465
1580
|
};
|
|
1466
1581
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1467
|
-
const
|
|
1468
|
-
return
|
|
1582
|
+
const response2 = SubmitMcpAuthErrorResponseSchema.parse(rawResponse);
|
|
1583
|
+
return response2;
|
|
1469
1584
|
}
|
|
1470
|
-
async listSkills() {
|
|
1585
|
+
async listSkills(params = {}) {
|
|
1471
1586
|
if (!this.currentSessionId) {
|
|
1472
1587
|
throw new SessionError(
|
|
1473
1588
|
"No active session. Call initializeSession or loadSession first."
|
|
1474
1589
|
);
|
|
1475
1590
|
}
|
|
1476
1591
|
const request = {
|
|
1477
|
-
factoryApiVersion:
|
|
1592
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1478
1593
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1479
1594
|
type: "request",
|
|
1480
1595
|
jsonrpc: JSONRPC_VERSION2,
|
|
1481
1596
|
id: uuidv4(),
|
|
1482
1597
|
method: "droid.list_skills" /* LIST_SKILLS */,
|
|
1483
|
-
params
|
|
1598
|
+
params
|
|
1484
1599
|
};
|
|
1485
1600
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1486
|
-
const
|
|
1487
|
-
return
|
|
1601
|
+
const response2 = ListSkillsResponseSchema.parse(rawResponse);
|
|
1602
|
+
return response2;
|
|
1488
1603
|
}
|
|
1489
1604
|
async setSkillDisabled(skillName, disabled, settingsLevel) {
|
|
1490
1605
|
if (!this.currentSessionId) {
|
|
@@ -1493,7 +1608,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1493
1608
|
);
|
|
1494
1609
|
}
|
|
1495
1610
|
const request = {
|
|
1496
|
-
factoryApiVersion:
|
|
1611
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1497
1612
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1498
1613
|
type: "request",
|
|
1499
1614
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1511,7 +1626,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1511
1626
|
);
|
|
1512
1627
|
}
|
|
1513
1628
|
const request = {
|
|
1514
|
-
factoryApiVersion:
|
|
1629
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1515
1630
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1516
1631
|
type: "request",
|
|
1517
1632
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1520,8 +1635,8 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1520
1635
|
params: {}
|
|
1521
1636
|
};
|
|
1522
1637
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1523
|
-
const
|
|
1524
|
-
return
|
|
1638
|
+
const response2 = ListCommandsResponseSchema.parse(rawResponse);
|
|
1639
|
+
return response2;
|
|
1525
1640
|
}
|
|
1526
1641
|
async getContextStats() {
|
|
1527
1642
|
if (!this.currentSessionId) {
|
|
@@ -1530,7 +1645,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1530
1645
|
);
|
|
1531
1646
|
}
|
|
1532
1647
|
const request = {
|
|
1533
|
-
factoryApiVersion:
|
|
1648
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1534
1649
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1535
1650
|
type: "request",
|
|
1536
1651
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1539,8 +1654,8 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1539
1654
|
params: {}
|
|
1540
1655
|
};
|
|
1541
1656
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1542
|
-
const
|
|
1543
|
-
return
|
|
1657
|
+
const response2 = GetContextStatsResponseSchema.parse(rawResponse);
|
|
1658
|
+
return response2;
|
|
1544
1659
|
}
|
|
1545
1660
|
async getContextBreakdown() {
|
|
1546
1661
|
if (!this.currentSessionId) {
|
|
@@ -1549,7 +1664,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1549
1664
|
);
|
|
1550
1665
|
}
|
|
1551
1666
|
const request = {
|
|
1552
|
-
factoryApiVersion:
|
|
1667
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1553
1668
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1554
1669
|
type: "request",
|
|
1555
1670
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1558,27 +1673,45 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1558
1673
|
params: {}
|
|
1559
1674
|
};
|
|
1560
1675
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1561
|
-
const
|
|
1562
|
-
return
|
|
1676
|
+
const response2 = GetContextBreakdownResponseSchema.parse(rawResponse);
|
|
1677
|
+
return response2;
|
|
1563
1678
|
}
|
|
1564
|
-
async
|
|
1679
|
+
async killBackgroundProcess(processId) {
|
|
1565
1680
|
if (!this.currentSessionId) {
|
|
1566
1681
|
throw new SessionError(
|
|
1567
1682
|
"No active session. Call initializeSession or loadSession first."
|
|
1568
1683
|
);
|
|
1569
1684
|
}
|
|
1570
1685
|
const request = {
|
|
1571
|
-
factoryApiVersion:
|
|
1686
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1687
|
+
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1688
|
+
type: "request",
|
|
1689
|
+
jsonrpc: JSONRPC_VERSION2,
|
|
1690
|
+
id: uuidv4(),
|
|
1691
|
+
method: "droid.kill_background_process" /* KILL_BACKGROUND_PROCESS */,
|
|
1692
|
+
params: { processId }
|
|
1693
|
+
};
|
|
1694
|
+
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1695
|
+
return KillBackgroundProcessResponseSchema.parse(rawResponse);
|
|
1696
|
+
}
|
|
1697
|
+
async submitBugReport(userComment, clientLogs, source, tuiLogs) {
|
|
1698
|
+
if (!this.currentSessionId) {
|
|
1699
|
+
throw new SessionError(
|
|
1700
|
+
"No active session. Call initializeSession or loadSession first."
|
|
1701
|
+
);
|
|
1702
|
+
}
|
|
1703
|
+
const request = {
|
|
1704
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1572
1705
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1573
1706
|
type: "request",
|
|
1574
1707
|
jsonrpc: JSONRPC_VERSION2,
|
|
1575
1708
|
id: uuidv4(),
|
|
1576
1709
|
method: "droid.submit_bug_report" /* SUBMIT_BUG_REPORT */,
|
|
1577
|
-
params: { userComment, clientLogs, source }
|
|
1710
|
+
params: { userComment, clientLogs, source, tuiLogs }
|
|
1578
1711
|
};
|
|
1579
1712
|
const rawResponse = await this.sendRequest(request, this.requestTimeout);
|
|
1580
|
-
const
|
|
1581
|
-
return
|
|
1713
|
+
const response2 = SubmitBugReportResponseSchema.parse(rawResponse);
|
|
1714
|
+
return response2;
|
|
1582
1715
|
}
|
|
1583
1716
|
async getRewindInfo(params, timeout = this.requestTimeout) {
|
|
1584
1717
|
if (!this.currentSessionId) {
|
|
@@ -1587,7 +1720,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1587
1720
|
);
|
|
1588
1721
|
}
|
|
1589
1722
|
const request = {
|
|
1590
|
-
factoryApiVersion:
|
|
1723
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1591
1724
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1592
1725
|
type: "request",
|
|
1593
1726
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1608,7 +1741,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1608
1741
|
);
|
|
1609
1742
|
}
|
|
1610
1743
|
const request = {
|
|
1611
|
-
factoryApiVersion:
|
|
1744
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1612
1745
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1613
1746
|
type: "request",
|
|
1614
1747
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1635,19 +1768,58 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1635
1768
|
);
|
|
1636
1769
|
}
|
|
1637
1770
|
const request = {
|
|
1638
|
-
factoryApiVersion:
|
|
1771
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1639
1772
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1640
1773
|
type: "request",
|
|
1641
1774
|
jsonrpc: JSONRPC_VERSION2,
|
|
1642
1775
|
id: uuidv4(),
|
|
1643
1776
|
method: "droid.compact_session" /* COMPACT_SESSION */,
|
|
1644
1777
|
params: {
|
|
1645
|
-
customInstructions: params.customInstructions
|
|
1778
|
+
customInstructions: params.customInstructions,
|
|
1779
|
+
mode: params.mode
|
|
1646
1780
|
}
|
|
1647
1781
|
};
|
|
1648
1782
|
const rawResponse = await this.sendRequest(request, COMPACTION_TIMEOUT2);
|
|
1649
1783
|
return CompactSessionResponseSchema.parse(rawResponse);
|
|
1650
1784
|
}
|
|
1785
|
+
/** Summarizes the session the way `/handoff` does, without writing anything. */
|
|
1786
|
+
async getHandoffSummary() {
|
|
1787
|
+
if (!this.currentSessionId) {
|
|
1788
|
+
throw new SessionError(
|
|
1789
|
+
"No active session. Call initializeSession or loadSession first."
|
|
1790
|
+
);
|
|
1791
|
+
}
|
|
1792
|
+
const request = {
|
|
1793
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1794
|
+
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1795
|
+
type: "request",
|
|
1796
|
+
jsonrpc: JSONRPC_VERSION2,
|
|
1797
|
+
id: uuidv4(),
|
|
1798
|
+
method: "droid.get_handoff_summary" /* GET_HANDOFF_SUMMARY */,
|
|
1799
|
+
params: {}
|
|
1800
|
+
};
|
|
1801
|
+
const rawResponse = await this.sendRequest(request, COMPACTION_TIMEOUT2);
|
|
1802
|
+
return GetHandoffSummaryResponseSchema.parse(rawResponse);
|
|
1803
|
+
}
|
|
1804
|
+
/** Writes the short summary people joining a shared copy read first. */
|
|
1805
|
+
async summarizeForMembers(params) {
|
|
1806
|
+
if (!this.currentSessionId) {
|
|
1807
|
+
throw new SessionError(
|
|
1808
|
+
"No active session. Call initializeSession or loadSession first."
|
|
1809
|
+
);
|
|
1810
|
+
}
|
|
1811
|
+
const request = {
|
|
1812
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1813
|
+
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1814
|
+
type: "request",
|
|
1815
|
+
jsonrpc: JSONRPC_VERSION2,
|
|
1816
|
+
id: uuidv4(),
|
|
1817
|
+
method: "droid.summarize_for_members" /* SUMMARIZE_FOR_MEMBERS */,
|
|
1818
|
+
params: { handoffSummary: params.handoffSummary }
|
|
1819
|
+
};
|
|
1820
|
+
const rawResponse = await this.sendRequest(request, COMPACTION_TIMEOUT2);
|
|
1821
|
+
return SummarizeForMembersResponseSchema.parse(rawResponse);
|
|
1822
|
+
}
|
|
1651
1823
|
async forkSession(params) {
|
|
1652
1824
|
if (!this.currentSessionId) {
|
|
1653
1825
|
throw new SessionError(
|
|
@@ -1655,7 +1827,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1655
1827
|
);
|
|
1656
1828
|
}
|
|
1657
1829
|
const request = {
|
|
1658
|
-
factoryApiVersion:
|
|
1830
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1659
1831
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1660
1832
|
type: "request",
|
|
1661
1833
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1673,7 +1845,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1673
1845
|
);
|
|
1674
1846
|
}
|
|
1675
1847
|
const request = {
|
|
1676
|
-
factoryApiVersion:
|
|
1848
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1677
1849
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1678
1850
|
type: "request",
|
|
1679
1851
|
jsonrpc: JSONRPC_VERSION2,
|
|
@@ -1687,15 +1859,15 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1687
1859
|
return RenameSessionResponseSchema.parse(rawResponse);
|
|
1688
1860
|
}
|
|
1689
1861
|
async warmupCache() {
|
|
1690
|
-
const
|
|
1691
|
-
factoryApiVersion:
|
|
1862
|
+
const response2 = {
|
|
1863
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
1692
1864
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
1693
1865
|
type: "response",
|
|
1694
1866
|
jsonrpc: JSONRPC_VERSION2,
|
|
1695
1867
|
id: uuidv4(),
|
|
1696
1868
|
result: {}
|
|
1697
1869
|
};
|
|
1698
|
-
return WarmupCacheResponseSchema.parse(
|
|
1870
|
+
return WarmupCacheResponseSchema.parse(response2);
|
|
1699
1871
|
}
|
|
1700
1872
|
onNotification(callback, filter) {
|
|
1701
1873
|
const handler = (notification) => {
|
|
@@ -1726,25 +1898,61 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1726
1898
|
setPermissionHandler(handler) {
|
|
1727
1899
|
this.permissionHandlers.set(
|
|
1728
1900
|
"default",
|
|
1729
|
-
async (event) => await handler(event)
|
|
1901
|
+
async (event, setResponseMetadata) => await handler(event, setResponseMetadata)
|
|
1730
1902
|
);
|
|
1731
1903
|
}
|
|
1732
1904
|
clearPermissionHandler() {
|
|
1733
1905
|
this.permissionHandlers.delete("default");
|
|
1734
1906
|
}
|
|
1735
1907
|
setAskUserHandler(handler) {
|
|
1736
|
-
this.askUserHandlers.set(
|
|
1908
|
+
this.askUserHandlers.set(
|
|
1909
|
+
"default",
|
|
1910
|
+
async (event, setResponseMetadata) => await handler(event, setResponseMetadata)
|
|
1911
|
+
);
|
|
1912
|
+
const held = this.heldQueuedAskUserRequests;
|
|
1913
|
+
this.heldQueuedAskUserRequests = [];
|
|
1914
|
+
for (const event of held) {
|
|
1915
|
+
void this.answerAskUserRequest(event).catch((error) => {
|
|
1916
|
+
this.reportHandlerFailure(
|
|
1917
|
+
error,
|
|
1918
|
+
"Failed to answer a held queued ask-user request"
|
|
1919
|
+
);
|
|
1920
|
+
});
|
|
1921
|
+
}
|
|
1737
1922
|
}
|
|
1738
1923
|
clearAskUserHandler() {
|
|
1739
1924
|
this.askUserHandlers.delete("default");
|
|
1740
1925
|
}
|
|
1741
|
-
|
|
1742
|
-
|
|
1926
|
+
setPickOptionsHandler(handler) {
|
|
1927
|
+
this.pickOptionsHandlers.set(
|
|
1928
|
+
"default",
|
|
1929
|
+
async (event, setResponseMetadata) => await handler(event, setResponseMetadata)
|
|
1930
|
+
);
|
|
1931
|
+
}
|
|
1932
|
+
clearPickOptionsHandler() {
|
|
1933
|
+
this.pickOptionsHandlers.delete("default");
|
|
1934
|
+
}
|
|
1935
|
+
async close(options) {
|
|
1936
|
+
const closeError = new DroidConnectionEndedError(
|
|
1743
1937
|
"Droid client closed: pending requests cancelled"
|
|
1744
1938
|
);
|
|
1939
|
+
if (options?.closeTransportFirst) {
|
|
1940
|
+
try {
|
|
1941
|
+
await this.transport.close();
|
|
1942
|
+
} finally {
|
|
1943
|
+
this.rejectAllPending(closeError);
|
|
1944
|
+
this.permissionHandlers.clear();
|
|
1945
|
+
this.askUserHandlers.clear();
|
|
1946
|
+
this.heldQueuedAskUserRequests = [];
|
|
1947
|
+
this.removeAllListeners();
|
|
1948
|
+
}
|
|
1949
|
+
return;
|
|
1950
|
+
}
|
|
1745
1951
|
this.rejectAllPending(closeError);
|
|
1746
1952
|
this.permissionHandlers.clear();
|
|
1747
1953
|
this.askUserHandlers.clear();
|
|
1954
|
+
this.heldQueuedAskUserRequests = [];
|
|
1955
|
+
this.pickOptionsHandlers.clear();
|
|
1748
1956
|
this.removeAllListeners();
|
|
1749
1957
|
await this.transport.close();
|
|
1750
1958
|
}
|
|
@@ -1765,6 +1973,10 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1765
1973
|
reject(error);
|
|
1766
1974
|
});
|
|
1767
1975
|
this.pendingAskUserRequests.clear();
|
|
1976
|
+
this.pendingPickOptionsRequests.forEach(({ reject }) => {
|
|
1977
|
+
reject(error);
|
|
1978
|
+
});
|
|
1979
|
+
this.pendingPickOptionsRequests.clear();
|
|
1768
1980
|
}
|
|
1769
1981
|
settleRequest(requestId) {
|
|
1770
1982
|
this.pendingRequests.delete(requestId);
|
|
@@ -1776,16 +1988,31 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1776
1988
|
} catch {
|
|
1777
1989
|
}
|
|
1778
1990
|
}
|
|
1779
|
-
|
|
1991
|
+
/** `_meta` for an answer this client gives itself: its caller and the current trace context. */
|
|
1992
|
+
responseMetadata() {
|
|
1993
|
+
const meta = {};
|
|
1994
|
+
const requestAttribution = this.getRequestAttribution?.();
|
|
1995
|
+
if (requestAttribution) meta.requestAttribution = requestAttribution;
|
|
1996
|
+
this.tracing.injectContext(meta, this.tracing.getCurrentContext());
|
|
1997
|
+
return meta;
|
|
1998
|
+
}
|
|
1999
|
+
async sendResponse(response2, hostMeta) {
|
|
2000
|
+
const meta = hostMeta ?? this.responseMetadata();
|
|
2001
|
+
await this.transport.send(
|
|
2002
|
+
Object.keys(meta).length > 0 ? { ...response2, _meta: meta } : response2
|
|
2003
|
+
);
|
|
2004
|
+
}
|
|
2005
|
+
async sendRequest(request, timeout, sessionId) {
|
|
1780
2006
|
if (this.transportError) {
|
|
1781
2007
|
throw this.transportError;
|
|
1782
2008
|
}
|
|
1783
|
-
const requestAttribution = this.getRequestAttribution?.();
|
|
1784
|
-
const _meta = {
|
|
1785
|
-
|
|
1786
|
-
|
|
2009
|
+
const requestAttribution = request._meta?.requestAttribution ?? this.getRequestAttribution?.();
|
|
2010
|
+
const _meta = { ...request._meta };
|
|
2011
|
+
delete _meta.requestAttribution;
|
|
2012
|
+
if (requestAttribution) _meta.requestAttribution = requestAttribution;
|
|
1787
2013
|
this.tracing.injectContext(_meta, this.tracing.getCurrentContext());
|
|
1788
|
-
const
|
|
2014
|
+
const { _meta: _originalMeta, ...requestWithoutMeta } = request;
|
|
2015
|
+
const requestWithMeta = Object.keys(_meta).length > 0 ? { ...request, _meta } : requestWithoutMeta;
|
|
1789
2016
|
const responsePromise = new Promise(
|
|
1790
2017
|
(resolve2, reject) => {
|
|
1791
2018
|
const timeoutId = timeout ? setTimeout(() => {
|
|
@@ -1802,16 +2029,23 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1802
2029
|
method: request.method,
|
|
1803
2030
|
resolve: resolve2,
|
|
1804
2031
|
reject,
|
|
1805
|
-
timeoutId
|
|
2032
|
+
timeoutId,
|
|
2033
|
+
sessionId
|
|
1806
2034
|
});
|
|
1807
2035
|
}
|
|
1808
2036
|
);
|
|
2037
|
+
void responsePromise.catch(() => {
|
|
2038
|
+
});
|
|
2039
|
+
void this.writeRequest(requestWithMeta);
|
|
2040
|
+
return responsePromise;
|
|
2041
|
+
}
|
|
2042
|
+
async writeRequest(request) {
|
|
1809
2043
|
try {
|
|
1810
2044
|
this.logger.info("[DroidClient] [daemon -> droid] sending request", {
|
|
1811
2045
|
requestId: request.id,
|
|
1812
2046
|
method: request.method
|
|
1813
2047
|
});
|
|
1814
|
-
await this.transport.send(
|
|
2048
|
+
await this.transport.send(request);
|
|
1815
2049
|
} catch (error) {
|
|
1816
2050
|
const pending = this.pendingRequests.get(request.id);
|
|
1817
2051
|
if (pending) {
|
|
@@ -1827,141 +2061,145 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1827
2061
|
);
|
|
1828
2062
|
}
|
|
1829
2063
|
}
|
|
1830
|
-
return responsePromise;
|
|
1831
2064
|
}
|
|
1832
2065
|
async handleMessage(message) {
|
|
1833
2066
|
try {
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
this.handleResponse(parsed);
|
|
1837
|
-
} else if ("method" in parsed) {
|
|
1838
|
-
await this.handleEvent(parsed);
|
|
2067
|
+
if (message.type === "response") {
|
|
2068
|
+
this.handleResponse(message);
|
|
1839
2069
|
} else {
|
|
1840
|
-
|
|
1841
|
-
message
|
|
1842
|
-
});
|
|
2070
|
+
await this.handleEvent(message);
|
|
1843
2071
|
}
|
|
1844
2072
|
} catch {
|
|
1845
|
-
this.logger.warn("[DroidClient] Failed to handle message"
|
|
1846
|
-
messageByteLength: new TextEncoder().encode(message).byteLength
|
|
1847
|
-
});
|
|
2073
|
+
this.logger.warn("[DroidClient] Failed to handle message");
|
|
1848
2074
|
}
|
|
1849
2075
|
}
|
|
1850
|
-
handleResponse(
|
|
2076
|
+
handleResponse(response2) {
|
|
1851
2077
|
try {
|
|
1852
|
-
const responseId = getResponseId(
|
|
2078
|
+
const responseId = getResponseId(response2);
|
|
1853
2079
|
if (responseId !== null && responseId !== void 0) {
|
|
1854
2080
|
const pending = this.pendingRequests.get(responseId);
|
|
1855
2081
|
if (pending) {
|
|
1856
2082
|
let validatedResponse;
|
|
1857
2083
|
switch (pending.method) {
|
|
1858
2084
|
case "droid.initialize_session" /* INITIALIZE_SESSION */:
|
|
1859
|
-
validatedResponse = InitializeSessionResponseSchema.parse(
|
|
2085
|
+
validatedResponse = InitializeSessionResponseSchema.parse(response2);
|
|
1860
2086
|
break;
|
|
1861
2087
|
case "droid.load_session" /* LOAD_SESSION */:
|
|
1862
|
-
validatedResponse = LoadSessionResponseSchema.parse(
|
|
2088
|
+
validatedResponse = LoadSessionResponseSchema.parse(response2);
|
|
1863
2089
|
break;
|
|
1864
2090
|
case "droid.add_user_message" /* ADD_USER_MESSAGE */:
|
|
1865
|
-
validatedResponse = AddUserMessageResponseSchema.parse(
|
|
2091
|
+
validatedResponse = AddUserMessageResponseSchema.parse(response2);
|
|
1866
2092
|
break;
|
|
1867
2093
|
case "droid.append_messages" /* APPEND_MESSAGES */:
|
|
1868
|
-
validatedResponse = AppendMessagesResponseSchema.parse(
|
|
2094
|
+
validatedResponse = AppendMessagesResponseSchema.parse(response2);
|
|
1869
2095
|
break;
|
|
1870
2096
|
case "droid.resolve_queued_user_message" /* RESOLVE_QUEUED_USER_MESSAGE */:
|
|
1871
|
-
validatedResponse = ResolveQueuedUserMessageResponseSchema.parse(
|
|
2097
|
+
validatedResponse = ResolveQueuedUserMessageResponseSchema.parse(response2);
|
|
1872
2098
|
break;
|
|
1873
2099
|
case "droid.interrupt_session" /* INTERRUPT_SESSION */:
|
|
1874
|
-
validatedResponse = InterruptSessionResponseSchema.parse(
|
|
2100
|
+
validatedResponse = InterruptSessionResponseSchema.parse(response2);
|
|
1875
2101
|
break;
|
|
1876
2102
|
case "droid.close_session" /* CLOSE_SESSION */:
|
|
1877
|
-
validatedResponse = CloseSessionResponseSchema.parse(
|
|
2103
|
+
validatedResponse = CloseSessionResponseSchema.parse(response2);
|
|
1878
2104
|
break;
|
|
1879
2105
|
case "droid.update_session_settings" /* UPDATE_SESSION_SETTINGS */:
|
|
1880
|
-
validatedResponse = UpdateSessionSettingsResponseSchema.parse(
|
|
2106
|
+
validatedResponse = UpdateSessionSettingsResponseSchema.parse(response2);
|
|
1881
2107
|
break;
|
|
1882
2108
|
case "droid.change_working_directory" /* CHANGE_WORKING_DIRECTORY */:
|
|
1883
|
-
validatedResponse = ChangeWorkingDirectoryResponseSchema.parse(
|
|
2109
|
+
validatedResponse = ChangeWorkingDirectoryResponseSchema.parse(response2);
|
|
1884
2110
|
break;
|
|
1885
2111
|
case "droid.toggle_mcp_server" /* TOGGLE_MCP_SERVER */:
|
|
1886
|
-
validatedResponse = ToggleMcpServerResponseSchema.parse(
|
|
2112
|
+
validatedResponse = ToggleMcpServerResponseSchema.parse(response2);
|
|
1887
2113
|
break;
|
|
1888
2114
|
case "droid.authenticate_mcp_server" /* AUTHENTICATE_MCP_SERVER */:
|
|
1889
|
-
validatedResponse = AuthenticateMcpServerResponseSchema.parse(
|
|
2115
|
+
validatedResponse = AuthenticateMcpServerResponseSchema.parse(response2);
|
|
1890
2116
|
break;
|
|
1891
2117
|
case "droid.cancel_mcp_auth" /* CANCEL_MCP_AUTH */:
|
|
1892
|
-
validatedResponse = CancelMcpAuthResponseSchema.parse(
|
|
2118
|
+
validatedResponse = CancelMcpAuthResponseSchema.parse(response2);
|
|
1893
2119
|
break;
|
|
1894
2120
|
case "droid.clear_mcp_auth" /* CLEAR_MCP_AUTH */:
|
|
1895
|
-
validatedResponse = ClearMcpAuthResponseSchema.parse(
|
|
2121
|
+
validatedResponse = ClearMcpAuthResponseSchema.parse(response2);
|
|
1896
2122
|
break;
|
|
1897
2123
|
case "droid.add_mcp_server" /* ADD_MCP_SERVER */:
|
|
1898
|
-
validatedResponse = AddMcpServerResponseSchema.parse(
|
|
2124
|
+
validatedResponse = AddMcpServerResponseSchema.parse(response2);
|
|
1899
2125
|
break;
|
|
1900
2126
|
case "droid.remove_mcp_server" /* REMOVE_MCP_SERVER */:
|
|
1901
|
-
validatedResponse = RemoveMcpServerResponseSchema.parse(
|
|
2127
|
+
validatedResponse = RemoveMcpServerResponseSchema.parse(response2);
|
|
1902
2128
|
break;
|
|
1903
2129
|
case "droid.list_models" /* LIST_MODELS */:
|
|
1904
|
-
validatedResponse = ListModelsResponseSchema.parse(
|
|
2130
|
+
validatedResponse = ListModelsResponseSchema.parse(response2);
|
|
1905
2131
|
break;
|
|
1906
2132
|
case "droid.list_mcp_registry" /* LIST_MCP_REGISTRY */:
|
|
1907
|
-
validatedResponse = ListMcpRegistryResponseSchema.parse(
|
|
2133
|
+
validatedResponse = ListMcpRegistryResponseSchema.parse(response2);
|
|
1908
2134
|
break;
|
|
1909
2135
|
case "droid.list_mcp_tools" /* LIST_MCP_TOOLS */:
|
|
1910
|
-
validatedResponse = ListMcpToolsResponseSchema.parse(
|
|
2136
|
+
validatedResponse = ListMcpToolsResponseSchema.parse(response2);
|
|
1911
2137
|
break;
|
|
1912
2138
|
case "droid.list_tools" /* LIST_TOOLS */:
|
|
1913
|
-
validatedResponse = ListToolsResponseSchema.parse(
|
|
2139
|
+
validatedResponse = ListToolsResponseSchema.parse(response2);
|
|
2140
|
+
break;
|
|
2141
|
+
case "droid.refresh_connector_tool_catalog" /* REFRESH_CONNECTOR_TOOL_CATALOG */:
|
|
2142
|
+
validatedResponse = RefreshConnectorToolCatalogResponseSchema.parse(response2);
|
|
1914
2143
|
break;
|
|
1915
2144
|
case "droid.toggle_mcp_tool" /* TOGGLE_MCP_TOOL */:
|
|
1916
|
-
validatedResponse = ToggleMcpToolResponseSchema.parse(
|
|
2145
|
+
validatedResponse = ToggleMcpToolResponseSchema.parse(response2);
|
|
1917
2146
|
break;
|
|
1918
2147
|
case "droid.submit_mcp_auth_code" /* SUBMIT_MCP_AUTH_CODE */:
|
|
1919
|
-
validatedResponse = SubmitMcpAuthCodeResponseSchema.parse(
|
|
2148
|
+
validatedResponse = SubmitMcpAuthCodeResponseSchema.parse(response2);
|
|
1920
2149
|
break;
|
|
1921
2150
|
case "droid.submit_mcp_auth_error" /* SUBMIT_MCP_AUTH_ERROR */:
|
|
1922
|
-
validatedResponse = SubmitMcpAuthErrorResponseSchema.parse(
|
|
2151
|
+
validatedResponse = SubmitMcpAuthErrorResponseSchema.parse(response2);
|
|
1923
2152
|
break;
|
|
1924
2153
|
case "droid.kill_worker_session" /* KILL_WORKER_SESSION */:
|
|
1925
|
-
validatedResponse = KillWorkerSessionResponseSchema.parse(
|
|
2154
|
+
validatedResponse = KillWorkerSessionResponseSchema.parse(response2);
|
|
1926
2155
|
break;
|
|
1927
2156
|
case "droid.list_skills" /* LIST_SKILLS */:
|
|
1928
|
-
validatedResponse = ListSkillsResponseSchema.parse(
|
|
2157
|
+
validatedResponse = ListSkillsResponseSchema.parse(response2);
|
|
1929
2158
|
break;
|
|
1930
2159
|
case "droid.set_skill_disabled" /* SET_SKILL_DISABLED */:
|
|
1931
|
-
validatedResponse = SetSkillDisabledResponseSchema.parse(
|
|
2160
|
+
validatedResponse = SetSkillDisabledResponseSchema.parse(response2);
|
|
1932
2161
|
break;
|
|
1933
2162
|
case "droid.list_commands" /* LIST_COMMANDS */:
|
|
1934
|
-
validatedResponse = ListCommandsResponseSchema.parse(
|
|
2163
|
+
validatedResponse = ListCommandsResponseSchema.parse(response2);
|
|
1935
2164
|
break;
|
|
1936
2165
|
case "droid.submit_bug_report" /* SUBMIT_BUG_REPORT */:
|
|
1937
|
-
validatedResponse = SubmitBugReportResponseSchema.parse(
|
|
2166
|
+
validatedResponse = SubmitBugReportResponseSchema.parse(response2);
|
|
1938
2167
|
break;
|
|
1939
2168
|
case "droid.list_mcp_servers" /* LIST_MCP_SERVERS */:
|
|
1940
|
-
validatedResponse = ListMcpServersResponseSchema.parse(
|
|
2169
|
+
validatedResponse = ListMcpServersResponseSchema.parse(response2);
|
|
1941
2170
|
break;
|
|
1942
2171
|
case "droid.get_rewind_info" /* GET_REWIND_INFO */:
|
|
1943
|
-
validatedResponse = GetRewindInfoResponseSchema.parse(
|
|
2172
|
+
validatedResponse = GetRewindInfoResponseSchema.parse(response2);
|
|
1944
2173
|
break;
|
|
1945
2174
|
case "droid.execute_rewind" /* EXECUTE_REWIND */:
|
|
1946
|
-
validatedResponse = ExecuteRewindResponseSchema.parse(
|
|
2175
|
+
validatedResponse = ExecuteRewindResponseSchema.parse(response2);
|
|
1947
2176
|
break;
|
|
1948
2177
|
case "droid.compact_session" /* COMPACT_SESSION */:
|
|
1949
|
-
validatedResponse = CompactSessionResponseSchema.parse(
|
|
2178
|
+
validatedResponse = CompactSessionResponseSchema.parse(response2);
|
|
2179
|
+
break;
|
|
2180
|
+
case "droid.get_handoff_summary" /* GET_HANDOFF_SUMMARY */:
|
|
2181
|
+
validatedResponse = GetHandoffSummaryResponseSchema.parse(response2);
|
|
2182
|
+
break;
|
|
2183
|
+
case "droid.summarize_for_members" /* SUMMARIZE_FOR_MEMBERS */:
|
|
2184
|
+
validatedResponse = SummarizeForMembersResponseSchema.parse(response2);
|
|
1950
2185
|
break;
|
|
1951
2186
|
case "droid.fork_session" /* FORK_SESSION */:
|
|
1952
|
-
validatedResponse = ForkSessionResponseSchema.parse(
|
|
2187
|
+
validatedResponse = ForkSessionResponseSchema.parse(response2);
|
|
1953
2188
|
break;
|
|
1954
2189
|
case "droid.rename_session" /* RENAME_SESSION */:
|
|
1955
|
-
validatedResponse = RenameSessionResponseSchema.parse(
|
|
2190
|
+
validatedResponse = RenameSessionResponseSchema.parse(response2);
|
|
1956
2191
|
break;
|
|
1957
2192
|
case "droid.get_context_stats" /* GET_CONTEXT_STATS */:
|
|
1958
|
-
validatedResponse = GetContextStatsResponseSchema.parse(
|
|
2193
|
+
validatedResponse = GetContextStatsResponseSchema.parse(response2);
|
|
1959
2194
|
break;
|
|
1960
2195
|
case "droid.get_context_breakdown" /* GET_CONTEXT_BREAKDOWN */:
|
|
1961
|
-
validatedResponse = GetContextBreakdownResponseSchema.parse(
|
|
2196
|
+
validatedResponse = GetContextBreakdownResponseSchema.parse(response2);
|
|
1962
2197
|
break;
|
|
1963
2198
|
case "droid.warmup_cache" /* WARMUP_CACHE */:
|
|
1964
|
-
validatedResponse = WarmupCacheResponseSchema.parse(
|
|
2199
|
+
validatedResponse = WarmupCacheResponseSchema.parse(response2);
|
|
2200
|
+
break;
|
|
2201
|
+
case "droid.kill_background_process" /* KILL_BACKGROUND_PROCESS */:
|
|
2202
|
+
validatedResponse = KillBackgroundProcessResponseSchema.parse(response2);
|
|
1965
2203
|
break;
|
|
1966
2204
|
default: {
|
|
1967
2205
|
const exhaustiveCheck = pending.method;
|
|
@@ -1979,7 +2217,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1979
2217
|
this.settleRequest(responseId);
|
|
1980
2218
|
pending.resolve(validatedResponse);
|
|
1981
2219
|
} else {
|
|
1982
|
-
const validatedResponse = JsonRpcBaseResponseSchema.parse(
|
|
2220
|
+
const validatedResponse = JsonRpcBaseResponseSchema.parse(response2);
|
|
1983
2221
|
this.logger.info(
|
|
1984
2222
|
"[DroidClient] Received response for request not in pending map",
|
|
1985
2223
|
{
|
|
@@ -1989,7 +2227,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
1989
2227
|
}
|
|
1990
2228
|
}
|
|
1991
2229
|
} catch (error) {
|
|
1992
|
-
const responseId = getResponseId(
|
|
2230
|
+
const responseId = getResponseId(response2);
|
|
1993
2231
|
const pending = responseId !== null && responseId !== void 0 ? this.pendingRequests.get(responseId) : void 0;
|
|
1994
2232
|
const zodIssues = error instanceof z.ZodError ? error.issues.map((issue) => ({
|
|
1995
2233
|
path: issue.path,
|
|
@@ -2025,7 +2263,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2025
2263
|
const syntheticFailure = {
|
|
2026
2264
|
jsonrpc: JSONRPC_VERSION2,
|
|
2027
2265
|
type: "response",
|
|
2028
|
-
factoryApiVersion:
|
|
2266
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
2029
2267
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
2030
2268
|
id: responseId,
|
|
2031
2269
|
error: {
|
|
@@ -2044,14 +2282,20 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2044
2282
|
const notification = validatedEvent.params.notification;
|
|
2045
2283
|
if (notification.type === "agent_turn_completed" /* AGENT_TURN_COMPLETED */) {
|
|
2046
2284
|
this.completedTurnObserved = true;
|
|
2047
|
-
} else if (notification.type === "droid_working_state_changed" /* DROID_WORKING_STATE_CHANGED */ && notification.newState
|
|
2285
|
+
} else if (notification.type === "droid_working_state_changed" /* DROID_WORKING_STATE_CHANGED */ && DROID_RUNNING_STATES.has(notification.newState)) {
|
|
2048
2286
|
this.completedTurnObserved = false;
|
|
2287
|
+
} else if (notification.type === "permission_resolved" /* PERMISSION_RESOLVED */) {
|
|
2288
|
+
this.pendingPermissionRequests.get(notification.requestId)?.withdraw();
|
|
2049
2289
|
}
|
|
2050
2290
|
this.emit("session_notification" /* SESSION_NOTIFICATION */, validatedEvent);
|
|
2051
2291
|
} else if (validatedEvent.method === "droid.request_permission" /* REQUEST_PERMISSION */) {
|
|
2052
2292
|
await this.handlePermissionRequest(validatedEvent);
|
|
2053
2293
|
} else if (validatedEvent.method === "droid.ask_user" /* ASK_USER */) {
|
|
2054
2294
|
await this.handleAskUserRequest(validatedEvent);
|
|
2295
|
+
} else if (validatedEvent.method === "droid.pick_options" /* PICK_OPTIONS */) {
|
|
2296
|
+
await this.handlePickOptionsRequest(validatedEvent);
|
|
2297
|
+
} else if (validatedEvent.method === "droid.disconnect" /* DISCONNECT */) {
|
|
2298
|
+
this.disconnected = true;
|
|
2055
2299
|
}
|
|
2056
2300
|
} catch (error) {
|
|
2057
2301
|
this.logDroppedEventParseError(error, event);
|
|
@@ -2076,7 +2320,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2076
2320
|
const errorResponse = {
|
|
2077
2321
|
jsonrpc: JSONRPC_VERSION2,
|
|
2078
2322
|
type: "response",
|
|
2079
|
-
factoryApiVersion:
|
|
2323
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
2080
2324
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
2081
2325
|
id,
|
|
2082
2326
|
error: {
|
|
@@ -2086,7 +2330,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2086
2330
|
}
|
|
2087
2331
|
};
|
|
2088
2332
|
try {
|
|
2089
|
-
await this.
|
|
2333
|
+
await this.sendResponse(errorResponse, void 0);
|
|
2090
2334
|
} catch (sendError) {
|
|
2091
2335
|
this.logger.exception(
|
|
2092
2336
|
sendError,
|
|
@@ -2131,6 +2375,13 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2131
2375
|
});
|
|
2132
2376
|
}
|
|
2133
2377
|
}
|
|
2378
|
+
reportHandlerFailure(error, message) {
|
|
2379
|
+
if (error instanceof RequestCancelledError || isDroidConnectionEnded(error)) {
|
|
2380
|
+
this.logger.info(message, { cause: error });
|
|
2381
|
+
} else {
|
|
2382
|
+
this.logger.exception(error, message);
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2134
2385
|
async handlePermissionRequest(event) {
|
|
2135
2386
|
if (this.pendingPermissionRequests.has(event.id)) {
|
|
2136
2387
|
this.logger.info(
|
|
@@ -2145,10 +2396,14 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2145
2396
|
requestId: event.id,
|
|
2146
2397
|
count: event.params.toolUses.length
|
|
2147
2398
|
});
|
|
2399
|
+
let hostMeta;
|
|
2400
|
+
const setResponseMetadata = (meta) => {
|
|
2401
|
+
hostMeta = meta;
|
|
2402
|
+
};
|
|
2148
2403
|
this.emit("request_permission" /* REQUEST_PERMISSION */, event);
|
|
2149
|
-
let
|
|
2150
|
-
|
|
2151
|
-
|
|
2404
|
+
let result = {
|
|
2405
|
+
selectedOption: "cancel" /* Cancel */
|
|
2406
|
+
};
|
|
2152
2407
|
const handler = this.permissionHandlers.get("default");
|
|
2153
2408
|
if (handler) {
|
|
2154
2409
|
try {
|
|
@@ -2158,15 +2413,25 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2158
2413
|
requestId: event.id
|
|
2159
2414
|
}
|
|
2160
2415
|
);
|
|
2161
|
-
const handlerPromise = new Promise(
|
|
2162
|
-
(
|
|
2163
|
-
|
|
2164
|
-
|
|
2416
|
+
const handlerPromise = new Promise((resolve2, reject) => {
|
|
2417
|
+
this.pendingPermissionRequests.set(event.id, {
|
|
2418
|
+
reject,
|
|
2419
|
+
withdraw: () => {
|
|
2165
2420
|
this.pendingPermissionRequests.delete(event.id);
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2421
|
+
resolve2(PERMISSION_WITHDRAWN);
|
|
2422
|
+
}
|
|
2423
|
+
});
|
|
2424
|
+
handler(event, setResponseMetadata).then(resolve2).catch(reject).finally(() => {
|
|
2425
|
+
this.pendingPermissionRequests.delete(event.id);
|
|
2426
|
+
});
|
|
2427
|
+
});
|
|
2169
2428
|
const handlerResult = await handlerPromise;
|
|
2429
|
+
if (handlerResult === PERMISSION_WITHDRAWN) {
|
|
2430
|
+
this.logger.info("[DroidClient] Permission request withdrawn", {
|
|
2431
|
+
requestId: event.id
|
|
2432
|
+
});
|
|
2433
|
+
return;
|
|
2434
|
+
}
|
|
2170
2435
|
if (typeof handlerResult === "string" && handlerResult === "proceed_edit" /* ProceedEdit */) {
|
|
2171
2436
|
throw new DroidClientError(
|
|
2172
2437
|
"Permission handler returned proceed_edit without editedSpecContent"
|
|
@@ -2176,9 +2441,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2176
2441
|
typeof handlerResult === "string" ? { selectedOption: handlerResult } : handlerResult
|
|
2177
2442
|
);
|
|
2178
2443
|
if (parsedHandlerResult.success) {
|
|
2179
|
-
|
|
2180
|
-
comment = parsedHandlerResult.data.comment;
|
|
2181
|
-
editedSpecContent = parsedHandlerResult.data.editedSpecContent;
|
|
2444
|
+
result = parsedHandlerResult.data;
|
|
2182
2445
|
} else {
|
|
2183
2446
|
throw new DroidClientError(
|
|
2184
2447
|
"Permission handler returned invalid result",
|
|
@@ -2187,19 +2450,20 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2187
2450
|
}
|
|
2188
2451
|
);
|
|
2189
2452
|
}
|
|
2190
|
-
if (!
|
|
2191
|
-
|
|
2453
|
+
if (!isOfferedPermissionOutcome(
|
|
2454
|
+
event.params.options,
|
|
2455
|
+
result.selectedOption
|
|
2192
2456
|
)) {
|
|
2193
2457
|
throw new DroidClientError(
|
|
2194
|
-
`Permission handler selected unavailable option: ${selectedOption}`
|
|
2458
|
+
`Permission handler selected unavailable option: ${result.selectedOption}`
|
|
2195
2459
|
);
|
|
2196
2460
|
}
|
|
2197
2461
|
this.logger.info("[DroidClient] Permission handler resolved", {
|
|
2198
2462
|
requestId: event.id,
|
|
2199
|
-
result: selectedOption
|
|
2463
|
+
result: result.selectedOption
|
|
2200
2464
|
});
|
|
2201
2465
|
} catch (error) {
|
|
2202
|
-
this.
|
|
2466
|
+
this.reportHandlerFailure(
|
|
2203
2467
|
error,
|
|
2204
2468
|
"Failed to handle permission request (processing)"
|
|
2205
2469
|
);
|
|
@@ -2214,7 +2478,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2214
2478
|
const cancelResponse = {
|
|
2215
2479
|
type: "response",
|
|
2216
2480
|
jsonrpc: JSONRPC_VERSION2,
|
|
2217
|
-
factoryApiVersion:
|
|
2481
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
2218
2482
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
2219
2483
|
id: event.id,
|
|
2220
2484
|
result: {
|
|
@@ -2222,9 +2486,9 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2222
2486
|
}
|
|
2223
2487
|
};
|
|
2224
2488
|
try {
|
|
2225
|
-
await this.
|
|
2489
|
+
await this.sendResponse(cancelResponse, hostMeta);
|
|
2226
2490
|
} catch (sendError) {
|
|
2227
|
-
this.
|
|
2491
|
+
this.reportHandlerFailure(
|
|
2228
2492
|
sendError,
|
|
2229
2493
|
"Failed to handle permission request (send cancellation)"
|
|
2230
2494
|
);
|
|
@@ -2239,23 +2503,19 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2239
2503
|
return;
|
|
2240
2504
|
}
|
|
2241
2505
|
}
|
|
2242
|
-
const
|
|
2506
|
+
const response2 = {
|
|
2243
2507
|
type: "response",
|
|
2244
2508
|
jsonrpc: JSONRPC_VERSION2,
|
|
2245
|
-
factoryApiVersion:
|
|
2509
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
2246
2510
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
2247
2511
|
id: event.id,
|
|
2248
|
-
result
|
|
2249
|
-
selectedOption,
|
|
2250
|
-
...comment !== void 0 && { comment },
|
|
2251
|
-
...editedSpecContent !== void 0 && { editedSpecContent }
|
|
2252
|
-
}
|
|
2512
|
+
result
|
|
2253
2513
|
};
|
|
2254
2514
|
this.logger.info("[DroidClient] Sending permission response back to CLI", {
|
|
2255
2515
|
requestId: event.id,
|
|
2256
|
-
result: String(selectedOption)
|
|
2516
|
+
result: String(result.selectedOption)
|
|
2257
2517
|
});
|
|
2258
|
-
await this.
|
|
2518
|
+
await this.sendResponse(response2, hostMeta);
|
|
2259
2519
|
}
|
|
2260
2520
|
async handleAskUserRequest(event) {
|
|
2261
2521
|
this.logger.info("[DroidClient] Handling ask-user request", {
|
|
@@ -2264,6 +2524,21 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2264
2524
|
count: event.params.questions.length
|
|
2265
2525
|
});
|
|
2266
2526
|
this.emit("ask_user" /* ASK_USER */, event);
|
|
2527
|
+
if (event.params.blocking === false && !this.askUserHandlers.has("default")) {
|
|
2528
|
+
this.heldQueuedAskUserRequests.push(event);
|
|
2529
|
+
this.logger.info(
|
|
2530
|
+
"[DroidClient] Holding queued ask-user request until a handler is set",
|
|
2531
|
+
{ requestId: event.id }
|
|
2532
|
+
);
|
|
2533
|
+
return;
|
|
2534
|
+
}
|
|
2535
|
+
await this.answerAskUserRequest(event);
|
|
2536
|
+
}
|
|
2537
|
+
async answerAskUserRequest(event) {
|
|
2538
|
+
let hostMeta;
|
|
2539
|
+
const setResponseMetadata = (meta) => {
|
|
2540
|
+
hostMeta = meta;
|
|
2541
|
+
};
|
|
2267
2542
|
let result = { cancelled: true, answers: [] };
|
|
2268
2543
|
const handler = this.askUserHandlers.get("default");
|
|
2269
2544
|
if (handler) {
|
|
@@ -2276,7 +2551,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2276
2551
|
);
|
|
2277
2552
|
const handlerPromise = new Promise((resolve2, reject) => {
|
|
2278
2553
|
this.pendingAskUserRequests.set(event.id, { reject });
|
|
2279
|
-
handler(event).then(resolve2).catch(reject).finally(() => {
|
|
2554
|
+
handler(event, setResponseMetadata).then(resolve2).catch(reject).finally(() => {
|
|
2280
2555
|
this.pendingAskUserRequests.delete(event.id);
|
|
2281
2556
|
});
|
|
2282
2557
|
});
|
|
@@ -2298,7 +2573,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2298
2573
|
count: result.answers.length
|
|
2299
2574
|
});
|
|
2300
2575
|
} catch (error) {
|
|
2301
|
-
this.
|
|
2576
|
+
this.reportHandlerFailure(error, "Failed to handle ask-user request");
|
|
2302
2577
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
2303
2578
|
this.emit(
|
|
2304
2579
|
"session_notification" /* SESSION_NOTIFICATION */,
|
|
@@ -2307,9 +2582,19 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2307
2582
|
)
|
|
2308
2583
|
);
|
|
2309
2584
|
this.pendingAskUserRequests.delete(event.id);
|
|
2310
|
-
const cancelResponse = {
|
|
2585
|
+
const cancelResponse = event.params.blocking === false ? {
|
|
2311
2586
|
jsonrpc: JSONRPC_VERSION2,
|
|
2312
|
-
factoryApiVersion:
|
|
2587
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
2588
|
+
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
2589
|
+
type: "response",
|
|
2590
|
+
id: event.id,
|
|
2591
|
+
error: {
|
|
2592
|
+
code: -32603 /* INTERNAL_ERROR */,
|
|
2593
|
+
message: "The queued AskUser request could not be answered"
|
|
2594
|
+
}
|
|
2595
|
+
} : {
|
|
2596
|
+
jsonrpc: JSONRPC_VERSION2,
|
|
2597
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
2313
2598
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
2314
2599
|
type: "response",
|
|
2315
2600
|
id: event.id,
|
|
@@ -2319,9 +2604,9 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2319
2604
|
}
|
|
2320
2605
|
};
|
|
2321
2606
|
try {
|
|
2322
|
-
await this.
|
|
2607
|
+
await this.sendResponse(cancelResponse, hostMeta);
|
|
2323
2608
|
} catch (sendError) {
|
|
2324
|
-
this.
|
|
2609
|
+
this.reportHandlerFailure(
|
|
2325
2610
|
sendError,
|
|
2326
2611
|
"Failed to send ask-user cancellation"
|
|
2327
2612
|
);
|
|
@@ -2329,10 +2614,10 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2329
2614
|
return;
|
|
2330
2615
|
}
|
|
2331
2616
|
}
|
|
2332
|
-
const
|
|
2617
|
+
const response2 = {
|
|
2333
2618
|
type: "response",
|
|
2334
2619
|
jsonrpc: JSONRPC_VERSION2,
|
|
2335
|
-
factoryApiVersion:
|
|
2620
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
2336
2621
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
2337
2622
|
id: event.id,
|
|
2338
2623
|
result
|
|
@@ -2341,11 +2626,117 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2341
2626
|
requestId: event.id,
|
|
2342
2627
|
cancelled: result.cancelled ?? false
|
|
2343
2628
|
});
|
|
2344
|
-
await this.
|
|
2629
|
+
await this.sendResponse(response2, hostMeta);
|
|
2630
|
+
}
|
|
2631
|
+
/**
|
|
2632
|
+
* Same shape as the ask-user round trip: the handler (a UI) resolves with
|
|
2633
|
+
* the user's selection, and any failure or missing handler answers the CLI
|
|
2634
|
+
* with a cancellation so its tool call never hangs. A handler that rejects
|
|
2635
|
+
* with {@link PickOptionsUnavailableError} is relayed as that JSON-RPC
|
|
2636
|
+
* error instead, which the CLI does not read as the user's cancel.
|
|
2637
|
+
*/
|
|
2638
|
+
async handlePickOptionsRequest(event) {
|
|
2639
|
+
this.logger.info("[DroidClient] Handling pick-options request", {
|
|
2640
|
+
requestId: event.id,
|
|
2641
|
+
toolCallId: event.params.toolCallId,
|
|
2642
|
+
count: event.params.rows.length
|
|
2643
|
+
});
|
|
2644
|
+
let hostMeta;
|
|
2645
|
+
const setResponseMetadata = (meta) => {
|
|
2646
|
+
hostMeta = meta;
|
|
2647
|
+
};
|
|
2648
|
+
this.emit("pick_options" /* PICK_OPTIONS */, event);
|
|
2649
|
+
let result = { cancelled: true, selectedIds: [] };
|
|
2650
|
+
const handler = this.pickOptionsHandlers.get("default");
|
|
2651
|
+
if (handler) {
|
|
2652
|
+
try {
|
|
2653
|
+
const handlerPromise = new Promise(
|
|
2654
|
+
(resolve2, reject) => {
|
|
2655
|
+
this.pendingPickOptionsRequests.set(event.id, { reject });
|
|
2656
|
+
handler(event, setResponseMetadata).then(resolve2).catch(reject).finally(() => {
|
|
2657
|
+
this.pendingPickOptionsRequests.delete(event.id);
|
|
2658
|
+
});
|
|
2659
|
+
}
|
|
2660
|
+
);
|
|
2661
|
+
const parsedResult = PickOptionsResultSchema.safeParse(
|
|
2662
|
+
await handlerPromise
|
|
2663
|
+
);
|
|
2664
|
+
if (!parsedResult.success) {
|
|
2665
|
+
throw new DroidClientError(
|
|
2666
|
+
"PickOptions handler returned invalid result",
|
|
2667
|
+
{ cause: parsedResult.error }
|
|
2668
|
+
);
|
|
2669
|
+
}
|
|
2670
|
+
result = parsedResult.data;
|
|
2671
|
+
} catch (error) {
|
|
2672
|
+
this.pendingPickOptionsRequests.delete(event.id);
|
|
2673
|
+
if (error instanceof PickOptionsUnavailableError) {
|
|
2674
|
+
this.logger.info("[DroidClient] Pick-options request unavailable", {
|
|
2675
|
+
requestId: event.id,
|
|
2676
|
+
code: error.rpcError.code
|
|
2677
|
+
});
|
|
2678
|
+
const failure = {
|
|
2679
|
+
jsonrpc: JSONRPC_VERSION2,
|
|
2680
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
2681
|
+
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
2682
|
+
type: "response",
|
|
2683
|
+
id: event.id,
|
|
2684
|
+
error: error.rpcError
|
|
2685
|
+
};
|
|
2686
|
+
try {
|
|
2687
|
+
await this.sendResponse(failure, hostMeta);
|
|
2688
|
+
} catch (sendError) {
|
|
2689
|
+
this.reportHandlerFailure(
|
|
2690
|
+
sendError,
|
|
2691
|
+
"Failed to send pick-options failure"
|
|
2692
|
+
);
|
|
2693
|
+
}
|
|
2694
|
+
return;
|
|
2695
|
+
}
|
|
2696
|
+
this.reportHandlerFailure(
|
|
2697
|
+
error,
|
|
2698
|
+
"Failed to handle pick-options request"
|
|
2699
|
+
);
|
|
2700
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
2701
|
+
this.emit(
|
|
2702
|
+
"session_notification" /* SESSION_NOTIFICATION */,
|
|
2703
|
+
_DroidClient.createNotificationEvent(
|
|
2704
|
+
_DroidClient.createErrorNotification(err)
|
|
2705
|
+
)
|
|
2706
|
+
);
|
|
2707
|
+
const cancelResponse = {
|
|
2708
|
+
jsonrpc: JSONRPC_VERSION2,
|
|
2709
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
2710
|
+
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
2711
|
+
type: "response",
|
|
2712
|
+
id: event.id,
|
|
2713
|
+
result: { cancelled: true, selectedIds: [] }
|
|
2714
|
+
};
|
|
2715
|
+
try {
|
|
2716
|
+
await this.sendResponse(cancelResponse, hostMeta);
|
|
2717
|
+
} catch (sendError) {
|
|
2718
|
+
this.reportHandlerFailure(
|
|
2719
|
+
sendError,
|
|
2720
|
+
"Failed to send pick-options cancellation"
|
|
2721
|
+
);
|
|
2722
|
+
}
|
|
2723
|
+
return;
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
const response2 = {
|
|
2727
|
+
type: "response",
|
|
2728
|
+
jsonrpc: JSONRPC_VERSION2,
|
|
2729
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
2730
|
+
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
2731
|
+
id: event.id,
|
|
2732
|
+
result
|
|
2733
|
+
};
|
|
2734
|
+
await this.sendResponse(response2, hostMeta);
|
|
2345
2735
|
}
|
|
2346
2736
|
static getErrorType(error) {
|
|
2347
2737
|
switch (error.constructor) {
|
|
2348
2738
|
case ConnectionError:
|
|
2739
|
+
case DroidConnectionEndedError:
|
|
2349
2740
|
return "ConnectionError" /* CONNECTION_ERROR */;
|
|
2350
2741
|
case ProtocolError:
|
|
2351
2742
|
return "ProtocolError" /* PROTOCOL_ERROR */;
|
|
@@ -2395,7 +2786,7 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2395
2786
|
return {
|
|
2396
2787
|
jsonrpc: JSONRPC_VERSION2,
|
|
2397
2788
|
type: "notification",
|
|
2398
|
-
factoryApiVersion:
|
|
2789
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
2399
2790
|
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
2400
2791
|
method: "droid.session_notification" /* SESSION_NOTIFICATION */,
|
|
2401
2792
|
params: { notification }
|
|
@@ -2403,10 +2794,52 @@ var DroidClient = class _DroidClient extends EventEmitter {
|
|
|
2403
2794
|
}
|
|
2404
2795
|
};
|
|
2405
2796
|
|
|
2797
|
+
// src/exec-core/message-transport.ts
|
|
2798
|
+
var JsonRpcCodecTransport = class {
|
|
2799
|
+
transport;
|
|
2800
|
+
logger;
|
|
2801
|
+
constructor(transport, logger) {
|
|
2802
|
+
this.transport = transport;
|
|
2803
|
+
this.logger = logger;
|
|
2804
|
+
}
|
|
2805
|
+
send(message) {
|
|
2806
|
+
return this.transport.send(JSON.stringify(message));
|
|
2807
|
+
}
|
|
2808
|
+
onMessage(handler) {
|
|
2809
|
+
this.transport.onMessage((frame) => {
|
|
2810
|
+
const message = decodeDroidMessage(frame, this.logger);
|
|
2811
|
+
if (message) handler(message);
|
|
2812
|
+
});
|
|
2813
|
+
}
|
|
2814
|
+
onError(handler) {
|
|
2815
|
+
this.transport.onError(handler);
|
|
2816
|
+
}
|
|
2817
|
+
close() {
|
|
2818
|
+
return this.transport.close();
|
|
2819
|
+
}
|
|
2820
|
+
get isConnected() {
|
|
2821
|
+
return this.transport.isConnected;
|
|
2822
|
+
}
|
|
2823
|
+
};
|
|
2824
|
+
function withJsonRpcCodec(transport, deps = defaultExecCoreDeps) {
|
|
2825
|
+
const { logger } = resolveExecCoreDeps(void 0, deps);
|
|
2826
|
+
return new JsonRpcCodecTransport(transport, logger);
|
|
2827
|
+
}
|
|
2828
|
+
function decodeDroidMessage(frame, logger) {
|
|
2829
|
+
try {
|
|
2830
|
+
return JsonRpcMessageSchema.parse(JSON.parse(frame));
|
|
2831
|
+
} catch (error) {
|
|
2832
|
+
logWarn(logger, "[DroidClient] Failed to handle message", {
|
|
2833
|
+
errorName: error instanceof Error ? error.name : typeof error,
|
|
2834
|
+
messageByteLength: new TextEncoder().encode(frame).byteLength
|
|
2835
|
+
});
|
|
2836
|
+
return void 0;
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2406
2840
|
// src/exec-core/managed-process.ts
|
|
2407
2841
|
import { spawnSync } from "child_process";
|
|
2408
2842
|
import fs2 from "fs";
|
|
2409
|
-
import * as readline from "readline";
|
|
2410
2843
|
|
|
2411
2844
|
// src/exec-core/runtime-utils.ts
|
|
2412
2845
|
import { homedir } from "os";
|
|
@@ -2613,6 +3046,13 @@ function describeSpawnError(error, context) {
|
|
|
2613
3046
|
}
|
|
2614
3047
|
return `Failed to start Droid: ${error.code}`;
|
|
2615
3048
|
}
|
|
3049
|
+
function createSpawnError(error, context) {
|
|
3050
|
+
return new DroidConnectionEndedError(describeSpawnError(error, context), {
|
|
3051
|
+
error,
|
|
3052
|
+
cwd: context?.cwd,
|
|
3053
|
+
execPath: context?.execPath
|
|
3054
|
+
});
|
|
3055
|
+
}
|
|
2616
3056
|
function describeExitError(code, signal) {
|
|
2617
3057
|
if (signal) {
|
|
2618
3058
|
return `Droid process was killed (${signal})`;
|
|
@@ -2637,7 +3077,13 @@ var ManagedProcessImpl = class {
|
|
|
2637
3077
|
_childProcess;
|
|
2638
3078
|
messageHandler = null;
|
|
2639
3079
|
errorHandler = null;
|
|
2640
|
-
|
|
3080
|
+
stdoutDecoder = new LfLineDecoder();
|
|
3081
|
+
stdoutDataHandler = (chunk) => {
|
|
3082
|
+
const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
3083
|
+
for (const line of this.stdoutDecoder.push(text)) {
|
|
3084
|
+
this.handleStdoutLine(line);
|
|
3085
|
+
}
|
|
3086
|
+
};
|
|
2641
3087
|
isClosing = false;
|
|
2642
3088
|
/** Latch so exit teardown/classification runs exactly once per process. */
|
|
2643
3089
|
exitFinalized = false;
|
|
@@ -2652,50 +3098,50 @@ var ManagedProcessImpl = class {
|
|
|
2652
3098
|
logger;
|
|
2653
3099
|
get childProcess() {
|
|
2654
3100
|
if (!this._childProcess) {
|
|
2655
|
-
throw new
|
|
3101
|
+
throw new DroidConnectionEndedError("Process not connected");
|
|
2656
3102
|
}
|
|
2657
3103
|
return this._childProcess;
|
|
2658
3104
|
}
|
|
3105
|
+
/** Wait for the runtime's spawn result without replacing the transport's error handler. */
|
|
3106
|
+
waitForSpawn() {
|
|
3107
|
+
const child = this.childProcess;
|
|
3108
|
+
return new Promise((resolve2, reject) => {
|
|
3109
|
+
const onSpawn = () => {
|
|
3110
|
+
child.off("error", onError);
|
|
3111
|
+
resolve2();
|
|
3112
|
+
};
|
|
3113
|
+
const onError = () => {
|
|
3114
|
+
child.off("spawn", onSpawn);
|
|
3115
|
+
reject(this.processError);
|
|
3116
|
+
};
|
|
3117
|
+
child.once("spawn", onSpawn);
|
|
3118
|
+
child.once("error", onError);
|
|
3119
|
+
});
|
|
3120
|
+
}
|
|
2659
3121
|
setupHandlers() {
|
|
2660
3122
|
if (!this.childProcess.stdout) {
|
|
2661
|
-
throw new
|
|
3123
|
+
throw new DroidConnectionEndedError("Failed to get process stdout");
|
|
2662
3124
|
}
|
|
2663
|
-
this.
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
const trimmedLine = line.trim();
|
|
2669
|
-
if (this.messageHandler && trimmedLine) {
|
|
2670
|
-
if (trimmedLine.startsWith("{") || trimmedLine.startsWith("[")) {
|
|
2671
|
-
logTransportMessage(
|
|
2672
|
-
"in" /* In */,
|
|
2673
|
-
trimmedLine,
|
|
2674
|
-
this._childProcess?.pid,
|
|
2675
|
-
this.transportLoggerDeps
|
|
2676
|
-
);
|
|
2677
|
-
this.messageHandler(trimmedLine);
|
|
2678
|
-
} else {
|
|
2679
|
-
const truncated = trimmedLine.length > MAX_NON_JSON_LOG_LENGTH ? trimmedLine.substring(0, MAX_NON_JSON_LOG_LENGTH) : trimmedLine;
|
|
2680
|
-
this.logger.warn("[droid process] non-JSON output", {
|
|
2681
|
-
state: this.logPrefix,
|
|
2682
|
-
output: truncated
|
|
2683
|
-
});
|
|
2684
|
-
}
|
|
3125
|
+
this.childProcess.stdout.setEncoding("utf8");
|
|
3126
|
+
this.childProcess.stdout.on("data", this.stdoutDataHandler);
|
|
3127
|
+
this.childProcess.on("error", (error) => {
|
|
3128
|
+
if (this.processError || this.isClosing || this.exitFinalized) {
|
|
3129
|
+
return;
|
|
2685
3130
|
}
|
|
3131
|
+
this.processError = createSpawnError(error, this.spawnContext);
|
|
3132
|
+
this.errorHandler?.(this.processError);
|
|
2686
3133
|
});
|
|
2687
|
-
this.childProcess.on("error", (error) => {
|
|
2688
|
-
this.processError
|
|
2689
|
-
|
|
3134
|
+
this.childProcess.stdin?.on("error", (error) => {
|
|
3135
|
+
if (this.processError || this.isClosing || this.exitFinalized) {
|
|
3136
|
+
return;
|
|
3137
|
+
}
|
|
3138
|
+
this.processError = new DroidConnectionEndedError(
|
|
3139
|
+
"Process stdin failed",
|
|
2690
3140
|
{
|
|
2691
|
-
error
|
|
2692
|
-
cwd: this.spawnContext?.cwd,
|
|
2693
|
-
execPath: this.spawnContext?.execPath
|
|
3141
|
+
error
|
|
2694
3142
|
}
|
|
2695
3143
|
);
|
|
2696
|
-
|
|
2697
|
-
this.errorHandler(this.processError);
|
|
2698
|
-
}
|
|
3144
|
+
this.errorHandler?.(this.processError);
|
|
2699
3145
|
});
|
|
2700
3146
|
this.childProcess.on("exit", (code, signal) => {
|
|
2701
3147
|
this.exitDrainTimer = setTimeout(() => {
|
|
@@ -2704,6 +3150,9 @@ var ManagedProcessImpl = class {
|
|
|
2704
3150
|
this.exitDrainTimer.unref?.();
|
|
2705
3151
|
});
|
|
2706
3152
|
this.childProcess.on("close", (code, signal) => {
|
|
3153
|
+
for (const line of this.stdoutDecoder.finish()) {
|
|
3154
|
+
this.handleStdoutLine(line);
|
|
3155
|
+
}
|
|
2707
3156
|
this.finalizeExit(code, signal);
|
|
2708
3157
|
});
|
|
2709
3158
|
if (this.childProcess.stderr) {
|
|
@@ -2715,6 +3164,27 @@ var ManagedProcessImpl = class {
|
|
|
2715
3164
|
});
|
|
2716
3165
|
}
|
|
2717
3166
|
}
|
|
3167
|
+
handleStdoutLine(line) {
|
|
3168
|
+
const trimmedLine = line.trim();
|
|
3169
|
+
if (!this.messageHandler || !trimmedLine) {
|
|
3170
|
+
return;
|
|
3171
|
+
}
|
|
3172
|
+
if (trimmedLine.startsWith("{") || trimmedLine.startsWith("[")) {
|
|
3173
|
+
logTransportMessage(
|
|
3174
|
+
"in" /* In */,
|
|
3175
|
+
trimmedLine,
|
|
3176
|
+
this._childProcess?.pid,
|
|
3177
|
+
this.transportLoggerDeps
|
|
3178
|
+
);
|
|
3179
|
+
this.messageHandler(trimmedLine);
|
|
3180
|
+
return;
|
|
3181
|
+
}
|
|
3182
|
+
const truncated = trimmedLine.length > MAX_NON_JSON_LOG_LENGTH ? trimmedLine.substring(0, MAX_NON_JSON_LOG_LENGTH) : trimmedLine;
|
|
3183
|
+
this.logger.warn("[droid process] non-JSON output", {
|
|
3184
|
+
state: this.logPrefix,
|
|
3185
|
+
output: truncated
|
|
3186
|
+
});
|
|
3187
|
+
}
|
|
2718
3188
|
finalizeExit(code, signal) {
|
|
2719
3189
|
if (this.exitFinalized) {
|
|
2720
3190
|
return;
|
|
@@ -2724,12 +3194,10 @@ var ManagedProcessImpl = class {
|
|
|
2724
3194
|
clearTimeout(this.exitDrainTimer);
|
|
2725
3195
|
this.exitDrainTimer = null;
|
|
2726
3196
|
}
|
|
3197
|
+
this._childProcess?.stdout?.off("data", this.stdoutDataHandler);
|
|
2727
3198
|
this._childProcess = null;
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
this.readlineInterface = null;
|
|
2731
|
-
}
|
|
2732
|
-
if (!this.isClosing) {
|
|
3199
|
+
this.stdoutDecoder.reset();
|
|
3200
|
+
if (!this.isClosing && !this.processError) {
|
|
2733
3201
|
this.processError = new ProcessExitError(
|
|
2734
3202
|
describeExitError(code, signal),
|
|
2735
3203
|
{
|
|
@@ -2747,28 +3215,32 @@ var ManagedProcessImpl = class {
|
|
|
2747
3215
|
throw this.processError;
|
|
2748
3216
|
}
|
|
2749
3217
|
if (!this._childProcess || !this._childProcess.stdin) {
|
|
2750
|
-
throw new
|
|
3218
|
+
throw new DroidConnectionEndedError("Process not connected");
|
|
2751
3219
|
}
|
|
2752
3220
|
const previousSends = this.queuedSendPromise;
|
|
2753
3221
|
this.queuedSendPromise = (async () => {
|
|
2754
3222
|
await previousSends.catch(() => {
|
|
2755
3223
|
});
|
|
2756
3224
|
if (!this._childProcess || !this._childProcess.stdin || this._childProcess.killed || this.isClosing) {
|
|
2757
|
-
throw new
|
|
3225
|
+
throw new DroidConnectionEndedError(
|
|
3226
|
+
"Process disconnected before write"
|
|
3227
|
+
);
|
|
2758
3228
|
}
|
|
2759
3229
|
await new Promise((resolve2, reject) => {
|
|
2760
3230
|
try {
|
|
2761
3231
|
if (!this._childProcess || !this._childProcess.stdin) {
|
|
2762
|
-
reject(new
|
|
3232
|
+
reject(new DroidConnectionEndedError("Process stdin unavailable"));
|
|
2763
3233
|
return;
|
|
2764
3234
|
}
|
|
2765
3235
|
const stdin = this._childProcess.stdin;
|
|
2766
3236
|
if ("writable" in stdin && !stdin.writable) {
|
|
2767
|
-
reject(
|
|
3237
|
+
reject(
|
|
3238
|
+
new DroidConnectionEndedError("Process stdin is not writable")
|
|
3239
|
+
);
|
|
2768
3240
|
return;
|
|
2769
3241
|
}
|
|
2770
3242
|
const childPid = this._childProcess?.pid;
|
|
2771
|
-
stdin.write(`${message}
|
|
3243
|
+
stdin.write(`${escapeJsonLineSeparators(message)}
|
|
2772
3244
|
`, (error) => {
|
|
2773
3245
|
if (error) {
|
|
2774
3246
|
logTransportMessage(
|
|
@@ -2780,15 +3252,21 @@ var ManagedProcessImpl = class {
|
|
|
2780
3252
|
const errorMessage = error.message || String(error);
|
|
2781
3253
|
if (errorMessage.includes("EPIPE") || errorMessage.includes("ECONNRESET")) {
|
|
2782
3254
|
reject(
|
|
2783
|
-
new
|
|
2784
|
-
|
|
2785
|
-
|
|
3255
|
+
new DroidConnectionEndedError(
|
|
3256
|
+
"Process stdin closed during write",
|
|
3257
|
+
{
|
|
3258
|
+
error
|
|
3259
|
+
}
|
|
3260
|
+
)
|
|
2786
3261
|
);
|
|
2787
3262
|
} else {
|
|
2788
3263
|
reject(
|
|
2789
|
-
new
|
|
2790
|
-
|
|
2791
|
-
|
|
3264
|
+
new DroidConnectionEndedError(
|
|
3265
|
+
"Failed to write to process stdin",
|
|
3266
|
+
{
|
|
3267
|
+
error
|
|
3268
|
+
}
|
|
3269
|
+
)
|
|
2792
3270
|
);
|
|
2793
3271
|
}
|
|
2794
3272
|
} else {
|
|
@@ -2810,7 +3288,7 @@ var ManagedProcessImpl = class {
|
|
|
2810
3288
|
}
|
|
2811
3289
|
);
|
|
2812
3290
|
reject(
|
|
2813
|
-
new
|
|
3291
|
+
new DroidConnectionEndedError("Error writing to process stdin", {
|
|
2814
3292
|
error: error instanceof Error ? error : new Error(String(error))
|
|
2815
3293
|
})
|
|
2816
3294
|
);
|
|
@@ -2858,11 +3336,9 @@ var ManagedProcessImpl = class {
|
|
|
2858
3336
|
}
|
|
2859
3337
|
});
|
|
2860
3338
|
}
|
|
3339
|
+
processToClose.stdout?.off("data", this.stdoutDataHandler);
|
|
2861
3340
|
}
|
|
2862
|
-
|
|
2863
|
-
this.readlineInterface.close();
|
|
2864
|
-
this.readlineInterface = null;
|
|
2865
|
-
}
|
|
3341
|
+
this.stdoutDecoder.reset();
|
|
2866
3342
|
this.exitFinalized = true;
|
|
2867
3343
|
if (this.exitDrainTimer) {
|
|
2868
3344
|
clearTimeout(this.exitDrainTimer);
|
|
@@ -2969,10 +3445,8 @@ async function spawnWithWindowsJobObjectRetry(spawnFactory, options = {}) {
|
|
|
2969
3445
|
const sleep = options.sleep ?? defaultSleep;
|
|
2970
3446
|
const logPrefix = options.logPrefix ?? "[spawnWithWindowsJobObjectRetry]";
|
|
2971
3447
|
const logger = options.logger ?? noopLogger;
|
|
2972
|
-
let
|
|
2973
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
3448
|
+
for (let attempt = 0; ; attempt++) {
|
|
2974
3449
|
const child = spawnFactory();
|
|
2975
|
-
lastChild = child;
|
|
2976
3450
|
const observation = await observeEarlySpawnFailure(
|
|
2977
3451
|
child,
|
|
2978
3452
|
gracePeriodMs,
|
|
@@ -2982,8 +3456,28 @@ async function spawnWithWindowsJobObjectRetry(spawnFactory, options = {}) {
|
|
|
2982
3456
|
return child;
|
|
2983
3457
|
}
|
|
2984
3458
|
const isRetryableJobObjectFailure = observation.stderr.includes(WINDOWS_JOB_OBJECT_ERROR_MARKER) || observation.exited && observation.code !== 0 && !observation.error;
|
|
2985
|
-
|
|
2986
|
-
|
|
3459
|
+
try {
|
|
3460
|
+
await options.disposeEarlyExited?.(child);
|
|
3461
|
+
} catch (disposeErr) {
|
|
3462
|
+
logWarn(logger, "spawnWithWindowsJobObjectRetry: dispose error", {
|
|
3463
|
+
cause: disposeErr instanceof Error ? disposeErr : new Error(String(disposeErr)),
|
|
3464
|
+
name: logPrefix
|
|
3465
|
+
});
|
|
3466
|
+
}
|
|
3467
|
+
if (attempt >= maxRetries || !isRetryableJobObjectFailure) {
|
|
3468
|
+
if (observation.error) {
|
|
3469
|
+
throw createSpawnError(observation.error, options);
|
|
3470
|
+
}
|
|
3471
|
+
throw new DroidConnectionEndedError(
|
|
3472
|
+
"Droid process exited during startup",
|
|
3473
|
+
{
|
|
3474
|
+
cwd: options.cwd,
|
|
3475
|
+
execPath: options.execPath,
|
|
3476
|
+
exitCode: observation.code,
|
|
3477
|
+
signal: observation.signal,
|
|
3478
|
+
stderrTail: observation.stderr.slice(-256)
|
|
3479
|
+
}
|
|
3480
|
+
);
|
|
2987
3481
|
}
|
|
2988
3482
|
logger.warn("spawnWithWindowsJobObjectRetry: retrying on early failure", {
|
|
2989
3483
|
name: logPrefix,
|
|
@@ -2993,24 +3487,19 @@ async function spawnWithWindowsJobObjectRetry(spawnFactory, options = {}) {
|
|
|
2993
3487
|
signal: observation.signal,
|
|
2994
3488
|
stderrTail: observation.stderr.slice(-256)
|
|
2995
3489
|
});
|
|
2996
|
-
try {
|
|
2997
|
-
await options.disposeEarlyExited?.(child);
|
|
2998
|
-
} catch (disposeErr) {
|
|
2999
|
-
logWarn(logger, "spawnWithWindowsJobObjectRetry: dispose error", {
|
|
3000
|
-
cause: disposeErr instanceof Error ? disposeErr : new Error(String(disposeErr)),
|
|
3001
|
-
name: logPrefix
|
|
3002
|
-
});
|
|
3003
|
-
}
|
|
3004
3490
|
await sleep(backoff[attempt] ?? backoff[backoff.length - 1] ?? 400);
|
|
3005
3491
|
}
|
|
3006
|
-
if (lastChild) return lastChild;
|
|
3007
|
-
throw new DroidClientError(
|
|
3008
|
-
"spawnWithWindowsJobObjectRetry: exhausted retries without child",
|
|
3009
|
-
{}
|
|
3010
|
-
);
|
|
3011
3492
|
}
|
|
3012
3493
|
|
|
3013
3494
|
// src/exec-core/process-manager.ts
|
|
3495
|
+
var NATIVE_PROCESS_LIFECYCLE_MESSAGE = "[droid process] native lifecycle";
|
|
3496
|
+
var MAX_SPAWN_ERROR_CODE_LENGTH = 64;
|
|
3497
|
+
function getSpawnErrorCode(error) {
|
|
3498
|
+
if (typeof error !== "object" || error === null || !("code" in error) || typeof error.code !== "string" && typeof error.code !== "number") {
|
|
3499
|
+
return void 0;
|
|
3500
|
+
}
|
|
3501
|
+
return String(error.code).slice(0, MAX_SPAWN_ERROR_CODE_LENGTH);
|
|
3502
|
+
}
|
|
3014
3503
|
function buildArgs(config) {
|
|
3015
3504
|
const args = [];
|
|
3016
3505
|
if (config.mode === "acp" /* Acp */) {
|
|
@@ -3029,6 +3518,13 @@ function buildArgs(config) {
|
|
|
3029
3518
|
}
|
|
3030
3519
|
return args;
|
|
3031
3520
|
}
|
|
3521
|
+
function ensureIpcStdio(stdio) {
|
|
3522
|
+
if (Array.isArray(stdio)) {
|
|
3523
|
+
return stdio.includes("ipc") ? stdio : [...stdio, "ipc"];
|
|
3524
|
+
}
|
|
3525
|
+
const standardChannel = stdio ?? "pipe";
|
|
3526
|
+
return [standardChannel, standardChannel, standardChannel, "ipc"];
|
|
3527
|
+
}
|
|
3032
3528
|
var DroidProcessManager = class {
|
|
3033
3529
|
deps;
|
|
3034
3530
|
transportLoggerDeps;
|
|
@@ -3080,6 +3576,8 @@ var DroidProcessManager = class {
|
|
|
3080
3576
|
() => this.invokeNodeSpawn(planned),
|
|
3081
3577
|
{
|
|
3082
3578
|
...retryOptions,
|
|
3579
|
+
cwd: planned.expandedCwd,
|
|
3580
|
+
execPath: planned.execPath,
|
|
3083
3581
|
logPrefix: "[DroidProcessManager]",
|
|
3084
3582
|
logger: this.logger,
|
|
3085
3583
|
disposeEarlyExited: (child) => {
|
|
@@ -3109,7 +3607,8 @@ var DroidProcessManager = class {
|
|
|
3109
3607
|
}
|
|
3110
3608
|
);
|
|
3111
3609
|
if (!childProcess.stdout || !childProcess.stdin) {
|
|
3112
|
-
|
|
3610
|
+
childProcess.kill();
|
|
3611
|
+
throw new DroidConnectionEndedError("Failed to get process stdio");
|
|
3113
3612
|
}
|
|
3114
3613
|
return new ManagedProcessImpl(
|
|
3115
3614
|
childProcess,
|
|
@@ -3155,21 +3654,88 @@ var DroidProcessManager = class {
|
|
|
3155
3654
|
};
|
|
3156
3655
|
}
|
|
3157
3656
|
invokeNodeSpawn(planned) {
|
|
3657
|
+
const stdio = planned.enableIpc ? ensureIpcStdio(planned.stdio) : planned.stdio ?? ["pipe", "pipe", "pipe"];
|
|
3158
3658
|
const options = {
|
|
3159
3659
|
cwd: planned.expandedCwd,
|
|
3160
3660
|
env: planned.env,
|
|
3161
|
-
stdio
|
|
3661
|
+
stdio
|
|
3162
3662
|
};
|
|
3163
3663
|
if (planned.enableIpc) {
|
|
3164
3664
|
options.serialization = "json";
|
|
3165
3665
|
}
|
|
3166
|
-
|
|
3666
|
+
const spawnedAt = Date.now();
|
|
3667
|
+
let childProcess;
|
|
3668
|
+
try {
|
|
3669
|
+
childProcess = spawn(planned.execPath, planned.args, options);
|
|
3670
|
+
} catch (error) {
|
|
3671
|
+
const failedAt = Date.now();
|
|
3672
|
+
this.logNativeProcessLifecycle({
|
|
3673
|
+
state: "spawn_error",
|
|
3674
|
+
pid: null,
|
|
3675
|
+
createdAt: spawnedAt,
|
|
3676
|
+
eventDate: new Date(failedAt).toISOString(),
|
|
3677
|
+
durationMs: failedAt - spawnedAt,
|
|
3678
|
+
errnoCode: getSpawnErrorCode(error)
|
|
3679
|
+
});
|
|
3680
|
+
throw error;
|
|
3681
|
+
}
|
|
3682
|
+
const pid = childProcess.pid;
|
|
3683
|
+
if (pid === void 0) {
|
|
3684
|
+
childProcess.once("error", (error) => {
|
|
3685
|
+
const failedAt = Date.now();
|
|
3686
|
+
this.logNativeProcessLifecycle({
|
|
3687
|
+
state: "spawn_error",
|
|
3688
|
+
pid: null,
|
|
3689
|
+
createdAt: spawnedAt,
|
|
3690
|
+
eventDate: new Date(failedAt).toISOString(),
|
|
3691
|
+
durationMs: failedAt - spawnedAt,
|
|
3692
|
+
errnoCode: getSpawnErrorCode(error)
|
|
3693
|
+
});
|
|
3694
|
+
});
|
|
3695
|
+
} else {
|
|
3696
|
+
childProcess.once("exit", (exitCode, signal) => {
|
|
3697
|
+
const exitedAt = Date.now();
|
|
3698
|
+
this.logNativeProcessLifecycle({
|
|
3699
|
+
state: "exited",
|
|
3700
|
+
pid,
|
|
3701
|
+
createdAt: spawnedAt,
|
|
3702
|
+
eventDate: new Date(exitedAt).toISOString(),
|
|
3703
|
+
durationMs: exitedAt - spawnedAt,
|
|
3704
|
+
exitCode,
|
|
3705
|
+
signal
|
|
3706
|
+
});
|
|
3707
|
+
});
|
|
3708
|
+
this.logNativeProcessLifecycle({
|
|
3709
|
+
state: "spawned",
|
|
3710
|
+
pid,
|
|
3711
|
+
createdAt: spawnedAt,
|
|
3712
|
+
eventDate: new Date(spawnedAt).toISOString()
|
|
3713
|
+
});
|
|
3714
|
+
}
|
|
3715
|
+
return childProcess;
|
|
3716
|
+
}
|
|
3717
|
+
/**
|
|
3718
|
+
* Emits the content-free native process record consumed by lifecycle
|
|
3719
|
+
* measurement harnesses. `createdAt` is the wall-clock lower bound captured
|
|
3720
|
+
* immediately before spawn; `eventDate` is the wall-clock observation time.
|
|
3721
|
+
*/
|
|
3722
|
+
logNativeProcessLifecycle(record) {
|
|
3723
|
+
try {
|
|
3724
|
+
this.logger.info(NATIVE_PROCESS_LIFECYCLE_MESSAGE, record);
|
|
3725
|
+
} catch (loggingError) {
|
|
3726
|
+
void loggingError;
|
|
3727
|
+
logWarn(
|
|
3728
|
+
defaultExecCoreDeps.logger,
|
|
3729
|
+
"[droid process] native lifecycle logger failed"
|
|
3730
|
+
);
|
|
3731
|
+
}
|
|
3167
3732
|
}
|
|
3168
3733
|
spawnChildProcess(config) {
|
|
3169
3734
|
const planned = this.prepareSpawn(config);
|
|
3170
3735
|
const childProcess = this.invokeNodeSpawn(planned);
|
|
3171
3736
|
if (!childProcess.stdout || !childProcess.stdin) {
|
|
3172
|
-
|
|
3737
|
+
childProcess.kill();
|
|
3738
|
+
throw new DroidConnectionEndedError("Failed to get process stdio");
|
|
3173
3739
|
}
|
|
3174
3740
|
return {
|
|
3175
3741
|
logPrefix: planned.logPrefix,
|
|
@@ -3187,12 +3753,20 @@ var ProcessTransport = class {
|
|
|
3187
3753
|
options;
|
|
3188
3754
|
// Store handlers that may be registered before connect() is called
|
|
3189
3755
|
messageHandler = null;
|
|
3756
|
+
logger;
|
|
3757
|
+
handleMessage = (frame) => {
|
|
3758
|
+
const message = decodeDroidMessage(frame, this.logger);
|
|
3759
|
+
if (message) this.messageHandler?.(message);
|
|
3760
|
+
};
|
|
3190
3761
|
errorHandler = null;
|
|
3191
3762
|
metrics;
|
|
3763
|
+
environmentResolver;
|
|
3192
3764
|
constructor(options = {}, deps = defaultExecCoreDeps) {
|
|
3193
3765
|
this.options = options;
|
|
3194
3766
|
const resolved = resolveExecCoreDeps(options.observability, deps);
|
|
3767
|
+
this.logger = resolved.logger;
|
|
3195
3768
|
this.metrics = resolved.metrics;
|
|
3769
|
+
this.environmentResolver = resolved.environmentResolver;
|
|
3196
3770
|
this.processManager = new DroidProcessManager(
|
|
3197
3771
|
{
|
|
3198
3772
|
observability: options.observability
|
|
@@ -3202,7 +3776,7 @@ var ProcessTransport = class {
|
|
|
3202
3776
|
}
|
|
3203
3777
|
async connect() {
|
|
3204
3778
|
if (this.managedProcess && this.managedProcess.isConnected) {
|
|
3205
|
-
throw new
|
|
3779
|
+
throw new DroidClientError("Transport already connected");
|
|
3206
3780
|
}
|
|
3207
3781
|
const config = {
|
|
3208
3782
|
execPath: this.options.droidExecPath,
|
|
@@ -3210,14 +3784,36 @@ var ProcessTransport = class {
|
|
|
3210
3784
|
mode: "stream-jsonrpc" /* StreamJsonRpc */,
|
|
3211
3785
|
cwd: this.options.cwd,
|
|
3212
3786
|
env: this.options.env,
|
|
3787
|
+
trustedEnv: {
|
|
3788
|
+
...this.options.runtimeSettingsAuthority ? this.environmentResolver.buildRuntimeSettingsAuthorityEnv(
|
|
3789
|
+
this.options.runtimeSettingsAuthority
|
|
3790
|
+
) : {},
|
|
3791
|
+
...this.options.trustedEnv
|
|
3792
|
+
},
|
|
3213
3793
|
extraArgs: this.options.droidExecExtraArgs,
|
|
3214
|
-
enableIpc: this.options.enableIpc
|
|
3794
|
+
enableIpc: this.options.enableIpc,
|
|
3795
|
+
stdio: this.options.stdio
|
|
3215
3796
|
};
|
|
3216
3797
|
const spawnStart = performance.now();
|
|
3217
3798
|
let spawnOutcome = "error";
|
|
3799
|
+
let managedProcess;
|
|
3218
3800
|
try {
|
|
3219
|
-
|
|
3801
|
+
if (process.platform === "win32") {
|
|
3802
|
+
managedProcess = await this.processManager.spawnWithWindowsRetry(config);
|
|
3803
|
+
} else {
|
|
3804
|
+
const spawned = this.processManager.spawn(config);
|
|
3805
|
+
managedProcess = spawned;
|
|
3806
|
+
if (spawned.childProcess.pid === void 0) {
|
|
3807
|
+
await spawned.waitForSpawn();
|
|
3808
|
+
}
|
|
3809
|
+
}
|
|
3220
3810
|
spawnOutcome = "success";
|
|
3811
|
+
} catch (error) {
|
|
3812
|
+
await managedProcess?.close();
|
|
3813
|
+
if (error instanceof DroidConnectionEndedError) {
|
|
3814
|
+
this.errorHandler?.(error);
|
|
3815
|
+
}
|
|
3816
|
+
throw error;
|
|
3221
3817
|
} finally {
|
|
3222
3818
|
this.metrics.recordDuration(
|
|
3223
3819
|
CLI_JSONRPC_CHILD_SPAWN_LATENCY_METRIC,
|
|
@@ -3225,8 +3821,15 @@ var ProcessTransport = class {
|
|
|
3225
3821
|
{ outcome: spawnOutcome, source: "process_transport" }
|
|
3226
3822
|
);
|
|
3227
3823
|
}
|
|
3824
|
+
try {
|
|
3825
|
+
this.options.onSpawned?.(managedProcess.childProcess);
|
|
3826
|
+
} catch (error) {
|
|
3827
|
+
await managedProcess.close();
|
|
3828
|
+
throw error;
|
|
3829
|
+
}
|
|
3830
|
+
this.managedProcess = managedProcess;
|
|
3228
3831
|
if (this.messageHandler) {
|
|
3229
|
-
this.managedProcess.onMessage(this.
|
|
3832
|
+
this.managedProcess.onMessage(this.handleMessage);
|
|
3230
3833
|
}
|
|
3231
3834
|
if (this.errorHandler) {
|
|
3232
3835
|
this.managedProcess.onError(this.errorHandler);
|
|
@@ -3234,14 +3837,14 @@ var ProcessTransport = class {
|
|
|
3234
3837
|
}
|
|
3235
3838
|
async send(message) {
|
|
3236
3839
|
if (!this.managedProcess) {
|
|
3237
|
-
throw new
|
|
3840
|
+
throw new DroidConnectionEndedError("Transport not connected");
|
|
3238
3841
|
}
|
|
3239
|
-
return this.managedProcess.send(message);
|
|
3842
|
+
return await this.managedProcess.send(JSON.stringify(message));
|
|
3240
3843
|
}
|
|
3241
3844
|
onMessage(handler) {
|
|
3242
3845
|
this.messageHandler = handler;
|
|
3243
3846
|
if (this.managedProcess) {
|
|
3244
|
-
this.managedProcess.onMessage(
|
|
3847
|
+
this.managedProcess.onMessage(this.handleMessage);
|
|
3245
3848
|
}
|
|
3246
3849
|
}
|
|
3247
3850
|
onError(handler) {
|
|
@@ -3264,6 +3867,180 @@ var ProcessTransport = class {
|
|
|
3264
3867
|
}
|
|
3265
3868
|
};
|
|
3266
3869
|
|
|
3870
|
+
// src/environment-session.ts
|
|
3871
|
+
import { v4 as uuidv43 } from "uuid";
|
|
3872
|
+
|
|
3873
|
+
// src/environment-launch/index.ts
|
|
3874
|
+
import { v4 as uuidv42 } from "uuid";
|
|
3875
|
+
|
|
3876
|
+
// src/environment-launch/errors.ts
|
|
3877
|
+
var EnvironmentLaunchError = class extends Error {
|
|
3878
|
+
computerId;
|
|
3879
|
+
computerName;
|
|
3880
|
+
cleanupError;
|
|
3881
|
+
constructor(options) {
|
|
3882
|
+
super(
|
|
3883
|
+
options.cause instanceof Error ? options.cause.message : "Environment session startup failed",
|
|
3884
|
+
{ cause: options.cause }
|
|
3885
|
+
);
|
|
3886
|
+
this.name = "EnvironmentLaunchError";
|
|
3887
|
+
this.computerId = options.computerId;
|
|
3888
|
+
this.computerName = options.computerName;
|
|
3889
|
+
this.cleanupError = options.cleanupError;
|
|
3890
|
+
}
|
|
3891
|
+
};
|
|
3892
|
+
|
|
3893
|
+
// src/environment-launch/index.ts
|
|
3894
|
+
async function launchEnvironmentSession(options) {
|
|
3895
|
+
const timeoutMs = options.timeoutMs ?? 18e4;
|
|
3896
|
+
const pollIntervalMs = options.pollIntervalMs ?? 1e3;
|
|
3897
|
+
const controller = new AbortController();
|
|
3898
|
+
const cancel = () => controller.abort(options.signal?.reason);
|
|
3899
|
+
if (options.signal?.aborted) cancel();
|
|
3900
|
+
else options.signal?.addEventListener("abort", cancel, { once: true });
|
|
3901
|
+
const timer = setTimeout(
|
|
3902
|
+
() => controller.abort(new EnvironmentComputerTimeoutError()),
|
|
3903
|
+
timeoutMs
|
|
3904
|
+
);
|
|
3905
|
+
const signal = controller.signal;
|
|
3906
|
+
let createdComputerId;
|
|
3907
|
+
let computerName;
|
|
3908
|
+
function launchError(cause, cleanupError) {
|
|
3909
|
+
return new EnvironmentLaunchError({
|
|
3910
|
+
cause,
|
|
3911
|
+
computerId: createdComputerId,
|
|
3912
|
+
computerName,
|
|
3913
|
+
cleanupError
|
|
3914
|
+
});
|
|
3915
|
+
}
|
|
3916
|
+
try {
|
|
3917
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || !Number.isFinite(pollIntervalMs) || pollIntervalMs <= 0)
|
|
3918
|
+
throw new Error("Invalid environment launch configuration");
|
|
3919
|
+
const selection = await runWithAbort(
|
|
3920
|
+
signal,
|
|
3921
|
+
async () => await resolveEnvironment({ ...options, signal })
|
|
3922
|
+
);
|
|
3923
|
+
computerName = `environment-${uuidv42()}`;
|
|
3924
|
+
signal.throwIfAborted();
|
|
3925
|
+
const createPromise = createOrRecoverComputer({
|
|
3926
|
+
name: computerName,
|
|
3927
|
+
environmentId: selection.environment.id,
|
|
3928
|
+
keepWhenIdle: options.keepWhenIdle,
|
|
3929
|
+
request: options.request,
|
|
3930
|
+
serviceAccountId: options.serviceAccountId,
|
|
3931
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
3932
|
+
});
|
|
3933
|
+
const allocated = await runWithAbort(signal, async () => await createPromise).catch(
|
|
3934
|
+
(cause) => {
|
|
3935
|
+
if (signal.aborted && createdComputerId === void 0)
|
|
3936
|
+
void createPromise.then(
|
|
3937
|
+
(computer2) => createFactoryApi(options.request).deleteComputer({
|
|
3938
|
+
computerId: computer2.id,
|
|
3939
|
+
signal: AbortSignal.timeout(Math.min(timeoutMs, 5e3))
|
|
3940
|
+
})
|
|
3941
|
+
).catch(() => {
|
|
3942
|
+
});
|
|
3943
|
+
throw cause;
|
|
3944
|
+
}
|
|
3945
|
+
);
|
|
3946
|
+
createdComputerId = allocated.id;
|
|
3947
|
+
await runWithAbort(signal, async () => await options.onComputer?.(allocated));
|
|
3948
|
+
const computer = await waitForEnvironmentComputer({
|
|
3949
|
+
computer: allocated,
|
|
3950
|
+
timeoutMs,
|
|
3951
|
+
pollIntervalMs,
|
|
3952
|
+
now: options.now,
|
|
3953
|
+
sleep: options.sleep,
|
|
3954
|
+
signal,
|
|
3955
|
+
isReady: isEnvironmentComputerReady,
|
|
3956
|
+
onComputer: options.onComputer,
|
|
3957
|
+
request: options.request,
|
|
3958
|
+
serviceAccountId: options.serviceAccountId
|
|
3959
|
+
});
|
|
3960
|
+
const connection = await runWithAbort(
|
|
3961
|
+
signal,
|
|
3962
|
+
async () => await options.connect({ computer, signal })
|
|
3963
|
+
);
|
|
3964
|
+
const session = await runWithAbort(
|
|
3965
|
+
signal,
|
|
3966
|
+
async () => await options.startSession({ connection, computer, selection, signal })
|
|
3967
|
+
);
|
|
3968
|
+
return { session, computer, selection };
|
|
3969
|
+
} catch (cause) {
|
|
3970
|
+
if (createdComputerId !== void 0) {
|
|
3971
|
+
const cleanup = new AbortController();
|
|
3972
|
+
const cleanupTimer = setTimeout(
|
|
3973
|
+
() => cleanup.abort(new EnvironmentComputerTimeoutError()),
|
|
3974
|
+
Math.min(timeoutMs, 5e3)
|
|
3975
|
+
);
|
|
3976
|
+
try {
|
|
3977
|
+
const computerId = createdComputerId;
|
|
3978
|
+
await runWithAbort(
|
|
3979
|
+
cleanup.signal,
|
|
3980
|
+
async () => await createFactoryApi(options.request).deleteComputer({
|
|
3981
|
+
computerId,
|
|
3982
|
+
signal: cleanup.signal
|
|
3983
|
+
})
|
|
3984
|
+
);
|
|
3985
|
+
} catch (failure) {
|
|
3986
|
+
throw launchError(cause, failure);
|
|
3987
|
+
} finally {
|
|
3988
|
+
clearTimeout(cleanupTimer);
|
|
3989
|
+
}
|
|
3990
|
+
}
|
|
3991
|
+
throw launchError(cause);
|
|
3992
|
+
} finally {
|
|
3993
|
+
clearTimeout(timer);
|
|
3994
|
+
options.signal?.removeEventListener("abort", cancel);
|
|
3995
|
+
}
|
|
3996
|
+
}
|
|
3997
|
+
async function resolveEnvironment(options) {
|
|
3998
|
+
const http2 = createFactoryApi(options.request);
|
|
3999
|
+
const selector = options.environment;
|
|
4000
|
+
if ("id" in selector ? !selector.id.trim() : !selector.name.trim())
|
|
4001
|
+
throw new Error("Invalid environment selector");
|
|
4002
|
+
const context = {
|
|
4003
|
+
serviceAccountId: options.serviceAccountId,
|
|
4004
|
+
signal: options.signal
|
|
4005
|
+
};
|
|
4006
|
+
let environment;
|
|
4007
|
+
if ("id" in selector && context.serviceAccountId === void 0) {
|
|
4008
|
+
environment = SandboxEnvironmentSchema.parse(
|
|
4009
|
+
await http2.getEnvironment({
|
|
4010
|
+
...context,
|
|
4011
|
+
environmentId: selector.id
|
|
4012
|
+
})
|
|
4013
|
+
);
|
|
4014
|
+
if (environment.id !== selector.id)
|
|
4015
|
+
throw new Error("Environment lookup returned a different ID");
|
|
4016
|
+
} else {
|
|
4017
|
+
const matches = [];
|
|
4018
|
+
options.signal?.throwIfAborted();
|
|
4019
|
+
const page = await http2.listEnvironments(context);
|
|
4020
|
+
if (!page || typeof page !== "object" || !("environments" in page) || !Array.isArray(page.environments))
|
|
4021
|
+
throw new Error("Invalid environment list response");
|
|
4022
|
+
for (const item of page.environments) {
|
|
4023
|
+
const candidate = SandboxEnvironmentSchema.parse(item);
|
|
4024
|
+
if ("id" in selector ? candidate.id === selector.id : candidate.name === selector.name)
|
|
4025
|
+
matches.push(candidate);
|
|
4026
|
+
}
|
|
4027
|
+
if (matches.length !== 1)
|
|
4028
|
+
throw new Error(
|
|
4029
|
+
"id" in selector ? "Environment is not accessible" : "Environment name must match exactly one accessible environment"
|
|
4030
|
+
);
|
|
4031
|
+
environment = matches[0];
|
|
4032
|
+
}
|
|
4033
|
+
if (!environment) throw new Error("Environment is not accessible");
|
|
4034
|
+
if (!isSandboxEnvironmentLaunchable(environment)) {
|
|
4035
|
+
throw new Error("Environment is not ready to launch");
|
|
4036
|
+
}
|
|
4037
|
+
return {
|
|
4038
|
+
environment,
|
|
4039
|
+
source: getSandboxEnvironmentLaunchSource(environment),
|
|
4040
|
+
repositories: getSandboxEnvironmentLaunchRepositories(environment)
|
|
4041
|
+
};
|
|
4042
|
+
}
|
|
4043
|
+
|
|
3267
4044
|
// src/helpers.ts
|
|
3268
4045
|
function resolveApiKey(apiKey) {
|
|
3269
4046
|
const resolved = apiKey ?? process.env.FACTORY_API_KEY;
|
|
@@ -3286,7 +4063,10 @@ async function createTransport(options) {
|
|
|
3286
4063
|
...options.env,
|
|
3287
4064
|
FACTORY_API_KEY: resolveApiKey(options.apiKey),
|
|
3288
4065
|
FACTORY_UPSTREAM_CLIENT_TYPE: "sdk" /* SDK */,
|
|
3289
|
-
FACTORY_UPSTREAM_SDK: SDK_IDENTITY
|
|
4066
|
+
FACTORY_UPSTREAM_SDK: SDK_IDENTITY,
|
|
4067
|
+
// This helper owns the original SDK process, unlike the generic
|
|
4068
|
+
// ProcessTransport also used by daemon workers.
|
|
4069
|
+
FACTORY_EXEC_ORIGINAL_INVOCATION: "1"
|
|
3290
4070
|
},
|
|
3291
4071
|
observability: options.observability
|
|
3292
4072
|
});
|
|
@@ -3294,13 +4074,26 @@ async function createTransport(options) {
|
|
|
3294
4074
|
return processTransport;
|
|
3295
4075
|
}
|
|
3296
4076
|
function setupClientHandlers(client, options) {
|
|
4077
|
+
const sessionId = () => {
|
|
4078
|
+
const addressed = client.addressedSessionId;
|
|
4079
|
+
if (!addressed) {
|
|
4080
|
+
throw new DroidClientError(
|
|
4081
|
+
"Received a prompt that no single session owns"
|
|
4082
|
+
);
|
|
4083
|
+
}
|
|
4084
|
+
return addressed;
|
|
4085
|
+
};
|
|
3297
4086
|
if (options.permissionHandler) {
|
|
3298
4087
|
const handler = options.permissionHandler;
|
|
3299
|
-
client.setPermissionHandler(
|
|
4088
|
+
client.setPermissionHandler(
|
|
4089
|
+
(event) => handler({ ...event.params, sessionId: sessionId() })
|
|
4090
|
+
);
|
|
3300
4091
|
}
|
|
3301
4092
|
if (options.askUserHandler) {
|
|
3302
4093
|
const handler = options.askUserHandler;
|
|
3303
|
-
client.setAskUserHandler(
|
|
4094
|
+
client.setAskUserHandler(
|
|
4095
|
+
(event) => handler({ ...event.params, sessionId: sessionId() })
|
|
4096
|
+
);
|
|
3304
4097
|
}
|
|
3305
4098
|
}
|
|
3306
4099
|
async function createConfiguredClient(options) {
|
|
@@ -3372,15 +4165,21 @@ import http from "http";
|
|
|
3372
4165
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3373
4166
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
3374
4167
|
import { z as z2 } from "zod";
|
|
3375
|
-
function tool(name, description, inputSchemaOrHandler,
|
|
4168
|
+
function tool(name, description, inputSchemaOrHandler, handlerOrOptions, maybeOptions) {
|
|
4169
|
+
const options = typeof handlerOrOptions === "function" ? maybeOptions : handlerOrOptions;
|
|
4170
|
+
const annotationFields = options?.annotations && {
|
|
4171
|
+
annotations: options.annotations
|
|
4172
|
+
};
|
|
3376
4173
|
if (typeof inputSchemaOrHandler === "function") {
|
|
3377
4174
|
const actualHandler = inputSchemaOrHandler;
|
|
3378
4175
|
return {
|
|
3379
4176
|
name,
|
|
3380
4177
|
description,
|
|
3381
|
-
handler: (input) => actualHandler(input)
|
|
4178
|
+
handler: (input) => actualHandler(input),
|
|
4179
|
+
...annotationFields
|
|
3382
4180
|
};
|
|
3383
4181
|
}
|
|
4182
|
+
const handler = typeof handlerOrOptions === "function" ? handlerOrOptions : void 0;
|
|
3384
4183
|
if (!handler) {
|
|
3385
4184
|
throw new Error(`Missing handler for SDK MCP tool "${name}"`);
|
|
3386
4185
|
}
|
|
@@ -3389,7 +4188,8 @@ function tool(name, description, inputSchemaOrHandler, handler) {
|
|
|
3389
4188
|
name,
|
|
3390
4189
|
description,
|
|
3391
4190
|
inputSchema: inputSchemaOrHandler,
|
|
3392
|
-
handler: (input) => handler(inputObjectSchema.parse(input))
|
|
4191
|
+
handler: (input) => handler(inputObjectSchema.parse(input)),
|
|
4192
|
+
...annotationFields
|
|
3393
4193
|
};
|
|
3394
4194
|
}
|
|
3395
4195
|
function isSdkMcpServer(server) {
|
|
@@ -3515,7 +4315,8 @@ var SdkMcpServer = class {
|
|
|
3515
4315
|
description: sdkTool.description,
|
|
3516
4316
|
...sdkTool.inputSchema && {
|
|
3517
4317
|
inputSchema: sdkTool.inputSchema
|
|
3518
|
-
}
|
|
4318
|
+
},
|
|
4319
|
+
...sdkTool.annotations && { annotations: sdkTool.annotations }
|
|
3519
4320
|
},
|
|
3520
4321
|
async (input) => toCallToolResult(await sdkTool.handler(input))
|
|
3521
4322
|
);
|
|
@@ -3592,6 +4393,313 @@ async function startSdkMcpServers(servers) {
|
|
|
3592
4393
|
};
|
|
3593
4394
|
}
|
|
3594
4395
|
|
|
4396
|
+
// src/session-operations.ts
|
|
4397
|
+
function response(result) {
|
|
4398
|
+
return {
|
|
4399
|
+
type: "response",
|
|
4400
|
+
jsonrpc: JSONRPC_VERSION2,
|
|
4401
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
4402
|
+
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
4403
|
+
id: "sdk-adapter",
|
|
4404
|
+
result
|
|
4405
|
+
};
|
|
4406
|
+
}
|
|
4407
|
+
function createDaemonSessionOperations(controller, initialSessionId, handlers) {
|
|
4408
|
+
let sessionId = initialSessionId;
|
|
4409
|
+
const ownedSessionIds = /* @__PURE__ */ new Set([initialSessionId]);
|
|
4410
|
+
const reportError = (error) => controller.emit("error", toError(error));
|
|
4411
|
+
const permission = async (request) => {
|
|
4412
|
+
if (request.sessionId !== sessionId && !request.associatedSessionIds.includes(sessionId))
|
|
4413
|
+
return;
|
|
4414
|
+
const selected = await resolvePermissionHandler(
|
|
4415
|
+
handlers.permissionHandler,
|
|
4416
|
+
request,
|
|
4417
|
+
reportError
|
|
4418
|
+
) ?? {
|
|
4419
|
+
selectedOption: "cancel" /* Cancel */
|
|
4420
|
+
};
|
|
4421
|
+
try {
|
|
4422
|
+
await controller.respondToPermission({
|
|
4423
|
+
permissionId: request.requestId,
|
|
4424
|
+
sessionId,
|
|
4425
|
+
...selected
|
|
4426
|
+
});
|
|
4427
|
+
} catch (error) {
|
|
4428
|
+
reportError(error);
|
|
4429
|
+
}
|
|
4430
|
+
};
|
|
4431
|
+
const askUser = async (request) => {
|
|
4432
|
+
if (request.sessionId !== sessionId) return;
|
|
4433
|
+
const result = await resolveAskUserHandler(
|
|
4434
|
+
handlers.askUserHandler,
|
|
4435
|
+
request,
|
|
4436
|
+
reportError
|
|
4437
|
+
);
|
|
4438
|
+
if (!result && request.blocking === false) return;
|
|
4439
|
+
try {
|
|
4440
|
+
await controller.respondToAskUser({
|
|
4441
|
+
requestId: request.requestId,
|
|
4442
|
+
sessionId,
|
|
4443
|
+
result: result ?? { cancelled: true, answers: [] }
|
|
4444
|
+
});
|
|
4445
|
+
} catch (error) {
|
|
4446
|
+
reportError(error);
|
|
4447
|
+
}
|
|
4448
|
+
};
|
|
4449
|
+
controller.on("permissionRequested" /* PermissionRequested */, permission);
|
|
4450
|
+
controller.on("askUserRequested" /* AskUserRequested */, askUser);
|
|
4451
|
+
const operations = {
|
|
4452
|
+
lifecycle: {
|
|
4453
|
+
shutdown: async () => {
|
|
4454
|
+
try {
|
|
4455
|
+
const results = await Promise.allSettled(
|
|
4456
|
+
[...ownedSessionIds].map((id) => controller.closeSession(id))
|
|
4457
|
+
);
|
|
4458
|
+
const failure = results.find(
|
|
4459
|
+
(result) => result.status === "rejected"
|
|
4460
|
+
);
|
|
4461
|
+
if (failure?.status === "rejected") throw toError(failure.reason);
|
|
4462
|
+
} finally {
|
|
4463
|
+
await operations.close();
|
|
4464
|
+
}
|
|
4465
|
+
},
|
|
4466
|
+
abort: (close) => {
|
|
4467
|
+
void close().catch(() => {
|
|
4468
|
+
});
|
|
4469
|
+
}
|
|
4470
|
+
},
|
|
4471
|
+
onNotification(callback, filter) {
|
|
4472
|
+
const listener = (event) => {
|
|
4473
|
+
if (event.sessionId !== sessionId || filter?.type !== void 0 && filter.type !== event.notification.type)
|
|
4474
|
+
return;
|
|
4475
|
+
try {
|
|
4476
|
+
callback({
|
|
4477
|
+
type: "notification",
|
|
4478
|
+
jsonrpc: JSONRPC_VERSION2,
|
|
4479
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION2,
|
|
4480
|
+
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
4481
|
+
method: "droid.session_notification" /* SESSION_NOTIFICATION */,
|
|
4482
|
+
params: { notification: event.notification }
|
|
4483
|
+
});
|
|
4484
|
+
} catch {
|
|
4485
|
+
}
|
|
4486
|
+
};
|
|
4487
|
+
controller.on("sessionNotification" /* SessionNotification */, listener);
|
|
4488
|
+
return () => controller.off("sessionNotification" /* SessionNotification */, listener);
|
|
4489
|
+
},
|
|
4490
|
+
onError(callback) {
|
|
4491
|
+
const disconnected = (code, reason) => callback(new ConnectionClosedError(code, reason));
|
|
4492
|
+
const exited = (event) => {
|
|
4493
|
+
if (event.sessionId === sessionId && event.notification.type === "session_process_exited" /* SESSION_PROCESS_EXITED */)
|
|
4494
|
+
callback(
|
|
4495
|
+
new DroidConnectionEndedError("Remote session process exited.")
|
|
4496
|
+
);
|
|
4497
|
+
};
|
|
4498
|
+
controller.on("error", callback);
|
|
4499
|
+
controller.on("disconnected" /* Disconnected */, disconnected);
|
|
4500
|
+
controller.on("sessionNotification" /* SessionNotification */, exited);
|
|
4501
|
+
return () => {
|
|
4502
|
+
controller.off("error", callback);
|
|
4503
|
+
controller.off("disconnected" /* Disconnected */, disconnected);
|
|
4504
|
+
controller.off("sessionNotification" /* SessionNotification */, exited);
|
|
4505
|
+
};
|
|
4506
|
+
},
|
|
4507
|
+
addUserMessage: async (params) => response(await controller.addUserMessage(sessionId, params)),
|
|
4508
|
+
interruptSession: async () => response(await controller.interruptSession(sessionId)),
|
|
4509
|
+
closeSession: async () => {
|
|
4510
|
+
await controller.closeSession(sessionId);
|
|
4511
|
+
return response({});
|
|
4512
|
+
},
|
|
4513
|
+
close: async () => {
|
|
4514
|
+
controller.off("permissionRequested" /* PermissionRequested */, permission);
|
|
4515
|
+
controller.off("askUserRequested" /* AskUserRequested */, askUser);
|
|
4516
|
+
controller.destroy();
|
|
4517
|
+
controller.getSessionStateManager().clear();
|
|
4518
|
+
},
|
|
4519
|
+
loadSession: async (params) => {
|
|
4520
|
+
ownedSessionIds.add(params.sessionId);
|
|
4521
|
+
const result = await controller.loadSession({
|
|
4522
|
+
...params,
|
|
4523
|
+
sessionOriginHint: params.sessionOriginHint,
|
|
4524
|
+
sessionSource: params.sessionSource
|
|
4525
|
+
});
|
|
4526
|
+
sessionId = params.sessionId;
|
|
4527
|
+
return response(result);
|
|
4528
|
+
},
|
|
4529
|
+
updateSessionSettings: async (params) => response(await controller.updateSessionSettings(sessionId, params)),
|
|
4530
|
+
addMcpServer: async (params) => response(await controller.addMcpServer({ ...params, sessionId })),
|
|
4531
|
+
removeMcpServer: async (params) => response(await controller.removeMcpServer({ ...params, sessionId })),
|
|
4532
|
+
toggleMcpServer: async (params) => response(await controller.toggleMcpServer({ ...params, sessionId })),
|
|
4533
|
+
listMcpServers: async () => response(await controller.listMcpServers(sessionId)),
|
|
4534
|
+
listMcpTools: async () => response(await controller.listMcpTools(sessionId)),
|
|
4535
|
+
refreshConnectorToolCatalog: async () => response(await controller.refreshConnectorToolCatalog()),
|
|
4536
|
+
authenticateMcpServer: async (params) => response(
|
|
4537
|
+
await controller.authenticateMcpServer({ ...params, sessionId })
|
|
4538
|
+
),
|
|
4539
|
+
listSkills: async (params) => response(await controller.listSkills(sessionId, params)),
|
|
4540
|
+
setSkillDisabled: async (skillName, disabled, settingsLevel) => response(
|
|
4541
|
+
await controller.setSkillDisabled({
|
|
4542
|
+
sessionId,
|
|
4543
|
+
skillName,
|
|
4544
|
+
disabled,
|
|
4545
|
+
settingsLevel
|
|
4546
|
+
})
|
|
4547
|
+
),
|
|
4548
|
+
getRewindInfo: async (params) => response(await controller.getRewindInfo(sessionId, params.messageId)),
|
|
4549
|
+
executeRewind: async (params) => response(await controller.executeRewind(sessionId, params)),
|
|
4550
|
+
compactSession: async (params) => response(
|
|
4551
|
+
await controller.compactSession(
|
|
4552
|
+
sessionId,
|
|
4553
|
+
params.customInstructions,
|
|
4554
|
+
params.mode
|
|
4555
|
+
)
|
|
4556
|
+
),
|
|
4557
|
+
forkSession: async (params) => response(await controller.forkSession(sessionId, params)),
|
|
4558
|
+
renameSession: async (params) => response(await controller.renameSession(sessionId, params.title)),
|
|
4559
|
+
listTools: async () => {
|
|
4560
|
+
throw new DroidClientError(
|
|
4561
|
+
"listTools is not supported by remote sessions."
|
|
4562
|
+
);
|
|
4563
|
+
},
|
|
4564
|
+
getContextStats: async () => {
|
|
4565
|
+
throw new DroidClientError(
|
|
4566
|
+
"getContextStats is not supported by remote sessions."
|
|
4567
|
+
);
|
|
4568
|
+
}
|
|
4569
|
+
};
|
|
4570
|
+
return operations;
|
|
4571
|
+
}
|
|
4572
|
+
|
|
4573
|
+
// src/environment-session.ts
|
|
4574
|
+
async function createEnvironmentSession(options, createHandle) {
|
|
4575
|
+
if (!options.environment)
|
|
4576
|
+
throw new DroidClientError("An environment is required.");
|
|
4577
|
+
for (const key of [
|
|
4578
|
+
"execPath",
|
|
4579
|
+
"execArgs",
|
|
4580
|
+
"env",
|
|
4581
|
+
"transport",
|
|
4582
|
+
"machineId"
|
|
4583
|
+
]) {
|
|
4584
|
+
if (options[key] !== void 0)
|
|
4585
|
+
throw new DroidClientError(
|
|
4586
|
+
`Option "${key}" is local-only and cannot be used with an environment.`
|
|
4587
|
+
);
|
|
4588
|
+
}
|
|
4589
|
+
const mcpServers = options.mcpServers?.map((server) => {
|
|
4590
|
+
if (server instanceof SdkMcpServer)
|
|
4591
|
+
throw new DroidClientError(
|
|
4592
|
+
"In-process MCP servers cannot be used with an environment."
|
|
4593
|
+
);
|
|
4594
|
+
return server;
|
|
4595
|
+
});
|
|
4596
|
+
const apiKey = resolveApiKey(options.apiKey);
|
|
4597
|
+
const auth = { apiKey, baseUrl: options.baseUrl };
|
|
4598
|
+
const request = createApiRequest(auth);
|
|
4599
|
+
const api = createFactoryApi(request);
|
|
4600
|
+
const sessionId = uuidv43();
|
|
4601
|
+
let startup;
|
|
4602
|
+
try {
|
|
4603
|
+
const launched = await launchEnvironmentSession({
|
|
4604
|
+
environment: options.environment,
|
|
4605
|
+
signal: options.abortSignal,
|
|
4606
|
+
request,
|
|
4607
|
+
connect: async ({ computer, signal }) => {
|
|
4608
|
+
if (!computer.relayClientUrl)
|
|
4609
|
+
throw new DroidClientError("Computer has no relay URL.");
|
|
4610
|
+
const connectionConfig = {
|
|
4611
|
+
...DEFAULT_CONNECTION_CONFIG,
|
|
4612
|
+
...MACHINE_TYPE_CONFIG["computer" /* Computer */]
|
|
4613
|
+
};
|
|
4614
|
+
const connected = new DaemonSessionController({
|
|
4615
|
+
sessionStateManager: new MultiSessionStateManager(),
|
|
4616
|
+
config: {
|
|
4617
|
+
machineId: computer.id,
|
|
4618
|
+
machineType: "computer" /* Computer */,
|
|
4619
|
+
providerType: computer.providerType,
|
|
4620
|
+
isManaged: true,
|
|
4621
|
+
ensureRunning: async () => ({ wasRestarted: false }),
|
|
4622
|
+
trustedIdentity: trustedIdentityFromComputerResponse(
|
|
4623
|
+
computer,
|
|
4624
|
+
async () => {
|
|
4625
|
+
const fresh = parseResponse(
|
|
4626
|
+
await api.getComputer({
|
|
4627
|
+
computerId: computer.id,
|
|
4628
|
+
signal: AbortSignal.timeout(5e3)
|
|
4629
|
+
}),
|
|
4630
|
+
ComputerReadSchema
|
|
4631
|
+
);
|
|
4632
|
+
if (fresh.id !== computer.id)
|
|
4633
|
+
throw new DroidClientError(
|
|
4634
|
+
"Identity refresh returned a different Computer."
|
|
4635
|
+
);
|
|
4636
|
+
return fresh;
|
|
4637
|
+
}
|
|
4638
|
+
),
|
|
4639
|
+
url: computer.relayClientUrl,
|
|
4640
|
+
clientType: "sdk" /* SDK */,
|
|
4641
|
+
sdk: SDK_CLIENT_METADATA,
|
|
4642
|
+
getCredential: async () => ({ apiKey }),
|
|
4643
|
+
connectionTimeoutMs: connectionConfig.connectionTimeoutMs,
|
|
4644
|
+
requestTimeout: connectionConfig.requestTimeoutMs,
|
|
4645
|
+
maxPollAttempts: connectionConfig.maxPollAttempts,
|
|
4646
|
+
maxReconnectAttempts: connectionConfig.maxReconnectAttempts,
|
|
4647
|
+
reconnectInterval: connectionConfig.reconnectInitialDelayMs,
|
|
4648
|
+
maxReconnectDelay: connectionConfig.reconnectMaxDelayMs,
|
|
4649
|
+
reconnectBackoffFactor: connectionConfig.reconnectBackoffFactor,
|
|
4650
|
+
supportsTerminalRestoreOnLoad: false
|
|
4651
|
+
}
|
|
4652
|
+
});
|
|
4653
|
+
const operations = createDaemonSessionOperations(
|
|
4654
|
+
connected,
|
|
4655
|
+
sessionId,
|
|
4656
|
+
options
|
|
4657
|
+
);
|
|
4658
|
+
const cancel = () => connected.destroy();
|
|
4659
|
+
signal.addEventListener("abort", cancel, { once: true });
|
|
4660
|
+
startup = {
|
|
4661
|
+
operations,
|
|
4662
|
+
releaseAbort: () => signal.removeEventListener("abort", cancel)
|
|
4663
|
+
};
|
|
4664
|
+
await connected.attemptInitialConnection();
|
|
4665
|
+
signal.throwIfAborted();
|
|
4666
|
+
return { controller: connected, operations };
|
|
4667
|
+
},
|
|
4668
|
+
startSession: async ({ connection, computer, signal }) => {
|
|
4669
|
+
const { controller, operations } = connection;
|
|
4670
|
+
const initParams = buildInitParams({
|
|
4671
|
+
...options,
|
|
4672
|
+
machineId: computer.id,
|
|
4673
|
+
cwd: options.cwd ?? computer.clonedRepoDirectories?.[0] ?? "~",
|
|
4674
|
+
mcpServers
|
|
4675
|
+
});
|
|
4676
|
+
controller.getSessionStateManager().markSessionLoading(sessionId, computer.id);
|
|
4677
|
+
const result = await controller.initializeSession({
|
|
4678
|
+
...initParams,
|
|
4679
|
+
sessionId,
|
|
4680
|
+
token: apiKey,
|
|
4681
|
+
sessionSource: initParams.sessionSource,
|
|
4682
|
+
sessionOriginHint: initParams.sessionOriginHint
|
|
4683
|
+
});
|
|
4684
|
+
signal.throwIfAborted();
|
|
4685
|
+
return createHandle({
|
|
4686
|
+
result,
|
|
4687
|
+
operations,
|
|
4688
|
+
computerId: computer.id,
|
|
4689
|
+
cwd: initParams.cwd,
|
|
4690
|
+
mcpServers
|
|
4691
|
+
});
|
|
4692
|
+
}
|
|
4693
|
+
});
|
|
4694
|
+
return launched.session;
|
|
4695
|
+
} catch (error) {
|
|
4696
|
+
await startup?.operations.close();
|
|
4697
|
+
throw error;
|
|
4698
|
+
} finally {
|
|
4699
|
+
startup?.releaseAbort();
|
|
4700
|
+
}
|
|
4701
|
+
}
|
|
4702
|
+
|
|
3595
4703
|
// src/session.ts
|
|
3596
4704
|
var DroidSession = class _DroidSession {
|
|
3597
4705
|
/** @internal */
|
|
@@ -3602,11 +4710,22 @@ var DroidSession = class _DroidSession {
|
|
|
3602
4710
|
this._settings = metadata.settings;
|
|
3603
4711
|
this._cwd = metadata.cwd;
|
|
3604
4712
|
this._cleanupCallbacks = cleanupCallbacks;
|
|
4713
|
+
this._lifecycle = _runtime.lifecycle ?? {
|
|
4714
|
+
shutdown: async () => {
|
|
4715
|
+
await client.closeSession({ reason: "other" }).catch(() => {
|
|
4716
|
+
});
|
|
4717
|
+
await client.close();
|
|
4718
|
+
},
|
|
4719
|
+
abort: (close) => {
|
|
4720
|
+
void close();
|
|
4721
|
+
}
|
|
4722
|
+
};
|
|
3605
4723
|
this._bindMetadataNotifications();
|
|
3606
4724
|
this._bindAbortSignal();
|
|
3607
4725
|
}
|
|
3608
4726
|
_runtime;
|
|
3609
4727
|
_client;
|
|
4728
|
+
_lifecycle;
|
|
3610
4729
|
_sessionId;
|
|
3611
4730
|
_settings;
|
|
3612
4731
|
_cwd;
|
|
@@ -3620,6 +4739,9 @@ var DroidSession = class _DroidSession {
|
|
|
3620
4739
|
get id() {
|
|
3621
4740
|
return this._sessionId;
|
|
3622
4741
|
}
|
|
4742
|
+
get computerId() {
|
|
4743
|
+
return this._runtime.computerId;
|
|
4744
|
+
}
|
|
3623
4745
|
get settings() {
|
|
3624
4746
|
return this._settings;
|
|
3625
4747
|
}
|
|
@@ -3664,9 +4786,7 @@ var DroidSession = class _DroidSession {
|
|
|
3664
4786
|
bridge.release();
|
|
3665
4787
|
}
|
|
3666
4788
|
try {
|
|
3667
|
-
await this.
|
|
3668
|
-
});
|
|
3669
|
-
await this._client.close();
|
|
4789
|
+
await this._lifecycle.shutdown();
|
|
3670
4790
|
} finally {
|
|
3671
4791
|
const cleanups = this._cleanupCallbacks.splice(0);
|
|
3672
4792
|
await Promise.all(cleanups.map((cleanup) => cleanup()));
|
|
@@ -3717,6 +4837,11 @@ var DroidSession = class _DroidSession {
|
|
|
3717
4837
|
this._ensureNotClosed();
|
|
3718
4838
|
return unwrapResponseResult(await this._client.listMcpTools()).tools;
|
|
3719
4839
|
}
|
|
4840
|
+
/** Refresh connector discovery. MCP configuration has its own lifecycle. */
|
|
4841
|
+
async refreshConnectorToolCatalog() {
|
|
4842
|
+
this._ensureNotClosed();
|
|
4843
|
+
unwrapResponseResult(await this._client.refreshConnectorToolCatalog());
|
|
4844
|
+
}
|
|
3720
4845
|
async listTools(params = {}) {
|
|
3721
4846
|
this._ensureNotClosed();
|
|
3722
4847
|
return unwrapResponseResult(await this._client.listTools(params)).tools.map(
|
|
@@ -3733,9 +4858,9 @@ var DroidSession = class _DroidSession {
|
|
|
3733
4858
|
await this._client.authenticateMcpServer(params)
|
|
3734
4859
|
);
|
|
3735
4860
|
}
|
|
3736
|
-
async listSkills() {
|
|
4861
|
+
async listSkills(params) {
|
|
3737
4862
|
this._ensureNotClosed();
|
|
3738
|
-
return unwrapResponseResult(await this._client.listSkills());
|
|
4863
|
+
return unwrapResponseResult(await this._client.listSkills(params));
|
|
3739
4864
|
}
|
|
3740
4865
|
async setSkillDisabled(params) {
|
|
3741
4866
|
this._ensureNotClosed();
|
|
@@ -3760,7 +4885,14 @@ var DroidSession = class _DroidSession {
|
|
|
3760
4885
|
}
|
|
3761
4886
|
async compact(params) {
|
|
3762
4887
|
const { session, result } = await this._runReplacement(
|
|
3763
|
-
() => this._client.compactSession(params ?? {}).then(unwrapResponseResult)
|
|
4888
|
+
() => this._client.compactSession(params ?? {}).then(unwrapResponseResult),
|
|
4889
|
+
{ retainSourceWhenSameId: true }
|
|
4890
|
+
);
|
|
4891
|
+
return { session, removedCount: result.removedCount };
|
|
4892
|
+
}
|
|
4893
|
+
async handoff(params) {
|
|
4894
|
+
const { session, result } = await this._runReplacement(
|
|
4895
|
+
() => this._client.compactSession({ ...params, mode: "handoff" }).then(unwrapResponseResult)
|
|
3764
4896
|
);
|
|
3765
4897
|
return { session, removedCount: result.removedCount };
|
|
3766
4898
|
}
|
|
@@ -3808,7 +4940,7 @@ var DroidSession = class _DroidSession {
|
|
|
3808
4940
|
}
|
|
3809
4941
|
this._status = "replacing";
|
|
3810
4942
|
}
|
|
3811
|
-
async _runReplacement(operation) {
|
|
4943
|
+
async _runReplacement(operation, options) {
|
|
3812
4944
|
this._beginReplacement();
|
|
3813
4945
|
let result;
|
|
3814
4946
|
try {
|
|
@@ -3829,6 +4961,10 @@ var DroidSession = class _DroidSession {
|
|
|
3829
4961
|
)
|
|
3830
4962
|
});
|
|
3831
4963
|
}
|
|
4964
|
+
if (options?.retainSourceWhenSameId && result.newSessionId === this._sessionId) {
|
|
4965
|
+
this._status = "active";
|
|
4966
|
+
return { session: this, result };
|
|
4967
|
+
}
|
|
3832
4968
|
return {
|
|
3833
4969
|
session: await this._loadReplacement(result.newSessionId),
|
|
3834
4970
|
result
|
|
@@ -3913,7 +5049,7 @@ var DroidSession = class _DroidSession {
|
|
|
3913
5049
|
_bindAbortSignal() {
|
|
3914
5050
|
this._cleanupAbortSignal = wireAbortSignal(
|
|
3915
5051
|
this._runtime.abortSignal,
|
|
3916
|
-
() =>
|
|
5052
|
+
() => this._lifecycle.abort(() => this.close())
|
|
3917
5053
|
);
|
|
3918
5054
|
}
|
|
3919
5055
|
_bindMetadataNotifications() {
|
|
@@ -3958,6 +5094,22 @@ function createReplacementLoadParams(options, mcpServers) {
|
|
|
3958
5094
|
};
|
|
3959
5095
|
}
|
|
3960
5096
|
async function createSession(options = {}) {
|
|
5097
|
+
if (options.environment) {
|
|
5098
|
+
return await createEnvironmentSession(
|
|
5099
|
+
options,
|
|
5100
|
+
({ result, operations, computerId, cwd, mcpServers }) => new DroidSession(
|
|
5101
|
+
operations,
|
|
5102
|
+
result.sessionId,
|
|
5103
|
+
{ settings: result.settings, cwd },
|
|
5104
|
+
{
|
|
5105
|
+
computerId,
|
|
5106
|
+
abortSignal: options.abortSignal,
|
|
5107
|
+
loadParams: createReplacementLoadParams(options, mcpServers),
|
|
5108
|
+
lifecycle: operations.lifecycle
|
|
5109
|
+
}
|
|
5110
|
+
)
|
|
5111
|
+
);
|
|
5112
|
+
}
|
|
3961
5113
|
const { client } = await createConfiguredClient(options);
|
|
3962
5114
|
let cleanupInitAbortSignal = options.abortSignal?.aborted ? () => {
|
|
3963
5115
|
} : wireAbortSignal(options.abortSignal, () => {
|
|
@@ -4047,12 +5199,14 @@ async function run(prompt, options = {}) {
|
|
|
4047
5199
|
includePartialMessages: false
|
|
4048
5200
|
})) {
|
|
4049
5201
|
if (msg.type === DroidMessageType.Result) {
|
|
4050
|
-
|
|
5202
|
+
const computerId = session.computerId;
|
|
5203
|
+
return computerId === void 0 ? msg : { ...msg, computerId };
|
|
4051
5204
|
}
|
|
4052
5205
|
}
|
|
4053
5206
|
throw new Error("Stream completed without a result message");
|
|
4054
5207
|
} finally {
|
|
4055
|
-
await session.close()
|
|
5208
|
+
await session.close().catch(() => {
|
|
5209
|
+
});
|
|
4056
5210
|
}
|
|
4057
5211
|
}
|
|
4058
5212
|
|
|
@@ -4072,9 +5226,14 @@ var CR = 13;
|
|
|
4072
5226
|
var SPACE = 32;
|
|
4073
5227
|
var TAB = 9;
|
|
4074
5228
|
var PARSE_OVERSAMPLE = 20;
|
|
4075
|
-
function
|
|
5229
|
+
function readFileOrNull(filePath, read) {
|
|
4076
5230
|
try {
|
|
4077
|
-
|
|
5231
|
+
const fd = fs3.openSync(filePath, "r");
|
|
5232
|
+
try {
|
|
5233
|
+
return read(fd);
|
|
5234
|
+
} finally {
|
|
5235
|
+
fs3.closeSync(fd);
|
|
5236
|
+
}
|
|
4078
5237
|
} catch {
|
|
4079
5238
|
return null;
|
|
4080
5239
|
}
|
|
@@ -4086,37 +5245,83 @@ function parseJsonBuffer(buf) {
|
|
|
4086
5245
|
return null;
|
|
4087
5246
|
}
|
|
4088
5247
|
}
|
|
4089
|
-
|
|
5248
|
+
var SCAN_CHUNK_BYTES = 64 * 1024;
|
|
5249
|
+
var MAX_SCANNED_FILE_BYTES = 2 ** 31 - 1;
|
|
5250
|
+
function scratchChunk(scratch, size) {
|
|
5251
|
+
const want = Math.min(SCAN_CHUNK_BYTES, size === 0 ? 8192 : size);
|
|
5252
|
+
const current = scratch.chunk;
|
|
5253
|
+
if (current && current.length >= want) return current;
|
|
5254
|
+
const grown = Buffer.allocUnsafe(
|
|
5255
|
+
Math.min(SCAN_CHUNK_BYTES, Math.max(want, 2 * (current?.length ?? 0)))
|
|
5256
|
+
);
|
|
5257
|
+
scratch.chunk = grown;
|
|
5258
|
+
return grown;
|
|
5259
|
+
}
|
|
5260
|
+
function copyFirstLine(parts, chunk, end) {
|
|
5261
|
+
return Buffer.concat([...parts, chunk.subarray(0, end)]);
|
|
5262
|
+
}
|
|
5263
|
+
function scanSessionFile(fd, scratch) {
|
|
5264
|
+
const stats = fs3.fstatSync(fd);
|
|
5265
|
+
const size = stats.isFile() ? stats.size : 0;
|
|
5266
|
+
if (size > MAX_SCANNED_FILE_BYTES) return null;
|
|
5267
|
+
const chunk = scratchChunk(scratch, size);
|
|
4090
5268
|
let nonEmptyLineCount = 0;
|
|
4091
|
-
let
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
5269
|
+
let lineHasContent = false;
|
|
5270
|
+
const firstLineParts = [];
|
|
5271
|
+
let firstLine;
|
|
5272
|
+
let pos = 0;
|
|
5273
|
+
for (; ; ) {
|
|
5274
|
+
const length = size === 0 ? chunk.length : Math.min(chunk.length, size - pos);
|
|
5275
|
+
if (length === 0) break;
|
|
5276
|
+
const bytesRead = fs3.readSync(fd, chunk, 0, length, null);
|
|
5277
|
+
if (bytesRead === 0) break;
|
|
5278
|
+
pos += bytesRead;
|
|
5279
|
+
let i = 0;
|
|
5280
|
+
while (i < bytesRead) {
|
|
5281
|
+
let lf;
|
|
5282
|
+
if (lineHasContent) {
|
|
5283
|
+
lf = chunk.indexOf(LF, i);
|
|
5284
|
+
if (lf === -1 || lf >= bytesRead) break;
|
|
5285
|
+
nonEmptyLineCount++;
|
|
5286
|
+
lineHasContent = false;
|
|
5287
|
+
} else {
|
|
5288
|
+
const ch = chunk[i];
|
|
5289
|
+
if (ch === CR || ch === SPACE || ch === TAB) {
|
|
5290
|
+
i++;
|
|
5291
|
+
continue;
|
|
5292
|
+
}
|
|
5293
|
+
if (ch !== LF) {
|
|
5294
|
+
lineHasContent = true;
|
|
5295
|
+
continue;
|
|
5296
|
+
}
|
|
5297
|
+
lf = i;
|
|
5298
|
+
}
|
|
5299
|
+
firstLine ??= copyFirstLine(firstLineParts, chunk, lf);
|
|
5300
|
+
i = lf + 1;
|
|
5301
|
+
}
|
|
5302
|
+
if (firstLine === void 0) {
|
|
5303
|
+
firstLineParts.push(Buffer.from(chunk.subarray(0, bytesRead)));
|
|
5304
|
+
}
|
|
5305
|
+
}
|
|
5306
|
+
if (lineHasContent) nonEmptyLineCount++;
|
|
5307
|
+
const [onlyPart] = firstLineParts;
|
|
5308
|
+
firstLine ??= onlyPart !== void 0 && firstLineParts.length === 1 ? onlyPart : Buffer.concat(firstLineParts);
|
|
5309
|
+
return { firstLine, nonEmptyLineCount };
|
|
4109
5310
|
}
|
|
4110
5311
|
function loadFavorites(sessionsDir) {
|
|
4111
|
-
const buf =
|
|
5312
|
+
const buf = readFileOrNull(
|
|
5313
|
+
path2.join(sessionsDir, FAVORITES_FILE),
|
|
5314
|
+
(fd) => fs3.readFileSync(fd)
|
|
5315
|
+
);
|
|
4112
5316
|
if (!buf) return /* @__PURE__ */ new Set();
|
|
4113
5317
|
const parsed = parseJsonBuffer(buf);
|
|
4114
5318
|
if (!Array.isArray(parsed)) return /* @__PURE__ */ new Set();
|
|
4115
5319
|
return new Set(parsed.filter((id) => typeof id === "string"));
|
|
4116
5320
|
}
|
|
4117
5321
|
function loadSettingsFile(directory, sessionId) {
|
|
4118
|
-
const buf =
|
|
4119
|
-
path2.join(directory, `${sessionId}${SETTINGS_SUFFIX}`)
|
|
5322
|
+
const buf = readFileOrNull(
|
|
5323
|
+
path2.join(directory, `${sessionId}${SETTINGS_SUFFIX}`),
|
|
5324
|
+
(fd) => fs3.readFileSync(fd)
|
|
4120
5325
|
);
|
|
4121
5326
|
if (!buf) return null;
|
|
4122
5327
|
const parsed = parseJsonBuffer(buf);
|
|
@@ -4138,9 +5343,11 @@ function getMissionMetadataFromTags(settings) {
|
|
|
4138
5343
|
};
|
|
4139
5344
|
}
|
|
4140
5345
|
function parseSessionFile(candidate, ctx) {
|
|
4141
|
-
const
|
|
4142
|
-
|
|
4143
|
-
|
|
5346
|
+
const scanned = readFileOrNull(
|
|
5347
|
+
candidate.sessionPath,
|
|
5348
|
+
(fd) => scanSessionFile(fd, ctx.scratch)
|
|
5349
|
+
);
|
|
5350
|
+
if (!scanned) return null;
|
|
4144
5351
|
const firstParsed = parseJsonBuffer(scanned.firstLine);
|
|
4145
5352
|
if (firstParsed === null) return null;
|
|
4146
5353
|
const firstResult = SessionStartEventSchema.safeParse(firstParsed);
|
|
@@ -4257,8 +5464,9 @@ async function listSessions(options = {}) {
|
|
|
4257
5464
|
projectCandidates.sort(byMtimeDesc);
|
|
4258
5465
|
legacyCandidates.sort(byMtimeDesc);
|
|
4259
5466
|
const parseLimit = options.limit !== void 0 && options.limit >= 0 ? options.limit + PARSE_OVERSAMPLE : void 0;
|
|
4260
|
-
const
|
|
4261
|
-
const
|
|
5467
|
+
const scratch = { chunk: void 0 };
|
|
5468
|
+
const ctx = { favorites, scratch };
|
|
5469
|
+
const legacyCtx = requiredCwd !== void 0 ? { favorites, scratch, requiredCwd } : ctx;
|
|
4262
5470
|
const projectSessions = parseUpTo(projectCandidates, ctx, parseLimit);
|
|
4263
5471
|
const legacySessions = parseUpTo(legacyCandidates, legacyCtx, parseLimit);
|
|
4264
5472
|
const byId = /* @__PURE__ */ new Map();
|
|
@@ -4282,10 +5490,10 @@ async function listModels(options = {}) {
|
|
|
4282
5490
|
const { includeDisabled, ...transportOptions } = options;
|
|
4283
5491
|
const { client } = await createConfiguredClient(transportOptions);
|
|
4284
5492
|
try {
|
|
4285
|
-
const
|
|
5493
|
+
const response2 = await client.listModels({
|
|
4286
5494
|
...includeDisabled !== void 0 && { includeDisabled }
|
|
4287
5495
|
});
|
|
4288
|
-
return unwrapResponseResult(
|
|
5496
|
+
return unwrapResponseResult(response2).models;
|
|
4289
5497
|
} finally {
|
|
4290
5498
|
await closeQuietly(client);
|
|
4291
5499
|
}
|
|
@@ -4300,6 +5508,7 @@ export {
|
|
|
4300
5508
|
AddUserMessageRequestSchema,
|
|
4301
5509
|
AddUserMessageResponseSchema,
|
|
4302
5510
|
AddUserMessageResultSchema,
|
|
5511
|
+
AnswerSessionElicitationResponseSchema,
|
|
4303
5512
|
ApplyPatchToolConfirmationDetailsSchema,
|
|
4304
5513
|
AskUserCollectedAnswerSchema,
|
|
4305
5514
|
AskUserConfirmationDetailsSchema,
|
|
@@ -4360,6 +5569,7 @@ export {
|
|
|
4360
5569
|
ConnectionError,
|
|
4361
5570
|
ConnectionFailureReason,
|
|
4362
5571
|
ContentBlockSchema,
|
|
5572
|
+
ContextApiError,
|
|
4363
5573
|
ContextBreakdownCategorySchema,
|
|
4364
5574
|
GetContextBreakdownResultSchema as ContextBreakdownResultSchema,
|
|
4365
5575
|
ContextStatsAccuracy,
|
|
@@ -4384,6 +5594,7 @@ export {
|
|
|
4384
5594
|
DroidClientError,
|
|
4385
5595
|
DroidClientEvent,
|
|
4386
5596
|
DroidClientMethod,
|
|
5597
|
+
DroidConnectionEndedError,
|
|
4387
5598
|
DroidErrorType,
|
|
4388
5599
|
DroidEvent,
|
|
4389
5600
|
DroidHookEventSchema,
|
|
@@ -4400,9 +5611,12 @@ export {
|
|
|
4400
5611
|
DroidWorkingStateChangedNotificationSchema,
|
|
4401
5612
|
EditToolConfirmationDetailsSchema,
|
|
4402
5613
|
EmptyResultSchema,
|
|
5614
|
+
EnvironmentListResponseSchema,
|
|
5615
|
+
EnvironmentSchema,
|
|
4403
5616
|
ErrorDetailSchema,
|
|
4404
5617
|
ErrorNotificationSchema,
|
|
4405
5618
|
ExecToolInfoSchema,
|
|
5619
|
+
ExecToolInfoWithSchemasSchema,
|
|
4406
5620
|
ExecuteRewindRequestParamsSchema,
|
|
4407
5621
|
ExecuteRewindRequestSchema,
|
|
4408
5622
|
ExecuteRewindResponseSchema,
|
|
@@ -4411,7 +5625,7 @@ export {
|
|
|
4411
5625
|
ExitSpecModeConfirmationDetailsSchema,
|
|
4412
5626
|
FACTORY_CLIENT_HEADER,
|
|
4413
5627
|
FACTORY_CLIENT_VERSION,
|
|
4414
|
-
|
|
5628
|
+
FACTORY_PROTOCOL_VERSION,
|
|
4415
5629
|
FactoryDaemonTransport,
|
|
4416
5630
|
FactoryDroidMessageRole,
|
|
4417
5631
|
FactoryDroidMessageSchema,
|
|
@@ -4454,7 +5668,7 @@ export {
|
|
|
4454
5668
|
InvalidSessionCwdError,
|
|
4455
5669
|
IpcDaemonClientTransport,
|
|
4456
5670
|
IssueSeverity,
|
|
4457
|
-
|
|
5671
|
+
JSONRPC_VERSION,
|
|
4458
5672
|
JsonArraySchema,
|
|
4459
5673
|
JsonObjectSchema,
|
|
4460
5674
|
JsonRpcEnvelopeSchema,
|
|
@@ -4473,7 +5687,7 @@ export {
|
|
|
4473
5687
|
KillWorkerSessionRequestSchema,
|
|
4474
5688
|
KillWorkerSessionResponseSchema,
|
|
4475
5689
|
KillWorkerSessionResultSchema,
|
|
4476
|
-
|
|
5690
|
+
LEGACY_FACTORY_API_VERSION,
|
|
4477
5691
|
LOCAL_MACHINE_ID,
|
|
4478
5692
|
ListMcpRegistryRequestParamsSchema,
|
|
4479
5693
|
ListMcpRegistryRequestSchema,
|
|
@@ -4489,6 +5703,7 @@ export {
|
|
|
4489
5703
|
ListMcpToolsResultSchema,
|
|
4490
5704
|
ListModelsOptionsSchema,
|
|
4491
5705
|
ListModelsResultSchema,
|
|
5706
|
+
ListSessionElicitationsResponseSchema,
|
|
4492
5707
|
ListSkillsRequestParamsSchema,
|
|
4493
5708
|
ListSkillsRequestSchema,
|
|
4494
5709
|
ListSkillsResponseSchema,
|
|
@@ -4496,7 +5711,9 @@ export {
|
|
|
4496
5711
|
ListToolsRequestParamsSchema,
|
|
4497
5712
|
ListToolsRequestSchema,
|
|
4498
5713
|
ListToolsResponseSchema,
|
|
5714
|
+
ListToolsResponseWithSchemasSchema,
|
|
4499
5715
|
ListToolsResultSchema,
|
|
5716
|
+
ListToolsResultWithSchemasSchema,
|
|
4500
5717
|
LoadSessionRequestParamsSchema,
|
|
4501
5718
|
LoadSessionRequestSchema,
|
|
4502
5719
|
LoadSessionResponseSchema,
|
|
@@ -4551,6 +5768,12 @@ export {
|
|
|
4551
5768
|
OutputFormatSchema,
|
|
4552
5769
|
OutputFormatType,
|
|
4553
5770
|
PermissionResolvedNotificationSchema,
|
|
5771
|
+
PickOptionsRequestParamsSchema,
|
|
5772
|
+
PickOptionsRequestSchema,
|
|
5773
|
+
PickOptionsResponseSchema,
|
|
5774
|
+
PickOptionsResultSchema,
|
|
5775
|
+
PickOptionsRowSchema,
|
|
5776
|
+
PickOptionsUnavailableError,
|
|
4554
5777
|
ProcessExitError,
|
|
4555
5778
|
ProcessTransport,
|
|
4556
5779
|
ProgressLogEntrySchema,
|
|
@@ -4574,6 +5797,7 @@ export {
|
|
|
4574
5797
|
RenameSessionRequestSchema,
|
|
4575
5798
|
RenameSessionResponseSchema,
|
|
4576
5799
|
RenameSessionResultSchema,
|
|
5800
|
+
RequestCancelledError,
|
|
4577
5801
|
RequestPermissionRequestParamsSchema,
|
|
4578
5802
|
RequestPermissionRequestSchema,
|
|
4579
5803
|
RequestPermissionResponseSchema,
|
|
@@ -4587,6 +5811,13 @@ export {
|
|
|
4587
5811
|
SLACK_DELEGATION_MAX_RETRIES,
|
|
4588
5812
|
SdkMcpServer,
|
|
4589
5813
|
ServerRequestHandlerType,
|
|
5814
|
+
SessionArtifactAction,
|
|
5815
|
+
SessionArtifactKind,
|
|
5816
|
+
SessionArtifactProvider,
|
|
5817
|
+
SessionArtifactSchema,
|
|
5818
|
+
SessionArtifactSource,
|
|
5819
|
+
SessionArtifactsSchema,
|
|
5820
|
+
SessionElicitationSchema,
|
|
4590
5821
|
SessionError,
|
|
4591
5822
|
SessionMetadataSchema,
|
|
4592
5823
|
SessionNotFoundError,
|
|
@@ -4658,11 +5889,15 @@ export {
|
|
|
4658
5889
|
ToolConfirmationListItemSchema,
|
|
4659
5890
|
ToolConfirmationOutcome,
|
|
4660
5891
|
ToolConfirmationType,
|
|
5892
|
+
ToolJsonSchemaSchema,
|
|
4661
5893
|
ToolProgressUpdateNotificationSchema,
|
|
4662
5894
|
ToolProgressUpdateSchema,
|
|
4663
5895
|
ToolResultSchema as ToolResultBlockSchema,
|
|
4664
5896
|
ToolResultNotificationSchema,
|
|
5897
|
+
ToolResultSchemaDescriptorSchema,
|
|
5898
|
+
ToolSchemasSchema,
|
|
4665
5899
|
ToolSelectionOverridesSchema,
|
|
5900
|
+
ToolSourceSchema,
|
|
4666
5901
|
ToolUseSchema as ToolUseBlockSchema,
|
|
4667
5902
|
ToolUseSchema2 as ToolUseSchema,
|
|
4668
5903
|
TraceContextMetaSchema,
|
|
@@ -4683,7 +5918,10 @@ export {
|
|
|
4683
5918
|
WorkerSelectedFeatureEntrySchema,
|
|
4684
5919
|
WorkerStartedEntrySchema,
|
|
4685
5920
|
WorkerStateInfoSchema,
|
|
5921
|
+
MissionMachineTargetKind as WorkstreamMachineTargetKind,
|
|
4686
5922
|
__resetTransportLoggerForTests,
|
|
5923
|
+
answerRemoteSessionElicitation,
|
|
5924
|
+
appendContextSession,
|
|
4687
5925
|
buildUserMessageContentBlocks,
|
|
4688
5926
|
configureDaemonCoreDeps,
|
|
4689
5927
|
connectAndAuthenticate,
|
|
@@ -4691,16 +5929,25 @@ export {
|
|
|
4691
5929
|
connectWithRetry,
|
|
4692
5930
|
convertNotificationToStreamMessage,
|
|
4693
5931
|
createComputer,
|
|
5932
|
+
createContextDocument,
|
|
5933
|
+
createContextFile,
|
|
5934
|
+
createContextSpace,
|
|
4694
5935
|
createResponseSchema,
|
|
4695
5936
|
createSdkMcpServer,
|
|
4696
5937
|
createSession,
|
|
4697
5938
|
createWebSocketDaemonClient,
|
|
4698
5939
|
defaultDaemonCoreDeps,
|
|
4699
5940
|
deleteComputer,
|
|
5941
|
+
deleteContextDocument,
|
|
5942
|
+
deleteContextFile,
|
|
4700
5943
|
filterMessagesForUI,
|
|
4701
5944
|
getComputer,
|
|
4702
5945
|
getComputerByName,
|
|
4703
5946
|
getComputerMetrics,
|
|
5947
|
+
getContextDocument,
|
|
5948
|
+
getContextDocumentByPath,
|
|
5949
|
+
getContextSession,
|
|
5950
|
+
getContextSpace,
|
|
4704
5951
|
getMachineTemplate,
|
|
4705
5952
|
getPermissionToolInputForDisplay,
|
|
4706
5953
|
getQueuedUserMessageDisplayGroup,
|
|
@@ -4712,22 +5959,29 @@ export {
|
|
|
4712
5959
|
hasSubagentSessionTag,
|
|
4713
5960
|
inspectJsonRpcEnvelope,
|
|
4714
5961
|
isDaemonQueuedMessageKind,
|
|
5962
|
+
isDroidConnectionEnded,
|
|
4715
5963
|
isPendingToolResultMarker,
|
|
4716
5964
|
isPersistedHookMessage,
|
|
4717
5965
|
isReviewableQueuedMessageKind,
|
|
4718
5966
|
isTransportLoggingEnabled,
|
|
4719
5967
|
listComputers,
|
|
5968
|
+
listContextDocuments,
|
|
5969
|
+
listContextSessions,
|
|
5970
|
+
listContextSpaces,
|
|
5971
|
+
listEnvironments,
|
|
4720
5972
|
listMachineTemplates,
|
|
4721
5973
|
listModels,
|
|
5974
|
+
listRemoteSessionElicitations,
|
|
4722
5975
|
listRemoteSessions,
|
|
4723
5976
|
listSessions,
|
|
4724
5977
|
logTransportMessage,
|
|
4725
5978
|
machineTypeToMachineConnectionType,
|
|
4726
5979
|
noopLogger,
|
|
4727
|
-
|
|
5980
|
+
readContextFilePart,
|
|
5981
|
+
readContextSessionRecords,
|
|
4728
5982
|
recordComputerConnectSli,
|
|
4729
5983
|
refreshComputer,
|
|
4730
|
-
|
|
5984
|
+
registerContextSession,
|
|
4731
5985
|
resolveExecCoreDeps,
|
|
4732
5986
|
restartComputer,
|
|
4733
5987
|
resumeSession,
|
|
@@ -4739,6 +5993,9 @@ export {
|
|
|
4739
5993
|
summarizeSessionToolUsage,
|
|
4740
5994
|
toError,
|
|
4741
5995
|
tool,
|
|
4742
|
-
updateComputer
|
|
5996
|
+
updateComputer,
|
|
5997
|
+
updateContextDocument,
|
|
5998
|
+
uploadContextFilePart,
|
|
5999
|
+
withJsonRpcCodec
|
|
4743
6000
|
};
|
|
4744
6001
|
//# sourceMappingURL=node.mjs.map
|